From 8d3db04c4f603853cc7648f17787c5a34576e370 Mon Sep 17 00:00:00 2001 From: Guen Prawiroatmodjo Date: Mon, 2 May 2022 10:25:43 -0700 Subject: [PATCH 1/6] add vqe notebooks add README Update README.md Update VQE-qiskit-hydrogen-ionq-sim.ipynb respond to code review comments update notebooks Update samples/azure-quantum/variational-quantum-eigensolver/VQE-qiskit-hydrogen-ionq-sim.ipynb Co-authored-by: Cassandra Granade add in link to qiskit textbook add pip install, formatting and comments snake case add back in missing changes add in vqe diagram Apply suggestions from code review Co-authored-by: Cassandra Granade Update README.md process review comments final run through remove pip install cell --- .../variational-quantum-eigensolver/README.md | 20 + .../VQE-qiskit-hydrogen-ionq-sim.ipynb | 674 ++++++++++++++++++ ...-qiskit-hydrogen-quantinuum-emulator.ipynb | 669 +++++++++++++++++ 3 files changed, 1363 insertions(+) create mode 100644 samples/azure-quantum/variational-quantum-eigensolver/README.md create mode 100644 samples/azure-quantum/variational-quantum-eigensolver/VQE-qiskit-hydrogen-ionq-sim.ipynb create mode 100644 samples/azure-quantum/variational-quantum-eigensolver/VQE-qiskit-hydrogen-quantinuum-emulator.ipynb 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..7311b086a429 --- /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: 05/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..eba7238abe90 --- /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.currency_code}, {num_iterations} iterations: {energy_eval_cost * num_iterations} {_cost.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..9d7f4d546173 --- /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\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.currency_code}, {num_iterations} iterations: {energy_eval_cost * num_iterations} {_cost.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 +} From c8b8fa9347b3bb54f75c8ad36559b5ac4e87e5f2 Mon Sep 17 00:00:00 2001 From: Guen Prawiroatmodjo Date: Thu, 2 Jun 2022 15:56:51 -0700 Subject: [PATCH 2/6] update ms.date --- samples/azure-quantum/variational-quantum-eigensolver/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/azure-quantum/variational-quantum-eigensolver/README.md b/samples/azure-quantum/variational-quantum-eigensolver/README.md index 7311b086a429..0eca1baf2d82 100644 --- a/samples/azure-quantum/variational-quantum-eigensolver/README.md +++ b/samples/azure-quantum/variational-quantum-eigensolver/README.md @@ -3,7 +3,7 @@ page_type: sample author: guenp description: Variational Quantum Eigensolver ms.author: guenp@microsoft.com -ms.date: 05/02/2022 +ms.date: 06/02/2022 languages: - python products: From 6cacf33a9189655b29c4f8e952d09e828c3e0ce9 Mon Sep 17 00:00:00 2001 From: Guen Prawiroatmodjo Date: Mon, 6 Jun 2022 11:46:17 -0700 Subject: [PATCH 3/6] Update binder-index.md --- binder-index.md | 8 ++++++++ 1 file changed, 8 insertions(+) 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 From ab8ee849431ce08aaa47a4a051b576ba0588563f Mon Sep 17 00:00:00 2001 From: Guen Prawiroatmodjo Date: Mon, 6 Jun 2022 15:32:58 -0700 Subject: [PATCH 4/6] Update VQE-qiskit-hydrogen-ionq-sim.ipynb --- .../VQE-qiskit-hydrogen-ionq-sim.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index eba7238abe90..a1e9e474b8f1 100644 --- 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 @@ -514,7 +514,7 @@ "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.currency_code}, {num_iterations} iterations: {energy_eval_cost * num_iterations} {_cost.currency_code}\")" + "print(f\"Single iteration: {energy_eval_cost} {cost[0].currency_code}, {num_iterations} iterations: {energy_eval_cost * num_iterations} {cost[0].currency_code}\")" ] }, { From 2512603aac2f73e9d443f60b2707d80ce2a439cc Mon Sep 17 00:00:00 2001 From: Guen Prawiroatmodjo Date: Mon, 6 Jun 2022 15:33:24 -0700 Subject: [PATCH 5/6] Update VQE-qiskit-hydrogen-quantinuum-emulator.ipynb --- .../VQE-qiskit-hydrogen-quantinuum-emulator.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 9d7f4d546173..580f99a3c82f 100644 --- 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 @@ -515,7 +515,7 @@ "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.currency_code}, {num_iterations} iterations: {energy_eval_cost * num_iterations} {_cost.currency_code}\")" + "print(f\"Single iteration: {energy_eval_cost} {cost[0].currency_code}, {num_iterations} iterations: {energy_eval_cost * num_iterations} {cost[0].currency_code}\")" ] }, { From e93e3e7f70ac7ffcece690e0af3714e9afde8982 Mon Sep 17 00:00:00 2001 From: Guen Prawiroatmodjo Date: Mon, 6 Jun 2022 15:34:35 -0700 Subject: [PATCH 6/6] Update VQE-qiskit-hydrogen-quantinuum-emulator.ipynb --- .../VQE-qiskit-hydrogen-quantinuum-emulator.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 580f99a3c82f..8376cd2a9d39 100644 --- 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 @@ -166,7 +166,7 @@ "# 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", + "# 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",