cirq-core 1.7.0.dev20250802022749__py3-none-any.whl → 1.7.0.dev20250805224853__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.

cirq/_version.py CHANGED
@@ -28,4 +28,4 @@ if sys.version_info < (3, 11, 0): # pragma: no cover
28
28
  'of Cirq (e.g. "python -m pip install cirq==1.5.0")'
29
29
  )
30
30
 
31
- __version__ = "1.7.0.dev20250802022749"
31
+ __version__ = "1.7.0.dev20250805224853"
cirq/_version_test.py CHANGED
@@ -3,4 +3,4 @@ import cirq
3
3
 
4
4
 
5
5
  def test_version() -> None:
6
- assert cirq.__version__ == "1.7.0.dev20250802022749"
6
+ assert cirq.__version__ == "1.7.0.dev20250805224853"
cirq/ops/pauli_string.py CHANGED
@@ -53,7 +53,6 @@ from cirq.ops import (
53
53
  identity,
54
54
  op_tree,
55
55
  pauli_gates,
56
- pauli_interaction_gate,
57
56
  raw_types,
58
57
  )
59
58
 
@@ -968,53 +967,13 @@ class PauliString(raw_types.Operation, Generic[TKey]):
968
967
  # Decompose P = Pc⊗R, where Pc acts on the same qubits as C, R acts on the remaining.
969
968
  # Then the conjugation = (C^{-1}⊗I·Pc⊗R·C⊗I) = (C^{-1}·Pc·C)⊗R.
970
969
 
