Description
Describe your design idea/issue
The gate cirq.XPowGate(global_shift=0.22).controlled()
decomposes to
Z**-0.28(q(0))
Z**0.5000000000000002(q(1))
(0.7071067811865474-0.7071067811865477j)
Y**-0.5(q(1))
CZ(q(0), q(1))
Y**0.5(q(1))
Z**-0.21999999999999992(q(1))
X**0.5(q(1))
S(q(1))
(0.33873792024529137-0.9408807689542256j)
Y**-0.5(q(1))
CZ(q(0), q(1))
Y**0.5(q(1))
Y**-0.49999999999999994(q(1))
Z**1.2199999999999998(q(1))
(-0.42577929156507277+0.9048270524660196j)
But it's easy to see that cirq.XPowGate(global_shift=0.22).controlled()
can be broken down into a regular X
gate plus a GlobalPhaseGate(0.22)
, with the same control applied to each. The controlled X
is therefore just CX
, which has a defined decomposition to [Y, CZ, Y]
, and a controlled phase gate is equivalent to a Z**phase
. Therefore, cirq.XPowGate(global_shift=0.22).controlled()
is logically equivalent to and probably should decompose to
Y**-0.5(q1)
CZ(q0, q1)
Y**0.5(q1)
Z**0.22(q0)
This similarly happens with other controlled instances of EigenGate
with global phases, where ControlledGate._decompose_
sends them through the raw numeric matrix reduction transformers, instead of just factoring out the phase first.
An approach to solve this could be
- Add a default
EigenGate._decompose_
that factors out any phase into its own gate. i.e. it returns a phase-free EigenGate and a separate global phase gate. - In
ControlledGate._decompose_
, move the matrix transformer option to be the last option to try (after attempting the decomposition of the subgate). This would allow the controlled phased gate to decompose into a controlled unphased gate plus a controlled global phase, which generally will be simpler to decompose further from there.