PennyLaneAI / pennylane

PennyLane is a cross-platform Python library for quantum computing, quantum machine learning, and quantum chemistry. Train a quantum computer the same way as a neural network.
https://pennylane.ai
Apache License 2.0
2.34k stars 602 forks source link

support quantum function in the QPE #2935

Closed KetpuntoG closed 1 year ago

KetpuntoG commented 2 years ago

Feature details

Currently the QPE template only supports operator pass-through as a matrix. It would be useful to be able to pass a quantum function and not have to think in arrays.

Example

Currently the code works as follows:


import pennylane as qml

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

def unitary_block(target_wires): 
    #this is the quantum function
    qml.CZ(wires = target_wires)
    qml.GroverOperator(wires = target_wires)

unitary = qml.matrix(unitary_block)([0,1])
target_wires = [0,1]
estimation_wires = [2,3]

@qml.qnode(dev)
@qml.compile()
def circuit():

    qml.QuantumPhaseEstimation(unitary, target_wires, estimation_wires, do_queue=True, id=None)
    return qml.state()

qml.draw_mpl(circuit)()
Captura de Pantalla 2022-11-16 a las 18 46 43

In this case, the matrix calculation seems unnecessary. It would be more natural to do the following:


import pennylane as qml

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

def unitary_block(target_wires):
    qml.CZ(wires = target_wires)
    qml.GroverOperator(wires = target_wires)

target_wires = [0,1]
estimation_wires = [2,3]

@qml.qnode(dev)
@qml.compile()
def circuit():

    qml.QuantumPhaseEstimation(unitary_block, target_wires, estimation_wires, do_queue=True, id=None)
    return qml.state()

qml.draw_mpl(circuit)()

Implementation

No response

How important would you say this feature is?

1: Not important. Would be nice to have.

Additional information

One thing to watch out for: quantum functions have definite wires while a matrix does not. I guess they can be ignored.

astralcai commented 1 year ago

Hi, I just created a pull request (https://github.com/PennyLaneAI/pennylane/pull/3373) for this feature.

albi3ro commented 1 year ago

Hello @astralcai and thanks for your pull request. @KetpuntoG has added some more information about what he thought the enhancement would look like, but I would like to propose an another way for how we want this to behave.

Sorry about changing the constraints of the problem on you.

We want to be able to construct the QPE template from something other than matrices. The goal of PennyLane is to be able to implement the circuit on real hardware, and figuring out to implement a general matrix on hardware is a challenging problem. The end goal of this enhancement is to be able to represent the QPE in terms of operations that can be implemented on a quantum computer.

A quantum function is one possible way of doing that, but in adds in extra questions. What's the call signature of the quantum function? How do we pass all the arguments and keyword arguments into the quantum function? Or do we just constrain the possible arguments, like saying it must only accept target_wires? And as you no doubt encountered, we then have to internally convert that quantum function to operations, adding to the source code complexity.

I would like to propose an alternate QPE call signature.

QPE( unitary: Union[Operator, ndarray], target_wires = None, estimation_wires=None, do_queue=True, id=None)

where unitary could either be an Operator or an ndarray. If unitary is a matrix, then target_wires must be specified. If unitary is an Operator, then target wires must be left as None, as the target wires are encased in the Operator.

If the user provides a matrix, it could be immediately converted to a QubitUnitary so the QPE is always storing the same kind of information, namely an operator.

This would look like:

qml.QPE(qml.RX(1.2, wires=0), estimation_wires=range(1, 6))

This would work well with the operator arithmetic that we have been hard at work developing.

For example, we can now simply write the whole algorithm like:

op_list = [qml.Hadamard(w) for w in estimation_wires]
pow_ops = (qml.pow(unitary, 2**i) for i in range(n-1, -1, -1))
op_list.extend(qml.ctrl(op, w) for op, w in zip(pow_ops, estimation_wires))
op_list.append(qml.adjoint(qml.templates.QFT(wires=estimation_wires)))

Sorry for not clarifying the desired behaviour earlier.

astralcai commented 1 year ago

Issue resolved with PR https://github.com/PennyLaneAI/pennylane/pull/3373