971
- # Isolate R
972
- remain: cirq.PauliString = PauliString(
970
+ # Conjugation on the qubits of op
971
+ conjugated = _calc_conjugation(ps, op)
972
+ # The pauli string on the remaining qubits
973
+ remain: PauliString = PauliString(
973
974
  *(pauli(q) for q in all_qubits - set(op.qubits) if (pauli := ps.get(q)) is not None)
974
975
  )
975
-
976
- # Initialize the conjugation of Pc.
977
- conjugated: cirq.DensePauliString = (
978
- dense_pauli_string.DensePauliString(pauli_mask=[identity.I for _ in op.qubits])
979
- * ps.coefficient
980
- )
981
-
982
- # Calculate the conjugation via CliffordGate's clifford_tableau.
983
- # Note the clifford_tableau in CliffordGate represents C·P·C^-1 instead of C^-1·P·C.
984
- # So we take the inverse of the tableau to match the definition of the conjugation here.
985
- gate_in_clifford: cirq.CliffordGate
986
- if isinstance(op.gate, clifford_gate.CliffordGate):
987
- gate_in_clifford = op.gate
988
- else:
989
- # Convert the clifford gate to CliffordGate type.
990
- gate_in_clifford = clifford_gate.CliffordGate.from_op_list([op], op.qubits)
991
- tableau = gate_in_clifford.clifford_tableau.inverse()
992
-
993
- # Calculate the conjugation by `op` via mutiplying the conjugation of each Pauli:
994
- # C^{-1}·(P_1⊗...⊗P_n)·C
995
- # = C^{-1}·(P_1⊗I) ...·(P_n⊗I)·C
996
- # = (C^{-1}(P_1⊗I)C)·...·(C^{-1}(P_n⊗I)C)
997
- # For the Pauli on the kth qubit P_k. The conjugation is calculated as following.
998
- # Puali X_k's conjugation is from the destabilzer table;
999
- # Puali Z_k's conjugation is from the stabilzer table;
1000
- # Puali Y_k's conjugation is calcluated according to Y = iXZ. E.g., for the kth qubit,
1001
- # C^{-1}·Y_k⊗I·C = C^{-1}·(iX_k⊗I·Z_k⊗I)·C = i (C^{-1}·X_k⊗I·C)·(C^{-1}·Z_k⊗I·C).
1002
- for qid, qubit in enumerate(op.qubits):
1003
- pauli = ps.get(qubit)
1004
- match pauli:
1005
- case None:
1006
- continue
1007
- case pauli_gates.X:
1008
- conjugated *= tableau.destabilizers()[qid]
1009
- case pauli_gates.Z:
1010
- conjugated *= tableau.stabilizers()[qid]
1011
- case pauli_gates.Y:
1012
- conjugated *= (
1013
- 1j
1014
- * tableau.destabilizers()[qid] # conj X first
1015
- * tableau.stabilizers()[qid] # then conj Z
1016
- )
1017
- ps = remain * conjugated.on(*op.qubits)
976
+ ps = remain * conjugated
1018
977
  return ps
1019
978
 
1020
979
  def after(self, ops: cirq.OP_TREE) -> cirq.PauliString:
@@ -1371,7 +1330,18 @@ class MutablePauliString(Generic[TKey]):
1371
1330
  Returns:
1372
1331
  The mutable pauli string that was mutated.
1373
1332
  """
1374
- return self.inplace_after(protocols.inverse(ops))
1333
+ # An inplace impl of PauliString.conjugated_by().
1334
+ flattened_ops = list(op_tree.flatten_to_ops(ops))
1335
+ for op in flattened_ops[::-1]:
1336
+ conjugated = _calc_conjugation(self.frozen(), op)
1337
+ self.coefficient = conjugated.coefficient
1338
+ for q in op.qubits:
1339
+ new_pauli_int = PAULI_GATE_LIKE_TO_INDEX_MAP[conjugated.get(q) or 0]
1340
+ if new_pauli_int == 0:
1341
+ self.pauli_int_dict.pop(cast(TKey, q), None)
1342
+ else:
1343
+ self.pauli_int_dict[cast(TKey, q)] = new_pauli_int
1344
+ return self
1375
1345
 
1376
1346
  def inplace_after(self, ops: cirq.OP_TREE) -> cirq.MutablePauliString:
1377
1347
  r"""Propagates the pauli string from before to after a Clifford effect.
@@ -1391,43 +1361,7 @@ class MutablePauliString(Generic[TKey]):
1391
1361
  NotImplementedError: If any ops decompose into an unsupported
1392
1362
  Clifford gate.
1393
1363
  """
1394
- for clifford in op_tree.flatten_to_ops(ops):
1395
- for op in _decompose_into_cliffords(clifford):
1396
- ps = [self.pauli_int_dict.pop(cast(TKey, q), 0) for q in op.qubits]
1397
- if not any(ps):
1398
- continue
1399
- gate = op.gate
1400
-
1401
- if isinstance(gate, clifford_gate.SingleQubitCliffordGate):
1402
- out = gate.pauli_tuple(_INT_TO_PAULI[ps[0] - 1])
1403
- if out[1]:
1404
- self.coefficient *= -1
1405
- self.pauli_int_dict[cast(TKey, op.qubits[0])] = PAULI_GATE_LIKE_TO_INDEX_MAP[
1406
- out[0]
1407
- ]
1408
-
1409
- elif isinstance(gate, pauli_interaction_gate.PauliInteractionGate):
1410
- q0, q1 = op.qubits
1411
- p0 = _INT_TO_PAULI_OR_IDENTITY[ps[0]]
1412
- p1 = _INT_TO_PAULI_OR_IDENTITY[ps[1]]
1413
-
1414
- # Kick across Paulis that anti-commute with the controls.
1415
- kickback_0_to_1 = not protocols.commutes(p0, gate.pauli0)
1416
- kickback_1_to_0 = not protocols.commutes(p1, gate.pauli1)
1417
- kick0 = gate.pauli1 if kickback_0_to_1 else identity.I
1418
- kick1 = gate.pauli0 if kickback_1_to_0 else identity.I
1419
- self.__imul__({q0: p0, q1: kick0})
1420
- self.__imul__({q0: kick1, q1: p1})
1421
-
1422
- # Decompose inverted controls into single-qubit operations.
1423
- if gate.invert0:
1424
- self.inplace_after(gate.pauli1(q1))
1425
- if gate.invert1:
1426
- self.inplace_after(gate.pauli0(q0))
1427
-
1428
- else: # pragma: no cover
1429
- raise NotImplementedError(f"Unrecognized decomposed Clifford: {op!r}")
1430
- return self
1364
+ return self.inplace_before(protocols.inverse(ops))
1431
1365
 
1432
1366
  def _imul_helper(self, other: cirq.PAULI_STRING_LIKE, sign: int):
1433
1367
  """Left-multiplies or right-multiplies by a PAULI_STRING_LIKE.
@@ -1594,35 +1528,6 @@ class MutablePauliString(Generic[TKey]):
1594
1528
  return f'{self.frozen()!r}.mutable_copy()'
1595
1529
 
1596
1530
 
1597
- def _decompose_into_cliffords(op: cirq.Operation) -> list[cirq.Operation]:
1598
- # An operation that can be ignored?
1599
- if isinstance(op.gate, global_phase_op.GlobalPhaseGate):
1600
- return []
1601
-
1602
- # Already a known Clifford?
1603
- if isinstance(
1604
- op.gate,
1605
- (clifford_gate.SingleQubitCliffordGate, pauli_interaction_gate.PauliInteractionGate),
1606
- ):
1607
- return [op]
1608
-
1609
- # Specifies a decomposition into Cliffords?
1610
- v = getattr(op, '_decompose_into_clifford_', None)
1611
- if v is not None:
1612
- result = v()
1613
- if result is not None and result is not NotImplemented:
1614
- return list(op_tree.flatten_to_ops(result))
1615
-
1616
- # Specifies a decomposition that happens to contain only Cliffords?
1617
- decomposed = protocols.decompose_once(op, None)
1618
- if decomposed is not None:
1619
- return [out for sub_op in decomposed for out in _decompose_into_cliffords(sub_op)]
1620
-
1621
- raise TypeError( # pragma: no cover
1622
- f'Operation is not a known Clifford and did not decompose into known Cliffords: {op!r}'
1623
- )
1624
-
1625
-
1626
1531
  # Mypy has extreme difficulty with these constants for some reason.
1627
1532
  _i = cast(identity.IdentityGate, identity.I) # type: ignore
1628
1533
  _x = cast(pauli_gates.Pauli, pauli_gates.X) # type: ignore
@@ -1667,3 +1572,52 @@ def _pauli_like_to_pauli_int(key: Any, pauli_gate_like: PAULI_GATE_LIKE):
1667
1572
  f"{set(PAULI_GATE_LIKE_TO_INDEX_MAP.keys())!r}"
1668
1573
  )
