diff --git a/binder-index.md b/binder-index.md index 06b87df6042c..037a1f8bf2e9 100644 --- a/binder-index.md +++ b/binder-index.md @@ -251,6 +251,14 @@ These are noted in the README.md files for each sample, along with complete inst Q# standalone + + + Variational Quantum Eigensolver + + + Qiskit + Python + + Characterization: Bayesian Phase Estimation diff --git a/samples/azure-quantum/variational-quantum-eigensolver/README.md b/samples/azure-quantum/variational-quantum-eigensolver/README.md new file mode 100644 index 000000000000..0eca1baf2d82 --- /dev/null +++ b/samples/azure-quantum/variational-quantum-eigensolver/README.md @@ -0,0 +1,20 @@ +--- +page_type: sample +author: guenp +description: Variational Quantum Eigensolver +ms.author: guenp@microsoft.com +ms.date: 06/02/2022 +languages: +- python +products: +- azure-quantum +--- + +# Variational Quantum Eigensolver + +This is an Azure Quantum sample notebook that illustrates how to implement and run a Variational Quantum Eigensolver (VQE) program. + +## Manifest + +- [VQE-qiskit-hydrogen-ionq-sim.ipynb](./VQE-qiskit-hydrogen-ionq-sim.ipynb): Azure Quantum notebook for running the sample on the IonQ simulator +- [VQE-qiskit-hydrogen-quantinuum-emulator.ipynb](./VQE-qiskit-hydrogen-quantinuum-emulator.ipynb): Azure Quantum notebook for running the sample on the Quantinuum emulator diff --git a/samples/azure-quantum/variational-quantum-eigensolver/VQE-qiskit-hydrogen-ionq-sim.ipynb b/samples/azure-quantum/variational-quantum-eigensolver/VQE-qiskit-hydrogen-ionq-sim.ipynb new file mode 100644 index 000000000000..a1e9e474b8f1 --- /dev/null +++ b/samples/azure-quantum/variational-quantum-eigensolver/VQE-qiskit-hydrogen-ionq-sim.ipynb @@ -0,0 +1,674 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "47574490", + "metadata": {}, + "source": [ + "# Simulate the ground state of a Hydrogen molecule using Variational Quantum Eigensolver (VQE) on the IonQ simulator\n", + "\n", + "![Hydrogen molecule](https://user-images.githubusercontent.com/4041805/166981145-c33b8d1a-24d1-4776-91ee-f514b0a5ab04.jpg)\n", + "\n", + "In this notebook, you'll learn how to run VQE for a $H_{2}$ molecule on the IonQ simulator using Qiskit on an Azure Quantum backend.\n", + "\n", + "VQE is a variational algorithm for quantum chemistry that uses an optimization loop to minimize a cost function. The cost function is an energy evaluation $E = \\left\\langle\\psi|H|\\psi\\right\\rangle$ where $|\\psi (\\theta)\\rangle$ is a parametric trial state that estimates the ground state of the molecule. For each evaluation, we modify the trial state until the energy reaches a minimum.\n", + "\n", + "![VQE diagram](https://user-images.githubusercontent.com/4041805/166981008-023aba4c-26f8-498e-93ee-a1d9a39ddbcd.png)\n", + "\n", + "For more information about running VQE using Qiskit, see: [Qiskit Textbook - VQE Molecules](https://qiskit.org/textbook/ch-applications/vqe-molecules.html#implementationnoisy).\n", + "\n", + "To read more about the optimization method used in this example, see [Wikipedia - SPSA](https://en.wikipedia.org/wiki/Simultaneous_perturbation_stochastic_approximation)." + ] + }, + { + "cell_type": "markdown", + "id": "f361a714", + "metadata": {}, + "source": [ + "Before geting started, you need to install and import the required packages." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "71d2cb0b", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "from qiskit import IBMQ, BasicAer, Aer\n", + "from qiskit.aqua import QuantumInstance\n", + "from qiskit.aqua.components.optimizers import COBYLA, SPSA, SLSQP\n", + "from qiskit.aqua.operators import Z2Symmetries\n", + "from qiskit.aqua.algorithms import VQE, NumPyEigensolver\n", + "from qiskit.chemistry.components.variational_forms import UCCSD\n", + "from qiskit.chemistry.components.initial_states import HartreeFock\n", + "from qiskit.circuit.library import EfficientSU2\n", + "from qiskit.chemistry.drivers import PySCFDriver, UnitsType\n", + "from qiskit.chemistry import FermionicOperator\n", + "from qiskit.ignis.mitigation.measurement import CompleteMeasFitter\n", + "from qiskit.providers.aer.noise import NoiseModel" + ] + }, + { + "cell_type": "markdown", + "id": "7dadd1bf", + "metadata": {}, + "source": [ + "First, prepare the qubit operators to get the one-body and two-body integrals that encode the hydrogen molecule and map them onto qubits using quantum gates.\n", + "\n", + "You'll use [PySCF](https://github.com/pyscf/pyscf) to generate the molecule, and [Qiskit Chemistry](https://quantum-computing.ibm.com/lab/docs/iql/chemistry) to encode it into Fermionic operators." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "9b4ce39a", + "metadata": {}, + "outputs": [], + "source": [ + "# Create a PySCF driver an generate the molecule\n", + "driver = PySCFDriver(atom='H .0 .0 -0.3625; H .0 .0 0.3625', unit=UnitsType.ANGSTROM, charge=0, spin=0, basis='sto3g')\n", + "molecule = driver.run()\n", + "# Get the total number of particles in the molecule\n", + "num_particles = molecule.num_alpha + molecule.num_beta\n", + "# Convert one-body and two-body integrals into fermionic operators\n", + "qubit_op = FermionicOperator(h1=molecule.one_body_integrals, h2=molecule.two_body_integrals).mapping(map_type='parity')\n", + "qubit_op = Z2Symmetries.two_qubit_reduction(qubit_op, num_particles)" + ] + }, + { + "cell_type": "markdown", + "id": "50174a98", + "metadata": {}, + "source": [ + "## 1. Simulate locally\n", + "\n", + "Here, you will simulate the program locally using the Aer simulator. You can create a `QuantumInstance` with a noise model using a mock device `FakeVigo` with noise characteristics." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "737c1000", + "metadata": {}, + "outputs": [], + "source": [ + "from qiskit.test.mock import FakeVigo\n", + "from qiskit.providers.aer import AerSimulator\n", + "from qiskit.providers.aer import QasmSimulator\n", + "from qiskit.providers.aer.noise import NoiseModel\n", + "\n", + "backend = AerSimulator()\n", + "device_backend = FakeVigo()\n", + "device = QasmSimulator.from_backend(device_backend)" + ] + }, + { + "cell_type": "markdown", + "id": "f9939a47", + "metadata": {}, + "source": [ + "Then, run the simulation using the VQE class." + ] + }, + { + "cell_type": "markdown", + "id": "c4ffa5a4", + "metadata": {}, + "source": [ + "### Simulate locally with noise and error mitigation\n", + "\n", + "You can read more about error mitigation in the Qiskit textbook chapter on [Measurement Error Mitigation](https://qiskit.org/textbook/ch-quantum-hardware/measurement-error-mitigation.html)." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "b4788b3c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Exact Result: [-1.13722138]\n", + "VQE Result on noisy simulator: -1.1182467061854797\n" + ] + } + ], + "source": [ + "# Create the noise characteristics and other parameters that describe the device\n", + "coupling_map = device.configuration().coupling_map\n", + "noise_model = NoiseModel.from_backend(device)\n", + "basis_gates = noise_model.basis_gates\n", + "\n", + "# Create the quantum instance to conncet to the backend\n", + "quantum_instance = QuantumInstance(backend=backend, \n", + " shots=8192, \n", + " noise_model=noise_model, \n", + " coupling_map=coupling_map,\n", + " measurement_error_mitigation_cls=CompleteMeasFitter,\n", + " cals_matrix_refresh_period=30)\n", + "\n", + "# Calculate the exact solution using numpy\n", + "exact_solution = NumPyEigensolver(qubit_op).run()\n", + "print(\"Exact Result:\", np.real(exact_solution.eigenvalues) + molecule.nuclear_repulsion_energy)\n", + "\n", + "# Create an optimizer (using SPSA)\n", + "optimizer = SPSA(maxiter=100)\n", + "\n", + "# Create the variational form\n", + "var_form = EfficientSU2(qubit_op.num_qubits, entanglement=\"linear\")\n", + "\n", + "# Create a VQE object that runs VQE using the above created qubit operations, variational form and optimizer\n", + "vqe = VQE(qubit_op, var_form, optimizer=optimizer)\n", + "\n", + "# Run the full VQE program\n", + "ret = vqe.run(quantum_instance)\n", + "\n", + "# Get and print the result\n", + "vqe_result = np.real(ret['eigenvalue'] + molecule.nuclear_repulsion_energy)\n", + "print(\"VQE Result on noisy simulator:\", vqe_result)" + ] + }, + { + "cell_type": "markdown", + "id": "84237dc8", + "metadata": {}, + "source": [ + "The parameters found by the optimization loop:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "77f373f5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 0.0620135 , -3.49279822, 0.82680219, -2.23349298, 0.2206398 ,\n", + " -0.52806491, -5.02282377, 0.25837181, -1.44203312, 1.48644364,\n", + " 2.2563787 , -2.97602046, 3.57251496, 1.08809463, -3.06435385,\n", + " 6.30261345])" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p0 = ret.optimal_point\n", + "p0" + ] + }, + { + "cell_type": "markdown", + "id": "c4338b61", + "metadata": {}, + "source": [ + "The energy was evaluated a total of `ret.cost_function_evals` times until the minimum was found." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "9930b2c9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "241" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ret.cost_function_evals" + ] + }, + { + "cell_type": "markdown", + "id": "87005ce0", + "metadata": {}, + "source": [ + "### Circuit visualization\n", + "\n", + "Each energy evaluation consists of two circuits. You can visualize these circuits with Qiskit using the `vqe` instance." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "69e6719e", + "metadata": {}, + "outputs": [], + "source": [ + "# The VQE class generates extra unused wires.\n", + "# This function is to remove idle wires to make the visualization more readable.\n", + "# See: https://quantumcomputing.stackexchange.com/questions/25672/remove-inactive-qubits-from-qiskit-circuit\n", + "from qiskit.converters import circuit_to_dag, dag_to_circuit\n", + "from collections import OrderedDict\n", + "\n", + "def remove_idle_qwires(circ):\n", + " dag = circuit_to_dag(circ)\n", + "\n", + " idle_wires = list(dag.idle_wires())\n", + " for w in idle_wires:\n", + " dag._remove_idle_wire(w)\n", + " dag.qubits.remove(w)\n", + "\n", + " dag.qregs = OrderedDict()\n", + "\n", + " return dag_to_circuit(dag)\n", + "\n", + "circs = vqe._circuit_sampler._transpiled_circ_cache\n", + "circs = [remove_idle_qwires(circ) for circ in circs]\n", + "circ = circs[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "e0ab0e41", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
      ┌──────────┐┌──────────┐     ┌──────────┐┌──────────┐     ┌──────────┐»\n",
