diff --git a/applications/chemistry/classiq_chemistry_application/classiq_chemistry_application.ipynb b/applications/chemistry/classiq_chemistry_application/classiq_chemistry_application.ipynb new file mode 100644 index 000000000..6ace7ed06 --- /dev/null +++ b/applications/chemistry/classiq_chemistry_application/classiq_chemistry_application.ipynb @@ -0,0 +1,1207 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "cbad17b4-2daa-4901-8a4b-1a4e22d53ed2", + "metadata": {}, + "source": [ + "# Classiq Chemistry Application" + ] + }, + { + "cell_type": "markdown", + "id": "890b4f90-df8f-4bf3-9616-d58493b37f39", + "metadata": {}, + "source": [ + "This tutorial presents the functionality of Classiq's Chemistry application module. The application is based on the OpenFermion package [[1](#OF)], which is a comprehensive library for defining and analyzing Fermionic systems, in particular quantum chemistry problems. It provides efficient tools for transforming Fermionic operators to Pauli operators, which are then can be used with Qmod to define quantum algorithms (for more details see their [OpenFermion intro tutorial](https://quantumai.google/openfermion/tutorials/intro_to_openfermion) [[2](#OFintro)]).\n", + "\n", + "The different classes and functions of Classiq's chemistry application is demonstrated below by implementing a Variational Quantum Eigensolver (VQE). A collection of concrete and concise VQE and QPE examples for chemistry can be found in the [chemistry application directory](https://github.com/Classiq/classiq-library/tree/main/applications/chemistry)." + ] + }, + { + "cell_type": "markdown", + "id": "e5cb14f1-004e-448b-9b06-ac42f03121fa", + "metadata": {}, + "source": [ + "***\n", + "## The `FermionHamiltonianProblem` class: Defining an Electronic structure problem.\n", + "\n", + "There are two ways of defining an electronic structure problem, either providing `MolecularData` of a molecule, or by directly defining a Fermionic Hamiltonian together with the number of spin up/down ($\\alpha/\\beta$) particles. Below we demonstrate the former, which is a more practical usecase. For the direct definition see [this](https://github.com/Classiq/classiq-library/blob/main/applications/chemistry/second_quantized_hamiltonian/second_quantized_hamiltonian.ipynb) example.\n", + "***" + ] + }, + { + "cell_type": "markdown", + "id": "9c71d9a3-e01b-4b21-9130-06b475ee458d", + "metadata": {}, + "source": [ + "### Defining a molecule\n", + "\n", + "We start with defining a molecule, specifying its geometry (elements and their 3D position), multiplicity ($2\\cdot(\\text{total spin})+1$), basis, and an optional string for its description. In this tutorial we focus on the LiH molecule. There are several ways to get geometry of molecules, typical way involves using the *SMILES* (Simplified Molecular Input Line Entry System) of a molecule and use a chemical package such as `RDkit` to extract the geometry as an `xyz` file (a code example is given in the Appendix A of this notebook). For simplicity, we store the geometry in advance in the `lih.xyz` file and load it.\n", + "\n", + "*Comment: For complex molecules it is possible to call directly `from openfermion.chem import geometry_from_pubchem`*" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "fba9a0e8-06cd-4d63-ab07-d13bf3999c03", + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-10T09:34:03.903578Z", + "start_time": "2025-04-10T09:34:02.388423Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('Li', (0.833472, 0.0, 0.0)), ('H', (-0.833472, 0.0, 0.0))]\n" + ] + } + ], + "source": [ + "import pathlib\n", + "\n", + "from openfermion.chem import MolecularData\n", + "\n", + "path = (\n", + " pathlib.Path(__file__).parent.resolve()\n", + " if \"__file__\" in locals()\n", + " else pathlib.Path(\".\")\n", + ")\n", + "geometry_file = path / \"lih.xyz\"\n", + "\n", + "# Set up molecule parameters\n", + "basis = \"sto-3g\" # Basis set\n", + "multiplicity = 1 # Singlet state S=0\n", + "charge = 0 # Neutral molecule\n", + "\n", + "# geometry\n", + "with open(geometry_file, \"r\") as f:\n", + " lines = f.readlines()\n", + " atom_lines = lines[2:] # skip atom count and comment\n", + " geometry = []\n", + " for line in atom_lines:\n", + " parts = line.strip().split()\n", + " symbol = parts[0]\n", + " coords = tuple(float(x) for x in parts[1:4])\n", + " geometry.append((symbol, coords))\n", + "\n", + "print(geometry)\n", + "description = \"LiH\"\n", + "\n", + "# Create MolecularData object\n", + "molecule = MolecularData(geometry, basis, multiplicity, charge, description)" + ] + }, + { + "cell_type": "markdown", + "id": "f3ca6546-9450-46ef-95a3-b4e26f2637e6", + "metadata": {}, + "source": [ + "Next, we run a pyscf plugin for calculating various objects for our molecule problem, such as the second quantized Hamiltonian that is at the core of the VQE algorithm. For small problems, we can also get the Full Configuration Interaction (FCI), which calculates classically the ground state energy, i.e., for validating our quantum approach.\n", + "\n", + "*Comment: For complex problems running pyscf can take time, it is possible to run it only once, and load the data later on, using the `save` and `load` methods*." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "db06a8be-7e78-4a20-84ec-e63d082ac0ac", + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-10T09:34:04.224339Z", + "start_time": "2025-04-10T09:34:03.904872Z" + } + }, + "outputs": [], + "source": [ + "from openfermionpyscf import run_pyscf\n", + "\n", + "RECALCULATE_MOLECULE = True # can be set to False after initial run\n", + "if RECALCULATE_MOLECULE:\n", + " molecule = run_pyscf(\n", + " molecule,\n", + " run_mp2=True,\n", + " run_cisd=True,\n", + " run_ccsd=True,\n", + " run_fci=True, # relevant for small, classically solvable problems\n", + " )\n", + " molecule.save()\n", + "\n", + "molecule.load()" + ] + }, + { + "cell_type": "markdown", + "id": "23e67540-a623-4356-bbe2-8ae21c439ef9", + "metadata": {}, + "source": [ + "Now we can get several properties of our molecular problem. The electronic structure problem is described as a second quantized Hamiltonian\n", + "$$\n", + "\\Large H = h_0 + \\sum_{p,q=0}^{2N-1} h_{pq}\\, a^\\dagger_p a_q + \\frac{1}{2} \\sum_{p,q,r,s=0}^{2N-1} h_{pqrs} \\, a^\\dagger_p a^\\dagger_q a_r a_s,\n", + "\\tag{1}\n", + "$$\n", + "where $h_0$ is a constant nuclear repulsion energy, and $h_{pq}$ and $h_{pqrs}$ are the well-known one-body and two-body molecular integrals, respectively. The sum is over all spin orbitals, which is twice the number of spatial orbitals $N$, as for each spatial orbital we have a spin up and spin down space (also known, and refer hereafter, as $\\alpha$ and $\\beta$ particles). This, together with the number of free electrons that can occupy those orbitals, define the electronic structure problem." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "5d3506ad-f775-4caf-a78b-76122b82c646", + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-10T09:34:04.225648Z", + "start_time": "2025-04-10T09:34:04.224142Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The electronic structure problems has 12 spin orbitals, and we need to occupy 4 electrons.\n", + "The spatial orbitals energies are: [-2.35046066 -0.27949547 0.07757097 0.16391248 0.16391248 0.52864126]\n" + ] + } + ], + "source": [ + "print(\n", + " f\"The electronic structure problems has {2*molecule.n_orbitals} spin orbitals, and we need to occupy {molecule.n_electrons} electrons.\"\n", + ")\n", + "print(f\"The spatial orbitals energies are: {molecule.orbital_energies}\")" + ] + }, + { + "cell_type": "markdown", + "id": "c66fa058-957d-490a-8e9a-c937ca7e5155", + "metadata": {}, + "source": [ + "### Defining a reduced problem (active space/freeze core)\n", + "\n", + "In some cases, we can \"freeze\" some of the orbitals, occupying them with both spin up and spin down electrons. This will be orbitals with very low energy, such as the core orbitals, which are expected to be \"classically\" (with both spin up and down) occupied. In addition, we can exclude orbitals with very high energies, as they are unlikely to contribute significantly to the ground state. In other words, we can choose the active space for our molecular problem --- the spatial orbitals that are relevant to the quantum problem. This of-course reduces the problem we need to tackle.\n", + "\n", + "\n", + "Below we define a `FermionHamiltonianProblem` for the LiH molecule, freezing its core ($0^{\\rm th}$) orbital. The updated number of spatial orbitals and electrons are a property of the class." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "a28a9671-ba18-4aec-b742-a6cfddd5365f", + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-10T09:34:04.233554Z", + "start_time": "2025-04-10T09:34:04.227260Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Reduced number of spatial orbitals after freeze core: 5\n", + "Reduced number of (alpha,beta) electrons after freeze core: (1, 1)\n", + "Length of Hamiltonian in Fermionic representation: 811\n" + ] + } + ], + "source": [ + "from classiq.applications.chemistry.problems import FermionHamiltonianProblem\n", + "\n", + "# Define a FermionHamiltonianProblem in an active space\n", + "first_active_index = 1\n", + "problem = FermionHamiltonianProblem.from_molecule(\n", + " molecule=molecule,\n", + " first_active_index=first_active_index, # freeze orbitals below the first index\n", + " remove_orbitlas=[], # remove orbitals\n", + ")\n", + "\n", + "print(f\"Reduced number of spatial orbitals after freeze core: {problem.n_orbitals}\")\n", + "print(\n", + " f\"Reduced number of (alpha,beta) electrons after freeze core: {problem.n_particles}\"\n", + ")\n", + "\n", + "print(\n", + " f\"Length of Hamiltonian in Fermionic representation: {len(problem.fermion_hamiltonian.terms)}\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "c4c30b3e-27f4-4f9b-bea0-68f664f3f3fb", + "metadata": {}, + "source": [ + "Let us look at several terms of our Fermionic operator:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "ef5c404b-d33f-4d1e-86c7-a64effe820cd", + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-10T09:34:04.240008Z", + "start_time": "2025-04-10T09:34:04.235441Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "((), -6.817329071667983)\n", + "(((0, 1), (0, 0)), -0.7621826148518264)\n", + "(((0, 1), (1, 0)), 0.049739077075891036)\n", + "(((0, 1), (4, 0)), -0.12350856641975391)\n", + "(((5, 1), (5, 0)), -0.7621826148518264)\n", + "(((9, 1), (9, 1), (9, 0), (9, 0)), 0.22555659839798667)\n", + "(((9, 1), (9, 1), (9, 0), (6, 0)), -0.022199146730809072)\n", + "(((9, 1), (9, 1), (9, 0), (5, 0)), 0.06490533159641326)\n", + "(((9, 1), (9, 1), (8, 0), (8, 0)), 0.00990347751080244)\n", + "(((9, 1), (9, 1), (7, 0), (7, 0)), 0.00990347751080244)\n" + ] + } + ], + "source": [ + "print(*list(problem.fermion_hamiltonian.terms.items())[:5], sep=\"\\n\")\n", + "print(*list(problem.fermion_hamiltonian.terms.items())[::-1][:5], sep=\"\\n\")" + ] + }, + { + "cell_type": "markdown", + "id": "2a49ea33-8cee-466d-a5f0-1a13bfe245f3", + "metadata": {}, + "source": [ + "We can see one-body terms $((i,1),(j,0))$ that refer to $a_i^{\\dagger}a_j$, and two-body terms $((i,1),(j,1),(k,0),(l,0))$ that corresponds to $a_i^{\\dagger}a_j^{\\dagger}a_ka_l$." + ] + }, + { + "cell_type": "markdown", + "id": "cf7ada21-0ccb-48d7-9414-1529b23cee9c", + "metadata": {}, + "source": [ + "
\n", + " Orbital labeling: For $N$ spatial orbitals we have $N_\\alpha (\\text{spin up})+N_\\beta (\\text{spin down})=2N$ electron orbitals. The Classiq object for the electronic structure problem is defined according to block spin labeling $(0_\\uparrow, 1_\\uparrow, \\dots, (N-1)_\\uparrow, 0_\\downarrow,1_\\downarrow\\dots, (N-1)_\\downarrow$). This is opposed to the OpenFermion conventions, that has alternating spin labeling $(0_\\uparrow, 0_\\downarrow, 1_\\uparrow, 1_\\downarrow,\\dots, (N-1)_\\uparrow, (N-1)_\\downarrow$). When transforming the problem to a Qubit Hamiltonian, described by Pauli strings, different labeling conventions can result in different Hamiltonians, which in turn, might lead to different quantum circuits in terms of depth or cx-counts.\n", + "
\n" + ] + }, + { + "cell_type": "markdown", + "id": "4acfdde7-d608-41ce-821e-f05c6a00d8ba", + "metadata": {}, + "source": [ + "***\n", + "## The `FermionToQubitMapper` class: From Fock space to Qubit space\n", + "***\n", + "\n", + "" + ] + }, + { + "cell_type": "markdown", + "id": "4fdebf94-ff6b-40cb-9baf-912cc7f1d685", + "metadata": {}, + "source": [ + "### Transforming to Qubit Hamiltonian (Pauli strings)\n", + "\n", + "Typically, when dealing with Fock space operators we need to transform the creation/annihilation operators to Pauli operators, suitable for quantum algorithms. There are several known transforms, such as Jordan Wigner (JW) and Bravyi Kitaev (BK) transforms." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "ad5347f8-ef2c-45f0-9cd6-b2a5bafa3d7c", + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-10T09:34:04.300403Z", + "start_time": "2025-04-10T09:34:04.278868Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Length of Hamiltonian in Pauli representation: 276\n", + "Example of Pauli Hamiltonian terms:\n", + "((), -5.750184614764152)\n", + "(((0, 'Z'),), -0.29670485079927406)\n", + "(((0, 'Y'), (1, 'Y')), -0.0025472629069889555)\n", + "(((0, 'X'), (1, 'X')), -0.0025472629069889555)\n", + "(((0, 'Y'), (1, 'Z'), (2, 'Z'), (3, 'Z'), (4, 'Y')), -0.01778020141438094)\n" + ] + } + ], + "source": [ + "from classiq.applications.chemistry.mapping import FermionToQubitMapper, MappingMethod\n", + "\n", + "mapper = FermionToQubitMapper(method=MappingMethod.JORDAN_WIGNER)\n", + "\n", + "qubit_hamiltonian = mapper.map(problem.fermion_hamiltonian)\n", + "qubit_hamiltonian.compress(abs_tol=1e-13) # trimming\n", + "\n", + "print(f\"Length of Hamiltonian in Pauli representation: {len(qubit_hamiltonian.terms)}\")\n", + "print(\"Example of Pauli Hamiltonian terms:\")\n", + "print(*list(qubit_hamiltonian.terms.items())[:5], sep=\"\\n\")" + ] + }, + { + "cell_type": "markdown", + "id": "bc952d5c-5189-40fc-b9ca-7cf888ee281f", + "metadata": {}, + "source": [ + "### Hartree Fock state\n", + "\n", + "Once we have a problem and a mapper in hand, we can construct some quantum primitives. One example is the Hartree Fock state, typically used as an initial condition for ground state solvers. For the Jordan Wigner or the Bravyi Kitaev transforms, the Hartree Fock state, which is an elementary basis state in the Fock space, is mapped into a single computational basis state. This state can be determined using the `get_hf_state` function.\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "aed823eb-5c53-493a-be60-296b51d5cbca", + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-10T09:34:04.300635Z", + "start_time": "2025-04-10T09:34:04.280858Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The HF state: 1000010000\n" + ] + } + ], + "source": [ + "from classiq.applications.chemistry.hartree_fock import get_hf_state\n", + "\n", + "hf_state = get_hf_state(problem, mapper)\n", + "print(f\"The HF state: {''.join(['1' if val else '0' for val in hf_state])}\")" + ] + }, + { + "cell_type": "markdown", + "id": "cfe1c7de-232f-4389-a61a-0a6bb44d5a09", + "metadata": {}, + "source": [ + "
\n", + " HF state under the JW transform: : Working with the JW transform, there is a simple relation between the original Fock (occupation number) and transformed (computational) basis states: the state $|\\underbrace{0\\dots 0}_{k-1}10\\dots 0\\rangle$ corresponds to occupation of the $k$-th spin orbital in both spaces. Therefore, the Hartree Fock state under this transformation is the string $|\\underbrace{1\\dots 1}_{N_{\\alpha}}00\\dots 0\\underbrace{1\\dots 1}_{N_{\\beta}}0\\dots 0\\rangle$. (This is as opposed to the BK transform, that gives a different computational basis state).\n", + "
\n" + ] + }, + { + "cell_type": "markdown", + "id": "5cc2d6cf-462c-4794-980b-e10c1ba11140", + "metadata": {}, + "source": [ + "***\n", + "## The `Z2SymTaperMapper` class: From Fock space to reduced Qubit space by using symmetries \n", + "***\n", + "\n", + "Using symmetries of the second quantized Hamiltonian, one can reduce the number of qubits representing the problem by removing (tapering) qubits.\n", + "The theory of qubit tapering is broad and complex, see for example Refs [[3](#sym1)] and [[4](#sym2)]. The `Z2SymTaperMapper` defines a mapper that includes qubit tapering. It can be initialized by providing $\\mathbb{Z}_2$ symmetries data (set of generators and Pauli $X$ operators) explicitly, or by providing a Fermionic Hamiltonian problem. In the latter case, that is introduced below, the $\\mathbb{Z}_2$ symmetries are deduced from the problem Hamiltonian. This is done via the `from_problem` method.\n", + "\n", + "**In the following section we provide some mathematical explanation of what is happening behind the secens when defining the `Z2SymTaperMapper`. All the logic presented below is incorporated as part of this class. The advanced reader is encouraged to follow this part, while less experienced readers may choose to skip ahead to the *Constructing a VQE* section without loss of continuity.**" + ] + }, + { + "cell_type": "markdown", + "id": "66e96e41-1317-459c-bc1e-7c133a594d01", + "metadata": {}, + "source": [ + "### Reducing the problem size with $\\mathbb{Z}_2$ symmetries (qubit tapering)\n", + "\n", + "The main steps of qubit tapering is as follows (see some technical details in Appendix B at the end of this notebook):\n", + "\n", + "1. Find generators $\\left\\{g^{(i)}\\right\\}^k_{i=1}$ for a group of operators that commute with the Hamiltonian $H$: for all $g\\in \\langle g^{(1)},\\dots g^{(k)}\\rangle$, $\\left[H, g\\right] = 0$. That means that there is a basis in which both $H$ and such $g$ operators are diagonal. These operators are assumed to be a single Pauli string, typically containing only Pauli $Z$ operators.\n", + "2. Find a unitary transformation $U$ that diagonalizes all $g^{(i)}$, such that each generator operates trivially on all qubits except one, e.g., they transform to operators of the form $X_{l}$ for some qubit number $l$. It can be shown that such unitary can be constructed as $\\Pi^k_{i=1}\\frac{1}{\\sqrt{2}}\\left(X_{m^{(i)}}+g^{(i)}\\right)$, where $X_{m^{(i)}}$ is operating on a some single qubit $m^{(i)}$.\n", + "3. Apply the transformation $U^{\\dagger} H U$, whose eigenspace will be identical to those of $U^{\\dagger} g_i U$. That means that on some qubits the transformed Hamiltonian is acting trivially, returning $\\pm 1$ (thus is the name $\\mathbb{Z}_2$ symmetries), and we can taper them off.\n", + "4. Taper off qubits from the transformed Hamiltonian." + ] + }, + { + "cell_type": "markdown", + "id": "09300b29-6ea9-471b-bc45-684c318f3a11", + "metadata": {}, + "source": [ + "Let us define a qubit tapering mapper and inspect its properties:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "280cfb35-f840-4969-a6f8-9afd0342a039", + "metadata": {}, + "outputs": [], + "source": [ + "from classiq.applications.chemistry.z2_symmetries import Z2SymTaperMapper\n", + "\n", + "z2taper_mapper = Z2SymTaperMapper.from_problem(\n", + " problem, method=MappingMethod.JORDAN_WIGNER\n", + ")\n", + "\n", + "generators = z2taper_mapper.generators\n", + "x_ops = z2taper_mapper.x_ops" + ] + }, + { + "cell_type": "markdown", + "id": "78f02229-49ff-4ef6-b638-8d44cdf5a0e4", + "metadata": {}, + "source": [ + "We can verify that the generators are indeed commuting with the Hamiltonian" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "fe33b23f-03d6-4d6d-b9e7-527638c32fc0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of generators: 4\n", + "For generator 1.0 [Z0 Z1 Z2 Z3 Z4]: the Norm of commutator with the Hamiltonian 0.0\n", + "For generator 1.0 [Z2 Z7]: the Norm of commutator with the Hamiltonian 0.0\n", + "For generator 1.0 [Z3 Z8]: the Norm of commutator with the Hamiltonian 0.0\n", + "For generator 1.0 [Z2 Z3 Z5 Z6 Z9]: the Norm of commutator with the Hamiltonian 0.0\n" + ] + } + ], + "source": [ + "from openfermion.utils import commutator\n", + "\n", + "print(f\"Number of generators: {len(generators)}\")\n", + "for gen in generators:\n", + " print(\n", + " f\"For generator {gen}: the Norm of commutator with the Hamiltonian {commutator(qubit_hamiltonian, gen).induced_norm(1)}\"\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "b2b3d8e8-aab7-4c22-9df1-8537f0b98d9d", + "metadata": {}, + "source": [ + "The generators for the symmetry group $\\left\\{g^{(i)}\\right\\}$ are accompained by $\\left\\{X_{m^{(i)}}\\right\\}$ operators, such that $g^{(i)} X_{m^{(j)}}= (-1)^{\\delta_{ij}} X_{m^{(j)}}g^{(i)} $. We can verify this as well:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "521e4e45-634f-4562-9848-0bcf0c911397", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The set of Pauli X operators: [[((0, 'X'),)], [((7, 'X'),)], [((8, 'X'),)], [((5, 'X'),)]]\n", + "=================================================================\n", + "For Pauli X_0 and generator 0: the commutator reads -2j [Y0 Z1 Z2 Z3 Z4]\n", + "For Pauli X_0 and generator 1: the commutator reads 0\n", + "For Pauli X_0 and generator 2: the commutator reads 0\n", + "For Pauli X_0 and generator 3: the commutator reads 0\n", + "For Pauli X_7 and generator 0: the commutator reads 0\n", + "For Pauli X_7 and generator 1: the commutator reads -2j [Z2 Y7]\n", + "For Pauli X_7 and generator 2: the commutator reads 0\n", + "For Pauli X_7 and generator 3: the commutator reads 0\n", + "For Pauli X_8 and generator 0: the commutator reads 0\n", + "For Pauli X_8 and generator 1: the commutator reads 0\n", + "For Pauli X_8 and generator 2: the commutator reads -2j [Z3 Y8]\n", + "For Pauli X_8 and generator 3: the commutator reads 0\n", + "For Pauli X_5 and generator 0: the commutator reads 0\n", + "For Pauli X_5 and generator 1: the commutator reads 0\n", + "For Pauli X_5 and generator 2: the commutator reads 0\n", + "For Pauli X_5 and generator 3: the commutator reads -2j [Z2 Z3 Y5 Z6 Z9]\n" + ] + } + ], + "source": [ + "print(f\"The set of Pauli X operators: {[list(op.terms.keys()) for op in x_ops]}\")\n", + "print(\"=\" * 65)\n", + "for pauli_x in x_ops:\n", + " x_position = list(pauli_x.terms.keys())[0][0][0]\n", + " for j in range(len(generators)):\n", + " print(\n", + " f\"For Pauli X_{x_position} and generator {j}: the commutator reads {commutator(pauli_x, generators[j])}\"\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "ea88b556-0905-4b5e-8237-78299ce3679e", + "metadata": {}, + "source": [ + "
\n", + " Intuition for conserved quantities under the JW transform: In electronic structure problems we have, for example, particle number conservation, spin conservation, and number of particles with fixed spin orientation. The latter corresponds to the two Fermionic operators:\n", + "$$\n", + "\\text{Total number of spin-up/down particles operator:} \\qquad N_{\\uparrow} = \\sum_i a^{\\dagger}_{i\\uparrow} a_{i\\uparrow}, \\qquad \n", + "N_{\\downarrow} = \\sum_i a^{\\dagger}_{i\\downarrow} a_{i\\downarrow}.\n", + "$$\n", + "As explained in the previous info box, working with the JW transform gives that Fock basis state are trasformed to the computational basis states. In particular, there is a relation between the orbital number operator and the $Z$ operators: $n_i \\equiv a_i^{\\dagger}a_i = \\frac{1}{2}\\left(1-Z_i\\right)$. We cannot use the transformation of $N_{\\uparrow(\\downarrow)}$ as our symmetry generators, since they correspond to a sum of Pauli strings rather than a single string. However, we can use any function of those, for example $g_{\\uparrow(\\downarrow)} = e^{\\pi i \\hat{N}_{\\uparrow(\\downarrow)}}$, which, up to a global phase, gives the generators\n", + "$$\n", + "g_{\\uparrow} = \\Pi^{N/2-1}_{k=0}Z_{k}, \\qquad g_{\\downarrow} = \\Pi^{N-1}_{k=N/2}Z_{k}.\n", + "$$\n", + "We can see that $g_{\\uparrow}$ is indeed a generator in the example above.\n", + "
\n" + ] + }, + { + "cell_type": "markdown", + "id": "6b0c4679-f12b-4c4d-8736-c0f7cc73d975", + "metadata": {}, + "source": [ + "Next, we can define a transformation from the generators the the Pauli $X$ operators, which means that it block-diagonalizes the Hamiltonian according to symmetry subspaces. This unitary is given by $U = \\Pi^k_{i=1}\\frac{1}{\\sqrt{2}}\\left(X_{m^{(i)}}+g^{(i)}\\right)$." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "2f925e8a-d5ea-43dc-a63d-4553679b568b", + "metadata": {}, + "outputs": [], + "source": [ + "from openfermion import QubitOperator\n", + "\n", + "blk_diagonalizing_op = QubitOperator(())\n", + "for gen, x_op in zip(generators, x_ops):\n", + " blk_diagonalizing_op *= (2 ** (-0.5)) * (x_op + gen)" + ] + }, + { + "cell_type": "markdown", + "id": "cb38bbeb-9824-44f0-a0a5-9a9a31818930", + "metadata": {}, + "source": [ + "Let us verify, for example, that indeed this diagonalizing operator map each generator into a single computational basis subspace:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "60e07b4c-08b8-4cda-bf58-ae28a2bb104c", + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-10T09:34:04.310884Z", + "start_time": "2025-04-10T09:34:04.305930Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Generator in the new basis: (1.0000000000000002+0j) [X0] --- compared to: 1.0 [X0]\n", + "Generator in the new basis: (1.0000000000000002+0j) [X7] --- compared to: 1.0 [X7]\n", + "Generator in the new basis: (1.0000000000000002+0j) [X8] --- compared to: 1.0 [X8]\n", + "Generator in the new basis: (1.0000000000000002+0j) [X5] --- compared to: 1.0 [X5]\n" + ] + } + ], + "source": [ + "for gen, x_op in zip(generators, x_ops):\n", + " print(\n", + " f\"Generator in the new basis: {blk_diagonalizing_op*gen*blk_diagonalizing_op} --- compared to: {x_op}\"\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "27c1f9d6-04f3-416e-bb4d-70308cc0f378", + "metadata": {}, + "source": [ + "Next, let us examine the block-diagonalized Hamiltonian--- We shall see that after transformation, the Hamiltonian acts trivially on some of the qubits, with the identity or with the $\\left\\{X_{m^{(i)}}\\right\\}$ operators found above. Thus, we can reduce it by going to one of the two eigenspaces of these operators, with eigenvalues $\\pm 1$." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "766c80a2-8da2-4de9-8546-46a1e41626f1", + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-10T09:34:04.408315Z", + "start_time": "2025-04-10T09:34:04.335407Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Example of Pauli Hamiltonian terms:\n", + "((), -5.750184614764152)\n", + "(((0, 'X'), (1, 'Z'), (2, 'Z'), (3, 'Z'), (4, 'Z')), -0.2967048507992741)\n", + "(((1, 'X'), (2, 'Z'), (3, 'Z'), (4, 'Z')), 0.002547262906988957)\n", + "(((0, 'X'), (1, 'X')), -0.002547262906988957)\n", + "(((4, 'X'),), 0.017780201414380945)\n", + "(((0, 'X'), (1, 'Z'), (2, 'Z'), (3, 'Z'), (4, 'X')), -0.017780201414380945)\n", + "(((2, 'Z'), (3, 'Z'), (5, 'X'), (6, 'Z'), (9, 'Z')), -0.2967048507992741)\n", + "(((2, 'Z'), (3, 'Z'), (6, 'X'), (9, 'Z')), 0.002547262906988951)\n", + "(((5, 'X'), (6, 'X')), -0.002547262906988951)\n", + "(((7, 'X'), (8, 'X'), (9, 'X')), 0.017780201414380938)\n", + "(((2, 'Z'), (3, 'Z'), (5, 'X'), (6, 'Z'), (7, 'X'), (8, 'X'), (9, 'X')), -0.017780201414380938)\n", + "(((1, 'Z'),), -0.39063013875079544)\n", + "(((1, 'Y'), (2, 'Z'), (3, 'Z'), (4, 'Y')), 0.024546035949578163)\n", + "(((1, 'X'), (2, 'Z'), (3, 'Z'), (4, 'X')), 0.024546035949578163)\n", + "(((6, 'Z'),), -0.39063013875079533)\n", + "(((2, 'Z'), (3, 'Z'), (6, 'Y'), (7, 'X'), (8, 'X'), (9, 'Y')), 0.024546035949578177)\n" + ] + } + ], + "source": [ + "block_diagonal_hamiltonian = (\n", + " blk_diagonalizing_op * qubit_hamiltonian * blk_diagonalizing_op\n", + ")\n", + "block_diagonal_hamiltonian.compress(1e-12)\n", + "print(\"Example of Pauli Hamiltonian terms:\")\n", + "print(*list(block_diagonal_hamiltonian.terms.items())[:16], sep=\"\\n\")" + ] + }, + { + "cell_type": "markdown", + "id": "0d08cad3-4147-43be-be79-1f0dced4824e", + "metadata": {}, + "source": [ + "We can see that on the 0$^{th}$ qubit we have only $X$ operations, therefore, we know that the eigenstates of our Hamiltonian will be of the form:\n", + "$$\n", + "|\\psi\\rangle_{10} = |\\pm 1\\rangle |\\bar{\\psi}\\rangle_{9}.\n", + "$$\n", + "That is, the first qubit is either at state $|+\\rangle$ or $|-\\rangle$ (the eigenvectors of the Puali $X$ matrix). The same is true for all the other Pauli $X$ operators in `x_ops`. We shall choose a sector, i.e., the $+1$ or $-1$ subspace, for each of the subspaces $X_{(m_i)}$ operations. \n", + "\n", + "Which eigenspace to choose?\n" + ] + }, + { + "cell_type": "markdown", + "id": "6b8c13f9-3c1c-4139-86f0-3cf80a877c5a", + "metadata": {}, + "source": [ + "The answer to this question depends on the problem at hand. If we would like to find the minimal energy of the Hamiltonian, then we shall take the subspace containing the minimal energy. One possibility is to solve multiple ($2^4$) problems on all sectors. However, another approach is to fix the sector according to the HF state, which is assumed to be in the optimal sector with minimal energy. This is the default sector defined in `Z2SymTaperMapper` when initializing with the `.from_problem` method." + ] + }, + { + "cell_type": "markdown", + "id": "bdc28270-9944-472c-81c5-fb1d53f28d5c", + "metadata": {}, + "source": [ + "To emphasize the effect of choosing different sectors, we construct $2^4$ tapered operators, each for the subspaces (sectors) $\\pm 1 \\otimes \\pm \\otimes \\pm 1 \\otimes \\pm 1$, and classically calculate the ground state for each tapered Hamiltonian. " + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "42aef862-3f32-42f8-a107-d0e74974b4b9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "For sector (1, 1, 1, 1): minimal eigenvalue: (-7.768908584655453+0j)\n", + "For sector (1, 1, 1, -1): minimal eigenvalue: (-7.804992414357773+0j)\n", + "For sector (1, 1, -1, 1): minimal eigenvalue: (-7.724554496308053+0j)\n", + "For sector (1, 1, -1, -1): minimal eigenvalue: (-7.717412859272543+0j)\n", + "For sector (1, -1, 1, 1): minimal eigenvalue: (-7.724554496308075+0j)\n", + "For sector (1, -1, 1, -1): minimal eigenvalue: (-7.717412859272538+0j)\n", + "For sector (1, -1, -1, 1): minimal eigenvalue: (-7.312750852207606+0j)\n", + "For sector (1, -1, -1, -1): minimal eigenvalue: (-7.555931078744113+0j)\n", + "For sector (-1, 1, 1, 1): minimal eigenvalue: (-7.8049924143578036+0j)\n", + "For sector (-1, 1, 1, -1): minimal eigenvalue: (-7.880416053961544+0j)\n", + "For sector (-1, 1, -1, 1): minimal eigenvalue: (-7.717412859272534+0j)\n", + "For sector (-1, 1, -1, -1): minimal eigenvalue: (-7.724554496308089+0j)\n", + "For sector (-1, -1, 1, 1): minimal eigenvalue: (-7.717412859272531+0j)\n", + "For sector (-1, -1, 1, -1): minimal eigenvalue: (-7.724554496308072+0j)\n", + "For sector (-1, -1, -1, 1): minimal eigenvalue: (-7.555931078744102+0j)\n", + "For sector (-1, -1, -1, -1): minimal eigenvalue: (-7.3127508522075795+0j)\n" + ] + } + ], + "source": [ + "import itertools\n", + "\n", + "import numpy as np\n", + "from openfermion.linalg import get_sparse_operator\n", + "\n", + "for sector in itertools.product([1, -1], repeat=len(x_ops)):\n", + " z2taper_mapper.set_sector(sector)\n", + " tapered_hamiltonian = z2taper_mapper.map(problem.fermion_hamiltonian)\n", + " tapered_hamiltonian_sparse = get_sparse_operator(tapered_hamiltonian)\n", + " w, v = np.linalg.eig(tapered_hamiltonian_sparse.toarray())\n", + " print(f\"For sector {sector}: minimal eigenvalue: {np.min(w)}\")" + ] + }, + { + "cell_type": "markdown", + "id": "a24bb9f9-a740-4b71-87a2-c98ccf7c651b", + "metadata": {}, + "source": [ + "***\n", + "## Constructing a VQE model with Classiq\n", + "***" + ] + }, + { + "cell_type": "markdown", + "id": "dd8b2a82-6e33-4e34-a52e-09b7d381c069", + "metadata": {}, + "source": [ + "Next, we use all the classical pre-processing and definitions from the previous sections to build, synthesize, and execute a VQE model.\n", + "We will take the following steps:\n", + "1. Defining the transformed and tapered-off Hartree Fock state, which serves as an initial condition for the problem.\n", + "2. Constructing the transformed and tapered-off UCC ansatz.\n", + "3. Defining, synthesizing, and executing the full model" + ] + }, + { + "cell_type": "markdown", + "id": "ce6ec31f-3104-4556-9657-09bb4d19bcf1", + "metadata": {}, + "source": [ + "As a preliminary step, we define the Hamiltonian of the VQE problem. Since this is the final Hamiltonian (after a series of transformation, from second quantized Hamiltonian, tapering, etc.), let us trim small values according to some rough threshold." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "cc06fd7c-0a20-4aab-bb9c-5af616d78e2f", + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-10T09:34:07.457664Z", + "start_time": "2025-04-10T09:34:06.407353Z" + } + }, + "outputs": [], + "source": [ + "from classiq import *\n", + "from classiq.applications.chemistry.op_utils import qubit_op_to_pauli_terms" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "b5fbeafb-a4c3-41ba-b911-a4c4cf86abdd", + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-10T09:34:07.466879Z", + "start_time": "2025-04-10T09:34:07.464817Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hamiltonian for VQE has: 231 terms, and is operating on 6 qubits\n" + ] + } + ], + "source": [ + "THRESHOLD = 1e-3\n", + "\n", + "z2taper_mapper = Z2SymTaperMapper.from_problem(problem)\n", + "\n", + "tapered_hamiltonian = z2taper_mapper.map(problem.fermion_hamiltonian, is_invariant=True)\n", + "tapered_hamiltonian.compress(THRESHOLD)\n", + "\n", + "n_vqe_qubits = z2taper_mapper.get_num_qubits(problem)\n", + "vqe_hamiltonian = qubit_op_to_pauli_terms(tapered_hamiltonian)\n", + "\n", + "print(\n", + " f\"Hamiltonian for VQE has: {len(vqe_hamiltonian.terms)} terms, and is operating on {n_vqe_qubits} qubits\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9d7a6358-4dd6-4d7f-bc05-7e4a5d9982cd", + "metadata": {}, + "source": [ + "Next, we use Classiq built-in functions to get the Hartree Fock state and the UCC ansatz Hamiltonians, given the problem and mapper." + ] + }, + { + "cell_type": "markdown", + "id": "7402641b-4b0b-4893-bdc5-a036f2729cfc", + "metadata": {}, + "source": [ + "
\n", + " Moving to symmetry subspaces: The Hartree Fock and the UCC operators that are defined below do not necessarily have the same symmetries of the molecular Hamiltonian. Thus, after the block-diagonalization, the resulting operators are not restricted to the symmetries' subspaces. We take the following approach: we remove terms which do not satisfy the symmetry relation, i.e., commute with symmetry generators. This is done automatically by calling the corresponding functions.\n", + "
\n" + ] + }, + { + "cell_type": "markdown", + "id": "9a21a5ca-ba62-430d-a974-b329167bca66", + "metadata": {}, + "source": [ + "### 1. Hartree Fock in the tapered-off space" + ] + }, + { + "cell_type": "markdown", + "id": "dc4c9f46-3df7-4bc7-aeb6-475137227388", + "metadata": {}, + "source": [ + "We have already calculated the HF state under the JW transform, let us find the HF state after qubit tapering:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "05127fdd-00c7-4d65-86fb-88d9486dc7d9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The HF state: 000000\n" + ] + } + ], + "source": [ + "hf_tapered_state = get_hf_state(problem, z2taper_mapper)\n", + "print(f\"The HF state: {''.join(['1' if val else '0' for val in hf_tapered_state])}\")" + ] + }, + { + "cell_type": "markdown", + "id": "a18ee148-88c5-43f6-be6d-390e4c4542b0", + "metadata": {}, + "source": [ + "### 2. UCC ansatz" + ] + }, + { + "cell_type": "markdown", + "id": "fdccea00-14a0-4419-8762-c58ad3d2863e", + "metadata": {}, + "source": [ + "The Unitary Coupled Cluster ansatz assumes that the HF state is initially occupied. Then, it includes excitations from the occupied to un-occupied states, where the former is defined by the HF state. In this tutorial we focus on the UCCSD ansatz, in which only singlet and doublet excitation are taken. The corresponding Fermionic operator reads:\n", + "\n", + "$$\n", + "\\large U_{\\text{UCCSD}} \\equiv e^{T - T^\\dagger}, \\qquad T = T_1 + T_2\n", + "$$\n", + "where:\n", + "$$\n", + "\\large T_1 = \\sum_{i \\in \\text{occ}} \\sum_{a \\in \\text{virt}} t_i^a a_a^\\dagger a_i, \\qquad T_2 = \\sum_{i None:\n", + " prepare_basis_state(hf_tapered_state, state)\n", + " multi_suzuki_trotter(\n", + " hamiltonians=uccsd_hamiltonians,\n", + " evolution_coefficients=params,\n", + " order=1,\n", + " repetitions=1,\n", + " qbv=state,\n", + " )\n", + "\n", + "\n", + "write_qmod(main, \"vqe_ucc\" + description, symbolic_only=False)\n", + "qprog = synthesize(main)\n", + "show(qprog)" + ] + }, + { + "cell_type": "markdown", + "id": "37eb1634-f1c3-48b9-86a6-ab906eabedfc", + "metadata": {}, + "source": [ + "To get a quick execution, we run on a statevector simulator." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "d419f218-ecf2-410f-b0f2-458f886fb376", + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-10T09:35:45.515839Z", + "start_time": "2025-04-10T09:34:29.913691Z" + } + }, + "outputs": [], + "source": [ + "qprog = set_quantum_program_execution_preferences(\n", + " qprog,\n", + " preferences=ExecutionPreferences(\n", + " num_shots=1000,\n", + " backend_preferences=ClassiqBackendPreferences(\n", + " backend_name=\"simulator_statevector\"\n", + " ),\n", + " ),\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f8ec528b-62aa-4bce-a05c-099bd18485e0", + "metadata": {}, + "source": [ + "We run simple optimization using the `minimize` method of `ExecutionSession` " + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "6907d29f-5487-49b9-aeee-bb245edcb369", + "metadata": {}, + "outputs": [], + "source": [ + "with ExecutionSession(qprog) as es:\n", + " result = es.minimize(\n", + " cost_function=vqe_hamiltonian,\n", + " initial_params={\"params\": [0] * num_params},\n", + " max_iteration=200,\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "483487d4-f48c-4457-b89e-a374fff282e3", + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-10T09:35:45.612248Z", + "start_time": "2025-04-10T09:35:45.518189Z" + }, + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "optimizer result classiq: -7.880416045210553\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "expected_energy = float(molecule.fci_energy)\n", + "\n", + "optimizer_res = result[-1][0]\n", + "print(f\"optimizer result classiq: {optimizer_res}\")\n", + "\n", + "vqe_results = {k: np.real(result[k][0]) for k in range(len(result))}\n", + "\n", + "\n", + "plt.plot(vqe_results.keys(), vqe_results.values(), \"-\")\n", + "plt.ylabel(\"Energy [Ha]\", fontsize=16)\n", + "plt.xlabel(\"iteration\", fontsize=16)\n", + "plt.tick_params(axis=\"both\", labelsize=16)\n", + "plt.title(\"VQE result for \" + description)\n", + "plt.text(\n", + " 50,\n", + " -7.75,\n", + " f\"vqe energy: {optimizer_res} Ha,\\n fci_energy: {expected_energy} Ha\",\n", + " fontsize=12,\n", + " bbox=dict(facecolor=\"lightgray\", edgecolor=\"black\", boxstyle=\"round,pad=0.3\"),\n", + ");" + ] + }, + { + "cell_type": "markdown", + "id": "60aca7a7-1cc0-40eb-bd18-5516256fac74", + "metadata": {}, + "source": [ + "## Appendix A - Loading molecule geometry" + ] + }, + { + "cell_type": "markdown", + "id": "92afa863-b04a-4db9-9982-eb4adbd57541", + "metadata": {}, + "source": [ + "```\n", + "from rdkit import Chem\n", + "from rdkit.Chem import AllChem\n", + "\n", + "# Generate 3D coordinates\n", + "mol = Chem.MolFromSmiles('[LiH]')\n", + "mol = Chem.AddHs(mol)\n", + "AllChem.EmbedMolecule(mol)\n", + "\n", + "# Prepare XYZ string\n", + "conf = mol.GetConformer()\n", + "n_atoms = mol.GetNumAtoms()\n", + "\n", + "xyz_lines = [f\"{n_atoms}\", \"LiH generated by RDKit\"]\n", + "\n", + "for atom in mol.GetAtoms():\n", + " idx = atom.GetIdx()\n", + " pos = conf.GetAtomPosition(idx)\n", + " line = f\"{atom.GetSymbol()} {pos.x:.6f} {pos.y:.6f} {pos.z:.6f}\"\n", + " xyz_lines.append(line)\n", + "\n", + "xyz_string = \"\\n\".join(xyz_lines)\n", + "\n", + "# Save to file\n", + "with open(\"lih.xyz\", \"w\") as f:\n", + " f.write(xyz_string)\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "4a76a3a4-980d-4197-81ef-231a926bbbad", + "metadata": {}, + "source": [ + "## Appendix B - Techical details on qubit tapering\n", + "\n", + "Below we provide some technical details concerning qubit tapering and $\\mathbb{Z}_2$ symmetries.\n", + "\n", + "It is a well-known fact in linear algebra that if two operators commute, $[A,B]=0$, then they can be mutually diagonalized. In particular, if $|v\\rangle$ is an eigenvector of $B$ with an eigenvalue $\\lambda$, we have\n", + "$$\n", + "[A,B]=0\\implies AB = BA \\implies AB|v\\rangle = BA|v\\rangle \\implies \\lambda \\left(A|v\\rangle\\right) = B\\left(A|v\\rangle\\right).\n", + "$$\n", + "That is, $A|v\\rangle$ is also an eigenvector of $B$ with eigenvalue $\\lambda$. Thus, $A|v\\rangle$ must be in the eigenspace $V_{\\lambda} \\equiv \\left\\{|u\\rangle, B|u\\rangle = \\lambda|u\\rangle\\right\\}$.\n", + "\n", + "Now, Refs. [[3](#sym1)] and [[4](#sym2)] show, and this is implemented explicitly in Appendix B, that we can find a Clifford transformation $U$, such that the transformed Hamiltonian $H'=U^{\\dagger} H U$ commutes with the transformed symmetries $X_{m^{(i)}} = U^{\\dagger} g_i U$. We know how the eigenspaces of $X_{m^{(i)}}$ look like. For example, $X_{0}$ has two eigenspaces that correspond to the eigenvalues $\\pm 1$: $V_{\\pm} = \\left\\{|u\\rangle_N, X_{0}|u\\rangle_N = \\pm |u\\rangle_N\\right\\} = \\left\\{|\\pm\\rangle \\otimes |\\tilde{u}\\rangle_{N-1},\\, |\\tilde{u}\\rangle_{N-1} \\text{ some state on } N-1 \\text{ qubits}\\right\\} $. From the arguments above we get that \n", + "$$\n", + "H'\\cdot \\left(|\\pm\\rangle |u\\rangle\\right) \\in V_{\\pm},\n", + "$$\n", + "which means that $H'$ must acts with $X_0$ or the Identity on the first qubit." + ] + }, + { + "cell_type": "markdown", + "id": "31a03a50-0d15-4bd5-a9ef-e52718b26420", + "metadata": {}, + "source": [ + "## References\n", + "\n", + "[1]: [McClean et. al. Quantum Sci. Technol. 5 034014 (2020). OpenFermion: the electronic structure package for quantum computers.](https://arxiv.org/abs/1710.07629)\n", + "\n", + "[2]: [Introduction to OpenFermion.](https://quantumai.google/openfermion/tutorials/intro_to_openfermion)\n", + "\n", + "[3]: [Bravyi et. al., arXiv preprint arXiv:1701.08213 (2017). Tapering off qubits to simulate fermionic Hamiltonians.\n", + "](https://arxiv.org/abs/1701.08213)\n", + "\n", + "[4]: [Kanav et al. J. Chem. Theo. Comp. 16 10 (2020). Reducing qubit requirements for quantum simulations using molecular point group symmetries.](https://arxiv.org/abs/1910.14644)\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/applications/chemistry/molecule_eigensolver_using_openfermion/lih.xyz b/applications/chemistry/classiq_chemistry_application/lih.xyz similarity index 100% rename from applications/chemistry/molecule_eigensolver_using_openfermion/lih.xyz rename to applications/chemistry/classiq_chemistry_application/lih.xyz diff --git a/applications/chemistry/classiq_chemistry_application/vqe_uccLiH.qmod b/applications/chemistry/classiq_chemistry_application/vqe_uccLiH.qmod new file mode 100644 index 000000000..d1b636050 --- /dev/null +++ b/applications/chemistry/classiq_chemistry_application/vqe_uccLiH.qmod @@ -0,0 +1,475 @@ +qfunc prepare_basis_state_expanded___0(output arr: qbit[6]) { + allocate(6, arr); +} + +qfunc main(params: real[10], output state: qbit[6]) { + prepare_basis_state_expanded___0(state); + multi_suzuki_trotter([ + SparsePauliOp { + terms=[ + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=2, index=5} + ], + coefficient=0.5 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=5} + ], + coefficient=0.5 + } + ], + num_qubits=6 + }, + SparsePauliOp { + terms=[ + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=2, index=1}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=0.5 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=1} + ], + coefficient=0.5 + } + ], + num_qubits=6 + }, + SparsePauliOp { + terms=[ + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=2} + ], + coefficient=0.5 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=0.5 + } + ], + num_qubits=6 + }, + SparsePauliOp { + terms=[ + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=0} + ], + coefficient=0.5 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=0.5 + } + ], + num_qubits=6 + }, + SparsePauliOp { + terms=[ + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=2, index=4} + ], + coefficient=0.125 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=2, index=4} + ], + coefficient=0.125 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=2, index=4}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=0.125 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=2, index=4}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=0.125 + } + ], + num_qubits=6 + }, + SparsePauliOp { + terms=[ + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=2, index=3} + ], + coefficient=-0.125 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=2, index=3}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=-0.125 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=2, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=-0.125 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=2, index=3}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=-0.125 + } + ], + num_qubits=6 + }, + SparsePauliOp { + terms=[ + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=0}, + IndexedPauli {pauli=1, index=2} + ], + coefficient=-0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=0}, + IndexedPauli {pauli=2, index=2} + ], + coefficient=-0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=2, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=-0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=1, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=-0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=0}, + IndexedPauli {pauli=1, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=-0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=0}, + IndexedPauli {pauli=2, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=-0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=2, index=2}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=-0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=1, index=2}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=-0.0625 + } + ], + num_qubits=6 + }, + SparsePauliOp { + terms=[ + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=0}, + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=2, index=5} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=0}, + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=1, index=5} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=2, index=5} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=1, index=5} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=0}, + IndexedPauli {pauli=1, index=5} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=0}, + IndexedPauli {pauli=2, index=5} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=1, index=5} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=2, index=5} + ], + coefficient=0.0625 + } + ], + num_qubits=6 + }, + SparsePauliOp { + terms=[ + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=1, index=1}, + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=2, index=5} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=2, index=1}, + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=1, index=5} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=1}, + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=2, index=5} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=1}, + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=1, index=5} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=2, index=1}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=1, index=5} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=1, index=1}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=2, index=5} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=1}, + IndexedPauli {pauli=1, index=5} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=1}, + IndexedPauli {pauli=2, index=5} + ], + coefficient=0.0625 + } + ], + num_qubits=6 + }, + SparsePauliOp { + terms=[ + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=1, index=1}, + IndexedPauli {pauli=2, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=2, index=1}, + IndexedPauli {pauli=1, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=1}, + IndexedPauli {pauli=2, index=2} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=1}, + IndexedPauli {pauli=1, index=2} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=2, index=1}, + IndexedPauli {pauli=1, index=2}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=1, index=1}, + IndexedPauli {pauli=2, index=2}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=1}, + IndexedPauli {pauli=1, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=0.0625 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=1}, + IndexedPauli {pauli=2, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=0.0625 + } + ], + num_qubits=6 + } + ], params, 1, 1, state); +} diff --git a/applications/chemistry/molecule_eigensolver_using_openfermion/vqe_uccLiH.synthesis_options.json b/applications/chemistry/classiq_chemistry_application/vqe_uccLiH.synthesis_options.json similarity index 93% rename from applications/chemistry/molecule_eigensolver_using_openfermion/vqe_uccLiH.synthesis_options.json rename to applications/chemistry/classiq_chemistry_application/vqe_uccLiH.synthesis_options.json index 0db258ce0..fdf97904c 100644 --- a/applications/chemistry/molecule_eigensolver_using_openfermion/vqe_uccLiH.synthesis_options.json +++ b/applications/chemistry/classiq_chemistry_application/vqe_uccLiH.synthesis_options.json @@ -7,28 +7,28 @@ "machine_precision": 8, "custom_hardware_settings": { "basis_gates": [ - "ry", "cx", - "z", - "rz", - "sdg", + "u1", + "u2", "id", + "cy", + "x", + "t", "sx", - "y", - "u1", - "cz", + "z", + "u", "rx", "p", - "r", - "t", - "u2", + "y", + "rz", "tdg", + "sdg", + "r", "h", - "cy", - "x", - "sxdg", "s", - "u" + "cz", + "sxdg", + "ry" ], "is_symmetric_connectivity": true }, @@ -39,6 +39,6 @@ "pretty_qasm": true, "transpilation_option": "auto optimize", "timeout_seconds": 300, - "random_seed": 1226821849 + "random_seed": 3932903525 } } diff --git a/applications/chemistry/molecular_energy_curve/molecular_energy_curve.ipynb b/applications/chemistry/molecular_energy_curve/molecular_energy_curve.ipynb index 88df595da..859262a46 100644 --- a/applications/chemistry/molecular_energy_curve/molecular_energy_curve.ipynb +++ b/applications/chemistry/molecular_energy_curve/molecular_energy_curve.ipynb @@ -13,51 +13,7 @@ "\n", "A potential energy curve gives the ground energy of an assembly of atoms as a function of the distances between them. The global minima of the curve indicates the binding energy and internuclear distance for the stable molecule. Therefore, such a curve can be powerful tool in computational chemistry for predicting the molecular structure and spectrum.\n", "\n", - "This tutorial demonstrates how to use the Classiq VQE package to create a molecule's potential energy curve. It compares the result with the Hartree-Fock approximation method and the exact results. The exact solution is a result of diagonalizing the Hamiltonian." - ] - }, - { - "cell_type": "markdown", - "id": "099a3eaa-aec8-4088-89cc-b7fb9fcf161c", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "## Prerequisites\n", - "\n", - "This model uses Classiq libraries in addition to IBM's simulating tool." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "02f49a11", - "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:14:17.533288Z", - "iopub.status.busy": "2024-05-07T15:14:17.532350Z", - "iopub.status.idle": "2024-05-07T15:14:20.443573Z", - "shell.execute_reply": "2024-05-07T15:14:20.442890Z" - } - }, - "outputs": [], - "source": [ - "import time\n", - "\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "from classiq import *\n", - "from classiq.applications.chemistry import (\n", - " ChemistryExecutionParameters,\n", - " HEAParameters,\n", - " Molecule,\n", - " MoleculeProblem,\n", - " UCCParameters,\n", - ")\n", - "from classiq.execution import OptimizerType" + "This tutorial demonstrates how to use the Classiq chemistry package to create a molecule's potential energy curve. It compares the result with the Hartree-Fock approximation method and the FCI (Full Configuration Interaction) energy." ] }, { @@ -76,15 +32,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "id": "238c6d3c-2ab7-4033-94c3-917debd90b17", "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:14:20.447086Z", - "iopub.status.busy": "2024-05-07T15:14:20.446361Z", - "iopub.status.idle": "2024-05-07T15:14:20.451781Z", - "shell.execute_reply": "2024-05-07T15:14:20.451128Z" - }, "pycharm": { "name": "#%%\n" } @@ -99,6 +49,8 @@ } ], "source": [ + "import numpy as np\n", + "\n", "# define the sampling params\n", "num1 = 5 # how many sampling points - determines your resolution\n", "start1 = 0.20 # what is your sampling start distance\n", @@ -137,31 +89,40 @@ "5. Obtaining the exact solution and Hartree-Fock solution." ] }, + { + "cell_type": "code", + "execution_count": 2, + "id": "4979cda7-ff3c-4f1b-bd72-000aabc84a2b", + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "\n", + "from classiq import *" + ] + }, { "cell_type": "code", "execution_count": 3, "id": "b25f416a", - "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:14:20.454446Z", - "iopub.status.busy": "2024-05-07T15:14:20.454046Z", - "iopub.status.idle": "2024-05-07T15:16:31.137135Z", - "shell.execute_reply": "2024-05-07T15:16:31.135771Z" - } - }, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "11.811192989349365\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "10.764894247055054\n" + "5.403509855270386\n", + "3.093651056289673\n", + "3.4077019691467285\n", + "3.023664712905884\n", + "3.3719558715820312\n", + "3.364731788635254\n", + "3.5703423023223877\n", + "3.436528205871582\n", + "3.3499598503112793\n", + "3.333562135696411\n", + "3.357571840286255\n", + "3.066948175430298\n" ] }, { @@ -236,8 +197,16 @@ } ], "source": [ - "# create the molecule, insert the distance, prepare H, create UCC anzats and solve in energy\n", + "from openfermion.chem import MolecularData\n", + "from openfermionpyscf import run_pyscf\n", "\n", + "from classiq.applications.chemistry.hartree_fock import get_hf_state\n", + "from classiq.applications.chemistry.op_utils import qubit_op_to_pauli_terms\n", + "from classiq.applications.chemistry.problems import FermionHamiltonianProblem\n", + "from classiq.applications.chemistry.ucc import get_ucc_hamiltonians\n", + "from classiq.applications.chemistry.z2_symmetries import Z2SymTaperMapper\n", + "\n", + "# create the molecule, insert the distance, prepare H, create UCC anzats and solve in energy\n", "qmods = []\n", "qprogs = []\n", "results = []\n", @@ -246,44 +215,56 @@ "for x in distance:\n", " time1 = time.time()\n", "\n", - " molecule = Molecule(atoms=[(\"H\", (0.0, 0.0, 0)), (\"H\", (0.0, 0.0, float(x)))])\n", - "\n", - " chemistry_problem = MoleculeProblem(\n", - " molecule=molecule,\n", - " mapping=\"jordan_wigner\", # 'bravyi_kitaev'\n", - " z2_symmetries=True,\n", - " freeze_core=True,\n", - " )\n", - "\n", - " qmod = construct_chemistry_model(\n", - " chemistry_problem=chemistry_problem,\n", - " use_hartree_fock=True,\n", - " ansatz_parameters=UCCParameters(excitations=[1, 2]),\n", - " execution_parameters=ChemistryExecutionParameters(\n", - " optimizer=OptimizerType.COBYLA,\n", - " max_iteration=30,\n", - " initial_point=None,\n", - " ),\n", + " # Define a molecule\n", + " geometry = [(\"H\", (0.0, 0.0, 0)), (\"H\", (0.0, 0.0, float(x)))]\n", + " molecule = MolecularData(geometry, basis=\"sto-3g\", multiplicity=1, charge=0)\n", + " molecule = run_pyscf(\n", + " molecule,\n", + " run_mp2=True,\n", + " run_cisd=True,\n", + " run_ccsd=True,\n", + " run_fci=True, # relevant for small, classically solvable problems\n", " )\n", - " qmods.append(qmod)\n", "\n", - " qprog = synthesize(qmod)\n", - " qprogs.append(qprog)\n", + " # Define a problem and a mapper\n", + " problem = FermionHamiltonianProblem.from_molecule(molecule)\n", + " mapper = Z2SymTaperMapper.from_problem(problem)\n", "\n", - " result = execute(qprog).result()\n", - " results.append(result)\n", - " chemistry_result_dict = result[1].value\n", + " # Construct a model\n", + " hf_state = get_hf_state(problem, mapper)\n", + " uccsd_hamiltonians = get_ucc_hamiltonians(problem, mapper, excitations=[1, 2])\n", + " num_params = len(uccsd_hamiltonians)\n", + " vqe_hamiltonian = qubit_op_to_pauli_terms(mapper.map(problem.fermion_hamiltonian))\n", "\n", - " operator = chemistry_problem.generate_hamiltonian()\n", - " mat = operator.to_matrix()\n", - " w, v = np.linalg.eig(mat)\n", - " result_exact = np.real(min(w)) + chemistry_result_dict[\"nuclear_repulsion_energy\"]\n", + " @qfunc\n", + " def main(params: CArray[CReal, num_params], state: Output[QArray]):\n", + " prepare_basis_state(hf_state, state)\n", + " multi_suzuki_trotter(uccsd_hamiltonians, params, 1, 1, state)\n", "\n", - " VQE_energy.append(chemistry_result_dict[\"total_energy\"])\n", + " # Synthesize\n", + " qprog = synthesize(main)\n", + " qprog = set_quantum_program_execution_preferences(\n", + " qprog,\n", + " preferences=ExecutionPreferences(\n", + " num_shots=1000,\n", + " backend_preferences=ClassiqBackendPreferences(\n", + " backend_name=\"simulator_statevector\"\n", + " ),\n", + " ),\n", + " )\n", + " qprogs.append(qprog)\n", "\n", - " HF_energy.append(chemistry_result_dict[\"hartree_fock_energy\"])\n", + " # Execute\n", + " with ExecutionSession(qprog) as es:\n", + " result = es.minimize(\n", + " cost_function=vqe_hamiltonian,\n", + " initial_params={\"params\": [0] * num_params},\n", + " max_iteration=500,\n", + " )\n", "\n", - " exact_energy.append(result_exact)\n", + " VQE_energy.append(result[-1][0])\n", + " HF_energy.append(molecule.hf_energy)\n", + " exact_energy.append(molecule.fci_energy)\n", "\n", " time2 = time.time()\n", " duration = time2 - time1\n", @@ -295,18 +276,11 @@ "cell_type": "code", "execution_count": 4, "id": "814b6501-6437-4fb8-96a9-4318b0ff54ea", - "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:16:31.141831Z", - "iopub.status.busy": "2024-05-07T15:16:31.140596Z", - "iopub.status.idle": "2024-05-07T15:16:31.165876Z", - "shell.execute_reply": "2024-05-07T15:16:31.165172Z" - } - }, + "metadata": {}, "outputs": [], "source": [ - "# save the last model to a qmod file\n", - "write_qmod(qmods[-1], \"molecular_energy_curve\")" + "# # save the last model to a qmod file\n", + "write_qmod(main, \"molecular_energy_curve\", symbolic_only=False)" ] }, { @@ -326,12 +300,6 @@ "execution_count": 5, "id": "1f657c3d", "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:16:31.170903Z", - "iopub.status.busy": "2024-05-07T15:16:31.169716Z", - "iopub.status.idle": "2024-05-07T15:16:31.470370Z", - "shell.execute_reply": "2024-05-07T15:16:31.469630Z" - }, "pycharm": { "name": "#%%\n" } @@ -339,7 +307,7 @@ "outputs": [ { "data": { - "image/png": "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", + "image/png": "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cxYvXowVK1bg448/xqFDhxAbG4vAwEDk5+erlbOwsFB7LZPJoFAoAIidk0uTlZWFcePGITY2VrWdPXsWly9fRr169XT6jCEhIbhw4QLMzc1V28WLFxEaGqrT+xBRxTCXOgAiMk316tWDhYUFTpw4AW9vbwDAgwcP8N9//6F79+4az6tWrRr69++P/v37Y+LEiWjcuDHOnTuH1q1bw9LSEoWFhWrljx07htdeew3vvPMOALG/z3///YcmTZpoHWuLFi1w69Yt/PfffyXWCrVu3RoXL15E/fr1tX7PkkRHR+PixYs4fPiw2txB6enp6NatG86cOQN/f//nugYR6YaJEBHphZ2dHUaNGoUZM2agRo0acHNzwyeffAK5XHNFdGhoqGpeHRsbG2zevBnVqlVDnTp1AIgjzP7++28MHjwYVlZWcHFxQYMGDfDbb7/h+PHjqF69Or755hvcvXtXp0Soe/fu6NatGwYOHIhvvvkG9evXx6VLlyCTydC7d298/PHHeOGFFzBp0iSMHj0atra2uHjxIiIiIrBq1SqtrxMSEoL27dujW7duxY517NgRISEhTISIKhmbxohIbxYvXoyuXbuif//+CAgIQJcuXdCmTRuN5Z2cnLB+/Xp07twZLVq0wIEDB/DHH3+gRo0aAIBPP/0U169fR7169eDq6goAmDNnDlq3bo3AwED06NED7u7uGDBggM6x7tixA+3atcOQIUPQpEkTfPTRR6rapxYtWuCvv/7Cf//9h65du8Lf3x9z586Fp6en1u+fm5uLn3/+GQMHDizx+MCBA7F169ZiTXpEpF8yQeBqf0REFW3+/PnYtWsXYmNjy/0ePXr0QKtWrYxqNm0iY8MaISIiPTl37hzs7Ozw3Xff6XTeli1bYGdnhyNHjugpMiJSYo0QEZEepKWlIS0tDYC4jIijo6PW5z58+BB3794FIDYXuri46CVGImIiRERERFUYm8aIiIioymIiRERERFUWEyEiIiKqspgIERERUZXFRIiIiIiqLCZCREREVGUxESIiIqIqi4kQERERVVlMhIiIiKjKYiJEREREVdb/AzlJORIlqjvHAAAAAElFTkSuQmCC", "text/plain": [ "
" ] @@ -349,6 +317,8 @@ } ], "source": [ + "import matplotlib.pyplot as plt\n", + "\n", "plt.plot(\n", " distance, VQE_energy, \"r--\", distance, HF_energy, \"bs\", distance, exact_energy, \"g^\"\n", ")\n", diff --git a/applications/chemistry/molecular_energy_curve/molecular_energy_curve.qmod b/applications/chemistry/molecular_energy_curve/molecular_energy_curve.qmod index 11db8722b..f521a98db 100644 --- a/applications/chemistry/molecular_energy_curve/molecular_energy_curve.qmod +++ b/applications/chemistry/molecular_energy_curve/molecular_energy_curve.qmod @@ -1,80 +1,20 @@ -qfunc main(output qbv: qbit[]) { - allocate(molecule_problem_to_hamiltonian(MoleculeProblem { - mapping=FermionMapping::JORDAN_WIGNER, - z2_symmetries=True, - molecule=Molecule { - atoms=[ - ChemistryAtom { - element=Element::H, - position=Position {x=0.0, y=0.0, z=0.0} - }, - ChemistryAtom { - element=Element::H, - position=Position {x=0.0, y=0.0, z=3.5} - } - ], - spin=1, - charge=0 - }, - freeze_core=True, - remove_orbitals=[] - })[0].pauli.len, qbv); - molecule_hartree_fock(MoleculeProblem { - mapping=FermionMapping::JORDAN_WIGNER, - z2_symmetries=True, - molecule=Molecule { - atoms=[ - ChemistryAtom { - element=Element::H, - position=Position {x=0.0, y=0.0, z=0.0} - }, - ChemistryAtom { - element=Element::H, - position=Position {x=0.0, y=0.0, z=3.5} - } - ], - spin=1, - charge=0 - }, - freeze_core=True, - remove_orbitals=[] - }, qbv); - molecule_ucc(MoleculeProblem { - mapping=FermionMapping::JORDAN_WIGNER, - z2_symmetries=True, - molecule=Molecule { - atoms=[ - ChemistryAtom { - element=Element::H, - position=Position {x=0.0, y=0.0, z=0.0} - }, - ChemistryAtom { - element=Element::H, - position=Position {x=0.0, y=0.0, z=3.5} +qfunc prepare_basis_state_expanded___0(output arr: qbit[1]) { + allocate(1, arr); +} + +qfunc main(params: real[1], output state: qbit[1]) { + prepare_basis_state_expanded___0(state); + multi_suzuki_trotter([ + SparsePauliOp { + terms=[ + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=0} + ], + coefficient=-0.5 } ], - spin=1, - charge=0 - }, - freeze_core=True, - remove_orbitals=[] - }, [1, 2], qbv); + num_qubits=1 + } + ], params, 1, 1, state); } - -cscope ``` -vqe_result = vqe( - hamiltonian=molecule_problem_to_hamiltonian(struct_literal(MoleculeProblem, mapping=FermionMapping.JORDAN_WIGNER, z2_symmetries=True, molecule=struct_literal(Molecule, atoms=[struct_literal(ChemistryAtom, element=Element.H, position=struct_literal(Position, x=0.0, y=0.0, z=0.0)), struct_literal(ChemistryAtom, element=Element.H, position=struct_literal(Position, x=0.0, y=0.0, z=3.5))], spin=1, charge=0), freeze_core=True, remove_orbitals=[])), maximize=False, -initial_point=[], -optimizer=Optimizer.COBYLA, -max_iteration=30, -tolerance=0, -step_size=0, -skip_compute_variance=False, -alpha_cvar=1.0, - -) -save({'vqe_result': vqe_result}) - -molecule_result = molecule_ground_state_solution_post_process(struct_literal(MoleculeProblem, mapping=FermionMapping.JORDAN_WIGNER, z2_symmetries=True, molecule=struct_literal(Molecule, atoms=[struct_literal(ChemistryAtom, element=Element.H, position=struct_literal(Position, x=0.0, y=0.0, z=0.0)), struct_literal(ChemistryAtom, element=Element.H, position=struct_literal(Position, x=0.0, y=0.0, z=3.5))], spin=1, charge=0), freeze_core=True, remove_orbitals=[]),vqe_result) -save({'molecule_result': molecule_result}) -``` diff --git a/applications/chemistry/molecular_energy_curve/molecular_energy_curve.synthesis_options.json b/applications/chemistry/molecular_energy_curve/molecular_energy_curve.synthesis_options.json index 0b5a0f62f..f2abf36af 100644 --- a/applications/chemistry/molecular_energy_curve/molecular_energy_curve.synthesis_options.json +++ b/applications/chemistry/molecular_energy_curve/molecular_energy_curve.synthesis_options.json @@ -7,28 +7,28 @@ "machine_precision": 8, "custom_hardware_settings": { "basis_gates": [ - "sx", "p", + "rx", + "u1", + "sx", + "z", "x", - "cx", - "tdg", "sdg", "cy", - "s", - "rx", - "sxdg", - "y", + "cx", "ry", - "u2", - "id", "rz", + "r", + "tdg", + "u2", "t", - "z", - "u", - "u1", + "y", + "s", + "id", "cz", "h", - "r" + "sxdg", + "u" ], "is_symmetric_connectivity": true }, @@ -39,6 +39,6 @@ "pretty_qasm": true, "transpilation_option": "auto optimize", "timeout_seconds": 300, - "random_seed": 3365615472 + "random_seed": 20440895 } } diff --git a/applications/chemistry/molecule_eigensolver/molecule_eigensolver.ipynb b/applications/chemistry/molecule_eigensolver/molecule_eigensolver.ipynb index dbf62f97d..7735ab290 100644 --- a/applications/chemistry/molecule_eigensolver/molecule_eigensolver.ipynb +++ b/applications/chemistry/molecule_eigensolver/molecule_eigensolver.ipynb @@ -18,55 +18,6 @@ "Within the scope of Classiq's VQE algorithm, define a molecule that is translated to a concise Hamiltonian. Then, choose among types of well studied ansatzes, which are carefully selected to fit your molecule type. In the last stage, the Hamiltonian and ansatz are sent to a classical optimizer. This tutorial demonstrates the steps and options in Classiq's VQE algorithm. It presents the optimization strength of Classiq's VQE algorithm and its state-of-the-art results in terms of efficient quantum circuit, with the ultimate combination of low depth and high accuracy while minimizing the number of CX gates." ] }, - { - "cell_type": "markdown", - "id": "54d09062-1b3b-4e4b-8351-5e05a633e269", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "## Prerequisites\n", - "\n", - "The model uses Classiq libraries:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "c6bbe65f-1e6a-475c-a43f-cb4cc04bbdfa", - "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:21:54.983816Z", - "iopub.status.busy": "2024-05-07T15:21:54.983159Z", - "iopub.status.idle": "2024-05-07T15:21:58.305203Z", - "shell.execute_reply": "2024-05-07T15:21:58.304507Z" - }, - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "from classiq import *\n", - "from classiq.applications.chemistry import (\n", - " ChemistryExecutionParameters,\n", - " HEAParameters,\n", - " Molecule,\n", - " MoleculeProblem,\n", - " UCCParameters,\n", - ")\n", - "from classiq.execution import (\n", - " ClassiqBackendPreferences,\n", - " ClassiqSimulatorBackendNames,\n", - " ExecutionPreferences,\n", - " OptimizerType,\n", - ")" - ] - }, { "cell_type": "markdown", "id": "faa3c10f", @@ -78,37 +29,35 @@ "source": [ "## Generating a Qubit Hamiltonian\n", "\n", - "Define the molecule to simulate, declaring the `molecule` class and inserting a list of atoms and their spacial positions. The algorithm automatically notes relevant attributes such as the atom's mass, charge, and spin.\n", + "Define the molecule to simulate, declaring the `MolecularData` class and inserting a list of atoms and their spatial positions (the distances are received in Å =$10^{-10} m$). In addition, provide basis, multiplicity, and charge.\n", "\n", "As mentioned above, this tutorial demonstrates how to define and find the ground state and energies for these molecules:" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "id": "ef2ce57e", "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:21:58.308346Z", - "iopub.status.busy": "2024-05-07T15:21:58.307789Z", - "iopub.status.idle": "2024-05-07T15:21:58.312947Z", - "shell.execute_reply": "2024-05-07T15:21:58.312497Z" - }, "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ - "molecule_H2 = Molecule(atoms=[(\"H\", (0.0, 0.0, 0)), (\"H\", (0.0, 0.0, 0.735))])\n", - "molecule_O2 = Molecule(atoms=[(\"O\", (0.0, 0.0, 0)), (\"O\", (0.0, 0.0, 1.16))])\n", - "molecule_LiH = Molecule(atoms=[(\"H\", (0.0, 0.0, 0.0)), (\"Li\", (0.0, 0.0, 1.596))])\n", - "molecule_H2O = Molecule(\n", - " atoms=[(\"O\", (0.0, 0.0, 0.0)), (\"H\", (0, 0.586, 0.757)), (\"H\", (0, 0.586, -0.757))]\n", - ")\n", - "molecule_BeH2 = Molecule(\n", - " atoms=[(\"Be\", (0.0, 0.0, 0.0)), (\"H\", (0, 0, 1.334)), (\"H\", (0, 0, -1.334))]\n", - ")" + "molecule_H2_geometry = [(\"H\", (0.0, 0.0, 0)), (\"H\", (0.0, 0.0, 0.735))]\n", + "molecule_O2_geometry = [(\"O\", (0.0, 0.0, 0)), (\"O\", (0.0, 0.0, 1.16))]\n", + "molecule_LiH_geometry = [(\"H\", (0.0, 0.0, 0.0)), (\"Li\", (0.0, 0.0, 1.596))]\n", + "molecule_H2O_geometry = [\n", + " (\"O\", (0.0, 0.0, 0.0)),\n", + " (\"H\", (0, 0.586, 0.757)),\n", + " (\"H\", (0, 0.586, -0.757)),\n", + "]\n", + "molecule_BeH2_geometry = [\n", + " (\"Be\", (0.0, 0.0, 0.0)),\n", + " (\"H\", (0, 0, 1.334)),\n", + " (\"H\", (0, 0, -1.334)),\n", + "]" ] }, { @@ -120,27 +69,37 @@ } }, "source": [ - "You can construct any valid assambly of atoms in a similar manner. The distances are received in Å ($10^{-10} m$). While this demonstration continues with a specific molecule, you can change the `molecule` below to study other cases." + "You can construct any valid assembly of atoms in a similar manner." ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "id": "2e77678f", "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:21:58.315498Z", - "iopub.status.busy": "2024-05-07T15:21:58.314960Z", - "iopub.status.idle": "2024-05-07T15:21:58.318124Z", - "shell.execute_reply": "2024-05-07T15:21:58.317557Z" - }, "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ - "molecule = molecule_H2" + "from openfermion.chem import MolecularData\n", + "from openfermionpyscf import run_pyscf\n", + "\n", + "geometry = molecule_H2_geometry\n", + "\n", + "basis = \"sto-3g\" # Basis set\n", + "multiplicity = 1 # Singlet state S=0\n", + "charge = 0 # Neutral molecule\n", + "molecule = MolecularData(molecule_H2_geometry, basis, multiplicity, charge)\n", + "\n", + "molecule = run_pyscf(\n", + " molecule,\n", + " run_mp2=True,\n", + " run_cisd=True,\n", + " run_ccsd=True,\n", + " run_fci=True, # relevant for small, classically solvable problems\n", + ")" ] }, { @@ -152,75 +111,57 @@ } }, "source": [ - "Define the parameters of the Hamiltonian generation program:\n", - "- `mapping` (str): the mapping between the fermionic Hamiltonian and and qubits Hamiltonian. Supported types:\n", - "- \n", - " - \"jordan_wigner\"\n", - " - \"parity\"\n", - " - \"bravyi_kitaev\"\n", - " - \"fast_bravyi_kitaev\"\n", - "- `freeze_core` (bool): removes the \"core\" orbitals of the atoms defining the molecule.\n", - "- `z2_symmetries` (bool): whether to perform z2 symmetries reduction. If symmetries in the molecules exist, this option decreases the number of qubits used, making the Hamiltonian and thus the calculations more efficient.\n", - "\n", - "Finally, the Hamiltonian is generated from `MoleculeProblem`." + "Define the parameters of the Hamiltonian problem (`FermionHamiltonianProblem`) and the mapper (`FermionToQubitMapper`) between Fermionic Hamiltonian and qubit Hamiltonians (Jordan Wigner or Bravyi Kitaev). If you want to use Z2-symmteries for reducing the problem size you can use `Z2SymTaperMapper` (see below)." ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "id": "2e0426d5", - "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:21:58.320678Z", - "iopub.status.busy": "2024-05-07T15:21:58.320142Z", - "iopub.status.idle": "2024-05-07T15:22:03.633083Z", - "shell.execute_reply": "2024-05-07T15:22:03.632220Z" - } - }, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Your Hamiltonian is\n", - "-1.041 * I\n", - "-0.796 * Z\n", - "+0.181 * X\n" + "(-0.09057898608834769+0j) [] +\n", + "(0.04523279994605784+0j) [X0 X1 X2 X3] +\n", + "(0.04523279994605784+0j) [X0 X1 Y2 Y3] +\n", + "(0.04523279994605784+0j) [Y0 Y1 X2 X3] +\n", + "(0.04523279994605784+0j) [Y0 Y1 Y2 Y3] +\n", + "(0.17218393261915538+0j) [Z0] +\n", + "(0.12091263261776627+0j) [Z0 Z1] +\n", + "(0.16892753870087907+0j) [Z0 Z2] +\n", + "(0.1661454325638241+0j) [Z0 Z3] +\n", + "(-0.2257534922240238+0j) [Z1] +\n", + "(0.1661454325638241+0j) [Z1 Z2] +\n", + "(0.17464343068300453+0j) [Z1 Z3] +\n", + "(0.1721839326191554+0j) [Z2] +\n", + "(0.12091263261776627+0j) [Z2 Z3] +\n", + "(-0.22575349222402386+0j) [Z3]\n", + "number of qubits 4\n" ] } ], "source": [ - "chemistry_problem = MoleculeProblem(\n", - " molecule=molecule,\n", - " mapping=\"jordan_wigner\", #'bravyi_kitaev'\n", - " z2_symmetries=True,\n", - " freeze_core=True,\n", - ")\n", + "from classiq.applications.chemistry.mapping import FermionToQubitMapper\n", + "from classiq.applications.chemistry.problems import FermionHamiltonianProblem\n", "\n", - "operator = chemistry_problem.generate_hamiltonian()\n", - "gs_problem = chemistry_problem.update_problem(operator.num_qubits)\n", - "print(\"Your Hamiltonian is\", operator.show(), sep=\"\\n\")" - ] - }, - { - "cell_type": "markdown", - "id": "67a124c2-33fc-420c-8cb3-0002f18f4e77", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "The output of the above code lines is the Hamiltonian presented as a superposition of Pauli matrices multiplication.\n", - "You can confirm that using z2*symmetries=True, the number of qubits is reduced (compared to z2_symmetries=False): \n", - "- for $H_2$ - from 4 to 1\n", - "- for $LiH$ from 12 to 8\n", - "- for $H*{2}O$ from 14 to 10" + "# Define a Hamiltonian in an active space\n", + "problem = FermionHamiltonianProblem.from_molecule(molecule=molecule)\n", + "mapper = FermionToQubitMapper()\n", + "\n", + "\n", + "qubit_hamiltonian = mapper.map(problem.fermion_hamiltonian)\n", + "print(\"Your Hamiltonian is\", qubit_hamiltonian, sep=\"\\n\")\n", + "num_qubits = mapper.get_num_qubits(problem)\n", + "print(f\"number of qubits {num_qubits}\")" ] }, { "cell_type": "markdown", - "id": "8abe3e3d-1b01-4fab-b86a-feaab3851950", + "id": "688d1b20-b7bf-4aca-806d-3a068e59932d", "metadata": { "pycharm": { "name": "#%% md\n" @@ -229,20 +170,14 @@ "source": [ "## Constructing and Synthesizing a Ground State Solver\n", "\n", - "A ground state solver model consists of a parameterized eigenfunction (\"the ansatz\"), on which to run a VQE. In addition, a postprocess of the result returns the total energy (combining the ground state energy of the Hamiltonian, the nuclear repulsion, and the static nuclear energy).\n", + "A ground state solver model consists of a parameterized eigenfunction (\"the ansatz\"), on which to run a VQE.\n", "\n", - "Specify a Hamiltonian and an ansatz, then send them to the VQE algorithm to find the Hamiltonian's ground state. In the process, the algorithm sends requests to a classical server, whose task is to minimize the energy expectation value and return the optimized parameters. The simulator and optimizing parameters are defined as part of the VQE part of the model. You can control the `max_iteration` value so the solution reaches a stable convergence. In addition, the `num_shots` value sets the number of measurements performed after each iteration, thus influencing the accuracy of the solutions.\n", - "\n", - "Below are two proposals for the wavefunction solution ansatz: \n", - "- Hardware (HW) efficient\n", - "- Unitary Coupled Cluster (UCC)\n", - "\n", - "For groundstate solvers, it is typical to initialize the ansatz with the Hartree-Fock state." + "Start with a Hardware (HW) efficient ansatz:" ] }, { "cell_type": "markdown", - "id": "07ed8f8e-485b-4f0f-93b7-78e7fd6fbe39", + "id": "3f9a1076-6791-4e40-8e94-b6b15f708333", "metadata": { "pycharm": { "name": "#%% md\n" @@ -251,86 +186,63 @@ "source": [ "### HW Efficient Ansatz\n", "\n", - "The suggested HW efficient ansatz solution is generated to fit a specific hardware [1]. The ansatz creates a state with a given number of parameters according to your choice of the number of qubits that fits the Hamiltonian, and creates entanglement between the qubits using the inputed connectivity map. This example uses a four qubit map, which is specifically made of $H_2$ with z2_symmetries=False.\n", + "The suggested HW efficient ansatz solution is generated to fit a specific hardware [1]. The ansatz creates a state with a given number of parameters according to your choice of the number of qubits that fits the Hamiltonian, and creates entanglement between the qubits using the inputed connectivity map. This example uses a four qubit map, which is specifically made for $H_2$ without using qubit tapering.\n", "\n", - "After constructing the model, synthesize it and view the output circuit, creating the state with an interactive interface." + "After constructing the model, synthesize it and view the output circuit." ] }, { - "cell_type": "code", - "execution_count": 5, - "id": "90b20061-8dbd-4136-adba-28ddacb1f583", - "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:22:03.637345Z", - "iopub.status.busy": "2024-05-07T15:22:03.637033Z", - "iopub.status.idle": "2024-05-07T15:22:03.660043Z", - "shell.execute_reply": "2024-05-07T15:22:03.659362Z" - } - }, - "outputs": [], + "cell_type": "markdown", + "id": "4fe0a35a-4f2f-4888-abe6-9319f6aaee15", + "metadata": {}, "source": [ - "chemistry_problem = MoleculeProblem(\n", - " molecule=molecule,\n", - " mapping=\"jordan_wigner\", #'bravyi_kitaev'\n", - " z2_symmetries=False,\n", - " freeze_core=True,\n", - ")\n", - "\n", - "hwea_params = HEAParameters(\n", - " num_qubits=4,\n", - " connectivity_map=[(0, 1), (1, 2), (2, 3)],\n", - " reps=3,\n", - " one_qubit_gates=[\"x\", \"ry\"],\n", - " two_qubit_gates=[\"cx\"],\n", - ")\n", - "\n", - "qmod_hwea = construct_chemistry_model(\n", - " chemistry_problem=chemistry_problem,\n", - " use_hartree_fock=True,\n", - " ansatz_parameters=hwea_params,\n", - " execution_parameters=ChemistryExecutionParameters(\n", - " optimizer=OptimizerType.COBYLA,\n", - " max_iteration=30,\n", - " initial_point=None,\n", - " ),\n", - ")\n", - "\n", - "backend_preferences = ClassiqBackendPreferences(\n", - " backend_name=ClassiqSimulatorBackendNames.SIMULATOR\n", - ")\n", - "\n", - "qmod_hwea = set_execution_preferences(\n", - " qmod_hwea,\n", - " execution_preferences=ExecutionPreferences(\n", - " num_shots=1000, backend_preferences=backend_preferences\n", - " ),\n", - " out_file=\"molecule_eigensolver\",\n", - ")" + "For groundstate solvers, it is typical to initialize the ansatz with the Hartree-Fock state. Use the `get_hf_state` and the `prepare_basis_state` qfunc." ] }, { "cell_type": "code", - "execution_count": 7, - "id": "22cd12d1-2c87-400a-a983-b2f24e40fa45", - "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:22:03.690648Z", - "iopub.status.busy": "2024-05-07T15:22:03.689438Z", - "iopub.status.idle": "2024-05-07T15:22:17.207052Z", - "shell.execute_reply": "2024-05-07T15:22:17.206288Z" - } - }, + "execution_count": 4, + "id": "7b70ed52-c331-4a17-b628-51c2489ac4af", + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Opening: https://platform.classiq.io/circuit/dd765d79-bcdb-49e0-85be-74af8c1b3f86?version=0.41.0.dev39%2B79c8fd0855\n" + "Quantum program link: https://platform.classiq.io/circuit/2z2Pa55XZ3UgYyUXfbL722GOz13\n" ] } ], "source": [ + "from classiq import *\n", + "from classiq.applications.chemistry.hartree_fock import get_hf_state\n", + "from classiq.applications.chemistry.op_utils import qubit_op_to_pauli_terms\n", + "\n", + "reps = 3\n", + "num_params = reps * num_qubits\n", + "hf_state = get_hf_state(problem, mapper)\n", + "vqe_hamiltonian = qubit_op_to_pauli_terms(mapper.map(problem.fermion_hamiltonian))\n", + "\n", + "\n", + "@qfunc\n", + "def main(params: CArray[CReal, num_params], state: Output[QArray]):\n", + " prepare_basis_state(hf_state, state)\n", + " full_hea(\n", + " num_qubits=num_qubits,\n", + " operands_1qubit=[lambda _, q: X(q), lambda theta, q: RY(theta, q)],\n", + " operands_2qubit=[lambda _, q1, q2: CX(q1, q2)],\n", + " is_parametrized=[0, 1, 0],\n", + " angle_params=params,\n", + " connectivity_map=[(0, 1), (1, 2), (2, 3)],\n", + " reps=reps,\n", + " x=state,\n", + " )\n", + "\n", + "\n", + "qmod_hwea = create_model(\n", + " main, execution_preferences=ExecutionPreferences(num_shots=1000)\n", + ")\n", + "write_qmod(qmod_hwea, \"molecule_eigensolver_hwea\", symbolic_only=False)\n", "qprog_hwea = synthesize(qmod_hwea)\n", "show(qprog_hwea)" ] @@ -344,13 +256,12 @@ } }, "source": [ - "### UCC Ansatz\n", + "### Unitary Coupled Cluster (UCC) Ansatz\n", "\n", "Create the commonly used chemistry-inspired UCC ansatz, which is a unitary version of the classical coupled cluster (CC) method [2].\n", "\n", "The parameter that defines the UCC ansatz:\n", - "`excitations` (List[int] or List[str]): list of desired excitations. Allowed excitations:\n", - "\n", + "`excitations` (List[int] or List[str]): list of desired excitations, e.g.,\n", "- 1 for singles\n", "- 2 for doubles\n", "- 3 for triples\n", @@ -360,58 +271,73 @@ ] }, { - "cell_type": "code", - "execution_count": 8, - "id": "1f520673", + "cell_type": "markdown", + "id": "1dba7601-a1c4-44f3-ad24-a6fe38c5ae9c", "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:22:17.210966Z", - "iopub.status.busy": "2024-05-07T15:22:17.210537Z", - "iopub.status.idle": "2024-05-07T15:22:42.664650Z", - "shell.execute_reply": "2024-05-07T15:22:42.663927Z" + "pycharm": { + "name": "#%% md\n" } }, + "source": [ + "For the current example, use the `Z2SymTaperMapper` that exploits Z2-symmetries of the molecule Hamiltonian to reduce the problem size.\n", + "You can confirm that using `Z2SymTaperMapper.from_problem` compared to `FermionToQubitMapper`, the number of qubits is reduced as: \n", + "- for $H_2$ - from 4 to 1\n", + "- for $LiH$ from 12 to 8 (together with freezing the core orbital `first_active_index=1`)\n", + "- for $H_{2}O$ from 14 to 10 (together with freezing the core orbital `first_active_index=1`)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "1f520673", + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Opening: https://platform.classiq.io/circuit/39cf374d-1965-4081-85bf-75c71cd73296?version=0.41.0.dev39%2B79c8fd0855\n", + "Your Hamiltonian is\n", + "-0.32112414706764497 [] +\n", + "0.18093119978423144 [X0] +\n", + "0.7958748496863588 [Z0]\n", + "number of qubits 1\n", + "Quantum program link: https://platform.classiq.io/circuit/2z2PaR8LzEVFs3Z6p3gy1DLXNnW\n", "circuit depth: 3\n" ] } ], "source": [ - "chemistry_problem = MoleculeProblem(\n", - " molecule=molecule,\n", - " mapping=\"jordan_wigner\", #'bravyi_kitaev'\n", - " z2_symmetries=True,\n", - " freeze_core=True,\n", - ")\n", + "from classiq.applications.chemistry.ucc import get_ucc_hamiltonians\n", + "from classiq.applications.chemistry.z2_symmetries import Z2SymTaperMapper\n", "\n", - "serialized_chemistry_model = construct_chemistry_model(\n", - " chemistry_problem=chemistry_problem,\n", - " use_hartree_fock=True,\n", - " ansatz_parameters=UCCParameters(excitations=[1, 2]),\n", - " execution_parameters=ChemistryExecutionParameters(\n", - " optimizer=OptimizerType.COBYLA,\n", - " max_iteration=30,\n", - " initial_point=None,\n", - " ),\n", - ")\n", + "problem = FermionHamiltonianProblem.from_molecule(molecule=molecule)\n", + "mapper = Z2SymTaperMapper.from_problem(problem)\n", "\n", - "backend_preferences = ClassiqBackendPreferences(\n", - " backend_name=ClassiqSimulatorBackendNames.SIMULATOR\n", - ")\n", "\n", - "serialized_chemistry_model = set_execution_preferences(\n", - " serialized_chemistry_model,\n", - " execution_preferences=ExecutionPreferences(\n", - " num_shots=1000, backend_preferences=backend_preferences\n", - " ),\n", + "qubit_hamiltonian = mapper.map(problem.fermion_hamiltonian)\n", + "print(\"Your Hamiltonian is\", qubit_hamiltonian, sep=\"\\n\")\n", + "num_qubits = mapper.get_num_qubits(problem)\n", + "print(f\"number of qubits {num_qubits}\")\n", + "\n", + "\n", + "hf_state = get_hf_state(problem, mapper)\n", + "uccsd_hamiltonians = get_ucc_hamiltonians(problem, mapper, excitations=[1, 2])\n", + "num_params = len(uccsd_hamiltonians)\n", + "vqe_hamiltonian = qubit_op_to_pauli_terms(mapper.map(problem.fermion_hamiltonian))\n", + "\n", + "\n", + "@qfunc\n", + "def main(params: CArray[CReal, num_params], state: Output[QArray]):\n", + " prepare_basis_state(hf_state, state)\n", + " multi_suzuki_trotter(uccsd_hamiltonians, params, 1, 1, state)\n", + "\n", + "\n", + "qmod_ucc = create_model(\n", + " main, execution_preferences=ExecutionPreferences(num_shots=1000)\n", ")\n", + "write_qmod(qmod_ucc, \"molecule_eigensolver_ucc\", symbolic_only=False)\n", + "qprog_ucc = synthesize(qmod_ucc)\n", "\n", - "qprog_ucc = synthesize(serialized_chemistry_model)\n", "show(qprog_ucc)\n", "\n", "print(f\"circuit depth: {qprog_ucc.transpiled_circuit.depth}\")" @@ -431,7 +357,7 @@ }, { "cell_type": "markdown", - "id": "ef36661f", + "id": "f0745289-84a6-4a44-868b-ca3efeb175b3", "metadata": { "pycharm": { "name": "#%% md\n" @@ -444,99 +370,60 @@ ] }, { - "cell_type": "code", - "execution_count": 9, - "id": "1a66d377", - "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:22:42.670417Z", - "iopub.status.busy": "2024-05-07T15:22:42.669946Z", - "iopub.status.idle": "2024-05-07T15:22:50.224366Z", - "shell.execute_reply": "2024-05-07T15:22:50.223567Z" - } - }, - "outputs": [], + "cell_type": "markdown", + "id": "1fc1bcf0-51f9-40f8-9f80-ff0ebca7252c", + "metadata": {}, "source": [ - "result = execute(qprog_ucc).result()\n", - "chemistry_result_dict = result[1].value" + "After you specified a Hamiltonian and an ansatz, send the resulting quantum program to the VQE algorithm to find the Hamiltonian's ground state. In the process, the algorithm sends requests to a classical server, whose task is to minimize the energy expectation value and return the optimized parameters. The simulator and optimizing parameters are defined as part of the VQE part of the model. You can control the `max_iteration` value so the solution reaches a stable convergence. In addition, the `num_shots` value sets the number of measurements performed after each iteration, thus influencing the accuracy of the solutions." ] }, { - "cell_type": "markdown", - "id": "f72ceeb5-bc71-46d8-a390-31ec874700f3", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "cell_type": "code", + "execution_count": 6, + "id": "1f332c01-0304-4941-99b7-ecc4b7492e96", + "metadata": {}, + "outputs": [], "source": [ - "Execution of the quantum program returns several useful outputs:\n", - "- `energy` : the output of the VQE algorithm - the electronic energy simulated.\n", - "- `nuclear_repulsion` : the electrostatic energy generated by the atom's nuclei.\n", - "- `hartree_fock_energy` : the Hartree-Fock energy.\n", - "- `total_energy` : the ground state energy of the Hamiltonian (combining the energy, the nuclear repulsion, and the static nuclear energy).\n", - "\n", - "It also contains the full VQE result from which you can get, for example:\n", - "- `optimal_parameters` : the results for the anzatz parameters minimizing that expectation value.\n", - "- `eigenstate` : the ground state wave function.\n", - "\n", - "Note that energy is presented in units of Hartree." + "with ExecutionSession(qprog_ucc) as es:\n", + " result_ucc = es.minimize(\n", + " cost_function=vqe_hamiltonian,\n", + " initial_params={\"params\": [0.0] * num_params},\n", + " max_iteration=200,\n", + " )" ] }, { "cell_type": "code", - "execution_count": 10, - "id": "437b3211", - "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:22:50.229659Z", - "iopub.status.busy": "2024-05-07T15:22:50.228329Z", - "iopub.status.idle": "2024-05-07T15:22:50.239525Z", - "shell.execute_reply": "2024-05-07T15:22:50.238826Z" - } - }, + "execution_count": 7, + "id": "1a66d377", + "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "-1.1382090268147285" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "optimizer result: -1.137409815524579\n", + "optimal parameter: {'params': [3.00005]}\n" + ] } ], "source": [ - "chemistry_result_dict[\"total_energy\"]" + "optimizer_res = result_ucc[-1][0]\n", + "optimal_params = result_ucc[-1][1]\n", + "print(f\"optimizer result: {optimizer_res}\")\n", + "print(f\"optimal parameter: {optimal_params}\")" ] }, { - "cell_type": "code", - "execution_count": 11, - "id": "9a537d3c", + "cell_type": "markdown", + "id": "f72ceeb5-bc71-46d8-a390-31ec874700f3", "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:22:50.244086Z", - "iopub.status.busy": "2024-05-07T15:22:50.242988Z", - "iopub.status.idle": "2024-05-07T15:22:50.250371Z", - "shell.execute_reply": "2024-05-07T15:22:50.249692Z" + "pycharm": { + "name": "#%% md\n" } }, - "outputs": [ - { - "data": { - "text/plain": [ - "{'param_0': 3.2624618497328566}" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ - "chemistry_result_dict[\"vqe_result\"][\"optimal_parameters\"]" + "Note that energy is presented in units of Hartree." ] }, { @@ -544,36 +431,28 @@ "id": "2375f3c3", "metadata": {}, "source": [ - "Finally, compare the VQE solution to the classical solution by employing exact diagonalization:" + "Finally, compare the VQE solution to the classical solution:" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 8, "id": "5c896576", - "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:22:50.255196Z", - "iopub.status.busy": "2024-05-07T15:22:50.253856Z", - "iopub.status.idle": "2024-05-07T15:22:50.261974Z", - "shell.execute_reply": "2024-05-07T15:22:50.261293Z" - } - }, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "exact result: -1.8572750302023786\n", - "vqe result: -1.8581780212637082\n" + "exact result: -1.1373060357533995\n", + "vqe result: -1.137409815524579\n" ] } ], "source": [ - "mat = operator.to_matrix()\n", - "w, v = np.linalg.eig(mat)\n", - "print(\"exact result:\", np.real(min(w)))\n", - "print(\"vqe result:\", chemistry_result_dict[\"energy\"])" + "expected_energy = molecule.fci_energy\n", + "print(\"exact result:\", expected_energy)\n", + "print(\"vqe result:\", optimizer_res)" ] }, { @@ -593,7 +472,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3.11.7 64-bit ('3.11.7')", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -607,7 +486,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.7" + "version": "3.11.9" }, "vscode": { "interpreter": { diff --git a/applications/chemistry/molecule_eigensolver/molecule_eigensolver.qmod b/applications/chemistry/molecule_eigensolver/molecule_eigensolver.qmod deleted file mode 100644 index 5314d791e..000000000 --- a/applications/chemistry/molecule_eigensolver/molecule_eigensolver.qmod +++ /dev/null @@ -1,67 +0,0 @@ -qfunc main(t: real[12], output qbv: qbit[]) { - allocate(molecule_problem_to_hamiltonian(MoleculeProblem { - mapping=FermionMapping::JORDAN_WIGNER, - z2_symmetries=False, - molecule=Molecule { - atoms=[ - ChemistryAtom { - element=Element::H, - position=Position {x=0.0, y=0.0, z=0.0} - }, - ChemistryAtom { - element=Element::H, - position=Position {x=0.0, y=0.0, z=0.735} - } - ], - spin=1, - charge=0 - }, - freeze_core=True, - remove_orbitals=[] - })[0].pauli.len, qbv); - molecule_hartree_fock(MoleculeProblem { - mapping=FermionMapping::JORDAN_WIGNER, - z2_symmetries=False, - molecule=Molecule { - atoms=[ - ChemistryAtom { - element=Element::H, - position=Position {x=0.0, y=0.0, z=0.0} - }, - ChemistryAtom { - element=Element::H, - position=Position {x=0.0, y=0.0, z=0.735} - } - ], - spin=1, - charge=0 - }, - freeze_core=True, - remove_orbitals=[] - }, qbv); - full_hea(4, [0, 1, 0], t, [[0, 1], [1, 2], [2, 3]], 3, [lambda(angle, q) { - X(q); - }, lambda(angle, q) { - RY(angle, q); - }], [lambda(angle, q1, q2) { - CX(q1, q2); - }], qbv); -} - -cscope ``` -vqe_result = vqe( - hamiltonian=molecule_problem_to_hamiltonian(struct_literal(MoleculeProblem, mapping=FermionMapping.JORDAN_WIGNER, z2_symmetries=False, molecule=struct_literal(Molecule, atoms=[struct_literal(ChemistryAtom, element=Element.H, position=struct_literal(Position, x=0.0, y=0.0, z=0.0)), struct_literal(ChemistryAtom, element=Element.H, position=struct_literal(Position, x=0.0, y=0.0, z=0.735))], spin=1, charge=0), freeze_core=True, remove_orbitals=[])), maximize=False, -initial_point=[], -optimizer=Optimizer.COBYLA, -max_iteration=30, -tolerance=0, -step_size=0, -skip_compute_variance=False, -alpha_cvar=1.0, - -) -save({'vqe_result': vqe_result}) - -molecule_result = molecule_ground_state_solution_post_process(struct_literal(MoleculeProblem, mapping=FermionMapping.JORDAN_WIGNER, z2_symmetries=False, molecule=struct_literal(Molecule, atoms=[struct_literal(ChemistryAtom, element=Element.H, position=struct_literal(Position, x=0.0, y=0.0, z=0.0)), struct_literal(ChemistryAtom, element=Element.H, position=struct_literal(Position, x=0.0, y=0.0, z=0.735))], spin=1, charge=0), freeze_core=True, remove_orbitals=[]),vqe_result) -save({'molecule_result': molecule_result}) -``` diff --git a/applications/chemistry/molecule_eigensolver/molecule_eigensolver.synthesis_options.json b/applications/chemistry/molecule_eigensolver/molecule_eigensolver.synthesis_options.json deleted file mode 100644 index 0967ef424..000000000 --- a/applications/chemistry/molecule_eigensolver/molecule_eigensolver.synthesis_options.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/applications/chemistry/molecule_eigensolver/molecule_eigensolver.metadata.json b/applications/chemistry/molecule_eigensolver/molecule_eigensolver_hwea.metadata.json similarity index 54% rename from applications/chemistry/molecule_eigensolver/molecule_eigensolver.metadata.json rename to applications/chemistry/molecule_eigensolver/molecule_eigensolver_hwea.metadata.json index a99ebceff..1fba04c46 100644 --- a/applications/chemistry/molecule_eigensolver/molecule_eigensolver.metadata.json +++ b/applications/chemistry/molecule_eigensolver/molecule_eigensolver_hwea.metadata.json @@ -1,6 +1,6 @@ { - "friendly_name": "VQE: Molecule Ground State", - "description": "Molecule Eigensolver (VQE method): Evaluating the Ground State of a Molecular Hamiltonian", + "friendly_name": "VQE: Molecule Ground State (HWEA)", + "description": "Molecule Eigensolver (VQE method): Evaluating the Ground State of a Molecular Hamiltonian with Hardware Efficient Ansatz", "problem_domain_tags": ["chemistry"], "qmod_type": ["application"], "level": ["demos"] diff --git a/applications/chemistry/molecule_eigensolver/molecule_eigensolver_hwea.qmod b/applications/chemistry/molecule_eigensolver/molecule_eigensolver_hwea.qmod new file mode 100644 index 000000000..4b561397e --- /dev/null +++ b/applications/chemistry/molecule_eigensolver/molecule_eigensolver_hwea.qmod @@ -0,0 +1,61 @@ +qfunc prepare_basis_state_expanded___0(output arr: qbit[4]) { + allocate(4, arr); + X(arr[0]); + X(arr[2]); +} + +qfunc operands_1qubit_0_lambda___0_0_expanded___0(_: real, permutable q: qbit) { + X(q); +} + +qfunc operands_1qubit_1_lambda___0_0_expanded___0(theta: real, q: qbit) { + RY(theta, q); +} + +qfunc operands_2qubit_0_lambda___0_0_expanded___0(_: real, const q1: qbit, permutable q2: qbit) { + CX(q1, q2); +} + +qfunc full_hea_expanded___0(num_qubits: int, is_parametrized: int[], angle_params: real[], connectivity_map: int[][], reps: int, x: qbit[4]) { + repeat (r: reps) { + repeat (i1: 2) { + repeat (index: num_qubits) { + if (is_parametrized[i1] == 1) { + if (i1 == 0) { + operands_1qubit_0_lambda___0_0_expanded___0(angle_params[(sum(is_parametrized[0:i1]) + index) + floor((12.0 * r) / reps)], x[index]); + } else { + if (i1 == 1) { + operands_1qubit_1_lambda___0_0_expanded___0(angle_params[(sum(is_parametrized[0:i1]) + index) + floor((12.0 * r) / reps)], x[index]); + } + } + } else { + if (i1 == 0) { + operands_1qubit_0_lambda___0_0_expanded___0(0, x[index]); + } else { + if (i1 == 1) { + operands_1qubit_1_lambda___0_0_expanded___0(0, x[index]); + } + } + } + } + } + repeat (i2: 1) { + repeat (index: 3) { + if (is_parametrized[i2 + 2] == 1) { + if (i2 == 0) { + operands_2qubit_0_lambda___0_0_expanded___0(angle_params[(((3 * sum(is_parametrized[2:(i2 + 2)])) + index) + (num_qubits * (is_parametrized[0:2][0] + is_parametrized[0:2][1]))) + floor((12.0 * r) / reps)], x[connectivity_map[index][0]], x[connectivity_map[index][1]]); + } + } else { + if (i2 == 0) { + operands_2qubit_0_lambda___0_0_expanded___0(0, x[connectivity_map[index][0]], x[connectivity_map[index][1]]); + } + } + } + } + } +} + +qfunc main(params: real[12], output state: qbit[4]) { + prepare_basis_state_expanded___0(state); + full_hea_expanded___0(4, [0, 1, 0], params, [[0, 1], [1, 2], [2, 3]], 3, state); +} diff --git a/applications/chemistry/molecule_eigensolver/molecule_eigensolver_hwea.synthesis_options.json b/applications/chemistry/molecule_eigensolver/molecule_eigensolver_hwea.synthesis_options.json new file mode 100644 index 000000000..5f6315562 --- /dev/null +++ b/applications/chemistry/molecule_eigensolver/molecule_eigensolver_hwea.synthesis_options.json @@ -0,0 +1,44 @@ +{ + "constraints": { + "max_gate_count": {}, + "optimization_parameter": "no_opt" + }, + "preferences": { + "machine_precision": 8, + "custom_hardware_settings": { + "basis_gates": [ + "x", + "sdg", + "p", + "rx", + "u", + "h", + "z", + "u1", + "ry", + "tdg", + "u2", + "t", + "rz", + "s", + "cy", + "sxdg", + "id", + "cz", + "cx", + "y", + "r", + "sx" + ], + "is_symmetric_connectivity": true + }, + "debug_mode": true, + "synthesize_all_separately": false, + "optimization_level": 3, + "output_format": ["qasm"], + "pretty_qasm": true, + "transpilation_option": "auto optimize", + "timeout_seconds": 300, + "random_seed": 3764702779 + } +} diff --git a/applications/chemistry/molecule_eigensolver/molecule_eigensolver_ucc.metadata.json b/applications/chemistry/molecule_eigensolver/molecule_eigensolver_ucc.metadata.json new file mode 100644 index 000000000..f138d371d --- /dev/null +++ b/applications/chemistry/molecule_eigensolver/molecule_eigensolver_ucc.metadata.json @@ -0,0 +1,7 @@ +{ + "friendly_name": "VQE: Molecule Ground State (UCC)", + "description": "Molecule Eigensolver (VQE method): Evaluating the Ground State of a Molecular Hamiltonian with Unitary Coupled Cluster ansatz", + "problem_domain_tags": ["chemistry"], + "qmod_type": ["application"], + "level": ["demos"] +} diff --git a/applications/chemistry/molecule_eigensolver/molecule_eigensolver_ucc.qmod b/applications/chemistry/molecule_eigensolver/molecule_eigensolver_ucc.qmod new file mode 100644 index 000000000..f521a98db --- /dev/null +++ b/applications/chemistry/molecule_eigensolver/molecule_eigensolver_ucc.qmod @@ -0,0 +1,20 @@ +qfunc prepare_basis_state_expanded___0(output arr: qbit[1]) { + allocate(1, arr); +} + +qfunc main(params: real[1], output state: qbit[1]) { + prepare_basis_state_expanded___0(state); + multi_suzuki_trotter([ + SparsePauliOp { + terms=[ + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=2, index=0} + ], + coefficient=-0.5 + } + ], + num_qubits=1 + } + ], params, 1, 1, state); +} diff --git a/applications/chemistry/molecule_eigensolver/molecule_eigensolver_ucc.synthesis_options.json b/applications/chemistry/molecule_eigensolver/molecule_eigensolver_ucc.synthesis_options.json new file mode 100644 index 000000000..73c581a03 --- /dev/null +++ b/applications/chemistry/molecule_eigensolver/molecule_eigensolver_ucc.synthesis_options.json @@ -0,0 +1,44 @@ +{ + "constraints": { + "max_gate_count": {}, + "optimization_parameter": "no_opt" + }, + "preferences": { + "machine_precision": 8, + "custom_hardware_settings": { + "basis_gates": [ + "x", + "sdg", + "p", + "rx", + "u", + "h", + "z", + "u1", + "ry", + "tdg", + "u2", + "t", + "rz", + "s", + "cy", + "sxdg", + "id", + "cz", + "cx", + "y", + "r", + "sx" + ], + "is_symmetric_connectivity": true + }, + "debug_mode": true, + "synthesize_all_separately": false, + "optimization_level": 3, + "output_format": ["qasm"], + "pretty_qasm": true, + "transpilation_option": "auto optimize", + "timeout_seconds": 300, + "random_seed": 1618746921 + } +} diff --git a/applications/chemistry/molecule_eigensolver_using_openfermion/molecule_eigensolver_using_openfermion.ipynb b/applications/chemistry/molecule_eigensolver_using_openfermion/molecule_eigensolver_using_openfermion.ipynb deleted file mode 100644 index bd4747794..000000000 --- a/applications/chemistry/molecule_eigensolver_using_openfermion/molecule_eigensolver_using_openfermion.ipynb +++ /dev/null @@ -1,1995 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "cbad17b4-2daa-4901-8a4b-1a4e22d53ed2", - "metadata": {}, - "source": [ - "# Variational Quantum Eigensolver using OpenFermion package" - ] - }, - { - "cell_type": "markdown", - "id": "890b4f90-df8f-4bf3-9616-d58493b37f39", - "metadata": {}, - "source": [ - "In this tutorial we build a Variational Quantum Eigensolver (VQE), using Qmod and OpenFermion packages [[1](#OF)]. OpenFermion is a comprehensive library for defining and analyzing Fermionic systems, in particular quantum chemistry problems. It provides efficient tools for transforming Fermionic operators to Pauli operators, which are then can be used with Qmod to define quantum algorithms. Some basic usage of this quantum chemistry package is incorporated in the notebook, however, we encourage the reader to read its [intro tutorial](https://quantumai.google/openfermion/tutorials/intro_to_openfermion) [[2](#OFintro)].\n", - "\n", - "This notebook implements the following logic, starting from a Molecule definition down to designing and executing a quantum model:\n", - "\n", - "* **Part (A):** Define a molecule and get its second-quantized Hamiltonian for the electronic structure problem. This part is done with the `openfermionpyscf` package.\n", - "\n", - "\n", - "* **Part (B):** Construct a transformation from Fermionic Fock space to Qubits space, including space reduction via symmetries. The latter depends on the Molecule Hamiltonian itself. This part is done with the `openfermion` package.\n", - "\n", - "\n", - "* **Part (C):** Build and run a VQE in the reduced Qubit space. The quantum primitives, such as Unitary Coupled Cluster (UCC) ansatz or Hartree Fock state preparation, are defined in the Fermionic Fock space. The quantum algorithm is thus consructed with the mapping defined in part (B). This part (C) is done with the `classiq` and its Qmod language." - ] - }, - { - "cell_type": "markdown", - "id": "e5cb14f1-004e-448b-9b06-ac42f03121fa", - "metadata": {}, - "source": [ - "***\n", - "## Part A: From Molecule to Electronic structure Hamiltonian\n", - "***\n", - "\n", - "This part addresses the transformation:\n", - "$$\n", - "\\large \\text{Molecule parameters}\\rightarrow \\text{Hamiltonian in Fermionic Fock space}\n", - "$$" - ] - }, - { - "cell_type": "markdown", - "id": "9c71d9a3-e01b-4b21-9130-06b475ee458d", - "metadata": {}, - "source": [ - "### Defining a molecule\n", - "\n", - "We start with defining a molecule, specifying its geometry (elements and their 3D position), multiplicity ($2\\cdot(\\text{total spin})+1$), basis, and an optional string for its description. In this tutorial we focus on the LiH molecule. There are several ways to get geometry of molecules, typical way involves using the *SMILES* (Simplified Molecular Input Line Entry System) of a molecule and use a chemical package such as `RDkit` to extract the geometry as an `xyz` file (a code example is given at the end of this notebook in Appendix C). For simplicity, we store the geometry in advance in the `lih.xyz` file and load it.\n", - "\n", - "*Comment: For complex molecules it is possible to call directly `from openfermion.chem import geometry_from_pubchem`*" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "fba9a0e8-06cd-4d63-ab07-d13bf3999c03", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:03.903578Z", - "start_time": "2025-04-10T09:34:02.388423Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[('Li', (0.833472, 0.0, 0.0)), ('H', (-0.833472, 0.0, 0.0))]\n" - ] - } - ], - "source": [ - "import pathlib\n", - "\n", - "from openfermion.chem import MolecularData\n", - "\n", - "path = (\n", - " pathlib.Path(__file__).parent.resolve()\n", - " if \"__file__\" in locals()\n", - " else pathlib.Path(\".\")\n", - ")\n", - "geometry_file = path / \"lih.xyz\"\n", - "\n", - "# Set up molecule parameters\n", - "basis = \"sto-3g\" # Basis set\n", - "multiplicity = 1 # Singlet state S=0\n", - "charge = 0 # Neutral molecule\n", - "\n", - "# geometry\n", - "with open(geometry_file, \"r\") as f:\n", - " lines = f.readlines()\n", - " atom_lines = lines[2:] # skip atom count and comment\n", - " geometry = []\n", - " for line in atom_lines:\n", - " parts = line.strip().split()\n", - " symbol = parts[0]\n", - " coords = tuple(float(x) for x in parts[1:4])\n", - " geometry.append((symbol, coords))\n", - "\n", - "print(geometry)\n", - "description = \"LiH\"\n", - "\n", - "# Create MolecularData object\n", - "molecule = MolecularData(geometry, basis, multiplicity, charge, description)" - ] - }, - { - "cell_type": "markdown", - "id": "f3ca6546-9450-46ef-95a3-b4e26f2637e6", - "metadata": {}, - "source": [ - "Next, we run a pyscf plugin for calculating various objects for our molecule problem, such as the second quantized Hamiltonian that is at the core of the VQE algorithm. For small problems, we can also get the Full Configuration Interaction (FCI), which calculates classically the ground state energy, i.e., for validating our quantum approach.\n", - "\n", - "*Comment: For complex problems running pyscf can take time, it is possible to run it only once, and load the data later on, using the `save` and `load` methods*." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "db06a8be-7e78-4a20-84ec-e63d082ac0ac", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:04.224339Z", - "start_time": "2025-04-10T09:34:03.904872Z" - } - }, - "outputs": [], - "source": [ - "from openfermionpyscf import run_pyscf\n", - "\n", - "RECALCULATE_MOLECULE = True # can be set to False after initial run\n", - "if RECALCULATE_MOLECULE:\n", - " molecule = run_pyscf(\n", - " molecule,\n", - " run_mp2=True,\n", - " run_cisd=True,\n", - " run_ccsd=True,\n", - " run_fci=True, # relevant for small, classically solvable problems\n", - " )\n", - " molecule.save()\n", - "\n", - "molecule.load()" - ] - }, - { - "cell_type": "markdown", - "id": "23e67540-a623-4356-bbe2-8ae21c439ef9", - "metadata": {}, - "source": [ - "Now we can get several properties of our molecular problem. The electronic structure problem is described as a second quantized Hamiltonian\n", - "$$\n", - "\\Large H = h_0 + \\sum_{p,q=0}^{2N-1} h_{pq}\\, a^\\dagger_p a_q + \\frac{1}{2} \\sum_{p,q,r,s=0}^{2N-1} h_{pqrs} \\, a^\\dagger_p a^\\dagger_q a_r a_s,\n", - "\\tag{1}\n", - "$$\n", - "where $h_0$ is a constant nuclear repulsion energy, and $h_{pq}$ and $h_{pqrs}$ are the well-known one-body and two-body molecular integrals, respectively. We can access these objects calling `molecule.nuclear_repulsion`, `molecule.one_body_integrals` and `molecule.two_body_integrals`. The sum is over all spin orbitals, which is twice the number of spatial orbitals $N$, as for each spatial orbital we have a spin up and spin down space (also known as alpha and beta particles). This, together with the number of free electrons that can occupy those orbitals, define the electronic structure problem." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "5d3506ad-f775-4caf-a78b-76122b82c646", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:04.225648Z", - "start_time": "2025-04-10T09:34:04.224142Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The electronic structure problems has 12 spin orbitals, and we need to occupy 4 electrons\n" - ] - } - ], - "source": [ - "n_spatial_orbitals = molecule.n_orbitals\n", - "n_electrons = molecule.n_electrons\n", - "print(\n", - " f\"The electronic structure problems has {2*n_spatial_orbitals} spin orbitals, and we need to occupy {n_electrons} electrons\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "c66fa058-957d-490a-8e9a-c937ca7e5155", - "metadata": {}, - "source": [ - "### Defining a Fermionic operator for a reduced problem (active space/freeze core)\n", - "\n", - "In some cases, we can \"freeze\" some of the orbitals, occupying them with both spin up and spin down electrons. In other words, we can choose the active space for our molecular problem --- the spatial orbitals that are relevant to the quantum problem. This of-course reduces the problem we need to tackle. Below we freeze the core ($0^{\\rm th}$) orbital, and define the Fermionic operator object (as in Eq. (1)). Note that we have to update the number of spatial orbitals and electrons accordingly." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "a28a9671-ba18-4aec-b742-a6cfddd5365f", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:04.233554Z", - "start_time": "2025-04-10T09:34:04.227260Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Reduced number of spatial orbitals after freeze core: 5\n", - "Reduced number of electrons after freeze core: 2\n", - "Length of Hamiltonian in Fermionic representation: 811\n", - "Number of qubits representing the problem: 10\n" - ] - } - ], - "source": [ - "from openfermion.transforms import get_fermion_operator\n", - "\n", - "# Get the Hamiltonian in an active space\n", - "first_active_index = 1\n", - "last_active_index = n_spatial_orbitals\n", - "molecular_hamiltonian = molecule.get_molecular_hamiltonian(\n", - " occupied_indices=range(first_active_index), # freezing the core\n", - " active_indices=range(\n", - " first_active_index, last_active_index\n", - " ), # active space is all the rest of the orbitals\n", - ")\n", - "\n", - "## Update the number of orbitals and electrons\n", - "n_freezed_orbitals = first_active_index + n_spatial_orbitals - last_active_index\n", - "n_spatial_orbitals -= n_freezed_orbitals\n", - "n_electrons -= 2 * n_freezed_orbitals\n", - "print(f\"Reduced number of spatial orbitals after freeze core: {n_spatial_orbitals}\")\n", - "print(f\"Reduced number of electrons after freeze core: {n_electrons}\")\n", - "\n", - "\n", - "# Map operator to fermions\n", - "fermion_hamiltonian = get_fermion_operator(molecular_hamiltonian)\n", - "fermion_hamiltonian.compress(abs_tol=1e-13) # trimming\n", - "n_qubits = molecular_hamiltonian.n_qubits\n", - "print(\n", - " f\"Length of Hamiltonian in Fermionic representation: {len(fermion_hamiltonian.terms)}\"\n", - ")\n", - "print(f\"Number of qubits representing the problem: {n_qubits}\")" - ] - }, - { - "cell_type": "markdown", - "id": "c4c30b3e-27f4-4f9b-bea0-68f664f3f3fb", - "metadata": {}, - "source": [ - "Let us look at several terms of our Fermionic operator:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "ef5c404b-d33f-4d1e-86c7-a64effe820cd", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:04.240008Z", - "start_time": "2025-04-10T09:34:04.235441Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "((), -6.817329071667983)\n", - "(((0, 1), (0, 0)), -0.7621826148518264)\n", - "(((0, 1), (2, 0)), 0.049739077075891036)\n", - "(((0, 1), (8, 0)), -0.12350856641975391)\n", - "(((1, 1), (1, 0)), -0.7621826148518264)\n", - "(((9, 1), (9, 1), (9, 0), (9, 0)), 0.22555659839798667)\n", - "(((9, 1), (9, 1), (9, 0), (3, 0)), -0.022199146730809072)\n", - "(((9, 1), (9, 1), (9, 0), (1, 0)), 0.06490533159641326)\n", - "(((9, 1), (9, 1), (7, 0), (7, 0)), 0.00990347751080244)\n", - "(((9, 1), (9, 1), (5, 0), (5, 0)), 0.00990347751080244)\n" - ] - } - ], - "source": [ - "print(*list(fermion_hamiltonian.terms.items())[:5], sep=\"\\n\")\n", - "print(*list(fermion_hamiltonian.terms.items())[::-1][:5], sep=\"\\n\")" - ] - }, - { - "cell_type": "markdown", - "id": "2a49ea33-8cee-466d-a5f0-1a13bfe245f3", - "metadata": {}, - "source": [ - "We can see one-body terms $((i,1),(j,0))$ that refer to $a_i^{\\dagger}a_j$, and two-body terms $((i,1),(j,1),(k,0),(l,0))$ that corresponds to $a_i^{\\dagger}a_j^{\\dagger}a_ka_l$." - ] - }, - { - "cell_type": "markdown", - "id": "cf7ada21-0ccb-48d7-9414-1529b23cee9c", - "metadata": {}, - "source": [ - "
\n", - " Orbital labeling: : For $N$ spatial orbitals we have $N_\\alpha (\\text{spin up})=N_\\beta (\\text{spin down})=N$. In OpenFermion, the order of spin orbitals is alternating spin labeling $(0_\\uparrow, 0_\\downarrow, 1_\\uparrow, 1_\\downarrow,\\dots, (N-1)_\\uparrow, (N-1)_\\downarrow$). When transforming the problem to a Qubit Hamiltonian, described by Pauli strings, then different ordering can result in different Hamiltonians, which in turn, might lead to different quantum circuits in terms of depth or cx-counts. For example, Classiq's built-in `MoleculeProblem` object is defined according to block spin labeling $(0_\\uparrow, 1_\\uparrow, \\dots, (N-1)_\\uparrow, 0_\\downarrow,1_\\downarrow\\dots, (N-1)_\\downarrow$).\n", - "
\n" - ] - }, - { - "cell_type": "markdown", - "id": "4acfdde7-d608-41ce-821e-f05c6a00d8ba", - "metadata": {}, - "source": [ - "***\n", - "## Part B: From Fock space to reduced Qubit space\n", - "***\n", - "\n", - "In this part we define the following transformations:\n", - "$$\n", - "\\large \\text{Fermionic Fock space}\\xrightarrow{\\text{JW}} \\text{Hilbert space for qubits} \\xrightarrow{\\text{Clifford transformation}} \\text{eigenspace of } \\mathbb{Z}_2 \\text{ symmetries} \\xrightarrow{\\text{tapering}} \\text{Reduced space},\n", - "$$\n", - "where JW stands for the Jordan-Wigner transform." - ] - }, - { - "cell_type": "markdown", - "id": "4fdebf94-ff6b-40cb-9baf-912cc7f1d685", - "metadata": {}, - "source": [ - "### Transforming to Qubit Hamiltonian (Pauli strings)\n", - "\n", - "Next, we need to transform the creation/annihilation operators to Pauli operators, suitable for quantum algorithms. There are several known transforms, such as Jordan Wigner (JW) and Bravyi Kitaev (BK) transforms. In this tutorial we will use the JW transform." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "ad5347f8-ef2c-45f0-9cd6-b2a5bafa3d7c", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:04.300403Z", - "start_time": "2025-04-10T09:34:04.278868Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Length of Hamiltonian in Pauli representation: 276\n", - "Example of Pauli Hamiltonian terms:\n", - "((), -5.750184614764152)\n", - "(((0, 'Z'),), -0.29670485079927406)\n", - "(((0, 'Y'), (1, 'Z'), (2, 'Y')), -0.0025472629069889555)\n", - "(((0, 'X'), (1, 'Z'), (2, 'X')), -0.0025472629069889555)\n", - "(((0, 'Y'), (1, 'Z'), (2, 'Z'), (3, 'Z'), (4, 'Z'), (5, 'Z'), (6, 'Z'), (7, 'Z'), (8, 'Y')), -0.01778020141438094)\n" - ] - } - ], - "source": [ - "from openfermion.transforms import jordan_wigner\n", - "\n", - "qubit_hamiltonian = jordan_wigner(fermion_hamiltonian)\n", - "qubit_hamiltonian.compress(abs_tol=1e-13) # trimming\n", - "\n", - "print(f\"Length of Hamiltonian in Pauli representation: {len(qubit_hamiltonian.terms)}\")\n", - "print(\"Example of Pauli Hamiltonian terms:\")\n", - "print(*list(qubit_hamiltonian.terms.items())[:5], sep=\"\\n\")" - ] - }, - { - "cell_type": "markdown", - "id": "bc952d5c-5189-40fc-b9ca-7cf888ee281f", - "metadata": {}, - "source": [ - "### Hartree Fock state\n", - "\n", - "The Hartree Fock state refers to excitation of all the lower energy orbitals. In OpenFermion notation, these refer to the lowest orbital indices. Thus, if we have $M$ free electrons, we just excite the first $M$ states. This is captured by operating on the zero state with the operator\n", - "$$\n", - "H_{\\rm HF} = \\Pi^{M}_{i=0} a^{\\dagger}_{i}.\n", - "$$" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "aed823eb-5c53-493a-be60-296b51d5cbca", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:04.300635Z", - "start_time": "2025-04-10T09:34:04.280858Z" - } - }, - "outputs": [], - "source": [ - "from openfermion import FermionOperator\n", - "\n", - "hf_excitation = FermionOperator(\" \".join(f\"{o}^\" for o in range(n_electrons)), 1.0)\n", - "hf_operator = jordan_wigner(hf_excitation)\n", - "hf_operator.compress(1e-13)" - ] - }, - { - "cell_type": "markdown", - "id": "85b4f316-6305-46a4-b45d-3cab43df29e4", - "metadata": {}, - "source": [ - "Next, we calculate the state generated by the Hartree Fock operator. We first define a general function that returns a qubit state from qubit operator application on the zero state." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "ed424647-20a2-4e64-959d-abb20beb863c", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:04.300721Z", - "start_time": "2025-04-10T09:34:04.291233Z" - } - }, - "outputs": [], - "source": [ - "from openfermion import QubitOperator\n", - "\n", - "\n", - "def qubit_operation_on_zero_state(qubit_operator: QubitOperator, n_qubits: int):\n", - " if qubit_operator == QubitOperator():\n", - " return {\"0\" * n_qubits: 1}\n", - " states = {}\n", - " for term, coefficient in qubit_operator.terms.items():\n", - " state = [0] * n_qubits\n", - " coe = coefficient\n", - " for op in term:\n", - " if op[1] == \"X\":\n", - " state[op[0]] ^= 1\n", - " if op[1] == \"Y\":\n", - " state[op[0]] ^= 1\n", - " coe *= 1j\n", - " state = \"\".join(map(str, state))\n", - " states[state] = states.get(state, 0) + coe\n", - "\n", - " return states" - ] - }, - { - "cell_type": "markdown", - "id": "15f17669-bf72-407a-938e-78d745d1bf53", - "metadata": {}, - "source": [ - "Typically, e.g., for the Jordan Wigner or the Bravyi Kitaev transforms, the Hartree Fock state, which is an elementary basis state in the Fock space, is mapped to a single computational basis state." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "7352ae4a-caee-48fb-8048-27f25d673c29", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:04.300846Z", - "start_time": "2025-04-10T09:34:04.291536Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The HF state: 1100000000\n" - ] - } - ], - "source": [ - "hf_state = qubit_operation_on_zero_state(hf_operator, n_qubits)\n", - "assert (\n", - " len(hf_state) == 1\n", - "), f\"The resulting HF state is not a single computationa state, got {hf_state}\"\n", - "hf_str = list(hf_state.keys())[0]\n", - "print(f\"The HF state: {hf_str}\")" - ] - }, - { - "cell_type": "markdown", - "id": "cfe1c7de-232f-4389-a61a-0a6bb44d5a09", - "metadata": {}, - "source": [ - "
\n", - " HF state under the JW transform: : Working with the JW transform, there is a simple relation between the original Fock (occupation number) and transformed (computational) basis states: the state $|\\underbrace{0\\dots 0}_{k-1}10\\dots 0\\rangle$ corresponds to occupation of the $k$-th spin orbital in both spaces. Therefore, the Hartree Fock state under this transformation is a string that startes with `n_electrons` 1s, and the rest is 0.\n", - "
\n" - ] - }, - { - "cell_type": "markdown", - "id": "66e96e41-1317-459c-bc1e-7c133a594d01", - "metadata": {}, - "source": [ - "### Reducing the problem size with $\\mathbb{Z}_2$ symmetries (qubit tapering)\n", - "\n", - "Next, we will use symmetries to reduce the problem size. The theory of qubit tapering is broad and complex, see for example Refs [[3](#sym1)] and [[4](#sym2)]. The main steps of this procedure are as follows (see some technical details in Appendix A at the end of this notebook):\n", - "\n", - "1. Find generators $\\left\\{g^{(i)}\\right\\}^k_{i=1}$ for a group of operators that commute with the Hamiltonian $H$: for all $g\\in \\langle g^{(1)},\\dots g^{(k)}\\rangle$, $\\left[H, g\\right] = 0$. That means that there is a basis in which both $H$ and such $g$ operators are diagonal. These operators are assumed to be a single Pauli string, typically containing only Pauli $Z$ operators.\n", - "2. Find a unitary transformation $U$ that diagonalizes all $g^{(i)}$, such that each generator operates trivially on all qubits except one, e.g., they transform to operators of the form $X_{l}$ for some qubit number $l$. It can be shown that such unitary can be constructed as $\\Pi^k_{i=1}\\frac{1}{\\sqrt{2}}\\left(X_{m^{(i)}}+g^{(i)}\\right)$, where $X_{m^{(i)}}$ is operating on a some single qubit $m^{(i)}$.\n", - "3. Apply the transformation $U^{\\dagger} H U$, whose eigenspace will be identical to those of $U^{\\dagger} g_i U$. That means that on some qubits the transformed Hamiltonian is acting trivially, returning $\\pm 1$ (thus is the name $\\mathbb{Z}_2$ symmetries), and we can taper them off.\n", - "4. Taper off qubits from the transformed Hamiltonian." - ] - }, - { - "cell_type": "markdown", - "id": "f5e0c390-c9c5-45d2-bfd3-3835331bce5e", - "metadata": {}, - "source": [ - "#### Step 1: Finding generators for the symmetry group $\\left\\{g^{(i)}\\right\\}$ and their accompanying $\\left\\{X_{m^{(i)}}\\right\\}$ operators\n", - "\n", - "There are known techniques for finding a set of independent $\\mathbb{Z}_2$-symmetry generators, see Refs [[3](#sym1)] and [[4](#sym2)]. In Appendix B of this tutorial we provide a code that implements a function, `find_z2sym`, for obtaining $\\left\\{\\left(g^{(i)}, X_{m^{(i)}}\\right)\\right\\}$ for a given Hamiltonian. Instead of working with the generic approach, in this tutorial we will use some educated guess, according to some physical properties--- conservation laws--- of our system, to define several symmetry operations. In electronic structure problems we have, for example, **particle number conservation**, **spin conservation**, and **number of particles with fixed spin orientation**. The latter corresponds to the two Fermionic operators:\n", - "$$\n", - "\\text{Total number of spin-up/down particles operator:} \\qquad N_{\\uparrow} = \\sum_i a^{\\dagger}_{i\\uparrow} a_{i\\uparrow}, \\qquad \n", - "N_{\\downarrow} = \\sum_i a^{\\dagger}_{i\\downarrow} a_{i\\downarrow}.\n", - "$$\n", - "We can use this conserved quantities to construct some relevant symmetry generators, when working with the JW transform: \n", - "$$\n", - "g_{\\uparrow} = \\Pi^{N/2}_{k=0}Z_{2k}, \\qquad g_{\\downarrow} = \\Pi^{N/2}_{k=0}Z_{2k+1}.\n", - "$$\n", - "For more details see the info box below (note that using the generic approach given in the Appendix, one finds 4 symmetry generators. See last code block at the bottom of the notebook)." - ] - }, - { - "cell_type": "markdown", - "id": "ea88b556-0905-4b5e-8237-78299ce3679e", - "metadata": {}, - "source": [ - "
\n", - " Conserved quantities under the JW transform: : As explained in the previous info box, working with the JW transform gives that Fock basis state are trasformed to the computational basis states. In particular, there is a relation between the orbital number operator and the $Z$ operators: $n_i = a_i^{\\dagger}a_i = \\frac{1}{2}\\left(1-Z_i\\right)$. We cannot use the transformation of $N_{\\uparrow(\\downarrow)}$ as our symmetry generators, as it corresponds to a sum of Pauli strings rather than a single string. However, we can use any function of those, for example $g_{\\uparrow(\\downarrow)} = e^{\\pi i \\hat{N}_{\\uparrow(\\downarrow)}}$, which, up to a global phase, gives the generators chosen above.\n", - "
\n" - ] - }, - { - "cell_type": "markdown", - "id": "7c2a581d-951b-4f97-aa5a-238bf14ddc1e", - "metadata": {}, - "source": [ - "Let us define and verify our generators, including their commutation relation with the Hamiltonian:" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "9a0d6f48-4bec-49ee-9f12-fc9ddb70ffab", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:04.301199Z", - "start_time": "2025-04-10T09:34:04.291617Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Up number generator:\n", - "1.0 [Z0 Z2 Z4 Z6 Z8]\n", - "Norm of commutator with the Hamiltonian 0.0\n", - "========================================\n", - "Down number generator:\n", - "1.0 [Z1 Z3 Z5 Z7 Z9]\n", - "Norm of commutator with the Hamiltonian 0.0\n" - ] - } - ], - "source": [ - "from openfermion import QubitOperator\n", - "from openfermion.utils import commutator\n", - "\n", - "## Total number operator\n", - "up_number_generator = QubitOperator(\n", - " tuple([(2 * k, \"Z\") for k in range(n_qubits // 2)]), 1.0\n", - ")\n", - "up_number_generator.compress(1e-13) # for removing small terms and zero imaginary ones\n", - "print(\"Up number generator:\")\n", - "print(*up_number_generator, sep=\"+\")\n", - "print(\n", - " f\"Norm of commutator with the Hamiltonian {commutator(qubit_hamiltonian, up_number_generator).induced_norm(1)}\"\n", - ")\n", - "print(\"=\" * 40)\n", - "\n", - "## S_z operator\n", - "down_number_generator = QubitOperator(\n", - " tuple([(2 * k + 1, \"Z\") for k in range(n_qubits // 2)]), 1.0\n", - ")\n", - "down_number_generator.compress(\n", - " 1e-13\n", - ") # for removing small terms and zero imaginary ones\n", - "print(\"Down number generator:\")\n", - "print(*down_number_generator, sep=\"+\")\n", - "print(\n", - " f\"Norm of commutator with the Hamiltonian {commutator(qubit_hamiltonian, down_number_generator).induced_norm(1)}\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "dc71b705-5afb-4636-9267-63edafc7b25f", - "metadata": {}, - "source": [ - "Now, for the given set of generators $\\left\\{g^{(i)}\\right\\}$, which are assumed to be single Pauli strings, we search for a set of single qubit Pauli $X$ operators, $\\left\\{ X_{m^{(i)}} \\right\\}$, such that $g^{(i)} X_{m^{(j)}}= (-1)^{\\delta_{ij}} X_{m^{(j)}}g^{(i)} $. Below we hard-code and verify those operators. A full algorithm is given in the Appendix of this notebook. " - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "865f5834-8a68-49f0-a20b-c4650f5e1610", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:04.310463Z", - "start_time": "2025-04-10T09:34:04.299568Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The set of Pauli X operators: [[((0, 'X'),)], [((1, 'X'),)]]\n", - "=================================================================\n", - "Pauli X_0 and generator 0 commutator: -2j [Y0 Z2 Z4 Z6 Z8]\n", - "Pauli X_0 and generator 1 commutator: 0\n", - "Pauli X_1 and generator 0 commutator: 0\n", - "Pauli X_1 and generator 1 commutator: -2j [Y1 Z3 Z5 Z7 Z9]\n" - ] - } - ], - "source": [ - "sym_generators = [\n", - " up_number_generator,\n", - " down_number_generator,\n", - "]\n", - "\n", - "single_pauli_xops = [QubitOperator((0, \"X\"), 1), QubitOperator((1, \"X\"), 1)]\n", - "print(\n", - " f\"The set of Pauli X operators: {[list(op.terms.keys()) for op in single_pauli_xops]}\"\n", - ")\n", - "print(\"=\" * 65)\n", - "for pauli_x in single_pauli_xops:\n", - " x_position = list(pauli_x.terms.keys())[0][0][0]\n", - " for j in range(len(sym_generators)):\n", - " print(\n", - " f\"Pauli X_{x_position} and generator {j} commutator: {commutator(pauli_x, sym_generators[j])}\"\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "debb3f40-ddc3-4369-8483-9e33385ca2b7", - "metadata": {}, - "source": [ - "#### Step 2: Defining a block-diagonalizing unitary\n", - "\n", - "Given the generators and the corresponding single Pauli X operators, we define the Clifford operator:\n", - "$$\n", - "\\Pi^k_{i=1}\\frac{1}{\\sqrt{2}}\\left(X_{m^{(i)}}+g^{(i)}\\right).\n", - "$$\n" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "2f07b959-99d1-44ef-9931-abbc9d74ba98", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:04.310753Z", - "start_time": "2025-04-10T09:34:04.302707Z" - } - }, - "outputs": [], - "source": [ - "block_diagonalizing_clifford = QubitOperator((), 1)\n", - "for gen, pauli_x in zip(sym_generators, single_pauli_xops):\n", - " block_diagonalizing_clifford *= (2 ** (-0.5)) * (pauli_x + gen)" - ] - }, - { - "cell_type": "markdown", - "id": "c1fec77e-40b9-4e4b-a6e8-bc0255380012", - "metadata": {}, - "source": [ - "Let us verify, for example, that indeed this diagonalizing operator map each generator into a single computational basis subspace:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "60e07b4c-08b8-4cda-bf58-ae28a2bb104c", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:04.310884Z", - "start_time": "2025-04-10T09:34:04.305930Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Generator in the new basis: 1.0000000000000004 [X0]\n", - "Generator in the new basis: 1.0000000000000004 [X1]\n" - ] - } - ], - "source": [ - "def clifford_transform(clifford: QubitOperator, qubit_op: QubitOperator):\n", - " transformed_op = clifford * qubit_op * clifford\n", - " transformed_op.compress(1e-13)\n", - " return transformed_op\n", - "\n", - "\n", - "for gen in sym_generators:\n", - " print(\n", - " \"Generator in the new basis:\",\n", - " clifford_transform(block_diagonalizing_clifford, gen),\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "27c1f9d6-04f3-416e-bb4d-70308cc0f378", - "metadata": {}, - "source": [ - "#### Step 3: Transforming the Hamiltonian\n", - "\n", - "Finally, we can now block-diagonalize the Hamiltonian. We shall see that after transformation, the Hamiltonian acts trivially on some of the qubits, with the identity or with the $\\left\\{X_{m^{(i)}}\\right\\}$ operators found above. Thus, we can reduce by going to one of the two eigenspaces of these operators, with eigenvalues $\\pm 1$.\n", - "\n", - "Which eigenspace to choose? We will answer this question in the next step." - ] - }, - { - "cell_type": "markdown", - "id": "e109eb96-2247-4010-93a9-c08479104b67", - "metadata": {}, - "source": [ - "Let us block-diagonalize our Hamiltonian:" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "766c80a2-8da2-4de9-8546-46a1e41626f1", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:04.408315Z", - "start_time": "2025-04-10T09:34:04.335407Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Example of Pauli Hamiltonian terms:\n", - "((), -5.750184614764154)\n", - "(((0, 'X'), (2, 'Z'), (4, 'Z'), (6, 'Z'), (8, 'Z')), -0.29670485079927417)\n", - "(((1, 'X'), (2, 'X'), (3, 'Z'), (4, 'Z'), (5, 'Z'), (6, 'Z'), (7, 'Z'), (8, 'Z'), (9, 'Z')), 0.0025472629069889564)\n", - "(((0, 'X'), (1, 'X'), (2, 'X'), (3, 'Z'), (5, 'Z'), (7, 'Z'), (9, 'Z')), -0.0025472629069889564)\n", - "(((1, 'X'), (8, 'X'), (9, 'Z')), 0.01778020141438095)\n", - "(((0, 'X'), (1, 'X'), (2, 'Z'), (4, 'Z'), (6, 'Z'), (8, 'X'), (9, 'Z')), -0.01778020141438095)\n", - "(((1, 'X'), (3, 'Z'), (5, 'Z'), (7, 'Z'), (9, 'Z')), -0.29670485079927417)\n", - "(((2, 'Z'), (3, 'X'), (5, 'Z'), (7, 'Z'), (9, 'Z')), 0.0025472629069889516)\n" - ] - } - ], - "source": [ - "block_diagonal_hamiltonian = clifford_transform(\n", - " block_diagonalizing_clifford, qubit_hamiltonian\n", - ")\n", - "print(\"Example of Pauli Hamiltonian terms:\")\n", - "print(*list(block_diagonal_hamiltonian.terms.items())[:8], sep=\"\\n\")" - ] - }, - { - "cell_type": "markdown", - "id": "6219a4d9-38ad-4077-af16-cd17c3ab3b01", - "metadata": {}, - "source": [ - "We can see that on the first and second qubits we have only $X$ operations." - ] - }, - { - "cell_type": "markdown", - "id": "5d87e60f-05a2-43e0-ac1e-f7edee2b37f9", - "metadata": {}, - "source": [ - "#### Step 4: Tapering-off qubits\n" - ] - }, - { - "cell_type": "markdown", - "id": "1b0aa0ec-dcc7-441b-8c93-4ae463c325c6", - "metadata": {}, - "source": [ - "Next, we can taper-off the Hamiltonian by using `openfermion` built-in function `taper_off_qubits`. We shall choose a sector, i.e., the $+1$ or $-1$ subspace, by modifying the signs of the $X$ operations. To emphasize the effect of choosing different sectors, we construct 4 tapered operators, each for the subspaces (sectors) $\\pm 1 \\otimes \\pm 1$, and classically calculate the ground state for each tapered Hamiltonian." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "4a91ae80-5c68-41f4-9766-4dfae3c1355d", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:06.321192Z", - "start_time": "2025-04-10T09:34:04.353651Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "For sector (1, 1): minimal eigenvalue: (-7.768908584655515+9.448436663467506e-30j)\n", - "For sector (1, -1): minimal eigenvalue: (-7.8049924143578036+0j)\n", - "For sector (-1, 1): minimal eigenvalue: (-7.804992414357779+2.5464948796165245e-29j)\n", - "For sector (-1, -1): minimal eigenvalue: (-7.88041605396157+0j)\n" - ] - } - ], - "source": [ - "import itertools\n", - "\n", - "import numpy as np\n", - "from openfermion.linalg import get_sparse_operator\n", - "from openfermion.transforms import taper_off_qubits\n", - "\n", - "for sector in itertools.product([1, -1], repeat=len(single_pauli_xops)):\n", - " tapered_hamiltonian = taper_off_qubits(\n", - " block_diagonal_hamiltonian,\n", - " [sector[i] * single_pauli_xops[i] for i in range(len(sector))],\n", - " )\n", - " tapered_hamiltonian.compress(1e-13)\n", - " tapered_hamiltonian_sparse = get_sparse_operator(tapered_hamiltonian)\n", - " w, v = np.linalg.eig(tapered_hamiltonian_sparse.toarray())\n", - " print(f\"For sector {sector}: minimal eigenvalue: {np.min(w)}\")" - ] - }, - { - "cell_type": "markdown", - "id": "8ab8556e-c633-4e8e-a00f-3f5a29dbd9ab", - "metadata": {}, - "source": [ - "##### Finding the optimal sector\n", - "\n", - "Qubit tapering should include a choice of eigenspace sector. In VQE we are looking for the minimal energy of the Hamiltonian, thus, we should find the sector containing the ground state. One possibility is to run multiple VQEs on all sectors. However, another approach is to fix the sector according to the HF state, which is assumed to be in the optimal sector.\n", - "\n", - "Let us define a function that determines which sector contains the HF state, by applying the symmetry generators on it. The function returns the signed $X$ operators for the optimal sector." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "bad58562-2475-4912-af61-df582ae47988", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:06.387456Z", - "start_time": "2025-04-10T09:34:06.346124Z" - } - }, - "outputs": [], - "source": [ - "def get_optimal_sector_xops(hf_str, sym_generators, x_ops, n_qubits):\n", - " hf_arr = np.array(list(hf_str), dtype=int)\n", - " optimal_sector = []\n", - " for gen in sym_generators:\n", - " z_locations = np.zeros(n_qubits)\n", - " for term in gen.terms.keys():\n", - " z_locations[[t[0] for t in term if t[1] == \"Z\"]] = 1\n", - " n_overlaps = sum(\n", - " np.logical_and(z_locations, hf_arr)\n", - " ) # number of overlapping Z and excitation\n", - " eig = 1 - 2 * (n_overlaps % 2)\n", - " optimal_sector.append(eig)\n", - "\n", - " print(f\"Optimal sector {optimal_sector}\")\n", - "\n", - " return [optimal_sector[i] * x_ops[i] for i in range(len(optimal_sector))]" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "317039d3-5d1d-481b-b01a-e2ce375ffae9", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:06.404597Z", - "start_time": "2025-04-10T09:34:06.390263Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimal sector [-1, -1]\n", - "The optimal sector X operators: [-1 [X0], -1 [X1]]\n" - ] - } - ], - "source": [ - "optimal_sector_xops = get_optimal_sector_xops(\n", - " hf_str, sym_generators, single_pauli_xops, n_qubits\n", - ")\n", - "print(f\"The optimal sector X operators: {optimal_sector_xops}\")" - ] - }, - { - "cell_type": "markdown", - "id": "a24bb9f9-a740-4b71-87a2-c98ccf7c651b", - "metadata": {}, - "source": [ - "***\n", - "## Part C: Constructing a VQE model with Classiq\n", - "***" - ] - }, - { - "cell_type": "markdown", - "id": "dd8b2a82-6e33-4e34-a52e-09b7d381c069", - "metadata": {}, - "source": [ - "Next, we use all the classical pre-processing from the previous sections to build, synthesize, and execute a VQE model.\n", - "We will take the following steps:\n", - "1. Defining the transformed and tapered-off Hartree Fock state, which serves as an initial condition for the problem.\n", - "2. Constructing the transformed and tapered-off UCC ansatz.\n", - "3. Defining, synthesizing, and executing the full model\n", - "\n", - "**For steps 1 and 2, we will have to perform all the transformation defined above (see diagram of at the top of Part B).**\n" - ] - }, - { - "cell_type": "markdown", - "id": "ce6ec31f-3104-4556-9657-09bb4d19bcf1", - "metadata": {}, - "source": [ - "As a preliminary step, we define the Hamiltonian of the VQE problem. Since this is the final Hamiltonian (after a series of transformation, from second quantized Hamiltonian, tapering, etc.), let us trim small values according to some rough threshold." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "cc06fd7c-0a20-4aab-bb9c-5af616d78e2f", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:07.457664Z", - "start_time": "2025-04-10T09:34:06.407353Z" - } - }, - "outputs": [], - "source": [ - "from classiq import *\n", - "\n", - "pauli_char_to_obj = {\"I\": Pauli.I, \"Z\": Pauli.Z, \"X\": Pauli.X, \"Y\": Pauli.Y}\n", - "\n", - "\n", - "def qubit_op_to_hamiltonian(qbit_op, n_qubits):\n", - " \"\"\"Convert OpenFermion QubitOperator to list of PauliTerm\"\"\"\n", - " hamiltonian = []\n", - "\n", - " for term, coeff in qbit_op.terms.items():\n", - "\n", - " pauli_list = [Pauli.I] * n_qubits # Default to identity\n", - "\n", - " for qubit, pauli in term:\n", - " pauli_list[qubit] = pauli_char_to_obj[pauli] # Replace with correct Pauli\n", - "\n", - " # Append list-style Pauli term\n", - " hamiltonian.append(PauliTerm(pauli=pauli_list[::-1], coefficient=coeff))\n", - "\n", - " return hamiltonian" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "b5fbeafb-a4c3-41ba-b911-a4c4cf86abdd", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:07.466879Z", - "start_time": "2025-04-10T09:34:07.464817Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Removed positions after tapering: [0, 1]\n", - "Hamiltonian for VQE has: 260 terms, and is operating on 8 qubits\n" - ] - } - ], - "source": [ - "THRESHOLD = 1e-3\n", - "\n", - "tapered_hamiltonian, removed_positions = taper_off_qubits(\n", - " block_diagonal_hamiltonian, optimal_sector_xops, output_tapered_positions=True\n", - ")\n", - "tapered_hamiltonian.compress(THRESHOLD)\n", - "print(f\"Removed positions after tapering: {removed_positions}\")\n", - "\n", - "n_vqe_qubits = n_qubits - len(sym_generators)\n", - "vqe_hamiltonian = qubit_op_to_hamiltonian(tapered_hamiltonian, n_vqe_qubits)\n", - "\n", - "print(\n", - " f\"Hamiltonian for VQE has: {len(vqe_hamiltonian)} terms, and is operating on {n_vqe_qubits} qubits\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "9d7a6358-4dd6-4d7f-bc05-7e4a5d9982cd", - "metadata": {}, - "source": [ - "The Hartree Fock and the UCC operators that are defined below do not necessarily have the same symmetries of the molecular Hamiltonian. Thus, after the Clifford transformation, the resulting operators are not restricted to the symmetries' subspaces. We will take the following approach: we remove terms which do not satisfy the symmetry relation, i.e., commute with symmetry generators. We define a function that checks whether an operator commutes with a given set of symmetry generators. We distinguish between two cases: removing the entire operator or removing only the non-invariant terms. The former is particularly important in the context of UCC ansatz, where preserving Hermiticity requires retaining or discarding operators as whole units:" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "7301e98b-78cf-4fc4-ae0e-acca25e27b64", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:07.469329Z", - "start_time": "2025-04-10T09:34:07.468067Z" - } - }, - "outputs": [], - "source": [ - "from openfermion.ops import QubitOperator\n", - "from openfermion.utils import commutator\n", - "\n", - "\n", - "def project_to_sym_space(\n", - " operator: QubitOperator, sym_gen: list[QubitOperator], all_terms: bool = False\n", - "):\n", - " if all_terms:\n", - " for gen in sym_gen:\n", - " if commutator(operator, gen).induced_norm(1) != 0:\n", - " return QubitOperator()\n", - " return operator\n", - " else:\n", - " new_op = QubitOperator()\n", - " for term, coeff in operator.terms.items():\n", - " single_term_op = QubitOperator(term, coeff)\n", - " if all(\n", - " commutator(single_term_op, gen).induced_norm(1) == 0 for gen in sym_gen\n", - " ):\n", - " new_op += single_term_op\n", - " return new_op if new_op.terms else QubitOperator()" - ] - }, - { - "cell_type": "markdown", - "id": "9a21a5ca-ba62-430d-a974-b329167bca66", - "metadata": {}, - "source": [ - "### 1. Hartree Fock in the tapered-off space" - ] - }, - { - "cell_type": "markdown", - "id": "dc4c9f46-3df7-4bc7-aeb6-475137227388", - "metadata": {}, - "source": [ - "We have already calculated the HF state under the JW transform, let us find the HF state after qubit tapering:" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "95d2c170-f3bc-41c5-8ce6-93b891547752", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:07.472220Z", - "start_time": "2025-04-10T09:34:07.470707Z" - } - }, - "outputs": [], - "source": [ - "hf_projected_operator = project_to_sym_space(hf_operator, sym_generators)\n", - "hf_tapered_operator = taper_off_qubits(\n", - " clifford_transform(block_diagonalizing_clifford, hf_projected_operator),\n", - " optimal_sector_xops,\n", - ")\n", - "hf_tapered_operator.compress(THRESHOLD)" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "83439fef-d0d4-464e-9694-26c89b81fd3e", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:34:07.475027Z", - "start_time": "2025-04-10T09:34:07.473300Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The HF state: 00000000\n" - ] - } - ], - "source": [ - "hf_tapered_state = qubit_operation_on_zero_state(hf_tapered_operator, n_vqe_qubits)\n", - "assert (\n", - " len(hf_tapered_state) == 1\n", - "), f\"The resulting HF state is not a single computationa state, got {hf_tapered_state}\"\n", - "hf_str_tapered = list(hf_tapered_state.keys())[0]\n", - "print(f\"The HF state: {hf_str_tapered}\")" - ] - }, - { - "cell_type": "markdown", - "id": "a18ee148-88c5-43f6-be6d-390e4c4542b0", - "metadata": {}, - "source": [ - "### 2. UCC ansatz" - ] - }, - { - "cell_type": "markdown", - "id": "fdccea00-14a0-4419-8762-c58ad3d2863e", - "metadata": {}, - "source": [ - "The Unitary Coupled Cluster ansatz assumes the initial state is the HF state. Then, it includes excitations from the occupied to un-occupied states, where the former is defined by the HF state. In this tutorial we focus on the UCCSD ansatz, in which only singlet and doublet excitation are taken. The corresponding Fermionic operator reads:\n", - "\n", - "$$\n", - "\\large U_{\\text{UCCSD}} \\equiv e^{T - T^\\dagger}, \\qquad T = T_1 + T_2\n", - "$$\n", - "where:\n", - "$$\n", - "\\large T_1 = \\sum_{i \\in \\text{occ}} \\sum_{a \\in \\text{virt}} t_i^a a_a^\\dagger a_i, \\qquad T_2 = \\sum_{i None:\n", - " allocate(n_vqe_qubits, state)\n", - " state ^= int(\n", - " hf_str_tapered[::-1], 2\n", - " ) # to avoid binding to QArray and repeat over bitstring\n", - "\n", - " hamiltonian_ansatz_paulis = []\n", - " hamiltonian_ansatz_coefficients = []\n", - " for i in range(num_params):\n", - " for k in range(len(ucc_tapered_hamiltonians[i])):\n", - " hamiltonian_ansatz_paulis.append(ucc_tapered_hamiltonians[i][k].pauli)\n", - " hamiltonian_ansatz_coefficients.append(\n", - " np.real(ucc_tapered_hamiltonians[i][k].coefficient) * params[i]\n", - " )\n", - "\n", - " # It is common, but not necessary, to use first order Suzuki-Trotter\n", - " parametric_suzuki_trotter(\n", - " hamiltonian_ansatz_paulis,\n", - " hamiltonian_ansatz_coefficients,\n", - " evolution_coefficient=-1.0,\n", - " order=1,\n", - " repetitions=1,\n", - " qbv=state,\n", - " )\n", - "\n", - "\n", - "qmod = create_model(main, out_file=\"vqe_ucc\" + description)\n", - "qprog = synthesize(qmod)\n", - "show(qprog)" - ] - }, - { - "cell_type": "markdown", - "id": "37eb1634-f1c3-48b9-86a6-ab906eabedfc", - "metadata": {}, - "source": [ - "To get a quick execution, we run on a statevector simulator." - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "d419f218-ecf2-410f-b0f2-458f886fb376", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:35:45.515839Z", - "start_time": "2025-04-10T09:34:29.913691Z" - } - }, - "outputs": [], - "source": [ - "qprog = set_quantum_program_execution_preferences(\n", - " qprog,\n", - " preferences=ExecutionPreferences(\n", - " num_shots=1000,\n", - " backend_preferences=ClassiqBackendPreferences(\n", - " backend_name=\"simulator_statevector\"\n", - " ),\n", - " ),\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "f8ec528b-62aa-4bce-a05c-099bd18485e0", - "metadata": {}, - "source": [ - "We run simple optimization using `scipy` and `ExecutionSession` " - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "id": "be3a2bde-cbfc-4ba3-ae73-c232edae431f", - "metadata": {}, - "outputs": [], - "source": [ - "from scipy.optimize import minimize\n", - "\n", - "from classiq.execution import ExecutionSession\n", - "\n", - "global intermidiate\n", - "intermediate = []\n", - "\n", - "with ExecutionSession(qprog) as es:\n", - "\n", - " def my_cost(es, params):\n", - " execution_params = {\"params\": params.tolist()}\n", - " energy_value = es.estimate(vqe_hamiltonian, execution_params).value\n", - " cost = np.real(energy_value)\n", - " intermediate.append({\"params\": tuple(params), \"energy\": energy_value})\n", - " return cost\n", - "\n", - " out = minimize(\n", - " lambda x: my_cost(es, x),\n", - " x0=[0] * num_params, # we perturbe the HF state, so we start with no evolution\n", - " method=\"COBYLA\",\n", - " options={\"maxiter\": 200},\n", - " tol=TOL,\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "483487d4-f48c-4457-b89e-a374fff282e3", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:35:45.612248Z", - "start_time": "2025-04-10T09:35:45.518189Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "optimizer result classiq: -7.880198058917717\n" - ] - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "expected_energy = float(molecule.fci_energy)\n", - "\n", - "optimizer_res = out.fun\n", - "print(f\"optimizer result classiq: {optimizer_res}\")\n", - "\n", - "vqe_results = {k: np.real(intermediate[k][\"energy\"]) for k in range(len(intermediate))}\n", - "\n", - "\n", - "plt.plot(vqe_results.keys(), vqe_results.values(), \"-\")\n", - "plt.ylabel(\"Energy [Ha]\", fontsize=16)\n", - "plt.xlabel(\"iteration\", fontsize=16)\n", - "plt.tick_params(axis=\"both\", labelsize=16)\n", - "plt.title(\"VQE result for \" + description)\n", - "plt.text(\n", - " 50,\n", - " -7.75,\n", - " f\"vqe energy: {optimizer_res} Ha,\\n fci_energy: {expected_energy} Ha\",\n", - " fontsize=12,\n", - " bbox=dict(facecolor=\"lightgray\", edgecolor=\"black\", boxstyle=\"round,pad=0.3\"),\n", - ");" - ] - }, - { - "cell_type": "markdown", - "id": "4a76a3a4-980d-4197-81ef-231a926bbbad", - "metadata": {}, - "source": [ - "## Appendix A - Techical details on qubit tapering\n", - "\n", - "Below we provide some technical details concerning qubit tapering and $\\mathbb{Z}_2$ symmetries.\n", - "\n", - "It is a well-known fact in linear algebra that if two operators commute, $[A,B]=0$, then they can be mutually diagonalized. In particular, if $|v\\rangle$ is an eigenvector of $B$ with an eigenvalue $\\lambda$, we have\n", - "$$\n", - "[A,B]=0\\implies AB = BA \\implies AB|v\\rangle = BA|v\\rangle \\implies \\lambda \\left(A|v\\rangle\\right) = B\\left(A|v\\rangle\\right).\n", - "$$\n", - "That is, $A|v\\rangle$ is also an eigenvector of $B$ with eigenvalue $\\lambda$. Thus, $A|v\\rangle$ must be in the eigenspace $V_{\\lambda} \\equiv \\left\\{|u\\rangle, B|u\\rangle = \\lambda|u\\rangle\\right\\}$.\n", - "\n", - "Now, Refs. [[3](#sym1)] and [[4](#sym2)] show, and this is implemented explicitly in Appendix B, that we can find a Clifford transformation $U$, such that the transformed Hamiltonian $H'=U^{\\dagger} H U$ commutes with the transformed symmetries $X_{m^{(i)}} = U^{\\dagger} g_i U$. We know how the eigenspaces of $X_{m^{(i)}}$ look like. For example, $X_{0}$ has two eigenspaces that correspond to the eigenvalues $\\pm 1$: $V_{\\pm} = \\left\\{|u\\rangle_N, X_{0}|u\\rangle_N = \\pm |u\\rangle_N\\right\\} = \\left\\{|\\pm\\rangle \\otimes |\\tilde{u}\\rangle_{N-1},\\, |\\tilde{u}\\rangle_{N-1} \\text{ some state on } N-1 \\text{ qubits}\\right\\} $. From the arguments above we get that \n", - "$$\n", - "H'\\cdot \\left(|\\pm\\rangle |u\\rangle\\right) \\in V_{\\pm},\n", - "$$\n", - "which means that $H'$ must acts with $X_0$ or the Identity on the first qubit." - ] - }, - { - "cell_type": "markdown", - "id": "86be434c-f86f-4b8c-b8fc-0b0de99bcdc9", - "metadata": {}, - "source": [ - "## Appendix B - generic approach for finding $\\mathbb{Z}_2$ symmetries " - ] - }, - { - "cell_type": "markdown", - "id": "aa63d239-6f87-4bb6-8451-0f65a72d3568", - "metadata": {}, - "source": [ - "Below we provide some classical functions for finding symmetry generators for a given Hamiltonian, and the corresponding Pauli $X$ operators. The code is based on the algorithm provided in Ref. [[3](#sym1)] (see also Ref. [[4](#sym2)]). The theory behind the algorithm is described here in some detail. We provide a unified function `find_z2_symmetries`, that accepts a Hamiltonian and returns generators and $X$ operators." - ] - }, - { - "cell_type": "markdown", - "id": "b3d7ac46-1469-46d2-9767-ef85efa72bb6", - "metadata": {}, - "source": [ - "### Moving to (x,z) representation" - ] - }, - { - "cell_type": "markdown", - "id": "b1161d49-c638-4963-bff2-1fc64b6a0880", - "metadata": {}, - "source": [ - "The convenient framework for finding $\\mathbb{Z}_2$ symmetries is the $(x,z)$ representation of Pauli strings. In this representation we map a Pauli matrix to two binaries, $\\sigma \\rightarrow (a_x, a_z)$, according to \n", - "$$\n", - "I\\rightarrow (0,0),\\quad Z\\rightarrow (0,1),\\quad X\\rightarrow (1,0),\\quad Y\\rightarrow (1,1),\n", - "$$\n", - "and a Pauli string on $N$ qubits $\\vec{\\sigma}$ is mapped to $2N$ binary vector $(\\vec{a}_x, \\vec{a}_z)$. We have that two Pauli strings, $(\\vec{a}_x, \\vec{a}_z)$ and $(\\vec{b}_x, \\vec{b}_z)$, commutes, if $\\vec{a}_x \\vec{b}_z + \\vec{a}_z \\vec{b}_x = 0 \\,\\bmod{2}$. Thus, we can find the symmetry generators of an Hamiltonian by the following procedure:\n", - "\n", - "1. Construct a binary matrix for the Hamiltonian. A Hamiltonian with $r$ terms on $N$ qubits corresponds to $r\\times 2N$ binary matrix.\n", - "2. Find the kernel (null space) of this matrix (by a Guass elimination). Then, each kernel vector $(g_z,g_x)$ (note the switch in $x,z$ positions) correspond to a Pauli string that commutes with all the Hamiltonian elements.\n", - "3. For the $X$ operators, a simple procedure can be carried on within the $(x,z)$ representation.\n" - ] - }, - { - "cell_type": "markdown", - "id": "ccd1ee07-21ad-47e2-9f05-b99ba84c6c4a", - "metadata": {}, - "source": [ - "As a preliminary step, we start with two functions, transforming between operator and $(x,z)$ representations:" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "id": "02e4630d-7c6e-443a-8bde-9a988a26e6bb", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:35:45.616192Z", - "start_time": "2025-04-10T09:35:45.614972Z" - } - }, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "bin_to_op = {(0, 1): \"Z\", (1, 1): \"Y\", (1, 0): \"X\"}\n", - "\n", - "\n", - "def pauli_to_xz(qubit_op: QubitOperator, n_qubits: int):\n", - " \"\"\"\n", - " Convert a single Pauli string of size n_qubits (QubitOperator of length 1) to its (x,z) bits.\n", - " \"\"\"\n", - "\n", - " if len(qubit_op.terms) != 1:\n", - " raise ValueError(\n", - " \"Expected a single-term QubitOperator for a Z2 symmetry generator.\"\n", - " )\n", - "\n", - " ((pauli_term, coeff),) = qubit_op.terms.items()\n", - "\n", - " # Initialize bits\n", - " x_bits = [0] * n_qubits\n", - " z_bits = [0] * n_qubits\n", - " if abs(coeff) < 1e-14:\n", - " # Then it's effectively identity or zero operator\n", - " # Just return identity bits\n", - " return x_bits, z_bits\n", - "\n", - " for qubit_idx, pauli_str in pauli_term:\n", - " if pauli_str == \"X\":\n", - " x_bits[qubit_idx] = 1\n", - " z_bits[qubit_idx] = 0\n", - " elif pauli_str == \"Y\":\n", - " x_bits[qubit_idx] = 1\n", - " z_bits[qubit_idx] = 1\n", - " elif pauli_str == \"Z\":\n", - " x_bits[qubit_idx] = 0\n", - " z_bits[qubit_idx] = 1\n", - "\n", - " return x_bits, z_bits\n", - "\n", - "\n", - "def qubit_op_to_xz(qubit_op: QubitOperator, n_qubits: int):\n", - " \"\"\"\n", - " Return an ndarray of shape (len(qubit_op), 2*n_qubits), each row is (x_bits|z_bits).\n", - " \"\"\"\n", - " op_size = len(qubit_op.terms)\n", - " binary_mat = np.zeros((op_size, 2 * n_qubits), dtype=int)\n", - "\n", - " for row, term in enumerate(qubit_op):\n", - " x_bits, z_bits = pauli_to_xz(term, n_qubits)\n", - " # Fill the row\n", - " # We put x_bits in columns [0..n_qubits-1], z_bits in columns [n_qubits..2*n_qubits-1]\n", - " binary_mat[row, :n_qubits] = x_bits\n", - " binary_mat[row, n_qubits:] = z_bits\n", - "\n", - " return binary_mat\n", - "\n", - "\n", - "def xz_to_opt(binary_matrix: np.ndarray):\n", - " \"\"\"\n", - " Return an ndarray of shape (n_sym, 2*n_qubits), each row is (x_bits|z_bits).\n", - " \"\"\"\n", - " binary_matrix = binary_matrix[\n", - " ~np.all(binary_matrix == 0, axis=1)\n", - " ] # remove all-zero rows (Identity)\n", - " qubit_op = QubitOperator()\n", - " n_rows, n_cols = binary_matrix.shape\n", - " n_qubits = n_cols // 2\n", - " for raw in binary_matrix:\n", - " op = [\n", - " (i, bin_to_op[(raw[i], raw[n_qubits + i])])\n", - " for i in range(n_qubits)\n", - " if (raw[i], raw[n_qubits + i]) != (0, 0)\n", - " ]\n", - " qubit_op += QubitOperator(tuple(op), 1)\n", - "\n", - " return qubit_op" - ] - }, - { - "cell_type": "markdown", - "id": "f8208bb0-7d95-49eb-a684-adc6d8a52ce9", - "metadata": {}, - "source": [ - "### Finding the null space for the Hamiltonian" - ] - }, - { - "cell_type": "markdown", - "id": "2e6c365b-a9c3-41a4-a5cf-fa4fec05cd26", - "metadata": {}, - "source": [ - "The null space of the Hamiltonian in the $(x,z)$ representation can be found using two steps:\n", - "\n", - "1. First, get the Reduced Row Echelon Form (RREF) of the matrix. In this form we have:\n", - " * Every nonzero row has a leading 1.\n", - " * Each leading 1 is the only nonzero entry in its column.\n", - " * Rows of all zeros (if any) appear at the bottom of the matrix.\n", - "2. Then, in RREF it is easy to check and apply the null space equations." - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "589357f3-2aac-4ce1-9cfc-5d77e0405508", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:35:45.621456Z", - "start_time": "2025-04-10T09:35:45.620113Z" - } - }, - "outputs": [], - "source": [ - "def get_rref(binary_matrix):\n", - " r\"\"\"Returns the reduced row echelon form (RREF) of a matrix over the binary finite field :math:`\\mathbb{Z}_2`.\n", - "\n", - " Args:\n", - " binary_matrix (np.ndarray): Binary matrix (dtype=int) to be reduced. Each entry should be 0 or 1.\n", - "\n", - " Returns:\n", - " np.ndarray: The RREF of the given `binary_matrix` over :math:`\\mathbb{Z}_2`.\n", - "\n", - " \"\"\"\n", - " # Make a copy, so we don't modify the original matrix.\n", - " rref_binary_mat = binary_matrix.copy()\n", - " shape = rref_binary_mat.shape\n", - " n_rows, n_cols = shape\n", - " icol = 0\n", - "\n", - " # Process each row.\n", - " for irow in range(n_rows):\n", - " # Find the pivot in the current row.\n", - " while icol < n_cols and rref_binary_mat[irow, icol] == 0:\n", - " # Look for a nonzero entry below in the same column.\n", - " non_zero_idx = np.nonzero(rref_binary_mat[irow:, icol])[0]\n", - " if len(non_zero_idx) == 0:\n", - " # Entire column below is zero, move to next column.\n", - " icol += 1\n", - " else:\n", - " # Swap the current row with the row containing the nonzero entry.\n", - " krow = irow + non_zero_idx[0]\n", - " rref_binary_mat[[irow, krow], icol:] = rref_binary_mat[\n", - " [krow, irow], icol:\n", - " ].copy()\n", - " # If we have a pivot, eliminate other 1s in the column.\n", - " if icol < n_cols and rref_binary_mat[irow, icol] == 1:\n", - " # Copy the pivot row's right-hand part.\n", - " rpvt_cols = rref_binary_mat[irow, icol:].copy()\n", - " # For all other rows, if they have a 1 in column icol, eliminate it by XORing.\n", - " currcol = rref_binary_mat[:, icol].copy()\n", - " currcol[irow] = 0 # Skip pivot row.\n", - " # The XOR is implemented as addition mod 2.\n", - " rref_binary_mat[:, icol:] ^= np.outer(currcol, rpvt_cols)\n", - " icol += 1\n", - "\n", - " return rref_binary_mat.astype(int)\n", - "\n", - "\n", - "def kernel_from_rref(rref_mat):\n", - " \"\"\"\n", - " Given a binary matrix in reduced row echelon form (RREF) over Z2,\n", - " return a basis for its kernel (null space) as a NumPy array.\n", - "\n", - " Each row of the returned array is a kernel vector (a basis vector for the nullspace),\n", - " with arithmetic done modulo 2.\n", - "\n", - " Args:\n", - " rref_mat (np.ndarray): A binary matrix (dtype=int) in RREF over Z2 with shape (m, n).\n", - "\n", - " Returns:\n", - " np.ndarray: A matrix of shape (n - rank, n) whose rows form a basis for the kernel.\n", - " \"\"\"\n", - "\n", - " # Remove all-zero rows\n", - " rref_mat = rref_mat[~np.all(rref_mat == 0, axis=1)]\n", - " m, n = rref_mat.shape\n", - "\n", - " # Identify pivot columns. For each row, the first nonzero entry (if any) is a pivot.\n", - " pivots = []\n", - " for i in range(m):\n", - " row = rref_mat[i]\n", - " nonzero = np.where(row == 1)[0]\n", - " if nonzero.size > 0:\n", - " pivots.append(nonzero[0])\n", - " pivots = np.array(pivots)\n", - "\n", - " # The free (non-pivot) columns:\n", - " free_cols = np.setdiff1d(np.arange(n), pivots)\n", - " num_free = free_cols.size\n", - "\n", - " # We'll build a basis for the kernel.\n", - " # For each free column, we set that free variable to 1 and the others to 0,\n", - " # then solve for the pivot variables using the RREF equations.\n", - " kernel_basis = np.zeros((num_free, n), dtype=int)\n", - "\n", - " # For each free variable, assign it the value 1.\n", - " for i, free_col in enumerate(free_cols):\n", - " kernel_basis[i, free_col] = 1\n", - "\n", - " # Now, for each pivot row in the RREF, the equation is:\n", - " # x[pivot] + sum_{j in free columns} (rref_mat[i, j] * x[j]) = 0 (mod 2)\n", - " # So, for each pivot row, if rref_mat[i, free_col]==1, we must set x[pivot] = 1 in that basis vector.\n", - " for i in range(m):\n", - " # Find pivot column for this row (if any)\n", - " nonzero = np.where(rref_mat[i] == 1)[0]\n", - " if nonzero.size == 0:\n", - " continue\n", - " pivot_col = nonzero[0]\n", - " # For every free column, if there is a 1 in that free column for the current row,\n", - " # then the pivot variable must equal 1 (because 1+1 = 0 mod2).\n", - " for basis_idx, free_col in enumerate(free_cols):\n", - " if rref_mat[i, free_col] == 1:\n", - " kernel_basis[basis_idx, pivot_col] = 1\n", - "\n", - " return kernel_basis" - ] - }, - { - "cell_type": "markdown", - "id": "47378019-cc78-406b-b22e-05407841e537", - "metadata": {}, - "source": [ - "Now, we can define a function for obtaining the list of generators for a given Hamiltonian:" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "id": "2b4162e4-4b70-49f1-a769-816d525d37fb", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:35:45.623737Z", - "start_time": "2025-04-10T09:35:45.622902Z" - } - }, - "outputs": [], - "source": [ - "from typing import List\n", - "\n", - "\n", - "def get_z2symmetry_generators(qubit_op: QubitOperator, n_qubits: int):\n", - "\n", - " binary_mat = qubit_op_to_xz(qubit_op, n_qubits)\n", - " kernel = kernel_from_rref(get_rref(binary_mat))\n", - " kernel_zx = np.hstack(\n", - " (kernel[:, n_qubits:], kernel[:, :n_qubits])\n", - " ) # swaping x and z\n", - " generators = []\n", - " for raw in kernel_zx:\n", - " generators.append(xz_to_opt(np.array([raw])))\n", - "\n", - " return generators" - ] - }, - { - "cell_type": "markdown", - "id": "3ca75151-95d1-4ce8-a746-9ba73eb73cfc", - "metadata": {}, - "source": [ - "The $\\left\\{X_{m^{(i)}}\\right\\}$ operators can be found by a simple procedure, working in the $(x,z)$ representation. We construct the binary matrix for the list of generators, for $k$ generators we have a $k\\times 2N$ binary matrix. Now, we need to find a set of $k$ binary vectors such that each vector $i$:\n", - "* Has a single 1 entry in the $m^{(i)}\\in [0,N-1]$ positions, and all other entries are zero.\n", - "* It anticommutes with the $i$-th row of the binary matrix.\n", - "* It commutes with all the other rows.\n", - "\n", - "Since we are working with a simple $\\bmod 2$ arithmetics, this can be achieved by simple steps." - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "id": "3ec8cce4-3c24-426d-ab19-3f24c8f9556b", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:35:45.627183Z", - "start_time": "2025-04-10T09:35:45.626076Z" - } - }, - "outputs": [], - "source": [ - "def get_xops_for_generators(generators: List[QubitOperator], n_qubits):\n", - "\n", - " kernel_xz = np.array([qubit_op_to_xz(gen, n_qubits)[0] for gen in generators])\n", - " n_sym = len(generators)\n", - " result_ops = [None] * n_sym\n", - " for row_idx in range(n_sym):\n", - " row_data = kernel_xz[row_idx]\n", - " # separate x/z for this row\n", - " x_row = row_data[:n_qubits]\n", - " z_row = row_data[n_qubits:]\n", - "\n", - " # The rest\n", - " rest_binary_mat = np.delete(kernel_xz, row_idx, axis=0)\n", - "\n", - " found_col = None\n", - " for col in range(n_qubits):\n", - " # We want this row to have z=1 => anticommute with X, i.e. z_row[col] should be 1\n", - " # Then for all other rows, we want them to commute with X => z=0 means they commute\n", - " if z_row[col] == 1:\n", - " # Now check rest, they must have z=0 at 'col' (col + n_qubits as we look at the z part)\n", - " z_part_rest = rest_binary_mat[:, n_qubits + col]\n", - " if np.all(z_part_rest == 0):\n", - " found_col = col\n", - " break\n", - "\n", - " if found_col is not None:\n", - " # Build QubitOperator for X on 'found_col'\n", - " qop = QubitOperator(((found_col, \"X\"),), 1.0)\n", - " result_ops[row_idx] = qop\n", - "\n", - " return result_ops" - ] - }, - { - "cell_type": "markdown", - "id": "278394fe-6cfc-4768-8610-4bc29233a9af", - "metadata": {}, - "source": [ - "### Wrapping everything together\n", - "\n", - "Finally, we define a single function that accepts a Hamiltonian and returns the symmetry generators and Pauli $X$ operators." - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "aec1b697-e89a-41ee-b826-41fab1b5232e", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:35:45.629605Z", - "start_time": "2025-04-10T09:35:45.628200Z" - } - }, - "outputs": [], - "source": [ - "def find_z2sym(qubit_op: QubitOperator, n_qubits: int):\n", - " generators = get_z2symmetry_generators(qubit_op, n_qubits)\n", - " x_ops = get_xops_for_generators(generators, n_qubits)\n", - " return generators, x_ops" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "id": "a798c77e-d573-4dda-b238-6fe51542ddaa", - "metadata": { - "ExecuteTime": { - "end_time": "2025-04-10T09:35:45.715936Z", - "start_time": "2025-04-10T09:35:45.629968Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Found 4 Z2 symmetries:\n", - "Generators: [1.0 [Z4 Z5], 1.0 [Z6 Z7], 1.0 [Z0 Z2 Z4 Z6 Z8], 1.0 [Z1 Z3 Z4 Z6 Z9]]\n", - "X operators: [1.0 [X5], 1.0 [X7], 1.0 [X0], 1.0 [X1]]\n" - ] - } - ], - "source": [ - "generators, x_ops = find_z2sym(qubit_hamiltonian, n_qubits)\n", - "print(f\"Found {len(generators)} Z2 symmetries:\")\n", - "print(f\"Generators: {generators}\")\n", - "print(f\"X operators: {x_ops}\")" - ] - }, - { - "cell_type": "markdown", - "id": "ae8b67b0-cae1-4c12-b9c9-5a2fcea92ccf", - "metadata": {}, - "source": [ - "## Appendix C - Loading molecule geometry" - ] - }, - { - "cell_type": "markdown", - "id": "5d6d0e77-d21d-49e1-a29b-57542c67d543", - "metadata": {}, - "source": [ - "```\n", - "from rdkit import Chem\n", - "from rdkit.Chem import AllChem\n", - "\n", - "# Generate 3D coordinates\n", - "mol = Chem.MolFromSmiles('[LiH]')\n", - "mol = Chem.AddHs(mol)\n", - "AllChem.EmbedMolecule(mol)\n", - "\n", - "# Prepare XYZ string\n", - "conf = mol.GetConformer()\n", - "n_atoms = mol.GetNumAtoms()\n", - "\n", - "xyz_lines = [f\"{n_atoms}\", \"LiH generated by RDKit\"]\n", - "\n", - "for atom in mol.GetAtoms():\n", - " idx = atom.GetIdx()\n", - " pos = conf.GetAtomPosition(idx)\n", - " line = f\"{atom.GetSymbol()} {pos.x:.6f} {pos.y:.6f} {pos.z:.6f}\"\n", - " xyz_lines.append(line)\n", - "\n", - "xyz_string = \"\\n\".join(xyz_lines)\n", - "\n", - "# Save to file\n", - "with open(\"lih.xyz\", \"w\") as f:\n", - " f.write(xyz_string)\n", - "```" - ] - }, - { - "cell_type": "markdown", - "id": "31a03a50-0d15-4bd5-a9ef-e52718b26420", - "metadata": {}, - "source": [ - "## References\n", - "\n", - "[1]: [McClean et. al. Quantum Sci. Technol. 5 034014 (2020). OpenFermion: the electronic structure package for quantum computers.](https://arxiv.org/abs/1710.07629)\n", - "\n", - "[2]: [Introduction to OpenFermion.](https://quantumai.google/openfermion/tutorials/intro_to_openfermion)\n", - "\n", - "[3]: [Bravyi et. al., arXiv preprint arXiv:1701.08213 (2017). Tapering off qubits to simulate fermionic Hamiltonians.\n", - "](https://arxiv.org/abs/1701.08213)\n", - "\n", - "[4]: [Kanav et al. J. Chem. Theo. Comp. 16 10 (2020). Reducing qubit requirements for quantum simulations using molecular point group symmetries.](https://arxiv.org/abs/1910.14644)\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/applications/chemistry/molecule_eigensolver_using_openfermion/vqe_uccLiH.qmod b/applications/chemistry/molecule_eigensolver_using_openfermion/vqe_uccLiH.qmod deleted file mode 100644 index 73c4d2459..000000000 --- a/applications/chemistry/molecule_eigensolver_using_openfermion/vqe_uccLiH.qmod +++ /dev/null @@ -1,1591 +0,0 @@ -qfunc main(params: real[24], output state: qnum) { - allocate(8, state); - state ^= 0; - parametric_suzuki_trotter([ - [ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Y - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::Y - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::I - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I - ], - [ - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Y, - Pauli::Z - ], - [ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Y, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::I, - Pauli::Z - ], - [ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z - ], - [ - Pauli::I, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::Y, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z - ], - [ - Pauli::Y, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::X, - Pauli::Y - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Y, - Pauli::X - ], - [ - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::X, - Pauli::Y - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Y, - Pauli::X - ], - [ - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::Y, - Pauli::X - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::X, - Pauli::Y - ], - [ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Y, - Pauli::X - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::X, - Pauli::Y - ], - [ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::Z, - Pauli::Y - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::I, - Pauli::X - ], - [ - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::Z, - Pauli::Y - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::I, - Pauli::X - ], - [ - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::Z, - Pauli::X - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::I, - Pauli::Y - ], - [ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::Z, - Pauli::X - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::I, - Pauli::Y - ], - [ - Pauli::I, - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Y - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::X - ], - [ - Pauli::I, - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::Y - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::X - ], - [ - Pauli::I, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::X - ], - [ - Pauli::Z, - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Y - ], - [ - Pauli::I, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::X - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Y - ], - [ - Pauli::X, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Y - ], - [ - Pauli::Y, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::X - ], - [ - Pauli::X, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::Y - ], - [ - Pauli::Y, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::X - ], - [ - Pauli::Y, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::X - ], - [ - Pauli::X, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Y - ], - [ - Pauli::Y, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::X - ], - [ - Pauli::X, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Y - ], - [ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::X, - Pauli::Y, - Pauli::I - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Y, - Pauli::X, - Pauli::Z - ], - [ - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Y, - Pauli::X, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::X, - Pauli::Y, - Pauli::I - ], - [ - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::X, - Pauli::Y, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::Y, - Pauli::X, - Pauli::I - ], - [ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Y, - Pauli::X, - Pauli::I - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::X, - Pauli::Y, - Pauli::Z - ], - [ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::Z, - Pauli::Y, - Pauli::I - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::I, - Pauli::X, - Pauli::Z - ], - [ - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::I, - Pauli::X, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::Z, - Pauli::Y, - Pauli::I - ], - [ - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::I, - Pauli::Y, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::Z, - Pauli::X, - Pauli::I - ], - [ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::Z, - Pauli::X, - Pauli::I - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::I, - Pauli::Y, - Pauli::Z - ], - [ - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Y, - Pauli::I - ], - [ - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::X, - Pauli::Z - ], - [ - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::X, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::Y, - Pauli::I - ], - [ - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Y, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::X, - Pauli::I - ], - [ - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::X, - Pauli::I - ], - [ - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Y, - Pauli::Z - ], - [ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::X, - Pauli::Y, - Pauli::I, - Pauli::I - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Y, - Pauli::X, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::X, - Pauli::Y, - Pauli::I, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Y, - Pauli::X, - Pauli::Z, - Pauli::I - ], - [ - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::Y, - Pauli::X, - Pauli::I, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::X, - Pauli::Y, - Pauli::Z, - Pauli::I - ], - [ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Y, - Pauli::X, - Pauli::I, - Pauli::I - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::X, - Pauli::Y, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::I, - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::I - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::I, - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::I - ], - [ - Pauli::I, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::I - ], - [ - Pauli::I, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::I - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::X, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::I - ], - [ - Pauli::Y, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::X, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::Z - ], - [ - Pauli::Y, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::I - ], - [ - Pauli::Y, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::Z - ], - [ - Pauli::X, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::I - ], - [ - Pauli::Y, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::I - ], - [ - Pauli::X, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::X, - Pauli::Y, - Pauli::I, - Pauli::I, - Pauli::I - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Y, - Pauli::X, - Pauli::Z, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Y, - Pauli::X, - Pauli::Z, - Pauli::I, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::X, - Pauli::Y, - Pauli::I, - Pauli::Z, - Pauli::I - ], - [ - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::X, - Pauli::Y, - Pauli::Z, - Pauli::I, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::Y, - Pauli::X, - Pauli::I, - Pauli::Z, - Pauli::I - ], - [ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Y, - Pauli::X, - Pauli::I, - Pauli::I, - Pauli::I - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::X, - Pauli::Y, - Pauli::Z, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::I, - Pauli::I - ], - [ - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::I, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::Z, - Pauli::I - ], - [ - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::I, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::Z, - Pauli::I - ], - [ - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::I, - Pauli::I - ], - [ - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::I, - Pauli::I, - Pauli::X, - Pauli::Y, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::Y, - Pauli::X, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::I, - Pauli::Z, - Pauli::X, - Pauli::Y, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::I, - Pauli::Y, - Pauli::X, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I - ], - [ - Pauli::I, - Pauli::Z, - Pauli::Y, - Pauli::X, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::I, - Pauli::X, - Pauli::Y, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I - ], - [ - Pauli::I, - Pauli::I, - Pauli::Y, - Pauli::X, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I - ], - [ - Pauli::Z, - Pauli::Z, - Pauli::X, - Pauli::Y, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::X, - Pauli::Z, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I - ], - [ - Pauli::Y, - Pauli::I, - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::X, - Pauli::I, - Pauli::Z, - Pauli::Y, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z - ], - [ - Pauli::Y, - Pauli::Z, - Pauli::I, - Pauli::X, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I - ], - [ - Pauli::Y, - Pauli::I, - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z - ], - [ - Pauli::X, - Pauli::Z, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I - ], - [ - Pauli::Y, - Pauli::Z, - Pauli::Z, - Pauli::X, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I - ], - [ - Pauli::X, - Pauli::I, - Pauli::I, - Pauli::Y, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::I, - Pauli::X, - Pauli::Y, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I - ], - [ - Pauli::Z, - Pauli::Y, - Pauli::X, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::I, - Pauli::Y, - Pauli::X, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::X, - Pauli::Y, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I - ], - [ - Pauli::I, - Pauli::X, - Pauli::Y, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z - ], - [ - Pauli::Z, - Pauli::Y, - Pauli::X, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I - ], - [ - Pauli::I, - Pauli::Y, - Pauli::X, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I - ], - [ - Pauli::Z, - Pauli::X, - Pauli::Y, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::X, - Pauli::Y, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I - ], - [ - Pauli::Y, - Pauli::X, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z - ], - [ - Pauli::X, - Pauli::Y, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z - ], - [ - Pauli::Y, - Pauli::X, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I - ], - [ - Pauli::Y, - Pauli::X, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z - ], - [ - Pauli::X, - Pauli::Y, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I - ], - [ - Pauli::Y, - Pauli::X, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I - ], - [ - Pauli::X, - Pauli::Y, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z - ] - ], [ - (0.5 * params[0]), - (0.5 * params[0]), - (0.5 * params[1]), - (0.5 * params[1]), - (0.5 * params[2]), - (0.5 * params[2]), - (0.5 * params[3]), - (0.5 * params[3]), - ((-0.5) * params[4]), - ((-0.5) * params[4]), - ((-0.5) * params[5]), - ((-0.5) * params[5]), - ((-0.5) * params[6]), - ((-0.5) * params[6]), - ((-0.5) * params[7]), - ((-0.5) * params[7]), - ((-0.0625) * params[8]), - ((-0.0625) * params[8]), - ((-0.0625) * params[8]), - ((-0.0625) * params[8]), - ((-0.0625) * params[8]), - ((-0.0625) * params[8]), - ((-0.0625) * params[8]), - ((-0.0625) * params[8]), - ((-0.0625) * params[9]), - ((-0.0625) * params[9]), - ((-0.0625) * params[9]), - ((-0.0625) * params[9]), - ((-0.0625) * params[9]), - ((-0.0625) * params[9]), - ((-0.0625) * params[9]), - ((-0.0625) * params[9]), - ((-0.0625) * params[10]), - ((-0.0625) * params[10]), - ((-0.0625) * params[10]), - ((-0.0625) * params[10]), - ((-0.0625) * params[10]), - ((-0.0625) * params[10]), - ((-0.0625) * params[10]), - ((-0.0625) * params[10]), - ((-0.0625) * params[11]), - ((-0.0625) * params[11]), - ((-0.0625) * params[11]), - ((-0.0625) * params[11]), - ((-0.0625) * params[11]), - ((-0.0625) * params[11]), - ((-0.0625) * params[11]), - ((-0.0625) * params[11]), - ((-0.0625) * params[12]), - ((-0.0625) * params[12]), - ((-0.0625) * params[12]), - ((-0.0625) * params[12]), - ((-0.0625) * params[12]), - ((-0.0625) * params[12]), - ((-0.0625) * params[12]), - ((-0.0625) * params[12]), - ((-0.0625) * params[13]), - ((-0.0625) * params[13]), - ((-0.0625) * params[13]), - ((-0.0625) * params[13]), - ((-0.0625) * params[13]), - ((-0.0625) * params[13]), - ((-0.0625) * params[13]), - ((-0.0625) * params[13]), - ((-0.0625) * params[14]), - ((-0.0625) * params[14]), - ((-0.0625) * params[14]), - ((-0.0625) * params[14]), - ((-0.0625) * params[14]), - ((-0.0625) * params[14]), - ((-0.0625) * params[14]), - ((-0.0625) * params[14]), - ((-0.0625) * params[15]), - ((-0.0625) * params[15]), - ((-0.0625) * params[15]), - ((-0.0625) * params[15]), - ((-0.0625) * params[15]), - ((-0.0625) * params[15]), - ((-0.0625) * params[15]), - ((-0.0625) * params[15]), - ((-0.0625) * params[16]), - ((-0.0625) * params[16]), - ((-0.0625) * params[16]), - ((-0.0625) * params[16]), - ((-0.0625) * params[16]), - ((-0.0625) * params[16]), - ((-0.0625) * params[16]), - ((-0.0625) * params[16]), - ((-0.0625) * params[17]), - ((-0.0625) * params[17]), - ((-0.0625) * params[17]), - ((-0.0625) * params[17]), - ((-0.0625) * params[17]), - ((-0.0625) * params[17]), - ((-0.0625) * params[17]), - ((-0.0625) * params[17]), - ((-0.0625) * params[18]), - ((-0.0625) * params[18]), - ((-0.0625) * params[18]), - ((-0.0625) * params[18]), - ((-0.0625) * params[18]), - ((-0.0625) * params[18]), - ((-0.0625) * params[18]), - ((-0.0625) * params[18]), - ((-0.0625) * params[19]), - ((-0.0625) * params[19]), - ((-0.0625) * params[19]), - ((-0.0625) * params[19]), - ((-0.0625) * params[19]), - ((-0.0625) * params[19]), - ((-0.0625) * params[19]), - ((-0.0625) * params[19]), - ((-0.0625) * params[20]), - ((-0.0625) * params[20]), - ((-0.0625) * params[20]), - ((-0.0625) * params[20]), - ((-0.0625) * params[20]), - ((-0.0625) * params[20]), - ((-0.0625) * params[20]), - ((-0.0625) * params[20]), - ((-0.0625) * params[21]), - ((-0.0625) * params[21]), - ((-0.0625) * params[21]), - ((-0.0625) * params[21]), - ((-0.0625) * params[21]), - ((-0.0625) * params[21]), - ((-0.0625) * params[21]), - ((-0.0625) * params[21]), - ((-0.0625) * params[22]), - ((-0.0625) * params[22]), - ((-0.0625) * params[22]), - ((-0.0625) * params[22]), - ((-0.0625) * params[22]), - ((-0.0625) * params[22]), - ((-0.0625) * params[22]), - ((-0.0625) * params[22]), - ((-0.0625) * params[23]), - ((-0.0625) * params[23]), - ((-0.0625) * params[23]), - ((-0.0625) * params[23]), - ((-0.0625) * params[23]), - ((-0.0625) * params[23]), - ((-0.0625) * params[23]), - ((-0.0625) * params[23]) - ], -1.0, 1, 1, state); -} diff --git a/applications/chemistry/qpe_for_molecules/qpe_for_molecules.ipynb b/applications/chemistry/qpe_for_molecules/qpe_for_molecules.ipynb index 1173b949c..377ee68e9 100644 --- a/applications/chemistry/qpe_for_molecules/qpe_for_molecules.ipynb +++ b/applications/chemistry/qpe_for_molecules/qpe_for_molecules.ipynb @@ -73,12 +73,11 @@ "import numpy as np\n", "\n", "from classiq import *\n", + "from classiq.applications.chemistry.op_utils import qubit_op_to_pauli_terms\n", "\n", "# for chemistry\n", - "from classiq.applications.chemistry import Molecule, MoleculeProblem\n", - "from classiq.applications.combinatorial_helpers.pauli_helpers.pauli_utils import (\n", - " pauli_operator_to_hamiltonian,\n", - ")" + "from classiq.applications.chemistry.problems import FermionHamiltonianProblem\n", + "from classiq.applications.chemistry.z2_symmetries import Z2SymTaperMapper" ] }, { @@ -110,27 +109,52 @@ }, "outputs": [], "source": [ - "# build your molecule\n", + "molecule_H2_geometry = [(\"H\", (0.0, 0.0, 0)), (\"H\", (0.0, 0.0, 0.735))]\n", + "molecule_O2_geometry = [(\"O\", (0.0, 0.0, 0)), (\"O\", (0.0, 0.0, 1.16))]\n", + "molecule_LiH_geometry = [(\"H\", (0.0, 0.0, 0.0)), (\"Li\", (0.0, 0.0, 1.596))]\n", + "molecule_H2O_geometry = [\n", + " (\"O\", (0.0, 0.0, 0.0)),\n", + " (\"H\", (0, 0.586, 0.757)),\n", + " (\"H\", (0, 0.586, -0.757)),\n", + "]\n", + "molecule_BeH2_geometry = [\n", + " (\"Be\", (0.0, 0.0, 0.0)),\n", + " (\"H\", (0, 0, 1.334)),\n", + " (\"H\", (0, 0, -1.334)),\n", + "]\n", "\n", + "molecule_geometry = molecule_LiH_geometry" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "b4d0230f-1434-49db-abf9-253d1f4b3ed8", + "metadata": {}, + "outputs": [], + "source": [ + "from openfermion.chem import MolecularData\n", + "from openfermionpyscf import run_pyscf\n", "\n", - "molecule_LiH = Molecule(atoms=[(\"H\", (0.0, 0.0, 0.0)), (\"Li\", (0.0, 0.0, 1.596))])\n", + "geometry = molecule_H2_geometry\n", "\n", - "# Example of some other molecules:\n", - "molecule_H2 = Molecule(atoms=[(\"H\", (0.0, 0.0, 0)), (\"H\", (0.0, 0.0, 0.735))])\n", - "molecule_O2 = Molecule(atoms=[(\"O\", (0.0, 0.0, 0)), (\"O\", (0.0, 0.0, 1.16))])\n", - "molecule_H2O = Molecule(\n", - " atoms=[(\"O\", (0.0, 0.0, 0.0)), (\"H\", (0, 0.586, 0.757)), (\"H\", (0, 0.586, -0.757))]\n", - ")\n", - "molecule_BeH2 = Molecule(\n", - " atoms=[(\"Be\", (0.0, 0.0, 0.0)), (\"H\", (0, 0, 1.334)), (\"H\", (0, 0, -1.334))]\n", - ")\n", + "basis = \"sto-3g\" # Basis set\n", + "multiplicity = 1 # Singlet state S=0\n", + "charge = 0 # Neutral molecule\n", + "molecule = MolecularData(molecule_geometry, basis, multiplicity, charge)\n", "\n", - "molecule = molecule_LiH" + "molecule = run_pyscf(\n", + " molecule,\n", + " run_mp2=True,\n", + " run_cisd=True,\n", + " run_ccsd=True,\n", + " run_fci=True, # relevant for small, classically solvable problems\n", + ")" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "id": "5d27e5df-e16e-44b2-b78a-187905577908", "metadata": { "ExecuteTime": { @@ -149,24 +173,19 @@ } ], "source": [ - "# define your molecule problem\n", + "# define your molecule problem and mapper\n", "\n", - "gs_problem = MoleculeProblem(\n", - " molecule=molecule,\n", - " basis=\"sto3g\",\n", - " mapping=\"jordan_wigner\", #'bravyi_kitaev'\n", - " z2_symmetries=True,\n", - " freeze_core=True,\n", + "problem = FermionHamiltonianProblem.from_molecule(\n", + " molecule=molecule, first_active_index=1\n", ")\n", + "mapper = Z2SymTaperMapper.from_problem(problem)\n", + "num_qubits = mapper.get_num_qubits(problem)\n", "\n", - "operator = gs_problem.generate_hamiltonian()\n", - "gs_problem = gs_problem.update_problem(operator.num_qubits)\n", - "\n", - "mol_hamiltonian = pauli_operator_to_hamiltonian(operator.pauli_list)\n", - "problem_size = len(mol_hamiltonian[0].pauli)\n", + "constant_energy = problem.fermion_hamiltonian.constant\n", + "mol_hamiltonian = mapper.map(problem.fermion_hamiltonian - constant_energy)\n", "\n", "print(\n", - " f\"The Hamiltonian is defined on {problem_size} qubits, and contains {len(mol_hamiltonian)} Pauli strings\"\n", + " f\"The Hamiltonian is defined on {num_qubits} qubits, and contains {len(mol_hamiltonian.terms)} Pauli strings\"\n", ")" ] }, @@ -175,12 +194,12 @@ "id": "7e1e299b-bd9d-40e8-a1a6-c610e61f7354", "metadata": {}, "source": [ - "Finally, calculate the ground state energy as a reference solution to the quantum solver. Note that the Hamiltonian obtained from the Molecule object excludes the nuclear repulsion energy." + "Finally, we calculate the ground state energy as a reference solution to the quantum solver" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "id": "ca1d9c36-2d54-45c4-b3ce-f6ee8abbb28f", "metadata": { "ExecuteTime": { @@ -193,15 +212,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "Expected energy (without nuclear repulsion energy): -1.0789776863285236 Ha\n" + "Expected energy: -7.882386993638953 Ha\n" ] } ], "source": [ - "mat = hamiltonian_to_matrix(mol_hamiltonian)\n", - "w, v = np.linalg.eig(mat)\n", - "classical_sol = np.real(min(w))\n", - "print(f\"Expected energy (without nuclear repulsion energy): {classical_sol} Ha\")" + "classical_sol = molecule.fci_energy\n", + "print(f\"Expected energy: {classical_sol} Ha\")" ] }, { @@ -224,7 +241,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "id": "c7d00124-e791-43f7-b910-bc1031865e37", "metadata": { "ExecuteTime": { @@ -245,7 +262,7 @@ } ], "source": [ - "coeffs = [term.coefficient for term in mol_hamiltonian]\n", + "coeffs = list(mol_hamiltonian.terms.values())\n", "plt.semilogy(np.sort(np.abs(coeffs))[::-1], \"o\")\n", "plt.ylabel(r\"$|\\alpha_i|$\", fontsize=16)\n", "plt.xlabel(r\"$i$\", fontsize=16)\n", @@ -263,26 +280,6 @@ "Define a threshold and trim the Hamiltonian accordingly:" ] }, - { - "cell_type": "code", - "execution_count": 6, - "id": "e84941d6-18e3-430b-b3e0-570c2858df50", - "metadata": { - "ExecuteTime": { - "end_time": "2025-03-04T20:44:27.521414Z", - "start_time": "2025-03-04T20:44:27.515198Z" - } - }, - "outputs": [], - "source": [ - "def trim_hamiltonian(hamiltonian, threshold):\n", - " return [\n", - " PauliTerm(pauli=term.pauli, coefficient=term.coefficient)\n", - " for term in hamiltonian\n", - " if np.abs(term.coefficient) > threshold\n", - " ]" - ] - }, { "cell_type": "code", "execution_count": 7, @@ -305,8 +302,8 @@ "source": [ "THRESHOLD = 0.03\n", "\n", - "trimmed_mol_hamiltonian = trim_hamiltonian(mol_hamiltonian, THRESHOLD)\n", - "print(f\"Length of trimmed Hamiltonian: {len(trimmed_mol_hamiltonian)}\")" + "mol_hamiltonian.compress(THRESHOLD)\n", + "print(f\"Length of trimmed Hamiltonian: {len(mol_hamiltonian.terms)}\")" ] }, { @@ -334,36 +331,23 @@ "name": "stdout", "output_type": "stream", "text": [ - "The normalization value of the Hamiltonian is 17.61546220154492\n" + "The normalization value of the Hamiltonian is 17.61546220154498\n" ] } ], "source": [ "def normalize_hamiltonian(hamiltonian):\n", - " approx_lambda_max = sum(np.abs(term.coefficient) for term in hamiltonian)\n", + " approx_lambda_max = sum(np.abs(value) for value in hamiltonian.terms.values())\n", " normalization = 2 * approx_lambda_max\n", - " normalized_mol_hamiltonian = [\n", - " PauliTerm(pauli=term.pauli, coefficient=term.coefficient / (normalization))\n", - " for term in hamiltonian\n", - " ]\n", "\n", + " normalized_mol_hamiltonian = hamiltonian * (1 / normalization)\n", " return normalization, normalized_mol_hamiltonian\n", "\n", "\n", - "normalization, normalized_mol_hamiltonian = normalize_hamiltonian(\n", - " trimmed_mol_hamiltonian\n", - ")\n", + "normalization, normalized_mol_hamiltonian = normalize_hamiltonian(mol_hamiltonian)\n", "print(f\"The normalization value of the Hamiltonian is {normalization}\")" ] }, - { - "cell_type": "markdown", - "id": "817d2e3b-ec15-4998-847c-f7942b37dcc1", - "metadata": {}, - "source": [ - "In the QPE models, define the `phase` variable as a fixed point quantum number in $[-1/2,1/2)$: `QNum[QPE_SIZE,SIGNED,QPE_SIZE]`. Thus, you need to postprocess the algorithm result by multiplying back the normalization factor (see the Measurement and Analysis section below)." - ] - }, { "cell_type": "markdown", "id": "cf78c5bb-240f-429e-aa47-d7c9720d90c1", @@ -396,94 +380,20 @@ "$$\n", "and approximate each power with Suzuki-Trotter for appropriate order and repetition parameters, keeping the same error per QPE iteration. You can thus use the bound above to define a powered Suzuki-Trotter `qfunc` for the specific molecule.\n", "\n", - "First, define classical auxiliary functions that help evaluate the right side of Eq. (1):" + "First, define a classical auxiliary function that help evaluate the right-hand-side side of Eq. (1):" ] }, { "cell_type": "code", "execution_count": 9, - "id": "740ccdac-65a1-4b70-bbee-a340950683ab", - "metadata": { - "ExecuteTime": { - "end_time": "2025-03-04T20:44:29.178026Z", - "start_time": "2025-03-04T20:44:29.176709Z" - } - }, + "id": "265b0699-1f3a-4b3f-a65c-0aec1effebe3", + "metadata": {}, "outputs": [], "source": [ "import itertools\n", "\n", - "\n", - "def multiply_single_qubit(pa, pb):\n", - " \"\"\"\n", - " Multiply two single-qubit Pauli operators pa*pb.\n", - " Returns (phase, pc) where:\n", - " - phase in {1, -1, 1j, -1j}\n", - " - pc is the resulting single-qubit Pauli.\n", - " \"\"\"\n", - " table = {\n", - " (Pauli.I, Pauli.I): (1, Pauli.I),\n", - " (Pauli.I, Pauli.X): (1, Pauli.X),\n", - " (Pauli.I, Pauli.Y): (1, Pauli.Y),\n", - " (Pauli.I, Pauli.Z): (1, Pauli.Z),\n", - " (Pauli.X, Pauli.I): (1, Pauli.X),\n", - " (Pauli.X, Pauli.X): (1, Pauli.I),\n", - " (Pauli.X, Pauli.Y): (1j, Pauli.Z), # X*Y = iZ\n", - " (Pauli.X, Pauli.Z): (-1j, Pauli.Y), # X*Z = -iY\n", - " (Pauli.Y, Pauli.I): (1, Pauli.Y),\n", - " (Pauli.Y, Pauli.X): (-1j, Pauli.Z), # Y*X = -iZ\n", - " (Pauli.Y, Pauli.Y): (1, Pauli.I),\n", - " (Pauli.Y, Pauli.Z): (1j, Pauli.X), # Y*Z = iX\n", - " (Pauli.Z, Pauli.I): (1, Pauli.Z),\n", - " (Pauli.Z, Pauli.X): (1j, Pauli.Y), # Z*X = iY\n", - " (Pauli.Z, Pauli.Y): (-1j, Pauli.X), # Z*Y = -iX\n", - " (Pauli.Z, Pauli.Z): (1, Pauli.I),\n", - " }\n", - "\n", - " return table[(pa, pb)]\n", - "\n", - "\n", - "def multiply_pauli_lists(pA_list, pB_list):\n", - " \"\"\"\n", - " Multiply two multi-qubit Pauli lists A and B.\n", - " Returns PauliTerm(pauli, coefficient), where:\n", - " - coefficient in {1, -1, 1j, -1j}\n", - " - pauli is a Pauli list representing AB.\n", - " \"\"\"\n", - " if len(pA_list) != len(pB_list):\n", - " raise ValueError(\"Pauli lists must have the same length.\")\n", - "\n", - " phase_total = 1 + 0j # start with complex 1\n", - " product = []\n", - "\n", - " for pA, pB in zip(pA_list, pB_list):\n", - " phase_local, pC = multiply_single_qubit(pA, pB)\n", - " phase_total *= phase_local\n", - " product.append(pC)\n", - "\n", - " return PauliTerm(pauli=product, coefficient=phase_total)\n", - "\n", - "\n", - "def commutator_infinity_norm(pA_list, pB_list):\n", - " \"\"\"\n", - " Compute the 'infinity-norm of [A,B]' . The commutation relation between two Pauli lists\n", - " can be inferred by counting the number of qubit positions i where A[i] != B[i],\n", - " ignoring position with A[i] or B[i] equal to Pauli.I.\n", - " Then:\n", - " - If the count is even, A and B commute => norm = 0\n", - " - If the count is odd, A and B anticommute => norm = 2\n", - "\n", - " \"\"\"\n", - " if len(pA_list) != len(pB_list):\n", - " raise ValueError(\"Pauli strings must have the same length.\")\n", - "\n", - " # Count positions where A and B are both in {X,Y,Z}, differ, and none is I\n", - " difference_count = 0\n", - " for pA, pB in zip(pA_list, pB_list):\n", - " if pA != Pauli.I and pB != Pauli.I and pA != pB:\n", - " difference_count += 1\n", - "\n", - " return 2 * (difference_count % 2)\n", + "from openfermion import QubitOperator\n", + "from openfermion.utils import commutator\n", "\n", "\n", "def calculate_gamma_2(hamiltonian):\n", @@ -491,16 +401,20 @@ " Compute the $\\gamma_2$ value appearing in the bound for Suzuki Trotter of order 2\n", " \"\"\"\n", " gamma_2 = 0\n", - " for triplet in itertools.combinations(range(len(hamiltonian)), 3):\n", - " terms = [hamiltonian[index] for index in triplet]\n", - " factor = np.abs(\n", - " (terms[0].coefficient) * (terms[1].coefficient) * (terms[2].coefficient)\n", - " )\n", - " inner_commutator = commutator_infinity_norm(terms[1].pauli, terms[0].pauli)\n", + " for triplet in itertools.combinations(range(len(hamiltonian.terms)), 3):\n", + " terms = [list(hamiltonian.terms.keys())[index] for index in triplet]\n", + " values = [list(hamiltonian.terms.values())[index] for index in triplet]\n", + " factor = np.abs(values[0] * values[1] * values[2])\n", + " inner_commutator = commutator(\n", + " QubitOperator(terms[1], 1), QubitOperator(terms[0], 1)\n", + " ).induced_norm()\n", " if inner_commutator != 0:\n", - " outer_commutator = 2 * commutator_infinity_norm(\n", - " terms[2].pauli,\n", - " multiply_pauli_lists(terms[0].pauli, terms[1].pauli).pauli,\n", + " outer_commutator = (\n", + " 2\n", + " * commutator(\n", + " QubitOperator(terms[2], 1),\n", + " QubitOperator(terms[0], 1) * QubitOperator(terms[1], 1),\n", + " ).induced_norm()\n", " )\n", " gamma_2 += factor * outer_commutator\n", "\n", @@ -530,7 +444,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "The powers of the Hamiltonian simulation along a QPE routine of size 7: \n", + "The power of the Hamiltonian simulation along a QPE routine of size 7: \n", "[ 1 2 4 8 16 32 64]\n" ] } @@ -568,7 +482,7 @@ "output_type": "stream", "text": [ "The theoretical bounds for the repetitions for QPE size 7, keeping an error 0.1 per QPE iteration are:\n", - "[ 4. 11. 30. 85. 240. 677. 1915.]\n" + "[ 5. 12. 33. 93. 261. 737. 2084.]\n" ] } ], @@ -607,7 +521,7 @@ "output_type": "stream", "text": [ "The repetitions for QPE size 7, taking a naive QPE, per QPE iteration:\n", - "[ 4. 8. 15. 30. 60. 120. 240.]\n" + "[ 5. 9. 17. 33. 66. 131. 261.]\n" ] } ], @@ -625,7 +539,7 @@ "source": [ "While this naive QPE results in a shallower circuit, compared to taking repetitions according to the theoretical bounds (due to smaller values of repetitions), it is unclear whether it keeps the same operator error per phase bit.\n", "\n", - "In practice, the bounds given in the literature are quite loose. This tutorial therefore takes a more experimental approach, assuming that the scaling of the bound with the evolution time $t$ is similar to Eq. (1), but taking a smaller prefactor. " + "In practice, the bounds given in the literature are quite loose. This tutorial therefore takes a more experimental approach, assuming that the scaling of the bound with the evolution time $t$ is similar to Eq. (1), but taking a smaller prefactor." ] }, { @@ -682,8 +596,8 @@ "@qfunc\n", "def powered_st2_for_LiH(p: CInt, state: QArray[QBit]):\n", " suzuki_trotter(\n", - " pauli_operator=normalized_mol_hamiltonian,\n", - " evolution_coefficient=-2 * pi * p,\n", + " pauli_operator=qubit_op_to_pauli_terms(normalized_mol_hamiltonian),\n", + " evolution_coefficient=-2 * np.pi * p,\n", " order=2,\n", " repetitions=ceiling_qmod(experimental_r0 * p ** (3 / 2)),\n", " qbv=state,\n", @@ -710,22 +624,28 @@ }, "outputs": [], "source": [ + "from classiq.applications.chemistry.hartree_fock import get_hf_state\n", + "\n", + "hf_state = get_hf_state(problem, mapper)\n", + "\n", + "\n", "@qfunc\n", "def main(\n", - " state: Output[QArray[QBit]], phase: Output[QNum[QPE_SIZE, SIGNED, QPE_SIZE]]\n", + " state: Output[QArray[QBit, num_qubits]],\n", + " phase: Output[QNum[QPE_SIZE, SIGNED, QPE_SIZE]],\n", ") -> None:\n", "\n", - " allocate(problem_size, state)\n", - " molecule_hartree_fock(molecule_problem_to_qmod(gs_problem), state)\n", - " allocate(QPE_SIZE, phase)\n", + " prepare_basis_state(hf_state, state)\n", + " allocate(phase)\n", " qpe_flexible(lambda p: powered_st2_for_LiH(p, state), phase)\n", "\n", "\n", "qmod = create_model(\n", " main,\n", " preferences=Preferences(timeout_seconds=600),\n", - " out_file=\"qpe_for_molecules\",\n", ")\n", + "write_qmod(qmod, \"qpe_for_molecules\", symbolic_only=False)\n", + "\n", "qprog = synthesize(qmod)" ] }, @@ -734,7 +654,7 @@ "id": "c7e16994-cca8-4b2b-b65d-79868780f749", "metadata": {}, "source": [ - "## Measurement and Analysis\n" + "## Measurement and Analysis" ] }, { @@ -784,14 +704,14 @@ "output_type": "stream", "text": [ "\n", - "Energy with maximal probability: -1.1009663875965574 Ha\n", - "Precision: 0.13762079844956968 Ha\n", - "Classical solution:, -1.0789776863285236 Ha\n" + "Energy with maximal probability: -7.904148198365434 Ha\n", + "Precision: 0.13762079844957015 Ha\n", + "Classical solution:, -7.882386993638953 Ha\n" ] }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkoAAAHTCAYAAADYojePAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAABNKklEQVR4nO3deVxUZeP///coOCAI7miigksuH/eFNLAMbdE2NbVQ79K7NDUj7W7RSkut9PZuw7K0XMsls3Ircrk1LVxR0TTL8hYUd0VZNEWR8/vDH/N1ggMzDMuAr+fjMY+HnHOd61znDMy8vc51rmMxDMMQAAAAsilT3A0AAABwVwQlAAAAEwQlAAAAEwQlAAAAEwQlAAAAEwQlAAAAEwQlAAAAEwQlAAAAEwQlAAAAEwQlAMXujTfekMViKe5mlFirVq1Sq1at5OXlJYvFouTk5OJuElBqEJSAQjB37lxZLBbT19atW4u7iYXKYrFoxIgROa7LOjc7duxwaR/Hjx/XG2+8od27d7tUT0mXlJSkvn37ytvbW9OmTdMXX3whHx+f4m5WnjZt2qSePXsqICBAVqtVQUFBGjp0qBITE7OVzQrSWa/y5curadOmeu2115Sammord7P/3aFweBR3A4DSbMKECQoODs62vEGDBsXQGvf12muvafTo0U5tc/z4cY0fP15BQUFq1apV4TSsBIiNjVVaWpomTpyorl27FndzHPLhhx/queeeU7169fTss8+qZs2a+u233zRz5kwtXrxYP/zwgzp06JBtu08++US+vr66cOGC1qxZo7feekvr16/Xpk2b7Hok+btDQSIoAYWoW7duateuXXE3QxcvXnTrXgYPDw95eJSsj6OMjAxlZmaqXLlyxdqO06dPS5IqVqyYZ9m//vpL5cuXL+QW5W7Tpk0aOXKkwsLCtGrVKrv2DBs2TKGhoXrkkUf066+/Zjum3r17q2rVqpKkoUOH6pFHHtG3336rrVu3qmPHjrZy7vJ3h9KBS29AMUpISJDFYtE777yjTz/9VPXr15fValX79u0VGxubrfzvv/+u3r17q3LlyvLy8lK7du20YsUKuzJZlx82btyo4cOHq3r16goMDLStnzZtmurVqydvb2+FhITo559/VufOndW5c2dJ0oULF+Tj46Pnnnsu2/6PHj2qsmXLatKkSQV6HnIao7R27VqFhYWp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y7/55hv5+fnJ09NTgYGBdpcZb+To3x3gCIIS4AZu7Pm5kWEYkmTrVXnhhRd077335lj271/43t7eLrXp8ccf13/+8x8tW7ZMERERWrhwoR544AG73oXC4u3trZ9++kk//vijvv/+e61atUqLFy9WeHi41qxZY3q+iqJdfzd//nwNHDhQPXr00Isvvqjq1avbBrxnjaG5kVnb8/odKKj2Oqsg29uwYUN5eHjol19+MS2Tnp6uAwcOKCQkJNu6O+64w3bXG1BUCEpACVCvXj1J1y+R5HeunLp160q63jt111132ZZnZGQoISFBLVq0sCvfrFkztW7dWgsWLFBgYKCOHDmiDz/8MJ9H4LwyZcqoS5cu6tKli9577z29/fbbevXVV/Xjjz+qa9eupjN5Zx3ngQMHbHdFZTlw4IBt/Y3n4+9yWmbm66+/Vr169fTtt9/aten11193uI6iVLduXf3yyy/KzMy061X6/fffbesLS/ny5dWlSxf997//1eHDh3Pc11dffaX09HSHey6BwsYYJaAEqF69ujp37qwZM2boxIkT2dafOXMmzzratWunKlWq6LPPPlNGRoZt+YIFC0wvl/zjH//QmjVr9MEHH6hKlSrq1q1b/g/CCTndZp5191h6erok2eaF+vvjOtq1a6fq1atr+vTptrKS9MMPP+i3337T/fffL0m65ZZb1KxZM33++ed2d+Jt3LhRe/fudbitWT0rN/akbNu2TVu2bHG4jqLUvXt3nTx5UosXL7Yty8jI0IcffihfX1/deeedhbr/1157TYZhaODAgbp06ZLduvj4eL300kuqXbu2/vGPfxRqOwBH0aMEFKIffvjB9j/1G91+++22XiJHTZs2TWFhYWrevLkGDx6sevXq6dSpU9qyZYuOHj2qPXv25Lp9uXLl9MYbb+jZZ59VeHi4+vbtq4SEBM2dO1f169fPsYemX79+eumll7R06VINGzbMNlVBYZswYYJ++ukn3X///apbt65Onz6tjz/+WIGBgQoLC5N0fc6dihUravr06apQoYJ8fHx02223KTg4WP/+9781aNAg3XnnnYqIiLBNDxAUFKRRo0bZ9vP222/r4YcfVmhoqAYNGqTz58/ro48+UrNmzRyaxkCSHnjgAX377bfq2bOn7r//fsXHx2v69Olq2rSpw3UUpSFDhmjGjBkaOHCgdu7cqaCgIH399dfatGmTPvjggzwHWrsqLCxM77//vkaOHKkWLVpo4MCBqlmzpn7//Xd99tlnKlOmjJYtW+bQBJpmCvLvDiAoAYVo3LhxOS6fM2eO0x/YTZs21Y4dOzR+/HjNnTtXSUlJql69ulq3bm26n78bMWKEDMPQu+++qxdeeEEtW7bUihUrFBkZaXeHWJaAgADdc889io6OLtL/4T/00ENKSEjQ7NmzdfbsWVWtWlV33nmnxo8fbxsj5enpqXnz5mnMmDEaOnSoMjIyNGfOHAUHB2vgwIEqX768Jk+erJdfflk+Pj7q2bOn/v3vf9t9AT/44INatGiR3njjDY0ePVoNGzbU3LlzNW/ePP36668OtXXgwIE6efKkZsyYodWrV6tp06aaP3++lixZog0bNhTC2XGNt7e3NmzYoNGjR2vevHlKTU1Vo0aNNGfOHNtklYUtMjJSbdq0sU3gmZSUJMMwVL16de3Zs0c1atRwqf6C/LsDLIYrIwUBlHiZmZmqVq2aevXqpc8++yzb+p49e2rv3r1Ojdsp6Vq1aqVq1app7dq1xd2Um8bEiRM1btw4vfrqq3rzzTeLuzmADWOUgJvI5cuXs92V9Pnnn+vcuXO2R5jc6MSJE/r+++9L7XiRq1ev2o3Xkq4/HmXPnj05ng8UnrFjx2ro0KF66623HHp8CVBU6FECbiIbNmzQqFGj1KdPH1WpUkW7du3SrFmz1KRJE+3cudM25058fLw2bdqkmTNnKjY2Vv/73/9cvhzijhISEtS1a1cNGDBAt9xyi37//XdNnz5d/v7+2rdvH4+8AMAYJeBmEhQUpNq1a2vq1Kk6d+6cKleurMcff1yTJ0+2m5hw48aNGjRokOrUqaN58+aVypAkXZ/Ys23btpo5c6bOnDkjHx8f3X///Zo8eTIhCYAkepQAAABMMUYJAADABEEJAADABGOUXJSZmanjx4+rQoUKpo9UAAAA7sUwDKWlpemWW27J9WHbBCUXHT9+PNtTtAEAQMmQmJiowMBA0/UEJRdlTfefmJgoPz+/Ym4NAABwRGpqqmrXrp3nY3sISi7Kutzm5+dHUAIAoITJa9gMg7kBAABMEJQAAABMEJQAAABMuH1QWrJkiTp37qxKlSrJx8dHLVu21JQpU3T16lWn67p48aImTZqkdu3ayc/PT56enqpRo4YeeOABrVixohBaDwAASjK3foTJyJEjFRUVJQ8PD4WHh8vX11fr169XcnKywsLCtGbNGnl7eztUV1JSku644w7t379fvr6+uv3221WxYkUdPHhQu3btkiRFRkYqKirKqTampqbK399fKSkpDOYGAKCEcPT72217lJYtW6aoqCj5+vpq27ZtWr16tb755hv9+eefat68uWJiYjR27FiH65swYYL279+vtm3b6vDhw1q9erUWL16snTt36vvvv5eHh4emTp2qrVu3FuJRAQCAksRtg9Lbb78tSRo9erTatGljW161alV9/PHHkqSPPvpIKSkpDtW3fv16SdLLL7+sypUr263r3r277rrrLknSli1bXG47AAAoHdwyKB07dkyxsbGSpH79+mVbHxYWptq1ays9PV3R0dEO1enl5eVQuapVqzreUAAAUKq5ZVCKi4uTJFWuXFnBwcE5lmnXrp1d2bx069ZNkvTvf/9b586ds1sXHR2tH3/8UTVq1NBDDz2U32YDAIBSxi1n5o6Pj5ck1alTx7RM1vPVssrm5eWXX9b27du1evVq1a1bV6GhobbB3Dt37lRoaKhmzZolf3//XOtJT09Xenq67efU1FSH9g+g4FzLNLQ9/pxOp11W9QpeCgmurLJleCg1gILnlkEpLS1NkuTj42NaxtfXV5LjQcXHx0crV67UK6+8onfffVerV6+2ratSpYq6du2qWrVq5VnPpEmTNH78eIf2CaDgrdp3QuNX7teJlMu2ZTX9vfT6g011X7OaxdgyAKWRW156KwwnTpxQaGioPvzwQ7355ps6dOiQLly4oO3bt6tt27YaP368wsLCbCHNzJgxY5SSkmJ7JSYmFtERAFi174SGzd9lF5Ik6WTKZQ2bv0ur9p0oppYBKK3cMihlPcn34sWLpmUuXLggSQ7PXfTEE08oNjZWEydO1CuvvKLg4GD5+Pioffv2+u6779S8eXPt2bNH77zzTq71WK1W2wNweRAuUHSuZRoav3K/cpr4LWvZ+JX7dS3TbaeGA1ACuWVQCgoKkqRce2uy1mWVzc2xY8e0du1aSVJERES29Z6enurdu7ck6b///a+TrQVQFLbHn8vWk3QjQ9KJlMvaHn/OtAwAOMstg1Lr1q0lXZ9N22yw9o4dOyTJbo4lM0eOHLH926wHKGsQ99/viAPgHk6nmYek/JQDAEe4ZVAKDAxU+/btJUkLFy7Mtj4mJkaJiYmyWq3q3r17nvXdOEh727ZtOZbJmpHbbDoCAMWregXH5kJztBwAOMItg5IkvfLKK5KkyZMn257FJl3vZRo+fLgkacSIEXa38y9dulSNGzdWly5d7OqqU6eOLXg999xzSkhIsFs/f/58LV68WFLOE1wCKH4hwZVV099LZpMAWHT97reQ4MomJQDAeW45PYAk9ejRQ5GRkZo6dao6dOigLl26yMfHR+vWrVNycrJCQ0M1ceJEu21SUlJ04MABXb6cvet99uzZuuuuu/Tbb7+pSZMm6tChg6pWrarffvtNv/76qyRpwIAB6t+/f5EcHwDnlC1j0esPNtWw+btkkewGdWeFp9cfbMp8SgAKlNv2KElSVFSUFi9erI4dO2rz5s2Kjo5WYGCgJk+erPXr18vb29vhupo1a6Z9+/bp5Zdf1q233qrY2FgtW7ZMp0+f1r333qvFixfriy++kMXChyzgru5rVlOfDGijGv72l9dq+HvpkwFtmEcJQIGzGIbBvbQuSE1Nlb+/v1JSUpgqACgizMwNwFWOfn+77aU3ADBTtoxFHetXKe5mALgJuPWlNwAAgOJEUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADBBUAIAADDh9kFpyZIl6ty5sypVqiQfHx+1bNlSU6ZM0dWrV/Nd5/Lly/XQQw+pRo0aKleunKpXr67bb79dEyZMKMCWAwCAks5iGIZR3I0wM3LkSEVFRcnDw0Ph4eHy9fXV+vXrlZycrLCwMK1Zs0be3t4O13flyhUNGDBAS5Yskbe3tzp27KiAgACdPHlSv/76q65du6azZ8861cbU1FT5+/srJSVFfn5+zh4iAAAoBo5+f3sUYZucsmzZMkVFRcnX11cbN25UmzZtJElnz55VeHi4YmJiNHbsWL3zzjsO1zl48GAtWbJEPXr00GeffaaqVava1mVmZmr79u0FfhwAAKDkctsepZCQEMXGxurNN9/Uq6++arcuJiZGnTp1ktVq1alTp+Tv759nfevWrVPXrl3VrFkz7dq1S56engXSTnqUAAAoeRz9/nbLMUrHjh1TbGysJKlfv37Z1oeFhal27dpKT09XdHS0Q3V++OGHkq5fziuokAQAAEo3t7z0FhcXJ0mqXLmygoODcyzTrl07JSYmKi4uThEREbnWd+3aNa1bt06SdMcdd+jkyZP68ssvdeDAAVmtVrVu3VqPPPKIfH19C/ZAAABAieaWQSk+Pl6SVKdOHdMytWvXtiubm0OHDunChQuSpK1bt2r48OG2n7O8+OKL+vLLLxUeHp7fZgMAgFLGLS+9paWlSZJ8fHxMy2T1/qSmpuZZX1JSku3fTz75pNq2bavY2FilpaVp9+7d6t69u86cOaOHH35Yf/75Z651paenKzU11e4FAABKJ7cMSgXtxvHqtWrV0urVq9WuXTv5+vqqZcuWWrFihZo1a6YLFy5o8uTJudY1adIk+fv7215ZPVsAAKD0ccugVKFCBUnSxYsXTctkXTpz5E6zrPokaeDAgbJarXbry5Ytq6efflqS9N///jfXusaMGaOUlBTbKzExMc/9AwCAksktxygFBQVJUq4hJGtdVtm86rNYLDIMQ/Xq1cuxTNbyEydO5FqX1WrNFrQAAEDp5JY9Sq1bt5Z0fWyR2WDtHTt2SJJtIsrc+Pr6qlGjRpJkOvN21nLufAMAAFncMigFBgaqffv2kqSFCxdmWx8TE6PExERZrVZ1797doTr79OkjyfzS2tq1ayVdn+gSAABActOgJEmvvPKKJGny5MnatWuXbXlSUpKGDx8uSRoxYoTdrNxLly5V48aN1aVLl2z1RUZGqlKlSoqOjtaMGTPs1n355ZdasGCBrRwAAIDkxkGpR48eioyM1IULF9ShQwd169ZNvXv3VoMGDbR3716FhoZq4sSJdtukpKTowIED+t///petvqpVq2rx4sXy8vLS0KFD1axZM/Xp00dt2rRRRESEDMPQ2LFjHe6hAgAApZ/bBiVJioqK0uLFi9WxY0dt3rxZ0dHRCgwM1OTJk7V+/Xp5e3s7Vd/dd9+tPXv26IknnlBycrKWL1+uI0eOqHv37lq9erUmTJhQSEcCAABKIrd9KG5JwUNxAQAoeUr0Q3EBAADcAUEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADABEEJAADAhIerFVy7dk3btm3Trl27dOrUKZ0/f16VKlVSQECA2rZtq5CQEJUtW7Yg2goAAFCk8h2UYmJiNG3aNH3//fe6ePGibblhGLJYLLaffX19df/99+uZZ55RaGioa60FAAAoQhbDMAxnNvj55581atQoxcXFyTAMlSlTRs2aNdP//d//qUqVKvLz81NKSoqSkpK0b98+7d+/X5mZmbJYLGrTpo3ee+89derUqbCOp8ilpqbK399fKSkp8vPzK+7mAAAABzj6/e1Uj9Jjjz2mJUuWyMPDQw899JAGDhyo8PBwVahQIdeGrFu3TnPnztWqVavUuXNn9e3bV4sWLXJm1wAAAEXOqR4lq9WqIUOG6LXXXlNAQIDTOzt16pQmTJigWbNm6fLly05v747oUQIAoORx9PvbqaCUkJCgoKAglxsXHx+v4OBgl+txBwQlAABKHke/v52aHqAgQpKkUhOSAABA6ebSPErnz58vqHYAAAC4HZeCUmBgoAYPHqzdu3cXUHMAAADch0tB6cqVK5o1a5batm2rTp06afHixcrIyCiotgEAABQrl4LSkSNHNHbsWAUEBGjTpk3q16+f6tSpo/Hjx+vkyZMF1UYAAIBi4fSEkznJyMjQ119/rWnTpmnTpk2yWCzy8PBQr1699MwzzygsLKwg2uqWuOsNAICSp1DuejPj4eGhxx57TD///LP27Nmjp556SuXKldPixYt15513qnXr1qVq7iQAAHBzKJCgdKPmzZtrxowZOnr0qF544QUZhqFffvlFQ4YMUa1atTR27FilpqYW9G4BAAAKXIEHJen68+CGDBmiqKgoSVK5cuUUEhKi5ORkvf3222ratKl+/fXXwtg1AABAgSmwoHTp0iV9+umnatmypTp37qwlS5aoatWqmjBhgo4cOaItW7bo999/V58+fXT8+HH961//KqhdAwAAFAqnHoqbk4MHD2ratGmaN2+eUlJSZBiGQkJCFBkZqb59+8rD4//tomHDhvryyy91+PBhbd261dVdAwAAFCqXglK3bt20du1aZWZmytPTU4899pgiIyN122235bpd06ZNtX37dld2DQAAUOhcCkqrV69WtWrVNGTIEA0fPlw1a9Z0aLsePXqoTp06ruwaAACg0Lk0j9LcuXPVr18/lStXriDbVKIwjxIAACWPo9/fLvUoDRw40JXNAQAA3FqhTA8AAABQGrjUoxQeHu5QuXLlyqlq1apq166dIiIiFBAQ4MpuAQAAioRLY5TKlLneIWWxWCRJOVVlsVhsyy0Wi7y8vPTJJ5/o8ccfz+9u3QpjlAAAKHmKZIzSjz/+qO+++07vvvuu2rdvr379+ikoKEgWi0UJCQlauHChtm/frueff16tWrXS+vXrNW/ePD311FNq3LixQkJCXNk9AABAoXIpKJUrV05RUVF67733NHLkyGzrIyMjFRUVpRdffFEbNmzQgAED1LFjRz399NOKiorSggULXNk9AABAoXLp0lv37t119OhR/fLLL7mWa9GihQIDAxUdHS3DMFS/fn1du3ZNhw8fzu+u3QaX3gAAKHkc/f526a637du3q3nz5nmWa968ubZt2ybp+jilpk2b6vTp067sGgAAoNC5FJQuXbqkEydO5FnuxIkTunz5su1nHx8fu2fAAQAAuCOXglKTJk30888/23qLcrJt2zb9/PPPatq0qW3ZsWPHVLVqVVd2DQAAUOhcCkrDhw/XtWvXdM8992js2LH67bffdOnSJV26dEm///67xo0bp3vvvVeZmZkaNmyYJOmvv/5SXFyc2rZtWyAHAAAAUFhcGswtXQ9L06dPt82l9HeGYejpp5/WJ598Iknav3+//vOf/+ixxx7Tvffe68qu3QKDuQEAKHkc/f52OShJ0ooVKxQVFaUtW7bYxiJZrVZ17NhRkZGR6tGjh6u7cFsEJQAASp4iDUpZrl27prNnz0qSqlSpclMM2CYoAQBQ8hTJ9AD16tXTfffdZ/u5bNmyCggIUEBAwE0RkgAAQOnmUlA6deqUKleuXFBtAQAAcCsuBaW6desqNTW1oNoCAADgVlwKSr1799ZPP/2kM2fOFFR7AAAA3IZLQWnMmDFq0qSJ7rnnHm3evLmg2gQAAOAWXBpxff/996ts2bLas2ePOnXqpOrVqysoKEje3t7ZylosFq1bt87pfSxZskTTpk3Tnj17dOXKFTVo0ED9+/fXqFGj5Onp6UrzFR0drfvvv1+S1KVLF/33v/91qT4AAFC6uDQ9QJkyjndIWSwWXbt2zan6R44cqaioKHl4eCg8PFy+vr5av369kpOTFRYWpjVr1uQYyhxx/vx5NWvWTCdOnJBhGPkOSkwPAABAyePo97dLPUo//vijK5vnatmyZYqKipKvr682btyoNm3aSJLOnj2r8PBwxcTEaOzYsXrnnXfyVf+zzz6rU6dOaejQobZZwwEAAG5UoBNOFqSQkBDFxsbqzTff1Kuvvmq3LiYmRp06dZLVatWpU6fk7+/vVN1Lly5Vr1699OKLL6pp06YaNGgQPUoAANxEimTCycJy7NgxxcbGSpL69euXbX1YWJhq166t9PR0RUdHO1X32bNnNXToUDVq1EgTJkwokPYCAIDSqUCCkmEYio6O1muvvaann35as2fPtq07c+aM/vjjD6fGJ8XFxUmSKleurODg4BzLtGvXzq6so4YNG6azZ89q1qxZ8vLycmpbAABwc3H5OSN79uzRo48+qj///FOGYchisejq1av65z//KUlau3at/vGPf2jZsmV68MEHHaozPj5eklSnTh3TMrVr17Yr64gvv/xSX3/9tZ577jmFhoY6vB0AALg5udSjdPToUXXt2lV//PGHunXrpilTpujvQ5569OghT09PLV++3OF609LSJEk+Pj6mZXx9fSXJ4ZnBT548qWeeeUb169fX22+/7XBb/i49PV2pqal2LwAAUDq5FJTefvttJSUl6YMPPtB3332nF154IVuZ8uXLq2XLlrYxR8VlyJAhOn/+vGbOnKny5cvnu55JkybJ39/f9srq2QIAAKWPS0Fp1apVaty4sSIjI3MtFxQUpBMnTjhcb4UKFSRJFy9eNC1z4cIFSXLoTrN58+Zp5cqVGjp0qDp37uxwO3IyZswYpaSk2F6JiYku1QcAANyXS2OU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GZfegFy89957OnjwoCwWi+rUqaO7777brkcBpV9cXJwkqXLlygoODs6xTLt27ZSYmKi4uDhFREQUZfPgxn788Uft3btXaWlpqlKlikJCQtS9e3dm6C5hCEpALv71r3/Z/Tx69Gjdd999mjt3rgICAoqpVShK8fHxkqQ6deqYlqldu7ZdWUCSPv/882zLatasqdmzZ+u+++4rhhYhP7j0BuSgX79+WrZsmRISEnTp0iX98ccf+uijj1SlShWtWrVKd999N7f33iTS0tIkST4+PqZlfH19JUmpqalF0ia4t5YtWyoqKkr79u1TamqqTp06pTVr1uj222/XiRMn9NBDD2nDhg3F3Uw4iB4llCovvfSSVqxY4fR2M2fOVFhYmO3nBQsW2K1v2LChGjZsqO7du6t169bau3evpk+frpEjR7raZAClzKhRo+x+rlChgu6++2517dpVPXv21PLlyzVy5Ejt3r27eBoIpxCUUKocP35cBw4ccHq7CxcuOFQuODhYgwYN0gcffKCVK1cSlG4CFSpUkCRdvHjRtEzW74+fn1+RtAklk8Vi0fjx47V8+XLt2bNHiYmJtsu2cF9cekOpMn/+fBmG4fTLmfECTZo0kSQdPXq0sA4DbiQoKEiSlJiYaFoma11WWcBM1ueHxGdISUFQApyUlJQk6f/1NKB0a926taTr77vZYO0dO3ZIEndEIk9Znx8SnyElBUEJcEJmZqa++uorSVJISEgxtwZFITAwUO3bt5ckLVy4MNv6mJgYJSYmymq1qnv37kXdPJQwX375paTrl2kbNWpUzK2BIwhKwN8sWLAgx3FOp0+fVv/+/bV79255enrq2WefLYbWoTi88sorkqTJkydr165dtuVJSUkaPny4JGnEiBHy9/cvlvbBfezevVsrVqxQRkaG3fLMzEzNmjXL9rsUGRkpT0/P4mginGQxDMMo7kYA7qRHjx5avny5GjZsqKZNm8rHx0dHjhzR7t27deHCBZUvX15z585Vnz59irupKELPPfecpk6dKk9PT3Xp0kU+Pj5at26dkpOTFRoaqrVr1/JQXGjZsmXq2bOnKlWqpDZt2iggIEDJycnat2+fjhw5IkmKiIjQ559/Lg8P7qcqCQhKwN8sXbpU3377rXbv3q2TJ08qOTlZ3t7eql+/vrp06aJnnnnGdIZmlG5fffWVpk2bpt27d+vq1auqX7++BgwYoFGjRqlcuXLF3Ty4gfj4eE2dOlU7duxQfHy8kpKSZBiGAgICFBISokGDBnGJtoQhKAEAAJhgjBIAAIAJghIAAIAJghIAAIAJghIAAIAJghIAAIAJghIAAIAJghIAAIAJghIAAIAJghKAXAUFBcliseT5mjt3bnE3tcSJi4tT2bJlsz03cMOGDbbzmpuEhARbuYSEBJfbEx8fr3Llyqlv374u1wWUFjxoBoBDQkND1aBBA9P1ua1Dzp599ll5e3tr7Nixxd0USVJwcLCGDBmiadOmaePGjbrzzjuLu0lAsSMoAXDIU089pYEDBxZ3M0qNr7/+Wps2bdKLL76o6tWrF3dzbF577TV9+umnGjVqlHbt2lXczQGKHZfeAKAYvP/++5KkJ598sphbYq9GjRrq3r274uLi9NNPPxV3c4BiR1ACUChuHGPzzTffKCwsTH5+fvLx8VFoaKiio6NNt83IyNDMmTPVuXNnVa5cWVarVcHBwRo2bJgSExOzlc8a09O5c2f99ddfGjdunJo0aaLy5csrKCjIVs4wDM2ePVvt2rVT+fLlVaVKFXXr1k2bN2+2qyPLnDlzZLFYdO+995q29fjx4/L09JS3t7eSkpIcOjdxcXHavHmzOnTooEaNGjm0jbMOHz6sf//73woPD1edOnVktVpVsWJFhYWFacaMGcrMzDTdNqvncNq0aYXSNqAkISgBKFSvv/66+vTpI0nq3r27GjZsqM2bN+uBBx7Q0qVLs5VPS0vT3XffrcGDB2vnzp1q0aKFHnroIVmtVk2fPl2tW7dWXFxcjvu6fPmyOnfurPfee0/BwcF66KGH1LBhQ9v6Z555Rk8++aTi4uIUEhKie+65R4mJibrjjjv03XffZauvX79+qlatmtauXas//vgjx33OmDFDGRkZioiIUJUqVRw6J8uWLZMkde3a1aHy+fHFF19o9OjRSkhI0K233qpevXqpVatWio2N1dChQ9WnTx8ZhpHjtuHh4SpTpoy+//57Xb16tdDaCJQIBgDkom7duoYkY86cOU5tJ8mQZFSsWNHYunWr3brXX3/dkGTceuut2bbr16+fIcl44IEHjFOnTtmte//99w1JRsOGDY2MjAzb8h9//NG2vxYtWhgnTpzIVu/y5csNSYavr6+xadMmu3Xvvvuubfs777zTbt2rr75qSDIiIyOz1XnlyhWjRo0ahiRj586deZ6TLGFhYYYk4/vvv89x/Y3Hk5v4+Hhbufj4eLt127dvN/bu3Zttm2PHjhktW7Y0JBlfffWVad0tWrQwJBk///xz3gcElGIEJQC5ygpKeb3Onz9vt13W8qlTp2ar8/Lly4a/v78hyThy5Iht+f79+w2LxWLccsstRmpqao7t6d69uyHJWLlypW3ZjcHip59+ynG78PBwQ5IxZsyYHNe3b98+x6B07Ngxw9PT0/D39zcuXLhgt27RokWGJKNjx4451mnGx8fHkGQcOnQox/U3Ho+jr78HpdysXr3akGT06dPHtExERIQhyYiKinLq2IDShrveADgkr+kBypUrl+PyBx98MNsyq9WqevXqKS4uTseOHVPt2rUlSdHR0TIMQ926dVOFChVyrK9z586Kjo62Xb67UfXq1dWpU6ds22RkZGjz5s2SpP79++dYb79+/RQbG5tt+S233KLevXtr0aJF+uKLLzR06FDbuqwxPCNGjMixzpxcvHhRFy9elCSHLtU98cQTpusuXLigb775xnR9enq61qxZo9jYWJ0+fVrp6ekyDENpaWmSpAMHDphum9W2U6dO5dlGoDQjKAFwSH6nB6hTp06Oy/38/CRdH1eU5dChQ5KkWbNmadasWbnWe+bMmWzLbhy4faOzZ8/a9mNWxmy5JEVGRmrRokWaNm2aLSj98ssviomJUUBAgHr37p1rW2+UkpJi+7dZGLxRbhN5JiQkmAalrVu36tFHH9WRI0dMt09NTTVdl/X+nD9/Ps82AqUZQQlAoSpTxvF7RrLuxGrVqpVatmyZa9nbbrst2zJvb2/nGneD3GbB7tChg0JCQrR9+3bbRIxZvUlDhgwx7U3LScWKFW3/TktLswWSgvTXX3+pR48eOnXqlAYNGqRhw4apQYMG8vPzU9myZfXHH3+oUaNGpoO5pf8X6CpVqlTg7QNKEoISALeRdQkuNDRUH330UYHVW6VKFVmtVqWnp+vw4cNq2rRptjJ5PQIkMjJSAwYM0EcffaSWLVtqwYIF8vDwsLsU54jy5cvLx8dHFy9eVFJSUqEEpZ9++kmnTp1SmzZtNHv27Gzr//zzzzzryJrqICAgoMDbB5QkTA8AwG1069ZNkrRixQq7S3Ku8vT0VMeOHSVJCxcuzLHMokWLcq2jb9++qlmzppYtW6a33npLFy9eVM+ePXXLLbc43Z42bdpIkvbv3+/0to44d+6cJPPLnvPnz8+zjn379kmS2rZtW3ANA0ogghIAt9G6dWs98sgjSkxMVK9evXLs5bl48aIWLFjg9CDjyMhISdLUqVO1detWu3VRUVHatm1brtt7enpq2LBhysjI0DvvvCPJuUHcN7rrrrskSVu2bMnX9nlp0qSJJGndunXZwtinn36qxYsX57p9SkqK9u/fL19fX4WEhBRKG4GSgktvABwyc+ZMbdiwwXT9Pffco379+rm8nzlz5ig5OVk//PCDGjVqpJYtWyo4OFiGYSghIUF79uzRlStX9Ntvvzl1Wahnz54aMmSIPv30U4WFhalTp06qWbOm9u7dq99++02jRo3S+++/n+t4o6efflpvvfWW0tPT1aJFC91xxx35OsYePXpowoQJWrt2rd5888181ZGb1q1b6+GHH9by5cvVunVr2wznu3fv1oEDB/TKK6/orbfeMt1+/fr1yszMVPfu3eXp6Vng7QNKEoISAIds2rRJmzZtMl1fsWLFAglKFSpU0Jo1a7R48WLNnz9fO3fu1O7du+Xn56eaNWuqf//+euihh1S/fn2n654+fbrat2+vTz75RFu3bpWXl5dCQkL08ccf23qvqlatarp99erV1apVK23btk3PPPNMfg9RrVu31u23367Nmzfrt99+s/UAFaQlS5YoKipKn3/+uWJiYuTl5aV27dpp6tSpatiwYa5BKetOO1eOESgtLEZutz0AwE3in//8p+bMmaN3331Xzz//fI5l/vjjDzVu3Fj+/v46duyYypcvn+/9ff311+rTp4+ef/55vfvuu/mup6CdPHlSderUUbNmzbRr167ibg5Q7BijBOCm8euvv9ome8ySmZmpzz77THPnzpWXl5ciIiJMtx83bpwMw9CwYcNcCkmS1Lt3b4WGhmrGjBluNanjxIkTdfXqVb333nvF3RTALdCjBOCmMXDgQH311Vdq3bq1atWqpYsXL2r//v1KSEhQ2bJl9dlnn2nQoEF226xYsULLly/Xr7/+qm3btqlGjRr67bff7OZDyq+4uDi1a9dOw4YNK9DpEPLr0KFDaty4sXr06KGvvvqquJsDuAXGKAG4aTz66KNKTU21jXvKyMhQ9erV9eijj2rkyJHq0KFDtm127dql2bNnq0KFCuratavee++9AglJ0vWxSteuXSuQugpCvXr1dOXKleJuBuBW6FECAAAwwRglAAAAEwQlAAAAEwQlAAAAEwQlAAAAEwQlAAAAEwQlAAAAEwQlAAAAEwQlAAAAEwQlAAAAE/8fwHDBu4jI/h8AAAAASUVORK5CYII=", + "image/png": "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ElUFj3LEQ1JFyhERvQoMcjA3AISFhSEiIgLz589H27ZtERISAmtraxw4cACZmZkICAjAzJkzFbbJysrC9evXkZ+v/EG/cuVKvPnmm7h69SqaNm2Ktm3bombNmrh69SouX74MABg4cCAGDBhQKcdHVNmcbFWbnV7VckRErwKDDUoAEBkZiYCAACxcuBDHjx/H8+fP0bBhQ0yYMAHjxo2Dubm5ynV5eXnhn3/+wc8//4y//voL8fHxKCgoQI0aNdC5c2d89NFH6Nu3rw6Phki//D0cUMfeAg+z8ksdpyQBUNveAv4eDqWsJSJ6NUkEQeDITQ1kZ2fD3t4eWVlZ/AYcGTzZt94AKIQlyf/9d9HAVpwigIheCar+/TbYMUpEpH3veNXBooGtUNte8fZabXsLhiQiolIY9K03ItK+d7zq4K1mtXE6MQOPcvLhZPvidls1E0n5GxMRvWIYlIheQdVMJGjX0FHfzSAiMni89UZEREQkgkGJiIiISASDEhEREZEIBiUiIiIiEQxKRERERCIYlIiIiIhEMCgRERERiWBQIiIiIhLBoEREREQkgkGJiIiISASDEhEREZEIBiUiIiIiEQxKRERERCIYlIiIiIhEMCgRERERiWBQIiIiIhLBoEREREQkgkGJiIiISASDEhEREZEIBiUiIiIiEQxKRERERCIYlIiIiIhEMCgRERERiWBQIiIiIhLBoEREREQkgkGJiIiISASDEhEREZEIBiUiIiIiEQxKRERERCIYlIiIiIhEMCgRERERiWBQIiIiIhLBoEREREQkgkGJiIiISASDEhEREZEIBiUiIiIiEQxKRERERCIYlIiIiIhEMCgRERERiWBQIiIiIhLBoEREREQkgkGJiIiISASDEhEREZEIBiUiIiIiEQxKRERERCIYlIiIiIhEMCgRERERiWBQIiIiIhLBoEREREQkgkGJiIiISASDEhEREZEIBiUiIiIiEQxKRERERCIYlIiIiIhEMCgRERERiWBQIiIiIhLBoEREREQkgkGJiIiISASDEhEREZEIBiUiIiIiEQxKRERERCIYlIiIiIhEMCgRERERiWBQIiIiIhLBoEREREQkwuCDUlRUFIKCglCjRg1YW1ujRYsWmDt3Lp4/f17hOnfs2IHu3bujdu3aMDc3h5OTE9544w3MmDFDiy0nIiIiYycRBEHQdyPEjB07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djRp0gQhISFK9cXExKB3794oKirC4sWLGZKIiIioXAY5RgkAwsLCEBERgfnz56Nt27YICQmBtbU1Dhw4gMzMTAQEBGDmzJkK22RlZeH69evIz89XWP7o0SP07NkThYWFcHFxwfHjx3H8+PFS9ztv3jzUrFlTZ8dFRERExsNggxIAREZGIiAgAAsXLsTx48fx/PlzNGzYEBMmTMC4ceNgbm6uUj1Pnz6Vz3107949rFmzRrTstGnTGJSIiIgIgAE/FNdY8KG4RERExseoH4pLREREZAgYlIiIiIhEMCgRERERiWBQIiIiIhLBoEREREQkgkGJiIiISASDEhEREZEIBiUiIiIiEQxKRERERCIYlIiIiIhEMCgRERERiWBQIiIiIhLBoEREREQkgkGJiIiISASDEhEREZEIBiUiIiIiEQxKRERERCIYlIiIiIhEMCgRERERiWBQIiIiIhLBoEREREQkgkGJiIiISASDEhEREZEIBiUiIiIiEQxKRERERCIYlIiIiIhEMCgRERERiWBQIiIiIhLBoEREREQkwlTfDSAiw1BcIuB0YgYe5eTDydYC/h4OqGYi0XeziIj0ikGJiLDnnweYvusKHmTly5fVsbfAt+82wztedfTYMiIi/eKtN6JX3J5/HmDk+nMKIQkAHmblY+T6c9jzzwM9tYyISP8YlIheYcUlAqbvugKhlHWyZdN3XUFxSWkliIiqPgYlolfY6cQMpZ6klwkAHmTl43RiRuU1iojIgDAoEb3CHuWIh6SKlCMiqmoYlIheYU62FlotR0RU1TAoEb3C/D0cUMfeAmKTAEjw4ttv/h4OldksIiKDwaBE9AqrZiLBt+82AwClsCT7+dt3m3E+JSJ6ZTEoEb3i3vGqg0UDW6G2veLttdr2Flg0sBXnUSKiVxonnCQivONVB281q82ZuYmI/oNBiYgAvLgN166ho76bQURkUHjrjYiIiEgEgxIRERGRCAYlIiIiIhEMSkREREQiGJSIiIiIRDAoEREREYlgUCIiIiISwaBEREREJIJBiYiIiEgEgxIRERGRCAYlIiIiIhEMSkREREQiGJSIiIiIRDAoEREREYlgUCIiIiISwaBEREREJIJBiYiIiEiEqb4bQES6V1wi4HRiBh7l5MPJ1gL+Hg6oZiLRd7OIiAwegxJRFbfnnweYvusKHmTly5fVsbfAt+82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", "text/plain": [ "
" ] @@ -805,7 +725,7 @@ "num_shots = res.num_shots\n", "\n", "energy_results = {\n", - " sample.state[\"phase\"] * normalization: sample.shots / num_shots\n", + " sample.state[\"phase\"] * normalization + constant_energy: sample.shots / num_shots\n", " for sample in phase_counts\n", "}\n", "\n", @@ -834,7 +754,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 18, "id": "342f2fdd-1f07-4005-aecd-10155222dab4", "metadata": {}, "outputs": [ @@ -843,11 +763,11 @@ "output_type": "stream", "text": [ "Number of maxima: 1\n", - "maxima over the threshold at [-1.1009663875965574] Ha\n", + "maxima over the threshold at [-7.904148198365434] Ha\n", "\n", - "Lowest eigenvalue: -1.1009663875965574 Ha\n", - "Precision: 0.13762079844956968 Ha\n", - "Classical solution:, -1.0789776863285236 Ha\n" + "Lowest eigenvalue: -7.904148198365434 Ha\n", + "Precision: 0.13762079844957015 Ha\n", + "Classical solution:, -7.882386993638953 Ha\n" ] } ], @@ -902,6 +822,7 @@ "\n", "[3] [Diamond Norm (Wikipedia).\n", "](https://en.wikipedia.org/wiki/Diamond_norm)\n", + "\n", "\n" ] } diff --git a/applications/chemistry/qpe_for_molecules/qpe_for_molecules.qmod b/applications/chemistry/qpe_for_molecules/qpe_for_molecules.qmod index 8a60b25cf..c5bb9dd73 100644 --- a/applications/chemistry/qpe_for_molecules/qpe_for_molecules.qmod +++ b/applications/chemistry/qpe_for_molecules/qpe_for_molecules.qmod @@ -1,571 +1,439 @@ -qfunc powered_st2_for_LiH(p: int, state: qbit[]) { - suzuki_trotter([ - PauliTerm { - pauli=[ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I - ], - coefficient=0.0696 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::Z, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::Z - ], - coefficient=0.0169 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Z - ], - coefficient=-0.0222 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::Z, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I - ], - coefficient=-0.003 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::I, - Pauli::I - ], - coefficient=-0.0484 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::I, - Pauli::Z, - Pauli::Z - ], - coefficient=-0.0073 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I - ], - coefficient=-0.0484 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::Z - ], - coefficient=-0.0073 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Z, - Pauli::I - ], - coefficient=-0.032 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::Z, - Pauli::Z, - Pauli::I, - Pauli::I, - Pauli::Z - ], - coefficient=-0.0047 - }, - PauliTerm { - pauli=[ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::I, - Pauli::I - ], - coefficient=0.0169 - }, - PauliTerm { - pauli=[ - Pauli::Z, - Pauli::I, - Pauli::I, - Pauli::Z, - Pauli::Z, - Pauli::Z - ], - coefficient=0.0069 - }, - PauliTerm { - pauli=[ - Pauli::X, - Pauli::Z, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::Z - ], - coefficient=-0.0018 - }, - PauliTerm { - pauli=[ - Pauli::X, - Pauli::I, - Pauli::I, - Pauli::Z, - Pauli::Z, - Pauli::Z - ], - coefficient=-0.0018 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::I - ], - coefficient=-0.0222 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z - ], - coefficient=-0.0032 - }, - PauliTerm { - pauli=[ - Pauli::Z, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I - ], - coefficient=-0.032 - }, - PauliTerm { - pauli=[ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::Z - ], - coefficient=-0.0064 - }, - PauliTerm { - pauli=[ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::X, - Pauli::I - ], - coefficient=-0.0018 - }, - PauliTerm { - pauli=[ - Pauli::Z, - Pauli::I, - Pauli::I, - Pauli::Z, - Pauli::X, - Pauli::Z - ], - coefficient=-0.0018 - }, - PauliTerm { - pauli=[ - Pauli::X, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::X, - Pauli::I - ], - coefficient=0.0018 - }, - PauliTerm { - pauli=[ - Pauli::X, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::X, - Pauli::I - ], - coefficient=0.0018 - }, - PauliTerm { - pauli=[ - Pauli::X, - Pauli::Z, - Pauli::Z, - Pauli::I, - Pauli::X, - Pauli::Z - ], - coefficient=0.0018 - }, - PauliTerm { - pauli=[ - Pauli::X, - Pauli::I, - Pauli::I, - Pauli::Z, - Pauli::X, - Pauli::Z - ], - coefficient=0.0018 - }, - PauliTerm { - pauli=[ - Pauli::Z, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::X, - Pauli::I - ], - coefficient=0.0019 - }, - PauliTerm { - pauli=[ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::I, - Pauli::X, - Pauli::Z - ], - coefficient=0.0019 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::I, - Pauli::Z - ], - coefficient=0.0074 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Z - ], - coefficient=0.0074 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Z, - Pauli::Z - ], - coefficient=0.0031 - }, - PauliTerm { - pauli=[ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::I, - Pauli::Z - ], - coefficient=-0.0032 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z - ], - coefficient=0.0048 - }, - PauliTerm { - pauli=[ - Pauli::Z, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Z - ], - coefficient=0.0034 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::Z, - Pauli::Z, - Pauli::I, - Pauli::I, - Pauli::I - ], - coefficient=0.0154 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I - ], - coefficient=0.0073 - }, - PauliTerm { - pauli=[ - Pauli::Z, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::I - ], - coefficient=-0.0073 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::I, - Pauli::Z, - Pauli::Z, - Pauli::I, - Pauli::I - ], - coefficient=0.0074 - }, - PauliTerm { - pauli=[ - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::I, - Pauli::I - ], - coefficient=0.0073 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::I, - Pauli::Z, - Pauli::I - ], - coefficient=0.0073 - }, - PauliTerm { - pauli=[ - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::Z, - Pauli::I, - Pauli::I - ], - coefficient=-0.0073 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::I - ], - coefficient=0.0074 - }, - PauliTerm { - pauli=[ - Pauli::Z, - Pauli::Z, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::I - ], - coefficient=0.0073 - }, - PauliTerm { - pauli=[ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::I - ], - coefficient=-0.0064 - }, - PauliTerm { - pauli=[ - Pauli::X, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Z, - Pauli::I - ], - coefficient=0.0019 - }, - PauliTerm { - pauli=[ - Pauli::X, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::I - ], - coefficient=0.0019 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Z, - Pauli::Z, - Pauli::I - ], - coefficient=0.0034 - }, - PauliTerm { - pauli=[ - Pauli::Z, - Pauli::I, - Pauli::I, - Pauli::I, - Pauli::Z, - Pauli::I - ], - coefficient=0.0064 - }, - PauliTerm { - pauli=[ - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::I, - Pauli::I, - Pauli::I - ], - coefficient=-0.003 - }, - PauliTerm { - pauli=[ - Pauli::I, - Pauli::Z, - Pauli::Z, - Pauli::Z, - Pauli::I, - Pauli::I - ], - coefficient=-0.0047 - }, - PauliTerm { - pauli=[ - Pauli::Z, - Pauli::I, - Pauli::I, - Pauli::Z, - Pauli::I, - Pauli::I - ], - coefficient=0.0031 +qfunc prepare_basis_state_expanded___0(output arr: qbit[6]) { + allocate(6, arr); +} + +qfunc apply_to_all_expanded___0(target: qbit[7]) { + repeat (index: 7) { + H(target[index]); + } +} + +qfunc powered_st2_for_LiH_expanded___0(p: int, state: qbit[6]) { + suzuki_trotter(SparsePauliOp { + terms=[ + SparsePauliTerm { + paulis=[], + coefficient=0.0696 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=0.0169 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=0.0169 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=5} + ], + coefficient=-0.0222 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=1} + ], + coefficient=-0.0222 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=4} + ], + coefficient=-0.0484 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=3} + ], + coefficient=-0.0484 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=2} + ], + coefficient=-0.032 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0} + ], + coefficient=-0.032 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=0.0069 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=1, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=-0.0018 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=1, index=2}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=-0.0018 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=0}, + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=-0.0018 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=-0.0018 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=0}, + IndexedPauli {pauli=1, index=2} + ], + coefficient=0.0018 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=1, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=0.0018 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=0}, + IndexedPauli {pauli=1, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=0.0018 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=1, index=2}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=0.0018 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=-0.003 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=-0.0032 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=-0.0073 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=-0.0073 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=-0.0047 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=-0.0064 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=1, index=2} + ], + coefficient=0.0019 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=1, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=0.0019 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=-0.0032 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=-0.003 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=3} + ], + coefficient=-0.0073 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=-0.0073 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=-0.0064 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=0}, + IndexedPauli {pauli=3, index=2} + ], + coefficient=0.0019 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=1, index=0}, + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=0.0019 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=-0.0047 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=0.0048 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=4}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=0.0074 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=0.0074 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=0.0031 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=3, index=5} + ], + coefficient=0.0034 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=0.0074 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=3} + ], + coefficient=0.0074 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=1}, + IndexedPauli {pauli=3, index=2} + ], + coefficient=0.0034 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=3, index=1} + ], + coefficient=0.0031 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=3}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=0.0154 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=0.0073 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=3, index=4} + ], + coefficient=0.0073 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=2}, + IndexedPauli {pauli=3, index=3} + ], + coefficient=0.0073 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=3, index=3} + ], + coefficient=0.0073 + }, + SparsePauliTerm { + paulis=[ + IndexedPauli {pauli=3, index=0}, + IndexedPauli {pauli=3, index=2} + ], + coefficient=0.0064 + } + ], + num_qubits=6 + }, (-6.2832) * p, 2, ceiling(0.05 * (p ** 1.5)), state); +} + +qfunc unitary_with_power_0_lambda___0_0_expanded___0(p: int, state_captured__main__0: qbit[6]) { + powered_st2_for_LiH_expanded___0(p, state_captured__main__0); +} + +qfunc qft_no_swap_expanded___0(qbv: qbit[7]) { + repeat (i: 7) { + H(qbv[i]); + repeat (j: 6 - i) { + CPHASE(3.1416 * (2.0 ** ((-j) - 1.0)), qbv[(i + j) + 1], qbv[i]); + } + } +} + +qfunc qft_expanded___0(target: qbit[7]) { + repeat (index: 3.5) { + SWAP(target[index], target[6 - index]); + } + qft_no_swap_expanded___0(target); +} + +qfunc qpe_flexible_expanded___0(phase: qbit[7], state_captured__main__0: qbit[6]) { + apply_to_all_expanded___0(phase); + repeat (index: 7) { + control (phase[index]) { + unitary_with_power_0_lambda___0_0_expanded___0(2 ** index, state_captured__main__0); } - ], ((-2) * pi) * p, 2, ceiling(0.05 * (p ** 1.5)), state); + } + invert { + qft_expanded___0(phase); + } } -qfunc main(output state: qbit[], output phase: qnum<7, SIGNED, 7>) { - allocate(6, state); - molecule_hartree_fock(MoleculeProblem { - mapping=FermionMapping::JORDAN_WIGNER, - z2_symmetries=True, - molecule=Molecule { - atoms=[ - ChemistryAtom { - element=Element::H, - position=Position {x=0.0, y=0.0, z=0.0} - }, - ChemistryAtom { - element=Element::Li, - position=Position {x=0.0, y=0.0, z=1.596} - } - ], - spin=1, - charge=0 - }, - freeze_core=True, - remove_orbitals=[] - }, state); +qfunc main(output state: qbit[6], output phase: qnum<7, True, 7>) { + prepare_basis_state_expanded___0(state); allocate(7, phase); - qpe_flexible(lambda(p) { - powered_st2_for_LiH(p, state); - }, phase); + qpe_flexible_expanded___0(phase, state); } diff --git a/applications/chemistry/qpe_for_molecules/qpe_for_molecules.synthesis_options.json b/applications/chemistry/qpe_for_molecules/qpe_for_molecules.synthesis_options.json index b694c1897..3df19af6e 100644 --- a/applications/chemistry/qpe_for_molecules/qpe_for_molecules.synthesis_options.json +++ b/applications/chemistry/qpe_for_molecules/qpe_for_molecules.synthesis_options.json @@ -7,28 +7,28 @@ "machine_precision": 8, "custom_hardware_settings": { "basis_gates": [ - "u2", - "r", - "cy", - "t", + "h", "sdg", + "r", + "tdg", + "rx", + "sx", + "sxdg", + "ry", + "p", + "u1", "x", + "u2", "z", + "t", "s", - "h", - "sxdg", - "p", - "u", - "rx", "rz", - "y", + "cy", "cz", - "tdg", "cx", - "sx", - "u1", - "id", - "ry" + "u", + "y", + "id" ], "is_symmetric_connectivity": true }, @@ -39,6 +39,6 @@ "pretty_qasm": true, "transpilation_option": "auto optimize", "timeout_seconds": 600, - "random_seed": 723171489 + "random_seed": 1351002448 } } diff --git a/applications/chemistry/second_quantized_hamiltonian/second_quantized_hamiltonian.ipynb b/applications/chemistry/second_quantized_hamiltonian/second_quantized_hamiltonian.ipynb index 379406eeb..67f1f4d86 100644 --- a/applications/chemistry/second_quantized_hamiltonian/second_quantized_hamiltonian.ipynb +++ b/applications/chemistry/second_quantized_hamiltonian/second_quantized_hamiltonian.ipynb @@ -17,29 +17,21 @@ "execution_count": 1, "id": "151e1188", "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:14:02.285843Z", - "iopub.status.busy": "2024-05-07T15:14:02.282963Z", - "iopub.status.idle": "2024-05-07T15:14:05.330696Z", - "shell.execute_reply": "2024-05-07T15:14:05.330041Z" - }, "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ + "import time\n", + "\n", "import numpy as np\n", + "from openfermion import FermionOperator\n", "\n", "from classiq import *\n", - "from classiq.applications.chemistry import (\n", - " ChemistryExecutionParameters,\n", - " FermionicOperator,\n", - " HamiltonianProblem,\n", - " HEAParameters,\n", - " SummedFermionicOperator,\n", - ")\n", - "from classiq.execution import OptimizerType" + "from classiq.applications.chemistry.mapping import FermionToQubitMapper\n", + "from classiq.applications.chemistry.op_utils import qubit_op_to_pauli_terms\n", + "from classiq.applications.chemistry.problems import FermionHamiltonianProblem" ] }, { @@ -47,12 +39,6 @@ "execution_count": 2, "id": "a34b8008", "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:14:05.333874Z", - "iopub.status.busy": "2024-05-07T15:14:05.333266Z", - "iopub.status.idle": "2024-05-07T15:14:05.339319Z", - "shell.execute_reply": "2024-05-07T15:14:05.338667Z" - }, "pycharm": { "name": "#%%\n" } @@ -62,29 +48,25 @@ "name": "stdout", "output_type": "stream", "text": [ - "0.2 * a⁺₀a₀ + \n", - "0.3 * a₁a₁ + \n", - "0.4 * a₂a₂ + \n", - "0.5 * a₃a₃ + \n", - "-0.1 * a⁺₀a⁺₁a₁a₀ + \n", - "-0.3 * a⁺₂a⁺₃a₂a₃\n" + "0.2 [0^ 0] +\n", + "-0.1 [0^ 1^ 1 0] +\n", + "-0.3 [2^ 3^ 2 3]\n" ] } ], "source": [ - "hamiltonian = SummedFermionicOperator(\n", - " op_list=[\n", - " (FermionicOperator(op_list=[(\"+\", 0), (\"-\", 0)]), 0.2),\n", - " (FermionicOperator(op_list=[(\"-\", 1), (\"-\", 1)]), 0.3),\n", - " (FermionicOperator(op_list=[(\"-\", 2), (\"-\", 2)]), 0.4),\n", - " (FermionicOperator(op_list=[(\"-\", 3), (\"-\", 3)]), 0.5),\n", - " (FermionicOperator(op_list=[(\"+\", 0), (\"+\", 1), (\"-\", 1), (\"-\", 0)]), -0.1),\n", - " (FermionicOperator(op_list=[(\"+\", 2), (\"+\", 3), (\"-\", 2), (\"-\", 3)]), -0.3),\n", - " ]\n", + "op_list = [\n", + " FermionOperator(\"0^ 0\", 0.2),\n", + " FermionOperator(\"0^ 1^ 1 0\", -0.1),\n", + " FermionOperator(\"2^ 3^ 2 3\", -0.3),\n", + "]\n", + "hamiltonian = sum(op_list)\n", + "\n", + "ham_problem = FermionHamiltonianProblem(\n", + " fermion_hamiltonian=hamiltonian, n_particles=(1, 1)\n", ")\n", - "ham_problem = HamiltonianProblem(hamiltonian=hamiltonian, num_particles=[1, 1])\n", "\n", - "print(ham_problem.hamiltonian)" + "print(ham_problem.fermion_hamiltonian)" ] }, { @@ -92,50 +74,43 @@ "execution_count": 3, "id": "b37a0870-c254-4459-a2cc-840a6f8d4a4f", "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:14:05.341642Z", - "iopub.status.busy": "2024-05-07T15:14:05.341283Z", - "iopub.status.idle": "2024-05-07T15:14:05.350068Z", - "shell.execute_reply": "2024-05-07T15:14:05.349441Z" - }, "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ - "hwea_params = HEAParameters(\n", - " num_qubits=4,\n", - " connectivity_map=[(0, 1), (1, 2), (2, 3)],\n", - " reps=3,\n", - " one_qubit_gates=[\"x\", \"ry\"],\n", - " two_qubit_gates=[\"cx\"],\n", - ")\n", + "mapper = FermionToQubitMapper()\n", + "vqe_hamiltonian = qubit_op_to_pauli_terms(mapper.map(ham_problem.fermion_hamiltonian))\n", + "num_qubits = mapper.get_num_qubits(ham_problem)\n", "\n", - "qmod = construct_chemistry_model(\n", - " chemistry_problem=ham_problem,\n", - " use_hartree_fock=False,\n", - " ansatz_parameters=hwea_params,\n", - " execution_parameters=ChemistryExecutionParameters(\n", - " optimizer=OptimizerType.COBYLA,\n", - " max_iteration=100,\n", - " initial_point=None,\n", - " ),\n", - ")\n", - "write_qmod(qmod, name=\"second_quantized_hamiltonian\")" + "reps = 3\n", + "num_params = reps * num_qubits\n", + "\n", + "\n", + "@qfunc\n", + "def main(params: CArray[CReal, num_params], state: Output[QArray[QBit, num_qubits]]):\n", + " allocate(state)\n", + " full_hea(\n", + " num_qubits=num_qubits,\n", + " operands_1qubit=[lambda _, q: X(q), lambda theta, q: RY(theta, q)],\n", + " operands_2qubit=[lambda _, q1, q2: CX(q1, q2)],\n", + " is_parametrized=[0, 1, 0],\n", + " angle_params=params,\n", + " connectivity_map=[(0, 1), (1, 2), (2, 3)],\n", + " reps=reps,\n", + " x=state,\n", + " )\n", + "\n", + "\n", + "write_qmod(main, \"second_quantized_hamiltonian\")" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "id": "7657b2e7-4b3d-4ac1-807c-665dfb05007f", "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:14:05.369638Z", - "iopub.status.busy": "2024-05-07T15:14:05.369046Z", - "iopub.status.idle": "2024-05-07T15:14:08.802073Z", - "shell.execute_reply": "2024-05-07T15:14:08.801359Z" - }, "pycharm": { "name": "#%%\n" } @@ -145,42 +120,47 @@ "name": "stdout", "output_type": "stream", "text": [ - "Opening: https://platform.classiq.io/circuit/2806f7a1-c17c-4a05-9abb-d19786e25884?version=0.41.0.dev39%2B79c8fd0855\n" + "Quantum program link: https://platform.classiq.io/circuit/2z2Pn8HYrS4DcJQbHXR4VCudnrx\n" ] } ], "source": [ - "qprog = synthesize(qmod)\n", + "qprog = synthesize(main)\n", "show(qprog)" ] }, + { + "cell_type": "code", + "execution_count": 5, + "id": "6f986d61-c6ab-48b3-a1b6-877e435d8092", + "metadata": {}, + "outputs": [], + "source": [ + "with ExecutionSession(qprog) as es:\n", + " result = es.minimize(\n", + " cost_function=vqe_hamiltonian,\n", + " initial_params={\"params\": [0.0] * num_params},\n", + " max_iteration=200,\n", + " )" + ] + }, { "cell_type": "code", "execution_count": 6, - "id": "ccad338b", - "metadata": { - "execution": { - "iopub.execute_input": "2024-05-07T15:14:08.804889Z", - "iopub.status.busy": "2024-05-07T15:14:08.804325Z", - "iopub.status.idle": "2024-05-07T15:14:13.717989Z", - "shell.execute_reply": "2024-05-07T15:14:13.717206Z" - } - }, + "id": "70287cea-f706-4bf5-93e4-2fae16bfbafa", + "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "0.0006000000000000068" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "vqe result: 0.00029296875000001403\n" + ] } ], "source": [ - "result = execute(qprog).result_value()\n", - "result.energy" + "optimizer_res = result[-1][0]\n", + "print(\"vqe result:\", optimizer_res)" ] } ], diff --git a/applications/chemistry/second_quantized_hamiltonian/second_quantized_hamiltonian.qmod b/applications/chemistry/second_quantized_hamiltonian/second_quantized_hamiltonian.qmod index 8219abe1e..f83362f33 100644 --- a/applications/chemistry/second_quantized_hamiltonian/second_quantized_hamiltonian.qmod +++ b/applications/chemistry/second_quantized_hamiltonian/second_quantized_hamiltonian.qmod @@ -1,171 +1,10 @@ -qfunc main(t: real[12], output qbv: qbit[]) { - allocate(fock_hamiltonian_problem_to_hamiltonian(FockHamiltonianProblem { - mapping=FermionMapping::JORDAN_WIGNER, - z2_symmetries=False, - terms=[ - LadderTerm { - coefficient=0.2, - ops=[ - LadderOp { - op=LadderOperator::PLUS, - index=0 - }, - LadderOp { - op=LadderOperator::MINUS, - index=0 - } - ] - }, - LadderTerm { - coefficient=0.3, - ops=[ - LadderOp { - op=LadderOperator::MINUS, - index=1 - }, - LadderOp { - op=LadderOperator::MINUS, - index=1 - } - ] - }, - LadderTerm { - coefficient=0.4, - ops=[ - LadderOp { - op=LadderOperator::MINUS, - index=2 - }, - LadderOp { - op=LadderOperator::MINUS, - index=2 - } - ] - }, - LadderTerm { - coefficient=0.5, - ops=[ - LadderOp { - op=LadderOperator::MINUS, - index=3 - }, - LadderOp { - op=LadderOperator::MINUS, - index=3 - } - ] - }, - LadderTerm { - coefficient=-0.1, - ops=[ - LadderOp { - op=LadderOperator::PLUS, - index=0 - }, - LadderOp { - op=LadderOperator::PLUS, - index=1 - }, - LadderOp { - op=LadderOperator::MINUS, - index=1 - }, - LadderOp { - op=LadderOperator::MINUS, - index=0 - } - ] - }, - LadderTerm { - coefficient=-0.3, - ops=[ - LadderOp { - op=LadderOperator::PLUS, - index=2 - }, - LadderOp { - op=LadderOperator::PLUS, - index=3 - }, - LadderOp { - op=LadderOperator::MINUS, - index=2 - }, - LadderOp { - op=LadderOperator::MINUS, - index=3 - } - ] - } - ], - num_particles=[1, 1] - })[0].pauli.len, qbv); - full_hea(4, [0, 1, 0], t, [[0, 1], [1, 2], [2, 3]], 3, [lambda(angle, q) { +qfunc main(params: real[12], output state: qbit[4]) { + allocate(state); + full_hea(4, [0, 1, 0], params, [[0, 1], [1, 2], [2, 3]], 3, [lambda(_, q) { X(q); - }, lambda(angle, q) { - RY(angle, q); - }], [lambda(angle, q1, q2) { + }, lambda(theta, q) { + RY(theta, q); + }], [lambda(_, q1, q2) { CX(q1, q2); - }], qbv); + }], state); } - -cscope ``` -vqe_result = vqe( - hamiltonian=fock_hamiltonian_problem_to_hamiltonian(struct_literal(FockHamiltonianProblem,mapping=FermionMapping.JORDAN_WIGNER,z2_symmetries=False,terms=[ - struct_literal(LadderTerm, - coefficient=0.2, - ops=[ - struct_literal(LadderOp, op=LadderOperator.PLUS, index=0), - struct_literal(LadderOp, op=LadderOperator.MINUS, index=0) - ] - ), - struct_literal(LadderTerm, - coefficient=0.3, - ops=[ - struct_literal(LadderOp, op=LadderOperator.MINUS, index=1), - struct_literal(LadderOp, op=LadderOperator.MINUS, index=1) - ] - ), - struct_literal(LadderTerm, - coefficient=0.4, - ops=[ - struct_literal(LadderOp, op=LadderOperator.MINUS, index=2), - struct_literal(LadderOp, op=LadderOperator.MINUS, index=2) - ] - ), - struct_literal(LadderTerm, - coefficient=0.5, - ops=[ - struct_literal(LadderOp, op=LadderOperator.MINUS, index=3), - struct_literal(LadderOp, op=LadderOperator.MINUS, index=3) - ] - ), - struct_literal(LadderTerm, - coefficient=-0.1, - ops=[ - struct_literal(LadderOp, op=LadderOperator.PLUS, index=0), - struct_literal(LadderOp, op=LadderOperator.PLUS, index=1), - struct_literal(LadderOp, op=LadderOperator.MINUS, index=1), - struct_literal(LadderOp, op=LadderOperator.MINUS, index=0) - ] - ), - struct_literal(LadderTerm, - coefficient=-0.3, - ops=[ - struct_literal(LadderOp, op=LadderOperator.PLUS, index=2), - struct_literal(LadderOp, op=LadderOperator.PLUS, index=3), - struct_literal(LadderOp, op=LadderOperator.MINUS, index=2), - struct_literal(LadderOp, op=LadderOperator.MINUS, index=3) - ] - )],num_particles=[1, 1])), maximize=False, -initial_point=[], -optimizer=Optimizer.COBYLA, -max_iteration=100, -tolerance=0, -step_size=0, -skip_compute_variance=False, -alpha_cvar=1.0, - -) -save({'vqe_result': vqe_result}) -``` diff --git a/applications/chemistry/second_quantized_hamiltonian/second_quantized_hamiltonian.synthesis_options.json b/applications/chemistry/second_quantized_hamiltonian/second_quantized_hamiltonian.synthesis_options.json index 0967ef424..c4df8f20d 100644 --- a/applications/chemistry/second_quantized_hamiltonian/second_quantized_hamiltonian.synthesis_options.json +++ b/applications/chemistry/second_quantized_hamiltonian/second_quantized_hamiltonian.synthesis_options.json @@ -1 +1,44 @@ -{} +{ + "constraints": { + "max_gate_count": {}, + "optimization_parameter": "no_opt" + }, + "preferences": { + "machine_precision": 8, + "custom_hardware_settings": { + "basis_gates": [ + "z", + "id", + "s", + "cz", + "u", + "u1", + "p", + "r", + "cy", + "ry", + "cx", + "rz", + "x", + "sdg", + "sx", + "rx", + "y", + "sxdg", + "u2", + "tdg", + "t", + "h" + ], + "is_symmetric_connectivity": true + }, + "debug_mode": true, + "synthesize_all_separately": false, + "optimization_level": 3, + "output_format": ["qasm"], + "pretty_qasm": true, + "transpilation_option": "auto optimize", + "timeout_seconds": 300, + "random_seed": 1285000645 + } +} diff --git a/tests/notebooks/test_molecule_eigensolver_using_openfermion.py b/tests/notebooks/test_classiq_chemistry_application.py similarity index 73% rename from tests/notebooks/test_molecule_eigensolver_using_openfermion.py rename to tests/notebooks/test_classiq_chemistry_application.py index a6c612455..65c5e7b15 100644 --- a/tests/notebooks/test_molecule_eigensolver_using_openfermion.py +++ b/tests/notebooks/test_classiq_chemistry_application.py @@ -1,6 +1,5 @@ from tests.utils_for_testbook import ( validate_quantum_program_size, - validate_quantum_model, wrap_testbook, ) from testbook.client import TestbookNotebookClient @@ -8,21 +7,20 @@ @wrap_testbook( - "molecule_eigensolver_using_openfermion", - timeout_seconds=600, + "classiq_chemistry_application", + timeout_seconds=80, ) def test_notebook(tb: TestbookNotebookClient) -> None: """ A notebook for finding the ground state of a molecule using VQE. The test verifies that the classical optimizer converges to the expected ground state. """ - # test models - validate_quantum_model(tb.ref("qmod")) + # test quantum programs validate_quantum_program_size( tb.ref_pydantic("qprog"), - expected_width=8, # actual width: 8 - expected_depth=650, # actual depth: 484 + expected_width=6, # actual width: 8 + expected_depth=300, # actual depth: 166 ) # test notebook content diff --git a/tests/notebooks/test_molecule_eigensolver.py b/tests/notebooks/test_molecule_eigensolver.py index ae8f5e120..5a5a2191c 100644 --- a/tests/notebooks/test_molecule_eigensolver.py +++ b/tests/notebooks/test_molecule_eigensolver.py @@ -12,7 +12,7 @@ def test_notebook(tb: TestbookNotebookClient) -> None: # test models validate_quantum_model(tb.ref("qmod_hwea")) - validate_quantum_model(tb.ref("serialized_chemistry_model")) + validate_quantum_model(tb.ref("qmod_ucc")) # test quantum programs validate_quantum_program_size( tb.ref_pydantic("qprog_hwea"), @@ -26,13 +26,8 @@ def test_notebook(tb: TestbookNotebookClient) -> None: ) # test notebook content - # operator = tb.ref("operator.to_matrix()") - # w, v = np.linalg.eig(operator) - # exact_result = np.real(min(w)) - exact_result = tb.ref("np.real(min( np.linalg.eig(operator.to_matrix())[0] ))") - - chemistry_result_dict = tb.ref("chemistry_result_dict") - vqe_result = chemistry_result_dict["energy"] + vqe_result = tb.ref("optimizer_res") + exact_result = tb.ref("expected_energy") assert np.isclose( vqe_result, exact_result, atol=0.02 diff --git a/tests/notebooks/test_qpe_for_molecules.py b/tests/notebooks/test_qpe_for_molecules.py index 251833b73..407d94b7b 100644 --- a/tests/notebooks/test_qpe_for_molecules.py +++ b/tests/notebooks/test_qpe_for_molecules.py @@ -22,9 +22,7 @@ def test_notebook(tb: TestbookNotebookClient) -> None: solution_first_peak = tb.ref("measured_energy") resolution = tb.ref("2**(-QPE_SIZE)* normalization") - exact_result = tb.ref( - "np.real(min( np.linalg.eig( hamiltonian_to_matrix(mol_hamiltonian))[0] ))" - ) + exact_result = tb.ref("classical_sol") for sol in [solution_max_prob, solution_first_peak]: assert sol - resolution <= exact_result <= sol + resolution diff --git a/tests/notebooks/test_second_quantized_hamiltonian.py b/tests/notebooks/test_second_quantized_hamiltonian.py index ea3ff75f4..2d4a1e79a 100644 --- a/tests/notebooks/test_second_quantized_hamiltonian.py +++ b/tests/notebooks/test_second_quantized_hamiltonian.py @@ -1,6 +1,5 @@ from tests.utils_for_testbook import ( validate_quantum_program_size, - validate_quantum_model, wrap_testbook, ) from testbook.client import TestbookNotebookClient @@ -8,8 +7,6 @@ @wrap_testbook("second_quantized_hamiltonian", timeout_seconds=44) def test_notebook(tb: TestbookNotebookClient) -> None: - # test models - validate_quantum_model(tb.ref("qmod")) # test quantum programs validate_quantum_program_size( tb.ref_pydantic("qprog"), diff --git a/tests/resources/timeouts.yaml b/tests/resources/timeouts.yaml index add0f506b..4f1f21cd6 100644 --- a/tests/resources/timeouts.yaml +++ b/tests/resources/timeouts.yaml @@ -54,6 +54,7 @@ bpde.ipynb: 600 bpde.qmod: 10 classical_variables_and_operations.ipynb: 20 classical_variables_and_operations.qmod: 10 +classiq_chemistry_application.ipynb: 80 classiq_discrete_quantum_walk.ipynb: 300 classiq_iQuHack_2025_final.ipynb: 200 classiq_iQuHack_2025_final_sol.ipynb: 200 @@ -190,8 +191,8 @@ modulo_example.qmod: 10 molecular_energy_curve.ipynb: 1200 molecular_energy_curve.qmod: 90 molecule_eigensolver.ipynb: 84 -molecule_eigensolver.qmod: 60 -molecule_eigensolver_using_openfermion.ipynb: 600 +molecule_eigensolver_hwea.qmod: 40 +molecule_eigensolver_ucc.qmod: 40 multiplication.ipynb: 20 multiplication_2vars_example.qmod: 10 multiplication_float_example.qmod: 10