Running several optimizations and keeping the best one with MultipleLaunchesPlugin¶
In this notebook, we present the MultipleLaunchesAnalyzer
plugin. Placed before a VQE plugin, it will run the job for several iterations with different random parameters at each run. It will then select the lowest observable value it has found among these runs.
More specifically, placing the MultipleLaunchesAnalyzer
plugin set with $n_{\mathrm{runs}}=10$ before an Optimizer
instantiated without any starting point will allow the ansatz to be optimized $n_{\mathrm{runs}}$ times, each time with a different set of random parameters. The output value will be the lowest found value obtained through the iteration process.
This is particularly useful when the ansatz parameters values cannot be guessed before a VQE.
Note: if a job in the batch is not variational, it will be evaluated 10 times!
Example : Solving an embedded model using MultipleLaunchesAnalyzer
¶
We will solve an embedded model using the MultipleLaunchesAnalyzer
. Let us say we are unsure about which ansatz would be best suited for this task. We select two ansatz :
- the 8-parameters hardware-efficient circuit proposed by (Keen et al., 2019) (https://doi.org/10.48550/arXiv.1910.09512)
- the physically-inspired circuit (LDCA) with 34 parameters proposed by P. Dallaire-Demers et al. (2019) (https://doi.org/10.48550/arXiv.1801.01053>)
We will start by defining the Hamiltonian to solve, define the two ansatze, and then compute the observable value for the two ansatze (using Batch
) and for different set of random parameters (using MultipleLaunchesAnalyzer
).
import matplotlib.pyplot as plt
import numpy as np
from itertools import product
from qat.qpus import get_default_qpu
from qat.core import Batch, Job
from qat.fermion.transforms import transform_to_jw_basis
from qat.fermion.hamiltonians import make_embedded_model
from qat.fermion.circuits import make_shallow_circ, make_ldca_circ
from qat.plugins import ScipyMinimizePlugin, MultipleLaunchesAnalyzer
We start by defining the Hamiltonian we'd like to find the ground state of with VQE.
# We define the Hamiltonian
U = 1
mu = U / 2
D = 0.4 * np.eye(2)
lambda_c = -0.04 * np.eye(2)
hamiltonian = make_embedded_model(U, mu, D, lambda_c, grouping="spins")
# The ordering of the orbitals (here, 'spins') is crucial for the HEA circuit
We now define two ansatze we want to use for the observable evaluation.
# Defining the first job
circ1 = make_shallow_circ()
job1 = circ1.to_job(job_type="OBS", observable=transform_to_jw_basis(hamiltonian))
# Defining the second job
circ2 = make_ldca_circ(4, 1)
job2 = circ2.to_job(job_type="OBS", observable=transform_to_jw_basis(hamiltonian))
We define a Batch
containing these two variational jobs, and define the stack to submit the Batch
to.
# Defining the batch
batch = Batch(jobs=[job1, job2])
# Build the stack and submit the job to the QPU
qpu = get_default_qpu()
multiple_launches_analyzer = MultipleLaunchesAnalyzer(n_runs=10, verbose=True)
scipy_optimizer = ScipyMinimizePlugin(method="COBYLA", tol=1e-3, options={"maxiter": 200})
stack = multiple_launches_analyzer | scipy_optimizer | qpu
res = stack.submit(batch)
Values found for job #1 [-0.90189307 -1.12181965 -0.80454213 -0.79259302 -0.79256468 -1.12866477 -0.79255775 -0.79259626 -0.79259486 -1.12850734] Lowest value is thus -1.1286647682975952 Position in batch of job with lowest value: 5 Values found for job #2 [-1.10791256 -1.1199605 -1.12658195 -1.09389316 -1.09837069 -1.12082038 -1.11704435 -1.11824569 -1.11676242 -1.11159489] Lowest value is thus -1.1265819524690277 Position in batch of job with lowest value: 12
# Select the lowest obtained energy
energy = min((result.value for _, result in enumerate(res)))
print(f"We obtained an energy of {energy}.")
We obtained an energy of -1.1286647682975952.
# Exact diagonalization of the Hamiltonian for future reference
eigvals_cl = np.linalg.eigvalsh(hamiltonian.get_matrix())
E0 = min(eigvals_cl)
print(f"Exact ground state = {E0}")
Exact ground state = -1.1286686816105571
print(
"Variance of results obtained by optimizing the small hardware-efficient circuit:", res[0].meta_data["optimal_values_variance"]
)
print("Variance of results obtained by optimizing the LDCA circuit:", res[1].meta_data["optimal_values_variance"])
Variance of results obtained by optimizing the small hardware-efficient circuit: 0.022028318542728707 Variance of results obtained by optimizing the LDCA circuit: 9.589094778758178e-05
As expected, the variance of the results is a lot greater for the small circuit, which is the sign of an increased sensitivity to the initial parameters.