# Chemistry¶

Classiq chemistry package allows the user to study quantum chemistry problems by defining a desired molecule and using quantum algorithms to solve corresponding problems.

## Introduction and Background¶

Calculating the energies of a molecular Hamiltonian, especially the ground state, allows us to understand the chemical properties of the molecule. Since the molecular Hamiltonian is inherently quantum, quantum computing can be used to calculate such properties efficiently by leveraging the same quantum effects in appropriate quantum algorithms. This is done in four steps:

1. Defining the molecule
2. Calculating the molecular Hamiltonian for the desired molecule.
3. Generating an appropriate variational quantum circuit (ansatz) to calculate the Hamiltonian's ground state.
4. Execute the desired quantum circuit as part of a hybrid quantum-classical algorithm.

The process is described visually in the following diagram.

flowchart LR
classDef default fill:#FFFFFF,stroke:#000000,stroke-width:1px;

A(Molecule Definition) --> B(Generate Hamiltonian);
B --> C(Ansatz Definition);
C --> D(Optimization);

## Generating a Molecular Hamiltonian¶

Given a molecule, we would like to know the full Hamiltonian describing the interactions between all electrons and nuclei. The following is an example of calculating the Hamiltonian of the Hydrogen molecule:

{
"ground_state_problem": {
"molecule": {
"atoms": [["H", [0, 0, 0]], ["H", [0, 0, 0.735]]]
},
"basis": "sto3g",
"mapping": "jordan_wigner"
}
}

from classiq.interface.chemistry.molecule import Molecule
from classiq.interface.chemistry.ground_state_problem import 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()


In the example above, a Hydrogen molecule is defined by specifying its two Hydrogen atoms and their position in 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 an qubits Hamiltonian. 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): preform Z2 symmetries reduction [1]

Finally, the Hamiltonian is generated from the MoleculeProblem.

Generating the Hamiltonian using the textual interface is done by opening the Command Palette (Ctrl+Shift+P / Command+Shift+P on Windows/Mac, respectively) and choosing the "Generate Hamiltonian for a Molecule" command.

## Generating a Variational Quantum Circuit¶

The ground state of a Hamiltonian is found by 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. For a list of build-in ansatze see the Ansatze section.

### Example - Unitary Coupled Cluster Ansatz¶

In this example we show the generation of the commonly used chemistry-inspired UCC ansatz, which is a unitary version of the classical coupled cluster (CC) method [2] . First the circuit is initialized to the Hartree-Fock state, then the UCC function is applied. More details on the UCC ansatz can be found in UCC.

  {
"ground_state_problem": {
"molecule": {
"atoms": [["H", [0, 0, 0]], ["H", [0, 0, 0.735]]]
},
"basis": "sto3g",
"mapping": "jordan_wigner"
},
"model": {
"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"
}
]
}
}


Synthesizing the ansatz circuit using the textual interface is done by opening the Command Palette (Ctrl+Shift+P / Command+Shift+P on Windows/Mac, respectively) and choosing the "Generate Ansatz" command.

from classiq import ModelDesigner
from classiq.builtin_functions import HartreeFock, UCC
from classiq.interface.chemistry.molecule import Molecule
from classiq.interface.chemistry.ground_state_problem import 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",
)

model_designer = ModelDesigner()

hf_params = HartreeFock(gs_problem=gs_problem)
output_dict = model_designer.HartreeFock(hf_params)
hf_output = output_dict["OUT"]

ucc_params = UCC(gs_problem=gs_problem, max_depth=100)

model_designer.UCC(ucc_params, in_wires={"IN": hf_output})
generation_result = model_designer.synthesize()


The output Circuit is:

## Executing a Ground State Problem¶

Once we've specified a molecular Hamiltonian, and a desired Ansatz to be used in our algorithm as well, we can combine everything and execute the VQE algorithm to find the Hamiltonian's ground state.

{
"ground_state_problem": {
"molecule": {
"atoms": [["H", [0, 0, 0]], ["H", [0, 0, 0.735]]]
},
"basis": "sto3g",
"mapping": "jordan_wigner"
},
"model": {
"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"
}
]
},
"execution_preferences": {
"optimizer_preferences": {
"max_iteration": 30
},
"backend_preferences": {
"backend_service_provider": "IBM Quantum",
"backend_name": "aer_simulator"
},
"num_shots": 1000
}
}


Executing the ground state problem using the textual interface is done by opening the Command Palette (Ctrl+Shift+P / Command+Shift+P on Windows/Mac, respectively) and choosing the "Execute Ground State Problem" command.

from classiq import ModelDesigner
from classiq.builtin_functions import UCC, HartreeFock

from classiq.interface.chemistry.molecule import Molecule
from classiq.interface.chemistry.ground_state_problem import MoleculeProblem
from classiq.interface.chemistry.ground_state_solver import GroundStateSolver
from classiq.interface.backend.backend_preferences import IBMBackendPreferences
from classiq.interface.executor.optimizer_preferences import GroundStateOptimizer

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()

model_designer = ModelDesigner()

hf_params = HartreeFock(gs_problem=gs_problem)
output_dict = model_designer.HartreeFock(hf_params)
hf_output = output_dict["OUT"]

ucc_params = UCC(gs_problem=gs_problem, max_depth=100)

model_designer.UCC(ucc_params, in_wires={"IN": hf_output})
circuit = model_designer.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()


The resulting convergence graph is

The VQE result can be compared 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 more details on the result object see GroundStateResult

[1] Bravyi, Sergey, Jay M. Gambetta, Antonio Mezzacapo, and Kristan Temme. Tapering off qubits to simulate fermionic Hamiltonians. arXiv preprint arXiv:1701.08213 (2017).

[2] Panagiotis Kl. 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)