Skip to content

Commit 55507d5

Browse files
authored
[cirqflow] Quantum runtime skeleton - part 2 (#4566)
Skeleton of the rest of `ExecutableGroupResult` ![RequestResponse2 (2)](https://user-images.githubusercontent.com/4967059/136300308-21dd2034-01f7-49a3-84a7-0b0d32928918.png) Most of these dataclasses only have barebones attributes which may beg the question: "why do we need a class for this?". Rest assured: I have big plans for adding more attributes to things. This follow #4565 ; splitting up #4556
1 parent 3326f36 commit 55507d5

File tree

7 files changed

+167
-1
lines changed

7 files changed

+167
-1
lines changed

cirq-google/cirq_google/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@
127127
SharedRuntimeInfo,
128128
RuntimeInfo,
129129
ExecutableResult,
130+
ExecutableGroupResult,
131+
QuantumRuntimeConfiguration,
130132
)
131133

132134
from cirq_google import experimental

cirq-google/cirq_google/json_resolver_cache.py

+2
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,6 @@ def _class_resolver_dictionary() -> Dict[str, ObjectFactory]:
4848
'cirq.google.SharedRuntimeInfo': cirq_google.SharedRuntimeInfo,
4949
'cirq.google.RuntimeInfo': cirq_google.RuntimeInfo,
5050
'cirq.google.ExecutableResult': cirq_google.ExecutableResult,
51+
'cirq.google.ExecutableGroupResult': cirq_google.ExecutableGroupResult,
52+
'cirq.google.QuantumRuntimeConfiguration': cirq_google.QuantumRuntimeConfiguration,
5153
}

cirq-google/cirq_google/json_test_data/spec.py

+10
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,20 @@
6060
'QuantumExecutableGroup',
6161
'KeyValueExecutableSpec',
6262
'ExecutableResult',
63+
'ExecutableGroupResult',
64+
'QuantumRuntimeConfiguration',
6365
'RuntimeInfo',
6466
'SharedRuntimeInfo',
6567
]
6668
},
69+
tested_elsewhere=[
70+
# Until `AbstractEngineProcessor` is implemented, we are using
71+
# `AbstractEngineProcessorShim` and a mocked implementation for the `processor` argument
72+
# in tests for `QuantumRuntimeConfiguration` (which is copied into `ExecutableGroupResult`).
73+
# Therefore, we test json roundtrippability for these two classes in quantum_runtime_test.py
74+
'cirq.google.QuantumRuntimeConfiguration',
75+
'cirq.google.ExecutableGroupResult',
76+
],
6777
resolver_cache=_class_resolver_dictionary(),
6878
deprecated={},
6979
)

cirq-google/cirq_google/workflow/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@
1010
SharedRuntimeInfo,
1111
RuntimeInfo,
1212
ExecutableResult,
13+
ExecutableGroupResult,
14+
QuantumRuntimeConfiguration,
1315
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Copyright 2021 The Cirq Developers
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
16+
import abc
17+
18+
import cirq.work
19+
20+
21+
class AbstractEngineProcessorShim(metaclass=abc.ABCMeta):
22+
@abc.abstractmethod
23+
def get_device(self) -> cirq.Device:
24+
pass
25+
26+
@abc.abstractmethod
27+
def get_sampler(self) -> cirq.Sampler:
28+
pass

cirq-google/cirq_google/workflow/quantum_runtime.py

+49-1
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@
1515
"""Runtime information dataclasses that accompany execution of executables."""
1616

1717
import dataclasses
18-
from typing import Any, Dict, Optional
18+
from typing import Any, Dict, Optional, List
1919

2020
import cirq
2121
from cirq import _compat
2222
from cirq.protocols import dataclass_json_dict
23+
from cirq_google.workflow._abstract_engine_processor_shim import AbstractEngineProcessorShim
2324
from cirq_google.workflow.quantum_executable import (
2425
ExecutableSpec,
2526
)
@@ -85,3 +86,50 @@ def _json_dict_(self) -> Dict[str, Any]:
8586

8687
def __repr__(self) -> str:
8788
return _compat.dataclass_repr(self, namespace='cirq_google')
89+
90+
91+
@dataclasses.dataclass
92+
class ExecutableGroupResult:
93+
"""Results for a `cg.QuantumExecutableGroup`.
94+
95+
Args:
96+
runtime_configuration: The `cg.QuantumRuntimeConfiguration` describing how the
97+
`cg.QuantumExecutableGroup` was requested to be executed.
98+
shared_runtime_info: A `cg.SharedRuntimeInfo` dataclass containing information gathered
99+
during execution of the `cg.QuantumExecutableGroup` which is relevant to all
100+
`executable_results`.
101+
executable_results: A list of `cg.ExecutableResult`. Each contains results and raw data
102+
for an individual `cg.QuantumExecutable`.
103+
"""
104+
105+
runtime_configuration: 'QuantumRuntimeConfiguration'
106+
shared_runtime_info: SharedRuntimeInfo
107+
executable_results: List[ExecutableResult]
108+
109+
def _json_dict_(self) -> Dict[str, Any]:
110+
return dataclass_json_dict(self, namespace='cirq.google')
111+
112+
def __repr__(self) -> str:
113+
return _compat.dataclass_repr(self, namespace='cirq_google')
114+
115+
116+
@dataclasses.dataclass
117+
class QuantumRuntimeConfiguration:
118+
"""User-requested configuration of how to execute a given `cg.QuantumExecutableGroup`.
119+
120+
Args:
121+
processor: The `cg.AbstractEngineProcessor` responsible for running circuits and providing
122+
device information.
123+
run_id: A unique `str` identifier for a run. If data already exists for the specified
124+
`run_id`, an exception will be raised. If not specified, we will generate a UUID4
125+
run identifier.
126+
"""
127+
128+
processor: AbstractEngineProcessorShim
129+
run_id: Optional[str] = None
130+
131+
def _json_dict_(self) -> Dict[str, Any]:
132+
return dataclass_json_dict(self, namespace='cirq.google')
133+
134+
def __repr__(self) -> str:
135+
return _compat.dataclass_repr(self, namespace='cirq_google')

