Skip to content

Commit

Permalink
docs
Browse files Browse the repository at this point in the history
  • Loading branch information
mpharrigan committed Oct 13, 2023
1 parent b342fcd commit 528ba03
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 10 deletions.
16 changes: 13 additions & 3 deletions qualtran/_infra/bloq.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,21 @@ def _decompose_from_build_composite_bloq(bloq: 'Bloq') -> 'CompositeBloq':


class DecomposeNotImplementedError(NotImplementedError):
pass
"""Raised if a decomposition is not yet provided.
In contrast to `DecomposeTypeError`, a decomposition is theoretically possible; just not
implemented yet.
"""


class DecomposeTypeError(TypeError):
pass
"""Raised if a decomposition does not make sense in this context.
In contrast to `DecomposeNotImplementedError`, a decomposition does not make sense
in this context. This can be raised if the bloq is "atomic" -- that is, considered part
of the compilation target gateset. This can be raised if certain bloq attributes do not
permit a decomposition, most commonly if an attribute is symbolic.
"""


class Bloq(metaclass=abc.ABCMeta):
Expand Down Expand Up @@ -107,7 +117,7 @@ def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str
The soquets corresponding to the outputs of the Bloq (keyed by name) or
`NotImplemented` if there is no decomposition.
"""
raise DecomposeNotImplementedError(f"{self}.")
raise DecomposeNotImplementedError(f"{self}")

def decompose_bloq(self) -> 'CompositeBloq':
"""Decompose this Bloq into its constituent parts contained in a CompositeBloq.
Expand Down
21 changes: 19 additions & 2 deletions qualtran/_infra/bloq_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,21 @@

@frozen
class BloqExample:
"""An instantiation of a bloq and its metadata.
In particular, this class wraps a callable that returns a bloq instantiation with
explicit attribute values.
Consider using the decorator `@bloq_example` to construct a `BloqExample` from a function.
Args:
func: The function that returns the bloq instantiation. Calling the `BloqExample` instance
will call this function.
name: A name for the bloq instantiation.
bloq_cls: The `Bloq` class that this instantiation is an instance of.
generalizer: Passed to `get_bloq_counts_graph` calls for bloq-counts equivalence checking.
"""

_func: Callable[[], Bloq] = field(repr=False, hash=False)
name: str
bloq_cls: Type[Bloq]
Expand All @@ -38,11 +53,13 @@ def __call__(self) -> Bloq:
return self.make()


def _name_from_func_name(func: Callable[[], Bloq]):
def _name_from_func_name(func: Callable[[], Bloq]) -> str:
"""Use the name of the function as the `BloqExample.name` when using the decorator."""
return func.__name__.lstrip('_')


def _bloq_cls_from_func_annotation(func: Callable[[], Bloq]):
def _bloq_cls_from_func_annotation(func: Callable[[], Bloq]) -> Type[Bloq]:
"""Use the function return type annotation as the `BloqExample.bloq_cls` with the decorator."""
anno = func.__annotations__
if 'return' not in anno:
raise ValueError(f'{func} must have a return type annotation.')
Expand Down
4 changes: 2 additions & 2 deletions qualtran/cirq_interop/_cirq_to_bloq.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ def decompose_from_cirq_op(bloq: 'Bloq') -> 'CompositeBloq':
cirq.is_parameterized(reg.bitsize) or cirq.is_parameterized(reg.side)
for reg in bloq.signature
):
raise DecomposeTypeError(f"{bloq} does not support decomposition.")
raise DecomposeTypeError(f"Cannot decompose parameterized {bloq}.")

qubit_manager = InteropQubitManager()
in_quregs = get_cirq_quregs(bloq.signature, qubit_manager)
Expand All @@ -383,7 +383,7 @@ def decompose_from_cirq_op(bloq: 'Bloq') -> 'CompositeBloq':
if cirq_op is None or (
isinstance(cirq_op, cirq.Operation) and isinstance(cirq_op.gate, BloqAsCirqGate)
):
raise NotImplementedError(f"{bloq} does not support decomposition.")
raise ValueError(f"Cannot decompose from cirq op: {bloq} doesn't have a cirq op.")

