cirq-core 1.6.0.dev20250505215959__py3-none-any.whl → 1.6.0.dev20250507223949__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 (40) hide show
  1. cirq/_compat_test.py +4 -1
  2. cirq/_version.py +1 -1
  3. cirq/_version_test.py +1 -1
  4. cirq/circuits/insert_strategy.py +7 -5
  5. cirq/contrib/acquaintance/gates_test.py +3 -1
  6. cirq/contrib/graph_device/hypergraph.py +3 -1
  7. cirq/contrib/paulistring/clifford_optimize.py +2 -2
  8. cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py +9 -3
  9. cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py +2 -0
  10. cirq/contrib/paulistring/pauli_string_optimize.py +2 -0
  11. cirq/contrib/paulistring/recombine.py +1 -1
  12. cirq/contrib/paulistring/separate.py +5 -4
  13. cirq/contrib/qasm_import/qasm.py +2 -0
  14. cirq/contrib/quimb/density_matrix.py +4 -1
  15. cirq/contrib/quimb/state_vector.py +4 -1
  16. cirq/contrib/quirk/quirk_gate.py +3 -1
  17. cirq/contrib/routing/router.py +2 -0
  18. cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking.py +4 -0
  19. cirq/experiments/fidelity_estimation.py +11 -5
  20. cirq/linalg/combinators.py +4 -2
  21. cirq/linalg/predicates.py +6 -1
  22. cirq/linalg/tolerance.py +4 -1
  23. cirq/neutral_atoms/convert_to_neutral_atom_gates.py +9 -3
  24. cirq/ops/clifford_gate_test.py +3 -1
  25. cirq/ops/pauli_string.py +3 -4
  26. cirq/ops/pauli_string_phasor.py +20 -3
  27. cirq/ops/pauli_string_phasor_test.py +2 -5
  28. cirq/ops/pauli_string_test.py +0 -147
  29. cirq/ops/projector.py +13 -8
  30. cirq/transformers/gauge_compiling/cphase_gauge.py +2 -0
  31. cirq/vis/heatmap.py +1 -1
  32. cirq/work/sampler.py +33 -34
  33. cirq/work/sampler_test.py +6 -2
  34. cirq/work/zeros_sampler.py +3 -1
  35. cirq/work/zeros_sampler_test.py +3 -1
  36. {cirq_core-1.6.0.dev20250505215959.dist-info → cirq_core-1.6.0.dev20250507223949.dist-info}/METADATA +1 -1
  37. {cirq_core-1.6.0.dev20250505215959.dist-info → cirq_core-1.6.0.dev20250507223949.dist-info}/RECORD +40 -40
  38. {cirq_core-1.6.0.dev20250505215959.dist-info → cirq_core-1.6.0.dev20250507223949.dist-info}/WHEEL +0 -0
  39. {cirq_core-1.6.0.dev20250505215959.dist-info → cirq_core-1.6.0.dev20250507223949.dist-info}/licenses/LICENSE +0 -0
  40. {cirq_core-1.6.0.dev20250505215959.dist-info → cirq_core-1.6.0.dev20250507223949.dist-info}/top_level.txt +0 -0
cirq/_compat_test.py CHANGED
@@ -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
+
15
+ from __future__ import annotations
16
+
14
17
  import collections
15
18
  import dataclasses
16
19
  import importlib.metadata
@@ -635,7 +638,7 @@ _repeated_child_deprecation_msg = [
635
638
  ] + _deprecation_origin
636
639
 
637
640
 
638
- def _trace_unhandled_exceptions(*args, queue: 'multiprocessing.Queue', func: Callable):
641
+ def _trace_unhandled_exceptions(*args, queue: multiprocessing.Queue, func: Callable):
639
642
  try:
640
643
  func(*args)
641
644
  queue.put(None)
cirq/_version.py CHANGED
@@ -28,4 +28,4 @@ if sys.version_info < (3, 10, 0): # pragma: no cover
28
28
  'of cirq (e.g. "python -m pip install cirq==1.1.*")'
29
29
  )
30
30
 
31
- __version__ = "1.6.0.dev20250505215959"
31
+ __version__ = "1.6.0.dev20250507223949"
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.6.0.dev20250505215959"
6
+ assert cirq.__version__ == "1.6.0.dev20250507223949"
@@ -14,16 +14,18 @@
14
14
 
15
15
  """Hard-coded options for adding multiple operations to a circuit."""
16
16
 
