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 log-normal disorder on strengths and static calibration spread, see Realistic Noise Models. For execution options (parallelism, progress bars), see Configuring the Simulator. To build Ising, Hubbard, Pauli-string, or hardware Hamiltonians, see Building Hamiltonians.

1. Hamiltonian

1from mqt.yaqs import Hamiltonian
2
3L = 5
4J, g = 1.0, 0.8
5H_0 = Hamiltonian.ising(L, J, g)

See Building Hamiltonians for Pauli sums, Fermi–Hubbard, Bose–Hubbard, and coupled-transmon factories.

2. Initial state and noise model

We prepare a Néel state \(\ket{01010\ldots}\) and track staggered magnetization under a transverse-field Ising model with on-site amplitude damping. The alternating \(\langle Z_i \rangle\) pattern at \(t=0\) spreads and decays in a site-dependent way.

1from mqt.yaqs import NoiseModel, State
2
3state = State(L, initial="Neel")
4
5gamma = 0.08
6noise_model = NoiseModel([
7    {"name": "lowering", "sites": [i], "strength": gamma} for i in range(L)
8])

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

3. Simulation parameters

 1from mqt.yaqs import AnalogSimParams, Observable
 2
 3sim_params = AnalogSimParams(
 4    observables=[Observable("z", site) for site in range(L)],
 5    elapsed_time=6.0,
 6    dt=0.1,
 7    num_traj=20,
 8    max_bond_dim=16,
 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("z", site) for site in range(L)],
 9    elapsed_time=1.0,
10    dt=0.1,
11    num_traj=16,
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()

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=(7, 4), layout="constrained")
 6im = ax.imshow(heatmap, aspect="auto", extent=(0, 6, L, 0), vmin=-1, vmax=1)
 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")
10fig.colorbar(im, ax=ax, shrink=0.9, label=r"$\langle Z \rangle$")
11plt.show()