Variational Quantum Eigensolver¶
The Variational Quantum Eigensolver (VQE) is a well-known algorithm for its applications in the chemistry field.
Background¶
Calculating the energies of a molecular Hamiltonian, especially the ground state, allows insights into the chemical properties of the molecule. Since the molecular Hamiltonian is inherently quantum, quantum computing calculates such properties efficiently by leveraging the same quantum effects in appropriate quantum algorithms.
Steps:
- Define the molecule and calculate its Hamiltonian operator.
- Generate an appropriate variational quantum circuit (the ansatz) to calculate the Hamiltonian ground state.
- Optimize the parameters in the ansatz using the hybrid quantum-classical algorithm to find the Hamiltonian (or molecule) ground state.
The process is described visually in the diagram:
flowchart LR
classDef default fill:#FFFFFF,stroke:#000000,stroke-width:1px;
A(Define Molecule and\nGenerate Hamiltonian) --> B(Define an\nAnsatz);
B --> C(Optimize its\nparameters);
Defining a Molecule and Calculating Its Hamiltonian¶
Given a molecule, what is the full Hamiltonian describing the interactions between all electrons and nuclei?
Following is an example of calculating the Hamiltonian of the hydrogen molecule.
Check you are in the chemistry application suite in the synthesis page
.
Enter the following model in the ground state problem editor:
{
"molecule": {
"atoms": [["H", [0, 0, 0]], ["H", [0, 0, 0.735]]]
},
"basis": "sto3g",
"mapping": "jordan_wigner",
"num_qubits": 4
}
{
"molecule": {
"atoms": [["H", [0, 0, 0]], ["H", [0, 0, 0.735]]]
},
"basis": "sto3g",
"mapping": "jordan_wigner"
"num_qubits": 4
}
from classiq.applications.chemistry import Molecule, MoleculeProblem
molecule = Molecule(
atoms=[
("H", (0.0, 0.0, 0.0)),
("H", (0.0, 0.0, 0.735)),
],
)
gs_problem = MoleculeProblem(
molecule=molecule,
basis="sto3g",
mapping="jordan_wigner",
)
hamiltonian = gs_problem.generate_hamiltonian()
gs_problem = gs_problem.update_problem(hamiltonian.num_qubits)
The example above defines a hydrogen molecule by specifying its two hydrogen atoms and their position in a 3D space. The molecule is then used to create a MoleculeProblem, together with the following optional parameters:
basis: str
– The basis set to be used. For supported types, see PySCF.mapping: str
– The mapping between the fermionic Hamiltonian and a Pauli string Hamiltonian that can be applied on the qubits. Supported types:"jordan_wigner"
"parity"
"bravyi_kitaev"
"fast_bravyi_kitaev"
freeze_core: bool
– Remove the "core" orbitals of the atoms defining the molecule.two_qubit_reduction: bool
– Perform two qubit reduction if possible.z2_symmetries: bool
– Perform Z2 symmetries reduction [1] .
Finally, the Hamiltonian is generated from the MoleculeProblem.
Generating a Variational Quantum Circuit¶
The ground state of a Hamiltonian is found using an appropriate variational quantum circuit (usually called an ansatz), which is combined with a classical optimizer to find the minimal expectation value for the Hamiltonian. See the list of built-in ansatzes.
Note that the chemical ansatz functions UCC and HVA need to know
the num_qubits
attribute of the chemical problem in advance.
Therefore, you can provide the num_qubits directly to the MoleculeProblem
or HamiltonianProblem
class using the generate_hamiltonian
or
update_problem
methods.
Unitary Coupled Cluster Ansatz Example¶
This example shows the generation of the commonly used, chemistry-inspired UCC ansatz, which is a unitary version of the classical coupled cluster (CC) method [2] . First, initialize the circuit to the Hartree-Fock state, then apply the UCC function. See details of the UCC ansatz in UCC.
After generating a Hamiltonian as described above, add the circuit in the Model Editor.
{
"logic_flow": [
{
"function": "HartreeFock",
"function_params": {
"gs_problem": "ground_state_problem"
},
"outputs": "hf_out"
},
{
"function": "UCC",
"function_params": {
"gs_problem": "ground_state_problem",
"max_depth": 100
},
"inputs": "hf_out"
}
]
}
Now, click the Synthesis or the Solve button:
Synthesis
takes you to the Visualization tab.Solve
takes you directly to the Execution tab to solve the ground state problem.
{
"logic_flow": [
{
"function": "HartreeFock",
"function_params": {
"gs_problem": "ground_state_problem"
},
"outputs": "hf_out"
},
{
"function": "UCC",
"function_params": {
"gs_problem": "ground_state_problem",
"max_depth": 100
},
"inputs": "hf_out"
}
]
}
from classiq import Model
from classiq.builtin_functions import HartreeFock, UCC
from classiq.applications.chemistry import Molecule, MoleculeProblem
molecule = Molecule(
atoms=[("H", (0.0, 0.0, 0.0)), ("H", (0.0, 0.0, 0.735))],
)
gs_problem = MoleculeProblem(
molecule=molecule,
mapping="jordan_wigner",
)
gs_problem = gs_problem.update_problem()
model = Model()
hf_params = HartreeFock(gs_problem=gs_problem)
output_dict = model.HartreeFock(hf_params)
hf_output = output_dict["OUT"]
ucc_params = UCC(gs_problem=gs_problem, max_depth=100)
model.UCC(ucc_params, in_wires={"IN": hf_output})
generation_result = model.synthesize()
generation_result.show()
This is the output circuit.
.
Optimizing to Find the Hamiltonian Ground State¶
After you specify a molecular Hamiltonian and an ansatz to use in the algorithm, combine everything and execute the VQE algorithm to find the Hamiltonian ground state.
Ensure you are in the circuit's Execution tab. (If you have clicked Solve after Modeling the Circuit, you should already be in the Execution tab. Otherwise, go to the Execution tab in the IDE.)
Check the Execute for Hamiltonian
box.
(If the checkbox is missing, see the Troubleshooting section below.)
Specify the Optimizer Preferences.
(These are the preferences for the Classical Optimizer in VQE.)
Click the Run
button in the same way that you execute other circuits throughout the platform.
In this case, the Classiq engine executes the hybrid algorithm, optimizing the parameters in the ansatz
to find the minimum of the objective function \(\left\langle \psi(\theta) \middle| H \middle| \psi(\theta) \right\rangle\).
This process attempts to find the molecule's ground state.
from classiq import Model
from classiq.builtin_functions import UCC, HartreeFock
from classiq.applications.chemistry import (
Molecule,
MoleculeProblem,
GroundStateSolver,
GroundStateOptimizer,
)
from classiq.execution import IBMBackendPreferences
molecule = Molecule(
atoms=[
("H", (0.0, 0.0, 0.0)),
("H", (0.0, 0.0, 0.735)),
],
)
gs_problem = MoleculeProblem(
molecule=molecule,
mapping="jordan_wigner",
)
hamiltonian = gs_problem.generate_hamiltonian()
gs_problem = gs_problem.update_problem(hamiltonian.num_qubits)
model = Model()
hf_params = HartreeFock(gs_problem=gs_problem)
output_dict = model.HartreeFock(hf_params)
hf_output = output_dict["OUT"]
ucc_params = UCC(gs_problem=gs_problem, max_depth=100)
model.UCC(ucc_params, in_wires={"IN": hf_output})
circuit = model.synthesize()
optimizer_preferences = GroundStateOptimizer(
max_iteration=30,
num_shots=1000,
)
backend_preferences = IBMBackendPreferences(
backend_service_provider="IBM Quantum", backend_name="aer_simulator"
)
gs_solver = GroundStateSolver(
ground_state_problem=gs_problem,
ansatz=circuit,
optimizer_preferences=optimizer_preferences,
backend_preferences=backend_preferences,
)
result = gs_solver.solve()
result.show_convergence_graph()
exact_result = gs_solver.solve_exact()
GroundStateSolver
function wraps everything together.
gs_solver.solve()
executes the hybrid algorithm, optimizing the parameters in the ansatz
to find the minimum of the objective function \(\left\langle \psi(\theta) \middle| H \middle| \psi(\theta) \right\rangle\).
This process attempts to find the molecule's ground state.
This is the resulting convergence graph.
Compare the VQE result to the exact result for small molecules obtained by the solve_exact
method.
The solve
method of the GroundStateSolver
class returns a GroundStateResult
object.
For details of the resulting object, see GroundStateResult.
Additional Examples¶
See further ansatz examples: hardware efficient ansatz, Hamiltonian variational ansatz, and user-defined ansatz.
Troubleshooting the IDE¶
- If the "Execute for Hamiltonian" checkbox is missing:
- The checkbox only appears when there is a Hamiltonian available for the circuit. It might be missing if:
- You clicked the
Synthesize
button before theGenerate Hamiltonian
button. - You used the SDK to generate the circuit, but the IDE to execute it. Classiq does not support Hamiltonians generated in the SDK.
- You clicked the
- The checkbox only appears when there is a Hamiltonian available for the circuit. It might be missing if:
References¶
[1] Bravyi, Sergey, Jay M. Gambetta, Antonio Mezzacapo, and Kristan Temme, Tapering off qubits to simulate fermionic Hamiltonians (2017).
[2] Panagiotis K. Barkoutsos, Jerome F. Gonthier, Igor Sokolov, Nikolaj Moll, Gian Salis, Andreas Fuhrer, Marc Ganzhorn, Daniel J. Egger, Matthias Troyer, Antonio Mezzacapo, Stefan Filipp, and Ivano Tavernelli, Quantum algorithms for electronic structure calculations: Particle-hole Hamiltonian and optimized wave-function expansions Phys. Rev. A 98, 022322 (2018).