17
+ from __future__ import annotations
18
+
17
19
 
18
20
  class InsertStrategy:
19
21
  """Indicates preferences on how to add multiple operations to a circuit."""
20
22
 
21
- NEW: 'InsertStrategy'
22
- NEW_THEN_INLINE: 'InsertStrategy'
23
- INLINE: 'InsertStrategy'
24
- EARLIEST: 'InsertStrategy'
23
+ NEW: InsertStrategy
24
+ NEW_THEN_INLINE: InsertStrategy
25
+ INLINE: InsertStrategy
26
+ EARLIEST: InsertStrategy
25
27
 
26
- def __new__(cls, name: str, doc: str) -> 'InsertStrategy':
28
+ def __new__(cls, name: str, doc: str) -> InsertStrategy:
27
29
  inst = getattr(cls, name, None)
28
30
  if not inst or not isinstance(inst, cls):
29
31
  inst = super().__new__(cls)
@@ -12,6 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from __future__ import annotations
16
+
15
17
  from itertools import combinations, product
16
18
  from random import randint
17
19
  from string import ascii_lowercase as alphabet
@@ -257,7 +259,7 @@ class OtherOperation(cirq.Operation):
257
259
  def qubits(self) -> Tuple[cirq.Qid, ...]:
258
260
  return self._qubits
259
261
 
260
- def with_qubits(self, *new_qubits: cirq.Qid) -> 'OtherOperation':
262
+ def with_qubits(self, *new_qubits: cirq.Qid) -> OtherOperation:
261
263
  return type(self)(self._qubits)
262
264
 
263
265
  def __eq__(self, other):
@@ -12,6 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from __future__ import annotations
16
+
15
17
  import itertools
16
18
  import random
17
19
  from typing import Any, Dict, FrozenSet, Hashable, Iterable, Mapping, Optional, Set, Tuple, Union
@@ -103,7 +105,7 @@ class UndirectedHypergraph:
103
105
  @classmethod
