PauliString.after() crashes for Clifford gate PhXZ(a=0.25,x=-1,z=0) in _decompose_into_cliffords
Description of the issue
PauliString.after() should be able to return a PauliString with Clifford ops input, but failed for the Clifford gate PhasedXZGate(axis_phase_exponent=0.25, x_exponent=-1,z_exponent=0).
How to reproduce the issue
>>> a = cirq.NamedQubit('a')
>>> ps = cirq.PauliString() * cirq.Y(a)
>>> phxz = cirq.PhasedXZGate(axis_phase_exponent=0.25, x_exponent=-1,z_exponent=0)
>>> ps.after(phxz.on(a))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/google/home/renyichen/miniconda3/envs/cirq-conda/lib/python3.10/site-packages/cirq/ops/pauli_string.py", line 1008, in after
return self.conjugated_by(protocols.inverse(ops))
File "/usr/local/google/home/renyichen/miniconda3/envs/cirq-conda/lib/python3.10/site-packages/cirq/ops/pauli_string.py", line 987, in conjugated_by
for clifford_op in _decompose_into_cliffords(op)[::-1]:
File "/usr/local/google/home/renyichen/miniconda3/envs/cirq-conda/lib/python3.10/site-packages/cirq/ops/pauli_string.py", line 1606, in _decompose_into_cliffords
return [out for sub_op in decomposed for out in _decompose_into_cliffords(sub_op)]
File "/usr/local/google/home/renyichen/miniconda3/envs/cirq-conda/lib/python3.10/site-packages/cirq/ops/pauli_string.py", line 1606, in <listcomp>
return [out for sub_op in decomposed for out in _decompose_into_cliffords(sub_op)]
File "/usr/local/google/home/renyichen/miniconda3/envs/cirq-conda/lib/python3.10/site-packages/cirq/ops/pauli_string.py", line 1608, in _decompose_into_cliffords
raise TypeError(
TypeError: Operation is not a known Clifford and did not decompose into known Cliffords: (cirq.T**-1).on(cirq.NamedQubit('a'))
Cirq version
1.5.0.dev20250109234340
cirq-sync: convert the gate to a Clifford and detect global phase (Which the clifford gate will ignore)
Interested in investigating and trying to fix this.
@babacry thanks Renyi, the fix we suggest is the same as you did in your PR + preserving the global phase
Thanks for the info, noted!
Global phases in the Clifford gate won't affect the conjugate_by(), after(), before() results as global phase commute with other gates,
$$ (GC) \cdot P \cdot (GC)^\dagger = C \cdot P \cdot C^\dagger $$
where $\mathrm{G}=k\mathrm{I}$ is the global phase gate, $C$ is Clifford gate, $P$ is Pauli gate.
Directly using cirq.CliffordGate.from_op_list() before calling _decompose_into_cliffords works for the phxz gate mentioned above, but doesn't work for all the use cases.
Investigating the recursive decomposition logic and trying to sort things out with a clean solution.
Global phases in the Clifford gate won't affect the conjugate_by(), after(), before()
good observation .. I forgot we were conjugating.
but doesn't work for all the use cases
which cases break it?
Thanks for the comments!
The test case failed in ISwapPowGate as this gate type doesn't have _has_stabilizer_effect_, fixed in the first commit of the PR.
The 2nd commit of the PR fix the issue itself.
#7103
#7294
Other than deprecating pass_operations_over in #7294, I still need to update the inplace_before() and inplace_after() of PauliString, then we may fully remove _decompose_into_cliffords() etc.