Introduction to Rivet Transpiler¶
Quantum Transpilation is the transformation of a given virtual quantum circuit:
to match the topology of a specific device
to optimize the circuit for execution
Rivet gives the User a high level of insight into, and control over the transpilation process, including the – typically invisible to the user – use of quantum resources, such as auxiliary qubits used in various transpilation passes, which can be constrained via the Qubit-Constrained Transpilation function. Combined with a debugging interface it allows to optimize the classical and quantum compute involved in the execution and shorten the development loop, especially in research and prototyping.
1. Basic Example¶
Transpilation includes placement of virtual qubits of a circuit to physical qubits of the quantum device or simulator. Additionally, SWAP gates can be included to route qubits around the backend topology.
Here we present a simple quantum circuit with 3 qubits before and after transpilation (using the function transpile_chain
which transpiles a chain of virtual circuits keeping qubits consistent).
BEFORE transpilation¶
from qiskit import QuantumCircuit
from qiskit_ibm_runtime.fake_provider import FakeLimaV2
from rivet_transpiler import transpile_chain
backend = FakeLimaV2()
circuit = QuantumCircuit(3)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.cx(0, 2)
circuit.barrier()
circuit.draw()
q_0: ──■─────────■──
┌─┴─┐ │
q_1: ┤ X ├──■────┼──
└───┘┌─┴─┐┌─┴─┐
q_2: ─────┤ X ├┤ X ├
└───┘└───┘
AFTER transpilation¶
CHAIN = [circuit] * 3
transpiled_circuit = transpile_chain(
CHAIN,
backend,
seed_transpiler=1234
)
transpiled_circuit.draw(fold=-1)
┌───┐ ░ ┌───┐ ░ ┌───┐ ┌───┐ ┌───┐ ░
q_1 -> 0 ──■─────────■──┤ X ├──■────────░─┤ X ├─────────────────■────────░───■──┤ X ├──■───────┤ X ├───────────────┤ X ├─░─
┌─┴─┐ ┌─┴─┐└─┬─┘┌─┴─┐ ░ └─┬─┘┌───┐ ┌───┐┌─┴─┐┌───┐ ░ ┌─┴─┐└─┬─┘┌─┴─┐┌───┐└─┬─┘┌───┐ ┌───┐└─┬─┘ ░
q_2 -> 1 ┤ X ├──■──┤ X ├──■──┤ X ├──■───░───■──┤ X ├──■──┤ X ├┤ X ├┤ X ├─░─┤ X ├──■──┤ X ├┤ X ├──■──┤ X ├──■──┤ X ├──■───░─
└───┘┌─┴─┐└───┘ └───┘┌─┴─┐ ░ └─┬─┘┌─┴─┐└─┬─┘└───┘└─┬─┘ ░ └───┘ └───┘└─┬─┘ └─┬─┘┌─┴─┐└─┬─┘ ░
q_0 -> 2 ─────┤ X ├───────────────┤ X ├─░────────■──┤ X ├──■─────────■───░──────────────────■─────────■──┤ X ├──■────────░─
└───┘ └───┘ ░ └───┘ ░ └───┘ ░
ancilla_0 -> 3 ────────────────────────────────────────────────────────────────░───────────────────────────────────────────────░─
░ ░
ancilla_1 -> 4 ────────────────────────────────────────────────────────────────░───────────────────────────────────────────────░─
░ ░
2. Transpilation Stages¶
Pass Manager is an internal Qiskit object constructed by the transpile
function “under the hood” during transpilation. Pass Manager consists of Passes which analyse or change the transpiled circuit. Calling pass_manager.run
is equivalent to calling transpile
and passing a circuit, backend and corresponding transpilation parameters.
[1]:
import qiskit
pass_manager = qiskit.transpiler.preset_passmanagers.generate_preset_pass_manager(
# backend=backend,
# initial_layout=[1, 0, 2],
optimization_level=3,
seed_transpiler=1234
)
Calling pass_manager.stages
the main transpilation stages can be displayed: (‘init’, ‘layout’, ‘routing’, ‘translation’, ‘optimization’, ‘scheduling’)
Init - Unrolling custom instructions and converting the circuit to all 1 and 2 qubit gates.
Layout - Mapping circuit virtual qubits to backend physical qubits.
Routing - Inject SWAP gates to comply with the backend’s coupling map.
Translation - Translate to the target backend’s basis gate set.
Optimization - Main optimization loop to increase circuit quality.
Scheduling - Conversion to hardware-specific pulses.
The Rivet Transpiler package provides a family of functions (transpile and service functions) for the efficient transpilation of quantum circuits. Check API Reference
section for more details.
3. Supported Stacks¶
Flexible Stack Selection: Users can transpile their entire circuit, or parts of a circuit, via one or a combination of transpilation passes from different stacks of their preference. This allows one to choose the optimal transpiling strategy for the given use case and circuit architecture. Supported stacks include:
Qiskit transpilation
Pytket transpilation
BQSKit QSearch synthesis
BQSKit QFactor instantiation
Make sure you have followed and installed Rivet Transpiler. Check the installation steps from Readme.md. Then import Qiskit, other modules required for the example execution and Rivet Transpiler functions.
Stacks Usage¶
[2]:
from rivet_transpiler import transpile
from rivet_transpiler import get_litmus_circuit
from qiskit_ibm_runtime.fake_provider import FakeLimaV2
backend = FakeLimaV2()
QUBITS_COUNT = 3
litmus_circuit = get_litmus_circuit(QUBITS_COUNT, "Litmus")
litmus_circuit.draw()
[2]:
┌──────────────┐ ┌───┐ Litmus Litmus_0_0: ┤ Rz(Litmus_0) ├──■───────┤ X ├───░──── ├──────────────┤┌─┴─┐ └─┬─┘ ░ Litmus_0_1: ┤ Rz(Litmus_1) ├┤ X ├──■────┼─────░──── ├──────────────┤└───┘┌─┴─┐ │ ░ Litmus_0_2: ┤ Rz(Litmus_2) ├─────┤ X ├──■─────░──── └──────────────┘ └───┘ ░
[3]:
STACKS = ["qiskit",
"qiskit_qsearch",
"qiskit_qfactor_qsearch",
"qiskit_pytket"]
Qiskit¶
[4]:
transpiled_circuit = transpile(
litmus_circuit,
backend,
stack="qiskit",
seed_transpiler=1234)
transpiled_circuit.draw()
[4]:
┌──────────────┐ ┌───┐ ┌───┐ Litmus Litmus_0_2 -> 0 ┤ Rz(Litmus_2) ├───────■──┤ X ├──■───────┤ X ├───░──── ├──────────────┤ ┌─┴─┐└─┬─┘┌─┴─┐┌───┐└─┬─┘ ░ Litmus_0_0 -> 1 ┤ Rz(Litmus_0) ├──■──┤ X ├──■──┤ X ├┤ X ├──■─────░──── ├──────────────┤┌─┴─┐└───┘ └───┘└─┬─┘ ░ Litmus_0_1 -> 2 ┤ Rz(Litmus_1) ├┤ X ├─────────────────■──────────░──── └──────────────┘└───┘ ░ ancilla_0 -> 3 ────────────────────────────────────────────────────── ancilla_1 -> 4 ──────────────────────────────────────────────────────
Pytket¶
[5]:
transpiled_circuit = transpile(
litmus_circuit,
backend,
stack="qiskit_pytket",
seed_transpiler=1234)
transpiled_circuit.draw()
[5]:
┌──────────────┐ ┌───┐ ┌───┐ ░ Litmus_0_2 -> 0 ┤ Rz(Litmus_2) ├───────■──┤ X ├──■───────┤ X ├─░─ ├──────────────┤ ┌─┴─┐└─┬─┘┌─┴─┐┌───┐└─┬─┘ ░ Litmus_0_0 -> 1 ┤ Rz(Litmus_0) ├──■──┤ X ├──■──┤ X ├┤ X ├──■───░─ ├──────────────┤┌─┴─┐└───┘ └───┘└─┬─┘ ░ Litmus_0_1 -> 2 ┤ Rz(Litmus_1) ├┤ X ├─────────────────■────────░─ └──────────────┘└───┘ ░ ancilla_0 -> 3 ───────────────────────────────────────────────── ancilla_1 -> 4 ─────────────────────────────────────────────────