104
106
  def random(
105
107
  cls, vertices: Union[int, Iterable], edge_probs: Mapping[int, float]
106
- ) -> 'UndirectedHypergraph':
108
+ ) -> UndirectedHypergraph:
107
109
  """A random hypergraph.
108
110
 
109
111
  Every possible edge is included with probability edge_prob[len(edge)].
@@ -65,7 +65,7 @@ def clifford_optimized_circuit(circuit: circuits.Circuit, atol: float = 1e-8) ->
65
65
  furthest_i = i
66
66
  break
67
67
  if cont_cond == CONTINUE:
68
- modified_op = modified_op.pass_operations_over([op], after_to_before=True)
68
+ modified_op = modified_op.conjugated_by(protocols.inverse(op))
69
69
  num_passed_over += 1
70
70
  if len(modified_op.pauli_string) == 1:
71
71
  furthest_op = modified_op
@@ -122,7 +122,7 @@ def clifford_optimized_circuit(circuit: circuits.Circuit, atol: float = 1e-8) ->
122
122
  all_ops.insert(merge_i + 1, part_cliff_gate(qubit))
123
123
  elif isinstance(other_op, ops.PauliStringPhasor):
124
124
  # Pass over a non-Clifford gate
125
- mod_op = other_op.pass_operations_over([part_cliff_gate(qubit)])
125
+ mod_op = other_op.conjugated_by([part_cliff_gate(qubit)])
126
126
  all_ops[merge_i] = mod_op
127
127
  all_ops.insert(merge_i + 1, part_cliff_gate(qubit))
128
128
  elif merge_i > start_i + 1 and num_passed > 0:
@@ -11,19 +11,25 @@
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
  """Tools for measuring expectation values of Pauli strings with readout error mitigation."""
16
+
17
+ from __future__ import annotations
18
+
15
19
  import itertools
16
20
  import time
17
- from typing import cast, Dict, FrozenSet, List, Optional, Sequence, Tuple, Union
21
+ from typing import cast, Dict, FrozenSet, List, Optional, Sequence, Tuple, TYPE_CHECKING, Union
18
22
 
19
23
  import attrs
20
24
  import numpy as np
21
25
 
22
26
  from cirq import circuits, ops, work
23
27
  from cirq.contrib.shuffle_circuits import run_shuffled_with_readout_benchmarking
24
- from cirq.experiments import SingleQubitReadoutCalibrationResult
25
28
  from cirq.experiments.readout_confusion_matrix import TensoredConfusionMatrices
26
- from cirq.study import ResultDict
29
+
30
+ if TYPE_CHECKING:
31
+ from cirq.experiments import SingleQubitReadoutCalibrationResult
32
+ from cirq.study import ResultDict
27
33
 
28
34
 
29
35
  @attrs.frozen
@@ -12,6 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from __future__ import annotations
16
+
15
17
  import itertools
16
18
  import random
17
19
  from typing import Dict, Sequence
@@ -12,6 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from __future__ import annotations
16
+
15
17
  import networkx
16
18
 
17
19
  from cirq import circuits, linalg
@@ -53,7 +53,7 @@ def _sorted_best_string_placements(
53
53
  ):
54
54
  # This is as far through as this Pauli string can move
55
55
  break
56
- string_op = string_op.pass_operations_over([out_op], after_to_before=True)
56
+ string_op = string_op.conjugated_by(protocols.inverse(out_op))
57
57
  curr = (string_op, i + 1, possible_node)
58
58
  if sort_key(curr) > sort_key(node_max):
59
59
  node_max = curr
@@ -89,8 +89,9 @@ def pauli_string_half(circuit: circuits.Circuit) -> circuits.Circuit:
89
89
 
90
90
 
91
91
  def _pull_non_clifford_before(circuit: circuits.Circuit) -> Iterator[ops.OP_TREE]:
92
- def _iter_ops_range_reversed(moment_end):
93
- for i in reversed(range(moment_end)):
92
+
93
+ def _iter_ops_range(moment_end):
94
+ for i in range(moment_end):
94
95
  moment = circuit[i]
95
96
  for op in moment.operations:
96
97
  if not isinstance(op, ops.PauliStringPhasor):
@@ -99,5 +100,5 @@ def _pull_non_clifford_before(circuit: circuits.Circuit) -> Iterator[ops.OP_TREE
99
100
  for i, moment in enumerate(circuit):
100
101
  for op in moment.operations:
101
102
  if isinstance(op, ops.PauliStringPhasor):
102
- ops_to_cross = _iter_ops_range_reversed(i)
103
- yield op.pass_operations_over(ops_to_cross)
103
+ ops_to_cross = _iter_ops_range(i)
104
+ yield op.conjugated_by(ops_to_cross)
@@ -12,6 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from __future__ import annotations
16
+
15
17
  from cirq import circuits
16
18
  from cirq.contrib.qasm_import._parser import QasmParser
17
19
 
@@ -1,4 +1,7 @@
1
1
  # pylint: disable=wrong-or-nonexistent-copyright-notice
2
+
3
+ from __future__ import annotations
4
+
2
5
  from functools import lru_cache
3
6
  from typing import Dict, List, Optional, Sequence, Tuple, Union
4
7
 
@@ -77,7 +80,7 @@ def _add_to_positions(
77
80
 
78
81
  def circuit_to_density_matrix_tensors(
79
82
  circuit: cirq.Circuit, qubits: Optional[Sequence[cirq.Qid]] = None
80
- ) -> Tuple[List[qtn.Tensor], Dict['cirq.Qid', int], Dict[Tuple[str, str], Tuple[float, float]]]:
83
+ ) -> Tuple[List[qtn.Tensor], Dict[cirq.Qid, int], Dict[Tuple[str, str], Tuple[float, float]]]:
81
84
  """Given a circuit with mixtures or channels, construct a tensor network
82
85
  representation of the density matrix.
83
86
 
@@ -1,4 +1,7 @@
1
1
  # pylint: disable=wrong-or-nonexistent-copyright-notice
2
+
3
+ from __future__ import annotations
4
+
2
5
  import warnings
3
6
  from typing import cast, Dict, List, Optional, Sequence, Tuple, Union
4
7
 
