F2FSynthesis¶
- class F2FSynthesis(config=None, *, apply=True, filter=None)¶
Bases:
GenericPass[DAGCircuit,DAGCircuit]A transpilation pass breaking gates down into smaller ones in fermionic space.
Some gates can be rewritten into a circuit of smaller fermionic gates before they reach the fermion-to-qubit stage, which then maps and synthesizes those. This pass does that for the gates named in
methods, with the plugin thatmethodsnames for each, so the choice is made once for a whole transpilation pipeline instead of gate by gate. It is the fermionic counterpart ofF2QSynthesis, one stage earlier: where that pass maps every instruction to qubits, this one rewrites some gates into others and leaves the rest as they are.pm.optimization = FermionicPassManager( [ MergeOrbitalRotations(), MergeSlaterDeterminantPreparation(), F2FSynthesis({"OrbitalRotation": "Givens", "PrepareSlaterDeterminant": "Givens"}), ] )
Usage
There are two ways to configure the plugins used by this transpiler pass:
Providing a
configduring initialization:>>> from qiskit_fermions.transpiler import passes >>> >>> config = {"Evolution": ("SuzukiTrotter", (), {"order": 2})} >>> synth = passes.F2FSynthesis(config)
Manually populating the
methodsattribute:>>> from qiskit_fermions.circuit.library import synthesis >>> from qiskit_fermions.transpiler import passes >>> >>> synth = passes.F2FSynthesis() >>> synth.methods["Evolution"] = synthesis.FermionicSuzukiTrotter(order=2)
Through this manual approach it is also possible to inject custom
F2FSynthesisPluginimplementations without requiring them to be registered through an entry-point.
It belongs in the
optimizationstage, ahead of the layout and the synthesis, and after the passes that consume these gates as such. Placing it earlier would break the gates up before those passes can fuse them, which silently gives up the cheaper Slater-determinant decomposition (seeMergeSlaterDeterminantPreparation).Each selected gate is replaced by the circuit that its plugin produces. A gate whose type is not a key of
methodsis left untouched, as is any gate that isatomic(also withapply=False: it is not even tagged with the plugin) and any node rejected by an optionalfilter. A gate that has no synthesis at all, such as anInitializeModes, passes through no matter what.Important
What the replacement is equivalent to is specified by the gate and its plugin, not by this pass: usually it implements the same unitary (or approximates it), but a gate may specify less, and then only a circuit that meets that weaker specification may use this pass. Consult the documentation of the gates you configure, and see
F2FSynthesisPlugin.Note
Running the pass again is harmless: the factors a plugin emits are
atomic, and an atomic gate is a terminal factor which this pass leaves in place rather than splitting further. The same exemption makes the pass a fixed point over the output ofQDriftTrotterization, whose sampled gates are atomic because the random draw is the Trotterization it performs.Note
Set
applytoFalseto only select the method and leave the expansion to something else, such as adecompose()call. Be aware that a gate which is never expanded reaches the fermion-to-qubit stage whole, where it is mapped without itssynthesisever being read, and every method then produces identical output.Caution
Not every method suits every operator. An
Evolutionwhose operator groups all mutually commute (the diagonal-Coulomb operators of aUCJ, for example) is synthesized exactly at any order, so a higher order only adds depth. Usefilterto restrict the pass to the gates that benefit.Expanding an operator that carries no
groupssplits it term by term, and a lone hopping term \(a^\dagger_i a_j\) is not Hermitian, so its exponential is not unitary. Nothing complains until the mapped operator reachesPauliEvolutionGate, which raisesValueError: Operator contains complex coefficients, which are not supported. Assigning conjugate-paired groups is what makes each factor Hermitian; seegroups_are_hermitian().Initializing this transpiler pass can be done with the arguments listed below.
- Parameters:
config (F2FSynthesisConfig | None) – an optional dictionary to pre-populate the
methodswith plugins provided by theF2FSynthesisPluginManager. SeeF2FSynthesisConfig.apply (bool) – whether to expand each selected gate into the factors its plugin produces. When
False, the gate is only tagged with the plugin (unless it is atomic, which is never touched) and something else has to expand it later. Seeapply.filter (Callable[[DAGOpNode], bool] | None) – an optional predicate deciding which nodes to break down. It is called with the
DAGOpNodeof a gate whose type is inmethods, and the node is left untouched unless it returnsTrue. IfNone(the default), every such node is selected.
- Raises:
Attributes
- methods: dict[str, F2FSynthesisPlugin]¶
A dictionary of the fermion-to-fermion synthesis methods, by gate.
The keys of this dictionary correspond to the
__name__of aFermionicGate, and the values are instances of theF2FSynthesisPluginprotocol. A gate that is not a key is not touched by this pass, so the dictionary is empty by default, which makes the pass do nothing. Pre-populate it with plugins provided by theF2FSynthesisPluginManagerthrough theconfigargument.
- apply¶
Whether to expand each selected gate into the factors its plugin produces.
When this is
False, the pass only selects the method: it tags each selected gate with its plugin (seeFermionicGate.with_synthesis()), except anatomicgate, which is left as it is, and leaves the expansion to whatever builds the gate’s definition later, such as adecompose()call. Note that a gate which is never expanded reaches the fermion-to-qubit stage whole, where it is mapped without itssynthesisever being read.
- filter¶
The predicate selecting which nodes to break down.
Methods
- run(dag)¶
Runs this transpilation pass.
Every node whose gate type is in
methodsand that is accepted byfilteris replaced by the gates that its plugin produces, or (whenapplyisFalse) by an equivalent gate merely carrying the plugin. All other nodes are left untouched. The input DAG is modified in place.- Parameters:
dag (DAGCircuit) – the input circuit with fermion-based instructions. Only
DAGOpNodewithFermionicGateinstances as theiropare supported, plusBarrierandFermionicMeasure, which are carried through untouched (a measurement keeps the classical bit it writes into).- Returns:
The output circuit which is still acting on a fermionic register.
- Return type:
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]
- 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: