Optimization of function

i have a quantum circuit and i want to find the parameters (angles) of this quantum circuit in a way that the output of the quantum circuit (which is a quantum state) be as close as possible to a desired vector. What method do you propose? i also tried with classical Netwon-Raphson optimization method but the final result was sufficiently good.
import numpy as np

import pennylane as qml

num_qubits = 3

dev = qml.device(“default.qubit”, wires=num_qubits)

a = np.array([np.sqrt(0.1), np.sqrt(0.2), np.sqrt(0.1), np.sqrt(0.3), 0, 0, np.sqrt(0.2), np.sqrt(0.1)])

@qml.qnode(dev)
def circuit(X0, X1, X2, X3, X4, X5, X6):

qml.RY(X0, wires=[0])

qml.RY(X1, wires=[1])

qml.RY(X2, wires=[2])

qml.CNOT(wires=[0, 1])

qml.RY(-X1, wires=[1])

qml.CNOT(wires=[0, 2])

qml.RY(X3, wires=[2])

qml.CNOT(wires=[1, 2])

qml.RY(X4, wires=[0])

qml.RY(X5, wires=[1])

qml.RY(X6, wires=[2])


return qml.state()

def func(X0, X1, X2, X3, X4, X5, X6):
return np.real(circuit(X0, X1, X2, X3, X4, X5, X6)-a)

the output of func must be close to zero.

Hi @sassan_moradi, here’s an example of how you can achieve your goal with the proposed circuit. Notice that I’ve changed the way to access your parameters for simplicity. I would also recommend that you try with other rotations in addition to RY in order to add complexity and maybe get closer to your target state. Generalized rotations Rot are a good option.

I also recommend that you read this blog post, which may clarify some concepts.

# Step 0 - Import the necessary libraries
import pennylane as qml
from pennylane import numpy as np

# Step 1 - Get your data ready
a = np.array([np.sqrt(0.1), np.sqrt(0.2), np.sqrt(0.1), np.sqrt(0.3), 0, 0, np.sqrt(0.2), np.sqrt(0.1)])

# Tell the optimizer that this is an input datapoint and not a parameter to optimize over.
a.requires_grad = False

# Step 2 - Create the device
num_qubits = 3
dev = qml.device('default.qubit', wires=num_qubits)

# Step 3 - Create the quantum circuit
@qml.qnode(dev)
def circuit(params):
    qml.RY(params[0], wires=[0])
    qml.RY(params[1], wires=[1])
    qml.RY(params[2], wires=[2])
    qml.CNOT(wires=[0, 1])
    qml.RY(-params[1], wires=[1])
    qml.CNOT(wires=[0, 2])
    qml.RY(params[3], wires=[2])
    qml.CNOT(wires=[1, 2])
    qml.RY(params[4], wires=[0])
    qml.RY(params[5], wires=[1])
    qml.RY(params[6], wires=[2])
    return qml.state()

# Step 4 - Classical Pre/Postprocessing
def loss(a,prediction):
    total_loss = np.real(np.sum(np.array((a-prediction)**2)))
    return total_loss

# Step 5 - Define your cost function, including any classical pre/postprocessing
def cost(a,params):
    prediction = circuit(params)
    cost = loss(a,prediction)
    return cost

# Step 6 - Train your circuit

# Steps 6.1 - Choose an optimizer and a step size
opt = qml.GradientDescentOptimizer(stepsize=0.1)

# Step 6.2 Make an initial guess for the parameters and set them as trainable
params = np.array([0.1,0.1,0.1,0.1,0.1,0.1,0.1],requires_grad=True)

# Step 6.2 - Iterate over a number of defined steps
for i in range(100):
    params_and_a,prev_cost = opt.step_and_cost(cost,a,params)
    params = params_and_a[1]
    if i%10==0:
        print(f'Step: {i},Cost: {cost(a,params)}') 

Please let me know if you have trouble running this code or if you have questions about anything that was done here.

I hope this helps you!

Many many thanks. your code is very instructive. It solved my problem.

I’m glad to hear @sassan_moradi!