1669
1574
  return pauli_int
1575
+
1576
+
1577
+ def _calc_conjugation(ps: cirq.PauliString, clifford_op: cirq.Operation) -> cirq.PauliString:
1578
+ """Computes the conjugation of a Pauli string by a single Clifford operation.
1579
+
1580
+ It computes $C^-1 P C$ where P is the Pauli string `ps` and C is the `clifford_op`.
1581
+ """
1582
+
1583
+ # Initialize the conjugation of the pauli string.
1584
+ conjugated = dense_pauli_string.DensePauliString('I' * len(clifford_op.qubits)) * ps.coefficient
1585
+
1586
+ # Calculate the conjugation via CliffordGate's clifford_tableau.
1587
+ # Note the clifford_tableau in CliffordGate represents C·P·C^-1 instead of C^-1·P·C.
1588
+ # So we take the inverse of the tableau to match the definition of the conjugation here.
1589
+ if isinstance(clifford_op.gate, clifford_gate.CliffordGate):
1590
+ gate_in_clifford = clifford_op.gate
1591
+ else:
1592
+ # Convert the clifford gate to CliffordGate type.
1593
+ gate_in_clifford = clifford_gate.CliffordGate.from_op_list(
1594
+ [clifford_op], clifford_op.qubits
1595
+ )
1596
+ tableau = gate_in_clifford.clifford_tableau.inverse()
1597
+
1598
+ # Calculate the conjugation by `clifford_op` via mutiplying the conjugation of each Pauli:
1599
+ # C^{-1}·(P_1⊗...⊗P_n)·C
1600
+ # = C^{-1}·(P_1⊗I) ...·(P_n⊗I)·C
1601
+ # = (C^{-1}(P_1⊗I)C)·...·(C^{-1}(P_n⊗I)C)
1602
+ # For the Pauli on the kth qubit P_k. The conjugation is calculated as following.
1603
+ # Pauli X_k's conjugation is from the destabilizer table;
1604
+ # Pauli Z_k's conjugation is from the stabilizer table;
1605
+ # Pauli Y_k's conjugation is calculated according to Y = iXZ. E.g., for the kth qubit,
1606
+ # C^{-1}·Y_k⊗I·C = C^{-1}·(iX_k⊗I·Z_k⊗I)·C = i (C^{-1}·X_k⊗I·C)·(C^{-1}·Z_k⊗I·C).
1607
+ for qid, qubit in enumerate(clifford_op.qubits):
1608
+ pauli = ps.get(qubit)
1609
+ match pauli:
1610
+ case None:
1611
+ continue
1612
+ case pauli_gates.X:
1613
+ conjugated *= tableau.destabilizers()[qid]
1614
+ case pauli_gates.Z:
1615
+ conjugated *= tableau.stabilizers()[qid]
1616
+ case pauli_gates.Y:
1617
+ conjugated *= (
1618
+ 1j
1619
+ * tableau.destabilizers()[qid] # conj X first
1620
+ * tableau.stabilizers()[qid] # then conj Z
1621
+ )
1622
+
1623
+ return conjugated.on(*clifford_op.qubits)
@@ -1714,6 +1714,9 @@ def test_mutable_pauli_string_inplace_conjugate_by():
1714
1714
  def _decompose_(self):
