From d0722919329eca4c6a9f4996c3cd0c9c6ecbe694 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan Date: Mon, 17 Mar 2025 11:24:23 -0400 Subject: [PATCH 01/14] Initiating the demo --- demonstrations/tutorial_dmet_embedding.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 demonstrations/tutorial_dmet_embedding.py diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py new file mode 100644 index 0000000000..e618c00cfc --- /dev/null +++ b/demonstrations/tutorial_dmet_embedding.py @@ -0,0 +1,16 @@ +r"""Quantum Defect Embedding Theory (QDET) +========================================= +Materials simulation presents a crucial challenge in quantum chemistry, as understanding and predicting the properties of +complex materials is essential for advancements in technology and science. While Density Functional Theory (DFT) is +the current workhorse in this field due to its balance between accuracy and computational efficiency, it often falls short in +accurately capturing the intricate electron correlation effects found in strongly correlated materials. As a result, +researchers often turn to more sophisticated methods, such as full configuration interaction or coupled cluster theory, +which provide better accuracy but come at a significantly higher computational cost. Embedding theories provide a balanced +midpoint solution that enhances our ability to simulate materials accurately and efficiently. The core idea behind embedding +is to treat the strongly correlated subsystem accurately using high-level quantum mechanical methods while approximating +the effects of the surrounding environment in a way that retains computational efficiency. +Density matrix embedding theory(DMET) is one such efficient wave-function-based embedding approach to treat strongly +correlated systems. Here, we present a demonstration of how to run DMET calculations through an existing library called +libDMET, along with the intructions on how we can use the generated Hamiltonian with PennyLane to use it with quantum +computing algorithms. We begin by providing a high-level introduction to DMET, followed by a tutorial on how to set up +a DMET calculation.""" \ No newline at end of file From fe690e3c329545ffe6dcd9345f8bd3db2e3ff7f8 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan Date: Mon, 17 Mar 2025 11:28:00 -0400 Subject: [PATCH 02/14] Initiating the demo --- demonstrations/tutorial_dmet_embedding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index e618c00cfc..a118c46c15 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -1,4 +1,4 @@ -r"""Quantum Defect Embedding Theory (QDET) +r"""Density Matrix Embedding Theory (DMET) ========================================= Materials simulation presents a crucial challenge in quantum chemistry, as understanding and predicting the properties of complex materials is essential for advancements in technology and science. While Density Functional Theory (DFT) is From 93a6f6553a193ab9f66b1f362d304bad7a38ab18 Mon Sep 17 00:00:00 2001 From: soranjh Date: Mon, 17 Mar 2025 17:47:08 -0400 Subject: [PATCH 03/14] add implementation sections --- demonstrations/tutorial_dmet_embedding.py | 110 +++++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index a118c46c15..1940a7186f 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -13,4 +13,112 @@ correlated systems. Here, we present a demonstration of how to run DMET calculations through an existing library called libDMET, along with the intructions on how we can use the generated Hamiltonian with PennyLane to use it with quantum computing algorithms. We begin by providing a high-level introduction to DMET, followed by a tutorial on how to set up -a DMET calculation.""" \ No newline at end of file +a DMET calculation. + +.. figure:: ../_static/demo_thumbnails/opengraph_demo_thumbnails/OGthumbnail_how_to_build_spin_hamiltonians.png + :align: center + :width: 70% + :target: javascript:void(0) +""" + +###################################################################### +# Theory +# ------ +# +###################################################################### +# Implementation +# -------------- +# We now use what we have learned to set up a DMET calculation for $H_6$ system. +# +# Constructing the system +# ^^^^^^^^^^^^^^^^^^^^^^^ +# We begin by defining a periodic system using the PySCF interface to create a cell object +# representing a hydrogen chain with 6 atoms. The lattice vectors are specified to define the +# geometry of the unit cell, within this unit cell, we place two hydrogen atoms: one at the origin +# (0.0, 0.0, 0.0) and the other at (0.0, 0.0, 0.75), corresponding to a bond length of +# 0.75 Å. We further specify a k-point mesh of [1, 1, 3], which represents the number of +# k-points sampled in each spatial direction for the periodic Brillouin zone. Finally, we +# construct a Lattice object from the libDMET library, associating it with the defined cell +# and k-mesh, which allows for the use of DMET in studying the properties of the hydrogen +# chain system. +import numpy as np +from pyscf.pbc import gto, df, scf, tools +from libdmet.system import lattice + +cell = gto.Cell() +cell.a = ''' 10.0 0.0 0.0 + 0.0 10.0 0.0 + 0.0 0.0 1.5 ''' +cell.atom = ''' H 0.0 0.0 0.0 + H 0.0 0.0 0.75 ''' +cell.basis = '321g' +cell.build(unit='Angstrom') + +kmesh = [1, 1, 3] +Lat = lattice.Lattice(cell, kmesh) +filling = cell.nelectron / (Lat.nscsites*2.0) +kpts = Lat.kpts +# +###################################################################### +# Now we have a description of our system and can start obtaining the fragment and bath orbitals. +# +# Constructing the bath orbitals +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# We perform a mean-field calculation on the whole system through Hartree-Fock with density +# fitted integrals using PySCF. +gdf = df.GDF(cell, kpts) +gdf._cderi_to_save = 'gdf_ints.h5' +gdf.build() + +kmf = scf.KRHF(cell, kpts, exxdiv=None).density_fit() +kmf.with_df = gdf +kmf.with_df._cderi = 'gdf_ints.h5' +kmf.conv_tol = 1e-12 +kmf.max_cycle = 200 +kmf.kernel() + +###################################################################### +# In quantum chemistry calculations, we can choose the bath and impurity by looking at the +# labels of orbitals. With this code, we can get the orbitals and separate the valence and +# virtual labels for each atom in the unit cell as shown below. This information helps us +# identify the orbitals to be included in the impurity, bath and unentangled environment. +# In this example, we choose to keep all the valence orbitals in the unit cell in the +# impurity, while the bath contains the virtual orbitals, and the orbitals belonging to the +# rest of the supercell becomes part of the unentangled environment. +from libdmet.lo.iao import reference_mol, get_labels, get_idx + +# aoind = cell.aoslice_by_atom() +# ao_labels = cell.ao_labels() + +labels, val_labels, virt_labels = get_labels(cell, minao="MINAO") + +ncore = 0 +nval = len(val_labels) +nvirt = len(virt_labels) + +Lat.set_val_virt_core(nval, nvirt, ncore) +print(labels, nval, nvirt) + +###################################################################### +# Further, we rotate the integrals into the embedding basis and obtain the rotated Hamiltonian + +from libdmet.basis_transform import make_basis + +C_ao_iao, C_ao_iao_val, C_ao_iao_virt, lo_labels = make_basis.get_C_ao_lo_iao(Lat, kmf, minao="MINAO", full_return=True, return_labels=True) +C_ao_lo = Lat.symmetrize_lo(C_ao_iao) + + +Lat.set_Ham(kmf, gdf, C_ao_lo, eri_symmetry=4) + +###################################################################### +# Self-consistent DMET +# ^^^^^^^^^^^^^^^^^^^^ +# Now that we have a description of our fragment and bath orbitals, we can implement DMET +# self-consistently. We implement each step of the process in a function and then iteratively +# call this functions in a loop to perform the calculations. +# +def mean_field(): + rho, Mu, res = dmet.HartreeFock(Lat, vcor, filling, mu, + beta=beta, ires=True, labels=lo_labels) + + return rho, Mu, res \ No newline at end of file From 2597e1b694a503dfed1f4b020d330d7eaef28cd7 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan Date: Tue, 18 Mar 2025 14:55:31 -0400 Subject: [PATCH 04/14] Added functions --- demonstrations/tutorial_dmet_embedding.py | 106 ++++++++++++++++++---- 1 file changed, 90 insertions(+), 16 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index 1940a7186f..567ac234a5 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -84,12 +84,9 @@ # identify the orbitals to be included in the impurity, bath and unentangled environment. # In this example, we choose to keep all the valence orbitals in the unit cell in the # impurity, while the bath contains the virtual orbitals, and the orbitals belonging to the -# rest of the supercell becomes part of the unentangled environment. +# rest of the supercell become part of the unentangled environment. from libdmet.lo.iao import reference_mol, get_labels, get_idx -# aoind = cell.aoslice_by_atom() -# ao_labels = cell.ao_labels() - labels, val_labels, virt_labels = get_labels(cell, minao="MINAO") ncore = 0 @@ -98,7 +95,6 @@ Lat.set_val_virt_core(nval, nvirt, ncore) print(labels, nval, nvirt) - ###################################################################### # Further, we rotate the integrals into the embedding basis and obtain the rotated Hamiltonian @@ -106,19 +102,97 @@ C_ao_iao, C_ao_iao_val, C_ao_iao_virt, lo_labels = make_basis.get_C_ao_lo_iao(Lat, kmf, minao="MINAO", full_return=True, return_labels=True) C_ao_lo = Lat.symmetrize_lo(C_ao_iao) - - Lat.set_Ham(kmf, gdf, C_ao_lo, eri_symmetry=4) ###################################################################### -# Self-consistent DMET +# DMET # ^^^^^^^^^^^^^^^^^^^^ -# Now that we have a description of our fragment and bath orbitals, we can implement DMET -# self-consistently. We implement each step of the process in a function and then iteratively -# call this functions in a loop to perform the calculations. -# -def mean_field(): - rho, Mu, res = dmet.HartreeFock(Lat, vcor, filling, mu, - beta=beta, ires=True, labels=lo_labels) +# Now that we have a description of our fragment and bath orbitals, we can implement DMET. +# We implement each step of the process in a function and +# then call these functions to perform the calculations. This can be done once for one iteration, +# referred to as single-shot DMET or we can call them iteratively to perform self-consistent DMET. +# Let's start by constructing the impurity Hamiltonian, +def construct_impurity_hamiltonian(Lat, vcor, filling, mu, last_dmu, int_bath=True): + + rho, mu, res = dmet.HartreeFock(Lat, vcor, filling, mu, + ires=True, labels=lo_labels) + + ImpHam, H1e, basis = dmet.ConstructImpHam(Lat, rho, vcor, int_bath=int_bath) + ImpHam = dmet.apply_dmu(Lat, ImpHam, basis, last_dmu) + + return rho, mu, res, ImpHam, basis + +# Next, we solve this impurity Hamiltonian with a high-level method, the following function defines +# the electronic structure solver for the impurity, provides an initial point for the calculation and +# passes the Lattice information to the solver. +def solve_impurity_hamiltonian(Lat, cell, basis, ImpHam, last_dmu, res): + + solver = dmet.impurity_solver.FCI(restricted=True, tol=1e-13) + basis_k = Lat.R2k_basis(basis) + + solver_args = {"nelec": min((Lat.ncore+Lat.nval)*2, Lat.nkpts*cell.nelectron), \ + "dm0": dmet.foldRho_k(res["rho_k"], basis_k)} + + rhoEmb, EnergyEmb, ImpHam, dmu = dmet.SolveImpHam_with_fitting(Lat, filling, + ImpHam, basis, solver, solver_args=solver_args) + + last_dmu += dmu + return rhoEmb, EnergyEmb, ImpHam, last_dmu, [solver, solver_args] + +# We can now calculate the properties for our embedded system through this embedding density matrix. Final step +# in single-shot DMET is to include the effect of environment in the final expectation value, so we define a +# function for the same which returns the density matrix and energy for the whole/embedded system +def solve_full_system(Lat, rhoEmb, EnergyEmb, basis, ImpHam, last_dmu, solver_info, lo_labels): + rhoImp, EnergyImp, nelecImp = \ + dmet.transformResults(rhoEmb, EnergyEmb, basis, ImpHam, \ + lattice=Lat, last_dmu=last_dmu, int_bath=True, \ + solver=solver_info[0], solver_args=solver_info[1], labels=lo_labels) + return rhoImp, EnergyImp + +# We must note here that the effect of environment included in the previous step is +# at the meanfield level. We can look at a more advanced version of DMET and improve this interaction +# with the use of self-consistency, referred to +# as self-consistent DMET, where a correlation potential is introduced to account for the interactions +# between the impurity and its environment. We start with an initial guess of zero for this correlation +# potential and optimize it by minimizing the difference between density matrices obtained from the +# mean-field Hamiltonian and the impurity Hamiltonian. Now, we initialize the correlation potential +# and define a function to optimize it. +import libdmet.dmet.Hubbard as dmet +vcor = dmet.VcorLocal(restricted=True, bogoliubov=False, nscsites=Lat.nscsites) +z_mat = np.zeros((2, Lat.nscsites, Lat.nscsites)) +vcor.assign(z_mat) +def fit_correlation_potential(rhoEmb, Lat, basis, vcor): + vcor_new, err = dmet.FitVcor(rhoEmb, Lat, basis, \ + vcor, beta=np.inf, filling=filling, MaxIter1=300, MaxIter2=0) + + dVcor_per_ele = np.max(np.abs(vcor_new.param - vcor.param)) + vcor.update(vcor_new.param) + return vcor, dVcor_per_ele + +# Now, we have defined all the ingredients of DMET, we can set up the self-consistency loop to get +# the full execution. We set up this loop by defining the maximum number of iterations and a convergence +# criteria. Here, we are using both energy and correlation potential as our convergence parameters, so we +# define the initial values and convergence tolerance for both. + +maxIter = 10 +E_old = 0.0 +dVcor_per_ele = None +u_tol = 1.0e-5 +E_tol = 1.0e-5 +mu = 0 +last_dmu = 0.0 +for i in range(maxIter): + rho, mu, res, ImpHam, basis = construct_impurity_hamiltonian(Lat, vcor, filling, mu, last_dmu) + rhoEmb, EnergyEmb, ImpHam, last_dmu, solver_info = solve_impurity_hamiltonian(Lat, cell, basis, ImpHam, last_dmu, res) + rhoImp, EnergyImp = solve_full_system(Lat, rhoEmb, EnergyEmb, basis, ImpHam, last_dmu, solver_info, lo_labels) + vcor, dVcor_per_ele = fit_correlation_potential(rhoEmb, Lat, basis, vcor) + + dE = EnergyImp - E_old + E_old = EnergyImp + if dVcor_per_ele < u_tol and abs(dE) < E_tol: + print("DMET Converged") + print("DMET Energy per cell: ", EnergyImp*Lat.nscsites/1) + break + + - return rho, Mu, res \ No newline at end of file From a49ac9bcc789f30256d34c64bef63fc06fe2139a Mon Sep 17 00:00:00 2001 From: Diksha Dhawan Date: Wed, 19 Mar 2025 14:22:17 -0400 Subject: [PATCH 05/14] Added Theory --- demonstrations/tutorial_dmet_embedding.py | 71 ++++++++++++++++++++--- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index 567ac234a5..bc4a8e1cf0 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -24,6 +24,32 @@ ###################################################################### # Theory # ------ +# DMET is a wavefunction based embedding approach, which uses density matrices for combining the low-level description +# of the environment with a high-level description of the impurity. The core of DMET relies on the Schmidt decomposition, +# which allows us to analyze the degree of entanglement between the impurity and its environment. Suppose we have a system +# partitioned into impurity and the environment, the state, :math:`\ket{\Psi}` of such a system can be +# represented as the tensor product of the Hilbert space of the two subsytems +# .. math:: +# +# \ket{\Psi} = \sum_{ij}\psi_{ij}\ket{i}_{imp}\ket{j}_{env} +# +# Schmidt decomposition of the coefficient tensor, :math:`\psi_{ij}`, thus allows us to identify the states +# in the environment which have overlap with the impurity. This helps reduce the size of the Hilbert space of the +# environment to be equal to the size of the impurity, and thus define a set of states referred to as bath. We are +# then able to project the full Hamiltonian to the space of impurity and bath states, known as embedding space. +# .. math:: +# +# \hat{H}^{imp} = \hat{P} \hat{H}^{sys}\hat{P} +# +# We must note here that the Schmidt decomposition requires apriori knowledge of the wavefunction. DMET, therefore, +# operates through a systematic iterative approach, starting with a meanfield description of the wavefunction and +# refining it through feedback from solution of impurity Hamiltonian. +# +# The DMET procedure starts by getting an approximate description of the system, which is used to partition the system +# into impurity and bath. We are then able to project the original Hamiltonian to this embedded space and +# solve it using a highly accurate method. This high-level description of impurity is then used to +# embed the updated correlation back into the full system, thus improving the initial approximation +# self-consistently. Let's take a look at the implementation of these steps. # ###################################################################### # Implementation @@ -62,7 +88,7 @@ ###################################################################### # Now we have a description of our system and can start obtaining the fragment and bath orbitals. # -# Constructing the bath orbitals +# Meanfield Calculation # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # We perform a mean-field calculation on the whole system through Hartree-Fock with density # fitted integrals using PySCF. @@ -85,7 +111,7 @@ # In this example, we choose to keep all the valence orbitals in the unit cell in the # impurity, while the bath contains the virtual orbitals, and the orbitals belonging to the # rest of the supercell become part of the unentangled environment. -from libdmet.lo.iao import reference_mol, get_labels, get_idx +from libdmet.lo.iao import get_labels labels, val_labels, virt_labels = get_labels(cell, minao="MINAO") @@ -96,7 +122,7 @@ Lat.set_val_virt_core(nval, nvirt, ncore) print(labels, nval, nvirt) ###################################################################### -# Further, we rotate the integrals into the embedding basis and obtain the rotated Hamiltonian +# Further, we rotate the integrals into a localized basis and obtain the rotated Hamiltonian from libdmet.basis_transform import make_basis @@ -111,7 +137,7 @@ # We implement each step of the process in a function and # then call these functions to perform the calculations. This can be done once for one iteration, # referred to as single-shot DMET or we can call them iteratively to perform self-consistent DMET. -# Let's start by constructing the impurity Hamiltonian, +# Let's start by constructing the impurity Hamiltonian def construct_impurity_hamiltonian(Lat, vcor, filling, mu, last_dmu, int_bath=True): rho, mu, res = dmet.HartreeFock(Lat, vcor, filling, mu, @@ -155,7 +181,7 @@ def solve_full_system(Lat, rhoEmb, EnergyEmb, basis, ImpHam, last_dmu, solver_in # as self-consistent DMET, where a correlation potential is introduced to account for the interactions # between the impurity and its environment. We start with an initial guess of zero for this correlation # potential and optimize it by minimizing the difference between density matrices obtained from the -# mean-field Hamiltonian and the impurity Hamiltonian. Now, we initialize the correlation potential +# mean-field Hamiltonian and the impurity Hamiltonian. Let's initialize the correlation potential # and define a function to optimize it. import libdmet.dmet.Hubbard as dmet vcor = dmet.VcorLocal(restricted=True, bogoliubov=False, nscsites=Lat.nscsites) @@ -173,7 +199,6 @@ def fit_correlation_potential(rhoEmb, Lat, basis, vcor): # the full execution. We set up this loop by defining the maximum number of iterations and a convergence # criteria. Here, we are using both energy and correlation potential as our convergence parameters, so we # define the initial values and convergence tolerance for both. - maxIter = 10 E_old = 0.0 dVcor_per_ele = None @@ -194,5 +219,35 @@ def fit_correlation_potential(rhoEmb, Lat, basis, vcor): print("DMET Energy per cell: ", EnergyImp*Lat.nscsites/1) break - - +# This concludes the DMET procedure. At this point, we should note that we are still limited by the number +# of orbitals we can have in the impurity because the cost of using a high-level solver such as FCI increases +# exponentially with increase in system size. One way to solve this problem could be through the use of +# quantum computing algorithm as solver. Next, we see how we can convert this impurity Hamiltonian to a +# qubit Hamiltonian through PennyLane to pave the path for using it with quantum algorithms. +# The ImpHam object generated above provides us with one-body and two-body integrals along with the +# nuclear repulsion energy which can be accessed as follows: +norb = ImpHam.norb +H1 = ImpHam.H1["cd"] +H2 = ImpHam.H2["ccdd"][0] + +# The two-body integrals here are saved in a two-dimensional array with a 4-fold permutation symmetry. +# We can convert this to a 4 dimensional array by using the ao2mo routine in PySCF [add reference] and +# further to physicist notation using numpy. These one-body and two-body integrals can then be used to +# generate the qubit Hamiltonian for PennyLane. +from pyscf import ao2mo +import pennylane as qml +from pennylane.qchem import one_particle, two_particle, observable + +H2 = ao2mo.restore(1, H2, norb) + +t = one_particle(H1[0]) +v = two_particle(np.swapaxes(H2, 1, 3)) # Swap to physicist's notation +qubit_op = observable([t,v], mapping="jordan_wigner") +eigval_qubit = qml.eigvals(qml.SparseHamiltonian(qubit_op.sparse_matrix(), wires = qubit_op.wires)) +print("eigenvalue from PennyLane: ", eigval_qubit) +print("embedding energy: ", EnergyEmb) + +# We obtained the qubit Hamiltonian for embedded system here and diagonalized it to get the eigenvalues, +# and show that this eigenvalue matches the energy we obtained for the embedded system above. +# We can also get ground state energy for the system from this value +# by solving for the full system as done above in the self-consistency loop using solve_full_system function. \ No newline at end of file From c41987a59059cd9e8115bff81628645e5ed0b75e Mon Sep 17 00:00:00 2001 From: Diksha Dhawan Date: Thu, 20 Mar 2025 11:15:28 -0400 Subject: [PATCH 06/14] Addressed comments --- demonstrations/tutorial_dmet_embedding.py | 36 ++++++++++++----------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index bc4a8e1cf0..99fb92c185 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -25,7 +25,7 @@ # Theory # ------ # DMET is a wavefunction based embedding approach, which uses density matrices for combining the low-level description -# of the environment with a high-level description of the impurity. The core of DMET relies on the Schmidt decomposition, +# of the environment with a high-level description of the impurity. DMET relies on Schmidt decomposition, # which allows us to analyze the degree of entanglement between the impurity and its environment. Suppose we have a system # partitioned into impurity and the environment, the state, :math:`\ket{\Psi}` of such a system can be # represented as the tensor product of the Hilbert space of the two subsytems @@ -40,7 +40,8 @@ # .. math:: # # \hat{H}^{imp} = \hat{P} \hat{H}^{sys}\hat{P} -# +# +# where P is the projection operator. # We must note here that the Schmidt decomposition requires apriori knowledge of the wavefunction. DMET, therefore, # operates through a systematic iterative approach, starting with a meanfield description of the wavefunction and # refining it through feedback from solution of impurity Hamiltonian. @@ -84,12 +85,8 @@ Lat = lattice.Lattice(cell, kmesh) filling = cell.nelectron / (Lat.nscsites*2.0) kpts = Lat.kpts -# + ###################################################################### -# Now we have a description of our system and can start obtaining the fragment and bath orbitals. -# -# Meanfield Calculation -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # We perform a mean-field calculation on the whole system through Hartree-Fock with density # fitted integrals using PySCF. gdf = df.GDF(cell, kpts) @@ -103,6 +100,19 @@ kmf.max_cycle = 200 kmf.kernel() +# Localization and Paritioning of Orbital Space +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# Now we have a description of our system and can start obtaining the fragment and bath orbitals. +# This requires the localization of the basis of orbitals, we could use any localized basis here, +# for example, molecular orbitals(MO), intrinsic atomic orbitals(IAO), etc. Here, we +# rotate the one-electron and two-electron integrals into IAO basis. + +from libdmet.basis_transform import make_basis + +C_ao_iao, C_ao_iao_val, C_ao_iao_virt, lo_labels = make_basis.get_C_ao_lo_iao(Lat, kmf, minao="MINAO", full_return=True, return_labels=True) +C_ao_lo = Lat.symmetrize_lo(C_ao_iao) +Lat.set_Ham(kmf, gdf, C_ao_lo, eri_symmetry=4) + ###################################################################### # In quantum chemistry calculations, we can choose the bath and impurity by looking at the # labels of orbitals. With this code, we can get the orbitals and separate the valence and @@ -121,23 +131,15 @@ Lat.set_val_virt_core(nval, nvirt, ncore) print(labels, nval, nvirt) -###################################################################### -# Further, we rotate the integrals into a localized basis and obtain the rotated Hamiltonian - -from libdmet.basis_transform import make_basis - -C_ao_iao, C_ao_iao_val, C_ao_iao_virt, lo_labels = make_basis.get_C_ao_lo_iao(Lat, kmf, minao="MINAO", full_return=True, return_labels=True) -C_ao_lo = Lat.symmetrize_lo(C_ao_iao) -Lat.set_Ham(kmf, gdf, C_ao_lo, eri_symmetry=4) ###################################################################### -# DMET +# Self-Consistent DMET # ^^^^^^^^^^^^^^^^^^^^ # Now that we have a description of our fragment and bath orbitals, we can implement DMET. # We implement each step of the process in a function and # then call these functions to perform the calculations. This can be done once for one iteration, # referred to as single-shot DMET or we can call them iteratively to perform self-consistent DMET. -# Let's start by constructing the impurity Hamiltonian +# Let's start by constructing the impurity Hamiltonian, def construct_impurity_hamiltonian(Lat, vcor, filling, mu, last_dmu, int_bath=True): rho, mu, res = dmet.HartreeFock(Lat, vcor, filling, mu, From 9e492fe769f5781c3fb5a6889833687099460d52 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Tue, 25 Mar 2025 14:35:57 -0400 Subject: [PATCH 07/14] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: Soran Jahangiri <40344468+soranjh@users.noreply.github.com> --- demonstrations/tutorial_dmet_embedding.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index 99fb92c185..d473180ee8 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -5,7 +5,9 @@ the current workhorse in this field due to its balance between accuracy and computational efficiency, it often falls short in accurately capturing the intricate electron correlation effects found in strongly correlated materials. As a result, researchers often turn to more sophisticated methods, such as full configuration interaction or coupled cluster theory, -which provide better accuracy but come at a significantly higher computational cost. Embedding theories provide a balanced +which provide better accuracy but come at a significantly higher computational cost. + +Embedding theories provide a balanced midpoint solution that enhances our ability to simulate materials accurately and efficiently. The core idea behind embedding is to treat the strongly correlated subsystem accurately using high-level quantum mechanical methods while approximating the effects of the surrounding environment in a way that retains computational efficiency. From 34c65272c817573f4906934df3f1361348fcda26 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Tue, 25 Mar 2025 14:36:41 -0400 Subject: [PATCH 08/14] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: Soran Jahangiri <40344468+soranjh@users.noreply.github.com> --- demonstrations/tutorial_dmet_embedding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index d473180ee8..52ebd990b6 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -11,7 +11,7 @@ midpoint solution that enhances our ability to simulate materials accurately and efficiently. The core idea behind embedding is to treat the strongly correlated subsystem accurately using high-level quantum mechanical methods while approximating the effects of the surrounding environment in a way that retains computational efficiency. -Density matrix embedding theory(DMET) is one such efficient wave-function-based embedding approach to treat strongly +Density matrix embedding theory (DMET) is an efficient wave-function-based embedding approach to treat strongly correlated systems. Here, we present a demonstration of how to run DMET calculations through an existing library called libDMET, along with the intructions on how we can use the generated Hamiltonian with PennyLane to use it with quantum computing algorithms. We begin by providing a high-level introduction to DMET, followed by a tutorial on how to set up From dd6550caee9883b01c153aa3e7813f09eca3082e Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Tue, 25 Mar 2025 14:36:52 -0400 Subject: [PATCH 09/14] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: Soran Jahangiri <40344468+soranjh@users.noreply.github.com> --- demonstrations/tutorial_dmet_embedding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index 52ebd990b6..77ddf9d46d 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -13,7 +13,7 @@ the effects of the surrounding environment in a way that retains computational efficiency. Density matrix embedding theory (DMET) is an efficient wave-function-based embedding approach to treat strongly correlated systems. Here, we present a demonstration of how to run DMET calculations through an existing library called -libDMET, along with the intructions on how we can use the generated Hamiltonian with PennyLane to use it with quantum +libDMET, along with the instructions on how we can use the generated DMET Hamiltonian with PennyLane to use it with quantum computing algorithms. We begin by providing a high-level introduction to DMET, followed by a tutorial on how to set up a DMET calculation. From 18cddf357ba11c1c102ea59b7435d70799bd6e97 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Tue, 25 Mar 2025 14:38:10 -0400 Subject: [PATCH 10/14] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: Soran Jahangiri <40344468+soranjh@users.noreply.github.com> --- demonstrations/tutorial_dmet_embedding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index 77ddf9d46d..9264177f9b 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -61,7 +61,7 @@ # # Constructing the system # ^^^^^^^^^^^^^^^^^^^^^^^ -# We begin by defining a periodic system using the PySCF interface to create a cell object +# We begin by defining a periodic system using PySCF to create a cell object # representing a hydrogen chain with 6 atoms. The lattice vectors are specified to define the # geometry of the unit cell, within this unit cell, we place two hydrogen atoms: one at the origin # (0.0, 0.0, 0.0) and the other at (0.0, 0.0, 0.75), corresponding to a bond length of From e6fc371f01a58a8d431d623ab1161193dc6664f0 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan Date: Thu, 27 Mar 2025 12:15:59 -0400 Subject: [PATCH 11/14] Addressed comments --- demonstrations/tutorial_dmet_embedding.py | 253 ++++++++++++---------- 1 file changed, 136 insertions(+), 117 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index 9264177f9b..4f6552b16c 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -9,8 +9,8 @@ Embedding theories provide a balanced midpoint solution that enhances our ability to simulate materials accurately and efficiently. The core idea behind embedding -is to treat the strongly correlated subsystem accurately using high-level quantum mechanical methods while approximating -the effects of the surrounding environment in a way that retains computational efficiency. +is that the system is divided into two parts: impurity, strongly correlated subsystem that requires an exact description, and +its environment, which can be treated with an approximate but computationally efficient method. Density matrix embedding theory (DMET) is an efficient wave-function-based embedding approach to treat strongly correlated systems. Here, we present a demonstration of how to run DMET calculations through an existing library called libDMET, along with the instructions on how we can use the generated DMET Hamiltonian with PennyLane to use it with quantum @@ -28,15 +28,11 @@ # ------ # DMET is a wavefunction based embedding approach, which uses density matrices for combining the low-level description # of the environment with a high-level description of the impurity. DMET relies on Schmidt decomposition, -# which allows us to analyze the degree of entanglement between the impurity and its environment. Suppose we have a system -# partitioned into impurity and the environment, the state, :math:`\ket{\Psi}` of such a system can be -# represented as the tensor product of the Hilbert space of the two subsytems -# .. math:: -# -# \ket{\Psi} = \sum_{ij}\psi_{ij}\ket{i}_{imp}\ket{j}_{env} -# -# Schmidt decomposition of the coefficient tensor, :math:`\psi_{ij}`, thus allows us to identify the states -# in the environment which have overlap with the impurity. This helps reduce the size of the Hilbert space of the +# which allows us to analyze the degree of entanglement between the two subsystems. The state, :math:`\ket{\Psi}` of +# the partitioned system can be represented as the tensor product of the Hilbert space of the two subsystems. +# Singular value decomposition (SVD) of the coefficient tensor, :math:`\psi_{ij}`, of this tensor product +# thus allows us to identify the states +# in the environment which have overlap with the impurity. This helps truncate the size of the Hilbert space of the # environment to be equal to the size of the impurity, and thus define a set of states referred to as bath. We are # then able to project the full Hamiltonian to the space of impurity and bath states, known as embedding space. # .. math:: @@ -61,15 +57,11 @@ # # Constructing the system # ^^^^^^^^^^^^^^^^^^^^^^^ -# We begin by defining a periodic system using PySCF to create a cell object -# representing a hydrogen chain with 6 atoms. The lattice vectors are specified to define the -# geometry of the unit cell, within this unit cell, we place two hydrogen atoms: one at the origin -# (0.0, 0.0, 0.0) and the other at (0.0, 0.0, 0.75), corresponding to a bond length of -# 0.75 Å. We further specify a k-point mesh of [1, 1, 3], which represents the number of -# k-points sampled in each spatial direction for the periodic Brillouin zone. Finally, we -# construct a Lattice object from the libDMET library, associating it with the defined cell -# and k-mesh, which allows for the use of DMET in studying the properties of the hydrogen -# chain system. +# We begin by defining a periodic system using PySCF [#pyscf]_ to create a cell object +# representing a hydrogen chain with 6 atoms. Each unit cell contains two Hydrogen atoms at a bond +# distance of 0.75 Å. Finally, we construct a Lattice object from the libDMET library, associating it with +# the defined cell and k-mesh, which allows for the use of DMET in studying the properties of +# the hydrogen chain system. import numpy as np from pyscf.pbc import gto, df, scf, tools from libdmet.system import lattice @@ -77,150 +69,158 @@ cell = gto.Cell() cell.a = ''' 10.0 0.0 0.0 0.0 10.0 0.0 - 0.0 0.0 1.5 ''' + 0.0 0.0 1.5 ''' # lattice vectors for unit cell cell.atom = ''' H 0.0 0.0 0.0 - H 0.0 0.0 0.75 ''' + H 0.0 0.0 0.75 ''' # coordinates of atoms in unit cell cell.basis = '321g' cell.build(unit='Angstrom') -kmesh = [1, 1, 3] -Lat = lattice.Lattice(cell, kmesh) -filling = cell.nelectron / (Lat.nscsites*2.0) -kpts = Lat.kpts +kmesh = [1, 1, 3] # number of k-points in xyz direction +lat = lattice.Lattice(cell, kmesh) +filling = cell.nelectron / (lat.nscsites*2.0) +kpts = lat.kpts ###################################################################### # We perform a mean-field calculation on the whole system through Hartree-Fock with density # fitted integrals using PySCF. gdf = df.GDF(cell, kpts) -gdf._cderi_to_save = 'gdf_ints.h5' -gdf.build() +gdf._cderi_to_save = 'gdf_ints.h5' #output file for density fitted integral tensor +gdf.build() #compute the density fitted integrals kmf = scf.KRHF(cell, kpts, exxdiv=None).density_fit() -kmf.with_df = gdf -kmf.with_df._cderi = 'gdf_ints.h5' -kmf.conv_tol = 1e-12 -kmf.max_cycle = 200 -kmf.kernel() +kmf.with_df = gdf #use density-fitted integrals +kmf.with_df._cderi = 'gdf_ints.h5' #input file for density fitted integrals +kmf.kernel() #run Hartree-Fock -# Localization and Paritioning of Orbital Space +# Paritioning of Orbital Space # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -# Now we have a description of our system and can start obtaining the fragment and bath orbitals. +# Now we have a description of our system and can start obtaining the impurity and bath orbitals. # This requires the localization of the basis of orbitals, we could use any localized basis here, -# for example, molecular orbitals(MO), intrinsic atomic orbitals(IAO), etc. Here, we +# for example, molecular orbitals(MO), intrinsic atomic orbitals(IAO), etc [#SWouters]_. The use of +# localized basis here provides a mathematically convenient way to understand the contribution of +# each atom to properties of the full system. Here, we # rotate the one-electron and two-electron integrals into IAO basis. from libdmet.basis_transform import make_basis -C_ao_iao, C_ao_iao_val, C_ao_iao_virt, lo_labels = make_basis.get_C_ao_lo_iao(Lat, kmf, minao="MINAO", full_return=True, return_labels=True) -C_ao_lo = Lat.symmetrize_lo(C_ao_iao) -Lat.set_Ham(kmf, gdf, C_ao_lo, eri_symmetry=4) +c_ao_iao, _, _, lo_labels = make_basis.get_C_ao_lo_iao(lat, kmf, minao="MINAO", full_return=True, return_labels=True) +c_ao_lo = lat.symmetrize_lo(c_ao_iao) +lat.set_Ham(kmf, gdf, c_ao_lo, eri_symmetry=4) #rotate integral tensors to IAO basis ###################################################################### -# In quantum chemistry calculations, we can choose the bath and impurity by looking at the -# labels of orbitals. With this code, we can get the orbitals and separate the valence and -# virtual labels for each atom in the unit cell as shown below. This information helps us -# identify the orbitals to be included in the impurity, bath and unentangled environment. -# In this example, we choose to keep all the valence orbitals in the unit cell in the -# impurity, while the bath contains the virtual orbitals, and the orbitals belonging to the -# rest of the supercell become part of the unentangled environment. +# In ab initio systems, we can choose the bath and impurity by looking at the +# labels of orbitals. We can get the orbitals for each atom in the unit cell by using +# aoslice_by_atom function. This information helps us identify the orbitals to be included +# in the impurity, bath and unentangled environment. +# In this example, we choose to keep the :math:`1s` orbitals in the unit cell in the +# impurity, while the bath contains the :math:`2s` orbitals, and the orbitals belonging to the +# rest of the supercell become part of the unentangled environment. These can be separated by +# getting the valence and virtual labels from get_labels function. from libdmet.lo.iao import get_labels +aoind = cell.aoslice_by_atom() labels, val_labels, virt_labels = get_labels(cell, minao="MINAO") - ncore = 0 -nval = len(val_labels) -nvirt = len(virt_labels) - -Lat.set_val_virt_core(nval, nvirt, ncore) -print(labels, nval, nvirt) +lat.set_val_virt_core(len(val_labels), len(virt_labels), ncore) +print("Valence orbitals: ", val_labels) +print("Virtual orbitals: ", virt_labels) ###################################################################### # Self-Consistent DMET # ^^^^^^^^^^^^^^^^^^^^ -# Now that we have a description of our fragment and bath orbitals, we can implement DMET. +# Now that we have a description of our impurity and bath orbitals, we can implement DMET. # We implement each step of the process in a function and # then call these functions to perform the calculations. This can be done once for one iteration, # referred to as single-shot DMET or we can call them iteratively to perform self-consistent DMET. # Let's start by constructing the impurity Hamiltonian, -def construct_impurity_hamiltonian(Lat, vcor, filling, mu, last_dmu, int_bath=True): +def construct_impurity_hamiltonian(lat, v_cor, filling, mu, last_dmu, int_bath=True): - rho, mu, res = dmet.HartreeFock(Lat, vcor, filling, mu, + rho, mu, scf_result = dmet.HartreeFock(lat, v_cor, filling, mu, ires=True, labels=lo_labels) - - ImpHam, H1e, basis = dmet.ConstructImpHam(Lat, rho, vcor, int_bath=int_bath) - ImpHam = dmet.apply_dmu(Lat, ImpHam, basis, last_dmu) + imp_ham, _, basis = dmet.ConstructImpHam(lat, rho, v_cor, int_bath=int_bath) + imp_ham = dmet.apply_dmu(lat, imp_ham, basis, last_dmu) - return rho, mu, res, ImpHam, basis + return rho, mu, scf_result, imp_ham, basis # Next, we solve this impurity Hamiltonian with a high-level method, the following function defines # the electronic structure solver for the impurity, provides an initial point for the calculation and -# passes the Lattice information to the solver. -def solve_impurity_hamiltonian(Lat, cell, basis, ImpHam, last_dmu, res): +# passes the Lattice information to the solver. The solver then calculates the energy and density matrix +# for the impurity. +def solve_impurity_hamiltonian(lat, cell, basis, imp_ham, last_dmu, scf_result): solver = dmet.impurity_solver.FCI(restricted=True, tol=1e-13) - basis_k = Lat.R2k_basis(basis) + basis_k = lat.R2k_basis(basis) #basis in k-space - solver_args = {"nelec": min((Lat.ncore+Lat.nval)*2, Lat.nkpts*cell.nelectron), \ - "dm0": dmet.foldRho_k(res["rho_k"], basis_k)} + solver_args = {"nelec": min((lat.ncore+lat.nval)*2, lat.nkpts*cell.nelectron), \ + "dm0": dmet.foldRho_k(scf_result["rho_k"], basis_k)} - rhoEmb, EnergyEmb, ImpHam, dmu = dmet.SolveImpHam_with_fitting(Lat, filling, - ImpHam, basis, solver, solver_args=solver_args) + rho_emb, energy_emb, imp_ham, dmu = dmet.SolveImpHam_with_fitting(lat, filling, + imp_ham, basis, solver, solver_args=solver_args) last_dmu += dmu - return rhoEmb, EnergyEmb, ImpHam, last_dmu, [solver, solver_args] + return rho_emb, energy_emb, imp_ham, last_dmu, [solver, solver_args] -# We can now calculate the properties for our embedded system through this embedding density matrix. Final step -# in single-shot DMET is to include the effect of environment in the final expectation value, so we define a -# function for the same which returns the density matrix and energy for the whole/embedded system -def solve_full_system(Lat, rhoEmb, EnergyEmb, basis, ImpHam, last_dmu, solver_info, lo_labels): - rhoImp, EnergyImp, nelecImp = \ - dmet.transformResults(rhoEmb, EnergyEmb, basis, ImpHam, \ - lattice=Lat, last_dmu=last_dmu, int_bath=True, \ +# Final step in single-shot DMET is to include the effect of environment in the final expectation value, +# so we define a function for the same which returns the density matrix and energy for the whole system. +def solve_full_system(lat, rho_emb, energy_emb, basis, imp_ham, last_dmu, solver_info, lo_labels): + rho_full, energy_full, nelec_full = \ + dmet.transformResults(rho_emb, energy_emb, basis, imp_ham, \ + lattice=lat, last_dmu=last_dmu, int_bath=True, \ solver=solver_info[0], solver_args=solver_info[1], labels=lo_labels) - return rhoImp, EnergyImp + energy_full *= lat.nscsites + return rho_full, energy_full # We must note here that the effect of environment included in the previous step is -# at the meanfield level. We can look at a more advanced version of DMET and improve this interaction -# with the use of self-consistency, referred to +# at the meanfield level, and will give the results for single-shot DMET. +# We can look at a more advanced version of DMET and improve this interaction +# with the use of self-consistency, referred to # as self-consistent DMET, where a correlation potential is introduced to account for the interactions # between the impurity and its environment. We start with an initial guess of zero for this correlation # potential and optimize it by minimizing the difference between density matrices obtained from the # mean-field Hamiltonian and the impurity Hamiltonian. Let's initialize the correlation potential # and define a function to optimize it. -import libdmet.dmet.Hubbard as dmet -vcor = dmet.VcorLocal(restricted=True, bogoliubov=False, nscsites=Lat.nscsites) -z_mat = np.zeros((2, Lat.nscsites, Lat.nscsites)) -vcor.assign(z_mat) -def fit_correlation_potential(rhoEmb, Lat, basis, vcor): - vcor_new, err = dmet.FitVcor(rhoEmb, Lat, basis, \ - vcor, beta=np.inf, filling=filling, MaxIter1=300, MaxIter2=0) +def initialize_vcor(lat): + v_cor = dmet.VcorLocal(restricted=True, bogoliubov=False, nscsites=lat.nscsites) + v_cor.assign(np.zeros((2, lat.nscsites, lat.nscsites))) + return v_cor - dVcor_per_ele = np.max(np.abs(vcor_new.param - vcor.param)) - vcor.update(vcor_new.param) - return vcor, dVcor_per_ele +def fit_correlation_potential(rho_emb, lat, basis, v_cor): + vcor_new, err = dmet.FitVcor(rho_emb, lat, basis, \ + v_cor, beta=np.inf, filling=filling, MaxIter1=300, MaxIter2=0) + + dVcor_per_ele = np.max(np.abs(vcor_new.param - v_cor.param)) + v_cor.update(vcor_new.param) + return v_cor, dVcor_per_ele # Now, we have defined all the ingredients of DMET, we can set up the self-consistency loop to get # the full execution. We set up this loop by defining the maximum number of iterations and a convergence # criteria. Here, we are using both energy and correlation potential as our convergence parameters, so we # define the initial values and convergence tolerance for both. -maxIter = 10 -E_old = 0.0 -dVcor_per_ele = None -u_tol = 1.0e-5 -E_tol = 1.0e-5 -mu = 0 -last_dmu = 0.0 -for i in range(maxIter): - rho, mu, res, ImpHam, basis = construct_impurity_hamiltonian(Lat, vcor, filling, mu, last_dmu) - rhoEmb, EnergyEmb, ImpHam, last_dmu, solver_info = solve_impurity_hamiltonian(Lat, cell, basis, ImpHam, last_dmu, res) - rhoImp, EnergyImp = solve_full_system(Lat, rhoEmb, EnergyEmb, basis, ImpHam, last_dmu, solver_info, lo_labels) - vcor, dVcor_per_ele = fit_correlation_potential(rhoEmb, Lat, basis, vcor) +import libdmet.dmet.Hubbard as dmet - dE = EnergyImp - E_old - E_old = EnergyImp - if dVcor_per_ele < u_tol and abs(dE) < E_tol: +max_iter = 10 # maximum number of iterations +e_old = 0.0 # initial value of energy +v_cor = initialize_vcor(lat) # initial value of correlation potential +dVcor_per_ele = None # initial value of correlation potential per electron +vcor_tol = 1.0e-5 # tolerance for correlation potential convergence +energy_tol = 1.0e-5 # tolerance for energy convergence +mu = 0 # initial chemical potential +last_dmu = 0.0 # change in chemical potential +for i in range(max_iter): + rho, mu, scf_result, imp_ham, basis = construct_impurity_hamiltonian(lat, + v_cor, filling, mu, last_dmu) # construct impurity Hamiltonian + rho_emb, energy_emb, imp_ham, last_dmu, solver_info = solve_impurity_hamiltonian(lat, cell, + basis, imp_ham, last_dmu, scf_result) # solve impurity Hamiltonian + rho_full, energy_full = solve_full_system(lat, rho_emb, energy_emb, basis, imp_ham, + last_dmu, solver_info, lo_labels) # include the environment interactions + v_cor, dVcor_per_ele = fit_correlation_potential(rho_emb, + lat, basis, v_cor) # fit correlation potential + + dE = energy_full - e_old + e_old = energy_full + if dVcor_per_ele < vcor_tol and abs(dE) < energy_tol: print("DMET Converged") - print("DMET Energy per cell: ", EnergyImp*Lat.nscsites/1) + print("DMET Energy per cell: ", energy_full) break # This concludes the DMET procedure. At this point, we should note that we are still limited by the number @@ -230,28 +230,47 @@ def fit_correlation_potential(rhoEmb, Lat, basis, vcor): # qubit Hamiltonian through PennyLane to pave the path for using it with quantum algorithms. # The ImpHam object generated above provides us with one-body and two-body integrals along with the # nuclear repulsion energy which can be accessed as follows: -norb = ImpHam.norb -H1 = ImpHam.H1["cd"] -H2 = ImpHam.H2["ccdd"][0] - -# The two-body integrals here are saved in a two-dimensional array with a 4-fold permutation symmetry. -# We can convert this to a 4 dimensional array by using the ao2mo routine in PySCF [add reference] and -# further to physicist notation using numpy. These one-body and two-body integrals can then be used to -# generate the qubit Hamiltonian for PennyLane. from pyscf import ao2mo +norb = imp_ham.norb +h1 = imp_ham.H1["cd"] +h2 = imp_ham.H2["ccdd"][0] +h2 = ao2mo.restore(1, h2, norb) # Get the correct shape based on permutation symmetry + +# These one-body and two-body integrals can then be used to generate the qubit Hamiltonian for PennyLane. import pennylane as qml from pennylane.qchem import one_particle, two_particle, observable -H2 = ao2mo.restore(1, H2, norb) - -t = one_particle(H1[0]) -v = two_particle(np.swapaxes(H2, 1, 3)) # Swap to physicist's notation +t = one_particle(h1[0]) +v = two_particle(np.swapaxes(h2, 1, 3)) # Swap to physicist's notation qubit_op = observable([t,v], mapping="jordan_wigner") eigval_qubit = qml.eigvals(qml.SparseHamiltonian(qubit_op.sparse_matrix(), wires = qubit_op.wires)) print("eigenvalue from PennyLane: ", eigval_qubit) -print("embedding energy: ", EnergyEmb) +print("embedding energy: ", energy_emb) # We obtained the qubit Hamiltonian for embedded system here and diagonalized it to get the eigenvalues, # and show that this eigenvalue matches the energy we obtained for the embedded system above. # We can also get ground state energy for the system from this value -# by solving for the full system as done above in the self-consistency loop using solve_full_system function. \ No newline at end of file +# by solving for the full system as done above in the self-consistency loop using solve_full_system function. + +###################################################################### +# Conclusion +# ^^^^^^^^^^^^^^ +# Density matrix embedding theory is a robust method, designed to tackle simulation of complex systems, +# by dividing them into subsystems. It is specifically suited for studying the ground state properties of +# a system. It provides for a computationally efficient alternative to dynamic quantum embedding schemes +# such as dynamic meanfield theory(DMFT), as it uses density matrix for embedding instead of the Green's function. +# It has been successfully used for studying various strongly correlated molecular and periodic systems. +# +# References +# ---------- +# +# .. [#SWouters] +# Sebastian Wouters, Carlos A. Jiménez-Hoyos, *et al.*, +# "A practical guide to density matrix embedding theory in quantum chemistry." +# `ArXiv `__. +# +# +# .. [#pyscf] +# Qiming Sun, Xing Zhang, *et al.*, "Recent developments in the PySCF program package." +# `ArXiv `__. +# \ No newline at end of file From bc15d92a2d8dde949ca74a2708159e20d14cc290 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan Date: Thu, 27 Mar 2025 13:29:33 -0400 Subject: [PATCH 12/14] Small fix --- demonstrations/tutorial_dmet_embedding.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index 4f6552b16c..5ecaea7e9b 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -258,7 +258,8 @@ def fit_correlation_potential(rho_emb, lat, basis, v_cor): # Density matrix embedding theory is a robust method, designed to tackle simulation of complex systems, # by dividing them into subsystems. It is specifically suited for studying the ground state properties of # a system. It provides for a computationally efficient alternative to dynamic quantum embedding schemes -# such as dynamic meanfield theory(DMFT), as it uses density matrix for embedding instead of the Green's function. +# such as dynamic meanfield theory(DMFT), as it uses density matrix for embedding instead of the Green's function +# and has limited number of bath orbitals. # It has been successfully used for studying various strongly correlated molecular and periodic systems. # # References From 25aa5655bebdd8c8f7064cb6fefc20d2c8509e6e Mon Sep 17 00:00:00 2001 From: soranjh Date: Tue, 29 Apr 2025 17:14:37 -0400 Subject: [PATCH 13/14] update theory --- demonstrations/tutorial_dmet_embedding.py | 74 ++++++++++++++--------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index 5ecaea7e9b..4b40e5b003 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -1,21 +1,21 @@ r"""Density Matrix Embedding Theory (DMET) ========================================= -Materials simulation presents a crucial challenge in quantum chemistry, as understanding and predicting the properties of -complex materials is essential for advancements in technology and science. While Density Functional Theory (DFT) is -the current workhorse in this field due to its balance between accuracy and computational efficiency, it often falls short in -accurately capturing the intricate electron correlation effects found in strongly correlated materials. As a result, -researchers often turn to more sophisticated methods, such as full configuration interaction or coupled cluster theory, -which provide better accuracy but come at a significantly higher computational cost. +Materials simulation presents a crucial challenge in quantum chemistry. Density Functional Theory +(DFT) is currently the workhorse for simulating materials due to its balance between accuracy and +computational efficiency. However, it often falls short in accurately capturing the intricate +electron correlation effects found in strongly correlated materials. As a result, researchers often +turn to more sophisticated methods, such as full configuration interaction or coupled cluster +theory, which provide better accuracy but come at a significantly higher computational cost. -Embedding theories provide a balanced -midpoint solution that enhances our ability to simulate materials accurately and efficiently. The core idea behind embedding -is that the system is divided into two parts: impurity, strongly correlated subsystem that requires an exact description, and -its environment, which can be treated with an approximate but computationally efficient method. -Density matrix embedding theory (DMET) is an efficient wave-function-based embedding approach to treat strongly -correlated systems. Here, we present a demonstration of how to run DMET calculations through an existing library called -libDMET, along with the instructions on how we can use the generated DMET Hamiltonian with PennyLane to use it with quantum -computing algorithms. We begin by providing a high-level introduction to DMET, followed by a tutorial on how to set up -a DMET calculation. +Embedding theories provide a balanced midpoint solution that enhances our ability to simulate +materials accurately and efficiently. The core idea behind embedding is that the system is divided + into two parts: an impurity which is a strongly correlated subsystem that requires exact +description and an environment which can be treated with approximate but computationally efficient +method. + +Density matrix embedding theory (DMET) is an efficient embedding approach to treat strongly +correlated systems. Here we provide a brief introduction of the method and demonstrate how to run +DMET calculations to construct a Hamiltonian that can be used in a quantum algorithm. .. figure:: ../_static/demo_thumbnails/opengraph_demo_thumbnails/OGthumbnail_how_to_build_spin_hamiltonians.png :align: center @@ -26,23 +26,41 @@ ###################################################################### # Theory # ------ -# DMET is a wavefunction based embedding approach, which uses density matrices for combining the low-level description -# of the environment with a high-level description of the impurity. DMET relies on Schmidt decomposition, -# which allows us to analyze the degree of entanglement between the two subsystems. The state, :math:`\ket{\Psi}` of -# the partitioned system can be represented as the tensor product of the Hilbert space of the two subsystems. -# Singular value decomposition (SVD) of the coefficient tensor, :math:`\psi_{ij}`, of this tensor product -# thus allows us to identify the states -# in the environment which have overlap with the impurity. This helps truncate the size of the Hilbert space of the -# environment to be equal to the size of the impurity, and thus define a set of states referred to as bath. We are -# then able to project the full Hamiltonian to the space of impurity and bath states, known as embedding space. +# The wave function for the embedded system composed of the impurity and the environment can be +# simply represented as +# +# .. math:: +# +# | \Psi \rangle = \sum_i^{N_I} \sum_j^{N_E} \Psi_{ij} | I_i \rangle | E_j \rangle, +# +# where :math:`I_i` and :math:`E_j` are basis states of the impurity :math:`I` and environment +# :math:`E`, respectively, :math:`\Psi_{ij}` is the matrix of coefficients and :math:`N` is the +# number of sites, e.g., orbitals. The key idea in DMET is to perform a singular value decomposition +# of the coefficient matrix :math:`\Psi_{ij} = \sum_{\alpha} U_{i \alpha} \lambda_{\alpha} V_{\alpha j}` +# and rearrange the wave functions such that +# +# .. math:: +# +# | \Psi \rangle = \sum_{\alpha}^{N} \lambda_{\alpha} | A_{\alpha} \rangle | B_{\alpha} \rangle, +# +# where :math:`A_{\alpha} = \sum_i U_{i \alpha} | I_i \rangle` are states obtained from rotations of +# :math:`I_i` to a new basis and :math:`B_{\alpha} = \sum_j V_{j \alpha} | E_j \rangle` are bath +# states representing the portion of the environment that interacts with the impurity. Note that the +# number of bath states is identical by the number of fragment states, regardless of the size of the +# environment. This new decomposition is the Schmidt decomposition of the system wave function. +# +# We are now able to project the full Hamiltonian to the space of impurity and bath states, known as +# embedding space. +# # .. math:: # # \hat{H}^{imp} = \hat{P} \hat{H}^{sys}\hat{P} # -# where P is the projection operator. -# We must note here that the Schmidt decomposition requires apriori knowledge of the wavefunction. DMET, therefore, -# operates through a systematic iterative approach, starting with a meanfield description of the wavefunction and -# refining it through feedback from solution of impurity Hamiltonian. +# where :math:`P` is the projection operator. +# +# Note here that the Schmidt decomposition requires apriori knowledge of the wavefunction. DMET, +# therefore, operates through a systematic iterative approach, starting with a meanfield description +# of the wavefunction and refining it through feedback from solution of impurity Hamiltonian. # # The DMET procedure starts by getting an approximate description of the system, which is used to partition the system # into impurity and bath. We are then able to project the original Hamiltonian to this embedded space and From 38f42192e7b130f2054f65a8081c6ee09c1baa38 Mon Sep 17 00:00:00 2001 From: soranjh Date: Wed, 30 Apr 2025 15:01:29 -0400 Subject: [PATCH 14/14] update implementation --- demonstrations/tutorial_dmet_embedding.py | 197 +++++++++++++--------- 1 file changed, 113 insertions(+), 84 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index 4b40e5b003..bcec955820 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -54,32 +54,34 @@ # # .. math:: # -# \hat{H}^{imp} = \hat{P} \hat{H}^{sys}\hat{P} +# \hat{H}^{emb} = \hat{P}^{\dagger} \hat{H}^{sys}\hat{P} # -# where :math:`P` is the projection operator. +# where :math:`P = \sum_{\alpha \beta} | A_{\alpha} B_{\beta} \rangle \langle A_{\alpha} B_{\beta}|` +# is a projection operator. # -# Note here that the Schmidt decomposition requires apriori knowledge of the wavefunction. DMET, -# therefore, operates through a systematic iterative approach, starting with a meanfield description -# of the wavefunction and refining it through feedback from solution of impurity Hamiltonian. -# -# The DMET procedure starts by getting an approximate description of the system, which is used to partition the system -# into impurity and bath. We are then able to project the original Hamiltonian to this embedded space and -# solve it using a highly accurate method. This high-level description of impurity is then used to -# embed the updated correlation back into the full system, thus improving the initial approximation -# self-consistently. Let's take a look at the implementation of these steps. +# Note that the Schmidt decomposition requires apriori knowledge of the wavefunction. To alleviate +# this, DMET operates through a systematic iterative approach, starting with a meanfield description +# of the wavefunction and refining it through feedback from solution of the impurity Hamiltonian. # ###################################################################### # Implementation # -------------- -# We now use what we have learned to set up a DMET calculation for $H_6$ system. +# The DMET procedure starts by getting an approximate description of the system. This approximate +# wavefunction is then partitioned with Schmidt decomposition to get the impurity and bath orbitals +# which are used to define an approximate projector :math:`P`. The projector is then used to +# construct the embedded Hamiltonian. This Hamiltonian is then solved using accurate methods such as +# post-Hartree-Fock methods, exact diagonalisation, or accurate quantum algorithms. the results are +# used to re-construct the projector and the process is repeated until the wave function converges. +# Let's now take a look at the implementation of these steps for the $H_6$ system. We use the +# programs PySCF [#pyscf]_ and libDMET which can be installed with # # Constructing the system # ^^^^^^^^^^^^^^^^^^^^^^^ -# We begin by defining a periodic system using PySCF [#pyscf]_ to create a cell object -# representing a hydrogen chain with 6 atoms. Each unit cell contains two Hydrogen atoms at a bond -# distance of 0.75 Å. Finally, we construct a Lattice object from the libDMET library, associating it with -# the defined cell and k-mesh, which allows for the use of DMET in studying the properties of -# the hydrogen chain system. +# We begin by defining a hydrogen chain with 6 atoms using PySCF. This is done by creating +# a ``Cell`` object with three unit cell each containing two Hydrogen atoms at a bond distance of +# 0.75 Å. Then, we construct a ``Lattice`` object from the libDMET library, associating it with +# the defined cell. + import numpy as np from pyscf.pbc import gto, df, scf, tools from libdmet.system import lattice @@ -94,63 +96,69 @@ cell.build(unit='Angstrom') kmesh = [1, 1, 3] # number of k-points in xyz direction + lat = lattice.Lattice(cell, kmesh) -filling = cell.nelectron / (lat.nscsites*2.0) +filling = cell.nelectron / (lat.nscsites * 2.0) kpts = lat.kpts ###################################################################### -# We perform a mean-field calculation on the whole system through Hartree-Fock with density +# Performing mean-field calculations +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# We can now perform a mean-field calculation on the whole system through Hartree-Fock with density # fitted integrals using PySCF. + gdf = df.GDF(cell, kpts) -gdf._cderi_to_save = 'gdf_ints.h5' #output file for density fitted integral tensor -gdf.build() #compute the density fitted integrals +gdf._cderi_to_save = 'gdf_ints.h5' # output file for density fitted integral tensor +gdf.build() # compute the density fitted integrals kmf = scf.KRHF(cell, kpts, exxdiv=None).density_fit() -kmf.with_df = gdf #use density-fitted integrals -kmf.with_df._cderi = 'gdf_ints.h5' #input file for density fitted integrals -kmf.kernel() #run Hartree-Fock - -# Paritioning of Orbital Space -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -# Now we have a description of our system and can start obtaining the impurity and bath orbitals. -# This requires the localization of the basis of orbitals, we could use any localized basis here, -# for example, molecular orbitals(MO), intrinsic atomic orbitals(IAO), etc [#SWouters]_. The use of -# localized basis here provides a mathematically convenient way to understand the contribution of -# each atom to properties of the full system. Here, we -# rotate the one-electron and two-electron integrals into IAO basis. +kmf.with_df = gdf # use density-fitted integrals +kmf.with_df._cderi = 'gdf_ints.h5' # input file for density fitted integrals +kmf.kernel() # run Hartree-Fock + +###################################################################### +# Partitioning the orbital space +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# Now we have an approximate description of our system and can start obtaining the impurity and bath +# orbitals. This requires the localization of the basis of orbitals. We can use any localized basis +# such as molecular orbitals (MO) or intrinsic atomic orbitals (IAO) [#SWouters]_. The use of +# localized basis provides a convenient way to understand the contribution of each atom to +# properties of the full system. Here, we rotate the one-electron and two-electron integrals into +# IAO basis. from libdmet.basis_transform import make_basis c_ao_iao, _, _, lo_labels = make_basis.get_C_ao_lo_iao(lat, kmf, minao="MINAO", full_return=True, return_labels=True) c_ao_lo = lat.symmetrize_lo(c_ao_iao) -lat.set_Ham(kmf, gdf, c_ao_lo, eri_symmetry=4) #rotate integral tensors to IAO basis +lat.set_Ham(kmf, gdf, c_ao_lo, eri_symmetry=4) # rotate integral tensors to IAO basis ###################################################################### -# In ab initio systems, we can choose the bath and impurity by looking at the -# labels of orbitals. We can get the orbitals for each atom in the unit cell by using -# aoslice_by_atom function. This information helps us identify the orbitals to be included -# in the impurity, bath and unentangled environment. -# In this example, we choose to keep the :math:`1s` orbitals in the unit cell in the -# impurity, while the bath contains the :math:`2s` orbitals, and the orbitals belonging to the -# rest of the supercell become part of the unentangled environment. These can be separated by +# We now obtain the orbital labels for each atom in the unit cell and define the impurity and bath +# by looking at the labels. In this example, we choose to keep the :math:`1s` orbitals in the unit +# cell in the impurity, while the bath contains the :math:`2s` orbitals, and the orbitals belonging +# to the rest of the supercell become part of the unentangled environment. These can be separated by # getting the valence and virtual labels from get_labels function. + from libdmet.lo.iao import get_labels aoind = cell.aoslice_by_atom() labels, val_labels, virt_labels = get_labels(cell, minao="MINAO") ncore = 0 lat.set_val_virt_core(len(val_labels), len(virt_labels), ncore) + print("Valence orbitals: ", val_labels) print("Virtual orbitals: ", virt_labels) ###################################################################### # Self-Consistent DMET # ^^^^^^^^^^^^^^^^^^^^ -# Now that we have a description of our impurity and bath orbitals, we can implement DMET. -# We implement each step of the process in a function and -# then call these functions to perform the calculations. This can be done once for one iteration, -# referred to as single-shot DMET or we can call them iteratively to perform self-consistent DMET. -# Let's start by constructing the impurity Hamiltonian, +# Now that we have a description of our impurity and bath orbitals, we can implement the iterative +# process of DMET. We implement each step of the process in a function and then call these functions +# to perform the calculations. Note that if we only perform one step of the iteration the process is +# referred to as single-shot DMET. +# +# We first need to construct the impurity Hamiltonian. + def construct_impurity_hamiltonian(lat, v_cor, filling, mu, last_dmu, int_bath=True): rho, mu, scf_result = dmet.HartreeFock(lat, v_cor, filling, mu, @@ -160,10 +168,12 @@ def construct_impurity_hamiltonian(lat, v_cor, filling, mu, last_dmu, int_bath=T return rho, mu, scf_result, imp_ham, basis -# Next, we solve this impurity Hamiltonian with a high-level method, the following function defines -# the electronic structure solver for the impurity, provides an initial point for the calculation and -# passes the Lattice information to the solver. The solver then calculates the energy and density matrix -# for the impurity. +###################################################################### +# Next, we solve this impurity Hamiltonian with a high-level method. The following function defines +# the electronic structure solver for the impurity, provides an initial point for the calculation +# and passes the ``Lattice`` information to the solver. The solver then calculates the energy and +# density matrix for the impurity. + def solve_impurity_hamiltonian(lat, cell, basis, imp_ham, last_dmu, scf_result): solver = dmet.impurity_solver.FCI(restricted=True, tol=1e-13) @@ -178,8 +188,10 @@ def solve_impurity_hamiltonian(lat, cell, basis, imp_ham, last_dmu, scf_result): last_dmu += dmu return rho_emb, energy_emb, imp_ham, last_dmu, [solver, solver_args] -# Final step in single-shot DMET is to include the effect of environment in the final expectation value, -# so we define a function for the same which returns the density matrix and energy for the whole system. +###################################################################### +# The final step is to include the effect of the environment in the expectation value. So we define +# a function which returns the density matrix and energy for the whole system. + def solve_full_system(lat, rho_emb, energy_emb, basis, imp_ham, last_dmu, solver_info, lo_labels): rho_full, energy_full, nelec_full = \ dmet.transformResults(rho_emb, energy_emb, basis, imp_ham, \ @@ -187,16 +199,18 @@ def solve_full_system(lat, rho_emb, energy_emb, basis, imp_ham, last_dmu, solver solver=solver_info[0], solver_args=solver_info[1], labels=lo_labels) energy_full *= lat.nscsites return rho_full, energy_full - -# We must note here that the effect of environment included in the previous step is -# at the meanfield level, and will give the results for single-shot DMET. -# We can look at a more advanced version of DMET and improve this interaction -# with the use of self-consistency, referred to -# as self-consistent DMET, where a correlation potential is introduced to account for the interactions -# between the impurity and its environment. We start with an initial guess of zero for this correlation -# potential and optimize it by minimizing the difference between density matrices obtained from the -# mean-field Hamiltonian and the impurity Hamiltonian. Let's initialize the correlation potential -# and define a function to optimize it. + +###################################################################### +# Note here that the effect of environment included in this step is at the meanfield level. So if we +# stop the iteration here, the results will be that of the single-shot DMET. + +# In the self-consistent DMET, the interaction between the environment and the impurity is improved +# iteratively. In this method, a correlation potential is introduced to account for the interactions +# between the impurity and its environment. We start with an initial guess of zero for this +# correlation potential and optimize it by minimizing the difference between density matrices +# obtained from the mean-field Hamiltonian and the impurity Hamiltonian. Let's initialize the +# correlation potential and define a function to optimize it. + def initialize_vcor(lat): v_cor = dmet.VcorLocal(restricted=True, bogoliubov=False, nscsites=lat.nscsites) v_cor.assign(np.zeros((2, lat.nscsites, lat.nscsites))) @@ -210,10 +224,12 @@ def fit_correlation_potential(rho_emb, lat, basis, v_cor): v_cor.update(vcor_new.param) return v_cor, dVcor_per_ele -# Now, we have defined all the ingredients of DMET, we can set up the self-consistency loop to get -# the full execution. We set up this loop by defining the maximum number of iterations and a convergence -# criteria. Here, we are using both energy and correlation potential as our convergence parameters, so we -# define the initial values and convergence tolerance for both. +###################################################################### +# Now, we have defined all the ingredients of DMET. We can set up the self-consistency loop to get +# the full execution. We set up this loop by defining the maximum number of iterations and a +# convergence criteria. We use both energy and correlation potential as our convergence parameters, +# so we define the initial values and convergence tolerance for both. + import libdmet.dmet.Hubbard as dmet max_iter = 10 # maximum number of iterations @@ -224,6 +240,10 @@ def fit_correlation_potential(rho_emb, lat, basis, v_cor): energy_tol = 1.0e-5 # tolerance for energy convergence mu = 0 # initial chemical potential last_dmu = 0.0 # change in chemical potential + +###################################################################### +# Now we set up the iterations in a loop. + for i in range(max_iter): rho, mu, scf_result, imp_ham, basis = construct_impurity_hamiltonian(lat, v_cor, filling, mu, last_dmu) # construct impurity Hamiltonian @@ -241,20 +261,30 @@ def fit_correlation_potential(rho_emb, lat, basis, v_cor): print("DMET Energy per cell: ", energy_full) break -# This concludes the DMET procedure. At this point, we should note that we are still limited by the number -# of orbitals we can have in the impurity because the cost of using a high-level solver such as FCI increases -# exponentially with increase in system size. One way to solve this problem could be through the use of -# quantum computing algorithm as solver. Next, we see how we can convert this impurity Hamiltonian to a -# qubit Hamiltonian through PennyLane to pave the path for using it with quantum algorithms. -# The ImpHam object generated above provides us with one-body and two-body integrals along with the -# nuclear repulsion energy which can be accessed as follows: +###################################################################### +# This concludes the DMET procedure. +# +# At this point, we should note that we are still limited by the number of orbitals we can have in +# the impurity because the cost of using a high-level solver such as FCI increases exponentially +# with increase in system size. One way to solve this problem could be through the use of +# quantum computing algorithm as solver. +# +# Next, we see how we can convert this impurity Hamiltonian to a qubit Hamiltonian through PennyLane +# to pave the path for using it with quantum algorithms. The hamiltonian object generated above +# provides us with one-body and two-body integrals along with the nuclear repulsion energy which can +# be accessed as follows: + from pyscf import ao2mo norb = imp_ham.norb h1 = imp_ham.H1["cd"] h2 = imp_ham.H2["ccdd"][0] h2 = ao2mo.restore(1, h2, norb) # Get the correct shape based on permutation symmetry -# These one-body and two-body integrals can then be used to generate the qubit Hamiltonian for PennyLane. +###################################################################### +# These one-body and two-body integrals can then be used to generate the qubit Hamiltonian in +# PennyLane. We then diagonaliz it to get the eigenvalues and show that the lowest eigenvalue +# matches the energy we obtained for the embedded system above. + import pennylane as qml from pennylane.qchem import one_particle, two_particle, observable @@ -265,20 +295,19 @@ def fit_correlation_potential(rho_emb, lat, basis, v_cor): print("eigenvalue from PennyLane: ", eigval_qubit) print("embedding energy: ", energy_emb) -# We obtained the qubit Hamiltonian for embedded system here and diagonalized it to get the eigenvalues, -# and show that this eigenvalue matches the energy we obtained for the embedded system above. -# We can also get ground state energy for the system from this value -# by solving for the full system as done above in the self-consistency loop using solve_full_system function. +###################################################################### +# We can also get ground state energy for the system from this value by solving for the full system +# as done above in the self-consistency loop using solve_full_system function. ###################################################################### # Conclusion # ^^^^^^^^^^^^^^ -# Density matrix embedding theory is a robust method, designed to tackle simulation of complex systems, -# by dividing them into subsystems. It is specifically suited for studying the ground state properties of -# a system. It provides for a computationally efficient alternative to dynamic quantum embedding schemes -# such as dynamic meanfield theory(DMFT), as it uses density matrix for embedding instead of the Green's function -# and has limited number of bath orbitals. -# It has been successfully used for studying various strongly correlated molecular and periodic systems. +# The density matrix embedding theory is a robust method designed to tackle simulation of complex +# systems by dividing them into subsystems. It is specifically suited for studying the ground state +# properties of a highly-correlated system. It provides for a computationally efficient alternative +# to dynamic quantum embedding schemes such as dynamic meanfield theory(DMFT), as it uses density +# matrix for embedding instead of the Green's function and has limited number of bath orbitals. It +# has been successfully used for studying various strongly correlated molecular and periodic systems. # # References # ----------