Noisy Analog Simulation

This guide walks through an open-system analog simulation with the tensor jump method (TJM): build a Hamiltonian, attach a noise model, configure AnalogSimParams, and visualize time-resolved observables.

For Gaussian (bell-curve) noise strengths and static disorder, see Realistic Noise Models. For execution options (parallelism, progress bars), see Configuring the Simulator.

1. Hamiltonian

Three equivalent ways to define the transverse-field Ising model \(H = -J \sum_i Z_i Z_{i+1} - g \sum_i X_i\) on an open chain:

 1from mqt.yaqs import Hamiltonian, MPO
 2
 3L = 3
 4J = 1
 5g = 0.5
 6
 7# Method 1: built-in constructor
 8H_0 = Hamiltonian.ising(L, J, g)
 9
10# Method 2: generic Pauli interface
11H_0 = Hamiltonian.pauli(
12    length=L,
13    two_body=[(-J, "Z", "Z")],
14    one_body=[(-g, "X")],
15    bc="open",
16)
17
18# Method 3: explicit Pauli-string MPO
19terms = [(-J, f"Z{i} Z{i+1}") for i in range(L - 1)] + [(-g, f"X{i}") for i in range(L)]
20mpo = MPO()
21mpo.from_pauli_sum(terms=terms, length=L)
22H_0 = Hamiltonian.from_mpo(mpo)

2. Initial state and noise model

 1from mqt.yaqs import NoiseModel, State
 2
 3state = State(L, initial="zeros")
 4# Alternative: State(L, initial="haar-random", pad=4)
 5
 6gamma = 0.1
 7noise_model = NoiseModel([
 8    {"name": name, "sites": [i], "strength": gamma}
 9    for i in range(L)
10    for name in ["lowering", "pauli_z"]
11])

Pass a float for each strength here. For distribution-valued strengths (Gaussian and other distributions), see Realistic Noise Models.

3. Simulation parameters

 1from mqt.yaqs import AnalogSimParams, Observable
 2
 3sim_params = AnalogSimParams(
 4    observables=[Observable("x", site) for site in range(L)],
 5    elapsed_time=10,
 6    dt=0.1,
 7    num_traj=100,
 8    max_bond_dim=4,
 9    svd_threshold=1e-6,
10    order=2,
11    sample_timesteps=True,
12)

Optional tdvp_sweeps (default 1) runs multiple symmetric TDVP substeps per physical step dt, improving unitary accuracy without changing the noise timestep.

Evolution integrator: analog simulations default to EvolutionMode.TDVP (two-site TDVP sweeps). EvolutionMode.BUG is available as an alternative on AnalogSimParams when you want the BUG integrator instead.

4. Reproducible stochastic runs

With num_traj > 1, each run() call averages independent quantum-jump trajectories. Set random_seed to fix the pseudorandom stream across trajectories (and for distribution-valued noise strengths):

 1import copy
 2
 3import numpy as np
 4
 5from mqt.yaqs import AnalogSimParams, Observable, Simulator
 6
 7repro_params = AnalogSimParams(
 8    observables=[Observable("x", site) for site in range(L)],
 9    elapsed_time=1.0,
10    dt=0.1,
11    num_traj=50,
12    max_bond_dim=4,
13    svd_threshold=1e-6,
14    order=2,
15    sample_timesteps=True,
16    random_seed=42,
17)
18
19sim = Simulator(parallel=True, show_progress=False)
20
21
22def run_reproducible() -> list[np.ndarray]:
23    st = copy.deepcopy(state)
24    params = copy.deepcopy(repro_params)
25    result = sim.run(st, H_0, params, copy.deepcopy(noise_model))
26    return result.expectation_values
27
28
29first_run = run_reproducible()
30second_run = run_reproducible()
31assert all(np.allclose(a, b) for a, b in zip(first_run, second_run, strict=True))
32print("Both runs produced identical trajectory-averaged observables.")
Both runs produced identical trajectory-averaged observables.

The same random_seed field exists on StrongSimParams and WeakSimParams.

5. Run and visualize

1result = sim.run(state, H_0, sim_params, noise_model)
 1import matplotlib.pyplot as plt
 2
 3heatmap = result.expectation_values
 4
 5fig, ax = plt.subplots(figsize=(5, 3))
 6im = ax.imshow(heatmap, aspect="auto", extent=(0, 10, L, 0), vmin=0, vmax=0.5)
 7ax.set_xlabel("Time")
 8ax.set_yticks([x - 0.5 for x in range(1, L + 1)], [str(x) for x in range(L)])
 9ax.set_ylabel("Site")
10
11fig.subplots_adjust(top=0.95, right=0.88)
12cbar_ax = fig.add_axes(rect=(0.9, 0.11, 0.025, 0.8))
13cbar = fig.colorbar(im, cax=cbar_ax)
14cbar.ax.set_title(r"$\langle X \rangle$")
15plt.tight_layout()
16plt.show()
/tmp/ipykernel_2371/1127387109.py:15: UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.
  plt.tight_layout()
../_images/bed31f4b04a55f642543f8b5c808f6a619166195e431d65507e7eb8e0c9fa3cf.svg