+       "   0: ┤ Ry(θ[0]) ├┤ Rz(θ[2]) ├──■──┤ Ry(θ[4]) ├┤ Rz(θ[6]) ├──■──┤ Ry(θ[8]) ├»\n",
+       "      ├──────────┤├──────────┤┌─┴─┐├──────────┤├──────────┤┌─┴─┐├──────────┤»\n",
+       "   1: ┤ Ry(θ[1]) ├┤ Rz(θ[3]) ├┤ X ├┤ Ry(θ[5]) ├┤ Rz(θ[7]) ├┤ X ├┤ Ry(θ[9]) ├»\n",
+       "      └──────────┘└──────────┘└───┘└──────────┘└──────────┘└───┘└──────────┘»\n",
+       "c0: 2/══════════════════════════════════════════════════════════════════════»\n",
+       "                                                                            »\n",
+       "«      ┌───────────┐     ┌───────────┐┌───────────┐┌───┐┌─┐   \n",
+       "«   0: ┤ Rz(θ[10]) ├──■──┤ Ry(θ[12]) ├┤ Rz(θ[14]) ├┤ H ├┤M├───\n",
+       "«      ├───────────┤┌─┴─┐├───────────┤├───────────┤├───┤└╥┘┌─┐\n",
+       "«   1: ┤ Rz(θ[11]) ├┤ X ├┤ Ry(θ[13]) ├┤ Rz(θ[15]) ├┤ H ├─╫─┤M├\n",
+       "«      └───────────┘└───┘└───────────┘└───────────┘└───┘ ║ └╥┘\n",
+       "«c0: 2/══════════════════════════════════════════════════╩══╩═\n",
+       "«                                                        0  1 
" + ], + "text/plain": [ + " ┌──────────┐┌──────────┐ ┌──────────┐┌──────────┐ ┌──────────┐»\n", + " 0: ┤ Ry(θ[0]) ├┤ Rz(θ[2]) ├──■──┤ Ry(θ[4]) ├┤ Rz(θ[6]) ├──■──┤ Ry(θ[8]) ├»\n", + " ├──────────┤├──────────┤┌─┴─┐├──────────┤├──────────┤┌─┴─┐├──────────┤»\n", + " 1: ┤ Ry(θ[1]) ├┤ Rz(θ[3]) ├┤ X ├┤ Ry(θ[5]) ├┤ Rz(θ[7]) ├┤ X ├┤ Ry(θ[9]) ├»\n", + " └──────────┘└──────────┘└───┘└──────────┘└──────────┘└───┘└──────────┘»\n", + "c0: 2/══════════════════════════════════════════════════════════════════════»\n", + " »\n", + "« ┌───────────┐ ┌───────────┐┌───────────┐┌───┐┌─┐ \n", + "« 0: ┤ Rz(θ[10]) ├──■──┤ Ry(θ[12]) ├┤ Rz(θ[14]) ├┤ H ├┤M├───\n", + "« ├───────────┤┌─┴─┐├───────────┤├───────────┤├───┤└╥┘┌─┐\n", + "« 1: ┤ Rz(θ[11]) ├┤ X ├┤ Ry(θ[13]) ├┤ Rz(θ[15]) ├┤ H ├─╫─┤M├\n", + "« └───────────┘└───┘└───────────┘└───────────┘└───┘ ║ └╥┘\n", + "«c0: 2/══════════════════════════════════════════════════╩══╩═\n", + "« 0 1 " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "circ.draw()" + ] + }, + { + "cell_type": "markdown", + "id": "5085e0c6", + "metadata": {}, + "source": [ + "This visualization shows the parametric trial state that is prepared and evaluated as part of VQE. The parameters, $\\theta[n]$, are assigned a value for each iteration." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "6dd36770", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
      ┌────────────────────────┐┌───────────────────────┐     »\n",