@@ -28,7 +31,7 @@ def circuit_to_tensors(
28
31
  circuit: cirq.Circuit,
29
32
  qubits: Optional[Sequence[cirq.Qid]] = None,
30
33
  initial_state: Union[int, None] = 0,
31
- ) -> Tuple[List[qtn.Tensor], Dict['cirq.Qid', int], None]:
34
+ ) -> Tuple[List[qtn.Tensor], Dict[cirq.Qid, int], None]:
32
35
  """Given a circuit, construct a tensor network representation.
33
36
 
34
37
  Indices are named "i{i}_q{x}" where i is a time index and x is a
@@ -12,6 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from __future__ import annotations
16
+
15
17
  from typing import Any, Callable, cast, Dict, Optional, Union
16
18
 
17
19
  import numpy as np
@@ -46,7 +48,7 @@ class QuirkOp:
46
48
  self.keys = keys
47
49
  self.can_merge = can_merge
48
50
 
49
- def controlled(self, control_count: int = 1) -> 'QuirkOp':
51
+ def controlled(self, control_count: int = 1) -> QuirkOp:
50
52
  return QuirkOp(*['•'] * control_count, *self.keys, can_merge=False)
51
53
 
52
54
 
@@ -12,6 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from __future__ import annotations
16
+
15
17
  from typing import Callable, Optional
16
18
 
17
19
  import networkx as nx
@@ -11,7 +11,11 @@
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
  """Tools for running circuits in a shuffled order with readout error benchmarking."""
16
+
17
+ from __future__ import annotations
18
+
15
19
  import time
16
20
  from typing import Dict, List, Optional, Tuple, Union
17
21
 
@@ -11,16 +11,22 @@
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
  """Estimation of fidelity associated with experimental circuit executions."""
15
- from typing import Callable, Mapping, Optional, Sequence
16
+
17
+ from __future__ import annotations
18
+
19
+ from typing import Callable, Mapping, Optional, Sequence, TYPE_CHECKING
16
20
 
17
21
  import numpy as np
18
22
 
19
- from cirq.circuits import Circuit
20
23
  from cirq.ops import QubitOrder, QubitOrderOrList
21
24
  from cirq.sim import final_state_vector
22
25
  from cirq.value import state_vector_to_probabilities
23
26
 
27
+ if TYPE_CHECKING:
28
+ import cirq
29
+
24
30
 
25
31
  def linear_xeb_fidelity_from_probabilities(
26
32
  hilbert_space_dimension: int, probabilities: Sequence[float]
@@ -132,7 +138,7 @@ def hog_score_xeb_fidelity_from_probabilities(
132
138
 
133
139
 
134
140
  def xeb_fidelity(
135
- circuit: Circuit,
141
+ circuit: cirq.Circuit,
136
142
  bitstrings: Sequence[int],
137
143
  qubit_order: QubitOrderOrList = QubitOrder.DEFAULT,
138
144
  amplitudes: Optional[Mapping[int, complex]] = None,
@@ -197,7 +203,7 @@ def xeb_fidelity(
197
203
 
198
204
 
199
205
  def linear_xeb_fidelity(
200
- circuit: Circuit,
206
+ circuit: cirq.Circuit,
201
207
  bitstrings: Sequence[int],
202
208
  qubit_order: QubitOrderOrList = QubitOrder.DEFAULT,
203
209
  amplitudes: Optional[Mapping[int, complex]] = None,
@@ -213,7 +219,7 @@ def linear_xeb_fidelity(
213
219
 
214
220
 
215
221
  def log_xeb_fidelity(
216
- circuit: Circuit,
222
+ circuit: cirq.Circuit,
217
223
  bitstrings: Sequence[int],
218
224
  qubit_order: QubitOrderOrList = QubitOrder.DEFAULT,
219
225
  amplitudes: Optional[Mapping[int, complex]] = None,
@@ -14,6 +14,8 @@
14
14
 
15
15
  """Utility methods for combining matrices."""
16
16
 
17
+ from __future__ import annotations
18
+
17
19
  import functools
18
20
  from typing import TYPE_CHECKING, Union
19
21
 
@@ -107,7 +109,7 @@ def kron_with_controls(*factors: Union[np.ndarray, complex]) -> np.ndarray:
107
109
  return product
108
110
 
109
111
 
110
- def dot(*values: 'ArrayLike') -> np.ndarray:
112
+ def dot(*values: ArrayLike) -> np.ndarray:
111
113
  """Computes the dot/matrix product of a sequence of values.
112
114
 
113
115
  Performs the computation in serial order without regard to the matrix
@@ -136,7 +138,7 @@ def dot(*values: 'ArrayLike') -> np.ndarray:
136
138
  return result
137
139
 
138
140
 
139
- def _merge_dtypes(dtype1: 'DTypeLike', dtype2: 'DTypeLike') -> np.dtype:
141
+ def _merge_dtypes(dtype1: DTypeLike, dtype2: DTypeLike) -> np.dtype:
140
142
  return (np.zeros(0, dtype1) + np.zeros(0, dtype2)).dtype
141
143
 
142
144
 
cirq/linalg/predicates.py CHANGED
@@ -11,7 +11,12 @@
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
  """Utility methods for checking properties of matrices."""
