[Reparameterizing a circuit]

Hi there,

Suppose I have the final circuit output from ADAPT-VQE, where all parameters have already been optimized.

My question is: Is there a way to reuse this circuit structure but reparameterize it with new (unoptimized) parameters? In other words, can I retain the same gate sequence but reset the parameter values to allow for fresh optimization?

This is my code by the way. Thanks so much.

# Load the dataset
dataset = qml.data.load("qchem", molname="H2", basis="6-31G")[0]
H, qubits = dataset.hamiltonian, len(dataset.hamiltonian.wires)
hf_state = dataset.hf_state

n_electrons = dataset.electrons


# Print dataset details
print("--- ADAPT-VQE BENCHMARK ---")
print("Number of qubits = ", qubits)
print("Hartree-Fock state = ", hf_state)
print("Reference VQE energy = ", dataset.vqe_energy)

# Define the quantum device
dev = qml.device("lightning.qubit", wires=qubits)

# Counter for circuit evaluations
circuit_evals = 0

# Generate operator pool
singles, doubles = qml.qchem.excitations(n_electrons, qubits)
singles_excitations = [qml.SingleExcitation(0.0, x) for x in singles]
doubles_excitations = [qml.DoubleExcitation(0.0, x) for x in doubles]
operator_pool = doubles_excitations + singles_excitations

# Define the circuit
@qml.qnode(dev)
def circuit():
    global circuit_evals
    circuit_evals += 1
    qml.BasisState(hf_state, wires=range(qubits))
    return qml.expval(H)

# Instantiate the optimizer
opt = qml.AdaptiveOptimizer(10, 0.9)
total_adapt_evals = 0

# Optimization loop
for i in range(len(operator_pool)):
    # Reset counter for this step
    circuit_evals = 0

    # Perform adaptive optimization step
    circuit, target, gradient = opt.step_and_cost(circuit, operator_pool, drain_pool=True)
    circuit_adapt = circuit
    # Count evaluations
    evals_for_step = circuit_evals
    total_adapt_evals += evals_for_step

    # Print results
    print(f'ADAPT-VQE Step {i+1}:')
    print('Energy:', target)
    print('Largest Gradient:', gradient)
    print('Circuit evaluations for gradient:', evals_for_step)
    print()

    # Check convergence
    if gradient < 1e-3:
        break