+       "   0: ┤ Ry(0.0620135025056964) ├┤ Rz(-1.44203311888193) ├──■──»\n",
+       "      ├───────────────────────┬┘└┬──────────────────────┤┌─┴─┐»\n",
+       "   1: ┤ Ry(0.258371806493365) ├──┤ Rz(1.48644364216686) ├┤ X ├»\n",
+       "      └───────────────────────┘  └──────────────────────┘└───┘»\n",
+       "c0: 2/════════════════════════════════════════════════════════»\n",
+       "                                                              »\n",
+       "«       ┌──────────────────────┐┌──────────────────────┐     »\n",
+       "«   0: ─┤ Ry(2.25637870168243) ├┤ Rz(3.57251495869326) ├──■──»\n",
+       "«      ┌┴──────────────────────┤├──────────────────────┤┌─┴─┐»\n",
+       "«   1: ┤ Ry(-2.97602046000987) ├┤ Rz(1.08809462606082) ├┤ X ├»\n",
+       "«      └───────────────────────┘└──────────────────────┘└───┘»\n",
+       "«c0: 2/══════════════════════════════════════════════════════»\n",
+       "«                                                            »\n",
+       "«      ┌───────────────────────┐┌───────────────────────┐     »\n",
+       "«   0: ┤ Ry(-3.06435384979108) ├┤ Rz(-3.49279822061742) ├──■──»\n",
+       "«      └┬──────────────────────┤├───────────────────────┤┌─┴─┐»\n",
+       "«   1: ─┤ Ry(6.30261345020689) ├┤ Rz(0.826802191635181) ├┤ X ├»\n",
+       "«       └──────────────────────┘└───────────────────────┘└───┘»\n",
+       "«c0: 2/═══════════════════════════════════════════════════════»\n",
+       "«                                                             »\n",
+       "«      ┌───────────────────────┐┌────────────────────────┐┌───┐┌─┐   \n",
+       "«   0: ┤ Ry(-2.23349298437292) ├┤ Rz(-0.528064906964863) ├┤ H ├┤M├───\n",
+       "«      ├───────────────────────┤└┬──────────────────────┬┘├───┤└╥┘┌─┐\n",
+       "«   1: ┤ Ry(0.220639796173816) ├─┤ Rz(-5.0228237656496) ├─┤ H ├─╫─┤M├\n",
+       "«      └───────────────────────┘ └──────────────────────┘ └───┘ ║ └╥┘\n",
+       "«c0: 2/═════════════════════════════════════════════════════════╩══╩═\n",
+       "«                                                               0  1 
" + ], + "text/plain": [ + " ┌────────────────────────┐┌───────────────────────┐ »\n", + " 0: ┤ Ry(0.0620135025056964) ├┤ Rz(-1.44203311888193) ├──■──»\n", + " ├───────────────────────┬┘└┬──────────────────────┤┌─┴─┐»\n", + " 1: ┤ Ry(0.258371806493365) ├──┤ Rz(1.48644364216686) ├┤ X ├»\n", + " └───────────────────────┘ └──────────────────────┘└───┘»\n", + "c0: 2/════════════════════════════════════════════════════════»\n", + " »\n", + "« ┌──────────────────────┐┌──────────────────────┐ »\n", + "« 0: ─┤ Ry(2.25637870168243) ├┤ Rz(3.57251495869326) ├──■──»\n", + "« ┌┴──────────────────────┤├──────────────────────┤┌─┴─┐»\n", + "« 1: ┤ Ry(-2.97602046000987) ├┤ Rz(1.08809462606082) ├┤ X ├»\n", + "« └───────────────────────┘└──────────────────────┘└───┘»\n", + "«c0: 2/══════════════════════════════════════════════════════»\n", + "« »\n", + "« ┌───────────────────────┐┌───────────────────────┐ »\n", + "« 0: ┤ Ry(-3.06435384979108) ├┤ Rz(-3.49279822061742) ├──■──»\n", + "« └┬──────────────────────┤├───────────────────────┤┌─┴─┐»\n", + "« 1: ─┤ Ry(6.30261345020689) ├┤ Rz(0.826802191635181) ├┤ X ├»\n", + "« └──────────────────────┘└───────────────────────┘└───┘»\n", + "«c0: 2/═══════════════════════════════════════════════════════»\n", + "« »\n", + "« ┌───────────────────────┐┌────────────────────────┐┌───┐┌─┐ \n", + "« 0: ┤ Ry(-2.23349298437292) ├┤ Rz(-0.528064906964863) ├┤ H ├┤M├───\n", + "« ├───────────────────────┤└┬──────────────────────┬┘├───┤└╥┘┌─┐\n", + "« 1: ┤ Ry(0.220639796173816) ├─┤ Rz(-5.0228237656496) ├─┤ H ├─╫─┤M├\n", + "« └───────────────────────┘ └──────────────────────┘ └───┘ ║ └╥┘\n", + "«c0: 2/═════════════════════════════════════════════════════════╩══╩═\n", + "« 0 1 " + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "circ.assign_parameters(ret.optimal_parameters).draw()" + ] + }, + { + "cell_type": "markdown", + "id": "4d49d174", + "metadata": {}, + "source": [ + "## 2. Run on IonQ simulator via an Azure Quantum workspace\n", + "\n", + "Now, you can connect to the Azure Quantum workspace and run VQE on the IonQ simulator backend." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "c042c41e", + "metadata": {}, + "outputs": [], + "source": [ + "# Connect to the Azure Quantum workspace via a Qiskit provider\n", + "from azure.quantum.qiskit import AzureQuantumProvider\n", + "provider = AzureQuantumProvider(\n", + " resource_id = \"\",\n", + " location = \"\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "c59bcf84", + "metadata": {}, + "outputs": [], + "source": [ + "# Create IonQ simulator and QPU backends\n", + "ionq_simulator_backend = provider.get_backend(\"ionq.simulator\")\n", + "ionq_qpu_backend = provider.get_backend(\"ionq.qpu\")" + ] + }, + { + "cell_type": "markdown", + "id": "69a3a14c", + "metadata": {}, + "source": [ + "### Estimate cost\n", + "\n", + "You can now estimate how much it will cost to run VQE. For more information about pricing, see the [Azure Quantum pricing](https://docs.microsoft.com/azure/quantum/pricing) documentation page." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "13e44adb", + "metadata": {}, + "outputs": [], + "source": [ + "cost = [ionq_qpu_backend.estimate_cost(circ.assign_parameters(ret.optimal_parameters), shots=1000) for circ in circs]" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "451f1310", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1.44 USD\n", + "1.38 USD\n" + ] + } + ], + "source": [ + "for _cost in cost:\n", + " print(_cost.estimated_total, _cost.currency_code)" + ] + }, + { + "cell_type": "markdown", + "id": "8924df25", + "metadata": {}, + "source": [ + "So, given approx. 300 energy evaluations, this would give a total cost" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "0102d812", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Single iteration: 2.82 USD, 300 iterations: 846.0 USD\n" + ] + } + ], + "source": [ + "num_iterations = 300\n", + "energy_eval_cost = sum(_cost.estimated_total for _cost in cost)\n", + "print(f\"Single iteration: {energy_eval_cost} {cost[0].currency_code}, {num_iterations} iterations: {energy_eval_cost * num_iterations} {cost[0].currency_code}\")" + ] + }, + { + "cell_type": "markdown", + "id": "c478eaa4", + "metadata": {}, + "source": [ + "To get a visual on the circuit width and depth, run:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "cb9c3998", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "width | depth\n", + "4 13\n", + "4 13\n" + ] + } + ], + "source": [ + "print(\"width | depth\")\n", + "for circuit in circs:\n", + " circuit = circ.assign_parameters(ret.optimal_parameters)\n", + " circuit = remove_idle_qwires(circuit)\n", + " print(circuit.width(), circuit.depth())" + ] + }, + { + "cell_type": "markdown", + "id": "bc8a8b3e", + "metadata": {}, + "source": [ + "### Run one iteration on IonQ simulator via the Azure Quantum workspace\n", + "\n", + "It can take a long time to run a full VQE program on hardware, because each iteration puts a circuit in the queue. For demonstration purposes, you can run only the last iteration using the parameters we found with the Aer simulator." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "72446518", + "metadata": {}, + "outputs": [], + "source": [ + "# This is a bug that will be addressed in this PR: https://github.com/microsoft/qdk-python/pull/301\n", + "ionq_simulator_backend.configuration().max_shots = None" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "2ba3e580", + "metadata": {}, + "outputs": [], + "source": [ + "# Create Quantum Instance\n", + "quantum_instance = QuantumInstance(backend=ionq_simulator_backend,\n", + " shots=8192)\n", + "# Unset qjob config to avoid errors when running job.result()\n", + "quantum_instance._qjob_config = {}" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "e764cfe4", + "metadata": {}, + "outputs": [], + "source": [ + "# Create optimizer with only one iteration\n", + "optimizer = SPSA(maxiter=1)\n", + "# Create the variational form of the ansatz\n", + "var_form = EfficientSU2(qubit_op.num_qubits, entanglement=\"linear\")\n", + "# Create a VQE object that runs the algorithm\n", + "vqe = VQE(qubit_op, var_form, optimizer=optimizer)\n", + "# Set the quantum instance to be able to run only the last iteration\n", + "vqe.quantum_instance = quantum_instance" + ] + }, + { + "cell_type": "markdown", + "id": "abb4e575-c468-4df4-a9af-426829237a16", + "metadata": { + "nteract": { + "transient": { + "deleting": false + } + } + }, + "source": [ + "The below cell will evaluate the energy at `p0` using the IonQ simulator.\n", + "\n", + "You have to add the molecular nuclear repulsion energy to the final result to get the ground state of the molecule." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "f55a0f10", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "......\n", + "\n", + "-1.1328210248074357\n" + ] + } + ], + "source": [ + "vqe._energy_evaluation(parameters=p0) + molecule.nuclear_repulsion_energy" + ] + }, + { + "cell_type": "markdown", + "id": "36ead1d5", + "metadata": {}, + "source": [ + "In this notebook, you've run a single iteration of VQE on an Azure Quantum backend to calculate the ground state of a $H_2$ molecule. Nice job! 👏🏽\n", + "\n", + "As a next step, you can modify the sample to run your own molecule, or run it on hardware." + ] + } + ], + "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.9.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/samples/azure-quantum/variational-quantum-eigensolver/VQE-qiskit-hydrogen-quantinuum-emulator.ipynb b/samples/azure-quantum/variational-quantum-eigensolver/VQE-qiskit-hydrogen-quantinuum-emulator.ipynb new file mode 100644 index 000000000000..8376cd2a9d39 --- /dev/null +++ b/samples/azure-quantum/variational-quantum-eigensolver/VQE-qiskit-hydrogen-quantinuum-emulator.ipynb @@ -0,0 +1,669 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "47574490", + "metadata": {}, + "source": [ + "# Simulate the ground state of a Hydrogen molecule using Variational Quantum Eigensolver (VQE) on the Quantinuum emulator\n", + "\n", + "![Hydrogen molecule](https://user-images.githubusercontent.com/4041805/166981145-c33b8d1a-24d1-4776-91ee-f514b0a5ab04.jpg)\n", + "\n", + "In this notebook, you'll learn how to run VQE for a $H_{2}$ molecule on the Quantinuum emulator using Qiskit on an Azure Quantum backend.\n", + "\n", + "VQE is a variational algorithm for quantum chemistry that uses an optimization loop to minimize a cost function. The cost function is an energy evaluation $E = <\\psi|H|\\psi>$ where $|\\psi (\\theta)>$ is a parametric trial state that estimates the ground state of the molecule. For each evaluation, we modify the trial state until the energy reaches a minimum.\n", + "\n", + "![VQE diagram](https://user-images.githubusercontent.com/4041805/166981008-023aba4c-26f8-498e-93ee-a1d9a39ddbcd.png)\n", + "\n", + "For more information about running VQE using Qiskit, see: [Qiskit Textbook - VQE Molecules](https://qiskit.org/textbook/ch-applications/vqe-molecules.html#implementationnoisy).\n", + "\n", + "To read more about the optimization method used in this example, see [Wikipedia - SPSA](https://en.wikipedia.org/wiki/Simultaneous_perturbation_stochastic_approximation)." + ] + }, + { + "cell_type": "markdown", + "id": "f361a714", + "metadata": {}, + "source": [ + "Before geting started, you need to install and import the required packages." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "71d2cb0b", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "from qiskit import IBMQ, BasicAer, Aer\n", + "from qiskit.aqua import QuantumInstance\n", + "from qiskit.aqua.components.optimizers import COBYLA, SPSA, SLSQP\n", + "from qiskit.aqua.operators import Z2Symmetries\n", + "from qiskit.aqua.algorithms import VQE, NumPyEigensolver\n", + "from qiskit.chemistry.components.variational_forms import UCCSD\n", + "from qiskit.chemistry.components.initial_states import HartreeFock\n", + "from qiskit.circuit.library import EfficientSU2\n", + "from qiskit.chemistry.drivers import PySCFDriver, UnitsType\n", + "from qiskit.chemistry import FermionicOperator\n", + "from qiskit.ignis.mitigation.measurement import CompleteMeasFitter\n", + "from qiskit.providers.aer.noise import NoiseModel" + ] + }, + { + "cell_type": "markdown", + "id": "7dadd1bf", + "metadata": {}, + "source": [ + "First, prepare the qubit operators to get the one-body and two-body integrals that encode the Hydrogen molecule and map them onto qubits using Quantum gates.\n", + "\n", + "You'll use [PySCF](https://github.com/pyscf/pyscf) to generate the molecule, and [Qiskit Chemistry](https://quantum-computing.ibm.com/lab/docs/iql/chemistry) to encode it into Fermionic operators." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "9b4ce39a", + "metadata": {}, + "outputs": [], + "source": [ + "# Create a PySCF driver an generate the molecule\n", + "driver = PySCFDriver(atom='H .0 .0 -0.3625; H .0 .0 0.3625', unit=UnitsType.ANGSTROM, charge=0, spin=0, basis='sto3g')\n", + "molecule = driver.run()\n", + "# Get the total number of particles in the molecule\n", + "num_particles = molecule.num_alpha + molecule.num_beta\n", + "# Convert one-body and two-body integrals into fermionic operators\n", + "qubit_op = FermionicOperator(h1=molecule.one_body_integrals, h2=molecule.two_body_integrals).mapping(map_type='parity')\n", + "qubit_op = Z2Symmetries.two_qubit_reduction(qubit_op, num_particles)" + ] + }, + { + "cell_type": "markdown", + "id": "50174a98", + "metadata": {}, + "source": [ + "## 1. Simulate locally\n", + "\n", + "Here, you will simulate the program locally using the Aer simulator. You can create a `QuantumInstance` with a noise model using a mock device `FakeVigo` with noise characteristics." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "737c1000", + "metadata": {}, + "outputs": [], + "source": [ + "from qiskit.test.mock import FakeVigo\n", + "from qiskit.providers.aer import AerSimulator\n", + "from qiskit.providers.aer import QasmSimulator\n", + "from qiskit.providers.aer.noise import NoiseModel\n", + "\n", + "backend = AerSimulator()\n", + "device_backend = FakeVigo()\n", + "device = QasmSimulator.from_backend(device_backend)" + ] + }, + { + "cell_type": "markdown", + "id": "f9939a47", + "metadata": {}, + "source": [ + "Then, run the simulation using the VQE class." + ] + }, + { + "cell_type": "markdown", + "id": "c4ffa5a4", + "metadata": {}, + "source": [ + "### Simulate locally with noise and error mitigation\n", + "\n", + "You can read more about error mitigation in the Qiskit textbook chapter on [Measurement Error Mitigation](https://qiskit.org/textbook/ch-quantum-hardware/measurement-error-mitigation.html)." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "b4788b3c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Exact Result: [-1.13722138]\n", + "VQE Result on noisy simulator: -1.0980120899310355\n" + ] + } + ], + "source": [ + "# Create the noise characteristics and other parameters that describe the device\n", + "coupling_map = device.configuration().coupling_map\n", + "noise_model = NoiseModel.from_backend(device)\n", + "basis_gates = noise_model.basis_gates\n", + "\n", + "# Create the quantum instance to conncet to the backend\n", + "quantum_instance = QuantumInstance(backend=backend, \n", + " shots=8192, \n", + " noise_model=noise_model, \n", + " coupling_map=coupling_map,\n", + " measurement_error_mitigation_cls=CompleteMeasFitter,\n", + " cals_matrix_refresh_period=30)\n", + "\n", + "# Calculate the exact solution using numpy\n", + "exact_solution = NumPyEigensolver(qubit_op).run()\n", + "print(\"Exact Result:\", np.real(exact_solution.eigenvalues) + molecule.nuclear_repulsion_energy)\n", + "\n", + "# Create an optimizer (using SPSA)\n", + "optimizer = SPSA(maxiter=100)\n", + "\n", + "# Create the variational form\n", + "var_form = EfficientSU2(qubit_op.num_qubits, entanglement=\"linear\")\n", + "\n", + "# Create a VQE object that runs VQE using the above created qubit operations, variational form and optimizer\n", + "vqe = VQE(qubit_op, var_form, optimizer=optimizer)\n", + "\n", + "# Run the full VQE program. This might take up to 50 seconds to run on the noisy simulator.\n", + "ret = vqe.run(quantum_instance)\n", + "\n", + "# Get and print the result\n", + "vqe_result = np.real(ret['eigenvalue'] + molecule.nuclear_repulsion_energy)\n", + "print(\"VQE Result on noisy simulator:\", vqe_result)" + ] + }, + { + "cell_type": "markdown", + "id": "84237dc8", + "metadata": {}, + "source": [ + "The parameters found by the optimization loop:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "77f373f5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 0.88146786, 2.14943478, -0.84908566, 1.72896896, -1.57937698,\n", + " 0.00403366, 2.67581075, 0.99780415, -1.25767836, 1.28513983,\n", + " 0.99229133, 1.02959351, -0.82504384, -0.44857987, -2.32099255,\n", + " 0.30197518])" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p0 = ret.optimal_point\n", + "p0" + ] + }, + { + "cell_type": "markdown", + "id": "c4338b61", + "metadata": {}, + "source": [ + "The energy was evaluated a total of `ret.cost_function_evals` times until the minimum was found." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "9930b2c9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "241" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ret.cost_function_evals" + ] + }, + { + "cell_type": "markdown", + "id": "87005ce0", + "metadata": {}, + "source": [ + "### Circuit visualization\n", + "\n", + "Each energy evaluation consists of two circuits. You can visualize these circuits with Qiskit using the `vqe` instance." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "69e6719e", + "metadata": {}, + "outputs": [], + "source": [ + "# The VQE class generates extra unused wires.\n", + "# This function is to remove idle wires to make the visualization more readable.\n", + "# See: https://quantumcomputing.stackexchange.com/questions/25672/remove-inactive-qubits-from-qiskit-circuit\n", + "from qiskit.converters import circuit_to_dag, dag_to_circuit\n", + "from collections import OrderedDict\n", + "\n", + "def remove_idle_qwires(circ):\n", + " dag = circuit_to_dag(circ)\n", + "\n", + " idle_wires = list(dag.idle_wires())\n", + " for w in idle_wires:\n", + " dag._remove_idle_wire(w)\n", + " dag.qubits.remove(w)\n", + "\n", + " dag.qregs = OrderedDict()\n", + "\n", + " return dag_to_circuit(dag)\n", + "\n", + "circs = vqe._circuit_sampler._transpiled_circ_cache\n", + "circs = [remove_idle_qwires(circ) for circ in circs]\n", + "circ = circs[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "e0ab0e41", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
      ┌──────────┐┌──────────┐     ┌──────────┐┌──────────┐     ┌──────────┐»\n",
