Skip to content

Commit

Permalink
classical sim wip
Browse files Browse the repository at this point in the history
  • Loading branch information
mpharrigan committed Mar 7, 2024
1 parent 67587df commit 0092122
Show file tree
Hide file tree
Showing 6 changed files with 796 additions and 12 deletions.
13 changes: 5 additions & 8 deletions dev_tools/qualtran_dev_tools/bloq_report_card.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from qualtran import Bloq, BloqExample
from qualtran.testing import (
BloqCheckResult,
check_bloq_example_classical_action,
check_bloq_example_decompose,
check_bloq_example_make,
check_equivalent_bloq_example_counts,
Expand Down Expand Up @@ -65,17 +66,12 @@ def bloq_classes_with_no_examples(


IDCOLS = ['package', 'bloq_cls', 'name']
CHECKCOLS = ['make', 'decomp', 'counts']
CHECKCOLS = ['make', 'decomp', 'counts', 'classical']


def record_for_class_with_no_examples(k: Type[Bloq]) -> Dict[str, Any]:
return {
'bloq_cls': k.__name__,
'package': _get_package(k),
'name': '-',
'make': BloqCheckResult.MISSING,
'decomp': BloqCheckResult.MISSING,
'counts': BloqCheckResult.MISSING,
return {'bloq_cls': k.__name__, 'package': _get_package(k), 'name': '-'} | {
checkcol: BloqCheckResult.MISSING for checkcol in CHECKCOLS
}


Expand All @@ -87,6 +83,7 @@ def record_for_bloq_example(be: BloqExample) -> Dict[str, Any]:
'make': check_bloq_example_make(be)[0],
'decomp': check_bloq_example_decompose(be)[0],
'counts': check_equivalent_bloq_example_counts(be)[0],
'classical': check_bloq_example_classical_action(be)[0],
}


Expand Down
53 changes: 50 additions & 3 deletions qualtran/_infra/data_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"""

import abc
from typing import Any, Iterable, Union
from typing import Any, Iterable, Optional, Tuple, Union

import attrs
import numpy as np
Expand All @@ -70,6 +70,13 @@ def get_classical_domain(self) -> Iterable[Any]:
"""Yields all possible classical (computational basis state) values representable
by this type."""

@abc.abstractmethod
def get_random_classical_vals(
self, rng: np.random.Generator, size: Optional[Union[int, Tuple[int, ...]]] = None
) -> Any:
"""Returns a random classical (computational basis state) value representable
by this type."""

@abc.abstractmethod
def assert_valid_classical_val(self, val: Any, debug_str: str = 'val'):
"""Raises an exception if `val` is not a valid classical value for this type.
Expand Down Expand Up @@ -106,6 +113,11 @@ def num_qubits(self):
def get_classical_domain(self) -> Iterable[int]:
yield from (0, 1)

def get_random_classical_vals(
self, rng: np.random.Generator, size: Optional[Union[int, Tuple[int, ...]]] = None
) -> Any:
return rng.choice([0, 1], size=size)

def assert_valid_classical_val(self, val: int, debug_str: str = 'val'):
if not (val == 0 or val == 1):
raise ValueError(f"Bad {self} value {val} in {debug_str}")
Expand All @@ -128,6 +140,11 @@ def num_qubits(self):
def get_classical_domain(self) -> Iterable[Any]:
raise TypeError(f"Ambiguous domain for {self}. Please use a more specific type.")

def get_random_classical_vals(
self, rng: np.random.Generator, size: Optional[Union[int, Tuple[int, ...]]] = None
) -> Any:
raise TypeError(f"Ambiguous domain for {self}. Please use a more specific type.")

def assert_valid_classical_val(self, val, debug_str: str = 'val'):
pass

Expand All @@ -154,6 +171,11 @@ def num_qubits(self):
def get_classical_domain(self) -> Iterable[int]:
return range(-(2 ** (self.bitsize - 1)), 2 ** (self.bitsize - 1))

def get_random_classical_vals(
self, rng: np.random.Generator, size: Optional[Union[int, Tuple[int, ...]]] = None
) -> Any:
return rng.integers(-(2 ** (self.bitsize - 1)), 2 ** (self.bitsize - 1), size=size)

def assert_valid_classical_val(self, val: int, debug_str: str = 'val'):
if not isinstance(val, (int, np.integer)):
raise ValueError(f"{debug_str} should be an integer, not {val!r}")
Expand Down Expand Up @@ -193,6 +215,11 @@ def num_qubits(self):
def get_classical_domain(self) -> Iterable[Any]:
raise NotImplementedError()

def get_random_classical_vals(
self, rng: np.random.Generator, size: Optional[Union[int, Tuple[int, ...]]] = None
) -> Any:
raise NotImplementedError()

def assert_valid_classical_val(self, val, debug_str: str = 'val'):
pass # TODO: implement

Expand All @@ -215,7 +242,12 @@ def num_qubits(self):
return self.bitsize

def get_classical_domain(self) -> Iterable[Any]:
return range(2 ** (self.bitsize))
return range(2**self.bitsize)

def get_random_classical_vals(
self, rng: np.random.Generator, size: Optional[Union[int, Tuple[int, ...]]] = None
) -> Any:
return rng.integers(2**self.bitsize, size=size)

def assert_valid_classical_val(self, val: int, debug_str: str = 'val'):
if not isinstance(val, (int, np.integer)):
Expand Down Expand Up @@ -301,6 +333,11 @@ def num_qubits(self):
def get_classical_domain(self) -> Iterable[Any]:
return range(0, self.iteration_length)

def get_random_classical_vals(
self, rng: np.random.Generator, size: Optional[Union[int, Tuple[int, ...]]] = None
) -> Any:
return rng.integers(0, self.iteration_length, size=size)

def assert_valid_classical_val(self, val: int, debug_str: str = 'val'):
if not isinstance(val, (int, np.integer)):
raise ValueError(f"{debug_str} should be an integer, not {val!r}")
Expand Down Expand Up @@ -366,6 +403,11 @@ def __attrs_post_init__(self):
def get_classical_domain(self) -> Iterable[Any]:
raise NotImplementedError()

def get_random_classical_vals(
self, rng: np.random.Generator, size: Optional[Union[int, Tuple[int, ...]]] = None
) -> Any:
raise NotImplementedError()

def assert_valid_classical_val(self, val, debug_str: str = 'val'):
pass # TODO: implement

Expand Down Expand Up @@ -405,7 +447,12 @@ def num_qubits(self):
return self.bitsize

def get_classical_domain(self) -> Iterable[Any]:
return range(2 ** (self.bitsize))
return range(2**self.bitsize)

def get_random_classical_vals(
self, rng: np.random.Generator, size: Optional[Union[int, Tuple[int, ...]]] = None
) -> Any:
return rng.integers(2**self.bitsize, size=size)

def assert_valid_classical_val(self, val: int, debug_str: str = 'val'):
if not isinstance(val, (int, np.integer)):
Expand Down
15 changes: 15 additions & 0 deletions qualtran/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,25 @@ def assert_equivalent_bloq_example_counts_for_pytest(bloq_ex: BloqExample):
raise bce from bce


def assert_bloq_example_classical_action_for_pytest(bloq_ex: BloqExample):
try:
qlt_testing.assert_bloq_example_classical_action(bloq_ex)
except qlt_testing.BloqCheckException as bce:
if bce.check_result in [
qlt_testing.BloqCheckResult.UNVERIFIED,
qlt_testing.BloqCheckResult.NA,
qlt_testing.BloqCheckResult.MISSING,
]:
pytest.skip(bce.msg)

raise bce from bce


_TESTFUNCS = [
('make', assert_bloq_example_make_for_pytest),
('decompose', assert_bloq_example_decompose_for_pytest),
('counts', assert_equivalent_bloq_example_counts_for_pytest),
# ('classical', assert_bloq_example_classical_action_for_pytest),
]


Expand Down
Loading

0 comments on commit 0092122

Please sign in to comment.