cirq-google/cirq_google/workflow/quantum_runtime_test.py

+74
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,34 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
from dataclasses import dataclass
1415

1516
import cirq
1617
import cirq_google as cg
1718
import numpy as np
19+
from cirq_google.workflow._abstract_engine_processor_shim import AbstractEngineProcessorShim
1820
from cirq_google.workflow.quantum_executable_test import _get_example_spec
1921

2022

23+
@dataclass
24+
class _MockEngineProcessor(AbstractEngineProcessorShim):
25+
def get_device(self) -> cirq.Device:
26+
return cg.Sycamore23
27+
28+
def get_sampler(self) -> cirq.Sampler:
29+
return cirq.ZerosSampler()
30+
31+
def _json_dict_(self):
32+
return cirq.obj_to_dict_helper(self, attribute_names=[], namespace='cirq.google.testing')
33+
34+
2135
def cg_assert_equivalent_repr(value):
2236
"""cirq.testing.assert_equivalent_repr with cirq_google.workflow imported."""
2337
return cirq.testing.assert_equivalent_repr(
2438
value,
2539
global_vals={
2640
'cirq_google': cg,
41+
'_MockEngineProcessor': _MockEngineProcessor,
2742
},
2843
)
2944

@@ -46,3 +61,62 @@ def test_executable_result():
4661
raw_data=cirq.Result(params=cirq.ParamResolver(), measurements={'z': np.ones((1_000, 4))}),
4762
)
4863
cg_assert_equivalent_repr(er)
64+
65+
66+
def _cg_read_json_gzip(fn):
67+
def _testing_resolver(cirq_type: str):
68+
if cirq_type == 'cirq.google.testing._MockEngineProcessor':
69+
return _MockEngineProcessor
70+
71+
return cirq.read_json_gzip(fn, resolvers=[_testing_resolver] + cirq.DEFAULT_RESOLVERS)
72+
73+
74+
def _assert_json_roundtrip(o, tmpdir):
75+
cirq.to_json_gzip(o, f'{tmpdir}/o.json')
76+
o2 = _cg_read_json_gzip(f'{tmpdir}/o.json')
77+
assert o == o2
78+
79+
80+
def test_quantum_runtime_configuration():
81+
rt_config = cg.QuantumRuntimeConfiguration(
82+
processor=_MockEngineProcessor(),
83+
run_id='unit-test',
84+
)
85+
86+
sampler = rt_config.processor.get_sampler()
87+
result = sampler.run(cirq.Circuit(cirq.measure(cirq.LineQubit(0), key='z')))
88+
assert isinstance(result, cirq.Result)
89+
90+
assert isinstance(rt_config.processor.get_device(), cirq.Device)
91+
92+
93+
def test_quantum_runtime_configuration_serialization(tmpdir):
94+
rt_config = cg.QuantumRuntimeConfiguration(
95+
processor=_MockEngineProcessor(),
96+
run_id='unit-test',
97+
)
98+
cg_assert_equivalent_repr(rt_config)
99+
_assert_json_roundtrip(rt_config, tmpdir)
100+
101+
102+
def test_executable_group_result(tmpdir):
103+
egr = cg.ExecutableGroupResult(
104+
runtime_configuration=cg.QuantumRuntimeConfiguration(
105+
processor=_MockEngineProcessor(),
106+
run_id='unit-test',
107+
),
108+
shared_runtime_info=cg.SharedRuntimeInfo(run_id='my run'),
109+
executable_results=[
110+
cg.ExecutableResult(
111+
spec=_get_example_spec(name=f'test-spec-{i}'),
112+
runtime_info=cg.RuntimeInfo(execution_index=i),
113+
raw_data=cirq.Result(
114+
params=cirq.ParamResolver(), measurements={'z': np.ones((1_000, 4))}
115+
),
116+
)
117+
for i in range(3)
118+
],
119+
)
120+
cg_assert_equivalent_repr(egr)
121+
assert len(egr.executable_results) == 3
122+
_assert_json_roundtrip(egr, tmpdir)

0 commit comments

Comments
 (0)