+       "   0: ┤ Ry(θ[0]) ├┤ Rz(θ[2]) ├──■──┤ Ry(θ[4]) ├┤ Rz(θ[6]) ├──■──┤ Ry(θ[8]) ├»\n",
+       "      ├──────────┤├──────────┤┌─┴─┐├──────────┤├──────────┤┌─┴─┐├──────────┤»\n",
+       "   1: ┤ Ry(θ[1]) ├┤ Rz(θ[3]) ├┤ X ├┤ Ry(θ[5]) ├┤ Rz(θ[7]) ├┤ X ├┤ Ry(θ[9]) ├»\n",
+       "      └──────────┘└──────────┘└───┘└──────────┘└──────────┘└───┘└──────────┘»\n",
+       "c0: 2/══════════════════════════════════════════════════════════════════════»\n",
+       "                                                                            »\n",
+       "«      ┌───────────┐     ┌───────────┐┌───────────┐┌───┐┌─┐   \n",
+       "«   0: ┤ Rz(θ[10]) ├──■──┤ Ry(θ[12]) ├┤ Rz(θ[14]) ├┤ H ├┤M├───\n",
+       "«      ├───────────┤┌─┴─┐├───────────┤├───────────┤├───┤└╥┘┌─┐\n",
+       "«   1: ┤ Rz(θ[11]) ├┤ X ├┤ Ry(θ[13]) ├┤ Rz(θ[15]) ├┤ H ├─╫─┤M├\n",
+       "«      └───────────┘└───┘└───────────┘└───────────┘└───┘ ║ └╥┘\n",
+       "«c0: 2/══════════════════════════════════════════════════╩══╩═\n",
+       "«                                                        0  1 
" + ], + "text/plain": [ + " ┌──────────┐┌──────────┐ ┌──────────┐┌──────────┐ ┌──────────┐»\n", + " 0: ┤ Ry(θ[0]) ├┤ Rz(θ[2]) ├──■──┤ Ry(θ[4]) ├┤ Rz(θ[6]) ├──■──┤ Ry(θ[8]) ├»\n", + " ├──────────┤├──────────┤┌─┴─┐├──────────┤├──────────┤┌─┴─┐├──────────┤»\n", + " 1: ┤ Ry(θ[1]) ├┤ Rz(θ[3]) ├┤ X ├┤ Ry(θ[5]) ├┤ Rz(θ[7]) ├┤ X ├┤ Ry(θ[9]) ├»\n", + " └──────────┘└──────────┘└───┘└──────────┘└──────────┘└───┘└──────────┘»\n", + "c0: 2/══════════════════════════════════════════════════════════════════════»\n", + " »\n", + "« ┌───────────┐ ┌───────────┐┌───────────┐┌───┐┌─┐ \n", + "« 0: ┤ Rz(θ[10]) ├──■──┤ Ry(θ[12]) ├┤ Rz(θ[14]) ├┤ H ├┤M├───\n", + "« ├───────────┤┌─┴─┐├───────────┤├───────────┤├───┤└╥┘┌─┐\n", + "« 1: ┤ Rz(θ[11]) ├┤ X ├┤ Ry(θ[13]) ├┤ Rz(θ[15]) ├┤ H ├─╫─┤M├\n", + "« └───────────┘└───┘└───────────┘└───────────┘└───┘ ║ └╥┘\n", + "«c0: 2/══════════════════════════════════════════════════╩══╩═\n", + "« 0 1 " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "circ.draw()" + ] + }, + { + "cell_type": "markdown", + "id": "5085e0c6", + "metadata": {}, + "source": [ + "This visualization shows the parametric trial state that is prepared and evaluated as part of VQE. The parameters, $\\theta[n]$, are assigned a value for each iteration." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "6dd36770", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
       ┌──────────────────────┐┌───────────────────────┐     »\n",
