Skip to content

Commit

Permalink
Docstrings construct QuantumTape via initialization instead of queu…
Browse files Browse the repository at this point in the history
…ing (#4243)

* show constructing quantumtape on initialization

* the rest of the docstrings

* Update doc/releases/changelog-dev.md

* Update pennylane/transforms/compile.py

* Apply suggestions from code review

Co-authored-by: Matthew Silverman <matthews@xanadu.ai>

* Update pennylane/drawer/tape_mpl.py

Co-authored-by: Tom Bromley <49409390+trbromley@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Mudit Pandey <mudit.pandey@xanadu.ai>

---------

Co-authored-by: Matthew Silverman <matthews@xanadu.ai>
Co-authored-by: Tom Bromley <49409390+trbromley@users.noreply.github.com>
Co-authored-by: Mudit Pandey <mudit.pandey@xanadu.ai>
  • Loading branch information
4 people authored Jun 15, 2023
1 parent 8a75abd commit d28563d
Show file tree
Hide file tree
Showing 30 changed files with 388 additions and 389 deletions.
3 changes: 3 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,9 @@

<h3>Documentation 📝</h3>

* The documentation is updated to construct `QuantumTape` upon initialization instead of with queuing.
[(#4243)](https://github.com/PennyLaneAI/pennylane/pull/4243)

* The docstring for `qml.ops.op_math.Pow.__new__` is now complete and it has been updated along with
`qml.ops.op_math.Adjoint.__new__`.
[(#4231)](https://github.com/PennyLaneAI/pennylane/pull/4231)
Expand Down
23 changes: 12 additions & 11 deletions pennylane/drawer/tape_mpl.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,14 +242,16 @@ def tape_mpl(
.. code-block:: python
with qml.tape.QuantumTape() as tape:
qml.QFT(wires=(0,1,2,3))
qml.IsingXX(1.234, wires=(0,2))
qml.Toffoli(wires=(0,1,2))
qml.CSWAP(wires=(0,2,3))
qml.RX(1.2345, wires=0)
ops = [
qml.QFT(wires=(0,1,2,3)),
qml.IsingXX(1.234, wires=(0,2)),
qml.Toffoli(wires=(0,1,2)),
qml.CSWAP(wires=(0,2,3)),
qml.RX(1.2345, wires=0),
qml.CRZ(1.2345, wires=(3,0))
qml.expval(qml.PauliZ(0))
]
measurements = [qml.expval(qml.PauliZ(0))]
tape = qml.tape.QuantumTape(ops, measurements)
fig, ax = tape_mpl(tape)
fig.show()
Expand All @@ -269,10 +271,9 @@ def tape_mpl(
.. code-block:: python
with qml.tape.QuantumTape() as tape2:
qml.RX(1.23456, wires=0)
qml.Rot(1.2345,2.3456, 3.456, wires=0)
qml.expval(qml.PauliZ(0))
ops = [qml.RX(1.23456, wires=0), qml.Rot(1.2345,2.3456, 3.456, wires=0)]
measurements = [qml.expval(qml.PauliZ(0))]
tape2 = qml.tape.QuantumTape(ops, measurements)
fig, ax = tape_mpl(tape2, decimals=2)
Expand Down
27 changes: 16 additions & 11 deletions pennylane/drawer/tape_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,16 +127,19 @@ def tape_text(
.. code-block:: python
with qml.tape.QuantumTape() as tape:
qml.QFT(wires=(0, 1, 2))
qml.RX(1.234, wires=0)
qml.RY(1.234, wires=1)
qml.RZ(1.234, wires=2)
ops = [
qml.QFT(wires=(0, 1, 2)),
qml.RX(1.234, wires=0),
qml.RY(1.234, wires=1),
qml.RZ(1.234, wires=2),
qml.Toffoli(wires=(0, 1, "aux"))
qml.expval(qml.PauliZ("aux"))
qml.var(qml.PauliZ(0) @ qml.PauliZ(1))
]
measurements = [
qml.expval(qml.PauliZ("aux")),
qml.var(qml.PauliZ(0) @ qml.PauliZ(1)),
qml.probs(wires=(0, 1, 2, "aux"))
]
tape = qml.tape.QuantumTape(ops, measurements)
>>> print(qml.drawer.tape_text(tape))
0: ─╭QFT──RX─╭●─┤ ╭Var[Z@Z] ╭Probs
Expand Down Expand Up @@ -208,10 +211,12 @@ def tape_text(
.. code-block:: python
with qml.tape.QuantumTape() as tape:
qml.QubitUnitary(np.eye(2), wires=0)
ops = [
qml.QubitUnitary(np.eye(2), wires=0),
qml.QubitUnitary(np.eye(2), wires=1)
qml.expval(qml.Hermitian(np.eye(4), wires=(0,1)))
]
measurements = [qml.expval(qml.Hermitian(np.eye(4), wires=(0,1)))]
tape = qml.tape.QuantumTape(ops, measurements)
>>> print(qml.drawer.tape_text(tape))
0: ──U(M0)─┤ ╭<𝓗(M1)>
Expand Down
14 changes: 8 additions & 6 deletions pennylane/gradients/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,12 +262,14 @@ def circuit(weights):
weights = np.array([0.1, 0.2, 0.3], requires_grad=True)
with qml.tape.QuantumTape() as tape:
qml.RX(weights[0], wires=0)
qml.RY(weights[1], wires=1)
qml.CNOT(wires=[0, 1])
qml.RX(weights[2], wires=1)
qml.expval(qml.PauliZ(1))
ops = [
qml.RX(weights[0], wires=0),
qml.RY(weights[1], wires=1),
qml.CNOT(wires=[0, 1]),
qml.RX(weights[2], wires=1)]
measurements = [qml.expval(qml.PauliZ(1))]
tape = qml.tape.QuantumTape(ops, measurements)
Unlike when transforming a QNode, transforming a tape directly
will perform no implicit quantum device evaluation. Instead, it returns
Expand Down
18 changes: 6 additions & 12 deletions pennylane/gradients/finite_difference.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,12 +282,9 @@ def finite_diff(
device evaluation. Instead, the processed tapes, and post-processing
function, which together define the gradient are directly returned:
>>> with qml.tape.QuantumTape() as tape:
... qml.RX(params[0], wires=0)
... qml.RY(params[1], wires=0)
... qml.RX(params[2], wires=0)
... qml.expval(qml.PauliZ(0))
... qml.var(qml.PauliZ(0))
>>> ops = [qml.RX(p, wires=0) for p in params]
>>> measurements = [qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(0))]
>>> tape = qml.tape.QuantumTape(ops, measurements)
>>> gradient_tapes, fn = qml.gradients.finite_diff(tape)
>>> gradient_tapes
[<QuantumTape: wires=[0], params=3>,
Expand Down Expand Up @@ -575,12 +572,9 @@ def _finite_diff_legacy(
device evaluation. Instead, the processed tapes, and post-processing
function, which together define the gradient are directly returned:
>>> with qml.tape.QuantumTape() as tape:
... qml.RX(params[0], wires=0)
... qml.RY(params[1], wires=0)
... qml.RX(params[2], wires=0)
... qml.expval(qml.PauliZ(0))
... qml.var(qml.PauliZ(0))
>>> ops = [qml.RX(p, wires=0) for p in params]
>>> measurements = [qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(0))]
>>> tape = qml.tape.QuantumTape(ops, measurements)
>>> gradient_tapes, fn = qml.gradients.finite_diff(tape)
>>> gradient_tapes
[<QuantumTape: wires=[0], params=3>,
Expand Down
8 changes: 3 additions & 5 deletions pennylane/gradients/hadamard_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,9 @@ def _hadamard_grad(
device evaluation. Instead, the processed tapes, and post-processing
function, which together define the gradient are directly returned:
>>> with qml.tape.QuantumTape() as tape:
... qml.RX(params[0], wires=0)
... qml.RY(params[1], wires=0)
... qml.RX(params[2], wires=0)
... qml.expval(qml.PauliZ(0))
>>> ops = [qml.RX(p, wires=0) for p in params]
>>> measurements = [qml.expval(qml.PauliZ(0))]
>>> tape = qml.tape.QuantumTape(ops, measurements)
>>> gradient_tapes, fn = qml.gradients.hadamard_grad(tape)
>>> gradient_tapes
[<QuantumTape: wires=[0, 1], params=3>,
Expand Down
46 changes: 22 additions & 24 deletions pennylane/gradients/jvp.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,16 +268,17 @@ def jvp(tape, tangent, gradient_fn, shots=None, gradient_kwargs=None):
x = jax.numpy.array([[0.1, 0.2, 0.3],
[0.4, 0.5, 0.6]])
with qml.tape.QuantumTape() as tape:
qml.RX(x[0, 0], wires=0)
qml.RY(x[0, 1], wires=1)
qml.RZ(x[0, 2], wires=0)
qml.CNOT(wires=[0, 1])
qml.RX(x[1, 0], wires=1)
qml.RY(x[1, 1], wires=0)
ops = [
qml.RX(x[0, 0], wires=0),
qml.RY(x[0, 1], wires=1),
qml.RZ(x[0, 2], wires=0),
qml.CNOT(wires=[0, 1]),
qml.RX(x[1, 0], wires=1),
qml.RY(x[1, 1], wires=0),
qml.RZ(x[1, 2], wires=1)
qml.expval(qml.PauliZ(0))
qml.probs(wires=1)
]
measurements = [qml.expval(qml.PauliZ(0)), qml.probs(wires=1)]
tape = qml.tape.QuantumTape(ops, measurements)
We can use the ``jvp`` function to compute the Jacobian vector product,
given a tangent vector ``tangent``:
Expand Down Expand Up @@ -371,23 +372,20 @@ def batch_jvp(tapes, tangents, gradient_fn, shots=None, reduction="append", grad
x = jax.numpy.array([[0.1, 0.2, 0.3],
[0.4, 0.5, 0.6]])
def ansatz(x):
qml.RX(x[0, 0], wires=0)
qml.RY(x[0, 1], wires=1)
qml.RZ(x[0, 2], wires=0)
qml.CNOT(wires=[0, 1])
qml.RX(x[1, 0], wires=1)
qml.RY(x[1, 1], wires=0)
ops = [
qml.RX(x[0, 0], wires=0),
qml.RY(x[0, 1], wires=1),
qml.RZ(x[0, 2], wires=0),
qml.CNOT(wires=[0, 1]),
qml.RX(x[1, 0], wires=1),
qml.RY(x[1, 1], wires=0),
qml.RZ(x[1, 2], wires=1)
]
measurements1 = [qml.expval(qml.PauliZ(0)), qml.probs(wires=1)]
tape1 = qml.tape.QuantumTape(ops, measurements1)
with qml.tape.QuantumTape() as tape1:
ansatz(x)
qml.expval(qml.PauliZ(0))
qml.probs(wires=1)
with qml.tape.QuantumTape() as tape2:
ansatz(x)
qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))
measurements2 = [qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))]
tape2 = qml.tape.QuantumTape(ops, measurements2)
tapes = [tape1, tape2]
Expand Down
34 changes: 12 additions & 22 deletions pennylane/gradients/parameter_shift.py
Original file line number Diff line number Diff line change
Expand Up @@ -1281,12 +1281,9 @@ def param_shift(
device evaluation. Instead, the processed tapes, and post-processing
function, which together define the gradient are directly returned:
>>> with qml.tape.QuantumTape() as tape:
... qml.RX(params[0], wires=0)
... qml.RY(params[1], wires=0)
... qml.RX(params[2], wires=0)
... qml.expval(qml.PauliZ(0))
... qml.var(qml.PauliZ(0))
>>> ops = [qml.RX(p, wires=0) for p in params]
>>> measurements = [qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(0))]
>>> tape = qml.tape.QuantumTape(ops, measurements)
>>> gradient_tapes, fn = qml.gradients.param_shift(tape)
>>> gradient_tapes
[<QuantumTape: wires=[0, 1], params=3>,
Expand Down Expand Up @@ -1334,11 +1331,9 @@ def param_shift(
broadcasted tapes:
>>> params = np.array([0.1, 0.2, 0.3], requires_grad=True)
>>> with qml.tape.QuantumTape() as tape:
... qml.RX(params[0], wires=0)
... qml.RY(params[1], wires=0)
... qml.RX(params[2], wires=0)
... qml.expval(qml.PauliZ(0))
>>> ops = [qml.RX(p, wires=0) for p in params]
>>> measurements = [qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(0))]
>>> tape = qml.tape.QuantumTape(ops, measurements)
>>> gradient_tapes, fn = qml.gradients.param_shift(tape, broadcast=True)
>>> len(gradient_tapes)
3
Expand Down Expand Up @@ -1687,12 +1682,9 @@ def _param_shift_legacy(
device evaluation. Instead, the processed tapes, and post-processing
function, which together define the gradient are directly returned:
>>> with qml.tape.QuantumTape() as tape:
... qml.RX(params[0], wires=0)
... qml.RY(params[1], wires=0)
... qml.RX(params[2], wires=0)
... qml.expval(qml.PauliZ(0))
... qml.var(qml.PauliZ(0))
>>> ops = [qml.RX(p, wires=0) for p in params]
>>> measurements = [qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(0))]
>>> tape = qml.tape.QuantumTape(ops, measurements)
>>> gradient_tapes, fn = qml.gradients.param_shift(tape)
>>> gradient_tapes
[<QuantumTape: wires=[0, 1], params=3>,
Expand All @@ -1718,11 +1710,9 @@ def _param_shift_legacy(
broadcasted tapes:
>>> params = np.array([0.1, 0.2, 0.3], requires_grad=True)
>>> with qml.tape.QuantumTape() as tape:
... qml.RX(params[0], wires=0)
... qml.RY(params[1], wires=0)
... qml.RX(params[2], wires=0)
... qml.expval(qml.PauliZ(0))
>>> ops = [qml.RX(p, wires=0) for p in params]
>>> measurements = [qml.expval(qml.PauliZ(0))]
>>> tape = qml.tape.QuantumTape(ops, measurements)
>>> gradient_tapes, fn = qml.gradients.param_shift(tape, broadcast=True)
>>> len(gradient_tapes)
3
Expand Down
6 changes: 2 additions & 4 deletions pennylane/gradients/parameter_shift_cv.py
Original file line number Diff line number Diff line change
Expand Up @@ -643,10 +643,8 @@ def circuit(weights):
function, which together define the gradient are directly returned:
>>> r0, phi0, r1, phi1 = [0.4, -0.3, -0.7, 0.2]
>>> with qml.tape.QuantumTape() as tape:
... qml.Squeezing(r0, phi0, wires=[0])
... qml.Squeezing(r1, phi1, wires=[0])
... qml.expval(qml.NumberOperator(0)) # second-order
>>> ops = [qml.Squeezing(r0, phi0, wires=0), qml.Squeezing(r1, phi2, wires=0)]
>>> tape = qml.tape.QuantumTape(ops, [qml.expval(qml.NumberOperator(0))])
>>> gradient_tapes, fn = qml.gradients.param_shift_cv(tape, dev)
>>> gradient_tapes
[<QuantumTape: wires=[0], params=4>,
Expand Down
18 changes: 6 additions & 12 deletions pennylane/gradients/spsa_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,12 +212,9 @@ def spsa_grad(
device evaluation. Instead, the processed tapes, and post-processing
function, which together define the gradient are directly returned:
>>> with qml.tape.QuantumTape() as tape:
... qml.RX(params[0], wires=0)
... qml.RY(params[1], wires=0)
... qml.RX(params[2], wires=0)
... qml.expval(qml.PauliZ(0))
... qml.var(qml.PauliZ(0))
>>> ops = [qml.RX(p, wires=0) for p in params]
>>> measurements = [qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(0))]
>>> tape = qml.tape.QuantumTape(ops, measurements)
>>> gradient_tapes, fn = qml.gradients.spsa_grad(tape)
>>> gradient_tapes
[<QuantumTape: wires=[0], params=3>, <QuantumTape: wires=[0], params=3>]
Expand Down Expand Up @@ -512,12 +509,9 @@ def _spsa_grad_legacy(
device evaluation. Instead, the processed tapes, and post-processing
function, which together define the gradient are directly returned:
>>> with qml.tape.QuantumTape() as tape:
... qml.RX(params[0], wires=0)
... qml.RY(params[1], wires=0)
... qml.RX(params[2], wires=0)
... qml.expval(qml.PauliZ(0))
... qml.var(qml.PauliZ(0))
>>> ops = [qml.RX(p, wires=0) for p in params]
>>> measurements = [qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(0))]
>>> tape = qml.tape.QuantumTape(ops, measurements)
>>> gradient_tapes, fn = qml.gradients.spsa_grad(tape)
>>> gradient_tapes
[<QuantumTape: wires=[0], params=3>, <QuantumTape: wires=[0], params=3>]
Expand Down
46 changes: 22 additions & 24 deletions pennylane/gradients/vjp.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,16 +313,17 @@ def vjp(tape, dy, gradient_fn, shots=None, gradient_kwargs=None):
x = torch.tensor([[0.1, 0.2, 0.3],
[0.4, 0.5, 0.6]], requires_grad=True, dtype=torch.float64)
with qml.tape.QuantumTape() as tape:
qml.RX(x[0, 0], wires=0)
qml.RY(x[0, 1], wires=1)
qml.RZ(x[0, 2], wires=0)
qml.CNOT(wires=[0, 1])
qml.RX(x[1, 0], wires=1)
qml.RY(x[1, 1], wires=0)
ops = [
qml.RX(x[0, 0], wires=0),
qml.RY(x[0, 1], wires=1),
qml.RZ(x[0, 2], wires=0),
qml.CNOT(wires=[0, 1]),
qml.RX(x[1, 0], wires=1),
qml.RY(x[1, 1], wires=0),
qml.RZ(x[1, 2], wires=1)
qml.expval(qml.PauliZ(0))
qml.probs(wires=1)
]
measurements = [qml.expval(qml.PauliZ(0)), qml.probs(wires=1)]
tape = qml.tape.QuantumTape(ops, measurements)
We can use the ``vjp`` function to compute the vector-Jacobian product,
given a gradient-output vector ``dy``:
Expand Down Expand Up @@ -461,23 +462,20 @@ def batch_vjp(tapes, dys, gradient_fn, shots=None, reduction="append", gradient_
x = torch.tensor([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]], requires_grad=True, dtype=torch.float64)
def ansatz(x):
qml.RX(x[0, 0], wires=0)
qml.RY(x[0, 1], wires=1)
qml.RZ(x[0, 2], wires=0)
qml.CNOT(wires=[0, 1])
qml.RX(x[1, 0], wires=1)
qml.RY(x[1, 1], wires=0)
ops = [
qml.RX(x[0, 0], wires=0),
qml.RY(x[0, 1], wires=1),
qml.RZ(x[0, 2], wires=0),
qml.CNOT(wires=[0, 1]),
qml.RX(x[1, 0], wires=1),
qml.RY(x[1, 1], wires=0),
qml.RZ(x[1, 2], wires=1)
]
measurements1 = [qml.expval(qml.PauliZ(0)), qml.probs(wires=1)]
tape1 = qml.tape.QuantumTape(ops, measurements1)
with qml.tape.QuantumTape() as tape1:
ansatz(x)
qml.expval(qml.PauliZ(0))
qml.probs(wires=1)
with qml.tape.QuantumTape() as tape2:
ansatz(x)
qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))
measurements2 = [qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))]
tape2 = qml.tape.QuantumTape(ops, measurements2)
tapes = [tape1, tape2]
Expand Down
Loading

0 comments on commit d28563d

Please sign in to comment.