Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add a with_loop method to Program #1717

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions docs/source/advanced_usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,8 @@ register of qubits to build your program.
H 12
H 14

.. _classical_control_flow:

**********************
Classical control flow
**********************
Expand Down Expand Up @@ -340,6 +342,13 @@ classical register. There are several classical commands that can be used in th
- ``MOVE`` which moves the value of a classical bit at one classical address into another
- ``EXCHANGE`` which swaps the value of two classical bits

.. note::

The approach documented here can be used to construct a "numshots" loop in pure Quil. See the
:py:meth:`~pyquil.quil.Program.apply_numshots_loop` method and :ref:`applying_a_numshots_loop` for more
information.


If, then
========

Expand Down Expand Up @@ -425,6 +434,10 @@ We can run this program a few times to see what we get in the readout register `
[1]
[0]]

Applying a numshots loop
------------------------


MarquessV marked this conversation as resolved.
Show resolved Hide resolved

**********************
Pauli Operator Algebra
Expand Down
57 changes: 57 additions & 0 deletions docs/source/programs_and_gates.rst
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ use the compiler to :ref:`re-index <rewiring>` your qubits):
for i, q in enumerate(qubits):
p += MEASURE(q, ro[i])

.. _specifying_trials:

Specifying the number of trials
===============================

Expand Down Expand Up @@ -240,6 +242,61 @@ program should be executed 1000 times:
The word “shot” comes from experimental physics where an experiment is
performed many times, and each result is called a shot.

.. _applying_a_numshots_loop:

Applying a numshots loop
------------------------

Specifying trials with :py:meth:`~pyquil.quil.Program.wrap_in_numshots_loop` doesn't modify the Quil in your program in
any way. Instead, the number of shots you specify is included in your job request and tells the executor how many times
to run your program. However, with Quil's :ref:`classical_control_flow`, instructions it is possible to write a program
that itself defines a loop over a number of shots. The :py:meth:`~pyquil.quil.Program.apply_numshots_loop` method will
help you do just that. It wraps the body of your program in a loop over the number of shots you specified with ``wrap_in_numshots_loop`` and returns the looped program with its ``num_shots`` property set to 1.

Let's see an example, we'll construct a classic bell state program and measure it 1000 times by applying a numshots
MarquessV marked this conversation as resolved.
Show resolved Hide resolved
loop.

.. testcode:: apply_numshots_loop

from pyquil import Program
from pyquil.quilatom import Label
from pyquil.gates import H, CNOT

# Setup the bell state program
p = Program(
H(0),
CNOT(0, 1),
)
ro = p.declare("ro", "BIT", 2)
p.measure(0, ro[0])
p.measure(1, ro[1])

# Declare a memory region to hold the number of shots
shot_count = p.declare("shot_count", "INTEGER")
p.wrap_in_numshots_loop(1000)

# Apply the numshots loop by passing in the MemoryReference for the shot_count and two
# labels to mark the beginning and end of the loop.
looped_program = p.apply_numshots_loop(shot_count, Label("start-loop"), Label("end-loop"))
print(looped_program.out())
print(looped_program.num_shots)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would also be useful to extend the example to include execution (i.e. that the memory reference has to be provided a value in qc.run or whatever).


.. testoutput:: apply_numshots_loop

DECLARE ro BIT[2]
DECLARE shot_count INTEGER[1]
MOVE shot_count[0] 1000
LABEL @start-loop
H 0
CNOT 0 1
MEASURE 0 ro[0]
MEASURE 1 ro[1]
SUB shot_count[0] 1
JUMP-UNLESS @end-loop shot_count[0]
JUMP @start-loop

1


.. _parametric_compilation:

Expand Down
92 changes: 46 additions & 46 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ rpcq = "^3.10.0"
pydantic = "^1.10.7"
networkx = ">=2.5"
importlib-metadata = { version = ">=3.7.3,<5", python = "<3.8" }
qcs-sdk-python = "0.16.0"
qcs-sdk-python = "0.16.1"
tenacity = "^8.2.2"
types-python-dateutil = "^2.8.19"
types-retry = "^0.9.9"
Expand Down
Loading
Loading