Skip to content

Exponentiation and Hamiltonian Simulation

View on GitHub Experiment in the IDE

This tutorial demonstrates how to use the Classiq platform exponentiation function to solve Hamiltonian simulation problems, thereby demonstrating the strength of the Classiq exponentiation module.

1. Chemical Simulation

Chemical simulation is one of the most exciting applications for quantum computers. When precise simulations of electron-electron interactions are necessary, it is sometimes possible to use a classical computer, but classical computers struggle to simulate more complex molecular interactions. It is best to simulate these particle interactions at the quantum level, and an excellent way to do this is with a quantum computer.

The ability to accurately simulate molecular interactions will have extensive applications. When used for drug discovery, it will allow for the rapid development of vaccines and new cures for diseases. In materials research, we can hope to discover materials with higher strength-to-weight ratios and environmentally friendly building materials.

2. The H2O Hamiltonian Simulation Problem

Generate a circuit that approximates the unitary \(e^{-iH}\) where \(H\) is the qubit Hamiltonian of a H2O (water) molecule. The H2O Hamiltonian is composed of 551 Pauli strings on twelve qubits.

from typing import cast

from classiq import Pauli, PauliTerm
from classiq.applications.chemistry import Molecule, MoleculeProblem

CHAR_TO_STUCT_DICT = {"I": Pauli.I, "X": Pauli.X, "Y": Pauli.Y, "Z": Pauli.Z}


def pauli_str_to_enums(pauli):
    return [CHAR_TO_STUCT_DICT[s] for s in pauli]


def pauli_list_to_hamiltonian(pauli_list):
    return [
        PauliTerm(
            pauli=pauli_str_to_enums(pauli), coefficient=cast(complex, coeff).real
        )
        for pauli, coeff in pauli_list
    ]


molecule_H2O = Molecule(
    atoms=[("O", (0.0, 0.0, 0.0)), ("H", (0, 0.586, 0.757)), ("H", (0, 0.586, -0.757))]
)

gs_problem = MoleculeProblem(
    molecule=molecule_H2O,
    basis="sto3g",
    mapping="jordan_wigner",
    z2_symmetries=False,
    freeze_core=True,
)

hamiltonian = pauli_list_to_hamiltonian(gs_problem.generate_hamiltonian().pauli_list)
from classiq import (
    CustomHardwareSettings,
    Preferences,
    QArray,
    QuantumProgram,
    allocate,
    create_model,
    qfunc,
    set_preferences,
    show,
    suzuki_trotter,
    synthesize,
    write_qmod,
)


@qfunc
def main() -> None:
    state = QArray("state")
    allocate(len(hamiltonian[0].pauli), state)
    suzuki_trotter(
        hamiltonian,
        evolution_coefficient=1,
        order=1,
        repetitions=1,
        qbv=state,
    )


qmod = create_model(main)
qmod = set_preferences(
    qmod,
    preferences=Preferences(
        custom_hardware_settings=CustomHardwareSettings(basis_gates=["cx", "u"])
    ),
)
write_qmod(qmod, "exponentiation")

qprog = synthesize(qmod)
circuit = QuantumProgram.from_qprog(qprog)

print(f"Classiq's exponentiation depth is {circuit.transpiled_circuit.depth}")
print(
    f"Classiq's exponentiation CX-count is {circuit.transpiled_circuit.count_ops['cx']}"
)
show(qprog)
Classiq's exponentiation depth is 2307
Classiq's exponentiation CX-count is 2598
Opening: https://platform.classiq.io/circuit/246676e4-7b83-4354-b62e-75a981e26cd4?version=0.41.0.dev39%2B79c8fd0855

These impressive results can be compared to the naive exponentiation modules often found in the literature, see comprehensive comparison in the Hamiltonian Evolution notebook under Technology Demonstrations section.

3. Automatic Error Reduction

The Classiq exponentiation module provides error management, automatically minimizes the error, and determines the best Trotter-Suzuki order and repetitions for any provided depth. Try this with an arbitrarily input Pauli list on eight qubits.

from classiq import exponentiation_with_depth_constraint

pauli_list = [
    ("IIZXXXII", 0.1),
    ("IIXXYYII", 0.2),
    ("IIIIZZYX", 0.3),
    ("XZIIIIIX", 0.4),
    ("IIIIIZXI", 0.5),
    ("IIIIIIZY", 0.6),
    ("IIIIIIXY", 0.7),
    ("IIYXYZII", 0.8),
    ("IIIIIIXZ", 0.9),
    ("IIYZYIII", 1.0),
]


@qfunc
def main() -> None:
    state = QArray("state")
    allocate(len(pauli_list[0][0]), state)
    exponentiation_with_depth_constraint(
        pauli_list_to_hamiltonian(pauli_list),
        evolution_coefficient=0.05,
        max_depth=400,
        qbv=state,
    )


qmod = create_model(main)


write_qmod(qmod, "exponentiation_minimize_error")

qprog = synthesize(qmod)
show(qprog)
Opening: https://platform.classiq.io/circuit/1670a54e-03cb-4726-87c9-5b86c793f505?version=0.41.0.dev39%2B79c8fd0855

The Classiq engine automatically opts for six second-order Suzuki-Trotter layers instead of 12 first-order layers, to minimize the error of the exponentiation within the depth constraints.

4. Conclusion

Classiq packages the domain expertise of dozens of scientists and quantum software engineers into the software platform. The result: a system that can automatically generate efficient quantum circuits for complex problems, making it faster and easier than ever to solve real-life problems with quantum computing. When the circuits are of manageable size, Classiq creates solutions that are on par with the best manually created circuits. When the circuits are larger than those a human can reasonably create, Classiq allows you to progress farther because of its powerful capabilities.