B2BSynthesis¶
- class B2BSynthesis(config=None, *, apply=True, filter=None)¶
Bases:
GenericPass[DAGCircuit,DAGCircuit]A transpilation pass breaking gates down into smaller ones in bosonic space.
Some gates can be rewritten into a circuit of smaller bosonic gates before they reach the boson-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 bosonic counterpart ofB2QSynthesis, 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 = BosonicPassManager( [ B2BSynthesis( { "Evolution": ("SuzukiTrotter", (), {"order": 2, "reps": 4}), "ModeRotation": "Clements", } ) ] )
Usage
There are two ways to configure the plugins used by this transpiler pass:
Providing a
configduring initialization:>>> from qiskit_bosons.transpiler import passes >>> >>> config = {"Evolution": ("SuzukiTrotter", (), {"order": 2})} >>> synth = passes.B2BSynthesis(config)
Manually populating the
methodsattribute:>>> from qiskit_bosons.circuit.library import synthesis >>> from qiskit_bosons.transpiler import passes >>> >>> synth = passes.B2BSynthesis() >>> synth.methods["Evolution"] = synthesis.BosonicSuzukiTrotter(order=2)
Through this manual approach it is also possible to inject custom
B2BSynthesisPluginimplementations without requiring them to be registered through an entry-point.
It belongs in the
optimizationstage, ahead of the layout and the synthesis. The method named here takes precedence over thesynthesisof an individual gate. To use the synthesis of the gates themselves instead, leave this pass out and calldecompose().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.This is where the grouping of the operator pays off for the outer Trotter error. A product formula handed to
MapperFnEvolutionSynthesisonly subdivides the terms within a single group and never interleaves the groups, so raising its repetition count does not reduce the error between groups that do not commute. A formula applied here splits along the groups themselves.Nothing in this step depends on the truncation or the encoding, which only enter later. The same decomposition therefore serves every
LevelSpec. SeeBosonicClementsDecompositionfor what it implies for the cutoff.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 ofBosonicQDrift, 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 Qiskit’sDecomposeor adecompose()call. Be aware that a gate which is never expanded reaches the boson-to-qubit stage whole, where it is mapped without itssynthesisever being read, and every method then produces identical output.Note
Decomposing is a choice, not a requirement. A
ModeRotationthat is left whole is lowered by a boson-to-qubit synthesis plugin registered for it, if there is one; see Lower a rotation without decomposing it.Caution
Not every method suits every operator. An
Evolutionwhose operator groups all mutually commute (a Hamiltonian made only of number operators, say) 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 \(b^\dagger_i b_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 (B2BSynthesisConfig | None) – an optional dictionary to pre-populate the
methodswith plugins provided by theB2BSynthesisPluginManager. SeeB2BSynthesisConfig.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, B2BSynthesisPlugin]¶
A dictionary of the boson-to-boson synthesis methods, by gate.
The keys of this dictionary correspond to the
__name__of aBosonicGate, and the values are instances of theB2BSynthesisPluginprotocol. 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 theB2BSynthesisPluginManagerthrough 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 (seeBosonicGate.with_synthesis()), except anatomicgate, which is left as it is, and leaves the expansion to whatever builds the gate’s definition later, such as Qiskit’sDecomposeor adecompose()call. Note that a gate which is never expanded reaches the boson-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 boson-based instructions. Only
DAGOpNodewithBosonicGateinstances as theiropare supported, plusBarrier, which is carried through untouched.- Returns:
The output circuit which is still acting on a bosonic 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: