cirq.decompose semantics are confusing
See original GitHub issueI believe there is a bug in the keep functionality of cirq.decompose. Perhaps I am just using it wrong. Consider the following code.
class MyGate(cirq.TwoQubitGate, cirq.InterchangeableQubitsGate):
def _decompose_(self, qubits):
a, b = qubits
yield cirq.XXPowGate(global_shift=-0.5, exponent=0.5).on(a, b)
yield cirq.YYPowGate(global_shift=-0.5, exponent=0.5).on(a, b)
def __repr__(self):
return 'MyGate'
class MyOtherGate(cirq.TwoQubitGate, cirq.InterchangeableQubitsGate):
def _decompose_(self, qubits):
a, b = qubits
yield (cirq.Z ** 1.4321001256099544).on(a)
yield cirq.CZ(a, b) ** (-3 / 17)
yield MyGate().on(a, b)
yield cirq.YYPowGate(global_shift=-0.5, exponent=0.5).on(a, b)
def stop_at_mygate(gate):
return isinstance(gate, MyGate)
a, b = cirq.LineQubit.range(2)
circuit = cirq.Circuit.from_ops(
cirq.decompose(MyOtherGate().on(a, b), keep=stop_at_mygate))
print(circuit)
I would have expected this code to decompose things until stopping at “MyGate”. Instead, it assumes that I really want it to decompose everything that isn’t MyGate, including things that cannot be decomposed further. Thus, I get the error message:
ValueError: Operation doesn't satisfy the given
keep but can't be decomposed: (cirq.Z**1.4321001256099544).on(cirq.LineQubit(0))
This is very counter intuitive at best. But fine, perhaps when I use this keep functionality I need to explicitly tell the decomposer to stop when things don’t have a decompose method. Thus, I tried changing stop_at_mygate in the following way:
def stop_at_mygate(gate):
return (isinstance(gate, MyGate) or
not hasattr(gate, '_decompose_'))
But that also did not work. What is going on here?
As a final note, if I do decompose things all the way (I don’t pass the keep argument) then things get compiled into Molmer-Sorensen gates. Who ordered that!? Those gates are only relevant for ion traps. My feeling is that nothing in Cirq should compile to MS gates by default.
Issue Analytics
- State:
- Created 4 years ago
- Comments:10 (2 by maintainers)
Also your “keep” method
def stop_at_mygate(gate): return isinstance(gate, MyGate)
will only return True if the thing that is passed into it is aGate
. You are passing itGateOperation
s via your generator. Does the following “keep” function give you behavior you expect?EDIT: What is your expected output?
An XXPowGate with global shift of -0.5 is by definition a MS gate. The reason an MS gate shows up in your circuit is because you put one in it, not because decompose is attempting to construct a circuit with it.