# Print final result
print(f"Final ADAPT-VQE energy: {target:.8f} Hartree")
print(f"Total ADAPT-VQE evaluations: {total_adapt_evals}")
print("-----------------------------")```

Hi @ethanrajkumar , welcome to the Forum!

I’m assuming you based your code on our demo on Adaptive Circuits. Is that right? I can see that there are some practical fixes you need for your code to run, but to answer your specific question, yes, you can definitely build a circuit by adaptively optimizing its gates and the reusing the circuit structure.

If you look at the first section of the demo, you’ll see how you can print the circuit after every 3 iterations and the circuit will change. If you then run this same example again but commenting the lines where you define your qnode, the current circuit will be the optimized one. When you run the optimization again the result will be that the gradient is very small so the program realizes there’s no more optimization to do and it quickly exits.

If you’re interested in more general circuits and not specifically for chemistry this is also possible. If this is what you’re looking for I can share a quick example if it will help.

Let me know if this answers your question!

Hi @CatalinaAlbornoz,
Thanks so much for your help. The main reason I am asking this is because I have developed a new optimization algorithm for VQE. To test it, I want to use the final circuit structure (the specific sequence of gates) that was built by the ADAPT-VQE algorithm.

My plan is to:

  1. Run ADAPT-VQE on a problem to generate a final circuit ansatz.
  2. Take that exact sequence of gates but discard the optimized parameter values it found.
  3. Re-initialize all the parameters in this circuit to a starting value, like 0.0.
  4. Finally, use my new optimizer to find the ground state energy using this fixed-structure, re-initialized circuit.

How would I do this?

I know that Pennylane Datasets has a circuit but I think it’s different from what I get for ADAPT-VQE, so I want to try that circuit.

Thanks so much again. I really appreciate your help.

Regards,
Ethan R.

Hi @ethanrajkumar ,

Thanks for explaining the context! In that case it might be better to follow the “Manual” approach explained in the demo. This way you have direct access to each of the excitations and you can set any parameters you want after having the finalized structure.

If you specifically want to use the “automated” approach then you might need to extract the gates from the circuit tape and re-create the circuit so that you can then add the parameters of your choice.

Are you looking for something like the former option or the latter?

Hi @CatalinaAlbornoz,

Thank you so much for the reply. From what you described, I think the latter approach (“automated” ) would be much more useful especially since, if I am going to be using this approach for multiple different molecules with multiple different bond lengths.

I really appreciate the help and support.

Regards,
Ethan

That makes sense @ethanrajkumar . In that case we may need to inspect the final circuit or access the tape to get the gates. Let me know if you know how to use tapes or Quantum Scripts. Otherwise I can share an example.

Hi @CatalinaAlbornoz

Thank you so much for the reply! I don’t know how to use tapes or quantum scripts. Would you be able to share an example?

I really appreciate your help and support.

Regards,

Ethan

Hi @ethanrajkumar ,

No problem, here’s an example. You use the “automatic” workflow we mentioned before to obtain a circuit with a certain structure.In my case I’ll use just the first iteration for simplicity, but you can use the full circuit with more gates and parameters.

Example from the demo with just one Givens rotation

import pennylane as qml
import jax
import numpy as np
import time

from pennylane import qchem
from jax import numpy as jnp

jax.config.update("jax_enable_x64", True)

symbols = ["Li", "H"]
geometry = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 2.969280527]])
molecule = qchem.Molecule(symbols, geometry)

H, qubits = qchem.molecular_hamiltonian(
    molecule,
    active_electrons=2,
    active_orbitals=5
)

active_electrons = 2

singles, doubles = qchem.excitations(active_electrons, qubits)

print(f"Total number of excitations = {len(singles) + len(doubles)}")

singles_excitations = [qml.SingleExcitation(0.0, x) for x in singles]
doubles_excitations = [qml.DoubleExcitation(0.0, x) for x in doubles]
operator_pool = doubles_excitations + singles_excitations

hf_state = qchem.hf_state(active_electrons, qubits)
dev = qml.device("default.qubit", wires=qubits)
@qml.qnode(dev)
def circuit():
    [qml.PauliX(i) for i in np.nonzero(hf_state)[0]]
    return qml.expval(H)


opt = qml.optimize.AdaptiveOptimizer()
for i in range(1):#len(operator_pool)):
    circuit, energy, gradient = opt.step_and_cost(circuit, operator_pool)
    if i % 3 == 0:
        print("n = {:},  E = {:.8f} H, Largest Gradient = {:.3f}".format(i, energy, gradient))
        print(qml.draw(circuit, decimals=None)())
        print()
    if gradient < 3e-3:
        break

Modification of the parameters

Now we can construct a QuantumTape from the circuit, modify the parameters, and execute the new circuit.

# Draw and print the output of the original circuit for comparison
qml.draw_mpl(circuit, decimals=1)()
print("Original output: ", circuit())

# Construct a tape from the circuit
tape = qml.workflow.construct_tape(circuit)()
old_params = tape.get_parameters()
print(f"old_params: {old_params}")

# Edit the parameters, just one in this case
new_tape = tape.bind_new_parameters(params=[1.0], indices=[0])
new_params = new_tape.get_parameters()
print(f"new_params: {new_params}")

# Draw and print the output of the modified circuit for comparison
print(new_tape.draw(decimals=1))
new_output = qml.execute([new_tape], dev)
print("New output: ", new_output)

Let me know if this works for you!

Hi @CatalinaAlbornoz ,

It works well! I just used in reference to what I have.

The situation has been resolved. Thanks so much for helping me with this!