`Xa*Zb*Zb*Zb` works but `Xa*Zb**3` raises error
How to reproduce the issue
In [1]: import cirq
...: a, b = cirq.LineQubit.range(2)
...: Xa, Zb = cirq.X(a), cirq.Z(b)
...: print(Xa * Zb * Zb * Zb) # Works because always stays a `cirq.PauliString`.
...: print(Xa * Zb ** 3) # Fails because Zb ** 3 returns a `cirq.ZPowGate` instead of `cirq._PauliZ`; which doesn't support multiplication with other pauli's.
X(q(0))*Z(q(1))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-2-402c68ab82e4> in <module>
3 Xa, Zb = cirq.X(a), cirq.Z(b)
4 print(Xa * Zb * Zb * Zb) # Works because always stays a `cirq.PauliString`.
----> 5 print(Xa * Zb ** 3) # Fails because Zb ** 3 returns a `cirq.ZPowGate` instead of `cirq._PauliZ`; which doesn't support multiplication with other pauli's.
TypeError: unsupported operand type(s) for *: 'SingleQubitPauliStringGateOperation' and 'GateOperation'
Cirq version: 0.16.0.dev
From cirq sync:
Looks like a bug and should be fixed. Should not be categorized as a breaking change.
Would this be a good first issue to look into. If so could this be assigned to me?
Kinda think this is not possible. Presumably it should work for even exponents too. However to work for even exponents, the gate needs to transform to cirq.I. However that ends up causing all sorts of downstream problems (even after making cirq.I an EigenGate) as can be seen in the linked PR above because cirq.I is special cased so much. Additionally it breaks all the eval(repr(x)) == x etc. protocol tests.
Well, it's possible, as I managed to get the linked PR to pass all tests. The changes are probably more breaking than desired though. And we need to add some extra handling and tests since IdentityGate, as an EigenGate, can now have a phase attached.
It also leaves Xa*Xa != Xa**2, which seems wrong. I think to solve this completely we'd need a _PauliI (which may be reasonable? Not sure.)
Nvm, different approach worked.
Nvm again. The second approach had an issue with PauliString(X(q)**2) turning into PauliString() and then losing the qubit and thus changing the commutation properties. To fix that we'd need to make I a paulistring option, which then we'd have to get into making a _PauliI, and then making Identity an EigenGate like in the first attempt. Doable, but a big change that needs some back-and-forth design and approvals since its backwards compatibility is questionable.
Would be a good issue though for someone with more time to contribute.