cirq-core 1.3.0.dev20231201164435__py3-none-any.whl → 1.4.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.
Files changed (157) hide show
  1. cirq/__init__.py +4 -0
  2. cirq/_compat.py +9 -11
  3. cirq/_compat_test.py +45 -56
  4. cirq/_version.py +31 -1
  5. cirq/_version_test.py +1 -1
  6. cirq/circuits/circuit.py +13 -8
  7. cirq/circuits/circuit_operation.py +2 -1
  8. cirq/circuits/circuit_test.py +2 -2
  9. cirq/circuits/frozen_circuit.py +3 -2
  10. cirq/circuits/moment.py +12 -10
  11. cirq/circuits/qasm_output.py +5 -1
  12. cirq/circuits/qasm_output_test.py +25 -10
  13. cirq/contrib/qcircuit/qcircuit_diagram_info.py +9 -7
  14. cirq/contrib/quimb/mps_simulator_test.py +1 -1
  15. cirq/contrib/quimb/state_vector.py +9 -2
  16. cirq/contrib/svg/svg.py +2 -1
  17. cirq/contrib/svg/svg_test.py +1 -0
  18. cirq/devices/grid_qubit.py +85 -32
  19. cirq/devices/grid_qubit_test.py +22 -4
  20. cirq/devices/line_qubit.py +74 -26
  21. cirq/devices/line_qubit_test.py +19 -0
  22. cirq/devices/noise_utils.py +33 -31
  23. cirq/devices/noise_utils_test.py +1 -84
  24. cirq/devices/superconducting_qubits_noise_properties.py +7 -6
  25. cirq/experiments/__init__.py +8 -0
  26. cirq/experiments/qubit_characterizations.py +288 -44
  27. cirq/experiments/qubit_characterizations_test.py +61 -7
  28. cirq/experiments/random_quantum_circuit_generation.py +1 -1
  29. cirq/experiments/single_qubit_readout_calibration.py +132 -6
  30. cirq/experiments/single_qubit_readout_calibration_test.py +3 -1
  31. cirq/experiments/t1_decay_experiment.py +14 -7
  32. cirq/experiments/t1_decay_experiment_test.py +14 -26
  33. cirq/experiments/two_qubit_xeb.py +483 -0
  34. cirq/experiments/two_qubit_xeb_test.py +304 -0
  35. cirq/json_resolver_cache.py +2 -0
  36. cirq/linalg/decompositions.py +11 -13
  37. cirq/linalg/decompositions_test.py +1 -3
  38. cirq/linalg/diagonalize.py +5 -4
  39. cirq/linalg/predicates.py +8 -6
  40. cirq/linalg/transformations.py +2 -1
  41. cirq/linalg/transformations_test.py +1 -1
  42. cirq/ops/__init__.py +2 -0
  43. cirq/ops/clifford_gate.py +59 -16
  44. cirq/ops/common_gates_test.py +1 -2
  45. cirq/ops/control_values.py +4 -3
  46. cirq/ops/controlled_gate_test.py +1 -3
  47. cirq/ops/gate_operation.py +10 -1
  48. cirq/ops/named_qubit.py +74 -28
  49. cirq/ops/named_qubit_test.py +19 -0
  50. cirq/ops/parity_gates.py +5 -0
  51. cirq/ops/parity_gates_test.py +2 -10
  52. cirq/ops/pauli_gates.py +5 -2
  53. cirq/ops/pauli_string.py +2 -2
  54. cirq/ops/permutation_gate.py +16 -18
  55. cirq/ops/phased_iswap_gate_test.py +1 -3
  56. cirq/ops/phased_x_gate.py +1 -1
  57. cirq/ops/phased_x_z_gate.py +17 -1
  58. cirq/ops/phased_x_z_gate_test.py +24 -0
  59. cirq/ops/qid_util.py +4 -8
  60. cirq/ops/qubit_manager.py +7 -4
  61. cirq/ops/qubit_manager_test.py +20 -0
  62. cirq/ops/raw_types.py +5 -2
  63. cirq/ops/raw_types_test.py +14 -15
  64. cirq/ops/uniform_superposition_gate.py +123 -0
  65. cirq/ops/uniform_superposition_gate_test.py +94 -0
  66. cirq/protocols/approximate_equality_protocol_test.py +2 -2
  67. cirq/protocols/circuit_diagram_info_protocol.py +6 -4
  68. cirq/protocols/commutes_protocol.py +2 -4
  69. cirq/protocols/decompose_protocol.py +7 -12
  70. cirq/protocols/decompose_protocol_test.py +7 -3
  71. cirq/protocols/has_stabilizer_effect_protocol.py +1 -5
  72. cirq/protocols/has_stabilizer_effect_protocol_test.py +13 -4
  73. cirq/protocols/json_serialization.py +51 -181
  74. cirq/protocols/json_serialization_test.py +13 -47
  75. cirq/protocols/json_test_data/CircuitOperation.json +131 -148
  76. cirq/protocols/json_test_data/CircuitOperation.json_inward +55 -0
  77. cirq/protocols/json_test_data/CircuitOperation.repr_inward +6 -0
  78. cirq/protocols/json_test_data/FrozenCircuit.json +196 -210
  79. cirq/protocols/json_test_data/FrozenCircuit.json_inward +35 -0
  80. cirq/protocols/json_test_data/FrozenCircuit.repr_inward +4 -0
  81. cirq/protocols/json_test_data/UniformSuperpositionGate.json +5 -0
  82. cirq/protocols/json_test_data/UniformSuperpositionGate.repr +1 -0
  83. cirq/protocols/json_test_data/cirq.MSGate.json +4 -0
  84. cirq/protocols/json_test_data/cirq.MSGate.repr +1 -0
  85. cirq/protocols/json_test_data/spec.py +2 -0
  86. cirq/protocols/pow_protocol_test.py +1 -3
  87. cirq/protocols/resolve_parameters.py +4 -2
  88. cirq/qis/__init__.py +10 -0
  89. cirq/qis/clifford_tableau.py +8 -2
  90. cirq/qis/noise_utils.py +123 -0
  91. cirq/qis/noise_utils_test.py +97 -0
  92. cirq/sim/classical_simulator.py +227 -87
  93. cirq/sim/classical_simulator_test.py +135 -0
  94. cirq/sim/clifford/clifford_simulator_test.py +4 -2
  95. cirq/sim/mux.py +5 -3
  96. cirq/sim/simulation_product_state.py +15 -10
  97. cirq/sim/simulation_state.py +1 -1
  98. cirq/sim/simulation_state_test.py +2 -2
  99. cirq/sim/simulator_base.py +3 -3
  100. cirq/sim/state_vector_simulation_state.py +4 -4
  101. cirq/sim/state_vector_simulator.py +17 -2
  102. cirq/study/__init__.py +1 -0
  103. cirq/study/result.py +14 -0
  104. cirq/study/result_test.py +6 -0
  105. cirq/study/sweeps.py +4 -2
  106. cirq/study/sweeps_test.py +8 -0
  107. cirq/testing/__init__.py +6 -1
  108. cirq/testing/_compat_test_data/__init__.py +3 -3
  109. cirq/testing/_compat_test_data/module_a/__init__.py +2 -2
  110. cirq/testing/circuit_compare.py +1 -1
  111. cirq/testing/consistent_qasm.py +6 -0
  112. cirq/testing/gate_features.py +10 -0
  113. cirq/testing/lin_alg_utils.py +5 -3
  114. cirq/transformers/__init__.py +15 -0
  115. cirq/transformers/analytical_decompositions/controlled_gate_decomposition.py +3 -1
  116. cirq/transformers/analytical_decompositions/two_qubit_to_cz.py +24 -0
  117. cirq/transformers/analytical_decompositions/two_qubit_to_cz_test.py +17 -0
  118. cirq/transformers/dynamical_decoupling.py +122 -0
  119. cirq/transformers/dynamical_decoupling_test.py +123 -0
  120. cirq/transformers/gauge_compiling/__init__.py +26 -0
  121. cirq/transformers/gauge_compiling/cz_gauge.py +46 -0
  122. cirq/transformers/gauge_compiling/cz_gauge_test.py +23 -0
  123. cirq/transformers/gauge_compiling/gauge_compiling.py +214 -0
  124. cirq/transformers/gauge_compiling/gauge_compiling_test.py +41 -0
  125. cirq/transformers/gauge_compiling/gauge_compiling_test_utils.py +83 -0
  126. cirq/transformers/gauge_compiling/gauge_compiling_test_utils_test.py +52 -0
  127. cirq/transformers/gauge_compiling/iswap_gauge.py +105 -0
  128. cirq/transformers/gauge_compiling/iswap_gauge_test.py +23 -0
  129. cirq/transformers/gauge_compiling/spin_inversion_gauge.py +33 -0
  130. cirq/transformers/gauge_compiling/spin_inversion_gauge_test.py +37 -0
  131. cirq/transformers/gauge_compiling/sqrt_cz_gauge.py +64 -0
  132. cirq/transformers/gauge_compiling/sqrt_cz_gauge_test.py +27 -0
  133. cirq/transformers/gauge_compiling/sqrt_iswap_gauge.py +94 -0
  134. cirq/transformers/gauge_compiling/sqrt_iswap_gauge_test.py +22 -0
  135. cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +1 -0
  136. cirq/transformers/merge_k_qubit_gates_test.py +23 -23
  137. cirq/transformers/merge_single_qubit_gates_test.py +14 -14
  138. cirq/transformers/optimize_for_target_gateset.py +39 -17
  139. cirq/transformers/optimize_for_target_gateset_test.py +189 -39
  140. cirq/transformers/qubit_management_transformers.py +1 -1
  141. cirq/transformers/routing/visualize_routed_circuit_test.py +17 -17
  142. cirq/transformers/stratify_test.py +13 -13
  143. cirq/transformers/target_gatesets/compilation_target_gateset.py +26 -2
  144. cirq/transformers/target_gatesets/compilation_target_gateset_test.py +16 -16
  145. cirq/transformers/target_gatesets/cz_gateset.py +4 -0
  146. cirq/transformers/transformer_api.py +1 -2
  147. cirq/transformers/transformer_primitives.py +15 -14
  148. cirq/transformers/transformer_primitives_test.py +99 -72
  149. cirq/value/classical_data.py +6 -6
  150. cirq/value/value_equality_attr.py +4 -0
  151. cirq/work/sampler.py +3 -4
  152. cirq/work/sampler_test.py +25 -0
  153. {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/METADATA +10 -19
  154. {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/RECORD +157 -130
  155. {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/WHEEL +1 -1
  156. {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/LICENSE +0 -0
  157. {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/top_level.txt +0 -0
@@ -28,7 +28,6 @@ from typing import (
28
28
  Optional,
29
29
  overload,
30
30
  Sequence,
31
- Set,
32
31
  Tuple,
33
32
  Type,
34
33
  Union,
@@ -48,8 +47,7 @@ ObjectFactory = Union[Type, Callable[..., Any]]
48
47
  class JsonResolver(Protocol):
49
48
  """Protocol for json resolver functions passed to read_json."""
50
49
 
51
- def __call__(self, cirq_type: str) -> Optional[ObjectFactory]:
52
- ...
50
+ def __call__(self, cirq_type: str) -> Optional[ObjectFactory]: ...
53
51
 
54
52
 
55
53
  def _lazy_resolver(dict_factory: Callable[[], Dict[str, ObjectFactory]]) -> JsonResolver:
@@ -221,10 +219,22 @@ class CirqEncoder(json.JSONEncoder):
221
219
  See https://github.com/quantumlib/Cirq/issues/2014
222
220
  """
223
221
 
222
+ def __init__(self, *args, **kwargs) -> None:
223
+ super().__init__(*args, **kwargs)
224
+ self._memo: dict[Any, dict] = {}
225
+
224
226
  def default(self, o):
225
227
  # Object with custom method?
226
228
  if hasattr(o, '_json_dict_'):
227
- return _json_dict_with_cirq_type(o)
229
+ json_dict = _json_dict_with_cirq_type(o)
230
+ if isinstance(o, SerializableByKey):
231
+ if ref := self._memo.get(o):
232
+ return ref
233
+ key = len(self._memo)
234
+ ref = {"cirq_type": "REF", "key": key}
235
+ self._memo[o] = ref
236
+ return {"cirq_type": "VAL", "key": key, "val": json_dict}
237
+ return json_dict
228
238
 
229
239
  # Sympy object? (Must come before general number checks.)
230
240
  # TODO: More support for sympy
@@ -306,27 +316,46 @@ class CirqEncoder(json.JSONEncoder):
306
316
  return super().default(o) # pragma: no cover
307
317
 
308
318
 
309
- def _cirq_object_hook(d, resolvers: Sequence[JsonResolver], context_map: Dict[str, Any]):
310
- if 'cirq_type' not in d:
311
- return d
319
+ class ObjectHook:
320
+ """Callable to be used as object_hook during deserialization."""
321
+
322
+ LEGACY_CONTEXT_TYPES = {'_ContextualSerialization', '_SerializedKey', '_SerializedContext'}
323
+
324
+ def __init__(self, resolvers: Sequence[JsonResolver]) -> None:
325
+ self.resolvers = resolvers
326
+ self.memo: Dict[int, SerializableByKey] = {}
327
+ self.context_map: Dict[int, SerializableByKey] = {}
312
328
 
313
- if d['cirq_type'] == '_SerializedKey':
314
- return _SerializedKey.read_from_context(context_map, **d)
329
+ def __call__(self, d):
330
+ cirq_type = d.get('cirq_type')
331
+ if cirq_type is None:
332
+ return d
315
333
 
316
- if d['cirq_type'] == '_SerializedContext':
317
- _SerializedContext.update_context(context_map, **d)
318
- return None
334
+ if cirq_type == 'VAL':
335
+ obj = d['val']
336
+ self.memo[d['key']] = obj
337
+ return obj
319
338
 
320
- if d['cirq_type'] == '_ContextualSerialization':
321
- return _ContextualSerialization.deserialize_with_context(**d)
339
+ if cirq_type == 'REF':
340
+ return self.memo[d['key']]
322
341
 
323
- cls = factory_from_json(d['cirq_type'], resolvers=resolvers)
324
- from_json_dict = getattr(cls, '_from_json_dict_', None)
325
- if from_json_dict is not None:
326
- return from_json_dict(**d)
342
+ # Deserialize from legacy "contextual serialization" format
343
+ if cirq_type in self.LEGACY_CONTEXT_TYPES:
344
+ if cirq_type == '_SerializedKey':
345
+ return self.context_map[d['key']]
346
+ if cirq_type == '_SerializedContext':
347
+ self.context_map[d['key']] = d['obj']
348
+ return None
349
+ if cirq_type == '_ContextualSerialization':
350
+ return d['object_dag'][-1]
327
351
 
328
- del d['cirq_type']
329
- return cls(**d)
352
+ cls = factory_from_json(cirq_type, resolvers=self.resolvers)
353
+ from_json_dict = getattr(cls, '_from_json_dict_', None)
354
+ if from_json_dict is not None:
355
+ return from_json_dict(**d)
356
+
357
+ del d['cirq_type']
358
+ return cls(**d)
330
359
 
331
360
 
332
361
  class SerializableByKey(SupportsJSON):
@@ -338,137 +367,6 @@ class SerializableByKey(SupportsJSON):
338
367
  """
339
368
 
340
369
 
341
- class _SerializedKey(SupportsJSON):
342
- """Internal object for holding a SerializableByKey key.
343
-
344
- This is a private type used in contextual serialization. Its deserialization
345
- is context-dependent, and is not expected to match the original; in other
346
- words, `cls._from_json_dict_(obj._json_dict_())` does not return
347
- the original `obj` for this type.
348
- """
349
-
350
- def __init__(self, key: str):
351
- self.key = key
352
-
353
- def _json_dict_(self):
354
- return obj_to_dict_helper(self, ['key'])
355
-
356
- @classmethod
357
- def _from_json_dict_(cls, **kwargs):
358
- raise TypeError(f'Internal error: {cls} should never deserialize with _from_json_dict_.')
359
-
360
- @classmethod
361
- def read_from_context(cls, context_map, key, **kwargs):
362
- return context_map[key]
363
-
364
-
365
- class _SerializedContext(SupportsJSON):
366
- """Internal object for a single SerializableByKey key-to-object mapping.
367
-
368
- This is a private type used in contextual serialization. Its deserialization
369
- is context-dependent, and is not expected to match the original; in other
370
- words, `cls._from_json_dict_(obj._json_dict_())` does not return
371
- the original `obj` for this type.
372
- """
373
-
374
- def __init__(self, obj: SerializableByKey, uid: int):
375
- self.key = uid
376
- self.obj = obj
377
-
378
- def _json_dict_(self):
379
- return obj_to_dict_helper(self, ['key', 'obj'])
380
-
381
- @classmethod
382
- def _from_json_dict_(cls, **kwargs):
383
- raise TypeError(f'Internal error: {cls} should never deserialize with _from_json_dict_.')
384
-
385
- @classmethod
386
- def update_context(cls, context_map, key, obj, **kwargs):
387
- context_map.update({key: obj})
388
-
389
-
390
- class _ContextualSerialization(SupportsJSON):
391
- """Internal object for serializing an object with its context.
392
-
393
- This is a private type used in contextual serialization. Its deserialization
394
- is context-dependent, and is not expected to match the original; in other
395
- words, `cls._from_json_dict_(obj._json_dict_())` does not return
396
- the original `obj` for this type.
397
- """
398
-
399
- def __init__(self, obj: Any):
400
- # Context information and the wrapped object are stored together in
401
- # `object_dag` to ensure consistent serialization ordering.
402
- self.object_dag = []
403
- context = []
404
- for sbk in get_serializable_by_keys(obj):
405
- if sbk not in context:
406
- context.append(sbk)
407
- new_sc = _SerializedContext(sbk, len(context))
408
- self.object_dag.append(new_sc)
409
- self.object_dag += [obj]
410
-
411
- def _json_dict_(self):
412
- return obj_to_dict_helper(self, ['object_dag'])
413
-
414
- @classmethod
415
- def _from_json_dict_(cls, **kwargs):
416
- raise TypeError(f'Internal error: {cls} should never deserialize with _from_json_dict_.')
417
-
418
- @classmethod
419
- def deserialize_with_context(cls, object_dag, **kwargs):
420
- # The last element of object_dag is the object to be deserialized.
421
- return object_dag[-1]
422
-
423
-
424
- def has_serializable_by_keys(obj: Any) -> bool:
425
- """Returns true if obj contains one or more SerializableByKey objects."""
426
- if isinstance(obj, SerializableByKey):
427
- return True
428
- json_dict = getattr(obj, '_json_dict_', lambda: None)()
429
- if isinstance(json_dict, Dict):
430
- return any(has_serializable_by_keys(v) for v in json_dict.values())
431
-
432
- # Handle primitive container types.
433
- if isinstance(obj, Dict):
434
- return any(has_serializable_by_keys(elem) for pair in obj.items() for elem in pair)
435
-
436
- if hasattr(obj, '__iter__') and not isinstance(obj, str):
437
- # Return False on TypeError because some numpy values
438
- # (like np.array(1)) have iterable methods
439
- # yet return a TypeError when there is an attempt to iterate over them
440
- try:
441
- return any(has_serializable_by_keys(elem) for elem in obj)
442
- except TypeError:
443
- return False
444
- return False
445
-
446
-
447
- def get_serializable_by_keys(obj: Any) -> List[SerializableByKey]:
448
- """Returns all SerializableByKeys contained by obj.
449
-
450
- Objects are ordered such that nested objects appear before the object they
451
- are nested inside. This is required to ensure SerializableByKeys are only
452
- fully defined once in serialization.
453
- """
454
- result = []
455
- if isinstance(obj, SerializableByKey):
456
- result.append(obj)
457
- json_dict = getattr(obj, '_json_dict_', lambda: None)()
458
- if isinstance(json_dict, Dict):
459
- for v in json_dict.values():
460
- result = get_serializable_by_keys(v) + result
461
- if result:
462
- return result
463
-
464
- # Handle primitive container types.
465
- if isinstance(obj, Dict):
466
- return [sbk for pair in obj.items() for sbk in get_serializable_by_keys(pair)]
467
- if hasattr(obj, '__iter__') and not isinstance(obj, str):
468
- return [sbk for v in obj for sbk in get_serializable_by_keys(v)]
469
- return []
470
-
471
-
472
370
  def json_namespace(type_obj: Type) -> str:
473
371
  """Returns a namespace for JSON serialization of `type_obj`.
474
372
 
@@ -610,37 +508,12 @@ def to_json(
610
508
  party classes, prefer adding the `_json_dict_` magic method
611
509
  to your classes rather than overriding this default.
612
510
  """
613
- if has_serializable_by_keys(obj):
614
- obj = _ContextualSerialization(obj)
615
-
616
- class ContextualEncoder(cls): # type: ignore
617
- """An encoder with a context map for concise serialization."""
618
-
619
- # These lists populate gradually during serialization. An object
620
- # with components defined in 'context' will represent those
621
- # components using their keys instead of inline definition.
622
- seen: Set[str] = set()
623
-
624
- def default(self, o):
625
- if not isinstance(o, SerializableByKey):
626
- return super().default(o)
627
- for candidate in obj.object_dag[:-1]:
628
- if candidate.obj == o:
629
- if not candidate.key in ContextualEncoder.seen:
630
- ContextualEncoder.seen.add(candidate.key)
631
- return _json_dict_with_cirq_type(candidate.obj)
632
- else:
633
- return _json_dict_with_cirq_type(_SerializedKey(candidate.key))
634
- raise ValueError("Object mutated during serialization.") # pragma: no cover
635
-
636
- cls = ContextualEncoder
637
-
638
511
  if file_or_fn is None:
639
512
  return json.dumps(obj, indent=indent, separators=separators, cls=cls)
640
513
 
641
514
  if isinstance(file_or_fn, (str, pathlib.Path)):
642
515
  with open(file_or_fn, 'w') as actually_a_file:
643
- json.dump(obj, actually_a_file, indent=indent, cls=cls)
516
+ json.dump(obj, actually_a_file, indent=indent, separators=separators, cls=cls)
644
517
  return None
645
518
 
646
519
  json.dump(obj, file_or_fn, indent=indent, separators=separators, cls=cls)
@@ -682,10 +555,7 @@ def read_json(
682
555
  if resolvers is None:
683
556
  resolvers = DEFAULT_RESOLVERS
684
557
 
685
- context_map: Dict[str, 'SerializableByKey'] = {}
686
-
687
- def obj_hook(x):
688
- return _cirq_object_hook(x, resolvers, context_map)
558
+ obj_hook = ObjectHook(resolvers)
689
559
 
690
560
  if json_text is not None:
691
561
  return json.loads(json_text, object_hook=obj_hook)
@@ -11,6 +11,7 @@
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
15
  import contextlib
15
16
  import dataclasses
16
17
  import datetime
@@ -19,7 +20,6 @@ import io
19
20
  import json
20
21
  import os
21
22
  import pathlib
22
- import sys
23
23
  import warnings
24
24
  from typing import Dict, List, Optional, Tuple, Type
25
25
  from unittest import mock
@@ -56,12 +56,6 @@ TESTED_MODULES: Dict[str, Optional[_ModuleDeprecation]] = {
56
56
  }
57
57
 
58
58
 
59
- # pyQuil 3.0, necessary for cirq_rigetti module requires
60
- # python >= 3.9
61
- if sys.version_info < (3, 9): # pragma: no cover
62
- del TESTED_MODULES['cirq_rigetti']
63
-
64
-
65
59
  def _get_testspecs_for_modules() -> List[ModuleJsonTestSpec]:
66
60
  modules = []
67
61
  for m in TESTED_MODULES.keys():
@@ -237,7 +231,7 @@ def test_not_yet_serializable_no_superfluous(mod_spec: ModuleJsonTestSpec):
237
231
 
238
232
 
239
233
  @pytest.mark.parametrize('mod_spec', MODULE_TEST_SPECS, ids=repr)
240
- def test_mutually_exclusive_lists(mod_spec: ModuleJsonTestSpec):
234
+ def test_mutually_exclusive_not_serialize_lists(mod_spec: ModuleJsonTestSpec):
241
235
  common = set(mod_spec.should_not_be_serialized) & set(mod_spec.not_yet_serializable)
242
236
  assert len(common) == 0, (
243
237
  f"Defined in both {mod_spec.name} 'Not yet serializable' "
@@ -373,6 +367,11 @@ class SBKImpl(cirq.SerializableByKey):
373
367
  and self.data_dict == other.data_dict
374
368
  )
375
369
 
370
+ def __hash__(self):
371
+ return hash(
372
+ (self.name, tuple(self.data_list), self.data_tuple, frozenset(self.data_dict.items()))
373
+ )
374
+
376
375
  def _json_dict_(self):
377
376
  return {
378
377
  "name": self.name,
@@ -386,12 +385,12 @@ class SBKImpl(cirq.SerializableByKey):
386
385
  return cls(name, data_list, tuple(data_tuple), data_dict)
387
386
 
388
387
 
389
- def test_context_serialization():
388
+ def test_serializable_by_key():
390
389
  def custom_resolver(name):
391
390
  if name == 'SBKImpl':
392
391
  return SBKImpl
393
392
 
394
- test_resolvers = [custom_resolver] + cirq.DEFAULT_RESOLVERS
393
+ test_resolvers = [custom_resolver, *cirq.DEFAULT_RESOLVERS]
395
394
 
396
395
  sbki_empty = SBKImpl('sbki_empty')
397
396
  assert_json_roundtrip_works(sbki_empty, resolvers=test_resolvers)
@@ -406,21 +405,10 @@ def test_context_serialization():
406
405
  assert_json_roundtrip_works(sbki_dict, resolvers=test_resolvers)
407
406
 
408
407
  sbki_json = str(cirq.to_json(sbki_dict))
409
- # There should be exactly one context item for each previous SBKImpl.
410
- assert sbki_json.count('"cirq_type": "_SerializedContext"') == 4
411
- # There should be exactly two key items for each of sbki_(empty|list|tuple),
412
- # plus one for the top-level sbki_dict.
413
- assert sbki_json.count('"cirq_type": "_SerializedKey"') == 7
414
- # The final object should be a _SerializedKey for sbki_dict.
415
- final_obj_idx = sbki_json.rfind('{')
416
- final_obj = sbki_json[final_obj_idx : sbki_json.find('}', final_obj_idx) + 1]
417
- assert (
418
- final_obj
419
- == """{
420
- "cirq_type": "_SerializedKey",
421
- "key": 4
422
- }"""
423
- )
408
+ # There are 4 SBKImpl instances, one each for empty, list, tuple, dict.
409
+ assert sbki_json.count('"cirq_type": "VAL"') == 4
410
+ # There are 3 SBKImpl refs, one each for empty, list, and tuple.
411
+ assert sbki_json.count('"cirq_type": "REF"') == 3
424
412
 
425
413
  list_sbki = [sbki_dict]
426
414
  assert_json_roundtrip_works(list_sbki, resolvers=test_resolvers)
@@ -428,33 +416,11 @@ def test_context_serialization():
428
416
  dict_sbki = {'a': sbki_dict}
429
417
  assert_json_roundtrip_works(dict_sbki, resolvers=test_resolvers)
430
418
 
431
- assert sbki_list != json_serialization._SerializedKey(sbki_list)
432
-
433
419
  # Serialization keys have unique suffixes.
434
420
  sbki_other_list = SBKImpl('sbki_list', data_list=[sbki_list])
435
421
  assert_json_roundtrip_works(sbki_other_list, resolvers=test_resolvers)
436
422
 
437
423
 
438
- def test_internal_serializer_types():
439
- sbki = SBKImpl('test_key')
440
- key = 1
441
- test_key = json_serialization._SerializedKey(key)
442
- test_context = json_serialization._SerializedContext(sbki, 1)
443
- test_serialization = json_serialization._ContextualSerialization(sbki)
444
-
445
- key_json = test_key._json_dict_()
446
- with pytest.raises(TypeError, match='_from_json_dict_'):
447
- _ = json_serialization._SerializedKey._from_json_dict_(**key_json)
448
-
449
- context_json = test_context._json_dict_()
450
- with pytest.raises(TypeError, match='_from_json_dict_'):
451
- _ = json_serialization._SerializedContext._from_json_dict_(**context_json)
452
-
453
- serialization_json = test_serialization._json_dict_()
454
- with pytest.raises(TypeError, match='_from_json_dict_'):
455
- _ = json_serialization._ContextualSerialization._from_json_dict_(**serialization_json)
456
-
457
-
458
424
  # during test setup deprecated submodules are inspected and trigger the
459
425
  # deprecation error in testing. It is cleaner to just turn it off than to assert
460
426
  # deprecation for each submodule.