{ "cells": [ { "attachments": {}, "cell_type": "markdown", "id": "d29537f8-fd49-411a-a4bd-78d07c2f4044", "metadata": {}, "source": [ "Tackling larger systems with fragmentation\n", "===========================================\n", "\n", "In the [basic VQE](InQ_tut_vqe_1.ipynb) and [extended VQE](InQ_tut_vqe_2.ipynb) tutorials, we covered how to run a simple VQE calculation using InQuanto and some optimizations that can be performed. Here, we look at using Density Matrix Embedding Theory (DMET) to examine a larger system by fragmenting it. As an example, we consider HCOOH (formic acid). Without considering symmetry or active space reductions, this system would require 34 qubits to simulate using an STO-3G basis. This requires more resources than are available on current quantum computers, and will be extremely expensive to simulate on a classical device.\n", "\n", "DMET is a method of studying large molecules by partitioning the system into fragments containing a smaller number of atoms. Each fragment is treated independently in a bath corresponding to the molecular environment. Crucially, DMET allows for different fragments to be treated using different electronic structure methods. For example, we could imagine using VQE on the quantum computer to treat one particular fragment of interest. We focus here on a simplified implementation of DMET -- the so-called one-shot DMET. More examples are in the examples/embeddings folder. For discussion of the theory underpinning DMET, see [Knizia & Chan (2012)](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.109.186404). As DMET relies heavily on performing classical electronic structure calculations in addition to any quantum computations, we need to import a driver and the fragment solvers from the `inquanto-pyscf` extension." ] }, { "cell_type": "code", "execution_count": null, "id": "dfc0b93e-14ab-4cbf-b411-a2f2b16814c2", "metadata": {}, "outputs": [], "source": [ "from inquanto.geometries import GeometryMolecular\n", "from inquanto.embeddings import DMETRHF\n", "from inquanto.extensions.pyscf import ChemistryDriverPySCFMolecularRHF\n", "from inquanto.extensions.pyscf import DMETRHFFragmentPySCFCCSD, get_fragment_orbital_masks, get_fragment_orbitals\n", "from pytket.extensions.qiskit import AerStateBackend" ] }, { "attachments": {}, "cell_type": "markdown", "id": "be2e7a06-a884-4e37-9b21-d349055fca0c", "metadata": {}, "source": [ "In order to use DMET to study our system, we must choose a scheme to split the molecule into fragments. In general, this is a task which requires chemical intuition and an awareness of the resource implications of the size of each fragment. As our goal here is to perform a simulation that runs quickly (and not to obtain highly accurate results), we choose a very fine fragmentation scheme with several small fragments.\n", "\n", "\n", "\n", "The above figure shows the fragmentation scheme graphically. We see that other than the hydroxyl, each atom is in its own fragment. This ensures that the maximum number of qubits required to simulate an individual fragment would be 12 (the hydroxyl fragment), a reasonable number of qubits to simulate on a large classical computer." ] }, { "cell_type": "code", "execution_count": null, "id": "ba6b44d0-2ae6-4eb1-9396-283362f870a3", "metadata": {}, "outputs": [], "source": [ "# ################# #\n", "# MOLECULE & DRIVER #\n", "# ################# #\n", "\n", "xyz = [['C', [0.000, 0.442, 0.000]],\n", " ['O', [-1.046, -0.467, 0.000]],\n", " ['O', [1.171, 0.120, 0.000]],\n", " ['H', [-0.389, 1.475, 0.000]],\n", " ['H', [-0.609, -1.355, 0.000]]]\n", "\n", "geometry = GeometryMolecular(xyz)\n", "\n", "basis = 'sto-3g'\n", "charge = 0\n", "driver = ChemistryDriverPySCFMolecularRHF(basis='sto-3g',\n", " geometry=geometry,\n", " charge=0,\n", " verbose=0)\n", "\n", "hamiltonian_operator, space, rdm1 = driver.get_lowdin_system()\n", "\n", "dmet = DMETRHF(hamiltonian_operator, rdm1)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "0a40b1ef", "metadata": {}, "source": [ "As before, we first initialise the driver. The initialization of the driver is much the same as in standard VQE with regards to the molecule geometry, basis and charge specification. However, because of the spatial fragmentation, DMET requires the localisation of the molecular orbitals. Therefore, when we compute the Hamiltonian operator, instead of `get_system()` we call the `get_lowdin_system()` method. This will perform an RHF simulation of the molecule, and will return the mean-field 1e-RDM as `rdm1`, the `space` and the `hamiltonian_operator` in the Löwdin basis, that is computed by Löwdin symmetric orthogonalization of the atomic orbitals.\n", "\n", "Finally, we initialize the DMET method with the `hamiltonian_operator` and the `rdm1`.\n", "\n", "At this stage, we have not specified any particular fragmentation scheme. Fragments in InQuanto are associated with the level of electronic structure theory that will be used to simulate them. As a first test, we try specifying that each fragment should be treated with classical CCSD." ] }, { "attachments": {}, "cell_type": "markdown", "id": "c34f707e", "metadata": {}, "source": [ "In order to specify a fragment, we need to determine the corresponding Löwdin orbitals. The easiest way to specify the fragments is by atoms. Based on the indices in the `xyz` table, we can make four sets of atom indices, and using the `get_fragment_orbitals()` utility function we can tabulate the orbitals and the four orbital fragment masks that select the Löwdin orbitals corresponding to the fragments:" ] }, { "cell_type": "code", "execution_count": null, "id": "2b4a747d", "metadata": {}, "outputs": [ { "data": { "application/vnd.microsoft.datawrangler.viewer.v0+json": { "columns": [ { "name": "index", "rawType": "int64", "type": "integer" }, { "name": "0", "rawType": "object", "type": "string" }, { "name": "1", "rawType": "bool", "type": "boolean" }, { "name": "2", "rawType": "bool", "type": "boolean" }, { "name": "3", "rawType": "bool", "type": "boolean" }, { "name": "4", "rawType": "bool", "type": "boolean" } ], "ref": "e01d9970-b0fb-4ebe-894a-d84591324186", "rows": [ [ "0", "0 C 1s ", "True", "False", "False", "False" ], [ "1", "0 C 2s ", "True", "False", "False", "False" ], [ "2", "0 C 2px ", "True", "False", "False", "False" ], [ "3", "0 C 2py ", "True", "False", "False", "False" ], [ "4", "0 C 2pz ", "True", "False", "False", "False" ], [ "5", "1 O 1s ", "False", "False", "True", "False" ], [ "6", "1 O 2s ", "False", "False", "True", "False" ], [ "7", "1 O 2px ", "False", "False", "True", "False" ], [ "8", "1 O 2py ", "False", "False", "True", "False" ], [ "9", "1 O 2pz ", "False", "False", "True", "False" ], [ "10", "2 O 1s ", "False", "True", "False", "False" ], [ "11", "2 O 2s ", "False", "True", "False", "False" ], [ "12", "2 O 2px ", "False", "True", "False", "False" ], [ "13", "2 O 2py ", "False", "True", "False", "False" ], [ "14", "2 O 2pz ", "False", "True", "False", "False" ], [ "15", "3 H 1s ", "False", "False", "False", "True" ], [ "16", "4 H 1s ", "False", "False", "True", "False" ] ], "shape": { "columns": 5, "rows": 17 } }, "text/html": [ "
\n", " | 0 | \n", "1 | \n", "2 | \n", "3 | \n", "4 | \n", "
---|---|---|---|---|---|
0 | \n", "0 C 1s | \n", "True | \n", "False | \n", "False | \n", "False | \n", "
1 | \n", "0 C 2s | \n", "True | \n", "False | \n", "False | \n", "False | \n", "
2 | \n", "0 C 2px | \n", "True | \n", "False | \n", "False | \n", "False | \n", "
3 | \n", "0 C 2py | \n", "True | \n", "False | \n", "False | \n", "False | \n", "
4 | \n", "0 C 2pz | \n", "True | \n", "False | \n", "False | \n", "False | \n", "
5 | \n", "1 O 1s | \n", "False | \n", "False | \n", "True | \n", "False | \n", "
6 | \n", "1 O 2s | \n", "False | \n", "False | \n", "True | \n", "False | \n", "
7 | \n", "1 O 2px | \n", "False | \n", "False | \n", "True | \n", "False | \n", "
8 | \n", "1 O 2py | \n", "False | \n", "False | \n", "True | \n", "False | \n", "
9 | \n", "1 O 2pz | \n", "False | \n", "False | \n", "True | \n", "False | \n", "
10 | \n", "2 O 1s | \n", "False | \n", "True | \n", "False | \n", "False | \n", "
11 | \n", "2 O 2s | \n", "False | \n", "True | \n", "False | \n", "False | \n", "
12 | \n", "2 O 2px | \n", "False | \n", "True | \n", "False | \n", "False | \n", "
13 | \n", "2 O 2py | \n", "False | \n", "True | \n", "False | \n", "False | \n", "
14 | \n", "2 O 2pz | \n", "False | \n", "True | \n", "False | \n", "False | \n", "
15 | \n", "3 H 1s | \n", "False | \n", "False | \n", "False | \n", "True | \n", "
16 | \n", "4 H 1s | \n", "False | \n", "False | \n", "True | \n", "False | \n", "