qml.from_qiskit¶
- from_qiskit(quantum_circuit, measurements=None)[source]¶
Converts a Qiskit QuantumCircuit into a PennyLane quantum function.
Note
This function depends upon the PennyLane-Qiskit plugin. Follow the installation instructions to get up and running. You may need to restart your kernel if you are running in a notebook environment.
- Parameters
quantum_circuit (qiskit.QuantumCircuit) – a quantum circuit created in Qiskit
measurements (None | MeasurementProcess | list[MeasurementProcess]) – an optional PennyLane measurement or list of PennyLane measurements that overrides any terminal measurements that may be present in the input circuit
- Returns
The PennyLane quantum function, created based on the input Qiskit
QuantumCircuit
object.- Return type
function
Example:
import pennylane as qml from qiskit import QuantumCircuit qc = QuantumCircuit(2, 2) qc.rx(0.785, 0) qc.ry(1.57, 1) my_qfunc = qml.from_qiskit(qc)
The
my_qfunc
function can now be used within QNodes, as a two-wire quantum template. We can also passwires
when calling the returned template to define which wires it should operate on. If no wires are passed, it will default to sequential wire labels starting at 0.dev = qml.device("default.qubit") @qml.qnode(dev) def circuit(): my_qfunc(wires=["a", "b"]) return qml.expval(qml.Z("a")), qml.var(qml.Z("b"))
>>> circuit() (tensor(0.70738827, requires_grad=True), tensor(0.99999937, requires_grad=True))
The measurements can also be passed directly to the function when creating the quantum function, making it possible to create a PennyLane circuit with
qml.QNode
:>>> measurements = [qml.expval(qml.Z(0)), qml.var(qml.Z(1))] >>> circuit = qml.QNode(qml.from_qiskit(qc, measurements), dev) >>> circuit() (tensor(0.70738827, requires_grad=True), tensor(0.99999937, requires_grad=True))
Note
The
measurements
keyword allows one to add a list of PennyLane measurements that will override any terminal measurements present in theQuantumCircuit
, so that they are not performed before the operations specified inmeasurements
.measurements=None
.If an existing
QuantumCircuit
already contains measurements,from_qiskit
will return those measurements, provided that they are not overriden as shown above. These measurements can be used, e.g., for conditioning withqml.cond()
, or simply included directly within the QNode’s return:qc = QuantumCircuit(2, 2) qc.rx(np.pi, 0) qc.measure_all() @qml.qnode(dev) def circuit(): # Since measurements=None, the measurements present in the QuantumCircuit are returned. measurements = qml.from_qiskit(qc)() return [qml.expval(m) for m in measurements]
>>> circuit() [tensor(1., requires_grad=True), tensor(0., requires_grad=True)]
Note
The
measurements
returned from aQuantumCircuit
are in the computational basis with 0 corresponding to \(|0\rangle\) and 1 corresponding to \(|1 \rangle\). This corresponds to the \(|1 \rangle \langle 1|\) observable rather than the \(Z\) Pauli operator.See below for more information regarding how to translate more complex circuits from Qiskit to PennyLane, including handling parametrized Qiskit circuits, mid-circuit measurements, and classical control flows.
Parametrized Quantum Circuits
A Qiskit
QuantumCircuit
is parametrized if it contains Parameter or ParameterVector references that need to be given defined values to evaluate the circuit. These can be passed to the generated quantum function as keyword or positional arguments. If we define a parametrized circuit:from qiskit.circuit import QuantumCircuit, Parameter angle0 = Parameter("x") angle1 = Parameter("y") qc = QuantumCircuit(2, 2) qc.rx(angle0, 0) qc.ry(angle1, 1) qc.cx(1, 0)
Then this circuit can be converted into a differentiable circuit in PennyLane and executed:
import pennylane as qml from pennylane import numpy as np dev = qml.device("default.qubit") qfunc = qml.from_qiskit(qc, measurements=qml.expval(qml.Z(0))) circuit = qml.QNode(qfunc, dev)
Now,
circuit
has a signature of(x, y)
. The parameters are ordered alphabetically.>>> x = np.pi / 4 >>> y = 0 >>> circuit(x, y) tensor(0.70710678, requires_grad=True)
>>> qml.grad(circuit, argnum=[0, 1])(np.pi/4, np.pi/6) (array(-0.61237244), array(-0.35355339))
The
QuantumCircuit
may also be parametrized with aParameterVector
. These can be similarly converted:from qiskit.circuit import ParameterVector angles = ParameterVector("angles", 2) qc = QuantumCircuit(2, 2) qc.rx(angles[0], 0) qc.ry(angles[1], 1) qc.cx(1, 0) @qml.qnode(dev) def circuit(angles): qml.from_qiskit(qc)(angles) return qml.expval(qml.Z(0))
>>> angles = [3.1, 0.45] >>> circuit(angles) tensor(-0.89966835, requires_grad=True)
Measurements and Classical Control Flows
When
measurement=None
, all of the measurements performed in theQuantumCircuit
will be returned by the quantum function in the form of a mid-circuit measurement. For example, if we define aQuantumCircuit
with measurements:import pennylane as qml from qiskit import QuantumCircuit qc = QuantumCircuit(2, 2) qc.h(0) qc.measure(0, 0) qc.rz(0.24, [0]) qc.cx(0, 1) qc.measure_all()
Then we can create a PennyLane circuit that uses this as a sub-circuit, and performs additional operations conditional on the results. We can also calculate standard mid-circuit measurement statistics, like expectation value, on the returned measurements:
@qml.qnode(qml.device("default.qubit")) def circuit(): # apply the QuantumCircuit and retrieve the measurements mid_measure0, m0, m1 = qml.from_qiskit(qc)() # conditionally apply an additional operation based on the results qml.cond(mid_measure0==0, qml.RX)(np.pi/2, 0) # return the expectation value of one of the mid-circuit measurements, and a terminal measurement return qml.expval(mid_measure0), qml.expval(m1)
>>> circuit() (tensor(0.5, requires_grad=True), tensor(0.5, requires_grad=True))
Note
The order of mid-circuit measurements returned by qml.from_qiskit() in the example above is determined by the order in which measurements appear in the input Qiskit
QuantumCircuit
.Furthermore, the Qiskit IfElseOp, SwitchCaseOp and c_if conditional workflows are automatically translated into their PennyLane counterparts during conversion. For example, if we construct a
QuantumCircuit
with these workflows:qc = QuantumCircuit(4, 1) qc.h(0) qc.measure(0, 0) # Use an `IfElseOp` operation. noop = QuantumCircuit(1) flip_x = QuantumCircuit(1) flip_x.x(0) qc.if_else((qc.clbits[0], True), flip_x, noop, [1], []) # Use a `SwitchCaseOp` operation. with qc.switch(qc.clbits[0]) as case: with case(0): qc.y(2) # Use the `c_if()` function. qc.z(3).c_if(qc.clbits[0], True) qc.measure_all()
We can convert the
QuantumCircuit
into a PennyLane quantum function using:dev = qml.device("default.qubit") measurements = [qml.expval(qml.Z(i)) for i in range(qc.num_qubits)] cond_circuit = qml.QNode(qml.from_qiskit(qc, measurements=measurements), dev)
The result is:
>>> print(qml.draw(cond_circuit)()) 0: ──H──┤↗├──────────╭||─┤ <Z> 1: ──────║───X───────├||─┤ <Z> 2: ──────║───║──Y────├||─┤ <Z> 3: ──────║───║──║──Z─╰||─┤ <Z> ╚═══╩══╩══╝