1715
1715
  return []
1716
1716
 
1717
+ def __pow__(self, power):
1718
+ return []
1719
+
1717
1720
  # No-ops
1718
1721
  p2 = p.inplace_after(cirq.global_phase_operation(1j))
1719
1722
  assert p2 is p and p == cirq.X(a)
@@ -1825,6 +1828,14 @@ def test_mutable_pauli_string_inplace_conjugate_by():
1825
1828
  assert p2 is p and p == cirq.X(a) * cirq.Y(b)
1826
1829
 
1827
1830
 
1831
+ def test_mps_inplace_after_clifford_gate_type():
1832
+ q = cirq.LineQubit(0)
1833
+
1834
+ mps = cirq.MutablePauliString(cirq.X(q))
1835
+ mps2 = mps.inplace_after(cirq.CliffordGate.from_op_list([cirq.H(q)], [q]).on(q))
1836
+ assert mps2 is mps and mps == cirq.Z(q)
1837
+
1838
+
1828
1839
  def test_after_before_vs_conjugate_by():
1829
1840
  a, b, c = cirq.LineQubit.range(3)
1830
1841
  p = cirq.X(a) * cirq.Y(b) * cirq.Z(c)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cirq-core
3
- Version: 1.7.0.dev20250802022749
3
+ Version: 1.7.0.dev20250805224853
4
4
  Summary: A framework for creating, editing, and invoking Noisy Intermediate Scale Quantum (NISQ) circuits.
5
5
  Home-page: http://github.com/quantumlib/cirq
6
6
  Author: The Cirq Developers
@@ -4,8 +4,8 @@ cirq/_compat_test.py,sha256=emXpdD5ZvwLRlFAoQB8YatmZyU3b4e9jg6FppMTUhkU,33900
4
4
  cirq/_doc.py,sha256=BrnoABo1hk5RgB3Cgww4zLHUfiyFny0F1V-tOMCbdaU,2909
5
5
  cirq/_import.py,sha256=ixBu4EyGl46Ram2cP3p5eZVEFDW5L2DS-VyTjz4N9iw,8429
6
6
  cirq/_import_test.py,sha256=oF4izzOVZLc7NZ0aZHFcGv-r01eiFFt_JORx_x7_D4s,1089
7
- cirq/_version.py,sha256=84oGq-ECVYMR3OmoK4tDuZCj6fKc_viPoLc7p9lEh2U,1206
8
- cirq/_version_test.py,sha256=rb5aOSlFW4vWo6T5o4bOnFPjfh1hmDcnbW5s8SrL41Q,155
7
+ cirq/_version.py,sha256=t7C9uWfNwn6lKdTkdGHJLwlvYnU7AGf8qzRPQKNzNjo,1206
8
+ cirq/_version_test.py,sha256=YmjevXFxxA-3iaP_2Dm936nE5JFYxd1VX_KU1ZP3xvg,155
9
9
  cirq/conftest.py,sha256=wSDKNdIQRDfLnXvOCWD3erheOw8JHRhdfQ53EyTUIXg,1239
10
10
  cirq/json_resolver_cache.py,sha256=A5DIgFAY1hUNt9vai_C3-gGBv24116CJMzQxMcXOax4,13726
11
11
  cirq/py.typed,sha256=VFSlmh_lNwnaXzwY-ZuW-C2Ws5PkuDoVgBdNCs0jXJE,63
@@ -351,12 +351,12 @@ cirq/ops/pauli_interaction_gate.py,sha256=1drxD57PLCmp7dI9p5oDX2HPzsqwh0rrqHltUj
351
351
  cirq/ops/pauli_interaction_gate_test.py,sha256=9IGQjf4cRNe1EAsxVJjTMysoO2TxUhDlp-6lXJuAYD8,4643
