qiskit-documentation/docs/tutorials/compute-dissociation-curves...

678 lines
19 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"id": "b6d1e3ec",
"metadata": {},
"source": [
"{/* cspell:ignore QSCI CISD CCSD markersize */}\n",
"\n",
"# Compute dissociation curves for strong coupling systems with QunaSys QSCI"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "a6f69b77",
"metadata": {},
"source": [
"*Usage estimate (NOTE: This is an estimate only. Your runtime may vary.)*\n",
"\n",
"* 5 minutes QPU time on ibm\\_strasbourg\n",
"* 2.5 minutes QPU time on ibm\\_torino"
]
},
{
"cell_type": "markdown",
"id": "8bf80006",
"metadata": {},
"source": [
"## Background\n",
"\n",
"Finding the ground state energy of molecules is a common step in material science, drug discovery and various other fields. Solving the ground state energy for strong coupling system in the dissociation process is particularly known to be difficult with classical methods such as Hartree-Fock (HF), CISD and CCSD. While FCI produces the exact ground state of the given Hamiltonian, diagonalizing the Hamiltonian using the full subspace basis vectors and is usually computationally costly. In this tutorial, you will learn how to use QURI Chemistry to produce the dissociation curve of $N_2$."
]
},
{
"cell_type": "markdown",
"id": "55b94021",
"metadata": {},
"source": [
"## Requirements\n",
"\n",
"Install the following dependencies to run the code in this tutorial."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0a778d85",
"metadata": {},
"outputs": [],
"source": [
"!pip install qiskit-ibm-catalog\n",
"!pip install pyscf"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "7db2e559",
"metadata": {},
"source": [
"## Setup\n",
"\n",
"To use QURI Chemistry, select the function via `QiskitFunctionCatalog`. You need an IBM Quantum Premium Plan account with a license from Qunasys to run this function."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bc380c46",
"metadata": {},
"outputs": [],
"source": [
"from qiskit_ibm_catalog import QiskitFunctionsCatalog\n",
"\n",
"catalog = QiskitFunctionsCatalog()\n",
"qsci = catalog.load(\"qunasys/qsci\")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "988ee237",
"metadata": {},
"source": [
"## Step 1: Map classical inputs to a quantum problem\n",
"\n",
"Construct the molecule in json format. As an illustration, we assume the separation between the 2 nitrogen atoms to be 1 angstrom apart from each other."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0ad66539",
"metadata": {},
"outputs": [],
"source": [
"parameters = {}\n",
"\n",
"parameters[\"mole\"] = {\"atom\": \"N 0 0 0; N 0 0 1.0\"}"
]
},
{
"cell_type": "markdown",
"id": "a93116dd",
"metadata": {},
"source": [
"Next, configure the QSCI algorithm by selecting the ansatz. Double excitation ansatz is recommended. CCSD parameter is used to prepare the ansatz."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "980f8455",
"metadata": {},
"outputs": [],
"source": [
"parameters[\"ansatz\"] = \"DoubleExcitation\"\n",
"parameters[\"ansatz_setting\"] = {\"n_amplitudes\": 20}\n",
"parameters[\"state_prep_method\"] = \"CCSD\""
]
},
{
"cell_type": "markdown",
"id": "aab531f1",
"metadata": {},
"source": [
"Discretion is required to select the subspace size $R$ to run the QSCI algorithm. A space too small cannot capture enough important configurations. However, a space too large would correspond to FCI and the use of quantum computers become redundant. In the sto-3g basis, $N_2$ contains 10 spatial orbitals and 14 electrons. This thus maps to a 20-qubit problem. The FCI space contains 14400 basis vectors, so the selected subspace size should not approach this value. We choose half of this size as the subspace size for demonstration."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "829552ef",
"metadata": {},
"outputs": [],
"source": [
"parameters[\"qsci_setting\"] = {\n",
" \"n_shots\": 100000,\n",
" \"number_of_states_pick_out\": 7200,\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6f22e572",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'ansatz': 'DoubleExcitation',\n",
" 'ansatz_setting': {'n_amplitudes': 20},\n",
" 'mole': {'atom': 'N 0 0 0; N 0 0 1.0'},\n",
" 'qsci_setting': {'n_shots': 100000, 'number_of_states_pick_out': 7200},\n",
" 'state_prep_method': 'CCSD'}\n"
]
}
],
"source": [
"from pprint import pprint\n",
"\n",
"pprint(parameters)"
]
},
{
"cell_type": "markdown",
"id": "2e61258f",
"metadata": {},
"source": [
"To improve the performance, it is recommended to turn on configuration recovery. For 20 qubit system with $R = 7200$, using the default configuration recovery setting is sufficient."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a8a4a2be",
"metadata": {},
"outputs": [],
"source": [
"parameters[\"mitigation_setting\"] = {\"configuration_recovery\": True}"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "b4d480b3",
"metadata": {},
"source": [
"## Step 3: Execute using Qiskit Primitives\n",
"\n",
"Now, pick the backend to submit the job to the function"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ccb51745",
"metadata": {},
"outputs": [],
"source": [
"result = qsci.run(\n",
" method=\"QSCI\",\n",
" parameters=parameters,\n",
" backend=\"ibm_torino\",\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "187261b5",
"metadata": {},
"outputs": [],
"source": [
"qsci_energy = result[\"qsci_energy\"]\n",
"state_vector = result[\"state_vector\"].copy()"
]
},
{
"cell_type": "markdown",
"id": "384584b1",
"metadata": {},
"source": [
"FCI computation is still feasible at the scale of 20-qubit. We use PySCF to perform several classical computations and compare the energies against the QSCI energy."
]
},
{
"cell_type": "markdown",
"id": "c14872f4",
"metadata": {},
"source": [
"## Step 4: Compare with classical methods"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dce9c70d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"HF energy : -107.4195 Ha, error: 129.77 mHa\n",
"CISD energy : -107.5414 Ha, error: 7.91 mHa\n",
"CCSD energy : -107.5467 Ha, error: 2.58 mHa\n",
"QSCI energy : -107.5492 Ha, error: 0.09 mHa\n",
"FCI energy : -107.5493 Ha\n"
]
}
],
"source": [
"from pyscf import gto, scf, cc, ci, fci\n",
"\n",
"mole = gto.M(atom=\"N 0 0 0; N 0 0 1.0\")\n",
"mf = scf.RHF(mole).run(verbose=0)\n",
"cisd = ci.CISD(mf).run(verbose=0)\n",
"ccsd = cc.CCSD(mf).run(verbose=0)\n",
"fci_solver = fci.FCI(mf).run()\n",
"\n",
"print(\n",
" f\"HF energy : {mf.e_tot: .4f} Ha, error: {(mf.e_tot - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(\n",
" f\"CISD energy : {cisd.e_tot: .4f} Ha, error: {(cisd.e_tot - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(\n",
" f\"CCSD energy : {ccsd.e_tot: .4f} Ha, error: {(ccsd.e_tot - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(\n",
" f\"QSCI energy : {qsci_energy: .4f} Ha, error: {(qsci_energy - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(f\"FCI energy : {fci_solver.e_tot: .4f} Ha\")"
]
},
{
"cell_type": "markdown",
"id": "b376cb2f",
"metadata": {},
"source": [
"You can see that QSCI is the only method that falls into the chemical accuracy region where energy error needs to be less than 1.6 mHa, and this is done by diagonalizing the subspace Hamiltonian *half* the size of the FCI space."
]
},
{
"cell_type": "markdown",
"id": "1d916e65",
"metadata": {},
"source": [
"## Producing the dissociation curve\n",
"\n",
"As mentioned at the beginning of this tutorial, the non-triviality of our method is that it produces the *whole* $N_2$ dissociation curve with high accuracy. You can reuse the qsci input above with different distance settings."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "31c8db57",
"metadata": {},
"outputs": [],
"source": [
"def get_qsci_json(distance: float) -> None:\n",
" return {\n",
" \"mole\": {\"atom\": f\"N 0 0 0; N 0 0 {distance}\"},\n",
" \"ansatz\": \"DoubleExcitation\",\n",
" \"state_prep_method\": \"CCSD\",\n",
" \"ansatz_setting\": {\"n_amplitudes\": 20},\n",
" \"qsci_setting\": {\n",
" \"n_shots\": 100000,\n",
" \"number_of_states_pick_out\": 7200,\n",
" },\n",
" \"mitigation_setting\": {\"configuration_recovery\": True},\n",
" }"
]
},
{
"cell_type": "markdown",
"id": "6496a13c",
"metadata": {},
"source": [
"With this function, we scan over $d = 0.7, 1.0, 1.5, 2.0, 2.4$."
]
},
{
"cell_type": "markdown",
"id": "61232aea",
"metadata": {},
"source": [
"#### d = 0.7 angstrom"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6fff18fd",
"metadata": {},
"outputs": [],
"source": [
"input_07 = get_qsci_json(0.7)\n",
"result_07 = qsci.run(method=\"QSCI\", parameters=input_07, backend=\"ibm_torino\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4e18bd6d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"HF energy : -105.6974 Ha, error: 67.57 mHa\n",
"CISD energy : -105.7632 Ha, error: 1.76 mHa\n",
"CCSD energy : -105.7642 Ha, error: 0.75 mHa\n",
"QSCI energy : -105.7650 Ha, error: 0.01 mHa\n",
"FCI energy : -105.7650 Ha\n"
]
}
],
"source": [
"mole = gto.M(atom=\"N 0 0 0; N 0 0 0.7\")\n",
"mf = scf.RHF(mole).run(verbose=0)\n",
"cisd = ci.CISD(mf).run(verbose=0)\n",
"ccsd = cc.CCSD(mf).run(verbose=0)\n",
"fci_solver = fci.FCI(mf).run()\n",
"\n",
"qsci_energy_07 = result_07[\"qsci_energy\"]\n",
"print(\n",
" f\"HF energy : {mf.e_tot: .4f} Ha, error: {(mf.e_tot - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(\n",
" f\"CISD energy : {cisd.e_tot: .4f} Ha, error: {(cisd.e_tot - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(\n",
" f\"CCSD energy : {ccsd.e_tot: .4f} Ha, error: {(ccsd.e_tot - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(\n",
" f\"QSCI energy : {qsci_energy_07: .4f} Ha, error: {(qsci_energy_07 - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(f\"FCI energy : {fci_solver.e_tot: .4f} Ha\")"
]
},
{
"cell_type": "markdown",
"id": "0fba0913",
"metadata": {},
"source": [
"#### d = 1.5 angstrom"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6994ed90",
"metadata": {},
"outputs": [],
"source": [
"input_15 = get_qsci_json(1.5)\n",
"result_15 = qsci.run(method=\"QSCI\", parameters=input_15, backend=\"ibm_torino\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "eecfda6c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"HF energy : -107.2724 Ha, error: 309.19 mHa\n",
"CISD energy : -107.5269 Ha, error: 54.69 mHa\n",
"CCSD energy : -107.5679 Ha, error: 13.78 mHa\n",
"QSCI energy : -107.5810 Ha, error: 0.66 mHa\n",
"FCI energy : -107.5816 Ha\n"
]
}
],
"source": [
"mole = gto.M(atom=\"N 0 0 0; N 0 0 1.5\")\n",
"mf = scf.RHF(mole).run(verbose=0)\n",
"cisd = ci.CISD(mf).run(verbose=0)\n",
"ccsd = cc.CCSD(mf).run(verbose=0)\n",
"fci_solver = fci.FCI(mf).run()\n",
"\n",
"qsci_energy_15 = result_15[\"qsci_energy\"]\n",
"print(\n",
" f\"HF energy : {mf.e_tot: .4f} Ha, error: {(mf.e_tot - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(\n",
" f\"CISD energy : {cisd.e_tot: .4f} Ha, error: {(cisd.e_tot - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(\n",
" f\"CCSD energy : {ccsd.e_tot: .4f} Ha, error: {(ccsd.e_tot - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(\n",
" f\"QSCI energy : {qsci_energy_15: .4f} Ha, error: {(qsci_energy_15 - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(f\"FCI energy : {fci_solver.e_tot: .4f} Ha\")"
]
},
{
"cell_type": "markdown",
"id": "018efc55",
"metadata": {},
"source": [
"#### d = 2.0 angstrom"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b3c4c55e",
"metadata": {},
"outputs": [],
"source": [
"input_20 = get_qsci_json(2.0)\n",
"result_20 = qsci.run(method=\"QSCI\", parameters=input_20, backend=\"ibm_torino\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a8881659",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"HF energy : -106.8715 Ha, error: 583.65 mHa\n",
"CISD energy : -107.2857 Ha, error: 169.48 mHa\n",
"CCSD energy : -107.5570 Ha, error: -101.83 mHa\n",
"QSCI energy : -107.4519 Ha, error: 3.21 mHa\n",
"FCI energy : -107.4552 Ha\n"
]
}
],
"source": [
"mole = gto.M(atom=\"N 0 0 0; N 0 0 2.0\")\n",
"mf = scf.RHF(mole).run(verbose=0)\n",
"cisd = ci.CISD(mf).run(verbose=0)\n",
"ccsd = cc.CCSD(mf).run(verbose=0)\n",
"fci_solver = fci.FCI(mf).run()\n",
"\n",
"qsci_energy_20 = result_20[\"qsci_energy\"]\n",
"print(\n",
" f\"HF energy : {mf.e_tot: .4f} Ha, error: {(mf.e_tot - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(\n",
" f\"CISD energy : {cisd.e_tot: .4f} Ha, error: {(cisd.e_tot - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(\n",
" f\"CCSD energy : {ccsd.e_tot: .4f} Ha, error: {(ccsd.e_tot - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(\n",
" f\"QSCI energy : {qsci_energy_20: .4f} Ha, error: {(qsci_energy_20 - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(f\"FCI energy : {fci_solver.e_tot: .4f} Ha\")"
]
},
{
"cell_type": "markdown",
"id": "ff08f362",
"metadata": {},
"source": [
"#### d = 2.4 angstrom"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bb9782b1",
"metadata": {},
"outputs": [],
"source": [
"input_24 = get_qsci_json(2.4)\n",
"result_24 = qsci.run(method=\"QSCI\", parameters=input_24, backend=\"ibm_torino\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "830f532d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"HF energy : -106.6566 Ha, error: 784.70 mHa\n",
"CISD energy : -107.1734 Ha, error: 267.94 mHa\n",
"CCSD energy : -107.0828 Ha, error: 358.53 mHa\n",
"QSCI energy : -107.4413 Ha, error: 0.01 mHa\n",
"FCI energy : -107.4413 Ha\n"
]
}
],
"source": [
"mole = gto.M(atom=\"N 0 0 0; N 0 0 2.4\")\n",
"mf = scf.RHF(mole).run(verbose=0)\n",
"cisd = ci.CISD(mf).run(verbose=0)\n",
"ccsd = cc.CCSD(mf).run(verbose=0)\n",
"fci_solver = fci.FCI(mf).run()\n",
"\n",
"qsci_energy_24 = result_24[\"qsci_energy\"]\n",
"print(\n",
" f\"HF energy : {mf.e_tot: .4f} Ha, error: {(mf.e_tot - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(\n",
" f\"CISD energy : {cisd.e_tot: .4f} Ha, error: {(cisd.e_tot - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(\n",
" f\"CCSD energy : {ccsd.e_tot: .4f} Ha, error: {(ccsd.e_tot - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(\n",
" f\"QSCI energy : {qsci_energy_24: .4f} Ha, error: {(qsci_energy_24 - fci_solver.e_tot) * 1000: .2f} mHa\"\n",
")\n",
"print(f\"FCI energy : {fci_solver.e_tot: .4f} Ha\")"
]
},
{
"cell_type": "markdown",
"id": "ea3abb2f",
"metadata": {},
"source": [
"### The dissociation curve\n",
"\n",
"Finally, plot the QSCI energy against the classical methods: HF, CISD, CCSD, and FCI.\n",
"You can see that all the QSCI points match well with the FCI values."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "baa2ab11",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"\n",
"hf_list = []\n",
"cisd_list = []\n",
"ccsd_list = []\n",
"fci_list = []\n",
"\n",
"for d in np.linspace(0.7, 2.4, 18):\n",
" mole = gto.M(atom=f\"N 0 0 0; N 0 0 {d}\")\n",
" mf = scf.RHF(mole).run(verbose=0)\n",
" cisd = ci.CISD(mf).run(verbose=0)\n",
" ccsd = cc.CCSD(mf).run(verbose=0)\n",
" fci_solver = fci.FCI(mf).run()\n",
"\n",
" hf_list.append(mf.e_tot)\n",
" cisd_list.append(cisd.e_tot)\n",
" ccsd_list.append(ccsd.e_tot)\n",
" fci_list.append(fci_solver.e_tot)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6a911fe6",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<Image src=\"/docs/images/tutorials/compute-dissociation-curves-for-strong-coupling-systems-with-quna-sys-qsci/extracted-outputs/6a911fe6-0.avif\" alt=\"Output of the previous code cell\" />"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"ds = np.linspace(0.7, 2.4, 18)\n",
"\n",
"fig, ax = plt.subplots(1, 1)\n",
"ax.plot(ds, hf_list, \"-o\", label=\"HF\")\n",
"ax.plot(ds, cisd_list, \"-o\", label=\"CISD\")\n",
"ax.plot(ds, ccsd_list, \"-o\", label=\"CCSD\")\n",
"ax.plot(ds, fci_list, \"-o\", label=\"FCI\")\n",
"ax.plot(\n",
" [0.7, 1.0, 1.5, 2.0, 2.4],\n",
" [\n",
" qsci_energy_07,\n",
" qsci_energy,\n",
" qsci_energy_15,\n",
" qsci_energy_20,\n",
" qsci_energy_24,\n",
" ],\n",
" \"o\",\n",
" color=\"black\",\n",
" markersize=8,\n",
" label=\"QSCI\",\n",
")\n",
"ax.legend(fontsize=20)\n",
"ax.tick_params(\"both\", labelsize=16)\n",
"ax.set_xlabel(\"d\", size=20)\n",
"ax.set_ylabel(\"Energy (Ha)\", size=20)\n",
"ax.set_title(\"$N_2$ dissociation curve\", size=20)\n",
"fig.set_size_inches(14, 8)"
]
}
],
"metadata": {
"description": "Use QURI Chemistry to produce the dissociation curve of nitrogen (N2)",
"kernelspec": {
"display_name": "Python 3",
"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"
},
"platform": "cloud",
"title": "Compute dissociation curves for strong coupling systems with QunaSys QSCI"
},
"nbformat": 4,
"nbformat_minor": 5
}