Transpiling fermionic circuits¶
Important
The concepts in this guide are currently available only in the Python API. Equivalent functionality will be made available via the C API in a future release.
This guide explains how to transpile a FermionicCircuit to a standard
QuantumCircuit. We continue with the same time evolution
example from the fermionic circuits guide.
Transpilation stages¶
The FermionicStagedPassManager splits transpilation into four stages:
- Optimization
Fermionic-level optimizations that keep the circuit in fermionic space. These passes exploit fermionic structure and commutation relations while problem-aware knowledge remains fully available.
- Layout
Maps fermionic mode registers to quantum registers. For occupation-basis mappings like Jordan-Wigner, each fermionic mode maps to a single qubit. This stage also supports more general mappings where the number of qubits differs from the number of fermionic modes.
- Synthesis
Converts fermionic gates to qubit operations by using the chosen fermion-to-qubit mapping.
FermionicGateinstances are transformed into sequences of standard quantum gates.- Quantum
Standard Qiskit transpilation on the resulting qubit circuit, including optimization, layout, and routing for your target hardware.
A practical example: transpilation using Jordan-Wigner¶
Use the preset pass manager to transpile your fermionic circuit with the Jordan-Wigner fermion-to-qubit mapping:
>>> from qiskit_fermions.circuit import FermionicCircuit
>>> from qiskit_fermions.circuit.library import Evolution
>>> from qiskit_fermions.operators import FermionOperator, cre, ann
>>> from qiskit_fermions.transpiler.presets import generate_preset_jw_pass_manager
>>>
>>> # Create the same fermionic circuit from the previous guide
>>> circuit = FermionicCircuit(4)
>>> hamiltonian = FermionOperator.from_terms([
... ([cre(0), ann(2)], 0.5),
... ([cre(2), ann(0)], 0.5),
... ([cre(1), ann(3)], 0.5),
... ([cre(3), ann(1)], 0.5),
... ])
>>> hamiltonian.groups = [0, 0, 1, 1]
>>> evolution = Evolution(4, hamiltonian, time=1.0)
>>> circuit.append(evolution, circuit.register)
>>>
>>> # Generate the Jordan-Wigner transpilation pipeline
>>> pm = generate_preset_jw_pass_manager()
>>>
>>> # Transpile the fermionic circuit to a qubit circuit
>>> qubit_circuit = pm.run(circuit)
>>>
>>> # The result is a standard QuantumCircuit
>>> print(type(qubit_circuit))
<class 'qiskit.circuit.quantumcircuit.QuantumCircuit'>
// The C API for transpilation will be made available in a future release.
Compare with the traditional workflow¶
The fermionic circuits guide describes
how the traditional workflow performs fermion-to-qubit encoding before
building the QuantumCircuit. Compare the two
approaches:
>>> from qiskit_fermions.mappers.library import jordan_wigner
>>> from qiskit.circuit import QuantumCircuit
>>> from qiskit.circuit.library import PauliEvolutionGate
>>>
>>> # Map the fermionic Hamiltonian to a qubit operator
>>> qubit_hamiltonian = jordan_wigner(hamiltonian, 4).simplify()
>>>
>>> # Build the QuantumCircuit directly
>>> quantum_circuit = QuantumCircuit(4)
>>> pauli_evolution = PauliEvolutionGate(qubit_hamiltonian, time=1.0)
>>> quantum_circuit.append(pauli_evolution, quantum_circuit.qubits)
<qiskit.circuit.instructionset.InstructionSet object at ...>
Both workflows produce equivalent circuits. However, the traditional workflow requires you to implement optimization steps manually, whereas the fermionic-first approach allows you to integrate problem-aware optimizations into the transpilation process.
Advanced workflows¶
The preset pass manager provides a convenient starting point. For more advanced use cases, you can:
Customize the transpiler passes run during each stage.
Implement custom fermion-to-qubit mappings by creating synthesis plugins (see
F2QSynthesisPlugin).Build custom transpiler passes.