Skip to content

Commit

Permalink
docs: include test examples
Browse files Browse the repository at this point in the history
  • Loading branch information
erichulburd committed Jan 6, 2025
1 parent a52cb6e commit 2f25204
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 33 deletions.
4 changes: 2 additions & 2 deletions crates/python/qcs_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from typing import Type
from .qcs_sdk import *
import qcs_sdk._unitary_set
from . import _unitary_set

from types import ModuleType

Expand All @@ -15,7 +15,7 @@ def _monkey_patch(module: ModuleType, attribute: Type):
module.__all__.append(attribute.__name__)


_monkey_patch(qcs_sdk.qpu.experimental.randomized_measurements, qcs_sdk._unitary_set.UnitarySet)
_monkey_patch(qcs_sdk.qpu.experimental.randomized_measurements, _unitary_set.UnitarySet)


__doc__ = qcs_sdk.__doc__
Expand Down
10 changes: 1 addition & 9 deletions crates/python/qcs_sdk/_unitary_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,7 @@ class UnitarySet(ABC):
both the concrete set of unitaries from which to draw, as well as the Quil representation for
realizing the unitaries.
# Example
Below is an example implementation of `UnitarySet` as a unitary decomposition made of an
RZ-RX-RZ-RX-RZ gate sequence. A more thorough example can be found in
:mod:`tests.qpu.test_experimental`.
```python
.. include:: ../tests/qpu/test_experimental.py
```
See module level documentation for an example implementation.
"""

@abstractmethod
Expand Down
25 changes: 3 additions & 22 deletions crates/python/qcs_sdk/qpu/experimental/random.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -42,28 +42,9 @@ class ChooseRandomRealSubRegions:
and copy it to the destination memory region according to the seed value. The seed value is
mutated to the next element in the PRNG sequence.
>>> program = Program()
>>> destination = Declaration("destination", Vector(ScalarType.Real, 3), None)
>>> program.add_instruction(Instruction.from_declaration(destination))
>>> source = Declaration("source", Vector(ScalarType.Real, 12), None)
>>> program.add_instruction(Instruction.from_declaration(source))
>>> seed = Declaration("seed", Vector(ScalarType.Integer, 1), None)
>>> program.add_instruction(Instruction.from_declaration(seed))
>>> pragma_extern = Pragma("EXTERN", [PragmaArgument.from_identifier(ChooseRandomRealSubRegions.NAME)], ChooseRandomRealSubRegions.build_signature())
>>> program.add_instruction(Instruction.from_pragma(pragma_extern))
>>> call = Call(ChooseRandomRealSubRegions.NAME, [
... CallArgument.from_identifier("destination"),
... CallArgument.from_identifier("source"),
... CallArgument.from_immediate(complex(3, 0)),
... CallArgument.from_memory_reference(MemoryReference("seed", 0)),
... ])
>>> program.add_instruction(Instruction.from_call(call))
>>> print(program.to_quil())
PRAGMA EXTERN choose_random_real_sub_regions "(destination : mut REAL[], source : REAL[], sub_region_size : INTEGER, seed : mut INTEGER)"
DECLARE destination REAL[3]
DECLARE source REAL[9]
DECLARE seed INTEGER[1]
CALL choose_random_real_sub_regions destination source 3 seed[0]
```python
.. include:: tests/qpu/experimental/test_random.py
```
From there, you may reference the `destination` memory region in your pulse program.
"""
Expand Down
34 changes: 34 additions & 0 deletions crates/python/qcs_sdk/qpu/experimental/randomized_measurements.pyi
Original file line number Diff line number Diff line change
@@ -1,3 +1,37 @@
"""
Measurement randomization is a technique used in both quantum tomography and
quantum error mitigation. Essentially, it involves randomly rotating each
qubit prior to measurement. This module enables per-shot randomization, where
random rotations are applied to each qubit independently for each shot. For
some background on the technique, see
[Predicting Many Properties of a Quantum System from Very Few Measurements
(arxiv:2002.08953)](https://arxiv.org/abs/2002.08953).
The [`RandomizedMeasurements`] struct handles three critical components to
correctly add randomized measurements to a Rigetti QCS Quil program:
1. Program construction - adding the classical randomization calls to the
prologue of the program (i.e. before the pulse program begins) and referencing
those randomized values within a unitary decomposition prior to measurement.
2. Parameter construction - building a map of [`Parameters`] with seeds for
each qubit.
3. PRNG reconstruction - backing out the random indices that played on each
qubit during program execution.
This is not a QIS (quantum information science) library, but rather an
SDK for collecting data from Rigetti QPUs. As such, defining the proper
unitary set and using randomized measurement data is beyond the scope of this
library.
# Example
The below test module illustrates usage for implementing a `UnitarySet` and
the `RandomizedMeasurements` class using a RZ-RX-RZ-RX-RZ unitary decomposition.
```python
.. include:: tests/qpu/experimental/test_randomized_measurements.py
```
"""
from qcs_sdk.qpu.experimental.random import PrngSeedValue

from typing import Dict, List, Self, final
Expand Down
33 changes: 33 additions & 0 deletions crates/python/tests/qpu/experimental/test_random.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from quil.program import Program
from quil.instructions import Declaration, Instruction, Pragma, Call, CallArgument, MemoryReference, Vector, ScalarType, PragmaArgument
from qcs_sdk.qpu.experimental.random import ChooseRandomRealSubRegions


EXPECTED_QUIL = """
PRAGMA EXTERN choose_random_real_sub_regions "(destination : mut REAL[], source : REAL[], sub_region_size : INTEGER, seed : mut INTEGER)"
DECLARE destination REAL[3]
DECLARE source REAL[12]
DECLARE seed INTEGER[1]
CALL choose_random_real_sub_regions destination source 3 seed[0]
"""

def test_choose_random_real_subregions():
"""Test that `ChooseRandomRealSubRegions` is correctly added to a Quil progrram."""
program = Program()
destination = Declaration("destination", Vector(ScalarType.Real, 3), None)
program.add_instruction(Instruction.from_declaration(destination))
source = Declaration("source", Vector(ScalarType.Real, 12), None)
program.add_instruction(Instruction.from_declaration(source))
seed = Declaration("seed", Vector(ScalarType.Integer, 1), None)
program.add_instruction(Instruction.from_declaration(seed))
pragma_extern = Pragma("EXTERN", [PragmaArgument.from_identifier(ChooseRandomRealSubRegions.NAME)], ChooseRandomRealSubRegions.build_signature())
program.add_instruction(Instruction.from_pragma(pragma_extern))
call = Call(ChooseRandomRealSubRegions.NAME, [
CallArgument.from_identifier("destination"),
CallArgument.from_identifier("source"),
CallArgument.from_immediate(complex(3, 0)),
CallArgument.from_memory_reference(MemoryReference("seed", 0)),
])
program.add_instruction(Instruction.from_call(call))
assert program == Program.parse(EXPECTED_QUIL)

0 comments on commit 2f25204

Please sign in to comment.