Integrate with Qiskit
pyrauli offers seamless integration with Qiskit. This guide provides
recipes for common integration tasks.
Convert Qiskit objects to pyrauli objects
The from_qiskit function converts Qiskit QuantumCircuit and SparsePauliOp objects to their pyrauli equivalents.
# 1. Define a simple Qiskit circuit (Bell state)
qc_qiskit = QuantumCircuit(2)
qc_qiskit.h(0)
qc_qiskit.cx(0, 1)
# 2. Convert it to a pyrauli.Circuit
qc_converted = from_qiskit(qc_qiskit)
Warning
from_qiskit() only works if your circuit doesn’t require transpilation (i.e. only use gates compatible with Circuit). For more complex circuits, refer to the section below.
Use pyrauli as a Qiskit-compatible backend
The PBackend class allows you to use pyrauli as a backend within the
Qiskit ecosystem, enabling you to transpile and run circuits defined in Qiskit on the
pyrauli simulator.
Important
If your Qiskit circuit uses unsupported gates, you need to transpile it, as you would for any other backend.
Here is an example of transpilation to PBackend, relying on Qiskit PassManager:
backend = PBackend(num_qubits=2)
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
# Circuit with gates not in the basis set of pyrauli backend
qc = QuantumCircuit(2)
qc.rx(np.pi / 2, 0)
qc.sdg(1)
transpiled_qc = pm.run(qc) # Qiskit circuit compatible with pyrauli
And how to run it on the backend:
result = backend.run([(transpiled_qc, SparsePauliOp("XI"))]).result()
ev = result[0].data.evs[0]
Note that at this stage you could also call from_qiskit on transpiled_qc directly.
Use the PyrauliEstimator Qiskit Primitive
For modern, algorithm-focused development, the PyrauliEstimator provides a BaseEstimatorV2 primitive that uses the pyrauli simulator under
the hood.
estimator = PyrauliEstimator()
thetas = ParameterVector("theta", 2)
qc = QuantumCircuit(2)
qc.h([0, 1])
qc.rz(thetas[0], 0)
qc.rz(thetas[1], 1)
qc.h([0, 1])
observables = [SparsePauliOp("IZ"), SparsePauliOp("ZI")]
job = estimator.run([(qc, observables, (np.pi/2, np.pi/3)), (qc, observables, (np.pi/3, np.pi/2))])
result = job.result()
Full PUBs support
pyrauli intends to be fully compatible with Qiskit and the provided backends and estimators should be able to be swapped with any other qiskit backend. Therefore, PyrauliEstimator and PBackend .run methods allows for any PUB (see Qiskit documentation on PUBs https://qiskit.qotlabs.org/docs/guides/primitive-input-output).
Below is an example of what is possible:
backend = PBackend(num_qubits=2)
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.ry(Parameter("a"), 0)
circuit.rz(Parameter("b"), 0)
circuit.cx(0, 1)
circuit.h(0)
transpiled_circuit = pm.run(circuit)
params = np.vstack(
[
np.linspace(-np.pi, np.pi, 100),
np.linspace(-4 * np.pi, 4 * np.pi, 100),
]
).T
observables = [
[SparsePauliOp(["XX", "IY"], [0.5, 0.5])],
[SparsePauliOp("XX")],
[SparsePauliOp("IY")],
]
estimator_pub = (transpiled_circuit, observables, params)
job = backend.run([estimator_pub])
result = job.result()
Qiskit and reverse qubit ordering
Qiskit uses reverse qubit ordering, while pyrauli use normal ordering. from_qiskit will not reverse the order of the qubit or Observable unless the reverse=True parameter is used.
However, when a qiskit observable is passed to the .run method, it will be reversed so that the output result match the output you would get on any other qiskit backend.
Important
You don’t need to do anything different if using the qiskit compatible backend and qiskit observable. However, you may need to reverse the observable ordering when using Circuit and from_qiskit directly.