qml.cond¶
-
cond
(condition, true_fn=None, false_fn=None, elifs=())[source]¶ Quantum-compatible if-else conditionals — condition quantum operations on parameters such as the results of mid-circuit qubit measurements.
This method is restricted to simply branching on mid-circuit measurement results when it is not used with the
qjit()
decorator.When used with the
qjit()
decorator, this function allows for general if-elif-else constructs. Alltrue_fn
,false_fn
andelifs
branches will be captured by Catalyst, the just-in-time (JIT) compiler, with the executed branch determined at runtime. For more details, please seecatalyst.cond()
.Note
With the Python interpreter, support for
cond()
is device-dependent. If a device doesn’t support mid-circuit measurements natively, then the QNode will apply thedefer_measurements()
transform.Note
When used with
qjit()
, this function only supports the Catalyst compiler. Seecatalyst.cond()
for more details.Please see the Catalyst quickstart guide, as well as the sharp bits and debugging tips.
Note
When used with
pennylane.capture.enabled()
, this function allows for general if-elif-else constructs. As with the JIT mode, all branches are captured, with the executed branch determined at runtime.Each branch can receive arguments, but the arguments must be JAX-compatible. If a branch returns one or more variables, every other branch must return the same abstract values.
- Parameters
condition (Union[MeasurementValue, bool]) – a conditional expression that may involve a mid-circuit measurement value (see
pennylane.measure()
).true_fn (callable) – The quantum function or PennyLane operation to apply if
condition
isTrue
false_fn (callable) – The quantum function or PennyLane operation to apply if
condition
isFalse
elifs (Sequence(Tuple(bool, callable))) – A sequence of (bool, elif_fn) clauses. Can only be used when decorated by
qjit()
or if the condition is not a mid-circuit measurement.
- Returns
A new function that applies the conditional equivalent of
true_fn
. The returned function takes the same input arguments astrue_fn
.- Return type
function
Example
dev = qml.device("default.qubit", wires=3) @qml.qnode(dev) def qnode(x, y): qml.Hadamard(0) m_0 = qml.measure(0) qml.cond(m_0, qml.RY)(x, wires=1) qml.Hadamard(2) qml.RY(-np.pi/2, wires=[2]) m_1 = qml.measure(2) qml.cond(m_1 == 0, qml.RX)(y, wires=1) return qml.expval(qml.Z(1))
>>> first_par = np.array(0.3) >>> sec_par = np.array(1.23) >>> qnode(first_par, sec_par) tensor(0.32677361, requires_grad=True)
Note
If the first argument of
cond
is a measurement value (e.g.,m_0
inqml.cond(m_0, qml.RY)
), thenm_0 == 1
is considered internally.Warning
Expressions with boolean logic flow using operators like
and
,or
andnot
are not supported as thecondition
argument.While such statements may not result in errors, they may result in incorrect behaviour.
In just-in-time (JIT) mode using the
qjit()
decorator,dev = qml.device("lightning.qubit", wires=1) @qml.qjit @qml.qnode(dev) def circuit(x: float): def ansatz_true(): qml.RX(x, wires=0) qml.Hadamard(wires=0) def ansatz_false(): qml.RY(x, wires=0) qml.cond(x > 1.4, ansatz_true, ansatz_false)() return qml.expval(qml.Z(0))
>>> circuit(1.4) Array(0.16996714, dtype=float64) >>> circuit(1.6) Array(0., dtype=float64)
Additional ‘else-if’ clauses can also be included via the
elif
argument:@qml.qjit @qml.qnode(dev) def circuit(x): def true_fn(): qml.RX(x, wires=0) def elif_fn(): qml.RY(x, wires=0) def false_fn(): qml.RX(x ** 2, wires=0) qml.cond(x > 2.7, true_fn, false_fn, ((x > 1.4, elif_fn),))() return qml.expval(qml.Z(0))
>>> circuit(1.2) Array(0.13042371, dtype=float64)
Note
If the above syntax is used with a
QNode
that is not decorated withqjit()
and none of the predicates contain mid-circuit measurements,qml.cond
will fall back to using native Pythonif
-elif
-else
blocks.Usage Details
Conditional quantum functions
The
cond
transform allows conditioning quantum functions too:dev = qml.device("default.qubit") def qfunc(par, wires): qml.Hadamard(wires[0]) qml.RY(par, wires[0]) @qml.qnode(dev) def qnode(x): qml.Hadamard(0) m_0 = qml.measure(0) qml.cond(m_0, qfunc)(x, wires=[1]) return qml.expval(qml.Z(1))
>>> par = np.array(0.3) >>> qnode(par) tensor(0.3522399, requires_grad=True)
Postprocessing multiple measurements into a condition
The Boolean condition for
cond
may consist of arithmetic expressions of one or multiple mid-circuit measurements:def cond_fn(mcms): first_term = np.prod(mcms) second_term = (2 ** np.arange(len(mcms))) @ mcms return (1 - first_term) * (second_term > 3) @qml.qnode(dev) def qnode(x): ... mcms = [qml.measure(w) for w in range(4)] qml.cond(cond_fn(mcms), qml.RX)(x, wires=4) ... return qml.expval(qml.Z(1))
Passing two quantum functions
In the qubit model, single-qubit measurements may result in one of two outcomes. Such measurement outcomes may then be used to create conditional expressions.
According to the truth value of the conditional expression passed to
cond
, the transform can apply a quantum function in both theTrue
andFalse
case:dev = qml.device("default.qubit", wires=2) def qfunc1(x, wires): qml.Hadamard(wires[0]) qml.RY(x, wires[0]) def qfunc2(x, wires): qml.Hadamard(wires[0]) qml.RZ(x, wires[0]) @qml.qnode(dev) def qnode1(x): qml.Hadamard(0) m_0 = qml.measure(0) qml.cond(m_0, qfunc1, qfunc2)(x, wires=[1]) return qml.expval(qml.Z(1))
>>> par = np.array(0.3) >>> qnode1(par) tensor(-0.1477601, requires_grad=True)
The previous QNode is equivalent to using
cond
twice, inverting the conditional expression in the second case using the~
unary operator:@qml.qnode(dev) def qnode2(x): qml.Hadamard(0) m_0 = qml.measure(0) qml.cond(m_0, qfunc1)(x, wires=[1]) qml.cond(~m_0, qfunc2)(x, wires=[1]) return qml.expval(qml.Z(1))
>>> qnode2(par) tensor(-0.1477601, requires_grad=True)
Quantum functions with different signatures
It may be that the two quantum functions passed to
qml.cond
have different signatures. In such a case,lambda
functions taking no arguments can be used with Python closure:dev = qml.device("default.qubit", wires=2) def qfunc1(x, wire): qml.Hadamard(wire) qml.RY(x, wire) def qfunc2(x, y, z, wire): qml.Hadamard(wire) qml.Rot(x, y, z, wire) @qml.qnode(dev) def qnode(a, x, y, z): qml.Hadamard(0) m_0 = qml.measure(0) qml.cond(m_0, lambda: qfunc1(a, wire=1), lambda: qfunc2(x, y, z, wire=1))() return qml.expval(qml.Z(1))
>>> par = np.array(0.3) >>> x = np.array(1.2) >>> y = np.array(1.1) >>> z = np.array(0.3) >>> qnode(par, x, y, z) tensor(-0.30922805, requires_grad=True)