16
+
17
+ from __future__ import annotations
18
+
19
+ from types import EllipsisType
15
20
  from typing import cast, List, Optional, Sequence, Tuple, Union
16
21
 
17
22
  import numpy as np
@@ -228,7 +233,7 @@ def slice_for_qubits_equal_to(
228
233
  big_endian_qureg_value: int = 0,
229
234
  num_qubits: Optional[int] = None,
230
235
  qid_shape: Optional[Tuple[int, ...]] = None,
231
- ) -> Tuple[Union[slice, int, 'ellipsis'], ...]:
236
+ ) -> Tuple[Union[slice, int, EllipsisType], ...]:
232
237
  """Returns an index corresponding to a desired subset of an np.ndarray.
233
238
 
234
239
  It is assumed that the np.ndarray's shape is of the form (2, 2, 2, ..., 2).
cirq/linalg/tolerance.py CHANGED
@@ -14,6 +14,9 @@
14
14
 
15
15
  """Utility for testing approximate equality of matrices and scalars within
16
16
  tolerances."""
17
+
18
+ from __future__ import annotations
19
+
17
20
  from typing import Iterable, TYPE_CHECKING, Union
18
21
 
19
22
  import numpy as np
@@ -22,7 +25,7 @@ if TYPE_CHECKING:
22
25
  from numpy.typing import ArrayLike
23
26
 
24
27
 
25
- def all_near_zero(a: 'ArrayLike', *, atol: float = 1e-8) -> bool:
28
+ def all_near_zero(a: ArrayLike, *, atol: float = 1e-8) -> bool:
26
29
  """Checks if the tensor's elements are all near zero.
27
30
 
28
31
  Args:
@@ -12,15 +12,21 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from cirq import ops
15
+ from __future__ import annotations
16
+
17
+ from typing import TYPE_CHECKING
18
+
16
19
  from cirq.neutral_atoms import neutral_atom_devices
17
20
 
21
+ if TYPE_CHECKING:
22
+ import cirq
23
+
18
24
 
19
- def is_native_neutral_atom_op(operation: ops.Operation) -> bool:
25
+ def is_native_neutral_atom_op(operation: cirq.Operation) -> bool:
20
26
  """Returns true if the operation is in the default neutral atom gateset."""
21
27
  return operation in neutral_atom_devices.neutral_atom_gateset()
22
28
 
23
29
 
24
- def is_native_neutral_atom_gate(gate: ops.Gate) -> bool:
30
+ def is_native_neutral_atom_gate(gate: cirq.Gate) -> bool:
25
31
  """Returns true if the gate is in the default neutral atom gateset."""
26
32
  return gate in neutral_atom_devices.neutral_atom_gateset()
@@ -12,6 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from __future__ import annotations
16
+
15
17
  import functools
16
18
  import itertools
17
19
  from typing import Tuple, Type
@@ -59,7 +61,7 @@ def _all_rotation_pairs():
59
61
 
60
62
 
61
63
  @functools.lru_cache()