352
352
  cirq/ops/pauli_measurement_gate.py,sha256=OzbQeMzr9cHQsai8K-usg3Il74o8gdXZLksLuYr8RcU,7113
353
353
  cirq/ops/pauli_measurement_gate_test.py,sha256=BVTUl5EwLrKwYZmEWmVHYu15tH0L9EkF8SYrm0eL0HI,6814
354
- cirq/ops/pauli_string.py,sha256=sIU4ykQoAVRfBMfMtC_qSa31kJOVEqpygr5lqst2pic,66249
354
+ cirq/ops/pauli_string.py,sha256=_OYVeQ9G9sgim636rdrqD3h-KyPhuYHMqBRE8lTy6e8,64066
355
355
  cirq/ops/pauli_string_phasor.py,sha256=JLKZem7rdshQ0doNvFMJmP7cLhl9lCsHAI1QlOmbmrg,18207
356
356
  cirq/ops/pauli_string_phasor_test.py,sha256=-1mB1WLEFlrKnSfcgR1LabTaeLYf2bvcJQdWxEImGH4,27767
357
357
  cirq/ops/pauli_string_raw_types.py,sha256=lXW-Fv2TTv77g_7VMdQun33y4reD4p7dS7g9Nm1Id20,2256
358
358
  cirq/ops/pauli_string_raw_types_test.py,sha256=jjFEbQxGsazsR8p4y-EK7SaTryRWagR9Hi7YuixXi6A,2684
359
- cirq/ops/pauli_string_test.py,sha256=8XuWR-GMf5_evWpqwDPWLaJ_kI8V_Vvf-p-1DLNigiI,73683
359
+ cirq/ops/pauli_string_test.py,sha256=fgGtmToCPLYZDle7oLlT47x9-lWQswYKvQLRr4qo2rk,73992
360
360
  cirq/ops/pauli_sum_exponential.py,sha256=Zq8YBMZ7sLLEPQuoX4uR95I9VY4C38Ma8FtOEjQGr3k,4861
361
361
  cirq/ops/pauli_sum_exponential_test.py,sha256=u9fVBUMuiIb6xOPC2GRTR3zFUeO6N3vanejUk5_u9_8,5485
362
362
  cirq/ops/permutation_gate.py,sha256=CiAWDXloj3kszU-aEarBaCXcK73_6vJkcnnHWPKjVY8,4211
@@ -1234,8 +1234,8 @@ cirq/work/sampler.py,sha256=rxbMWvrhu3gfNSBjZKozw28lLKVvBAS_1EGyPdYe8Xg,19041
1234
1234
  cirq/work/sampler_test.py,sha256=SsMrRvLDYELyOAWLKISjkdEfrBwLYWRsT6D8WrsLM3Q,13533
1235
1235
  cirq/work/zeros_sampler.py,sha256=Fs2JWwq0n9zv7_G5Rm-9vPeHUag7uctcMOHg0JTkZpc,2371
1236
1236
  cirq/work/zeros_sampler_test.py,sha256=lQLgQDGBLtfImryys2HzQ2jOSGxHgc7-koVBUhv8qYk,3345
1237
- cirq_core-1.7.0.dev20250802022749.dist-info/licenses/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
1238
- cirq_core-1.7.0.dev20250802022749.dist-info/METADATA,sha256=f31y6zNaPyxsCJVjmUrmqypaohPrAApRgU49FP1M0Rk,4857
1239
- cirq_core-1.7.0.dev20250802022749.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1240
- cirq_core-1.7.0.dev20250802022749.dist-info/top_level.txt,sha256=Sz9iOxHU0IEMLSFGwiwOCaN2e9K-jFbBbtpPN1hB73g,5
1241
- cirq_core-1.7.0.dev20250802022749.dist-info/RECORD,,
1237
+ cirq_core-1.7.0.dev20250805224853.dist-info/licenses/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
1238
+ cirq_core-1.7.0.dev20250805224853.dist-info/METADATA,sha256=Y72Oatju05t4dHmtkp5Q1HIIUO6843DCAaAd-otF7hU,4857
1239
+ cirq_core-1.7.0.dev20250805224853.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1240
+ cirq_core-1.7.0.dev20250805224853.dist-info/top_level.txt,sha256=Sz9iOxHU0IEMLSFGwiwOCaN2e9K-jFbBbtpPN1hB73g,5
1241
+ cirq_core-1.7.0.dev20250805224853.dist-info/RECORD,,