Interface
How a problem is expressed as input — operator formats, the reference state, and the circuit.
This page describes how a problem is expressed as input to monoprop: the operator formats you can start from, the reference state, and how a circuit is bundled for simulation. For the exact constructors and arguments, see Python API.
Operator formats
A problem is defined by an operator together with a reference state. monoprop accepts operators in three forms, each suited to a different starting point; see Notation for how they relate.
Fermionic operators
The natural starting point for quantum chemistry and lattice models. An operator
is given as a weighted sum of products of fermionic creation and annihilation
operators on numbered modes (for example ); use
MajoranaPropagator.
from monoprop import MajoranaPropagator, Circuit, ExpGate
from monoprop.fermi import FermiOperator
# Observable: the hopping term c_0^† c_1 + c_1^† c_0 on 4 modes
# ('+' = creation, '-' = annihilation).
observable = FermiOperator(
[[(0, "+"), (1, "-")], [(1, "+"), (0, "-")]],
[1.0, 1.0],
num_modes=4,
)
# One fermionic rotation generated by the number operator n_0 = c_0^† c_0,
# with the Hartree-Fock reference |0, 1> (modes 0 and 1 occupied).
generator = FermiOperator([[(0, "+"), (0, "-")]], [1.0], num_modes=4)
circuit = Circuit(initial_state=[0, 1], gates=[ExpGate(generator)], parameters=[0.3])
mp = MajoranaPropagator.from_circuit(circuit, observable, cutoff=4)
print(sorted(mp.evolved_operator().items())) # keyed by Majorana indicesQubit (Pauli) operators
The natural starting point when you already hold a qubit Hamiltonian. An
operator is given as a real-coefficient sum of Paulis (tensor products of
). For qubit problems, use PauliPropagator, which accepts Pauli
operators and gates directly and truncates by Pauli weight.
from monoprop import PauliPropagator, Circuit, ExpGate, Pauli
from monoprop.pauli import PauliOperator
# Observable: Z⊗Z + 0.5 X⊗X on two qubits.
observable = PauliOperator({"ZZ": 1.0, "XX": 0.5}, num_qubits=2)
# One Pauli rotation exp(-i θ/2 · X_0) acting on qubit 0.
gate = ExpGate(PauliOperator({Pauli("X", 0): 1.0}, num_qubits=2))
circuit = Circuit(gates=[gate], parameters=[0.3])
mp = PauliPropagator.from_circuit(circuit, observable, cutoff=4)
print(sorted(mp.evolved_operator().items())) # keys are Majorana indicesMajorana operators
In this case the monomials are specified explicitly as sets of Majorana mode indices. The coefficient is the one multiplying the bare Majorana product, so it must keep the monomial Hermitian: real for length-4 monomials, imaginary for length-2 (since , see Notation).
from monoprop import MajoranaPropagator, Circuit, ExpGate, MajoranaOperator
# Observable given directly as the Hermitian Majorana monomial on indices
# (0, 1, 2, 3) - a length-4 monomial, so a real coefficient.
observable = MajoranaOperator({(0, 1, 2, 3): 1.0}, 4)
# Generator i·m_3 m_4 - a length-2 monomial, so an imaginary coefficient.
generator = MajoranaOperator({(3, 4): 1j}, 4)
circuit = Circuit(initial_state=[0, 1], gates=[ExpGate(generator)], parameters=[0.3])
mp = MajoranaPropagator.from_circuit(circuit, observable, cutoff=4)
print(sorted(mp.evolved_operator().items())) # keys are Majorana indicesThe reference state
A simulation also needs a reference state, given either as a Slater determinant (a list of occupied orbitals) or a computational-basis state. Expectation values are computed against it; in the Schrödinger picture it is the state that is evolved.
The circuit
A circuit is a sequence of gates, each a Majorana rotation described by:
- the generator — the Majorana monomial defining the rotation ;
- a parameter — the angle ; and
- a parameter index — which entry of the parameter vector supplies that angle, so several gates can share one parameter.
From input to result
- Express the operator (fermionic, qubit, or Majorana) and choose a reference state.
- Construct a simulator from the operator, reference state, and truncation settings.
- Propagate the circuit to build the reusable propagated operator.
- Evaluate expectation values or gradients across many parameter values.
Steps 1-2 happen once; steps 3-4 form the inner loop of a variational optimisation, covered in Propagation Algorithm with the concrete API in Python API.