How do I implement a controlled Rx in Cirq/Tensorflow Quantum?

1.1k Views Asked by At

I am trying to implement a controlled rotation gate in Cirq/Tensorflow Quantum.

The readthedocs.io at https://cirq.readthedocs.io/en/stable/gates.html states:

"Gates can be converted to a controlled version by using Gate.controlled(). In general, this returns an instance of a ControlledGate. However, for certain special cases where the controlled version of the gate is also a known gate, this returns the instance of that gate. For instance, cirq.X.controlled() returns a cirq.CNOT gate. Operations have similar functionality Operation.controlled_by(), such as cirq.X(q0).controlled_by(q1)."

I have implemented

cirq.rx(theta_0).on(q[0]).controlled_by(q[3])

I get the following error:

~/.local/lib/python3.6/site-packages/cirq/google/serializable_gate_set.py in 
serialize_op(self, op, msg, arg_function_language)
    193                         return proto_msg
    194         raise ValueError('Cannot serialize op {!r} of type {}'.format(
--> 195             gate_op, gate_type))
    196 
    197     def deserialize_dict(self,

ValueError: Cannot serialize op cirq.ControlledOperation(controls=(cirq.GridQubit(0, 3),), sub_operation=cirq.rx(sympy.Symbol('theta_0')).on(cirq.GridQubit(0, 0)), control_values=((1,),)) of type <class 'cirq.ops.controlled_gate.ControlledGate'>

I have the qubits and symbols initialized as:

q = cirq.GridQubit.rect(1, 4)
symbol_names = x_0, x_1, x_2, x_3, theta_0, theta_1, z_2, z_3

I do re-use the circuits with various circuits.

My question: How do I properly implement a controlled Rx in Cirq/Tensorflow Quantum?

P.S. I can't find a tag for Google Cirq

Follow up: How does this generalize to the similar situations of Controlled Ry and controlled Rz?

For Rz I found a gate decomposition at https://threeplusone.com/pubs/on_gates.pdf, involving H.on(q1), CNOT(q0, q1), H.on(q2), but this is not yet an CRz with an arbitrary angle. Would I introduce the angle before the H?

For the Ry, I did not find a decomposition yet, neither the CRy.

1

There are 1 best solutions below

2
On BEST ANSWER

What you have is a completely correct implementation of a controlled X rotation in Cirq. It can be used in simulation and other things like cirq.unitary without any issues.

TFQ only supports a subset of gates in Cirq. For example a cirq.ControlledGate can have an arbitrary number of control qubits, which in some cases can make it harder to decompose down to primitive gates that are compatible with NiSQ hardware platforms (This is why cirq.decompose doesn't do anything to ControlledOperations). TFQ only supports these primitive style gates , for a full list of the supported gates, you can do:

tfq.util.get_supported_gates().keys()

In your case it is possible to come up with a simpler implementation of this gate. First we can note that cirq.rx(some angle) is equal to cirq.X**(some angle / pi) offset by a global phase:

>>> a = cirq.rx(0.3)
>>> b = cirq.X**(0.3 / np.pi)
>>> cirq.equal_up_to_global_phase(cirq.unitary(a), cirq.unitary(b))
True

Lets move to using X now. Then the operation we are after is:

>>> qs = cirq.GridQubit.rect(1,2)
>>> a = (cirq.X**0.3)(qs[0]).controlled_by(qs[1])
>>> b = cirq.CNOT(qs[0], qs[1]) ** 0.3
>>> cirq.equal_up_to_global_phase(cirq.unitary(a), cirq.unitary(b))
True

Since cirq.CNOT is in the TFQ supported gates it should be serializable without any issues. If you want to make a symbolized version of the gate you can just replace the 0.3 with a sympy.Symbol.

Answer to follow up: If you want to do a CRz you can do the same thing you did above, swapping out the CNOT gate for the CZ gate. For CRy it's not as easy. For that I would recommend doing some combination of: cirq.Y(0) and cirq.YY(0, 1).

Edit: tfq-nightly builds and likely releases after 0.4.0 now include support for arbitrary controlled gates. So on these versions of tfq you could also do things like cirq.Y(...).controlled_by(...) to achieve the desired result now too.