Qml.ctrl problem

Hi! I’ve been working with qml.ctrl and I get this problem, could anyone help me?

DeviceError: Gate ControlledOperation not supported on device default.qubit.autograd

I share part of my code:

import pennylane as qml
from pennylane import numpy as np

np.random.seed(23)   
n = 2
@qml.template
def function1(x,w):
    for i in range(n):
        qml.CZ(wires = [i, (i+1)%n])
        qml.RY(w[i], wires = i)
        
    for i in range(n):
        qml.RY(x[i], wires = i)
        qml.CZ(wires = [i, (i+1)%n])
        qml.RZ(x[i], wires = i)

def circuit(x,y,w):
    qml.adjoint(function1(x,w))
    function1(y,w)
    

dev = qml.device("default.qubit", wires = n + 1)
@qml.qnode(dev)
def function2(x,y,w):
    ops = qml.ctrl(circuit, control = n)
    qml.Hadamard(n)
    ops(x = x, y = y, w = w)
    qml.Hadamard(n)
    return qml.probs(wires = n)

def function3(x,y,w):
    probs = function2(x,y,w)
    print(probs)
    return probs[0] - probs[1]

function3([1]*n,[2]*n,[3]*n)

Thanks in advance!

Thanks @Guillermo_Alonso!

Just a small comment, I think there is a small typo in your code:

qml.adjoint(function1(x,w))

should be

qml.adjoint(function1)(x,w)

After making that change, however, I think I have found the bug - qml.CZ doesn’t seem to support being made β€˜controlled’! If you change the qml.CZ to qml.CNOT, then it works.

I think there are two things that need to be done here:

  1. Update the error message so that it is more helpful. The error message in this case should have said CZ operation does not support controls.

  2. Add support for the CZ operation to be controlled :slight_smile:

I will open a bug over on the PennyLane GitHub to make sure this gets fixed.

Cool! Thanks @josh :muscle:

I’ve made a PR here to fix this bug: https://github.com/PennyLaneAI/pennylane/pull/1376

In the meantime @Guillermo_Alonso, you can install PennyLane directly from this PR so that your code will run:

pip install git+https://github.com/PennyLaneAI/pennylane.git@pennylane-release
1 Like

Hi,

I am struggle with qml.ctrl. I am trying to build a controlled time evolution gate and I completely failed. This is the code line:

qml.ctrl(qml.ApproxTimeEvolution(H,t,itrotter), control=w)

H is the hamiltonian, t is time, itrotter is the Trotter step, and w the control tire. So, I tried something simpler, that I show in the following. So I realized that the qml.ctrl is not working properly, and I want to know what I am doing wrong.

import pennylane as qml
from pennylane import numpy as np

Nqubits = 4
phi = np.pi/2
dev = qml.device('default.qubit', wires=Nqubits)

@qml.qnode(dev)
def circuit(N, theta, w1, w2, w3, w4):
   qml.PauliX(w1)
   qml.PauliX(w3)
   qml.ctrl(qml.RX(theta,wires=w1), control=w2)
   qml.CRX(theta, wires=(w4,w3))
   return [qml.expval(qml.PauliZ(i)) for i in range(N)]

circuit(Nqubits,phi,0,1,2,3)
drawer = qml.draw(circuit)
print(drawer(Nqubits,phi,0,1,2,3))

exp_value = circuit(Nqubits,phi,0,1,2,3)
print(exp_value)

And this is the result that I got:

0: ──X───RX(1.57)─── ⟨Z⟩
1: ───────────────── ⟨Z⟩
2: ──X──╭RX(1.57)─── ⟨Z⟩
3: ─────╰C────────── ⟨Z⟩

[-2.22044605e-16 1.00000000e+00 -1.00000000e+00 1.00000000e+00]

As you can see, the wires=0 was rotated even with the control wires=1 being equal to |0>.

Hi @Julio_Rocha! qml.ctrl works similarly to qml.adjoint; in particular, it takes the operation or template to transform, and returns a new operation. So it can be used like this:

qml.ctrl(qml.RX, control=w2)(theta, wires=w1)

Note the order of the arguments! We first create a controlled RX gate, and then we pass the parameters.

This can be seen more clearly by breaking it up into two steps:

# create a controlled version of RX, where
# the control wire is w2
ctrl_rx_gate = qml.ctrl(qml.RX, control=w2)

# this new gate now takes the same parameters as RX
ctrl_rx_gate(theta, wires=w1)
1 Like

Hi Josh,

it works perfectly! Thank you very much! :smiley: