Conditional random layers for optimization

Hi,

I am new to Pennylane and working on optimization using random layers.

I am trying to insert random layers in lieu of ‘PauliZ’ or ‘PauliX’ in the following lines of code

qml.cond(m_0, qml.PauliZ)(wires=3)
qml.cond(m_1, qml.PauliX)(wires=3)

My strawman solution was to do something like this

if m_0 == 0 and m_1 == 0:
  qml.RandomLayers(weights=weights[1], wires=3)
if m_0 == 0 and m_1 == 1:
  qml.RandomLayers(weights=weights[2], wires=3)
elif m_0 == 1 and m_1 == 0:
  qml.RandomLayers(weights=weights[3], wires=3)
elif m_0 == 1 and m_1 == 1:
  qml.RandomLayers(weights=weights[4], wires=3)

But that doesn’t seem to work well with the optimizer. I also tried using 4 qml.cond statements but that didn’t seem to work either. I imagine I could try storing the measurement results m_0 and m_1 in auxiliary wires and use qml.ctrl, but that seems like an unnecessary use of auxiliary wires to me.

Please help me see the correct way to optimize over random layers conditioned on measurement results and let me know if I need to clarify something.

Thanks

Hi @Mayank_Bhatia, welcome to the forum!

Your if statements will probably cause you trouble.

I don’t think we have a way of using two conditional measurements at once. If you could reformulate your problem so that you only need a single one then you could code something like the following:

dev = qml.device("default.qubit", wires=4)

@qml.qnode(dev)
@qml.defer_measurements
def qnode_conditional_op_on_zero(x, weights):
    qml.RY(x, wires=0)
    qml.CNOT(wires=[0, 1])
    m_2 = qml.measure(2)
    m_3 = qml.measure(3)

    qml.cond(m_3 == 0, qml.RandomLayers)(weights, wires=range(2))
    return qml.probs(wires=[0])

weights = np.array([[0.1, -2.1, 1.4]])
pars = np.array([0.643, weights], requires_grad=True)

qnode_conditional_op_on_zero(*pars)

Please let me know if this is what you needed!

Hi @CatalinaAlbornoz, thank you!

Thanks for the help. As far as I know, I will need multiple conditional measurements. Generally, if I make n measurements in my circuit, I believe I will need 2^n separate cases of random layers which to optimize.

For example, my desired behavior would be something like qml.cond(m_2 m_3 = 00, qml.RandomLayers)(weights,wires=range(2)).

I hope this is possible! Thanks

Hi @Mayank_Bhatia!

You can combine multiple outputs from qml.measure() into a new logical expression, e.g.:

import pennylane as qml

dev = qml.device("default.qubit", wires=3)

@qml.qnode(dev)
def f(x, y):
    qml.RX(x, wires=0)
    qml.RY(y, wires=1)
    
    m0 = qml.measure(0)
    m1 = qml.measure(1)
    
    qml.cond(m0 == 0 and m1 == 0, qml.RX)(x + y, wires=2)
    qml.cond(m0 == 0 and m1 == 1, qml.RY)(x - y, wires=2)
    qml.cond(m0 == 1 and m1 == 0, qml.RX)(-x + y, wires=2)
    qml.cond(m0 == 1 and m1 == 1, qml.RY)(-x - y, wires=2)
    return qml.expval(qml.PauliZ(2))

f(0.4, 0.5)

Hi @Tom_Bromley !

Thank you for your help! I am for some reason not able to use your suggestion in the circuit I am trying to optimize.

For example, I would believe that

qml.cond(m_0, qml.PauliZ)(wires=3)

Is no different than

qml.cond(m_0 == 1 and m_1 == 0, qml.PauliZ)(wires=3)
qml.cond(m_0 == 1 and m_1 == 1, qml.PauliZ)(wires=3)

However, I am not able to take a step with the Adam optimizer if I make this simple substitution in my code (I would get an eigenvalues don’t converge error if I did this).

I think that my description above might be a bit vague so I also have a brief notebook to provide the full context of my issue: Google Colab

Thank you!

Hi @Mayank_Bhatia,

I get no issue when I do the replacement that you propose. I think the error you see might be originating in how you’re passing the weights.

For instance the following works:

dev = qml.device("default.qubit", wires=4)

@qml.qnode(dev)
def qnode_conditional_op_on_zero(x, weights):
    qml.RY(x, wires=0)
    qml.CNOT(wires=[0, 1])
    m_2 = qml.measure(2)
    m_3 = qml.measure(3)

    qml.cond(m_2 == 0 and m_3 == 0, qml.RandomLayers)(weights, wires=range(2))
    return qml.probs(wires=[0])

weights = np.array([[0.1, -2.1, 1.4]])
pars = np.array([0.643, weights], requires_grad=True)

qnode_conditional_op_on_zero(*pars)

If you can reduce your code to a minimal example it might help you uncover the source of the error.