cirq-core 1.3.0.dev20231201141002__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.

Potentially problematic release.


This version of cirq-core might be problematic. Click here for more details.

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.dev20231201141002.dist-info → cirq_core-1.4.0.dist-info}/METADATA +10 -19
  154. {cirq_core-1.3.0.dev20231201141002.dist-info → cirq_core-1.4.0.dist-info}/RECORD +157 -130
  155. {cirq_core-1.3.0.dev20231201141002.dist-info → cirq_core-1.4.0.dist-info}/WHEEL +1 -1
  156. {cirq_core-1.3.0.dev20231201141002.dist-info → cirq_core-1.4.0.dist-info}/LICENSE +0 -0
  157. {cirq_core-1.3.0.dev20231201141002.dist-info → cirq_core-1.4.0.dist-info}/top_level.txt +0 -0
cirq/__init__.py CHANGED
@@ -240,6 +240,7 @@ from cirq.ops import (
240
240
  MatrixGate,
241
241
  MixedUnitaryChannel,
242
242
  M,
243
+ MSGate,
243
244
  measure,
244
245
  measure_each,
245
246
  measure_paulistring_terms,
@@ -331,10 +332,12 @@ from cirq.ops import (
331
332
  ZPowGate,
332
333
  ZZ,
333
334
  ZZPowGate,
335
+ UniformSuperpositionGate,
334
336
  )
335
337
 
336
338
  from cirq.transformers import (
337
339
  AbstractInitialMapper,
340
+ add_dynamical_decoupling,
338
341
  align_left,
339
342
  align_right,
340
343
  CompilationTargetGateset,
@@ -508,6 +511,7 @@ from cirq.study import (
508
511
  to_sweeps,
509
512
  Result,
510
513
  UnitSweep,
514
+ UNIT_SWEEP,
511
515
  Zip,
512
516
  ZipLongest,
513
517
  )
cirq/_compat.py CHANGED
@@ -61,23 +61,19 @@ def with_debug(value: bool) -> Iterator[None]:
61
61
  __cirq_debug__.reset(token)
62
62
 
63
63
 
64
- try:
65
- from functools import cached_property # pylint: disable=unused-import
66
- except ImportError:
67
- from backports.cached_property import cached_property # type: ignore[no-redef]
64
+ # Sentinel used by wrapped_no_args below when method has not yet been cached.
65
+ _NOT_FOUND = object()
68
66
 
69
67
 
70
68
  TFunc = TypeVar('TFunc', bound=Callable)
71
69
 
72
70
 
73
71
  @overload
74
- def cached_method(__func: TFunc) -> TFunc:
75
- ...
72
+ def cached_method(__func: TFunc) -> TFunc: ...
76
73
 
77
74
 
78
75
  @overload
79
- def cached_method(*, maxsize: int = 128) -> Callable[[TFunc], TFunc]:
80
- ...
76
+ def cached_method(*, maxsize: int = 128) -> Callable[[TFunc], TFunc]: ...
81
77
 
82
78
 
83
79
  def cached_method(method: Optional[TFunc] = None, *, maxsize: int = 128) -> Any:
@@ -103,9 +99,11 @@ def cached_method(method: Optional[TFunc] = None, *, maxsize: int = 128) -> Any:
103
99
 
104
100
  @functools.wraps(func)
105
101
  def wrapped_no_args(self):
106
- if not hasattr(self, cache_name):
107
- object.__setattr__(self, cache_name, func(self))
108
- return getattr(self, cache_name)
102
+ result = getattr(self, cache_name, _NOT_FOUND)
103
+ if result is _NOT_FOUND:
104
+ result = func(self)
105
+ object.__setattr__(self, cache_name, result)
106
+ return result
109
107
 
110
108
  return wrapped_no_args
111
109
 
cirq/_compat_test.py CHANGED
@@ -38,7 +38,6 @@ import cirq.testing
38
38
  from cirq._compat import (
39
39
  block_overlapping_deprecation,
40
40
  cached_method,
41
- cached_property,
42
41
  proper_repr,
43
42
  dataclass_repr,
44
43
  deprecated,
@@ -346,7 +345,7 @@ def test_wrap_module():
346
345
 
347
346
 
348
347
  def test_deprecate_attributes_assert_attributes_in_sys_modules():
349
- subprocess_context(_test_deprecate_attributes_assert_attributes_in_sys_modules)()
348
+ run_in_subprocess(_test_deprecate_attributes_assert_attributes_in_sys_modules)
350
349
 
351
350
 
352
351
  def _test_deprecate_attributes_assert_attributes_in_sys_modules():
@@ -635,42 +634,49 @@ _repeated_child_deprecation_msg = [
635
634
  ] + _deprecation_origin
636
635
 
637
636
 
638
- def _trace_unhandled_exceptions(*args, queue: 'multiprocessing.Queue', func: Callable, **kwargs):
637
+ def _trace_unhandled_exceptions(*args, queue: 'multiprocessing.Queue', func: Callable):
639
638
  try:
640
- func(*args, **kwargs)
639
+ func(*args)
641
640
  queue.put(None)
642
641
  except BaseException as ex:
643
642
  msg = str(ex)
644
643
  queue.put((type(ex).__name__, msg, traceback.format_exc()))
645
644
 
646
645
 
647
- def subprocess_context(test_func):
648
- """Ensures that sys.modules changes in subprocesses won't impact the parent process."""
646
+ def run_in_subprocess(test_func, *args):
647
+ """Run a function in a subprocess.
648
+
649
+ This ensures that sys.modules changes in subprocesses won't impact the parent process.
650
+
651
+ Args:
652
+ test_func: The function to be run in a subprocess.
653
+ *args: Positional args to pass to the function.
654
+ """
655
+
649
656
  assert callable(test_func), (
650
- "subprocess_context expects a function. Did you call the function instead of passing "
657
+ "run_in_subprocess expects a function. Did you call the function instead of passing "
651
658
  "it to this method?"
652
659
  )
653
660
 
654
- ctx = multiprocessing.get_context('spawn' if os.name == 'nt' else 'fork')
655
-
656
- exception = ctx.Queue()
661
+ # Use spawn to ensure subprocesses are isolated.
662
+ # See https://github.com/quantumlib/Cirq/issues/6373
663
+ ctx = multiprocessing.get_context('spawn')
657
664
 
658
- def isolated_func(*args, **kwargs):
659
- kwargs['queue'] = exception
660
- kwargs['func'] = test_func
661
- p = ctx.Process(target=_trace_unhandled_exceptions, args=args, kwargs=kwargs)
662
- p.start()
663
- p.join()
664
- result = exception.get()
665
- if result: # pragma: no cover
666
- ex_type, msg, ex_trace = result
667
- if ex_type == "Skipped":
668
- warnings.warn(f"Skipping: {ex_type}: {msg}\n{ex_trace}")
669
- pytest.skip(f'{ex_type}: {msg}\n{ex_trace}')
670
- else:
671
- pytest.fail(f'{ex_type}: {msg}\n{ex_trace}')
665
+ queue = ctx.Queue()
672
666
 
673
- return isolated_func
667
+ p = ctx.Process(
668
+ target=_trace_unhandled_exceptions, args=args, kwargs={'queue': queue, 'func': test_func}
669
+ )
670
+ p.start()
671
+ p.join()
672
+ result = queue.get()
673
+ if result: # pragma: no cover
674
+ ex_type, msg, ex_trace = result
675
+ if ex_type == "Skipped":
676
+ warnings.warn(f"Skipping: {ex_type}: {msg}\n{ex_trace}")
677
+ pytest.skip(f'{ex_type}: {msg}\n{ex_trace}')
678
+ else:
679
+ pytest.fail(f'{ex_type}: {msg}\n{ex_trace}')
674
680
 
675
681
 
676
682
  @mock.patch.dict(os.environ, {"CIRQ_FORCE_DEDUPE_MODULE_DEPRECATION": "1"})
@@ -698,7 +704,7 @@ def subprocess_context(test_func):
698
704
  ],
699
705
  )
700
706
  def test_deprecated_module(outdated_method, deprecation_messages):
701
- subprocess_context(_test_deprecated_module_inner)(outdated_method, deprecation_messages)
707
+ run_in_subprocess(_test_deprecated_module_inner, outdated_method, deprecation_messages)
702
708
 
703
709
 
704
710
  def _test_deprecated_module_inner(outdated_method, deprecation_messages):
@@ -736,7 +742,7 @@ def test_same_name_submodule_earlier_in_subtree():
736
742
  cirq.ops.engine.calibration packages. The wrong resolution resulted in false circular
737
743
  imports!
738
744
  """
739
- subprocess_context(_test_same_name_submodule_earlier_in_subtree_inner)()
745
+ run_in_subprocess(_test_same_name_submodule_earlier_in_subtree_inner)
740
746
 
741
747
 
742
748
  def _test_same_name_submodule_earlier_in_subtree_inner():
@@ -748,7 +754,7 @@ def _test_same_name_submodule_earlier_in_subtree_inner():
748
754
  def test_metadata_search_path():
749
755
  # to cater for metadata path finders
750
756
  # https://docs.python.org/3/library/importlib.metadata.html#extending-the-search-algorithm
751
- subprocess_context(_test_metadata_search_path_inner)()
757
+ run_in_subprocess(_test_metadata_search_path_inner)
752
758
 
753
759
 
754
760
  def _test_metadata_search_path_inner(): # pragma: no cover
@@ -760,7 +766,7 @@ def _test_metadata_search_path_inner(): # pragma: no cover
760
766
 
761
767
 
762
768
  def test_metadata_distributions_after_deprecated_submodule():
763
- subprocess_context(_test_metadata_distributions_after_deprecated_submodule)()
769
+ run_in_subprocess(_test_metadata_distributions_after_deprecated_submodule)
764
770
 
765
771
 
766
772
  def _test_metadata_distributions_after_deprecated_submodule():
@@ -779,7 +785,7 @@ def _test_metadata_distributions_after_deprecated_submodule():
779
785
 
780
786
 
781
787
  def test_parent_spec_after_deprecated_submodule():
782
- subprocess_context(_test_parent_spec_after_deprecated_submodule)()
788
+ run_in_subprocess(_test_parent_spec_after_deprecated_submodule)
783
789
 
784
790
 
785
791
  def _test_parent_spec_after_deprecated_submodule():
@@ -791,7 +797,7 @@ def _test_parent_spec_after_deprecated_submodule():
791
797
  def test_type_repr_in_new_module():
792
798
  # to cater for metadata path finders
793
799
  # https://docs.python.org/3/library/importlib.metadata.html#extending-the-search-algorithm
794
- subprocess_context(_test_type_repr_in_new_module_inner)()
800
+ run_in_subprocess(_test_type_repr_in_new_module_inner)
795
801
 
796
802
 
797
803
  def _test_type_repr_in_new_module_inner():
@@ -849,19 +855,19 @@ def _test_broken_module_3_inner():
849
855
 
850
856
 
851
857
  def test_deprecated_module_error_handling_1():
852
- subprocess_context(_test_broken_module_1_inner)()
858
+ run_in_subprocess(_test_broken_module_1_inner)
853
859
 
854
860
 
855
861
  def test_deprecated_module_error_handling_2():
856
- subprocess_context(_test_broken_module_2_inner)()
862
+ run_in_subprocess(_test_broken_module_2_inner)
857
863
 
858
864
 
859
865
  def test_deprecated_module_error_handling_3():
860
- subprocess_context(_test_broken_module_3_inner)()
866
+ run_in_subprocess(_test_broken_module_3_inner)
861
867
 
862
868
 
863
869
  def test_new_module_is_top_level():
864
- subprocess_context(_test_new_module_is_top_level_inner)()
870
+ run_in_subprocess(_test_new_module_is_top_level_inner)
865
871
 
866
872
 
867
873
  def _test_new_module_is_top_level_inner():
@@ -877,7 +883,7 @@ def _test_new_module_is_top_level_inner():
877
883
 
878
884
 
879
885
  def test_import_deprecated_with_no_attribute():
880
- subprocess_context(_test_import_deprecated_with_no_attribute_inner)()
886
+ run_in_subprocess(_test_import_deprecated_with_no_attribute_inner)
881
887
 
882
888
 
883
889
  def _test_import_deprecated_with_no_attribute_inner():
@@ -970,7 +976,7 @@ def test_deprecated_module_loader_repr():
970
976
 
971
977
  def test_subprocess_test_failure():
972
978
  with pytest.raises(Failed, match='ValueError.*this fails'):
973
- subprocess_context(_test_subprocess_test_failure_inner)()
979
+ run_in_subprocess(_test_subprocess_test_failure_inner)
974
980
 
975
981
 
976
982
  def _test_subprocess_test_failure_inner():
@@ -978,7 +984,7 @@ def _test_subprocess_test_failure_inner():
978
984
 
979
985
 
980
986
  def test_dir_is_still_valid():
981
- subprocess_context(_dir_is_still_valid_inner)()
987
+ run_in_subprocess(_dir_is_still_valid_inner)
982
988
 
983
989
 
984
990
  def _dir_is_still_valid_inner():
@@ -986,7 +992,7 @@ def _dir_is_still_valid_inner():
986
992
 
987
993
  import cirq.testing._compat_test_data as mod
988
994
 
989
- for m in ['fake_a', 'info', 'module_a', 'sys']:
995
+ for m in ['fake_a', 'logging', 'module_a']:
990
996
  assert m in dir(mod)
991
997
 
992
998
 
@@ -1004,23 +1010,6 @@ def test_block_overlapping_deprecation():
1004
1010
  f(5)
1005
1011
 
1006
1012
 
1007
- def test_cached_property():
1008
- class Foo:
1009
- def __init__(self):
1010
- self.bar_calls = 0
1011
-
1012
- @cached_property
1013
- def bar(self):
1014
- self.bar_calls += 1
1015
- return []
1016
-
1017
- foo = Foo()
1018
- bar = foo.bar
1019
- bar2 = foo.bar
1020
- assert bar2 is bar
1021
- assert foo.bar_calls == 1
1022
-
1023
-
1024
1013
  class Bar:
1025
1014
  def __init__(self) -> None:
1026
1015
  self.foo_calls: Dict[int, int] = collections.Counter()
cirq/_version.py CHANGED
@@ -1 +1,31 @@
1
- __version__ = "1.3.0.dev20231201141002"
1
+ # Copyright 2018 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
+ """Define version number here, read it from setup.py automatically,
16
+ and warn users that the latest version of cirq uses python 3.10+"""
17
+
18
+ import sys
19
+
20
+ if sys.version_info < (3, 10, 0): # pragma: no cover
21
+ raise SystemError(
22
+ "You installed the latest version of cirq but aren't on python 3.10+.\n"
23
+ 'To fix this error, you need to either:\n'
24
+ '\n'
25
+ 'A) Update to python 3.10 or later.\n'
26
+ '- OR -\n'
27
+ 'B) Explicitly install an older deprecated-but-compatible version '
28
+ 'of cirq (e.g. "python -m pip install cirq==1.1.*")'
29
+ )
30
+
31
+ __version__ = "1.4.0"
cirq/_version_test.py CHANGED
@@ -3,4 +3,4 @@ import cirq
3
3
 
4
4
 
5
5
  def test_version():
6
- assert cirq.__version__ == "1.3.0.dev"
6
+ assert cirq.__version__ == "1.4.0"
cirq/circuits/circuit.py CHANGED
@@ -29,14 +29,14 @@ from typing import (
29
29
  AbstractSet,
30
30
  Any,
31
31
  Callable,
32
- Mapping,
33
- MutableSequence,
34
32
  cast,
35
33
  Dict,
36
34
  FrozenSet,
37
35
  Iterable,
38
36
  Iterator,
39
37
  List,
38
+ Mapping,
39
+ MutableSequence,
40
40
  Optional,
41
41
  overload,
42
42
  Sequence,
@@ -58,9 +58,9 @@ from cirq._doc import document
58
58
  from cirq.circuits._bucket_priority_queue import BucketPriorityQueue
59
59
  from cirq.circuits.circuit_operation import CircuitOperation
60
60
  from cirq.circuits.insert_strategy import InsertStrategy
61
+ from cirq.circuits.moment import Moment
61
62
  from cirq.circuits.qasm_output import QasmOutput
62
63
  from cirq.circuits.text_diagram_drawer import TextDiagramDrawer
63
- from cirq.circuits.moment import Moment
64
64
  from cirq.protocols import circuit_diagram_info_protocol
65
65
  from cirq.type_workarounds import NotImplementedType
66
66
 
@@ -203,19 +203,24 @@ class AbstractCircuit(abc.ABC):
203
203
  copy: If True and 'self' is a Circuit, returns a copy that circuit.
204
204
  """
205
205
 
206
- def __bool__(self):
206
+ def __bool__(self) -> bool:
207
207
  return bool(self.moments)
208
208
 
209
- def __eq__(self, other):
209
+ def __eq__(self, other) -> bool:
210
210
  if not isinstance(other, AbstractCircuit):
211
211
  return NotImplemented
212
- return tuple(self.moments) == tuple(other.moments)
212
+ return other is self or (
213
+ len(self.moments) == len(other.moments)
214
+ and all(m0 == m1 for m0, m1 in zip(self.moments, other.moments))
215
+ )
213
216
 
214
217
  def _approx_eq_(self, other: Any, atol: Union[int, float]) -> bool:
215
218
  """See `cirq.protocols.SupportsApproximateEquality`."""
216
219
  if not isinstance(other, AbstractCircuit):
217
220
  return NotImplemented
218
- return cirq.protocols.approx_eq(tuple(self.moments), tuple(other.moments), atol=atol)
221
+ return other is self or cirq.protocols.approx_eq(
222
+ tuple(self.moments), tuple(other.moments), atol=atol
223
+ )
219
224
 
220
225
  def __ne__(self, other) -> bool:
221
226
  return not self == other
@@ -2625,7 +2630,7 @@ def _draw_moment_in_diagram(
2625
2630
  if desc:
2626
2631
  y = max(label_map.values(), default=0) + 1
2627
2632
  if tags and include_tags:
2628
- desc = desc + str(tags)
2633
+ desc = desc + f"[{', '.join(map(str, tags))}]"
2629
2634
  out_diagram.write(x0, y, desc)
2630
2635
 
2631
2636
  if not non_global_ops:
@@ -19,6 +19,7 @@ applied as part of a larger circuit, a CircuitOperation will execute all
19
19
  component operations in order, including any nested CircuitOperations.
20
20
  """
21
21
  import math
22
+ from functools import cached_property
22
23
  from typing import (
23
24
  Callable,
24
25
  cast,
@@ -38,7 +39,7 @@ import numpy as np
38
39
  import sympy
39
40
 
40
41
  from cirq import circuits, ops, protocols, value, study
41
- from cirq._compat import cached_property, proper_repr
42
+ from cirq._compat import proper_repr
42
43
 
43
44
  if TYPE_CHECKING:
44
45
  import cirq
@@ -2305,9 +2305,9 @@ global phase: 0.5π 0.5π
2305
2305
  cirq.testing.assert_has_diagram(
2306
2306
  c,
2307
2307
  """\
2308
- 2: ───X──────────
2308
+ 2: ───X────────
2309
2309
 
2310
- π['tag']""",
2310
+ π[tag]""",
2311
2311
  )
2312
2312
 
2313
2313
 
@@ -12,6 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
  """An immutable version of the Circuit data structure."""
15
+ from functools import cached_property
15
16
  from typing import (
16
17
  AbstractSet,
17
18
  FrozenSet,
@@ -90,7 +91,7 @@ class FrozenCircuit(AbstractCircuit, protocols.SerializableByKey):
90
91
  """Returns a tuple of the Circuit's tags."""
91
92
  return self._tags
92
93
 
93
- @_compat.cached_property
94
+ @cached_property
94
95
  def untagged(self) -> 'cirq.FrozenCircuit':
95
96
  """Returns the underlying FrozenCircuit without any tags."""
96
97
  return self._from_moments(self._moments) if self.tags else self
@@ -148,7 +149,7 @@ class FrozenCircuit(AbstractCircuit, protocols.SerializableByKey):
148
149
  def all_qubits(self) -> FrozenSet['cirq.Qid']:
149
150
  return super().all_qubits()
150
151
 
151
- @_compat.cached_property
152
+ @cached_property
152
153
  def _all_operations(self) -> Tuple['cirq.Operation', ...]:
153
154
  return tuple(super().all_operations())
154
155
 
cirq/circuits/moment.py CHANGED
@@ -283,9 +283,11 @@ class Moment:
283
283
 
284
284
  def _with_measurement_key_mapping_(self, key_map: Mapping[str, str]):
285
285
  return Moment(
286
- protocols.with_measurement_key_mapping(op, key_map)
287
- if protocols.measurement_keys_touched(op)
288
- else op
286
+ (
287
+ protocols.with_measurement_key_mapping(op, key_map)
288
+ if protocols.measurement_keys_touched(op)
289
+ else op
290
+ )
289
291
  for op in self.operations
290
292
  )
291
293
 
@@ -320,9 +322,11 @@ class Moment:
320
322
 
321
323
  def _with_key_path_prefix_(self, prefix: Tuple[str, ...]):
322
324
  return Moment(
323
- protocols.with_key_path_prefix(op, prefix)
324
- if protocols.measurement_keys_touched(op)
325
- else op
325
+ (
326
+ protocols.with_key_path_prefix(op, prefix)
327
+ if protocols.measurement_keys_touched(op)
328
+ else op
329
+ )
326
330
  for op in self.operations
327
331
  )
328
332
 
@@ -343,14 +347,14 @@ class Moment:
343
347
  if not isinstance(other, type(self)):
344
348
  return NotImplemented
345
349
 
346
- return self._sorted_operations_() == other._sorted_operations_()
350
+ return self is other or self._sorted_operations_() == other._sorted_operations_()
347
351
 
348
352
  def _approx_eq_(self, other: Any, atol: Union[int, float]) -> bool:
349
353
  """See `cirq.protocols.SupportsApproximateEquality`."""
350
354
  if not isinstance(other, type(self)):
351
355
  return NotImplemented
352
356
 
353
- return protocols.approx_eq(
357
+ return self is other or protocols.approx_eq(
354
358
  self._sorted_operations_(), other._sorted_operations_(), atol=atol
355
359
  )
356
360
 
@@ -510,13 +514,11 @@ class Moment:
510
514
  return cls.from_ops(*operations)
511
515
 
512
516
  def __add__(self, other: 'cirq.OP_TREE') -> 'cirq.Moment':
513
-
514
517
  if isinstance(other, circuits.AbstractCircuit):
515
518
  return NotImplemented # Delegate to Circuit.__radd__.
516
519
  return self.with_operations(other)
517
520
 
518
521
  def __sub__(self, other: 'cirq.OP_TREE') -> 'cirq.Moment':
519
-
520
522
  must_remove = set(op_tree.flatten_to_ops(other))
521
523
  new_ops = []
522
524
  for op in self.operations:
@@ -293,7 +293,11 @@ class QasmOutput:
293
293
  output(f'creg {meas_id}[{len(meas.qubits)}];\n')
294
294
  else:
295
295
  output(f'creg {meas_id}[{len(meas.qubits)}]; // Measurement: {comment}\n')
296
- output_line_gap(2)
296
+ # In OpenQASM 2.0, the transformation of global phase gates is ignored.
297
+ # Therefore, no newline is created when the operations contained in
298
+ # a circuit consist only of global phase gates.
299
+ if any(not isinstance(op.gate, ops.GlobalPhaseGate) for op in self.operations):
300
+ output_line_gap(2)
297
301
 
298
302
  # Operations
299
303
  self._write_operations(self.operations, output, output_line_gap)
@@ -191,6 +191,19 @@ ry(pi*-0.25) q[0];
191
191
  )
192
192
 
193
193
 
194
+ def test_qasm_global_pahse():
195
+ output = cirq.QasmOutput((cirq.global_phase_operation(np.exp(1j * 5))), ())
196
+ assert (
197
+ str(output)
198
+ == """OPENQASM 2.0;
199
+ include "qelib1.inc";
200
+
201
+
202
+ // Qubits: []
203
+ """
204
+ )
205
+
206
+
194
207
  def test_precision():
195
208
  (q0,) = _make_qubits(1)
196
209
  output = cirq.QasmOutput((cirq.X(q0) ** 0.1234567,), (q0,), precision=3)
@@ -318,16 +331,18 @@ def _all_operations(q0, q1, q2, q3, q4, include_measurements=True):
318
331
  cirq.PhasedXPowGate(phase_exponent=0.333, exponent=0.5).on(q1),
319
332
  cirq.PhasedXPowGate(phase_exponent=0.777, exponent=-0.5).on(q1),
320
333
  (
321
- cirq.measure(q0, key='xX'),
322
- cirq.measure(q2, key='x_a'),
323
- cirq.measure(q1, key='x?'),
324
- cirq.measure(q3, key='X'),
325
- cirq.measure(q4, key='_x'),
326
- cirq.measure(q2, key='x_a'),
327
- cirq.measure(q1, q2, q3, key='multi', invert_mask=(False, True)),
328
- )
329
- if include_measurements
330
- else (),
334
+ (
335
+ cirq.measure(q0, key='xX'),
336
+ cirq.measure(q2, key='x_a'),
337
+ cirq.measure(q1, key='x?'),
338
+ cirq.measure(q3, key='X'),
339
+ cirq.measure(q4, key='_x'),
340
+ cirq.measure(q2, key='x_a'),
341
+ cirq.measure(q1, q2, q3, key='multi', invert_mask=(False, True)),
342
+ )
343
+ if include_measurements
344
+ else ()
345
+ ),
331
346
  ExampleOperation(),
332
347
  ExampleCompositeOperation(),
333
348
  )