62
- def _all_clifford_gates() -> Tuple['cirq.SingleQubitCliffordGate', ...]:
64
+ def _all_clifford_gates() -> Tuple[cirq.SingleQubitCliffordGate, ...]:
63
65
  return tuple(
64
66
  cirq.SingleQubitCliffordGate.from_xz_map(trans_x, trans_z)
65
67
  for trans_x, trans_z in _all_rotation_pairs()
cirq/ops/pauli_string.py CHANGED
@@ -45,6 +45,7 @@ import numpy as np
45
45
  import sympy
46
46
 
47
47
  from cirq import _compat, linalg, protocols, qis, value
48
+ from cirq._compat import deprecated
48
49
  from cirq._doc import document
49
50
  from cirq._import import LazyLoader
50
51
  from cirq.ops import (
@@ -1070,9 +1071,10 @@ class PauliString(raw_types.Operation, Generic[TKey]):
1070
1071
  """
1071
1072
  return self.conjugated_by(ops)
1072
1073
 
1074
+ @deprecated(deadline="v2.0", fix="Use conjuagetd_by()/before()/after() instead.")
1073
1075
  def pass_operations_over(
1074
1076
  self, ops: Iterable[cirq.Operation], after_to_before: bool = False
1075
- ) -> PauliString:
1077
+ ) -> PauliString: # pragma: no cover
1076
1078
  """Determines how the Pauli string changes when conjugated by Cliffords.
1077
1079
 
1078
1080
  The output and input pauli strings are related by a circuit equivalence.
@@ -1099,9 +1101,6 @@ class PauliString(raw_types.Operation, Generic[TKey]):
1099
1101
  pauli string, instead of before (and so are moving in the
1100
1102
  opposite direction).
1101
1103
  """
1102
- # TODO(#6946): deprecate this method.
1103
- # Note: This method is supposed to be replaced by conjugated_by()
1104
- # (see #2351 for details).
1105
1104
  if after_to_before:
1106
1105
  return self.after(ops)
1107
1106
 
@@ -30,7 +30,7 @@ from typing import (
30
30
  import sympy
31
31
 
32
32
  from cirq import protocols, value
33
- from cirq._compat import proper_repr
33
+ from cirq._compat import deprecated, proper_repr
34
34
  from cirq.ops import (
35
35
  common_gates,
36
36
  dense_pauli_string as dps,
@@ -199,9 +199,21 @@ class PauliStringPhasor(gate_operation.GateOperation):
199
199
  syms = tuple(sym(qubit) for qubit in qubits)
200
200
  return protocols.CircuitDiagramInfo(wire_symbols=syms, exponent=self.exponent_relative)
201
201
 
202
+ def conjugated_by(self, clifford: 'cirq.OP_TREE') -> 'PauliStringPhasor':
203
+ r"""Returns the Pauli string conjugated by a clifford operation.
204
+
205
+ The PauliStringPhasor $P$ conjugated by the Clifford operation $C$ is
206
+ $C^\dagger P C$.
207
+ """
208
+ new_pauli_string: ps.PauliString = self.pauli_string.conjugated_by(clifford)
209
+ pp = self.exponent_pos
210
+ pn = self.exponent_neg
211
+ return PauliStringPhasor(new_pauli_string, exponent_pos=pp, exponent_neg=pn)
212
+
213
+ @deprecated(deadline="v2.0", fix="Use conjuagetd_by() instead.")
202
214
  def pass_operations_over(
203
215
  self, ops: Iterable[raw_types.Operation], after_to_before: bool = False
204
- ) -> PauliStringPhasor:
216
+ ) -> PauliStringPhasor: # pragma: no cover
205
217
  """Determines how the Pauli phasor changes when conjugated by Cliffords.
206
218
 
207
219
  The output and input pauli phasors are related by a circuit equivalence.
@@ -228,7 +240,12 @@ class PauliStringPhasor(gate_operation.GateOperation):
228
240
  pauli string, instead of before (and so are moving in the
229
241
  opposite direction).
230
242
  """
231
- new_pauli_string = self.pauli_string.pass_operations_over(ops, after_to_before)
243
+ new_pauli_string: ps.PauliString = ps.PauliString()
244
+ if after_to_before:
245
+ new_pauli_string = self.pauli_string.after(ops)
246
+ else:
247
+ all_ops = list(op_tree.flatten_to_ops(ops))
248
+ new_pauli_string = self.pauli_string.before(all_ops[::-1])
232
249
  pp = self.exponent_pos
233
250
  pn = self.exponent_neg
234
251
  return PauliStringPhasor(new_pauli_string, exponent_pos=pp, exponent_neg=pn)
@@ -155,7 +155,7 @@ def test_consistent():
155
155
  cirq.testing.assert_implements_consistent_protocols(p)
156
156
 
157
157
 
158
- def test_pass_operations_over():
158
+ def test_conjugated_by():
159
159
  q0, q1 = _make_qubits(2)
160
160
  op = cirq.SingleQubitCliffordGate.from_double_map(
161
161
  {cirq.Z: (cirq.X, False), cirq.X: (cirq.Z, False)}
@@ -164,10 +164,7 @@ def test_pass_operations_over():
164
164
  ps_after = cirq.PauliString({q0: cirq.Z, q1: cirq.Y}, -1)
165
165
  before = cirq.PauliStringPhasor(ps_before, exponent_neg=0.1)
166
166
  after = cirq.PauliStringPhasor(ps_after, exponent_neg=0.1)
167
- assert before.pass_operations_over([op]).pauli_string == after.pauli_string
168
- assert (
169
- after.pass_operations_over([op], after_to_before=True).pauli_string == before.pauli_string
170
- )
167
+ assert before.conjugated_by(op).pauli_string == after.pauli_string
171
168
 
172
169
 
173
170
  def test_extrapolate_effect():