Skip to content

Commit

Permalink
[cirqflow] QuantumExecutableGroup (#4551)
Browse files Browse the repository at this point in the history
This is a simple container for a sequence of quantum executables. It ensures immutability and caches potentially expensive hash values.
![RequestResponse2 (1)](https://user-images.githubusercontent.com/4967059/135943054-1743c6e1-02d6-4ff5-becf-313b91646922.png)


follows #4527
  • Loading branch information
mpharrigan authored Oct 5, 2021
1 parent 7e0d5d2 commit eaa7f33
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 2 deletions.
1 change: 1 addition & 0 deletions cirq-google/cirq_google/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
from cirq_google.workflow import (
ExecutableSpec,
QuantumExecutable,
QuantumExecutableGroup,
BitstringsMeasurement,
)

Expand Down
1 change: 1 addition & 0 deletions cirq-google/cirq_google/json_resolver_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ def _class_resolver_dictionary() -> Dict[str, ObjectFactory]:
'LocalXEBPhasedFSimCalibrationRequest': cirq_google.LocalXEBPhasedFSimCalibrationRequest,
'cirq.google.BitstringsMeasurement': cirq_google.BitstringsMeasurement,
'cirq.google.QuantumExecutable': cirq_google.QuantumExecutable,
'cirq.google.QuantumExecutableGroup': cirq_google.QuantumExecutableGroup,
}
2 changes: 2 additions & 0 deletions cirq-google/cirq_google/json_test_data/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,14 @@
for k in [
'BitstringsMeasurement',
'QuantumExecutable',
'QuantumExecutableGroup',
]
},
tested_elsewhere=[
# Requires a concrete ExecutableSpec,
# serialization tested in cirq_google/workflow/quantum_executable_test
'cirq.google.QuantumExecutable',
'cirq.google.QuantumExecutableGroup',
],
resolver_cache=_class_resolver_dictionary(),
deprecated={},
Expand Down
1 change: 1 addition & 0 deletions cirq-google/cirq_google/workflow/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from cirq_google.workflow.quantum_executable import (
ExecutableSpec,
QuantumExecutable,
QuantumExecutableGroup,
BitstringsMeasurement,
)
52 changes: 51 additions & 1 deletion cirq-google/cirq_google/workflow/quantum_executable.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import abc
import dataclasses
from dataclasses import dataclass
from typing import Union, Tuple, Optional, Sequence, cast
from typing import Union, Tuple, Optional, Sequence, cast, Iterable, Dict, Any

from cirq import _compat, study
import cirq
Expand Down Expand Up @@ -157,3 +157,53 @@ def __repr__(self):

def _json_dict_(self):
return cirq.dataclass_json_dict(self, namespace='cirq.google')


@dataclass(frozen=True)
class QuantumExecutableGroup:
"""A collection of `QuantumExecutable`s.
Attributes:
executables: A tuple of `cg.QuantumExecutable`.
"""

executables: Tuple[QuantumExecutable, ...]

def __init__(
self,
executables: Sequence[QuantumExecutable],
):
"""Initialize and normalize the quantum executable group.
Args:
executables: A sequence of `cg.QuantumExecutable` which will be frozen into a
tuple.
"""

if not isinstance(executables, tuple):
executables = tuple(executables)
object.__setattr__(self, 'executables', executables)

object.__setattr__(self, '_hash', hash(dataclasses.astuple(self)))

def __len__(self) -> int:
return len(self.executables)

def __iter__(self) -> Iterable[QuantumExecutable]:
yield from self.executables

def __str__(self) -> str:
exe_str = ', '.join(str(exe) for exe in self.executables[:2])
if len(self.executables) > 2:
exe_str += ', ...'

return f'QuantumExecutable(executables=[{exe_str}])'

def __repr__(self) -> str:
return _compat.dataclass_repr(self, namespace='cirq_google')

def __hash__(self) -> int:
return self._hash # type: ignore

def _json_dict_(self) -> Dict[str, Any]:
return cirq.dataclass_json_dict(self, namespace='cirq.google')
60 changes: 59 additions & 1 deletion cirq-google/cirq_google/workflow/quantum_executable_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@
import cirq
import cirq_google
import pytest
from cirq_google import QuantumExecutable, BitstringsMeasurement, ExecutableSpec
from cirq_google import (
QuantumExecutable,
BitstringsMeasurement,
ExecutableSpec,
QuantumExecutableGroup,
)


def test_bitstrings_measurement():
Expand Down Expand Up @@ -117,3 +122,56 @@ def test_quantum_executable_inputs():
)
with pytest.raises(TypeError):
_ = QuantumExecutable(spec={'name': 'main'}, circuit=circuit, measurement=measurement)


def _get_quantum_executables():
qubits = cirq.LineQubit.range(10)
return [
QuantumExecutable(
spec=ExampleSpec(name=f'example-program-{i}'),
circuit=_get_random_circuit(qubits, random_state=i),
measurement=BitstringsMeasurement(n_repetitions=10),
)
for i in range(3)
]


def test_quantum_executable_group_to_tuple():
exes1 = list(_get_quantum_executables())
exes2 = tuple(_get_quantum_executables())

eg1 = QuantumExecutableGroup(exes1)
eg2 = QuantumExecutableGroup(exes2)
assert hash(eg1) == hash(eg2)
assert eg1 == eg2


def test_quantum_executable_group_methods():
exes = _get_quantum_executables()
eg = QuantumExecutableGroup(exes)

# pylint: disable=line-too-long
assert str(eg) == (
"QuantumExecutable(executables=["
"QuantumExecutable(spec=ExampleSpec(name='example-program-0', executable_family='cirq_google.algo_benchmarks.example')), "
"QuantumExecutable(spec=ExampleSpec(name='example-program-1', executable_family='cirq_google.algo_benchmarks.example')), ...])"
)
# pylint: enable=line-too-long

assert len(eg) == len(exes), '__len__'
assert exes == [e for e in eg], '__iter__'


def test_quantum_executable_group_serialization(tmpdir):
exes = _get_quantum_executables()
eg = QuantumExecutableGroup(exes)

cirq.testing.assert_equivalent_repr(
eg, global_vals={'ExampleSpec': ExampleSpec, 'cirq_google': cirq_google}
)

cirq.to_json(eg, f'{tmpdir}/eg.json')
eg_reconstructed = cirq.read_json(
f'{tmpdir}/eg.json', resolvers=[_testing_resolver] + cirq.DEFAULT_RESOLVERS
)
assert eg == eg_reconstructed

0 comments on commit eaa7f33

Please sign in to comment.