qat.plugins.PQEOptimizationPlugin

This plugin is one of the two plugins that, once combined, allow performing projective quantum eigensolving (PQE, Stair et al.) on Qaptiva.

This plugin has to be used second in the stack, it performs the quasi-Newton root finding procedure.

class qat.plugins.PQEOptimizationPlugin(orbital_energies: List[float], hf_state: int, maxiter: int = 50, equation_threshold: float = 0.001, use_diis_bool: bool = True, diis_depth: int = 6, diis_threshold: float = 1e-05, print_norm_during_optimization: bool = False, use_convergence_criterion: bool = False)

Plugin for the optimization part (“microiterations”) of the PQE algorithm based on Stair and al. article.

It uses the quasi-Newton update rule:

\[t_\mu^{(n+1)} = t_\mu^{(n)} + \frac{r_\mu^{(n)}}{\Delta_\mu}\]

where: \(t_\mu^{(n)}\) is the parameter for operator \(\hat{\kappa_\mu}\) at the n-th step, \(r_\mu = \bra{\Phi_\mu}\hat{U}^\dagger\hat{H}\hat{U}\ket{\Phi_0}\), and \(\Delta_{a,b, \cdots, i, j} = \epsilon_{a} + \epsilon_{b} \cdots - \epsilon_{i} - \epsilon_{j}\) with \(\epsilon_k\) the orbital energies.

Parameters
  • orbital_energies (List[float]) – list of the Hartree-Fock orbital energies

  • hf_state (int) – index of the Hartree-Fock state (e.g “010”, corresponding to the second molecular orbital being occupied, corresponds to hf_state = 2)

  • maxiter (int, optional) – maximum number of Newton iterations. Defaults to 50.

  • equation_threshold (float, optional) – convergence threshold for Newton method. Defaults to 1e-3.

  • use_diis_bool (bool, optional) – whether to use a DIIS convergence accelation method. Defaults to True.

  • diis_depth (int, optional) – depth of DIIS. Defaults to 6.

  • diis_threshold (float, optional) – threshold of DIIS. Defaults to 1e-5.

  • print_norm_during_optimization (bool, optional) – whether to print the norm of the residues during optimization. Defaults to False.

  • use_convergence_criterion (bool, optional) – Use a convergence criterion. Defaults to False.

run(batch, meta_data)

Uses the quasi-Newton update rule.

Parameters

batch (Batch) – the batch containing the variational circuit

Returns

Result whose value is the trial state energy, whose parameter_map contains the optimized parameters and whose meta_data contains the energy optimization trace, residue optimization trace, the number of measurements and the number of optimization steps.

Return type

Result

# Projective quantum eigensolver for the H2 molecule at r = 0.75
# we first set up the computation of the inputs for the H2 molecule,
# namely the Hamiltonian of the molecule and the parameters of the
# Hartree-Fock starting point

from qat.lang.AQASM import Program, X
from qat.qpus import LinAlg
from qat.fermion.chemistry.pyscf_tools import perform_pyscf_computation
from qat.fermion.chemistry import MolecularHamiltonian
from qat.fermion.chemistry.ucc import get_hf_ket
from qat.fermion.transforms import recode_integer, get_jw_code
from qat.plugins import SPQEPlugin, PQEOptimizationPlugin

r = 0.75
geometry = [("H", (0, 0, 0)), ("H", (0, 0, r))]
charge, spin = 0, 0

basis = "sto-3g"
(
    rdm1,
    orbital_energies,
    nuclear_repulsion,
    n_electrons,
    one_body_integrals,
    two_body_integrals,
    info,
) = perform_pyscf_computation(
    geometry=geometry, basis=basis, spin=spin, charge=charge, run_fci=True
)
mol_h = MolecularHamiltonian(
    one_body_integrals, two_body_integrals, nuclear_repulsion
)
nqbits = rdm1.shape[0] * 2
ket_hf_init = get_hf_ket(n_electrons, nqbits=nqbits)
H_mol = mol_h.get_electronic_hamiltonian()
H_sp = H_mol.to_spin()
hf_init_sp = recode_integer(ket_hf_init, get_jw_code(H_sp.nbqbits))

# Here, we initialize the circuit with the Hartree-Fock state
# PQE will do the rest by adding parameterized gates corresponding to
# single, double, etc., excitations

prog = Program()
reg = prog.qalloc(nqbits)
for j, char in enumerate(format(hf_init_sp, "0" + str(nqbits) + "b")):
    if char == "1":
        prog.apply(X, reg[j])
job = prog.to_circ().to_job(observable=H_sp, nbshots=0)

PQE_plugin = SPQEPlugin(
    hf_state=hf_init_sp,
    max_excitation_order=2,
    selection_threshold=1e-3,
    delta_t=1e-1
)

PQEOptimization = PQEOptimizationPlugin(
    orbital_energies,
    hf_init_sp,
    use_diis_bool=True,
    maxiter=50,
    diis_depth=6,
    diis_threshold=1e-5,
    equation_threshold=1e-5,
    print_norm_during_optimization=False,
)

qpu = LinAlg()

stack = PQE_plugin | PQEOptimization | qpu

result_PQE = stack.submit(job)
print("E0 = ", result_PQE.value, ", err: ", abs(result_PQE.value - info["FCI"]))
E0 =  -1.1371170673128344 , err:  3.289724048727294e-11