QDriftTrotterization

class QDriftTrotterization(num_terms, *, filter_trivial=False, rng=None)

Bases: GenericPass[DAGCircuit, DAGCircuit]

A transpilation pass to Trotterize Evolution gates via the qDRIFT protocol.

This pass replaces the exact evolution \(e^{-i t H}\) of each Evolution gate by a randomized product formula: it draws num_terms samples from the Hamiltonian’s terms (or groups, if assigned), with each term sampled with a probability proportional to the magnitude of its coefficient, and emits one Evolution gate per sample. Every sampled gate evolves its (unit-magnitude, sign-preserving) term for the same time

\[\delta = \frac{\lambda t}{\texttt{num\_terms}}, \qquad \lambda = \sum_j |c_j|,\]

where the \(c_j\) are the coefficients of the sampled terms/groups. The ordered product of the sampled evolutions does not reproduce \(e^{-i t H}\) exactly; rather, its expectation over the sampling approximates the exact evolution, with an error that decreases as num_terms grows. Because the output depends on the random draws, it differs from run to run unless a fixed rng is supplied.

Hint

Terms that are diagonal in the occupation-number basis (i.e. products of number operators) have no effect on the sampled bitstrings, so including them only increases the sampling overhead. Filter them out with filter_diagonal_terms() on the Hamiltonian before constructing the Evolution gate, rather than on every call to run(): this pass runs once per transpiled circuit, so filtering upstream avoids repeating the same filtering work for every circuit generated from the same Hamiltonian.

See also

The qDRIFT protocol was introduced in arXiv:1811.08017.

Initializing this transpiler pass can be done with the arguments listed below.

Parameters:
  • num_terms (int) – the number of terms to sample for the qDRIFT Trotterization. This equals the number of Evolution gates emitted per input gate; a larger value reduces the Trotterization error at the cost of a deeper circuit.

  • filter_trivial (bool) – when set to True, the sampling loop rejects a sampled term unless it couples a mode known to be occupied with a mode known to be unoccupied. Any term acting only within one of these two sets cannot change the occupation and, thus, has no effect on a sampled bitstring, so re-drawing avoids wasting one of the num_terms slots on it. This requires an InitializeModes or PrepareSlaterDeterminant gate to precede the Evolution gates being Trotterized (to seed the initial occupied and unoccupied mode sets); if none is found, or if the mode sets it seeds turn out to be entirely occupied or entirely unoccupied, filtering is skipped for that gate and a UserWarning is emitted instead. Any OrbitalRotation gate encountered before or between the Evolution gates also updates these sets: every mode it acts on becomes “uncertain” (since the rotation may mix it with any other mode it touches), just like a mode touched by an accepted qDRIFT term. A PrepareSlaterDeterminant gate updates these sets the same way its InitializeModes and OrbitalRotation components would if applied in sequence: it seeds the occupied/unoccupied sets from its occupation, then immediately marks every mode it acts on as “uncertain” because of its rotation. See the run() docstring for the precise acceptance rule.

  • rng (np.random.Generator | int | None) – the random number generator (rng) to be used. When this is an int, the internal rng will be initialized with np.random.default_rng(seed=rng).

Attributes

MAX_SAMPLE_RETRIES = 1000000

The maximum number of consecutive rejected samples tolerated by filter_trivial before run() gives up and raises RuntimeError. This guards against an infinite loop when the Hamiltonian’s remaining terms cannot bridge the tracked occupied/unoccupied mode sets — for example, when both sets remain small and disjoint (few modes have been marked occupied or unoccupied, and none have yet become “uncertain”) and no remaining term’s support touches both.

num_terms

The number of terms to include in the qDRIFT Trotterization.

filter_trivial

Whether to reject sampled terms that cannot affect the sampled bitstring (see the class docstring for the filter_trivial argument).

Methods

run(dag)

Runs this transpilation pass.

Each Evolution node is replaced by num_terms sampled single-term Evolution gates (see the class docstring). Nodes that are not Evolution gates are copied to the output unchanged. Since the sampling is random, the output varies between runs unless the rng was seeded.

When filter_trivial is set, this method tracks the sets of modes that are known to be occupied or unoccupied, seeded from any InitializeModes gate(s) preceding the Evolution gates in the circuit (several such gates placed in parallel, e.g. one per spin sector, are accumulated together). A sampled term is only accepted if its support intersects both sets, i.e. it couples a known-occupied mode with a known-unoccupied one; otherwise it is discarded and re-sampled, since it cannot affect the sampled bitstring. Once a term is accepted, every mode in its support becomes “uncertain” and is added to both sets, making it eligible to participate in either role for subsequent samples. Any OrbitalRotation gate found in the circuit updates these sets the same way: every mode it acts on becomes “uncertain” too, since the rotation may mix it with any other mode in its support. A PrepareSlaterDeterminant gate is treated as its InitializeModes and OrbitalRotation components applied back-to-back: its occupation first seeds the occupied/unoccupied sets, and then every mode it acts on is immediately marked “uncertain”, since it also carries a rotation.

Parameters:

dag (DAGCircuit) – the input circuit with fermion-based instructions. Only DAGOpNode with FermionicGate instances as their op are supported.

Returns:

The output circuit which is still acting on a fermionic register.

Raises:

RuntimeError – if filter_trivial is True and MAX_SAMPLE_RETRIES consecutive samples are rejected without finding a non-trivial term to emit.

Return type:

DAGCircuit

Inherited Methods

execute(passmanager_ir, state, callback=None)

Execute optimization task for input Qiskit IR.

Parameters:
  • passmanager_ir (IR) – Qiskit IR to optimize.

  • state (PassManagerState) – State associated with workflow execution by the pass manager itself.

  • callback (Callable[[Task, IR_OUT, PropertySet, float, int], None] | None) – A callback function which is called per execution of optimization task.

Returns:

Optimized Qiskit IR and state of the workflow.

Return type:

tuple[IR_OUT, PassManagerState]

name()

Name of the pass.

Return type:

str

update_status(state, run_state)

Update workflow status.

Parameters:
  • state (PassManagerState) – Pass manager state to update.

  • run_state (RunState) – Completion status of current task.

Returns:

Updated pass manager state.

Return type:

PassManagerState