{ "cells": [ { "cell_type": "markdown", "id": "2fceac37", "metadata": {}, "source": [ "# Efficiently Simulating the VQE Algorithm with the Quantum Chemistry Toolbox\n", "\n", "[![Download Notebook](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/master/resource/_static/logo_notebook_en.svg)](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/master/mindquantum/en/advanced/mindspore_mqchem_tutorial.ipynb) \n", "[![Download Code](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/master/resource/_static/logo_download_code_en.svg)](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/master/mindquantum/en/advanced/mindspore_mqchem_tutorial.py) \n", "[![View Source On Gitee](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/master/resource/_static/logo_source_en.svg)](https://gitee.com/mindspore/docs/blob/master/docs/mindquantum/docs/source_en/advanced/mqchem_tutorial.ipynb)\n", "\n", "## 1. Introduction\n", "\n", "`mqchem` is an integrated toolbox designed specifically for solving quantum chemistry problems. Its core advantage lies in its simulation method based on **Configuration Interaction (CI)**. Unlike general-purpose simulators that operate in the full $2^{N}$-dimensional Hilbert space, `mqchem`'s simulator evolves within a subspace defined by a fixed number of electrons (`n_electrons`). This approach significantly reduces runtime, enabling us to simulate chemical systems of 20 qubits or more in a very short amount of time.\n", "\n", "The `mqchem` module primarily consists of three core components that work in synergy:\n", "\n", "- **`CIHamiltonian`**: For efficiently representing the Hamiltonian of a chemical problem.\n", "- **`UCCExcitationGate`**: The fundamental building block for variational ansatze like UCCSD.\n", "- **`MQChemSimulator`**: A high-performance simulator that performs quantum circuit evolution and measurements within the CI space.\n", "\n", "In this tutorial, you will learn to follow a natural workflow using the components of the `mqchem` module to solve a chemistry problem:\n", "\n", "1. Understand the core components of `mqchem` and their respective responsibilities.\n", "2. Learn how to combine these components to apply a quantum circuit and calculate expectation values.\n", "3. Utilize the high-level function `prepare_uccsd_vqe` to quickly set up a complete VQE workflow.\n", "4. Work through a hands-on example to calculate the ground state energy of a linear H₆ molecule.\n", "\n", "**Prerequisites**:\n", "Before you begin, please ensure you have MindQuantum installed, along with `openfermion` and `openfermionpyscf` for chemistry calculations.\n", "\n", "```bash\n", "pip install mindquantum openfermion openfermionpyscf\n", "```" ] }, { "cell_type": "markdown", "id": "7e7950ef", "metadata": {}, "source": [ "---\n", "\n", "## 2. The Core Components of `mqchem`\n", "\n", "When solving a quantum chemistry problem, we typically need to define the problem itself (the Hamiltonian), construct a solution strategy (the ansatz circuit), and execute it in a simulation environment. The three core components of `mqchem` correspond precisely to these steps.\n", "\n", "### 2.1 `CIHamiltonian`: Defining the Problem\n", "\n", "`CIHamiltonian` is a wrapper class for `FermionOperator` that converts a fermionic Hamiltonian into a format suitable for efficient computation within the CI space. It serves as the objective function for our VQE calculations." ] }, { "cell_type": "code", "execution_count": 1, "id": "a97af432", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CI Hamiltonian:\n", "1 [0^ 0] +\n", "1 [1^ 1]\n" ] } ], "source": [ "from mindquantum.core.operators import FermionOperator\n", "from mindquantum.simulator import mqchem\n", "\n", "# Any FermionOperator can be wrapped.\n", "# For example, let's define a simple number operator H = n_0 + n_1\n", "ham_op = FermionOperator('0^ 0') + FermionOperator('1^ 1')\n", "\n", "# Wrap it as a CIHamiltonian\n", "ci_ham = mqchem.CIHamiltonian(ham_op)\n", "\n", "print(\"CI Hamiltonian:\")\n", "print(ci_ham)" ] }, { "cell_type": "markdown", "id": "01c41ce7", "metadata": {}, "source": [ "### 2.2 `UCCExcitationGate`: Constructing the Solution\n", "\n", "The `UCCExcitationGate` is the fundamental building block for constructing a UCC (Unitary Coupled-Cluster) ansatz. It represents the unitary operator $U(\\theta) = e^{\\theta(T - T^\\dagger)}$, where $T$ is a fermionic excitation operator (e.g., $a_p^\\dagger a_q$) and $\\theta$ is a trainable parameter.\n", "\n", "The simulators in the `mqchem` module are specially optimized to apply this type of gate with high efficiency." ] }, { "cell_type": "code", "execution_count": 2, "id": "54218f4c", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Created UCC Gate:\n", "exp{(theta)([2^ 0] + [2 0^])}\n" ] } ], "source": [ "# Create an excitation operator T = a_2^\\dagger a_0 that excites from orbital 0 to 2.\n", "# 'theta' is the name of a trainable parameter.\n", "t_op = FermionOperator('2^ 0', 'theta')\n", "\n", "# Create a UCC excitation gate from this operator\n", "ucc_gate = mqchem.UCCExcitationGate(t_op)\n", "\n", "print(\"Created UCC Gate:\")\n", "print(ucc_gate)" ] }, { "cell_type": "markdown", "id": "5d3433a4", "metadata": {}, "source": [ "### 2.3 `MQChemSimulator`: Providing the Execution Environment\n", "\n", "The `MQChemSimulator` is the engine that executes the simulation. It maintains a quantum state on the CI basis and provides methods to apply `UCCExcitationGate`s and calculate the expectation value of a `CIHamiltonian`.\n", "\n", "When initializing, you need to specify the system's `n_qubits` (total number of spin-orbitals) and `n_electrons` (total number of electrons). By default, the simulator starts from the **Hartree-Fock (HF)** state, which is the most common reference state in quantum chemistry calculations." ] }, { "cell_type": "code", "execution_count": 3, "id": "815256e3", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Simulator n_qubits: 4\n", "Simulator n_electrons: 2\n", "\n", "Initial Hartree-Fock state:\n", "1¦0011⟩\n" ] } ], "source": [ "from mindquantum.core.circuit import Circuit\n", "\n", "# Initialize a simulator for a 4-qubit, 2-electron system\n", "sim = mqchem.MQChemSimulator(n_qubits=4, n_electrons=2, seed=42)\n", "\n", "print(f\"Simulator n_qubits: {sim.n_qubits}\")\n", "print(f\"Simulator n_electrons: {sim.n_electrons}\")\n", "\n", "# The default HF state is |0011> (bits are numbered 0, 1, 2, 3 from right to left)\n", "print(\"\\nInitial Hartree-Fock state:\")\n", "print(sim.get_qs(ket=True))" ] }, { "cell_type": "markdown", "id": "88e9cf97", "metadata": {}, "source": [ "---\n", "\n", "## 3. Putting It All Together: Simulation and Calculation\n", "\n", "Now that we understand the three main components, let's see how to combine them to execute a complete simulation workflow.\n", "\n", "### 3.1 Applying Gates and Circuits\n", "\n", "We can use the `apply_gate` or `apply_circuit` methods to act with a `UCCExcitationGate` on the quantum state maintained by the `MQChemSimulator`." ] }, { "cell_type": "code", "execution_count": 4, "id": "12a7cd04", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "State after applying a single gate:\n", "0.99500417¦0011⟩\n", "-0.09983342¦0110⟩\n", "\n", "State after applying the circuit:\n", "0.97517033¦0011⟩\n", "-0.0978434¦0110⟩\n", "0.19767681¦1001⟩\n", "0.01983384¦1100⟩\n" ] } ], "source": [ "# Reset the simulator to the HF state\n", "sim.reset()\n", "\n", "# Apply the previously created ucc_gate and assign the value 0.1 to the parameter 'theta'\n", "sim.apply_gate(ucc_gate, pr={'theta': 0.1})\n", "\n", "print(\"State after applying a single gate:\")\n", "print(sim.get_qs(ket=True))\n", "\n", "# You can also apply a circuit containing multiple gates\n", "sim.reset()\n", "t_op2 = FermionOperator('3^ 1', 0.2) # Use a constant as the parameter\n", "ucc_gate2 = mqchem.UCCExcitationGate(t_op2)\n", "circuit = Circuit([ucc_gate, ucc_gate2])\n", "\n", "# Apply the circuit and assign a value to the parameter 'theta'\n", "sim.apply_circuit(circuit, pr={'theta': 0.1})\n", "\n", "print(\"\\nState after applying the circuit:\")\n", "print(sim.get_qs(ket=True))" ] }, { "cell_type": "markdown", "id": "6adc7f65", "metadata": {}, "source": [ "### 3.2 Calculating Expectation Values\n", "\n", "The `get_expectation` method is used to calculate the expectation value $\\langle\\psi|H|\\psi\\rangle$ of a `CIHamiltonian` with respect to the current quantum state.\n", "\n", "For example, let's verify the expectation value of the Hamiltonian $H = n_0 + n_1$ in the HF state $|0011\\rangle$. Since orbitals 0 and 1 are both occupied, we expect the result to be $1+1=2$." ] }, { "cell_type": "code", "execution_count": 5, "id": "c018325f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Expectation value of is: 2.0\n" ] } ], "source": [ "sim.reset()\n", "\n", "# Use the previously created ci_ham\n", "expectation = sim.get_expectation(ci_ham)\n", "print(f\"Expectation value of is: {expectation}\")" ] }, { "cell_type": "markdown", "id": "f4827f34", "metadata": {}, "source": [ "---\n", "\n", "## 4. VQE in Action: Calculating the Ground State Energy of an H₆ Molecule\n", "\n", "Now, we will apply what we've learned to calculate the ground state energy of a linear H₆ molecule using the VQE algorithm. This is a classic example that showcases the power of the `mqchem` module.\n", "\n", "### 4.1 Preparation: Defining the Molecule\n", "\n", "We use `openfermion` and `openfermionpyscf` to obtain the data for the H₆ molecule. `run_pyscf` will perform classical quantum chemistry calculations (like HF and CCSD), and these results will serve as input for our quantum algorithm.\n", "\n", "**Key Point**: We must set `run_ccsd=True` because the `prepare_uccsd_vqe` function requires the results of the CCSD calculation to provide high-quality initial parameters for the VQE." ] }, { "cell_type": "code", "execution_count": 6, "id": "9e1bfe88", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Molecule: H₆ linear chain\n", "Number of qubits (spin-orbitals): 12\n", "Number of electrons: 6\n", "Exact ground state energy (FCI): -3.23606628 Hartrees\n" ] } ], "source": [ "from openfermion import MolecularData\n", "from openfermionpyscf import run_pyscf\n", "\n", "# Define an H₆ molecule with a bond length of 1 Angstrom\n", "geometry = [(\"H\", (i, 0, 0)) for i in range(6)]\n", "basis = \"sto-3g\"\n", "multiplicity = 1 # Spin multiplicity (2S+1), singlet state S=0\n", "charge = 0\n", "\n", "# Create the molecular data object and run PySCF\n", "# Note: run_ccsd=True is crucial for obtaining initial amplitudes\n", "molecule = MolecularData(geometry, basis, multiplicity, charge)\n", "mol = run_pyscf(molecule, run_ccsd=True, run_fci=True)\n", "\n", "print(f\"Molecule: H₆ linear chain\")\n", "print(f\"Number of qubits (spin-orbitals): {mol.n_qubits}\")\n", "print(f\"Number of electrons: {mol.n_electrons}\")\n", "print(f\"Exact ground state energy (FCI): {mol.fci_energy:.8f} Hartrees\")" ] }, { "cell_type": "markdown", "id": "71a77e2e", "metadata": {}, "source": [ "### 4.2 Streamlined VQE Preparation with `prepare_uccsd_vqe`\n", "\n", "`prepare_uccsd_vqe` is a major highlight of the `mqchem` module. This high-level factory function automates the most tedious steps of VQE preparation, encapsulating the component creation process we learned earlier:\n", "\n", "1. Generates the fermionic Hamiltonian from the molecular data and wraps it as a `CIHamiltonian`.\n", "2. Constructs a parameterized `Circuit` based on the UCCSD (Unitary Coupled-Cluster Singles and Doubles) theory, containing a series of `UCCExcitationGate`s.\n", "3. Extracts the coupled-cluster amplitudes from the classical CCSD calculation to use as **initial parameters** for the VQE optimization. This is often an excellent starting point." ] }, { "cell_type": "code", "execution_count": 7, "id": "2f47bc36", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CI Hamiltonian (first few terms):\n", " 4.6038 [] +\n", "-2.2818 [0^ 0] +\n", "-0.1459 [4 0^] +\n", " 0.0642 [8 0^] +\n", "-2.2818 [1^ 1] +\n", "-0.1459 [5 1^] +\n", " 0.0642 [9 1^] +\n", "-2.0409 [2^ 2] +\n", "-0.2111 [6 2^] +\n", " 0.0417 [10 2^] +\n", "-2.0409 [3^ 3] +\n", "-0.2111 [7 3^] +...\n", "\n", "Generated Ansatz circuit contains 59 gates.\n", "Circuit parameter names: ['d1_0', 's_1', 'd1_1', 'd1_2', 's_3', 'd1_3', 'd1_4', 's_5', 'd1_5', 'd1_6', 's_7', 'd1_7', 'd1_8', 'd2_1', 'd2_3', 'd2_9', 'd2_5', 'd2_18', 'd2_7', 'd2_11', 'd2_16', 'd2_13', 'd2_20', 'd2_22', 'd2_24', 'd2_27', 'd2_29', 'd2_31', 'd2_34']\n", "\n", "Initial amplitudes extracted from CCSD (total 29):\n", "[-0.02172895 -0.00966027 -0.03288994 -0.10380602 0.0028648 -0.0143801\n", " -0.03201595 -0.00681583 -0.02420889 -0.01695636 -0.00239016 -0.01001419\n", " -0.01221332 0.00432926 0.01629623 0.00904958 -0.00799714 0.01818314\n", " 0.03079327 0.04406509 0.02507472 0.01007596 -0.00356389 -0.00956368\n", " -0.01592823 -0.01108764 -0.01197809 -0.00586536 0.00582737]\n" ] } ], "source": [ "# Generate the Hamiltonian, UCCSD ansatz circuit, and initial parameters in one step\n", "# threshold=1e-6 is used to filter out excitation terms with small CCSD amplitudes, simplifying the ansatz\n", "hamiltonian, ansatz_circuit, initial_amplitudes = mqchem.prepare_uccsd_vqe(mol, threshold=1e-6)\n", "\n", "print(\"CI Hamiltonian (first few terms):\")\n", "print(str(hamiltonian.fermion_hamiltonian)[:200] + \"...\")\n", "\n", "print(f\"\\nGenerated Ansatz circuit contains {len(ansatz_circuit)} gates.\")\n", "print(\"Circuit parameter names:\", ansatz_circuit.params_name)\n", "\n", "print(f\"\\nInitial amplitudes extracted from CCSD (total {len(initial_amplitudes)}):\")\n", "print(initial_amplitudes)" ] }, { "cell_type": "markdown", "id": "0c6ff7df", "metadata": {}, "source": [ "### 4.3 Getting the Expectation and Gradient Function\n", "\n", "The core of VQE is to minimize the energy expectation value. Efficient optimization algorithms (like L-BFGS-B) require the gradient of the energy with respect to the parameters. The `get_expectation_with_grad` method is designed precisely for this. It returns a function that takes parameter values and returns both the energy expectation value and the gradient simultaneously." ] }, { "cell_type": "code", "execution_count": 8, "id": "2b392132", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Energy calculated with initial parameters: -3.21777544\n", "Corresponding gradient (first 5 elements): [-0.03673877 0.02322724 -0.06124962 -0.10907011 -0.00220752]\n" ] } ], "source": [ "# Initialize a new simulator for the VQE calculation\n", "vqe_sim = mqchem.MQChemSimulator(mol.n_qubits, mol.n_electrons)\n", "\n", "# Get the function that can calculate both expectation and gradient\n", "# This function is compatible with the interface of scipy.optimize.minimize\n", "grad_ops = vqe_sim.get_expectation_with_grad(hamiltonian, ansatz_circuit)\n", "\n", "# We can test this function\n", "energy, gradient = grad_ops(initial_amplitudes)\n", "print(f\"Energy calculated with initial parameters: {energy:.8f}\")\n", "print(f\"Corresponding gradient (first 5 elements): {gradient[:5]}\")" ] }, { "cell_type": "markdown", "id": "cb615724", "metadata": {}, "source": [ "### 4.4 Running the Optimizer\n", "\n", "Finally, we use a classical optimizer, `scipy.optimize.minimize`, to find the optimal parameters and thus obtain the variational approximation of the ground state energy." ] }, { "cell_type": "code", "execution_count": 9, "id": "07749c60", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "--- VQE Optimization Complete ---\n", "VQE calculated ground state energy: -3.23544945 Hartrees\n", "Exact FCI ground state energy: -3.23606628 Hartrees\n", "Error: 6.17e-04 Hartrees\n", "Runtime: 0.02 seconds\n" ] } ], "source": [ "from scipy.optimize import minimize\n", "from time import time\n", "\n", "t0 = time()\n", "\n", "# Perform optimization using the L-BFGS-B algorithm\n", "# jac=True indicates that our grad_ops function returns both the value and the Jacobian (gradient)\n", "result = minimize(grad_ops, initial_amplitudes, method=\"L-BFGS-B\", jac=True)\n", "\n", "vqe_energy = result.fun\n", "\n", "print(\"\\n--- VQE Optimization Complete ---\")\n", "print(f\"VQE calculated ground state energy: {vqe_energy:.8f} Hartrees\")\n", "print(f\"Exact FCI ground state energy: {mol.fci_energy:.8f} Hartrees\")\n", "print(f\"Error: {abs(vqe_energy - mol.fci_energy):.2e} Hartrees\")\n", "print(f\"Runtime: {time() - t0:.2f} seconds\")" ] }, { "cell_type": "markdown", "id": "79062bf6", "metadata": {}, "source": [ "As you can see, the VQE result is very close to the exact FCI energy, and the entire optimization process completed in under 0.02 seconds! This demonstrates the correctness and high performance of the `mqchem` components working together.\n", "\n", "---\n", "\n", "## 5. Summary\n", "\n", "In this tutorial, we systematically introduced the `mqchem` module. We started with its three core components—`CIHamiltonian`, `UCCExcitationGate`, and `MQChemSimulator`—to understand their respective roles in the quantum chemistry simulation workflow.\n", "\n", "We not only learned how to use these components individually but, more importantly, saw how they seamlessly integrate to solve practical problems. Finally, through a VQE example of calculating the ground state energy of an H₆ molecule, we demonstrated how to use convenient tools like `prepare_uccsd_vqe` to efficiently build and run a complete quantum chemistry simulation pipeline.\n", "\n", "The `mqchem` module provides powerful support for high-performance, high-precision quantum chemistry research on the MindQuantum platform. We hope this tutorial helps you get started quickly and encourages you to explore more interesting chemistry problems" ] } ], "metadata": { "kernelspec": { "display_name": "py39", "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.9.21" } }, "nbformat": 4, "nbformat_minor": 5 }