cirq-core 1.1.0.dev20221219200817__py3-none-any.whl → 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cirq/__init__.py +8 -0
- cirq/_compat.py +29 -4
- cirq/_compat_test.py +24 -26
- cirq/_version.py +32 -1
- cirq/_version_test.py +1 -1
- cirq/circuits/_block_diagram_drawer_test.py +4 -3
- cirq/circuits/circuit.py +109 -63
- cirq/circuits/circuit_operation.py +2 -3
- cirq/circuits/circuit_operation_test.py +4 -4
- cirq/circuits/circuit_test.py +11 -0
- cirq/circuits/frozen_circuit.py +13 -1
- cirq/circuits/frozen_circuit_test.py +5 -1
- cirq/circuits/moment.py +39 -14
- cirq/circuits/moment_test.py +7 -0
- cirq/circuits/text_diagram_drawer.py +1 -1
- cirq/circuits/text_diagram_drawer_test.py +3 -7
- cirq/conftest.py +8 -0
- cirq/contrib/acquaintance/bipartite.py +1 -1
- cirq/contrib/acquaintance/devices.py +2 -2
- cirq/contrib/acquaintance/executor.py +5 -2
- cirq/contrib/acquaintance/gates.py +3 -2
- cirq/contrib/acquaintance/permutation.py +13 -2
- cirq/contrib/acquaintance/testing.py +3 -5
- cirq/contrib/paulistring/recombine.py +3 -6
- cirq/contrib/qasm_import/_parser.py +17 -21
- cirq/contrib/qasm_import/_parser_test.py +30 -45
- cirq/contrib/qcircuit/qcircuit_test.py +3 -7
- cirq/contrib/quantum_volume/quantum_volume.py +3 -3
- cirq/contrib/quimb/mps_simulator.py +1 -1
- cirq/contrib/quimb/state_vector.py +2 -0
- cirq/contrib/quirk/quirk_gate.py +1 -0
- cirq/contrib/svg/svg.py +4 -7
- cirq/contrib/svg/svg_test.py +29 -1
- cirq/devices/grid_qubit.py +26 -28
- cirq/devices/grid_qubit_test.py +21 -5
- cirq/devices/line_qubit.py +10 -12
- cirq/devices/line_qubit_test.py +9 -2
- cirq/devices/named_topologies.py +1 -1
- cirq/devices/noise_model.py +4 -1
- cirq/devices/superconducting_qubits_noise_properties.py +1 -3
- cirq/experiments/n_qubit_tomography.py +1 -1
- cirq/experiments/qubit_characterizations.py +2 -2
- cirq/experiments/single_qubit_readout_calibration.py +1 -1
- cirq/experiments/t2_decay_experiment.py +1 -1
- cirq/experiments/xeb_simulation_test.py +2 -2
- cirq/interop/quirk/cells/testing.py +1 -1
- cirq/json_resolver_cache.py +1 -0
- cirq/linalg/__init__.py +2 -0
- cirq/linalg/decompositions_test.py +4 -4
- cirq/linalg/diagonalize_test.py +5 -6
- cirq/linalg/transformations.py +72 -9
- cirq/linalg/transformations_test.py +23 -7
- cirq/ops/__init__.py +4 -0
- cirq/ops/arithmetic_operation.py +4 -6
- cirq/ops/classically_controlled_operation.py +10 -3
- cirq/ops/clifford_gate.py +1 -7
- cirq/ops/common_channels.py +21 -15
- cirq/ops/common_gate_families.py +2 -3
- cirq/ops/common_gates.py +48 -11
- cirq/ops/common_gates_test.py +4 -0
- cirq/ops/controlled_gate.py +44 -18
- cirq/ops/controlled_operation.py +13 -5
- cirq/ops/dense_pauli_string.py +14 -19
- cirq/ops/diagonal_gate.py +3 -4
- cirq/ops/eigen_gate.py +8 -10
- cirq/ops/eigen_gate_test.py +6 -0
- cirq/ops/gate_operation.py +11 -6
- cirq/ops/gate_operation_test.py +11 -2
- cirq/ops/gateset.py +2 -1
- cirq/ops/gateset_test.py +38 -5
- cirq/ops/global_phase_op.py +28 -2
- cirq/ops/global_phase_op_test.py +21 -0
- cirq/ops/identity.py +1 -1
- cirq/ops/kraus_channel_test.py +2 -2
- cirq/ops/linear_combinations.py +7 -6
- cirq/ops/linear_combinations_test.py +26 -10
- cirq/ops/matrix_gates.py +8 -4
- cirq/ops/matrix_gates_test.py +25 -3
- cirq/ops/measure_util.py +13 -5
- cirq/ops/measure_util_test.py +8 -2
- cirq/ops/measurement_gate.py +1 -1
- cirq/ops/measurement_gate_test.py +9 -4
- cirq/ops/mixed_unitary_channel_test.py +4 -4
- cirq/ops/named_qubit.py +2 -4
- cirq/ops/parity_gates.py +5 -1
- cirq/ops/parity_gates_test.py +6 -0
- cirq/ops/pauli_gates.py +9 -9
- cirq/ops/pauli_string.py +4 -2
- cirq/ops/pauli_string_raw_types.py +4 -11
- cirq/ops/pauli_string_test.py +13 -13
- cirq/ops/pauli_sum_exponential.py +6 -1
- cirq/ops/qubit_manager.py +97 -0
- cirq/ops/qubit_manager_test.py +66 -0
- cirq/ops/raw_types.py +75 -33
- cirq/ops/raw_types_test.py +34 -0
- cirq/ops/three_qubit_gates.py +16 -10
- cirq/ops/three_qubit_gates_test.py +4 -2
- cirq/ops/two_qubit_diagonal_gate.py +3 -3
- cirq/ops/wait_gate.py +1 -1
- cirq/protocols/__init__.py +1 -0
- cirq/protocols/act_on_protocol.py +3 -3
- cirq/protocols/act_on_protocol_test.py +5 -5
- cirq/protocols/apply_channel_protocol.py +9 -8
- cirq/protocols/apply_mixture_protocol.py +8 -8
- cirq/protocols/apply_mixture_protocol_test.py +1 -1
- cirq/protocols/apply_unitary_protocol.py +66 -19
- cirq/protocols/apply_unitary_protocol_test.py +50 -0
- cirq/protocols/circuit_diagram_info_protocol.py +7 -9
- cirq/protocols/decompose_protocol.py +167 -125
- cirq/protocols/decompose_protocol_test.py +132 -2
- cirq/protocols/has_stabilizer_effect_protocol.py +2 -1
- cirq/protocols/inverse_protocol.py +2 -2
- cirq/protocols/json_serialization_test.py +3 -3
- cirq/protocols/json_test_data/Linspace.json +20 -7
- cirq/protocols/json_test_data/Linspace.repr +4 -1
- cirq/protocols/json_test_data/Points.json +19 -8
- cirq/protocols/json_test_data/Points.repr +4 -1
- cirq/protocols/json_test_data/Result.repr_inward +1 -1
- cirq/protocols/json_test_data/ResultDict.repr +1 -1
- cirq/protocols/json_test_data/ResultDict.repr_inward +1 -1
- cirq/protocols/json_test_data/TrialResult.repr_inward +1 -1
- cirq/protocols/json_test_data/XPowGate.json +13 -5
- cirq/protocols/json_test_data/XPowGate.repr +1 -1
- cirq/protocols/json_test_data/ZPowGate.json +13 -5
- cirq/protocols/json_test_data/ZPowGate.repr +1 -1
- cirq/protocols/json_test_data/ZipLongest.json +19 -0
- cirq/protocols/json_test_data/ZipLongest.repr +1 -0
- cirq/protocols/json_test_data/spec.py +1 -0
- cirq/protocols/kraus_protocol.py +3 -4
- cirq/protocols/measurement_key_protocol.py +3 -1
- cirq/protocols/mixture_protocol.py +3 -2
- cirq/protocols/phase_protocol.py +3 -3
- cirq/protocols/pow_protocol.py +1 -2
- cirq/protocols/qasm.py +4 -4
- cirq/protocols/qid_shape_protocol.py +8 -8
- cirq/protocols/resolve_parameters.py +8 -3
- cirq/protocols/resolve_parameters_test.py +3 -3
- cirq/protocols/unitary_protocol.py +19 -11
- cirq/protocols/unitary_protocol_test.py +37 -0
- cirq/qis/channels.py +1 -1
- cirq/qis/clifford_tableau.py +4 -5
- cirq/qis/quantum_state_representation.py +7 -9
- cirq/qis/states.py +21 -13
- cirq/qis/states_test.py +7 -0
- cirq/sim/clifford/clifford_simulator.py +3 -3
- cirq/sim/density_matrix_simulation_state.py +2 -1
- cirq/sim/density_matrix_simulator.py +1 -1
- cirq/sim/density_matrix_simulator_test.py +9 -5
- cirq/sim/density_matrix_utils.py +7 -32
- cirq/sim/mux.py +2 -2
- cirq/sim/simulation_state.py +58 -18
- cirq/sim/simulation_state_base.py +5 -2
- cirq/sim/simulation_state_test.py +121 -9
- cirq/sim/simulation_utils.py +59 -0
- cirq/sim/simulation_utils_test.py +32 -0
- cirq/sim/simulator.py +2 -1
- cirq/sim/simulator_base_test.py +3 -3
- cirq/sim/sparse_simulator.py +1 -1
- cirq/sim/sparse_simulator_test.py +5 -5
- cirq/sim/state_vector.py +7 -36
- cirq/sim/state_vector_simulation_state.py +18 -1
- cirq/sim/state_vector_simulator.py +3 -2
- cirq/sim/state_vector_simulator_test.py +24 -2
- cirq/sim/state_vector_test.py +46 -15
- cirq/study/__init__.py +1 -0
- cirq/study/flatten_expressions.py +2 -2
- cirq/study/resolver.py +2 -0
- cirq/study/resolver_test.py +1 -1
- cirq/study/result.py +1 -1
- cirq/study/sweeps.py +103 -9
- cirq/study/sweeps_test.py +64 -0
- cirq/testing/__init__.py +4 -0
- cirq/testing/circuit_compare.py +15 -18
- cirq/testing/consistent_act_on.py +4 -4
- cirq/testing/consistent_controlled_gate_op_test.py +1 -1
- cirq/testing/consistent_decomposition.py +11 -2
- cirq/testing/consistent_decomposition_test.py +8 -1
- cirq/testing/consistent_protocols.py +2 -0
- cirq/testing/consistent_protocols_test.py +8 -4
- cirq/testing/consistent_qasm.py +8 -15
- cirq/testing/consistent_specified_has_unitary.py +1 -1
- cirq/testing/consistent_unitary.py +85 -0
- cirq/testing/consistent_unitary_test.py +96 -0
- cirq/testing/equivalent_repr_eval.py +10 -10
- cirq/testing/json.py +3 -3
- cirq/testing/logs.py +1 -1
- cirq/testing/order_tester.py +4 -5
- cirq/testing/random_circuit.py +3 -5
- cirq/testing/sample_gates.py +79 -0
- cirq/testing/sample_gates_test.py +59 -0
- cirq/transformers/__init__.py +2 -0
- cirq/transformers/analytical_decompositions/__init__.py +8 -0
- cirq/transformers/analytical_decompositions/pauli_string_decomposition.py +130 -0
- cirq/transformers/analytical_decompositions/pauli_string_decomposition_test.py +58 -0
- cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py +230 -0
- cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py +112 -0
- cirq/transformers/analytical_decompositions/three_qubit_decomposition_test.py +1 -3
- cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +1 -1
- cirq/transformers/expand_composite.py +1 -1
- cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +4 -4
- cirq/transformers/measurement_transformers.py +4 -4
- cirq/transformers/merge_single_qubit_gates.py +17 -4
- cirq/transformers/routing/route_circuit_cqc.py +2 -2
- cirq/transformers/stratify.py +125 -62
- cirq/transformers/stratify_test.py +20 -16
- cirq/transformers/transformer_api.py +1 -1
- cirq/transformers/transformer_primitives.py +3 -2
- cirq/transformers/transformer_primitives_test.py +11 -0
- cirq/value/abc_alt.py +3 -2
- cirq/value/abc_alt_test.py +1 -0
- cirq/value/classical_data.py +10 -10
- cirq/value/digits.py +2 -2
- cirq/value/linear_dict.py +18 -19
- cirq/value/product_state.py +7 -6
- cirq/value/value_equality_attr.py +2 -2
- cirq/vis/heatmap.py +1 -1
- cirq/vis/heatmap_test.py +2 -2
- cirq/work/collector.py +2 -2
- cirq/work/observable_measurement_data.py +5 -5
- cirq/work/observable_readout_calibration.py +3 -1
- cirq/work/observable_settings.py +1 -1
- cirq/work/pauli_sum_collector.py +9 -8
- cirq/work/sampler.py +2 -0
- cirq/work/zeros_sampler.py +2 -2
- {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/METADATA +7 -15
- {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/RECORD +229 -215
- {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/WHEEL +1 -1
- {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/LICENSE +0 -0
- {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/top_level.txt +0 -0
|
@@ -11,13 +11,17 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
-
|
|
14
|
+
import itertools
|
|
15
|
+
import dataclasses
|
|
16
|
+
import inspect
|
|
17
|
+
from collections import defaultdict
|
|
15
18
|
from typing import (
|
|
16
19
|
TYPE_CHECKING,
|
|
17
20
|
Any,
|
|
18
21
|
Callable,
|
|
19
22
|
Dict,
|
|
20
23
|
Iterable,
|
|
24
|
+
Iterator,
|
|
21
25
|
List,
|
|
22
26
|
Optional,
|
|
23
27
|
overload,
|
|
@@ -26,7 +30,7 @@ from typing import (
|
|
|
26
30
|
TypeVar,
|
|
27
31
|
Union,
|
|
28
32
|
)
|
|
29
|
-
from
|
|
33
|
+
from typing_extensions import runtime_checkable
|
|
30
34
|
|
|
31
35
|
from typing_extensions import Protocol
|
|
32
36
|
|
|
@@ -45,7 +49,19 @@ TError = TypeVar('TError', bound=Exception)
|
|
|
45
49
|
RaiseTypeErrorIfNotProvided: Any = ([],)
|
|
46
50
|
|
|
47
51
|
DecomposeResult = Union[None, NotImplementedType, 'cirq.OP_TREE']
|
|
48
|
-
|
|
52
|
+
|
|
53
|
+
_CONTEXT_COUNTER = itertools.count() # Use _reset_context_counter() to reset the counter.
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@runtime_checkable
|
|
57
|
+
class OpDecomposerWithContext(Protocol):
|
|
58
|
+
def __call__(
|
|
59
|
+
self, __op: 'cirq.Operation', *, context: Optional['cirq.DecompositionContext'] = None
|
|
60
|
+
) -> DecomposeResult:
|
|
61
|
+
...
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
OpDecomposer = Union[Callable[['cirq.Operation'], DecomposeResult], OpDecomposerWithContext]
|
|
49
65
|
|
|
50
66
|
DECOMPOSE_TARGET_GATESET = ops.Gateset(
|
|
51
67
|
ops.XPowGate,
|
|
@@ -61,6 +77,18 @@ def _value_error_describing_bad_operation(op: 'cirq.Operation') -> ValueError:
|
|
|
61
77
|
return ValueError(f"Operation doesn't satisfy the given `keep` but can't be decomposed: {op!r}")
|
|
62
78
|
|
|
63
79
|
|
|
80
|
+
@dataclasses.dataclass(frozen=True)
|
|
81
|
+
class DecompositionContext:
|
|
82
|
+
"""Stores common configurable options for decomposing composite gates into simpler operations.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
qubit_manager: A `cirq.QubitManager` instance to allocate clean / dirty ancilla qubits as
|
|
86
|
+
part of the decompose protocol.
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
qubit_manager: 'cirq.QubitManager'
|
|
90
|
+
|
|
91
|
+
|
|
64
92
|
class SupportsDecompose(Protocol):
|
|
65
93
|
"""An object that can be decomposed into simpler operations.
|
|
66
94
|
|
|
@@ -104,6 +132,11 @@ class SupportsDecompose(Protocol):
|
|
|
104
132
|
def _decompose_(self) -> DecomposeResult:
|
|
105
133
|
pass
|
|
106
134
|
|
|
135
|
+
def _decompose_with_context_(
|
|
136
|
+
self, *, context: Optional[DecompositionContext] = None
|
|
137
|
+
) -> DecomposeResult:
|
|
138
|
+
pass
|
|
139
|
+
|
|
107
140
|
|
|
108
141
|
class SupportsDecomposeWithQubits(Protocol):
|
|
109
142
|
"""An object that can be decomposed into operations on given qubits.
|
|
@@ -127,6 +160,72 @@ class SupportsDecomposeWithQubits(Protocol):
|
|
|
127
160
|
def _decompose_(self, qubits: Tuple['cirq.Qid', ...]) -> DecomposeResult:
|
|
128
161
|
pass
|
|
129
162
|
|
|
163
|
+
def _decompose_with_context_(
|
|
164
|
+
self, qubits: Tuple['cirq.Qid', ...], *, context: Optional[DecompositionContext] = None
|
|
165
|
+
) -> DecomposeResult:
|
|
166
|
+
pass
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _try_op_decomposer(
|
|
170
|
+
val: Any, decomposer: Optional[OpDecomposer], *, context: Optional[DecompositionContext] = None
|
|
171
|
+
) -> DecomposeResult:
|
|
172
|
+
if decomposer is None or not isinstance(val, ops.Operation):
|
|
173
|
+
return None
|
|
174
|
+
if 'context' in inspect.signature(decomposer).parameters:
|
|
175
|
+
assert isinstance(decomposer, OpDecomposerWithContext)
|
|
176
|
+
return decomposer(val, context=context)
|
|
177
|
+
else:
|
|
178
|
+
return decomposer(val)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@dataclasses.dataclass(frozen=True)
|
|
182
|
+
class _DecomposeArgs:
|
|
183
|
+
context: Optional[DecompositionContext]
|
|
184
|
+
intercepting_decomposer: Optional[OpDecomposer]
|
|
185
|
+
fallback_decomposer: Optional[OpDecomposer]
|
|
186
|
+
keep: Optional[Callable[['cirq.Operation'], bool]]
|
|
187
|
+
on_stuck_raise: Union[None, Exception, Callable[['cirq.Operation'], Optional[Exception]]]
|
|
188
|
+
preserve_structure: bool
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _decompose_dfs(item: Any, args: _DecomposeArgs) -> Iterator['cirq.Operation']:
|
|
192
|
+
from cirq.circuits import CircuitOperation, FrozenCircuit
|
|
193
|
+
|
|
194
|
+
if isinstance(item, ops.Operation):
|
|
195
|
+
item_untagged = item.untagged
|
|
196
|
+
if args.preserve_structure and isinstance(item_untagged, CircuitOperation):
|
|
197
|
+
new_fc = FrozenCircuit(_decompose_dfs(item_untagged.circuit, args))
|
|
198
|
+
yield item_untagged.replace(circuit=new_fc).with_tags(*item.tags)
|
|
199
|
+
return
|
|
200
|
+
if args.keep is not None and args.keep(item):
|
|
201
|
+
yield item
|
|
202
|
+
return
|
|
203
|
+
|
|
204
|
+
decomposed = _try_op_decomposer(item, args.intercepting_decomposer, context=args.context)
|
|
205
|
+
|
|
206
|
+
if decomposed is NotImplemented or decomposed is None:
|
|
207
|
+
decomposed = decompose_once(item, default=None, flatten=False, context=args.context)
|
|
208
|
+
|
|
209
|
+
if decomposed is NotImplemented or decomposed is None:
|
|
210
|
+
decomposed = _try_op_decomposer(item, args.fallback_decomposer, context=args.context)
|
|
211
|
+
|
|
212
|
+
if decomposed is NotImplemented or decomposed is None:
|
|
213
|
+
if not isinstance(item, ops.Operation) and isinstance(item, Iterable):
|
|
214
|
+
decomposed = item
|
|
215
|
+
|
|
216
|
+
if decomposed is NotImplemented or decomposed is None:
|
|
217
|
+
if args.keep is not None and args.on_stuck_raise is not None:
|
|
218
|
+
if isinstance(args.on_stuck_raise, Exception):
|
|
219
|
+
raise args.on_stuck_raise
|
|
220
|
+
elif callable(args.on_stuck_raise):
|
|
221
|
+
error = args.on_stuck_raise(item)
|
|
222
|
+
if error is not None:
|
|
223
|
+
raise error
|
|
224
|
+
yield item
|
|
225
|
+
else:
|
|
226
|
+
for val in ops.flatten_to_ops(decomposed):
|
|
227
|
+
yield from _decompose_dfs(val, args)
|
|
228
|
+
|
|
130
229
|
|
|
131
230
|
def decompose(
|
|
132
231
|
val: Any,
|
|
@@ -138,6 +237,7 @@ def decompose(
|
|
|
138
237
|
None, Exception, Callable[['cirq.Operation'], Optional[Exception]]
|
|
139
238
|
] = _value_error_describing_bad_operation,
|
|
140
239
|
preserve_structure: bool = False,
|
|
240
|
+
context: Optional[DecompositionContext] = None,
|
|
141
241
|
) -> List['cirq.Operation']:
|
|
142
242
|
"""Recursively decomposes a value into `cirq.Operation`s meeting a criteria.
|
|
143
243
|
|
|
@@ -169,6 +269,8 @@ def decompose(
|
|
|
169
269
|
preserve_structure: Prevents subcircuits (i.e. `CircuitOperation`s)
|
|
170
270
|
from being decomposed, but decomposes their contents. If this is
|
|
171
271
|
True, `intercepting_decomposer` cannot be specified.
|
|
272
|
+
context: Decomposition context specifying common configurable options for
|
|
273
|
+
controlling the behavior of decompose.
|
|
172
274
|
|
|
173
275
|
Returns:
|
|
174
276
|
A list of operations that the given value was decomposed into. If
|
|
@@ -200,55 +302,17 @@ def decompose(
|
|
|
200
302
|
"acceptable to keep."
|
|
201
303
|
)
|
|
202
304
|
|
|
203
|
-
if
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
return None
|
|
215
|
-
return decomposer(val)
|
|
216
|
-
|
|
217
|
-
output = []
|
|
218
|
-
queue: List[Any] = [val]
|
|
219
|
-
while queue:
|
|
220
|
-
item = queue.pop(0)
|
|
221
|
-
if isinstance(item, ops.Operation) and keep is not None and keep(item):
|
|
222
|
-
output.append(item)
|
|
223
|
-
continue
|
|
224
|
-
|
|
225
|
-
decomposed = try_op_decomposer(item, intercepting_decomposer)
|
|
226
|
-
|
|
227
|
-
if decomposed is NotImplemented or decomposed is None:
|
|
228
|
-
decomposed = decompose_once(item, default=None)
|
|
229
|
-
|
|
230
|
-
if decomposed is NotImplemented or decomposed is None:
|
|
231
|
-
decomposed = try_op_decomposer(item, fallback_decomposer)
|
|
232
|
-
|
|
233
|
-
if decomposed is not NotImplemented and decomposed is not None:
|
|
234
|
-
queue[:0] = ops.flatten_to_ops(decomposed)
|
|
235
|
-
continue
|
|
236
|
-
|
|
237
|
-
if not isinstance(item, ops.Operation) and isinstance(item, Iterable):
|
|
238
|
-
queue[:0] = ops.flatten_to_ops(item)
|
|
239
|
-
continue
|
|
240
|
-
|
|
241
|
-
if keep is not None and on_stuck_raise is not None:
|
|
242
|
-
if isinstance(on_stuck_raise, Exception):
|
|
243
|
-
raise on_stuck_raise
|
|
244
|
-
elif callable(on_stuck_raise):
|
|
245
|
-
error = on_stuck_raise(item)
|
|
246
|
-
if error is not None:
|
|
247
|
-
raise error
|
|
248
|
-
|
|
249
|
-
output.append(item)
|
|
250
|
-
|
|
251
|
-
return output
|
|
305
|
+
if context is None:
|
|
306
|
+
context = DecompositionContext(ops.SimpleQubitManager(prefix='_decompose_protocol'))
|
|
307
|
+
args = _DecomposeArgs(
|
|
308
|
+
context=context,
|
|
309
|
+
intercepting_decomposer=intercepting_decomposer,
|
|
310
|
+
fallback_decomposer=fallback_decomposer,
|
|
311
|
+
keep=keep,
|
|
312
|
+
on_stuck_raise=on_stuck_raise,
|
|
313
|
+
preserve_structure=preserve_structure,
|
|
314
|
+
)
|
|
315
|
+
return [*_decompose_dfs(val, args)]
|
|
252
316
|
|
|
253
317
|
|
|
254
318
|
# pylint: disable=function-redefined
|
|
@@ -261,12 +325,19 @@ def decompose_once(val: Any, **kwargs) -> List['cirq.Operation']:
|
|
|
261
325
|
|
|
262
326
|
@overload
|
|
263
327
|
def decompose_once(
|
|
264
|
-
val: Any, default: TDefault, *args, **kwargs
|
|
328
|
+
val: Any, default: TDefault, *args, flatten: bool = True, **kwargs
|
|
265
329
|
) -> Union[TDefault, List['cirq.Operation']]:
|
|
266
330
|
pass
|
|
267
331
|
|
|
268
332
|
|
|
269
|
-
def decompose_once(
|
|
333
|
+
def decompose_once(
|
|
334
|
+
val: Any,
|
|
335
|
+
default=RaiseTypeErrorIfNotProvided,
|
|
336
|
+
*args,
|
|
337
|
+
flatten: bool = True,
|
|
338
|
+
context: Optional[DecompositionContext] = None,
|
|
339
|
+
**kwargs,
|
|
340
|
+
):
|
|
270
341
|
"""Decomposes a value into operations, if possible.
|
|
271
342
|
|
|
272
343
|
This method decomposes the value exactly once, instead of decomposing it
|
|
@@ -282,6 +353,9 @@ def decompose_once(val: Any, default=RaiseTypeErrorIfNotProvided, *args, **kwarg
|
|
|
282
353
|
*args: Positional arguments to forward into the `_decompose_` method of
|
|
283
354
|
`val`. For example, this is used to tell gates what qubits they are
|
|
284
355
|
being applied to.
|
|
356
|
+
flatten: If True, the returned OP-TREE will be flattened to a list of operations.
|
|
357
|
+
context: Decomposition context specifying common configurable options for
|
|
358
|
+
controlling the behavior of decompose.
|
|
285
359
|
**kwargs: Keyword arguments to forward into the `_decompose_` method of
|
|
286
360
|
`val`.
|
|
287
361
|
|
|
@@ -295,36 +369,62 @@ def decompose_once(val: Any, default=RaiseTypeErrorIfNotProvided, *args, **kwarg
|
|
|
295
369
|
TypeError: `val` didn't have a `_decompose_` method (or that method returned
|
|
296
370
|
`NotImplemented` or `None`) and `default` wasn't set.
|
|
297
371
|
"""
|
|
298
|
-
|
|
299
|
-
|
|
372
|
+
if context is None:
|
|
373
|
+
context = DecompositionContext(
|
|
374
|
+
ops.SimpleQubitManager(prefix=f'_decompose_protocol_{next(_CONTEXT_COUNTER)}')
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
method = getattr(val, '_decompose_with_context_', None)
|
|
378
|
+
decomposed = NotImplemented if method is None else method(*args, **kwargs, context=context)
|
|
379
|
+
if decomposed is NotImplemented or None:
|
|
380
|
+
method = getattr(val, '_decompose_', None)
|
|
381
|
+
decomposed = NotImplemented if method is None else method(*args, **kwargs)
|
|
300
382
|
|
|
301
383
|
if decomposed is not NotImplemented and decomposed is not None:
|
|
302
|
-
return list(ops.
|
|
384
|
+
return list(ops.flatten_to_ops(decomposed)) if flatten else decomposed
|
|
303
385
|
|
|
304
386
|
if default is not RaiseTypeErrorIfNotProvided:
|
|
305
387
|
return default
|
|
306
388
|
if method is None:
|
|
307
|
-
raise TypeError(
|
|
389
|
+
raise TypeError(
|
|
390
|
+
f"object of type '{type(val)}' has no _decompose_with_context_ or "
|
|
391
|
+
f"_decompose_ method."
|
|
392
|
+
)
|
|
308
393
|
raise TypeError(
|
|
309
|
-
"object of type
|
|
310
|
-
"but it returned NotImplemented or None."
|
|
394
|
+
f"object of type {type(val)} does have a _decompose_ method, "
|
|
395
|
+
"but it returned NotImplemented or None."
|
|
311
396
|
)
|
|
312
397
|
|
|
313
398
|
|
|
314
399
|
@overload
|
|
315
|
-
def decompose_once_with_qubits(
|
|
400
|
+
def decompose_once_with_qubits(
|
|
401
|
+
val: Any,
|
|
402
|
+
qubits: Iterable['cirq.Qid'],
|
|
403
|
+
*,
|
|
404
|
+
flatten: bool = True,
|
|
405
|
+
context: Optional['DecompositionContext'] = None,
|
|
406
|
+
) -> List['cirq.Operation']:
|
|
316
407
|
pass
|
|
317
408
|
|
|
318
409
|
|
|
319
410
|
@overload
|
|
320
411
|
def decompose_once_with_qubits(
|
|
321
|
-
val: Any,
|
|
412
|
+
val: Any,
|
|
413
|
+
qubits: Iterable['cirq.Qid'],
|
|
414
|
+
default: Optional[TDefault],
|
|
415
|
+
*,
|
|
416
|
+
flatten: bool = True,
|
|
417
|
+
context: Optional['DecompositionContext'] = None,
|
|
322
418
|
) -> Union[TDefault, List['cirq.Operation']]:
|
|
323
419
|
pass
|
|
324
420
|
|
|
325
421
|
|
|
326
422
|
def decompose_once_with_qubits(
|
|
327
|
-
val: Any,
|
|
423
|
+
val: Any,
|
|
424
|
+
qubits: Iterable['cirq.Qid'],
|
|
425
|
+
default=RaiseTypeErrorIfNotProvided,
|
|
426
|
+
flatten: bool = True,
|
|
427
|
+
context: Optional['DecompositionContext'] = None,
|
|
328
428
|
):
|
|
329
429
|
"""Decomposes a value into operations on the given qubits.
|
|
330
430
|
|
|
@@ -341,6 +441,9 @@ def decompose_once_with_qubits(
|
|
|
341
441
|
`_decompose_` method or that method returns `NotImplemented` or
|
|
342
442
|
`None`. If not specified, non-decomposable values cause a
|
|
343
443
|
`TypeError`.
|
|
444
|
+
flatten: If True, the returned OP-TREE will be flattened to a list of operations.
|
|
445
|
+
context: Decomposition context specifying common configurable options for
|
|
446
|
+
controlling the behavior of decompose.
|
|
344
447
|
|
|
345
448
|
Returns:
|
|
346
449
|
The result of `val._decompose_(qubits)`, if `val` has a
|
|
@@ -352,7 +455,7 @@ def decompose_once_with_qubits(
|
|
|
352
455
|
`val` didn't have a `_decompose_` method (or that method returned
|
|
353
456
|
`NotImplemented` or `None`) and `default` wasn't set.
|
|
354
457
|
"""
|
|
355
|
-
return decompose_once(val, default, tuple(qubits))
|
|
458
|
+
return decompose_once(val, default, tuple(qubits), flatten=flatten, context=context)
|
|
356
459
|
|
|
357
460
|
|
|
358
461
|
# pylint: enable=function-redefined
|
|
@@ -383,65 +486,4 @@ def _try_decompose_into_operations_and_qubits(
|
|
|
383
486
|
qid_shape_dict[q] = max(qid_shape_dict[q], level)
|
|
384
487
|
qubits = sorted(qubit_set)
|
|
385
488
|
return result, qubits, tuple(qid_shape_dict[q] for q in qubits)
|
|
386
|
-
|
|
387
489
|
return None, (), ()
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
def _decompose_preserving_structure(
|
|
391
|
-
val: Any,
|
|
392
|
-
*,
|
|
393
|
-
intercepting_decomposer: Optional[OpDecomposer] = None,
|
|
394
|
-
fallback_decomposer: Optional[OpDecomposer] = None,
|
|
395
|
-
keep: Optional[Callable[['cirq.Operation'], bool]] = None,
|
|
396
|
-
on_stuck_raise: Union[
|
|
397
|
-
None, Exception, Callable[['cirq.Operation'], Optional[Exception]]
|
|
398
|
-
] = _value_error_describing_bad_operation,
|
|
399
|
-
) -> List['cirq.Operation']:
|
|
400
|
-
"""Preserves structure (e.g. subcircuits) while decomposing ops.
|
|
401
|
-
|
|
402
|
-
This can be used to reduce a circuit to a particular gateset without
|
|
403
|
-
increasing its serialization size. See tests for examples.
|
|
404
|
-
"""
|
|
405
|
-
|
|
406
|
-
# This method provides a generated 'keep' to its decompose() calls.
|
|
407
|
-
# If the user-provided keep is not set, on_stuck_raise must be unset to
|
|
408
|
-
# ensure that failure to decompose does not generate errors.
|
|
409
|
-
on_stuck_raise = on_stuck_raise if keep is not None else None
|
|
410
|
-
|
|
411
|
-
from cirq.circuits import CircuitOperation, FrozenCircuit
|
|
412
|
-
|
|
413
|
-
visited_fcs = set()
|
|
414
|
-
|
|
415
|
-
def keep_structure(op: 'cirq.Operation'):
|
|
416
|
-
circuit = getattr(op.untagged, 'circuit', None)
|
|
417
|
-
if circuit is not None:
|
|
418
|
-
return circuit in visited_fcs
|
|
419
|
-
if keep is not None and keep(op):
|
|
420
|
-
return True
|
|
421
|
-
|
|
422
|
-
def dps_interceptor(op: 'cirq.Operation'):
|
|
423
|
-
if not isinstance(op.untagged, CircuitOperation):
|
|
424
|
-
if intercepting_decomposer is None:
|
|
425
|
-
return NotImplemented
|
|
426
|
-
return intercepting_decomposer(op)
|
|
427
|
-
|
|
428
|
-
new_fc = FrozenCircuit(
|
|
429
|
-
decompose(
|
|
430
|
-
op.untagged.circuit,
|
|
431
|
-
intercepting_decomposer=dps_interceptor,
|
|
432
|
-
fallback_decomposer=fallback_decomposer,
|
|
433
|
-
keep=keep_structure,
|
|
434
|
-
on_stuck_raise=on_stuck_raise,
|
|
435
|
-
)
|
|
436
|
-
)
|
|
437
|
-
visited_fcs.add(new_fc)
|
|
438
|
-
new_co = op.untagged.replace(circuit=new_fc)
|
|
439
|
-
return new_co if not op.tags else new_co.with_tags(*op.tags)
|
|
440
|
-
|
|
441
|
-
return decompose(
|
|
442
|
-
val,
|
|
443
|
-
intercepting_decomposer=dps_interceptor,
|
|
444
|
-
fallback_decomposer=fallback_decomposer,
|
|
445
|
-
keep=keep_structure,
|
|
446
|
-
on_stuck_raise=on_stuck_raise,
|
|
447
|
-
)
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
+
import itertools
|
|
15
|
+
from typing import Optional
|
|
16
|
+
from unittest import mock
|
|
14
17
|
import pytest
|
|
15
18
|
|
|
16
19
|
import cirq
|
|
@@ -59,7 +62,7 @@ class DecomposeQuditGate:
|
|
|
59
62
|
|
|
60
63
|
def test_decompose_once():
|
|
61
64
|
# No default value results in descriptive error.
|
|
62
|
-
with pytest.raises(TypeError, match='no _decompose_ method'):
|
|
65
|
+
with pytest.raises(TypeError, match='no _decompose_with_context_ or _decompose_ method'):
|
|
63
66
|
_ = cirq.decompose_once(NoMethod())
|
|
64
67
|
with pytest.raises(TypeError, match='returned NotImplemented or None'):
|
|
65
68
|
_ = cirq.decompose_once(DecomposeNotImplemented())
|
|
@@ -88,7 +91,7 @@ def test_decompose_once_with_qubits():
|
|
|
88
91
|
qs = cirq.LineQubit.range(3)
|
|
89
92
|
|
|
90
93
|
# No default value results in descriptive error.
|
|
91
|
-
with pytest.raises(TypeError, match='no _decompose_ method'):
|
|
94
|
+
with pytest.raises(TypeError, match='no _decompose_with_context_ or _decompose_ method'):
|
|
92
95
|
_ = cirq.decompose_once_with_qubits(NoMethod(), qs)
|
|
93
96
|
with pytest.raises(TypeError, match='returned NotImplemented or None'):
|
|
94
97
|
_ = cirq.decompose_once_with_qubits(DecomposeNotImplemented(), qs)
|
|
@@ -222,6 +225,23 @@ def test_decompose_intercept():
|
|
|
222
225
|
)
|
|
223
226
|
assert actual == [cirq.CNOT(a, b), cirq.CNOT(b, a), cirq.CNOT(a, b)]
|
|
224
227
|
|
|
228
|
+
# Accepts a context, when provided.
|
|
229
|
+
def _intercept_with_context(
|
|
230
|
+
op: cirq.Operation, context: Optional[cirq.DecompositionContext] = None
|
|
231
|
+
):
|
|
232
|
+
assert context is not None
|
|
233
|
+
if op.gate == cirq.SWAP:
|
|
234
|
+
q = context.qubit_manager.qalloc(1)
|
|
235
|
+
a, b = op.qubits
|
|
236
|
+
return [cirq.X(a), cirq.X(*q), cirq.X(b)]
|
|
237
|
+
return NotImplemented
|
|
238
|
+
|
|
239
|
+
context = cirq.DecompositionContext(cirq.ops.SimpleQubitManager())
|
|
240
|
+
actual = cirq.decompose(
|
|
241
|
+
cirq.SWAP(a, b), intercepting_decomposer=_intercept_with_context, context=context
|
|
242
|
+
)
|
|
243
|
+
assert actual == [cirq.X(a), cirq.X(cirq.ops.CleanQubit(0)), cirq.X(b)]
|
|
244
|
+
|
|
225
245
|
|
|
226
246
|
def test_decompose_preserving_structure():
|
|
227
247
|
a, b = cirq.LineQubit.range(2)
|
|
@@ -308,3 +328,113 @@ def test_decompose_tagged_operation():
|
|
|
308
328
|
'tag',
|
|
309
329
|
)
|
|
310
330
|
assert cirq.decompose_once(op) == cirq.decompose_once(op.untagged)
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
class RecursiveDecompose(cirq.Gate):
|
|
334
|
+
def __init__(
|
|
335
|
+
self,
|
|
336
|
+
recurse: bool = True,
|
|
337
|
+
mock_qm=mock.Mock(spec=cirq.QubitManager),
|
|
338
|
+
with_context: bool = False,
|
|
339
|
+
):
|
|
340
|
+
self.recurse = recurse
|
|
341
|
+
self.mock_qm = mock_qm
|
|
342
|
+
self.with_context = with_context
|
|
343
|
+
|
|
344
|
+
def _num_qubits_(self) -> int:
|
|
345
|
+
return 2
|
|
346
|
+
|
|
347
|
+
def _decompose_impl(self, qubits, mock_qm: mock.Mock):
|
|
348
|
+
mock_qm.qalloc(self.recurse)
|
|
349
|
+
yield RecursiveDecompose(
|
|
350
|
+
recurse=False, mock_qm=self.mock_qm, with_context=self.with_context
|
|
351
|
+
).on(*qubits) if self.recurse else cirq.Z.on_each(*qubits)
|
|
352
|
+
mock_qm.qfree(self.recurse)
|
|
353
|
+
|
|
354
|
+
def _decompose_(self, qubits):
|
|
355
|
+
if self.with_context:
|
|
356
|
+
assert False
|
|
357
|
+
else:
|
|
358
|
+
return self._decompose_impl(qubits, self.mock_qm)
|
|
359
|
+
|
|
360
|
+
def _decompose_with_context_(self, qubits, context):
|
|
361
|
+
if self.with_context:
|
|
362
|
+
qm = self.mock_qm if context is None else context.qubit_manager
|
|
363
|
+
return self._decompose_impl(qubits, qm)
|
|
364
|
+
else:
|
|
365
|
+
return NotImplemented
|
|
366
|
+
|
|
367
|
+
def _has_unitary_(self):
|
|
368
|
+
return True
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
@pytest.mark.parametrize('with_context', [True, False])
|
|
372
|
+
def test_decompose_recursive_dfs(with_context: bool):
|
|
373
|
+
expected_calls = [
|
|
374
|
+
mock.call.qalloc(True),
|
|
375
|
+
mock.call.qalloc(False),
|
|
376
|
+
mock.call.qfree(False),
|
|
377
|
+
mock.call.qfree(True),
|
|
378
|
+
]
|
|
379
|
+
mock_qm = mock.Mock(spec=cirq.QubitManager)
|
|
380
|
+
context_qm = mock.Mock(spec=cirq.QubitManager)
|
|
381
|
+
gate = RecursiveDecompose(mock_qm=mock_qm, with_context=with_context)
|
|
382
|
+
q = cirq.LineQubit.range(3)
|
|
383
|
+
gate_op = gate.on(*q[:2])
|
|
384
|
+
tagged_op = gate_op.with_tags("custom tag")
|
|
385
|
+
controlled_op = gate_op.controlled_by(q[2])
|
|
386
|
+
classically_controlled_op = gate_op.with_classical_controls('key')
|
|
387
|
+
moment = cirq.Moment(gate_op)
|
|
388
|
+
circuit = cirq.Circuit(moment)
|
|
389
|
+
for val in [gate_op, tagged_op, controlled_op, classically_controlled_op, moment, circuit]:
|
|
390
|
+
mock_qm.reset_mock()
|
|
391
|
+
_ = cirq.decompose(val, context=cirq.DecompositionContext(qubit_manager=mock_qm))
|
|
392
|
+
assert mock_qm.method_calls == expected_calls
|
|
393
|
+
|
|
394
|
+
mock_qm.reset_mock()
|
|
395
|
+
context_qm.reset_mock()
|
|
396
|
+
_ = cirq.decompose(val, context=cirq.DecompositionContext(context_qm))
|
|
397
|
+
assert (
|
|
398
|
+
context_qm.method_calls == expected_calls
|
|
399
|
+
if with_context
|
|
400
|
+
else mock_qm.method_calls == expected_calls
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
class G1(cirq.Gate):
|
|
405
|
+
def _num_qubits_(self) -> int:
|
|
406
|
+
return 1
|
|
407
|
+
|
|
408
|
+
def _decompose_with_context_(self, qubits, context):
|
|
409
|
+
yield cirq.CNOT(qubits[0], context.qubit_manager.qalloc(1)[0])
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
class G2(cirq.Gate):
|
|
413
|
+
def _num_qubits_(self) -> int:
|
|
414
|
+
return 1
|
|
415
|
+
|
|
416
|
+
def _decompose_with_context_(self, qubits, context):
|
|
417
|
+
yield G1()(*context.qubit_manager.qalloc(1))
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
@mock.patch('cirq.protocols.decompose_protocol._CONTEXT_COUNTER', itertools.count())
|
|
421
|
+
def test_successive_decompose_once_succeed():
|
|
422
|
+
op = G2()(cirq.NamedQubit('q'))
|
|
423
|
+
d1 = cirq.decompose_once(op)
|
|
424
|
+
d2 = cirq.decompose_once(d1[0])
|
|
425
|
+
assert d2 == [
|
|
426
|
+
cirq.CNOT(
|
|
427
|
+
cirq.ops.CleanQubit(0, prefix='_decompose_protocol_0'),
|
|
428
|
+
cirq.ops.CleanQubit(0, prefix='_decompose_protocol_1'),
|
|
429
|
+
)
|
|
430
|
+
]
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
def test_decompose_without_context_succeed():
|
|
434
|
+
op = G2()(cirq.NamedQubit('q'))
|
|
435
|
+
assert cirq.decompose(op, keep=lambda op: op.gate is cirq.CNOT) == [
|
|
436
|
+
cirq.CNOT(
|
|
437
|
+
cirq.ops.CleanQubit(0, prefix='_decompose_protocol'),
|
|
438
|
+
cirq.ops.CleanQubit(1, prefix='_decompose_protocol'),
|
|
439
|
+
)
|
|
440
|
+
]
|
|
@@ -63,7 +63,8 @@ def _strat_has_stabilizer_effect_from_unitary(val: Any) -> Optional[bool]:
|
|
|
63
63
|
"""
|
|
64
64
|
# Do not try this strategy if there is no unitary or if the number of
|
|
65
65
|
# qubits is not 1 since that would be expensive.
|
|
66
|
-
|
|
66
|
+
qid_shape = protocols.qid_shape(val, default=None)
|
|
67
|
+
if qid_shape is None or len(qid_shape) != 1 or not protocols.has_unitary(val):
|
|
67
68
|
return None
|
|
68
69
|
unitary = protocols.unitary(val)
|
|
69
70
|
return SingleQubitCliffordGate.from_unitary(unitary) is not None
|
|
@@ -115,9 +115,9 @@ def inverse(val: Any, default: Any = RaiseTypeErrorIfNotProvided) -> Any:
|
|
|
115
115
|
if default is not RaiseTypeErrorIfNotProvided:
|
|
116
116
|
return default
|
|
117
117
|
raise TypeError(
|
|
118
|
-
"object of type '{}' isn't invertible. "
|
|
118
|
+
f"object of type '{type(val)}' isn't invertible. "
|
|
119
119
|
"It has no __pow__ method (or the method returned NotImplemented) "
|
|
120
|
-
"and it isn't an iterable of invertible objects."
|
|
120
|
+
"and it isn't an iterable of invertible objects."
|
|
121
121
|
)
|
|
122
122
|
|
|
123
123
|
|
|
@@ -57,8 +57,8 @@ TESTED_MODULES: Dict[str, Optional[_ModuleDeprecation]] = {
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
# pyQuil 3.0, necessary for cirq_rigetti module requires
|
|
60
|
-
# python >= 3.
|
|
61
|
-
if sys.version_info < (3,
|
|
60
|
+
# python >= 3.9
|
|
61
|
+
if sys.version_info < (3, 9): # pragma: no cover
|
|
62
62
|
del TESTED_MODULES['cirq_rigetti']
|
|
63
63
|
|
|
64
64
|
|
|
@@ -767,7 +767,7 @@ def test_pathlib_paths(tmpdir):
|
|
|
767
767
|
assert cirq.read_json_gzip(gzip_path) == cirq.X
|
|
768
768
|
|
|
769
769
|
|
|
770
|
-
def test_dataclass_json_dict():
|
|
770
|
+
def test_dataclass_json_dict() -> None:
|
|
771
771
|
@dataclasses.dataclass(frozen=True)
|
|
772
772
|
class MyDC:
|
|
773
773
|
q: cirq.LineQubit
|
|
@@ -1,7 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"cirq_type": "Linspace",
|
|
4
|
+
"key": "a",
|
|
5
|
+
"start": 0,
|
|
6
|
+
"stop": 1,
|
|
7
|
+
"length": 4
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"cirq_type": "Linspace",
|
|
11
|
+
"key": "b",
|
|
12
|
+
"start": 1,
|
|
13
|
+
"stop": 2,
|
|
14
|
+
"length": 3,
|
|
15
|
+
"metadata": {
|
|
16
|
+
"cirq_type": "NamedQubit",
|
|
17
|
+
"name": "b"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
]
|
|
@@ -1,8 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"cirq_type": "Points",
|
|
4
|
+
"key": "a",
|
|
5
|
+
"points": [
|
|
6
|
+
0,
|
|
7
|
+
0.4
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"cirq_type": "Points",
|
|
12
|
+
"key": "amp",
|
|
13
|
+
"points": [
|
|
14
|
+
0,
|
|
15
|
+
1
|
|
16
|
+
],
|
|
17
|
+
"metadata": "used to turn amp on or off"
|
|
18
|
+
}
|
|
19
|
+
]
|