return cirq_optree_to_cbloq(
cirq_op, signature=bloq.signature, in_quregs=in_quregs, out_quregs=out_quregs
Expand Down
4 changes: 2 additions & 2 deletions qualtran/cirq_interop/_cirq_to_bloq_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from attrs import frozen

import qualtran
from qualtran import Bloq, BloqBuilder, CompositeBloq, Side, Signature
from qualtran import Bloq, BloqBuilder, CompositeBloq, DecomposeTypeError, Side, Signature
from qualtran.bloqs.basic_gates import OneState
from qualtran.bloqs.util_bloqs import Allocate, Free, Join, Split
from qualtran.cirq_interop import (
Expand Down Expand Up @@ -107,7 +107,7 @@ def test_bloq_decompose_from_cirq_op():
assert circuit == cirq.Circuit(cirq.CNOT(*cirq_quregs['control'], *cirq_quregs['target']))
assert tb.t_complexity() == cirq_ft.TComplexity(clifford=1)

with pytest.raises(NotImplementedError):
with pytest.raises(DecomposeTypeError):
TestCNOTSymbolic().decompose_bloq()


Expand Down
8 changes: 8 additions & 0 deletions qualtran/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@


def assert_bloq_example_make(bloq_ex: BloqExample):
"""Wrap `check_bloq_example_make`.
Anything other than PASS is a test failure.
"""
status, err = qlt_testing.check_bloq_example_make(bloq_ex)
if status is qlt_testing.BloqCheckResult.PASS:
return
Expand All @@ -39,6 +43,10 @@ def assert_bloq_example_make(bloq_ex: BloqExample):


def assert_bloq_example_decompose(bloq_ex: BloqExample):
"""Wrap `check_bloq_example_decompose`.
`NA` or `MISSING` result in the test being skipped.
"""
status, err = qlt_testing.check_bloq_example_decompose(bloq_ex)
if status is qlt_testing.BloqCheckResult.PASS:
return
Expand Down
25 changes: 24 additions & 1 deletion qualtran/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,12 +220,26 @@ def execute_notebook(name: str):


class BloqCheckResult(Enum):
"""The status result of the `check_bloq_example_xxx` functions."""

PASS = 0
"""The check passed and is an unqualified success."""

FAIL = 1
"""The check failed with a broken assertion or invariant."""

MISSING = 2
"""The check did not pass because the required functionality is missing."""

NA = 3
"""The check is not applicable in the current context."""

UNVERIFIED = 4
"""The bloq protocol has provided a value, but some functionality is missing so we can't
verify the result."""

ERROR = 5
"""An unexpected error occurred during execution of the check."""


def _check_bloq_example_make_impl(bloq_ex: BloqExample) -> Tuple[BloqCheckResult, str]:
Expand All @@ -242,7 +256,12 @@ def _check_bloq_example_make_impl(bloq_ex: BloqExample) -> Tuple[BloqCheckResult


def check_bloq_example_make(bloq_ex: BloqExample) -> Tuple[BloqCheckResult, str]:
"""Check that the BloqExample returns the desired bloq."""
"""Check that the BloqExample returns the desired bloq.
Returns:
result: The `BloqCheckResult`.
msg: A message providing details from the check.
"""
try:
return _check_bloq_example_make_impl(bloq_ex)
except Exception as e:
Expand Down Expand Up @@ -272,6 +291,10 @@ def check_bloq_example_decompose(bloq_ex: BloqExample) -> Tuple[BloqCheckResult,
This will use `assert_valid_decomposition` which has a variety of sub-checks. A failure
in any of those checks will result in `FAIL`. `DecomposeTypeError` results in a
not-applicable `NA` status. `DecomposeNotImplementedError` results in a `MISSING` status.
Returns:
result: The `BloqCheckResult`.
msg: A message providing details from the check.
"""
try:
return _check_bloq_example_decompose_impl(bloq_ex)
Expand Down

0 comments on commit 528ba03

Please sign in to comment.