@@ -51,13 +51,15 @@ def hardcoded_qcircuit_diagram_info(op: ops.Operation) -> Optional[protocols.Cir
51
51
  symbols = (
52
52
  (r'\targ',)
53
53
  if op.gate == ops.X
54
- else (r'\control', r'\control')
55
- if op.gate == ops.CZ
56
- else (r'\control', r'\targ')
57
- if op.gate == ops.CNOT
58
- else (r'\meter',)
59
- if isinstance(op.gate, ops.MeasurementGate)
60
- else ()
54
+ else (
55
+ (r'\control', r'\control')
56
+ if op.gate == ops.CZ
57
+ else (
58
+ (r'\control', r'\targ')
59
+ if op.gate == ops.CNOT
60
+ else (r'\meter',) if isinstance(op.gate, ops.MeasurementGate) else ()
61
+ )
62
+ )
61
63
  )
62
64
  return protocols.CircuitDiagramInfo(symbols) if symbols else None
63
65
 
@@ -335,7 +335,7 @@ def test_random_circuits_equal_more_rows():
335
335
  assert_same_output_as_dense(circuit, qubits)
336
336
 
337
337
 
338
- def test_supremacy_equal_more_cols():
338
+ def test_random_circuits_equal_more_cols():
339
339
  circuit = cirq.testing.random_circuit(
340
340
  qubits=cirq.GridQubit.rect(2, 3), n_moments=6, op_density=1.0
341
341
  )
@@ -170,8 +170,15 @@ def tensor_expectation_value(
170
170
  )
171
171
  else:
172
172
  tn.rank_simplify(inplace=True)
173
- path_info = tn.contract(get='path-info')
174
- ram_gb = path_info.largest_intermediate * 128 / 8 / 1024 / 1024 / 1024
173
+ # TODO(#6586): revert when our minimum quimb version has bugfix for quimb#231
174
+ # Skip path-info evaluation when TensorNetwork consists of scalar Tensors.
175
+ # Avoid bug in quimb-1.8.0.
176
+ # Ref: https://github.com/jcmgray/quimb/issues/231
177
+ if tn.ind_map:
178
+ path_info = tn.contract(get='path-info')
179
+ ram_gb = path_info.largest_intermediate * 128 / 8 / 1024 / 1024 / 1024
180
+ else:
181
+ ram_gb = 0
175
182
  if ram_gb > max_ram_gb:
176
183
  raise MemoryError(f"We estimate that this contraction will take too much RAM! {ram_gb} GB")
177
184
  e_val = tn.contract(inplace=True)
cirq/contrib/svg/svg.py CHANGED
@@ -9,7 +9,7 @@ if TYPE_CHECKING:
9
9
  import cirq
10
10
 
11
11
  QBLUE = '#1967d2'
12
- FONT = matplotlib.font_manager.FontProperties(family="Arial")
12
+ FONT = matplotlib.font_manager.FontProperties()
13
13
  EMPTY_MOMENT_COLWIDTH = float(21) # assumed default column width
14
14
 
15
15
 
@@ -21,6 +21,7 @@ def fixup_text(text: str):
21
21
  # https://github.com/quantumlib/Cirq/issues/2905
22
22
  text = text.replace('[<virtual>]', '')
23
23
  text = text.replace('[cirq.VirtualTag()]', '')
24
+ text = text.replace('&', '&amp;')
24
25
  text = text.replace('<', '&lt;').replace('>', '&gt;')
25
26
  return text
26
27
 
@@ -65,6 +65,7 @@ def test_empty_moments():
65
65
  'symbol,svg_symbol',
66
66
  [
67
67
  ('<a', '&lt;a'),
68
+ ('<a&', '&lt;a&amp;'),
68
69
  ('<=b', '&lt;=b'),
69
70
  ('>c', '&gt;c'),
70
71
  ('>=d', '&gt;=d'),