+       "   0: ─┤ Ry(0.88146786270954) ├┤ Rz(-1.25767836106238) ├──■──»\n",
+       "      ┌┴──────────────────────┤└┬──────────────────────┤┌─┴─┐»\n",
+       "   1: ┤ Ry(0.997804153760643) ├─┤ Rz(1.28513982964721) ├┤ X ├»\n",
+       "      └───────────────────────┘ └──────────────────────┘└───┘»\n",
+       "c0: 2/═══════════════════════════════════════════════════════»\n",
+       "                                                             »\n",
+       "«      ┌───────────────────────┐┌────────────────────────┐     »\n",
+       "«   0: ┤ Ry(0.992291331777119) ├┤ Rz(-0.825043844596012) ├──■──»\n",
+       "«      └┬─────────────────────┬┘├────────────────────────┤┌─┴─┐»\n",
+       "«   1: ─┤ Ry(1.0295935084448) ├─┤ Rz(-0.448579872331894) ├┤ X ├»\n",
+       "«       └─────────────────────┘ └────────────────────────┘└───┘»\n",
+       "«c0: 2/════════════════════════════════════════════════════════»\n",
+       "«                                                              »\n",
+       "«      ┌───────────────────────┐ ┌──────────────────────┐      »\n",
+       "«   0: ┤ Ry(-2.32099254965095) ├─┤ Rz(2.14943478014898) ├───■──»\n",
+       "«      ├───────────────────────┤┌┴──────────────────────┴┐┌─┴─┐»\n",
+       "«   1: ┤ Ry(0.301975180425836) ├┤ Rz(-0.849085656093776) ├┤ X ├»\n",
+       "«      └───────────────────────┘└────────────────────────┘└───┘»\n",
+       "«c0: 2/════════════════════════════════════════════════════════»\n",
+       "«                                                              »\n",
+       "«       ┌──────────────────────┐┌─────────────────────────┐┌───┐┌─┐   \n",
+       "«   0: ─┤ Ry(1.72896895522764) ├┤ Rz(0.00403365782424605) ├┤ H ├┤M├───\n",
+       "«      ┌┴──────────────────────┤└─┬─────────────────────┬─┘├───┤└╥┘┌─┐\n",
+       "«   1: ┤ Ry(-1.57937697516976) ├──┤ Rz(2.6758107484427) ├──┤ H ├─╫─┤M├\n",
+       "«      └───────────────────────┘  └─────────────────────┘  └───┘ ║ └╥┘\n",
+       "«c0: 2/══════════════════════════════════════════════════════════╩══╩═\n",
+       "«                                                                0  1 
" + ], + "text/plain": [ + " ┌──────────────────────┐┌───────────────────────┐ »\n", + " 0: ─┤ Ry(0.88146786270954) ├┤ Rz(-1.25767836106238) ├──■──»\n", + " ┌┴──────────────────────┤└┬──────────────────────┤┌─┴─┐»\n", + " 1: ┤ Ry(0.997804153760643) ├─┤ Rz(1.28513982964721) ├┤ X ├»\n", + " └───────────────────────┘ └──────────────────────┘└───┘»\n", + "c0: 2/═══════════════════════════════════════════════════════»\n", + " »\n", + "« ┌───────────────────────┐┌────────────────────────┐ »\n", + "« 0: ┤ Ry(0.992291331777119) ├┤ Rz(-0.825043844596012) ├──■──»\n", + "« └┬─────────────────────┬┘├────────────────────────┤┌─┴─┐»\n", + "« 1: ─┤ Ry(1.0295935084448) ├─┤ Rz(-0.448579872331894) ├┤ X ├»\n", + "« └─────────────────────┘ └────────────────────────┘└───┘»\n", + "«c0: 2/════════════════════════════════════════════════════════»\n", + "« »\n", + "« ┌───────────────────────┐ ┌──────────────────────┐ »\n", + "« 0: ┤ Ry(-2.32099254965095) ├─┤ Rz(2.14943478014898) ├───■──»\n", + "« ├───────────────────────┤┌┴──────────────────────┴┐┌─┴─┐»\n", + "« 1: ┤ Ry(0.301975180425836) ├┤ Rz(-0.849085656093776) ├┤ X ├»\n", + "« └───────────────────────┘└────────────────────────┘└───┘»\n", + "«c0: 2/════════════════════════════════════════════════════════»\n", + "« »\n", + "« ┌──────────────────────┐┌─────────────────────────┐┌───┐┌─┐ \n", + "« 0: ─┤ Ry(1.72896895522764) ├┤ Rz(0.00403365782424605) ├┤ H ├┤M├───\n", + "« ┌┴──────────────────────┤└─┬─────────────────────┬─┘├───┤└╥┘┌─┐\n", + "« 1: ┤ Ry(-1.57937697516976) ├──┤ Rz(2.6758107484427) ├──┤ H ├─╫─┤M├\n", + "« └───────────────────────┘ └─────────────────────┘ └───┘ ║ └╥┘\n", + "«c0: 2/══════════════════════════════════════════════════════════╩══╩═\n", + "« 0 1 " + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "circ.assign_parameters(ret.optimal_parameters).draw()" + ] + }, + { + "cell_type": "markdown", + "id": "4d49d174", + "metadata": {}, + "source": [ + "## 2. Run on Quantinuum emulator via Azure Quantum Workspace\n", + "\n", + "Now, you can connect to the Azure Quantum Workspace and run VQE on the hardware backends." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "c042c41e", + "metadata": {}, + "outputs": [], + "source": [ + "# Connect to the Azure Quantum Workspace via a Qiskit provider\n", + "from azure.quantum.qiskit import AzureQuantumProvider\n", + "provider = AzureQuantumProvider(\n", + " resource_id = \"\",\n", + " location = \"\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "592e9d54", + "metadata": {}, + "outputs": [], + "source": [ + "# Create Quantinuum emulator backend\n", + "quantinuum_emulator = provider.get_backend(\"quantinuum.hqs-lt-s1-sim\")" + ] + }, + { + "cell_type": "markdown", + "id": "69a3a14c", + "metadata": {}, + "source": [ + "### Estimate cost\n", + "\n", + "You can now estimate how many credits (\"HQC\"/\"EHQC\" for Quantinuum) it will cost to run VQE. For more information about pricing, see the [Azure Quantum pricing](https://docs.microsoft.com/azure/quantum/pricing) documentation page." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "ed975803", + "metadata": {}, + "outputs": [], + "source": [ + "cost = [quantinuum_emulator.estimate_cost(circ.assign_parameters(ret.optimal_parameters), shots=1000) for circ in circs]" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "9edf5289", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "16.6 EHQC\n", + "16.2 EHQC\n" + ] + } + ], + "source": [ + "for _cost in cost:\n", + " print(_cost.estimated_total, _cost.currency_code)" + ] + }, + { + "cell_type": "markdown", + "id": "8924df25", + "metadata": {}, + "source": [ + "So, given approx. 300 energy evaluations, this would give a total cost" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "627268da", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Single iteration: 32.8 EHQC, 300 iterations: 9840.0 EHQC\n" + ] + } + ], + "source": [ + "num_iterations = 300\n", + "energy_eval_cost = sum(_cost.estimated_total for _cost in cost)\n", + "print(f\"Single iteration: {energy_eval_cost} {cost[0].currency_code}, {num_iterations} iterations: {energy_eval_cost * num_iterations} {cost[0].currency_code}\")" + ] + }, + { + "cell_type": "markdown", + "id": "c478eaa4", + "metadata": {}, + "source": [ + "To get a visual on the circuit width and depth, run:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "cb9c3998", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "width | depth\n", + "4 13\n", + "4 13\n" + ] + } + ], + "source": [ + "print(\"width | depth\")\n", + "for circuit in circs:\n", + " circuit = circ.assign_parameters(ret.optimal_parameters)\n", + " circuit = remove_idle_qwires(circuit)\n", + " print(circuit.width(), circuit.depth())" + ] + }, + { + "cell_type": "markdown", + "id": "bc8a8b3e", + "metadata": {}, + "source": [ + "### Run one iteration on Quantinuum emulator via Azure Quantum\n", + "\n", + "It can take a long time to run a full VQE program on hardware, because each iteration puts a circuit in the queue. For demonstration purposes, you can run only the last iteration using the parameters we found with the Aer simulator." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "cedb793f", + "metadata": {}, + "outputs": [], + "source": [ + "# This is a bug that will be addressed in this PR: https://github.com/microsoft/qdk-python/pull/301\n", + "quantinuum_emulator.configuration().max_shots = None" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "a8c69fa4", + "metadata": {}, + "outputs": [], + "source": [ + "# Create Quantum Instance to connect to the backend\n", + "quantum_instance = QuantumInstance(backend=quantinuum_emulator,\n", + " shots=8192)\n", + "# Unset qjob config to avoid errors when running job.result()\n", + "quantum_instance._qjob_config = {}" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "aa220dee", + "metadata": {}, + "outputs": [], + "source": [ + "# Create optimizer with only one iteration\n", + "optimizer = SPSA(maxiter=1)\n", + "# Create the variational form of the ansatz\n", + "var_form = EfficientSU2(qubit_op.num_qubits, entanglement=\"linear\")\n", + "# Create a VQE object that runs the algorithm\n", + "vqe = VQE(qubit_op, var_form, optimizer=optimizer)\n", + "# Set the quantum instance to be able to run only the last iteration\n", + "vqe.quantum_instance = quantum_instance" + ] + }, + { + "cell_type": "markdown", + "id": "ecddf94a", + "metadata": {}, + "source": [ + "The below cell will evaluate the energy at `p0` using the Quantinuum emulator.\n", + "\n", + "You have to add the molecular nuclear repulsion energy to the final result to get the ground state of the molecule." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "659ed1a0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ".....................\n", + "\n", + "-1.1198872295256754\n" + ] + } + ], + "source": [ + "vqe._energy_evaluation(parameters=p0) + molecule.nuclear_repulsion_energy" + ] + }, + { + "cell_type": "markdown", + "id": "6a91f4a4", + "metadata": {}, + "source": [ + "In this notebook, you've run a single iteration of VQE on an Azure Quantum backend to calculate the ground state of a $H_2$ molecule. Nice job! 👏🏽\n", + "\n", + "As a next step, you can modify the sample to run your own molecule, or run it on hardware." + ] + } + ], + "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.9.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}