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