Skip to content

Commit

Permalink
Adding documentation for qml.breakpoint() and qml.PLDB (#5789)
Browse files Browse the repository at this point in the history
**Context:**
Adding documentation for the new debugger feature.

---------

Co-authored-by: Mikhail Andrenkov <mikhail@xanadu.ai>
Co-authored-by: Utkarsh <utkarshazad98@gmail.com>
Co-authored-by: Diego <67476785+DSGuala@users.noreply.github.com>
Co-authored-by: Josh Izaac <josh146@gmail.com>
Co-authored-by: soranjh <40344468+soranjh@users.noreply.github.com>
Co-authored-by: Diego <diego_guala@hotmail.com>
  • Loading branch information
7 people committed Jun 20, 2024
1 parent 66421f1 commit 88938c3
Show file tree
Hide file tree
Showing 7 changed files with 506 additions and 24 deletions.
222 changes: 222 additions & 0 deletions doc/code/qml_debugging.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
qml.debugging
=============

.. automodapi:: pennylane.debugging
:no-heading:
:no-inherited-members:
:skip: PLDB
:skip: pldb_device_manager

Entering the Debugging Context
------------------------------

The :func:`~pennylane.breakpoint` function provides an interface for interacting with and
stepping through a quantum circuit during execution. It allows for faster debugging
by providing access to the internal state of the circuit and the ``QuantumTape`` as
the circuit operations are applied. The functionality is highlighted by the example
circuit below.

.. code-block:: python
import pennylane as qml
@qml.qnode(qml.device('default.qubit', wires=(0,1,2)))
def circuit(x):
qml.breakpoint()
qml.Hadamard(wires=0)
qml.CNOT(wires=(0,2))
for w in (0, 1, 2):
qml.RX(2*x, wires=w)
qml.breakpoint()
qml.RX(-x, wires=1)
return qml.sample()
circuit(1.2345)
Running the above python script opens up the interactive ``[pldb]:`` prompt in the terminal.
When this code reaches ``qml.breakpoint()`` it will pause and launch an interactive
debugging prompt. The prompt specifies the path to the script and the next line to be
executed after the breakpoint:

.. code-block:: console
> /Users/your/path/to/script.py(7)circuit()
-> qml.Hadamard(wires=0)
[pldb]:
Controlling Code Execution in the Debugging Context
---------------------------------------------------

The Pennylane Debugger (PLDB) is built from the native python debugger (Pdb), as such
it shares a similar interface. We can interact with the debugger using the
builtin commands: ``list``, ``longlist``, ``next``, ``continue``, and ``quit``. Any
variables defined in the scope of the quantum function can also be accessed from the
debugger.

.. code-block:: console
[pldb]: print(x)
1.2345
The ``list`` (and ``longlist``) command will print a section of code around the
breakpoint, highlighting the next line to be executed. This can be used to determine
the location of execution in the circuit.

.. code-block:: console
[pldb]: longlist
3 @qml.qnode(qml.device('default.qubit', wires=(0,1,2)))
4 def circuit(x):
5 qml.breakpoint()
6
7 -> qml.Hadamard(wires=0)
8 qml.CNOT(wires=(0,2))
9
10 for w in (0, 1, 2):
11 qml.RX(2*x, wires=w)
12
13 qml.breakpoint()
14 qml.RX(-x, wires=1)
15 return qml.sample()
The ``next`` command will execute the next line of code, and print the following
line to be executed, e.g., the next operation to execute is ``CNOT``.

.. code-block:: console
[pldb]: next
> /Users/your/path/to/script.py(8)circuit()
-> qml.CNOT(wires=(0,2))
[pldb]: list
3 @qml.qnode(qml.device('default.qubit', wires=(0,1,2)))
4 def circuit(x):
5 qml.breakpoint()
6
7 qml.Hadamard(wires=0)
8 -> qml.CNOT(wires=(0,2))
9
10 for w in (0, 1, 2):
11 qml.RX(2*x, wires=w)
12
13 qml.breakpoint()
Alternative, the ``continue`` command allows for jumping between breakpoints. This command resumes
code execution until the next breakpoint is reached. Finally, the ``quit`` command
ends the debugging prompt.

.. code-block:: console
[pldb]: continue
> /Users/your/path/to/script.py(14)circuit()
-> qml.RX(-x, wires=1)
[pldb]: list
9
10 for w in (0, 1, 2):
11 qml.RX(2*x, wires=w)
12
13 qml.breakpoint()
14 -> qml.RX(-x, wires=1)
15 return qml.sample()
16
17 circuit(1.2345)
[EOF]
[pldb]: quit
Extracting Circuit Information
------------------------------

While in the debugging prompt, we can extract information and perform measurements
on the qunatum circuit. Specifically we can make measurements using
:func:`~pennylane.debug_expval`, :func:`~pennylane.debug_state`,
:func:`~pennylane.debug_probs`, and access the gates in the circuit using
:func:`~pennylane.debug_tape`.

Consider the circuit from above,

.. code-block:: console
> /Users/your/path/to/script.py(7)circuit()
-> qml.Hadamard(wires=0)
[pldb]: longlist
3 @qml.qnode(qml.device('default.qubit', wires=(0,1,2)))
4 def circuit(x):
5 qml.breakpoint()
6
7 -> qml.Hadamard(wires=0)
8 qml.CNOT(wires=(0,2))
9
10 for w in (0, 1, 2):
11 qml.RX(2*x, wires=w)
12
13 qml.breakpoint()
14 qml.RX(-x, wires=1)
15 return qml.sample()
[pldb]: next
> /Users/your/path/to/script.py(8)circuit()
-> qml.CNOT(wires=(0,2))
[pldb]: next
> /Users/your/path/to/script.py(10)circuit()
-> for w in (0, 1, 2):
[pldb]:
All of the operations applied so far are tracked in the circuit's ``QuantumTape``
which is accessible using :func:`~pennylane.debug_tape`. This can be used to
*visually* debug the circuit.

.. code-block:: console
[pldb]: qtape = qml.debug_tape()
[pldb]: qtape.operations
[Hadamard(wires=[0]), CNOT(wires=[0, 2])]
[pldb]: print(qtape.draw())
0: ──H─╭●─┤
2: ────╰X─┤
The quantum state of the circuit at this point can be extracted using
:func:`~pennylane.debug_state`. The associated probability distribution
for the wires of interest can be probed using :func:`~pennylane.debug_probs`.

.. code-block:: console
[pldb]: qml.debug_state()
array([0.70710678+0.j, 0. +0.j, 0. +0.j, 0. +0.j,
0. +0.j, 0.70710678+0.j, 0. +0.j, 0. +0.j])
[pldb]: qml.debug_probs(wires=(0,2))
array([0.5, 0. , 0. , 0.5])
Another method for probing the system is by measuring observables via
:func:`~pennylane.debug_expval`.

.. code-block:: console
[pldb]: qml.debug_expval(qml.Z(0))
0.0
[pldb]: qml.debug_expval(qml.X(0)@qml.X(2))
0.9999999999999996
Additionally, the quantum circuit can be dynamically updated by adding gates directly
from the prompt. This allows users to modify the circuit *on-the-fly*!

.. code-block:: console
[pldb]: continue
> /Users/your/path/to/script.py(14)circuit()
-> qml.RX(-x, wires=1)
[pldb]: qtape = qml.debug_tape()
[pldb]: print(qtape.draw(wire_order=(0,1,2)))
0: ──H─╭●──RX─┤
1: ────│───RX─┤
2: ────╰X──RX─┤
[pldb]: qml.RZ(0.5*x, wires=0)
RZ(0.61725, wires=[0])
[pldb]: qml.CZ(wires=(1,2))
CZ(wires=[1, 2])
[pldb]: qtape = qml.debug_tape()
[pldb]: print(qtape.draw(wire_order=(0,1,2)))
0: ──H─╭●──RX──RZ─┤
1: ────│───RX─╭●──┤
2: ────╰X──RX─╰Z──┤
1 change: 1 addition & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ PennyLane is **free** and **open source**, released under the Apache License, Ve
code/qml
code/qml_compiler
code/qml_data
code/qml_debugging
code/qml_drawer
code/qml_fermi
code/qml_fourier
Expand Down
9 changes: 9 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@

<h3>New features since last release</h3>

* Added a quantum debugger (`PLDB`) which interfaces via `qml.breakpoint()` and provides tools for
debugging quantum circuits. Users can step through the quantum circuit operations, dynamically
queue operations and make measurements using (`qml.debug_state()`, `qml.debug_probs()`,
`qml.debug_expval()`, and `qml.debug_tape()`). Consider the following python script
containing the quantum circuit with breakpoints.
[(#5680)](https://github.com/PennyLaneAI/pennylane/pull/5680)
[(#5749)](https://github.com/PennyLaneAI/pennylane/pull/5749)
[(#5789)](https://github.com/PennyLaneAI/pennylane/pull/5789)

* The `default.tensor` device now supports the `tn` method to simulate quantum circuits using exact tensor networks.
[(#5786)](https://github.com/PennyLaneAI/pennylane/pull/5786)

Expand Down
9 changes: 8 additions & 1 deletion pennylane/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,14 @@
)
from pennylane.ops.identity import I
from pennylane.optimize import *
from pennylane.debugging import snapshots, breakpoint
from pennylane.debugging import (
snapshots,
breakpoint,
debug_expval,
debug_state,
debug_probs,
debug_tape,
)
from pennylane.shadows import ClassicalShadow
from pennylane.qcut import cut_circuit, cut_circuit_mc
import pennylane.pulse
Expand Down
8 changes: 4 additions & 4 deletions pennylane/debugging/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@

from .debugger import (
breakpoint,
expval,
debug_expval,
PLDB,
pldb_device_manager,
probs,
state,
tape,
debug_probs,
debug_state,
debug_tape,
)
Loading

0 comments on commit 88938c3

Please sign in to comment.