monoprop

Initialisation and updates

Constructing the simulator, choosing the Heisenberg or Schrödinger picture, and updating the operator in place.

The top-level classes are MajoranaPropagator and PauliPropagator (Python) / MonomialPropagator<NumModes> (C++). Every significant aspect of the simulation can be tuned at construction time and updated at runtime without rebuilding. The structural and coefficient cutoffs are covered separately in Truncation and cutoffs.

Heisenberg and Schrödinger pictures

Pass schrodinger_cutoff to switch from the default Heisenberg picture (operator evolution) to the Schrödinger picture (density matrix evolution). In the Schrödinger picture gates are applied to the state, whereas in the Heisenberg picture they are applied to the observable.

schrodinger_cutoff is the truncation applied to the initial state. It must be set higher than the regular cutoff for the Schrödinger-picture result to match the Heisenberg-picture one. A good value of the parameter depends on the circuit and observable, although setting schrodinger_cutoff = cutoff + 2 for MajoranaPropagator and schrodinger_cutoff = cutoff + 1 for PauliPropagator is usually a good starting point. For second-quantized Hamiltonians and usual Fermionic circuits coming from variational quantum computing, under length truncation the two pictures agree when schrodinger_cutoff = cutoff + 2 (see Appendix of (Chakraborty et al., 2026)).

Operator updates

The coefficients of the initial operator can be patched after construction without rebuilding the simulator or the graph. For MajoranaPropagator, MajoranaOperator is required while PauliPropagator requires PauliOperator.

from monoprop import MajoranaPropagator, MajoranaOperator

observable = MajoranaOperator({(0, 1, 2, 3): 1.0}, 4)
sim = MajoranaPropagator(observable, initial_state=[0, 1], cutoff=4)
sim.update_initial_operator(MajoranaOperator({(0, 1, 2, 3): 0.5}, 4))

This lets you estimate several observables without re-propagating: in the Schrödinger picture the state is evolved independently, so you can change the observable arbitrarily and read it off against the same evolved state; in the Heisenberg picture the observable can be re-weighted.

Only terms that already exist in the initial operator can be updated; supplying a monomial that is not present (or a non-Hermitian coefficient) raises RuntimeError:

import pytest
from monoprop import MajoranaPropagator, MajoranaOperator

observable = MajoranaOperator({(0, 1, 2, 3): 1.0}, 4)
sim = MajoranaPropagator(observable, initial_state=[0, 1], cutoff=4)
with pytest.raises(RuntimeError):
    sim.update_initial_operator(MajoranaOperator({(1, 2, 3, 4): 1.0}, 4))  # This monomial doesn't exist

On this page