From d0722919329eca4c6a9f4996c3cd0c9c6ecbe694 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan Date: Mon, 17 Mar 2025 11:24:23 -0400 Subject: [PATCH 01/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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 # ---------- From 4ff926c72d7eadb1541a99d067c388109747b727 Mon Sep 17 00:00:00 2001 From: soranjh Date: Thu, 1 May 2025 10:20:30 -0400 Subject: [PATCH 15/62] add metadata --- .../tutorial_dmet_embedding.metadata.json | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 demonstrations/tutorial_dmet_embedding.metadata.json diff --git a/demonstrations/tutorial_dmet_embedding.metadata.json b/demonstrations/tutorial_dmet_embedding.metadata.json new file mode 100644 index 0000000000..9c279265b1 --- /dev/null +++ b/demonstrations/tutorial_dmet_embedding.metadata.json @@ -0,0 +1,47 @@ +{ + "title": "Density Matrix Embedding Theory", + "authors": [ + { + "username": "ddhawan" + } + ], + "dateOfPublication": "2025-05-01T00:00:00+00:00", + "dateOfLastModification": "2025-05-01T00:00:00+00:00", + "categories": [ + "Getting Started", + "How-to" + ], + "tags": [], + "previewImages": [ + { + "type": "thumbnail", + "uri": "/_static/demo_thumbnails/regular_demo_thumbnails/thumbnail_how_to_build_spin_hamiltonians.png" + }, + { + "type": "large_thumbnail", + "uri": "/_static/demo_thumbnails/large_demo_thumbnails/thumbnail_large_how_to_build_spin_hamiltonians.png" + } + ], + "seoDescription": "Learn how to build a Density Matrix Embedding Theory (DMET) Hamiltonian.", + "doi": "", + "references": [ + { + "id": "ashcroft", + "type": "book", + "title": "Solid State Physics", + "authors": "N. W. Ashcroft, D. N. Mermin", + "year": "1976", + "publisher": "New York: Saunders College Publishing", + "url": "https://en.wikipedia.org/wiki/Ashcroft_and_Mermin" + } + ], + "basedOnPapers": [], + "referencedByPapers": [], + "relatedContent": [ + { + "type": "demonstration", + "id": "tutorial_quantum_chemistry", + "weight": 1.0 + } + ] +} From 908b82ee12af3f3330053d304755e36d5edcf8bf Mon Sep 17 00:00:00 2001 From: soranjh Date: Thu, 1 May 2025 10:28:07 -0400 Subject: [PATCH 16/62] disable code --- demonstrations/tutorial_dmet_embedding.py | 312 ++++++++++++---------- 1 file changed, 168 insertions(+), 144 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index bcec955820..3c48474006 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -81,41 +81,45 @@ # 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 - -cell = gto.Cell() -cell.a = ''' 10.0 0.0 0.0 - 0.0 10.0 0.0 - 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 ''' # coordinates of atoms in unit cell -cell.basis = '321g' -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) -kpts = lat.kpts - +# +# .. code-block:: python +# +# 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 ''' # lattice vectors for unit cell +# cell.atom = ''' H 0.0 0.0 0.0 +# H 0.0 0.0 0.75 ''' # coordinates of atoms in unit cell +# cell.basis = '321g' +# 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) +# kpts = lat.kpts +# ###################################################################### # 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 - -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 - +# +# .. code-block:: python +# +# 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 +# +# 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 +# ###################################################################### # Partitioning the orbital space # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -125,30 +129,34 @@ # 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 - +# +# .. code-block:: python +# +# 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 +# ###################################################################### # 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) - +# +# .. code-block:: python +# +# 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 # ^^^^^^^^^^^^^^^^^^^^ @@ -158,47 +166,53 @@ # 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, - ires=True, labels=lo_labels) - 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, scf_result, imp_ham, basis - +# +# .. code-block:: python +# +# 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, +# ires=True, labels=lo_labels) +# 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, 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. - -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 in k-space - - solver_args = {"nelec": min((lat.ncore+lat.nval)*2, lat.nkpts*cell.nelectron), \ - "dm0": dmet.foldRho_k(scf_result["rho_k"], basis_k)} - - 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 rho_emb, energy_emb, imp_ham, last_dmu, [solver, solver_args] - +# +# .. code-block:: python +# +# 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 in k-space +# +# solver_args = {"nelec": min((lat.ncore+lat.nval)*2, lat.nkpts*cell.nelectron), \ +# "dm0": dmet.foldRho_k(scf_result["rho_k"], basis_k)} +# +# 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 rho_emb, energy_emb, imp_ham, last_dmu, [solver, solver_args] +# ###################################################################### # 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, \ - lattice=lat, last_dmu=last_dmu, int_bath=True, \ - solver=solver_info[0], solver_args=solver_info[1], labels=lo_labels) - energy_full *= lat.nscsites - return rho_full, energy_full +# +# .. code-block:: python +# +# 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) +# energy_full *= lat.nscsites +# return rho_full, energy_full ###################################################################### # Note here that the effect of environment included in this step is at the meanfield level. So if we @@ -210,57 +224,63 @@ def solve_full_system(lat, rho_emb, energy_emb, basis, imp_ham, last_dmu, solver # 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))) - return v_cor - -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 - +# +# .. code-block:: python +# +# 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 +# +# 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. 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 -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 - +# +# .. code-block:: python +# +# import libdmet.dmet.Hubbard as dmet +# +# 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 +# ###################################################################### # 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 - 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: ", energy_full) - break - +# +# .. code-block:: python +# +# 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: ", energy_full) +# break +# ###################################################################### # This concludes the DMET procedure. # @@ -273,32 +293,36 @@ def fit_correlation_potential(rho_emb, lat, basis, v_cor): # 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 - +# +# .. code-block:: python +# +# 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 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 - -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: ", energy_emb) - +# +# .. code-block:: python +# +# import pennylane as qml +# from pennylane.qchem import one_particle, two_particle, observable +# +# 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: ", energy_emb) +# ###################################################################### # 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 # ^^^^^^^^^^^^^^ From 4905427d8b3995809a8eae798083b944cd1800de Mon Sep 17 00:00:00 2001 From: soranjh Date: Thu, 1 May 2025 10:35:25 -0400 Subject: [PATCH 17/62] fix format --- demonstrations/tutorial_dmet_embedding.py | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index 3c48474006..b841ee1c38 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -22,8 +22,6 @@ :width: 70% :target: javascript:void(0) """ - -###################################################################### # Theory # ------ # The wave function for the embedded system composed of the impurity and the environment can be @@ -63,7 +61,6 @@ # 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 # -------------- # The DMET procedure starts by getting an approximate description of the system. This approximate @@ -103,7 +100,6 @@ # filling = cell.nelectron / (lat.nscsites * 2.0) # kpts = lat.kpts # -###################################################################### # Performing mean-field calculations # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # We can now perform a mean-field calculation on the whole system through Hartree-Fock with density @@ -120,7 +116,6 @@ # 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 @@ -138,7 +133,6 @@ # 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 # -###################################################################### # 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 @@ -157,7 +151,6 @@ # 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 the iterative @@ -178,7 +171,6 @@ # # 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 @@ -200,7 +192,6 @@ # last_dmu += dmu # return rho_emb, energy_emb, imp_ham, last_dmu, [solver, solver_args] # -###################################################################### # 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. # @@ -213,8 +204,7 @@ # solver=solver_info[0], solver_args=solver_info[1], labels=lo_labels) # energy_full *= lat.nscsites # return rho_full, energy_full - -###################################################################### +# # 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. @@ -240,7 +230,6 @@ # 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. We use both energy and correlation potential as our convergence parameters, @@ -259,7 +248,6 @@ # mu = 0 # initial chemical potential # last_dmu = 0.0 # change in chemical potential # -###################################################################### # Now we set up the iterations in a loop. # # .. code-block:: python @@ -281,7 +269,6 @@ # 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 @@ -302,7 +289,6 @@ # 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 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. @@ -319,11 +305,9 @@ # print("eigenvalue from PennyLane: ", eigval_qubit) # print("embedding energy: ", energy_emb) # -###################################################################### # 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 # ^^^^^^^^^^^^^^ # The density matrix embedding theory is a robust method designed to tackle simulation of complex From 367efd08a7398a1cb61ae45b913039fb39626555 Mon Sep 17 00:00:00 2001 From: soranjh Date: Thu, 1 May 2025 11:51:40 -0400 Subject: [PATCH 18/62] fix format --- demonstrations/tutorial_dmet_embedding.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index b841ee1c38..ebdc284ab6 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -22,6 +22,8 @@ :width: 70% :target: javascript:void(0) """ + +############################################# # Theory # ------ # The wave function for the embedded system composed of the impurity and the environment can be From 48c0fbbda0730ea5b6a15e2d4271612052604a25 Mon Sep 17 00:00:00 2001 From: soranjh Date: Thu, 1 May 2025 13:51:52 -0400 Subject: [PATCH 19/62] fix format --- 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 ebdc284ab6..dbbd6f0ea1 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -209,7 +209,7 @@ # # 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 From e6f4d1fdeda6bbbe1e4504592af0eafc5e4add30 Mon Sep 17 00:00:00 2001 From: soranjh Date: Thu, 1 May 2025 15:06:01 -0400 Subject: [PATCH 20/62] fix format --- 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 dbbd6f0ea1..fa7b328272 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -9,7 +9,7 @@ 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 +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. From b3e4da6899bbff0f308a3fc68462501dfe0f23e6 Mon Sep 17 00:00:00 2001 From: soranjh Date: Thu, 1 May 2025 15:37:25 -0400 Subject: [PATCH 21/62] fix format --- demonstrations/tutorial_dmet_embedding.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index fa7b328272..8d8763588b 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -54,10 +54,12 @@ # # .. math:: # -# \hat{H}^{emb} = \hat{P}^{\dagger} \hat{H}^{sys}\hat{P} +# \hat{H}_{emb} = \hat{P}^{\dagger} \hat{H} \hat{P} # # where :math:`P = \sum_{\alpha \beta} | A_{\alpha} B_{\beta} \rangle \langle A_{\alpha} B_{\beta}|` -# is a projection operator. +# is a projection operator. A key point about this representation is that the wave function +# :math:`\Psi \rangle` is the ground state of both the full system Hamiltonian :math:`\hat{H}` and +# the smaller embedded Hamiltonian :math:`\hat{H}_{emb}` [arXiv:2108.08611]. # # 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 @@ -131,7 +133,9 @@ # # 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_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 # @@ -203,7 +207,7 @@ # 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) +# solver=solver_info[0], solver_args=solver_info[1], labels=lo_labels) # energy_full *= lat.nscsites # return rho_full, energy_full # @@ -256,11 +260,11 @@ # # 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 +# 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 +# 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 +# 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 # From 8caa88abadfc3ba94639024edf1766696f5147b9 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan Date: Fri, 16 May 2025 17:13:56 -0400 Subject: [PATCH 22/62] Addressed Torin's comments --- demonstrations/tutorial_dmet_embedding.py | 325 +++++++++++++++------- 1 file changed, 229 insertions(+), 96 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index 8d8763588b..547aba3d01 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -3,19 +3,22 @@ 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. +electron correlation effects found in strongly correlated materials because of its meanfield nature. +As a result, researchers often turn to more sophisticated methods, such as configuration interaction +or coupled cluster based wavefunction methods, 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: 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. +into two parts: an impurity which is a strongly correlated subsystem that requires a high accuracy +description and an environment which can be treated with more approximate but computationally efficient level of theory. -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. +Embedding approaches differ in how they capture the environment's effect on the embedded region, +and can be broadly categorized as density in density, wavefunction in wavefunction and Green's function based embeddings. +In this demo, we will focus on Density matrix embedding theory (DMET), a +wavefunction based embedding approach that embeds the ground state density matrix. +We provide a brief introduction of the method and demonstrate how to run +DMET calculations to construct a Hamiltonian that can be used for quantum algorithms. .. figure:: ../_static/demo_thumbnails/opengraph_demo_thumbnails/OGthumbnail_how_to_build_spin_hamiltonians.png :align: center @@ -31,12 +34,12 @@ # # .. math:: # -# | \Psi \rangle = \sum_i^{N_I} \sum_j^{N_E} \Psi_{ij} | I_i \rangle | E_j \rangle, +# | \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 +# :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}` +# 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:: @@ -57,8 +60,8 @@ # \hat{H}_{emb} = \hat{P}^{\dagger} \hat{H} \hat{P} # # where :math:`P = \sum_{\alpha \beta} | A_{\alpha} B_{\beta} \rangle \langle A_{\alpha} B_{\beta}|` -# is a projection operator. A key point about this representation is that the wave function -# :math:`\Psi \rangle` is the ground state of both the full system Hamiltonian :math:`\hat{H}` and +# is a projection operator. A key point about this representation is that the wave function, +# :math:`|\Psi \rangle`, is the ground state of both the full system Hamiltonian :math:`\hat{H}` and # the smaller embedded Hamiltonian :math:`\hat{H}_{emb}` [arXiv:2108.08611]. # # Note that the Schmidt decomposition requires apriori knowledge of the wavefunction. To alleviate @@ -67,20 +70,27 @@ # # Implementation # -------------- -# 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 +# The DMET procedure starts by getting an approximate description of the system's wavefunction. +# Subsequently, this approximate wavefunction is partitioned with Schmidt decomposition to get +# the impurity and bath orbitals. These orbitals are then employed to define an approximate projector +# :math:`P`, which in turn used to construct the embedded Hamiltonian. High accuracy methods such as +# post-Hartree-Fock methods, exact diagonalisation, or accurate quantum algorithms are employed to solve this +# embedded Hamiltonian for its energy spectrum and corresponding eigenfunctions. 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 a toy system with 8 Hydrogen atoms. +# We use the programs PySCF [#pyscf]_ and libDMET [#libdmet]_ [#libdmet2]_ which can be installed with +# +# .. code-block:: python +# +# pip install pyscf +# pip install git+https://github.com/gkclab/libdmet_preview.git@main # # Constructing the 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 +# We begin by defining a hydrogen chain with 8 atoms using PySCF. This is done by creating +# a ``Cell`` object containing 8 Hydrogen atoms. The system is arranged with a central H$_4$ +# chain featuring a uniform 0.75 Å H-H bond length, flanked by two H$_2$ molecules at its termini. +# Then, we construct a ``Lattice`` object from the libDMET library, associating it with # the defined cell. # # .. code-block:: python @@ -91,18 +101,27 @@ # # cell = gto.Cell() # cell.a = ''' 10.0 0.0 0.0 -# 0.0 10.0 0.0 -# 0.0 0.0 1.5 ''' # lattice vectors for unit cell +# 0.0 10.0 0.0 +# 0.0 0.0 12.0 ''' # lattice vectors for unit cell +# # cell.atom = ''' H 0.0 0.0 0.0 -# H 0.0 0.0 0.75 ''' # coordinates of atoms in unit cell +# H 0.0 0.0 0.75 +# H 0.0 0.0 3.0 +# H 0.0 0.0 3.75 +# H 0.0 0.0 4.5 +# H 0.0 0.0 5.25 +# H 0.0 0.0 7.5 +# H 0.0 0.0 8.25''' # coordinates of atoms in unit cell +# # cell.basis = '321g' # cell.build(unit='Angstrom') # -# kmesh = [1, 1, 3] # number of k-points in xyz direction +# kmesh = [1, 1, 1] # number of k-points in xyz direction +# +# lattice = lattice.Lattice(cell, kmesh) +# filling = cell.nelectron / (lattice.nscsites * 2.0) +# kpts = lattice.kpts # -# lat = lattice.Lattice(cell, kmesh) -# filling = cell.nelectron / (lat.nscsites * 2.0) -# kpts = lat.kpts # # Performing mean-field calculations # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -133,29 +152,28 @@ # # 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 +# c_ao_iao, _, _ = make_basis.get_C_ao_lo_iao( +# lattice, kmf, minao="MINAO", full_return=True) +# c_ao_lo = lattice.symmetrize_lo(c_ao_iao) +# lattice.set_Ham(kmf, gdf, c_ao_lo, eri_symmetry=4) # rotate integral tensors to IAO basis # -# 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. +# Next, we identify 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 central +# :math:`H_4` chain in the impurity, while the bath contains the :math:`2s` orbitals, and the orbitals belonging +# to the terminal Hydrogen molecules form the unentangled environment. The indices for the valence and virtual orbitals +# of the central Hydrogen chain, which correspond to our impurity and bath orbitals, respectively, can be obtained using +# the get_idx function. # # .. code-block:: python # -# from libdmet.lo.iao import get_labels +# from libdmet.lo.iao import get_labels, get_idx # # 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) +# imp_idx = get_idx(val_labels, atom_num=[2,3,4,5]) +# bath_idx = get_idx(virt_labels, atom_num=[2,3,4,5], offset=len(val_labels)) +# ncore = [] +# lattice.set_val_virt_core(imp_idx, bath_idx, ncore) # # Self-Consistent DMET # ^^^^^^^^^^^^^^^^^^^^ @@ -168,12 +186,29 @@ # # .. code-block:: python # -# 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, -# ires=True, labels=lo_labels) -# imp_ham, _, basis = dmet.ConstructImpHam(lat, rho, v_cor, int_bath=int_bath) -# imp_ham = dmet.apply_dmu(lat, imp_ham, basis, last_dmu) +# def construct_impurity_hamiltonian(lattice, v_cor, filling, mu, last_dmu, int_bath=True): +# r"""A function to construct the impurity Hamiltonian +# +# Args: +# lattice: Lattice object containing information about the system +# v_core: correlation potential +# filling: average number of electrons occupying the orbitals +# mu: chemical potential +# last_dmu: change in chemical potential from last iterations +# int_bath: Flag to determine whether we are using an interactive bath +# +# Returns: +# rho: mean-field density matrix +# mu: chemical potential +# scf_result: object containing the results of meanfield calculation +# imp_ham: impurity Hamiltonian +# basis: rotation matrix for embedding basis +# """ +# +# rho, mu, scf_result = dmet.HartreeFock(lattice, v_cor, filling, mu, +# ires=True) +# imp_ham, _, basis = dmet.ConstructImpHam(lattice, rho, v_cor, int_bath=int_bath) +# imp_ham = dmet.apply_dmu(lattice, imp_ham, basis, last_dmu) # # return rho, mu, scf_result, imp_ham, basis # @@ -184,52 +219,118 @@ # # .. code-block:: python # -# 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 in k-space -# -# solver_args = {"nelec": min((lat.ncore+lat.nval)*2, lat.nkpts*cell.nelectron), \ +# def solve_impurity_hamiltonian(lattice, cell, basis, imp_ham, filling_imp, last_dmu, scf_result): +# r"""A function to solve impurity Hamiltonian +# +# Args: +# lattice: Lattice object containing information about the system +# cell: Cell object containing information about the unit cell +# basis: rotation matrix for embedding basis +# imp_ham: impurity Hamiltonian +# last_dmu: change in chemical potential from previous iterations +# scf_result: object containing the results of meanfield calculation +# +# Returns: +# rho_emb: density matrix for embedded system +# energy_emb: energy for embedded system +# imp_ham: impurity Hamiltonian +# last_dmu: change in chemical potential from last iterations +# solver_info: a list containing information about the solver +# """ +# +# solver = dmet.impurity_solver.FCI(restricted=True, tol=1e-8) # impurity solver +# basis_k = lattice.R2k_basis(basis) # basis in k-space +# +# solver_args = {"nelec": min((lattice.ncore+lattice.nval)*2, lattice.nkpts*cell.nelectron), \ # "dm0": dmet.foldRho_k(scf_result["rho_k"], basis_k)} # -# rho_emb, energy_emb, imp_ham, dmu = dmet.SolveImpHam_with_fitting(lat, filling, +# rho_emb, energy_emb, imp_ham, dmu = dmet.SolveImpHam_with_fitting(lattice, filling_imp, # imp_ham, basis, solver, solver_args=solver_args) # # last_dmu += dmu -# return rho_emb, energy_emb, imp_ham, last_dmu, [solver, solver_args] +# solver_info = [solver, solver_args] +# return rho_emb, energy_emb, imp_ham, last_dmu, solver_info # # 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. # # .. code-block:: python # -# def solve_full_system(lat, rho_emb, energy_emb, basis, imp_ham, last_dmu, solver_info, lo_labels): -# rho_full, energy_full, nelec_full = \ +# def solve_full_system(lattice, rho_emb, energy_emb, basis, imp_ham, last_dmu, solver_info): +# r"""A function to solve impurity Hamiltonian +# +# Args: +# lattice: Lattice object containing information about the system +# rho_emb: density matrix for embedded system +# energy_emb: energy for embedded system +# basis: rotation matrix for embedding basis +# imp_ham: impurity Hamiltonian +# last_dmu: change in chemical potential from last iterations +# solver_info: a list containing information about the solver +# +# Returns: +# energy: Ground state energy of the system +# """ +# +# from libdmet.routine.slater import get_E_dmet_HF +# +# rho_imp, energy_imp, nelec_imp = \ # 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) -# energy_full *= lat.nscsites -# return rho_full, energy_full +# lattice=lattice, last_dmu=last_dmu, int_bath=True, \ +# solver=solver_info[0], solver_args=solver_info[1]) +# energy_imp_fci = energy_imp * lattice.nscsites # Energy of impurity at FCI level +# energy_imp_scf = get_E_dmet_HF(basis, lattice, imp_ham, last_dmu, solver_info[0]) +# energy = kmf.e_tot - kmf.energy_nuc() - energy_imp_scf + energy_imp_fci +# +# return energy_imp_fci, energy # # 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 +# between the impurity and its environment, which can be represented as +# +# .. math:: +# +# \hat{C}_x = \sum_{kl} u_{kl}^{x}a_k^{\dagger}a_l +# +# We start with an initial guess of zero for the :math:`u` here, +# 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. # # .. code-block:: python # -# 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))) +# def initialize_vcor(lattice): +# r"""A function to initialize the correlation potential +# +# Args: +# lattice: Lattice object containing information about the system +# +# Returns: +# Initial correlation potential +# """ +# +# v_cor = dmet.VcorLocal(restricted=True, bogoliubov=False, nscsites=lattice.nscsites, idx_range=lattice.imp_idx) +# v_cor.assign(np.zeros((2, lattice.nscsites, lattice.nscsites))) # return v_cor # -# def fit_correlation_potential(rho_emb, lat, basis, v_cor): -# vcor_new, err = dmet.FitVcor(rho_emb, lat, basis, \ +# def fit_correlation_potential(rho_emb, lattice, basis, v_cor): +# r"""A function to solve impurity Hamiltonian +# +# Args: +# rho_emb: density matrix for embedded system +# lattice: Lattice object containing information about the system +# basis: rotation matrix for embedding basis +# v_cor: correlation potential +# +# Returns: +# v_cor: correlation potential +# dVcor_per_ele: change in correlation potential per electron +# """ +# +# vcor_new, err = dmet.FitVcor(rho_emb, lattice, 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)) @@ -237,7 +338,9 @@ # 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 +# the full execution. We should note that dividing the system into multiple fragments might lead to wrong +# number of electrons, we keep this in check through the use of chemical potential, :math:`\mu`. +# 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. # @@ -247,32 +350,38 @@ # # 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 +# v_cor = initialize_vcor(lattice) # 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 # -# Now we set up the iterations in a loop. +# Now we set up the iterations in a loop. We must note that defining an impurity which is a fragment of the unit cell, +# necessitates readjusting of the filling value for solution of impurity Hamiltonian, +# This filling value represents the average electron occupation, which scales proportional to the fraction +# of the unit cell included, while taking into account the different electronic species. +# For example, we are using half the number of Hydrogens inside the impurity, +# therefore, the filling becomes half as well. # # .. code-block:: python # # for i in range(max_iter): -# rho, mu, scf_result, imp_ham, basis = construct_impurity_hamiltonian(lat, +# rho, mu, scf_result, imp_ham, basis = construct_impurity_hamiltonian(lattice, # 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 +# filling_imp = filling * 0.5 +# rho_emb, energy_emb, imp_ham, last_dmu, solver_info = solve_impurity_hamiltonian(lattice, cell, +# basis, imp_ham, filling_imp, last_dmu, scf_result) # solve impurity Hamiltonian +# energy_imp, energy = solve_full_system(lattice, rho_emb, energy_emb, basis, imp_ham, +# last_dmu, solver_info) # include the environment interactions # v_cor, dVcor_per_ele = fit_correlation_potential(rho_emb, -# lat, basis, v_cor) # fit correlation potential +# lattice, basis, v_cor) # fit correlation potential # -# dE = energy_full - e_old -# e_old = energy_full +# dE = energy_imp - e_old +# e_old = energy_imp # if dVcor_per_ele < vcor_tol and abs(dE) < energy_tol: # print("DMET Converged") -# print("DMET Energy per cell: ", energy_full) +# print("DMET Energy per cell: ", energy) # break # # This concludes the DMET procedure. @@ -296,7 +405,7 @@ # 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 in -# PennyLane. We then diagonaliz it to get the eigenvalues and show that the lowest eigenvalue +# PennyLane. We further diagonalize it to get the eigenvalues and show that the lowest eigenvalue # matches the energy we obtained for the embedded system above. # # .. code-block:: python @@ -312,16 +421,28 @@ # print("embedding energy: ", energy_emb) # # 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. +# as done above in the self-consistency loop using solve_full_system function. This qubit Hamiltonian +# is particularly relevant for hybrid flavor of DMET approach, where classical mean-field calculations +# are coupled with a quantum algorithm for the self-consistent solver. However, directly employing a +# quantum solver iteratively might not be the most efficient use of quantum resources. An alternative +# strategy involves using a classical solver for the iterative self-consistency between the impurity and +# the environment. The resulting converged impurity Hamiltonian can then be treated with a quantum algorithm +# for a more accurate final energy calculation." # # Conclusion # ^^^^^^^^^^^^^^ # 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. +# systems by partitioning them into manageablesubsystems. It is particularly well suited for studying +# the ground state properties of strongly correlated materials and molecules. DMET offers a compelling +# alternative to dynamic quantum embedding schemes such as dynamic meanfield theory(DMFT). By employing density +# matrix for embedding instead of the Green's function and utilizing Schmidt decomposition to get limited number +# of bath orbitals, DMET achieves significant computational advantage. Furthermore, a major strength lies +# in its compatibility with quantum algorithms, enabling the accurate study of smaller, strongly correlated +# subsystems on quantum computers while the environment is studied classically. +# Its successful application to a wide range of strongly correlated molecular and periodic systems underscores its +# power and versatility in electronic structure theory, paving the way for hybrid quantum-classical simulations of +# challenging materials.[#DMETQC]_ + # # References # ---------- @@ -331,8 +452,20 @@ # "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 +# +# .. [#libdmet] +# Zhi-Hao Cui, Tianyu Zhu, *et al.*, "Efficient Implementation of Ab Initio Quantum Embedding in Periodic Systems: Density Matrix Embedding Theory." +# `ArXiv `__. +# +# .. [#libdmet2] +# Tianyu Zhu, Zhi-Hao Cui, *et al.*, "Efficient Formulation of Ab Initio Quantum Embedding in Periodic Systems: Dynamical Mean-Field Theory." +# `ArXiv `__. +# +# +# .. [#DMETQC] +# Changsu Cao,Jinzhao Sun, *et al.*, "Ab initio simulation of complex solids on a quantum computer with orbital-based multifragment density matrix embedding" +# `ArXiv `__. +# From 6e9c035a439678e4038c6614152489947f1c9a9f Mon Sep 17 00:00:00 2001 From: Diksha Dhawan Date: Fri, 16 May 2025 17:21:23 -0400 Subject: [PATCH 23/62] Small change --- 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 547aba3d01..7d0d0a3efc 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -15,7 +15,7 @@ Embedding approaches differ in how they capture the environment's effect on the embedded region, and can be broadly categorized as density in density, wavefunction in wavefunction and Green's function based embeddings. -In this demo, we will focus on Density matrix embedding theory (DMET), a +In this demo, we will focus on Density matrix embedding theory (DMET) [#SWouters]_, a wavefunction based embedding approach that embeds the ground state density matrix. We provide a brief introduction of the method and demonstrate how to run DMET calculations to construct a Hamiltonian that can be used for quantum algorithms. From f2d9e0e30ebecb04bbcf5cc9b30edc39bc677767 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Wed, 21 May 2025 11:57:12 -0400 Subject: [PATCH 24/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: agran2018 <45397799+agran2018@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 7d0d0a3efc..3714d405bb 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -49,7 +49,7 @@ # 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 +# number of bath states is equal to 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 From 7b03cfc6e5bb219a87f3aff5ba4ef6a27e545380 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Wed, 21 May 2025 11:57:24 -0400 Subject: [PATCH 25/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: agran2018 <45397799+agran2018@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 3714d405bb..adb1925a38 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -47,7 +47,7 @@ # | \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 +# :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 equal to the number of fragment states, regardless of the size of the # environment. This new decomposition is the Schmidt decomposition of the system wave function. From 351d7a36d87c7133f2e0598377a404feec23dfec Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Wed, 21 May 2025 11:58:06 -0400 Subject: [PATCH 26/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: agran2018 <45397799+agran2018@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 adb1925a38..293bb9568b 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -5,7 +5,7 @@ computational efficiency. However, it often falls short in accurately capturing the intricate electron correlation effects found in strongly correlated materials because of its meanfield nature. As a result, researchers often turn to more sophisticated methods, such as configuration interaction -or coupled cluster based wavefunction methods, which provide better accuracy but come at a +or coupled cluster, 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 From a4487ab18f4a8fef472546626764c68667dc966b Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Wed, 21 May 2025 11:58:29 -0400 Subject: [PATCH 27/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: agran2018 <45397799+agran2018@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 293bb9568b..c751338fea 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -4,7 +4,7 @@ (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 because of its meanfield nature. -As a result, researchers often turn to more sophisticated methods, such as configuration interaction +As a result, researchers often turn to wavefunction-based methods, such as configuration interaction or coupled cluster, which provide better accuracy but come at a significantly higher computational cost. From fd96877f0dfbbdcaccac56aaa04de8765bcf6282 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Wed, 21 May 2025 11:58:51 -0400 Subject: [PATCH 28/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: agran2018 <45397799+agran2018@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 c751338fea..c18a24211b 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -16,7 +16,7 @@ Embedding approaches differ in how they capture the environment's effect on the embedded region, and can be broadly categorized as density in density, wavefunction in wavefunction and Green's function based embeddings. In this demo, we will focus on Density matrix embedding theory (DMET) [#SWouters]_, a -wavefunction based embedding approach that embeds the ground state density matrix. +wavefunction based approach embedding the ground state density matrix. We provide a brief introduction of the method and demonstrate how to run DMET calculations to construct a Hamiltonian that can be used for quantum algorithms. From ee4ccdb50f42cf187b2e783abd124134f699cdd2 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Wed, 21 May 2025 12:47:57 -0400 Subject: [PATCH 29/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: agran2018 <45397799+agran2018@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 c18a24211b..f594c9b138 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -73,7 +73,7 @@ # The DMET procedure starts by getting an approximate description of the system's wavefunction. # Subsequently, this approximate wavefunction is partitioned with Schmidt decomposition to get # the impurity and bath orbitals. These orbitals are then employed to define an approximate projector -# :math:`P`, which in turn used to construct the embedded Hamiltonian. High accuracy methods such as +# :math:`P`, which in turn is used to construct the embedded Hamiltonian. High accuracy methods such as # post-Hartree-Fock methods, exact diagonalisation, or accurate quantum algorithms are employed to solve this # embedded Hamiltonian for its energy spectrum and corresponding eigenfunctions. The results are used to # re-construct the projector and the process is repeated until the wave function converges. Let's now From 2e2046795e83f45971eadf8647f7d961fbd8f16a Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Wed, 21 May 2025 12:50:25 -0400 Subject: [PATCH 30/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: agran2018 <45397799+agran2018@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 f594c9b138..8dd4c053b3 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -74,7 +74,7 @@ # Subsequently, this approximate wavefunction is partitioned with Schmidt decomposition to get # the impurity and bath orbitals. These orbitals are then employed to define an approximate projector # :math:`P`, which in turn is used to construct the embedded Hamiltonian. High accuracy methods such as -# post-Hartree-Fock methods, exact diagonalisation, or accurate quantum algorithms are employed to solve this +# post-Hartree-Fock methods, exact diagonalisation, or accurate quantum algorithms are employed to find # embedded Hamiltonian for its energy spectrum and corresponding eigenfunctions. 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 a toy system with 8 Hydrogen atoms. From 2fa6506a15be6aa36463a6e8ba5967fcafc31af5 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Wed, 21 May 2025 12:51:07 -0400 Subject: [PATCH 31/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: agran2018 <45397799+agran2018@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 8dd4c053b3..ac5966f6c7 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -75,7 +75,7 @@ # the impurity and bath orbitals. These orbitals are then employed to define an approximate projector # :math:`P`, which in turn is used to construct the embedded Hamiltonian. High accuracy methods such as # post-Hartree-Fock methods, exact diagonalisation, or accurate quantum algorithms are employed to find -# embedded Hamiltonian for its energy spectrum and corresponding eigenfunctions. The results are used to +# the energy spectrum of the embedded Hamiltonian. 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 a toy system with 8 Hydrogen atoms. # We use the programs PySCF [#pyscf]_ and libDMET [#libdmet]_ [#libdmet2]_ which can be installed with From 8cce3ad98576e42c7f2431a1cc3bd7f9330e2b8b Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Wed, 21 May 2025 12:57:28 -0400 Subject: [PATCH 32/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: agran2018 <45397799+agran2018@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 ac5966f6c7..d6765f77c9 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -161,7 +161,7 @@ # by looking at the labels. In this example, we choose to keep the :math:`1s` orbitals in the central # :math:`H_4` chain in the impurity, while the bath contains the :math:`2s` orbitals, and the orbitals belonging # to the terminal Hydrogen molecules form the unentangled environment. The indices for the valence and virtual orbitals -# of the central Hydrogen chain, which correspond to our impurity and bath orbitals, respectively, can be obtained using +# corresponding to the impurity and the bath, respectively, can be obtained using # the get_idx function. # # .. code-block:: python From e13d4287a101a2911b2f23567f8f2d89a1f091a4 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Wed, 21 May 2025 12:57:37 -0400 Subject: [PATCH 33/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: agran2018 <45397799+agran2018@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 d6765f77c9..76b78ea8a9 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -284,7 +284,7 @@ # # return energy_imp_fci, energy # -# Note here that the effect of environment included in this step is at the meanfield level. So if we +# Note here that the effect of environment included in this step is at the mean field 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 From 434a396c7df351d1a814e85093fc5d74a4e02905 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Wed, 21 May 2025 12:57:54 -0400 Subject: [PATCH 34/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: agran2018 <45397799+agran2018@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 76b78ea8a9..c0578ad7d2 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -432,7 +432,7 @@ # Conclusion # ^^^^^^^^^^^^^^ # The density matrix embedding theory is a robust method designed to tackle simulation of complex -# systems by partitioning them into manageablesubsystems. It is particularly well suited for studying +# systems by partitioning them into manageable subsystems. It is particularly well suited for studying # the ground state properties of strongly correlated materials and molecules. DMET offers a compelling # alternative to dynamic quantum embedding schemes such as dynamic meanfield theory(DMFT). By employing density # matrix for embedding instead of the Green's function and utilizing Schmidt decomposition to get limited number From 7a517837258eeaf61d66a720b850fd93f5df1a35 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan Date: Wed, 21 May 2025 13:34:19 -0400 Subject: [PATCH 35/62] Addressed comments --- .../tutorial_dmet_embedding.metadata.json | 57 +++++++++++++++---- demonstrations/tutorial_dmet_embedding.py | 53 ++++++++--------- 2 files changed, 74 insertions(+), 36 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.metadata.json b/demonstrations/tutorial_dmet_embedding.metadata.json index 9c279265b1..c9868e9099 100644 --- a/demonstrations/tutorial_dmet_embedding.metadata.json +++ b/demonstrations/tutorial_dmet_embedding.metadata.json @@ -5,10 +5,10 @@ "username": "ddhawan" } ], - "dateOfPublication": "2025-05-01T00:00:00+00:00", - "dateOfLastModification": "2025-05-01T00:00:00+00:00", + "dateOfPublication": "2025-05-21T00:00:00+00:00", + "dateOfLastModification": "2025-05-21T00:00:00+00:00", "categories": [ - "Getting Started", + "Quantum Chemistry", "How-to" ], "tags": [], @@ -26,13 +26,50 @@ "doi": "", "references": [ { - "id": "ashcroft", - "type": "book", - "title": "Solid State Physics", - "authors": "N. W. Ashcroft, D. N. Mermin", - "year": "1976", - "publisher": "New York: Saunders College Publishing", - "url": "https://en.wikipedia.org/wiki/Ashcroft_and_Mermin" + "id": "SWouters", + "type": "article", + "title": "A practical guide to density matrix embedding theory in quantum chemistry", + "authors": "Wouters, Sebastian and Jim{\'e}nez-Hoyos, Carlos A and Sun, Qiming and Chan, Garnet K-L", + "journal": "", + "year": "2016", + "url": "https://arxiv.org/pdf/1603.08443" + }, + { + "id": "pyscf", + "type": "article", + "title": "Recent developments in the PySCF program package", + "authors": "Sun, Qiming and Zhang, Xing and Banerjee, Samragni and Bao, Peng and Barbry, Marc and Blunt, Nick S and Bogdanov, Nikolay A and Booth, George H and Chen, Jia and Cui, Zhi-Hao and others", + "journal": "", + "year": "2020", + "url": "https://arxiv.org/pdf/2002.12531" + }, + { + "id": "libdmet", + "type": "article", + "title": "Efficient Implementation of Ab Initio Quantum Embedding in Periodic Systems: Density Matrix Embedding Theory", + "authors": "Cui, Zhi-Hao and Zhu, Tianyu and Chan, Garnet Kin-Lic", + "journal": "", + "year": "2020", + "url": "https://arxiv.org/pdf/1909.08596" + }, + { + "id": "libdmet2", + "type": "article", + "title": "Efficient formulation of ab initio quantum embedding in periodic systems: Dynamical mean-field theory", + "authors": "Zhu, Tianyu and Cui, Zhi-Hao and Chan, Garnet Kin-Lic", + "journal": "", + "year": "2019", + "url": "https://arxiv.org/pdf/1909.08592" + }, + { + "id": "DMETQC", + "type": "article", + "title": "Ab initio simulation of complex solids on a quantum computer +with orbital-based multifragment density matrix embedding", + "authors": "Cao, Changsu and Sun, Jinzhao and Yuan, Xiao and Hu, Han-Shi and Pham, Hung Q and Lv, Dingshun", + "journal": "", + "year": "2023", + "url": "https://arxiv.org/pdf/2209.03202" } ], "basedOnPapers": [], diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index c0578ad7d2..e6f3ee6d99 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -3,7 +3,7 @@ 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 because of its meanfield nature. +electron correlation effects found in strongly correlated materials because of its mean field nature. As a result, researchers often turn to wavefunction-based methods, such as configuration interaction or coupled cluster, which provide better accuracy but come at a significantly higher computational cost. @@ -62,10 +62,10 @@ # where :math:`P = \sum_{\alpha \beta} | A_{\alpha} B_{\beta} \rangle \langle A_{\alpha} B_{\beta}|` # is a projection operator. A key point about this representation is that the wave function, # :math:`|\Psi \rangle`, is the ground state of both the full system Hamiltonian :math:`\hat{H}` and -# the smaller embedded Hamiltonian :math:`\hat{H}_{emb}` [arXiv:2108.08611]. +# the smaller embedded Hamiltonian :math:`\hat{H}_{\text{emb}}` [arXiv:2108.08611]. # # 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 +# this, DMET operates through a systematic iterative approach, starting with a mean field description # of the wavefunction and refining it through feedback from solution of the impurity Hamiltonian. # # Implementation @@ -73,7 +73,7 @@ # The DMET procedure starts by getting an approximate description of the system's wavefunction. # Subsequently, this approximate wavefunction is partitioned with Schmidt decomposition to get # the impurity and bath orbitals. These orbitals are then employed to define an approximate projector -# :math:`P`, which in turn is used to construct the embedded Hamiltonian. High accuracy methods such as +# :math:`P`, which is used to construct the embedded Hamiltonian. High accuracy methods such as # post-Hartree-Fock methods, exact diagonalisation, or accurate quantum algorithms are employed to find # the energy spectrum of the embedded Hamiltonian. The results are used to # re-construct the projector and the process is repeated until the wave function converges. Let's now @@ -82,16 +82,16 @@ # # .. code-block:: python # -# pip install pyscf -# pip install git+https://github.com/gkclab/libdmet_preview.git@main +# pip install pyscf +# pip install git+https://github.com/gkclab/libdmet_preview.git@main # # Constructing the system # ^^^^^^^^^^^^^^^^^^^^^^^ -# We begin by defining a hydrogen chain with 8 atoms using PySCF. This is done by creating -# a ``Cell`` object containing 8 Hydrogen atoms. The system is arranged with a central H$_4$ -# chain featuring a uniform 0.75 Å H-H bond length, flanked by two H$_2$ molecules at its termini. -# Then, we construct a ``Lattice`` object from the libDMET library, associating it with -# the defined cell. +# We begin by defining a finite system containing a hydrogen chain with 8 atoms using PySCF. +# This is done by creating a ``Cell`` object containing 8 Hydrogen atoms. The system is arranged +# with a central H$_4$ chain featuring a uniform 0.75 Å H-H bond length, flanked by two H$_2$ +# molecules at its termini. Then, we construct a ``Lattice`` object from the libDMET library, +# associating it with the defined cell. # # .. code-block:: python # @@ -100,9 +100,10 @@ # 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 12.0 ''' # lattice vectors for unit cell +# cell.unit = 'Angstrom' +# cell.a = ''' 12.0 0.0 0.0 +# 0.0 12.0 0.0 +# 0.0 0.0 12.0 ''' # lattice vectors for unit cell # # cell.atom = ''' H 0.0 0.0 0.0 # H 0.0 0.0 0.75 @@ -114,7 +115,7 @@ # H 0.0 0.0 8.25''' # coordinates of atoms in unit cell # # cell.basis = '321g' -# cell.build(unit='Angstrom') +# cell.build() # # kmesh = [1, 1, 1] # number of k-points in xyz direction # @@ -123,9 +124,9 @@ # kpts = lattice.kpts # # -# Performing mean-field calculations +# Performing mean field calculations # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -# We can now perform a mean-field calculation on the whole system through Hartree-Fock with density +# We can now perform a mean field calculation on the whole system through Hartree-Fock with density # fitted integrals using PySCF. # # .. code-block:: python @@ -198,9 +199,9 @@ # int_bath: Flag to determine whether we are using an interactive bath # # Returns: -# rho: mean-field density matrix +# rho: mean field density matrix # mu: chemical potential -# scf_result: object containing the results of meanfield calculation +# scf_result: object containing the results of mean field calculation # imp_ham: impurity Hamiltonian # basis: rotation matrix for embedding basis # """ @@ -228,7 +229,7 @@ # basis: rotation matrix for embedding basis # imp_ham: impurity Hamiltonian # last_dmu: change in chemical potential from previous iterations -# scf_result: object containing the results of meanfield calculation +# scf_result: object containing the results of mean field calculation # # Returns: # rho_emb: density matrix for embedded system @@ -297,7 +298,7 @@ # # We start with an initial guess of zero for the :math:`u` here, # and optimize it by minimizing the difference between density matrices -# obtained from the mean-field Hamiltonian and the impurity Hamiltonian. Let's initialize the +# obtained from the mean field Hamiltonian and the impurity Hamiltonian. Let's initialize the # correlation potential and define a function to optimize it. # # .. code-block:: python @@ -422,7 +423,7 @@ # # 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. This qubit Hamiltonian -# is particularly relevant for hybrid flavor of DMET approach, where classical mean-field calculations +# is particularly relevant for hybrid flavor of DMET approach, where classical mean field calculations # are coupled with a quantum algorithm for the self-consistent solver. However, directly employing a # quantum solver iteratively might not be the most efficient use of quantum resources. An alternative # strategy involves using a classical solver for the iterative self-consistency between the impurity and @@ -434,14 +435,14 @@ # The density matrix embedding theory is a robust method designed to tackle simulation of complex # systems by partitioning them into manageable subsystems. It is particularly well suited for studying # the ground state properties of strongly correlated materials and molecules. DMET offers a compelling -# alternative to dynamic quantum embedding schemes such as dynamic meanfield theory(DMFT). By employing density -# matrix for embedding instead of the Green's function and utilizing Schmidt decomposition to get limited number -# of bath orbitals, DMET achieves significant computational advantage. Furthermore, a major strength lies +# alternative to dynamic quantum embedding schemes such as dynamic mean field theory(DMFT). By employing the density +# matrix for embedding instead of the Green's function and utilizing Schmidt decomposition to get a limited number +# of bath orbitals, DMET achieves a significant reduction in computational resources. Furthermore, a major strength lies # in its compatibility with quantum algorithms, enabling the accurate study of smaller, strongly correlated # subsystems on quantum computers while the environment is studied classically. # Its successful application to a wide range of strongly correlated molecular and periodic systems underscores its # power and versatility in electronic structure theory, paving the way for hybrid quantum-classical simulations of -# challenging materials.[#DMETQC]_ +# challenging materials. [#DMETQC]_ # # References From aa16e0d8064068d30a46c1227fb26954254fe34d Mon Sep 17 00:00:00 2001 From: Diksha Dhawan Date: Wed, 21 May 2025 15:08:27 -0400 Subject: [PATCH 36/62] Fixed rendering issue --- demonstrations/tutorial_dmet_embedding.metadata.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.metadata.json b/demonstrations/tutorial_dmet_embedding.metadata.json index c9868e9099..e2d0db3992 100644 --- a/demonstrations/tutorial_dmet_embedding.metadata.json +++ b/demonstrations/tutorial_dmet_embedding.metadata.json @@ -38,7 +38,7 @@ "id": "pyscf", "type": "article", "title": "Recent developments in the PySCF program package", - "authors": "Sun, Qiming and Zhang, Xing and Banerjee, Samragni and Bao, Peng and Barbry, Marc and Blunt, Nick S and Bogdanov, Nikolay A and Booth, George H and Chen, Jia and Cui, Zhi-Hao and others", + "authors": "Sun, Qiming and Zhang, Xing and Banerjee, Samragni and Bao, Peng and Barbry, and others", "journal": "", "year": "2020", "url": "https://arxiv.org/pdf/2002.12531" @@ -64,8 +64,7 @@ { "id": "DMETQC", "type": "article", - "title": "Ab initio simulation of complex solids on a quantum computer -with orbital-based multifragment density matrix embedding", + "title": "Ab initio simulation of complex solids on a quantum computer with orbital-based multifragment density matrix embedding", "authors": "Cao, Changsu and Sun, Jinzhao and Yuan, Xiao and Hu, Han-Shi and Pham, Hung Q and Lv, Dingshun", "journal": "", "year": "2023", From f01030eb912fb1c6348ba46ca572813946909dc4 Mon Sep 17 00:00:00 2001 From: soranjh Date: Thu, 29 May 2025 17:42:47 -0400 Subject: [PATCH 37/62] update text --- .../tutorial_dmet_embedding.metadata.json | 9 +++ demonstrations/tutorial_dmet_embedding.py | 65 ++++++++++--------- 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.metadata.json b/demonstrations/tutorial_dmet_embedding.metadata.json index e2d0db3992..4e6c24f060 100644 --- a/demonstrations/tutorial_dmet_embedding.metadata.json +++ b/demonstrations/tutorial_dmet_embedding.metadata.json @@ -34,6 +34,15 @@ "year": "2016", "url": "https://arxiv.org/pdf/1603.08443" }, + { + "id": "Mineh", + "type": "article", + "title": "Solving the Hubbard model using density matrix embedding theory and the variational quantum eigensolver", + "authors": "Mineh, Lana and Montanaro, Ashley", + "journal": "", + "year": "2021", + "url": "https://arxiv.org/abs/2108.08611" + }, { "id": "pyscf", "type": "article", diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index e6f3ee6d99..029570a4ed 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -13,24 +13,21 @@ into two parts: an impurity which is a strongly correlated subsystem that requires a high accuracy description and an environment which can be treated with more approximate but computationally efficient level of theory. -Embedding approaches differ in how they capture the environment's effect on the embedded region, -and can be broadly categorized as density in density, wavefunction in wavefunction and Green's function based embeddings. -In this demo, we will focus on Density matrix embedding theory (DMET) [#SWouters]_, a -wavefunction based approach embedding the ground state density matrix. -We provide a brief introduction of the method and demonstrate how to run -DMET calculations to construct a Hamiltonian that can be used for quantum algorithms. - -.. figure:: ../_static/demo_thumbnails/opengraph_demo_thumbnails/OGthumbnail_how_to_build_spin_hamiltonians.png +.. figure:: ../_static/demo_thumbnails/opengraph_demo_thumbnails/OGthumbnail_qdet_embedding.png :align: center :width: 70% :target: javascript:void(0) """ +# In this demo, we will focus on Density matrix embedding theory (DMET) [#SWouters]_, a wavefunction +# based approach embedding the ground state density matrix. We provide a brief introduction of the +# method and demonstrate how to run DMET calculations to construct a Hamiltonian that can be used in +# quantum algorithms. ############################################# # Theory # ------ -# The wave function for the embedded system composed of the impurity and the environment can be -# simply represented as +# The wave function for an embedded system composed of an impurity and an environment can be +# represented as [#SWouters]_: # # .. math:: # @@ -40,7 +37,7 @@ # :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 +# and rearrange the wave functions as: # # .. math:: # @@ -48,21 +45,22 @@ # # 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 equal to the number of fragment states, regardless of the size of the -# environment. This new decomposition is the Schmidt decomposition of the system wave function. +# states representing the portion of the environment that interacts with the impurity [#Mineh]_. Note +# that the number of bath states is equal to 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. +# embedding space: # # .. math:: # -# \hat{H}_{emb} = \hat{P}^{\dagger} \hat{H} \hat{P} +# \hat{H}_{emb} = \hat{P}^{\dagger} \hat{H} \hat{P}, # # where :math:`P = \sum_{\alpha \beta} | A_{\alpha} B_{\beta} \rangle \langle A_{\alpha} B_{\beta}|` # is a projection operator. A key point about this representation is that the wave function, # :math:`|\Psi \rangle`, is the ground state of both the full system Hamiltonian :math:`\hat{H}` and -# the smaller embedded Hamiltonian :math:`\hat{H}_{\text{emb}}` [arXiv:2108.08611]. +# the smaller embedded Hamiltonian :math:`\hat{H}_{\text{emb}}` [#Mineh]_. # # Note that the Schmidt decomposition requires apriori knowledge of the wavefunction. To alleviate # this, DMET operates through a systematic iterative approach, starting with a mean field description @@ -73,12 +71,14 @@ # The DMET procedure starts by getting an approximate description of the system's wavefunction. # Subsequently, this approximate wavefunction is partitioned with Schmidt decomposition to get # the impurity and bath orbitals. These orbitals are then employed to define an approximate projector -# :math:`P`, which is used to construct the embedded Hamiltonian. High accuracy methods such as -# post-Hartree-Fock methods, exact diagonalisation, or accurate quantum algorithms are employed to find -# the energy spectrum of the embedded Hamiltonian. 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 a toy system with 8 Hydrogen atoms. -# We use the programs PySCF [#pyscf]_ and libDMET [#libdmet]_ [#libdmet2]_ which can be installed with +# :math:`P`, which is used to construct the embedded Hamiltonian. Then, accurate methods such as +# post-Hartree-Fock methods, exact diagonalisation, or accurate quantum algorithms are employed +# to find the energy spectrum of the embedded Hamiltonian. 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 a toy system with 8 Hydrogen atoms. +# We use the programs PySCF [#pyscf]_ and libDMET [#libdmet]_ [#libdmet2]_ which can be installed +# with # # .. code-block:: python # @@ -89,9 +89,9 @@ # ^^^^^^^^^^^^^^^^^^^^^^^ # We begin by defining a finite system containing a hydrogen chain with 8 atoms using PySCF. # This is done by creating a ``Cell`` object containing 8 Hydrogen atoms. The system is arranged -# with a central H$_4$ chain featuring a uniform 0.75 Å H-H bond length, flanked by two H$_2$ -# molecules at its termini. Then, we construct a ``Lattice`` object from the libDMET library, -# associating it with the defined cell. +# with a central :math:`H_4` chain featuring a uniform 0.75 Å H-H bond length, flanked by two +# :math:`H_2` molecules at its termini. Then, we construct a ``Lattice`` object from the libDMET +# library, associating it with the defined cell. # # .. code-block:: python # @@ -132,12 +132,12 @@ # .. code-block:: python # # 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 the integral tensor +# gdf.build() # compute the 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.with_df._cderi = 'gdf_ints.h5' # input file for the integrals # kmf.kernel() # run Hartree-Fock # # Partitioning the orbital space @@ -156,7 +156,7 @@ # c_ao_iao, _, _ = make_basis.get_C_ao_lo_iao( # lattice, kmf, minao="MINAO", full_return=True) # c_ao_lo = lattice.symmetrize_lo(c_ao_iao) -# lattice.set_Ham(kmf, gdf, c_ao_lo, eri_symmetry=4) # rotate integral tensors to IAO basis +# lattice.set_Ham(kmf, gdf, c_ao_lo, eri_symmetry=4) # rotate to IAO basis # # Next, we identify 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 central @@ -452,6 +452,11 @@ # Sebastian Wouters, Carlos A. Jiménez-Hoyos, *et al.*, # "A practical guide to density matrix embedding theory in quantum chemistry." # `ArXiv `__. +# +# .. [#Mineh] +# Lana Mineh, Ashley Montanaro, +# "Solving the Hubbard model using density matrix embedding theory and the variational quantum eigensolver." +# `ArXiv `__. # # .. [#pyscf] # Qiming Sun, Xing Zhang, *et al.*, "Recent developments in the PySCF program package." From 2e69544f46f27e3279a09b2fb64a8b83ce0d74d3 Mon Sep 17 00:00:00 2001 From: soranjh Date: Fri, 30 May 2025 10:28:59 -0400 Subject: [PATCH 38/62] update implementation --- demonstrations/tutorial_dmet_embedding.py | 139 ++++++++++++---------- 1 file changed, 75 insertions(+), 64 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index 029570a4ed..eaed05127c 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -140,14 +140,16 @@ # kmf.with_df._cderi = 'gdf_ints.h5' # input file for the integrals # kmf.kernel() # run Hartree-Fock # +# This provides us with an approximate description of the whole system. +# # 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. +# Now that we have an approximate description of our system, we can start obtaining the impurity and +# bath orbitals. This requires the localization of the basis of orbitals. The use of localized basis +# provides a convenient way to understand the contribution of each atom to properties of the full +# system. We can use any localized basis such as molecular orbitals (MO) or intrinsic atomic +# orbitals (IAO) [#SWouters]_. Here, we rotate the one-electron and two-electron integrals into +# the IAO basis. # # .. code-block:: python # @@ -158,12 +160,10 @@ # c_ao_lo = lattice.symmetrize_lo(c_ao_iao) # lattice.set_Ham(kmf, gdf, c_ao_lo, eri_symmetry=4) # rotate to IAO basis # -# Next, we identify 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 central -# :math:`H_4` chain in the impurity, while the bath contains the :math:`2s` orbitals, and the orbitals belonging -# to the terminal Hydrogen molecules form the unentangled environment. The indices for the valence and virtual orbitals -# corresponding to the impurity and the bath, respectively, can be obtained using -# the get_idx function. +# Next, we identify 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 +# central :math:`H_4` chain in the impurity, while the bath contains the :math:`2s` orbitals, and +# the orbitals belonging to the terminal Hydrogen molecules form the unentangled environment. # # .. code-block:: python # @@ -176,12 +176,16 @@ # ncore = [] # lattice.set_val_virt_core(imp_idx, bath_idx, ncore) # +# Now that we have a description of our impurity, bath and environment orbitals, we can implement +# the iterative process of DMET. +# # Self-Consistent DMET # ^^^^^^^^^^^^^^^^^^^^ -# 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. +# The DMET calculations are performed by repeating four steps iteratively: First construct an +# impurity Hamiltonian, solve the impurity Hamiltonian, compute the full system energy and finally +# update the interactions between the impurity and its environment. To simplify the calculations, we +# create dedicated functions for each step and implement them in a self-consistent loop. 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. # @@ -252,7 +256,7 @@ # solver_info = [solver, solver_args] # return rho_emb, energy_emb, imp_ham, last_dmu, solver_info # -# The final step is to include the effect of the environment in the expectation value. So we define +# Now we 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. # # .. code-block:: python @@ -285,21 +289,20 @@ # # return energy_imp_fci, energy # -# Note here that the effect of environment included in this step is at the mean field level. So if we -# stop the iteration here, the results will be that of the single-shot DMET. +# Note here that the effect of environment included in this step is at the mean field 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 +# iteratively. To do that, a correlation potential is introduced to account for the interactions # between the impurity and its environment, which can be represented as # # .. math:: # -# \hat{C}_x = \sum_{kl} u_{kl}^{x}a_k^{\dagger}a_l +# C_x = \sum_{kl} u_{kl}^{x}a_k^{\dagger}a_l # -# We start with an initial guess of zero for the :math:`u` here, -# 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. +# We start with an initial guess of zero for the :math:`u` here, 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. # # .. code-block:: python # @@ -339,11 +342,13 @@ # 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 should note that dividing the system into multiple fragments might lead to wrong -# number of electrons, we keep this in check through the use of chemical potential, :math:`\mu`. -# 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. +# the full execution. +# +# We set up the 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. Also, since dividing the system into multiple fragments +# might lead to wrong number of electrons, we denfine and check a chemical potential :math:`\mu` +# as well. # # .. code-block:: python # @@ -358,11 +363,11 @@ # mu = 0 # initial chemical potential # last_dmu = 0.0 # change in chemical potential # -# Now we set up the iterations in a loop. We must note that defining an impurity which is a fragment of the unit cell, -# necessitates readjusting of the filling value for solution of impurity Hamiltonian, -# This filling value represents the average electron occupation, which scales proportional to the fraction -# of the unit cell included, while taking into account the different electronic species. -# For example, we are using half the number of Hydrogens inside the impurity, +# Now we set up the iterations in a loop. We must note that defining an impurity which is a fragment +# of the unit cell, necessitates readjusting of the filling value for solution of impurity +# Hamiltonian. This filling value represents the average electron occupation, which scales +# proportional to the fraction of the unit cell included, while taking into account the different +# electronic species. For example, we are using half the number of Hydrogens inside the impurity, # therefore, the filling becomes half as well. # # .. code-block:: python @@ -385,17 +390,19 @@ # print("DMET Energy per cell: ", energy) # break # -# This concludes the DMET procedure. +# 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. +# Quantum DMET +# ^^^^^^^^^^^^ +# Our implementation of DMET used FCI to accurately treat the impurity subsystem. The cost of using +# a high-level solver such as FCI increases exponentially with the system size which limits the +# number of orbitals we can have in the impurity. One way to solve this problem is to use a quantum +# algorithm as our accurate solver. We now convert our impurity Hamiltonian to a qubit Hamiltonian +# that can be used in a quantum algorithm using PennyLane. # -# 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: +# The hamiltonian object we generated above contains one-body and two-body integrals along with the +# nuclear repulsion energy which can be accessed and used to construct the qubit Hamiltonian. We +# first extract the information we need. # # .. code-block:: python # @@ -405,9 +412,7 @@ # 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 in -# PennyLane. We further diagonalize it to get the eigenvalues and show that the lowest eigenvalue -# matches the energy we obtained for the embedded system above. +# Now we generate the qubit Hamiltonian in PennyLane. # # .. code-block:: python # @@ -417,32 +422,38 @@ # 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") +# +# This Hamiltonian can be used in a proper quantum algorithm such as Quantum Phase Estimation (QPE). +# +# For simplicity, we just diagonalize the Hamiltonian to get the eigenvalues and show that the +# lowest eigenvalue matches the energy we obtained for the embedded system above. +# # eigval_qubit = qml.eigvals(qml.SparseHamiltonian(qubit_op.sparse_matrix(), wires = qubit_op.wires)) # print("eigenvalue from PennyLane: ", eigval_qubit) # print("embedding energy: ", energy_emb) # # 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. This qubit Hamiltonian -# is particularly relevant for hybrid flavor of DMET approach, where classical mean field calculations -# are coupled with a quantum algorithm for the self-consistent solver. However, directly employing a -# quantum solver iteratively might not be the most efficient use of quantum resources. An alternative -# strategy involves using a classical solver for the iterative self-consistency between the impurity and -# the environment. The resulting converged impurity Hamiltonian can then be treated with a quantum algorithm -# for a more accurate final energy calculation." +# as done above in the self-consistency loop using the ``solve_full_system`` function. The qubit +# Hamiltonian is particularly relevant for a hybrid version of DMET, where classical mean field +# calculations are coupled with a quantum algorithm for the self-consistent solver. To further +# reduce the quantum resources, an alternative strategy will be using a classical solver for the +# iterative self-consistency between the impurity and the environment and treat the resulting +# converged impurity Hamiltonian with a quantum algorithm. # # Conclusion # ^^^^^^^^^^^^^^ # The density matrix embedding theory is a robust method designed to tackle simulation of complex -# systems by partitioning them into manageable subsystems. It is particularly well suited for studying -# the ground state properties of strongly correlated materials and molecules. DMET offers a compelling -# alternative to dynamic quantum embedding schemes such as dynamic mean field theory(DMFT). By employing the density -# matrix for embedding instead of the Green's function and utilizing Schmidt decomposition to get a limited number -# of bath orbitals, DMET achieves a significant reduction in computational resources. Furthermore, a major strength lies -# in its compatibility with quantum algorithms, enabling the accurate study of smaller, strongly correlated -# subsystems on quantum computers while the environment is studied classically. -# Its successful application to a wide range of strongly correlated molecular and periodic systems underscores its -# power and versatility in electronic structure theory, paving the way for hybrid quantum-classical simulations of -# challenging materials. [#DMETQC]_ +# systems by partitioning them into manageable subsystems. It is particularly well suited for +# studying the ground state properties of strongly correlated materials and molecules. DMET offers a +# compelling alternative to dynamic quantum embedding schemes such as dynamic mean field theory +# (DMFT). By employing the density matrix for embedding instead of the Green's function and +# utilizing Schmidt decomposition to get a limited number of bath orbitals, DMET achieves a +# significant reduction in computational resources. Furthermore, a major strength lies in its +# compatibility with quantum algorithms, enabling the accurate study of smaller, strongly correlated +# subsystems on quantum computers while the environment is studied classically. Its successful +# application to a wide range of strongly correlated molecular and periodic systems underscores its +# power and versatility in electronic structure theory, paving the way for hybrid quantum-classical +# simulations of challenging materials. [#DMETQC]_ # # References From d4825f22a1d930462872d8cdb5a25fbb7d792d86 Mon Sep 17 00:00:00 2001 From: soranjh Date: Fri, 30 May 2025 10:37:57 -0400 Subject: [PATCH 39/62] fix format --- demonstrations/tutorial_dmet_embedding.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index eaed05127c..c327d5cd9e 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -441,7 +441,7 @@ # converged impurity Hamiltonian with a quantum algorithm. # # Conclusion -# ^^^^^^^^^^^^^^ +# ^^^^^^^^^^ # The density matrix embedding theory is a robust method designed to tackle simulation of complex # systems by partitioning them into manageable subsystems. It is particularly well suited for # studying the ground state properties of strongly correlated materials and molecules. DMET offers a @@ -454,7 +454,7 @@ # application to a wide range of strongly correlated molecular and periodic systems underscores its # power and versatility in electronic structure theory, paving the way for hybrid quantum-classical # simulations of challenging materials. [#DMETQC]_ - +# # # References # ---------- From d543b4ccad8e099c01e1c8519d2baae87be049c6 Mon Sep 17 00:00:00 2001 From: soranjh Date: Fri, 30 May 2025 11:44:22 -0400 Subject: [PATCH 40/62] update metadata --- demonstrations/tutorial_dmet_embedding.metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demonstrations/tutorial_dmet_embedding.metadata.json b/demonstrations/tutorial_dmet_embedding.metadata.json index 4e6c24f060..08050b5713 100644 --- a/demonstrations/tutorial_dmet_embedding.metadata.json +++ b/demonstrations/tutorial_dmet_embedding.metadata.json @@ -29,7 +29,7 @@ "id": "SWouters", "type": "article", "title": "A practical guide to density matrix embedding theory in quantum chemistry", - "authors": "Wouters, Sebastian and Jim{\'e}nez-Hoyos, Carlos A and Sun, Qiming and Chan, Garnet K-L", + "authors": "Wouters, Sebastian and Jimenez-Hoyos, Carlos A and Sun, Qiming and Chan, Garnet K-L", "journal": "", "year": "2016", "url": "https://arxiv.org/pdf/1603.08443" From f77f1fe9ed29c66968b05a7724756c3875eca8f5 Mon Sep 17 00:00:00 2001 From: soranjh Date: Fri, 30 May 2025 12:59:25 -0400 Subject: [PATCH 41/62] update intro --- demonstrations/tutorial_dmet_embedding.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index c327d5cd9e..8aae5e3669 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -1,27 +1,28 @@ r"""Density Matrix Embedding Theory (DMET) ========================================= 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 +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 because of its mean field nature. -As a result, researchers often turn to wavefunction-based methods, such as configuration interaction -or coupled cluster, which provide better accuracy but come at a -significantly higher computational cost. +electron correlation effects found in strongly correlated materials because of its mean field +nature. As a result, researchers often turn to wavefunction-based methods, such as configuration +interaction or coupled cluster, 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 +materials accurately and efficiently. The core idea behind embedding methods is to divide the system into two parts: an impurity which is a strongly correlated subsystem that requires a high accuracy -description and an environment which can be treated with more approximate but computationally efficient level of theory. +description and an environment which can be treated with a more approximate but computationally +efficient level of theory. .. figure:: ../_static/demo_thumbnails/opengraph_demo_thumbnails/OGthumbnail_qdet_embedding.png :align: center :width: 70% :target: javascript:void(0) """ -# In this demo, we will focus on Density matrix embedding theory (DMET) [#SWouters]_, a wavefunction -# based approach embedding the ground state density matrix. We provide a brief introduction of the +# In this demo, we will focus on density matrix embedding theory (DMET) [#SWouters]_, a wavefunction +# based approach that embeds the ground state density matrix. We provide a brief introduction of the # method and demonstrate how to run DMET calculations to construct a Hamiltonian that can be used in -# quantum algorithms. +# quantum algorithms using PennyLane. ############################################# # Theory From 1bd2eacf795d8a3d655ef14748a1daa328beefed Mon Sep 17 00:00:00 2001 From: soranjh Date: Fri, 30 May 2025 13:43:06 -0400 Subject: [PATCH 42/62] format code --- demonstrations/tutorial_dmet_embedding.py | 82 ++++++++++++----------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index 8aae5e3669..83a698e089 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -19,12 +19,13 @@ :width: 70% :target: javascript:void(0) """ -# In this demo, we will focus on density matrix embedding theory (DMET) [#SWouters]_, a wavefunction -# based approach that embeds the ground state density matrix. We provide a brief introduction of the -# method and demonstrate how to run DMET calculations to construct a Hamiltonian that can be used in -# quantum algorithms using PennyLane. ############################################# +# In this demo, we will learn density matrix embedding theory (DMET) [#SWouters]_, a +# wavefunction-based approach that embeds the ground state density matrix. We provide a brief +# introduction of the method and demonstrate how to run DMET calculations to construct a Hamiltonian +# that can be used in quantum algorithms using PennyLane. +# # Theory # ------ # The wave function for an embedded system composed of an impurity and an environment can be @@ -78,7 +79,7 @@ # 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 a toy system with 8 Hydrogen atoms. -# We use the programs PySCF [#pyscf]_ and libDMET [#libdmet]_ [#libdmet2]_ which can be installed +# We use the programs PySCF [#pyscf]_ and libDMET [#libdmet, #libdmet2]_ which can be installed # with # # .. code-block:: python @@ -104,21 +105,21 @@ # cell.unit = 'Angstrom' # cell.a = ''' 12.0 0.0 0.0 # 0.0 12.0 0.0 -# 0.0 0.0 12.0 ''' # lattice vectors for unit cell +# 0.0 0.0 12.0 ''' # lattice vectors of the unit cell # -# cell.atom = ''' H 0.0 0.0 0.0 -# H 0.0 0.0 0.75 -# H 0.0 0.0 3.0 -# H 0.0 0.0 3.75 -# H 0.0 0.0 4.5 -# H 0.0 0.0 5.25 -# H 0.0 0.0 7.5 -# H 0.0 0.0 8.25''' # coordinates of atoms in unit cell +# cell.atom = ''' H 0.0 0.0 0.0 +# H 0.0 0.0 0.75 +# H 0.0 0.0 3.0 +# H 0.0 0.0 3.75 +# H 0.0 0.0 4.5 +# H 0.0 0.0 5.25 +# H 0.0 0.0 7.5 +# H 0.0 0.0 8.25''' # coordinates of atoms in unit cell # # cell.basis = '321g' # cell.build() # -# kmesh = [1, 1, 1] # number of k-points in xyz direction +# kmesh = [1, 1, 1] # number of k-points in xyz direction # # lattice = lattice.Lattice(cell, kmesh) # filling = cell.nelectron / (lattice.nscsites * 2.0) @@ -133,13 +134,12 @@ # .. code-block:: python # # gdf = df.GDF(cell, kpts) -# gdf._cderi_to_save = 'gdf_ints.h5' # output file for the integral tensor -# gdf.build() # compute the integrals -# +# gdf._cderi_to_save = 'gdf_ints.h5' # output file for the integrals +# gdf.build() # compute the integrals # kmf = scf.KRHF(cell, kpts, exxdiv=None).density_fit() -# kmf.with_df = gdf # use density-fitted integrals +# kmf.with_df = gdf # use density-fitted integrals # kmf.with_df._cderi = 'gdf_ints.h5' # input file for the integrals -# kmf.kernel() # run Hartree-Fock +# kmf.kernel() # run Hartree-Fock # # This provides us with an approximate description of the whole system. # @@ -248,10 +248,10 @@ # basis_k = lattice.R2k_basis(basis) # basis in k-space # # solver_args = {"nelec": min((lattice.ncore+lattice.nval)*2, lattice.nkpts*cell.nelectron), \ -# "dm0": dmet.foldRho_k(scf_result["rho_k"], basis_k)} +# "dm0": dmet.foldRho_k(scf_result["rho_k"], basis_k)} # # rho_emb, energy_emb, imp_ham, dmu = dmet.SolveImpHam_with_fitting(lattice, filling_imp, -# imp_ham, basis, solver, solver_args=solver_args) +# imp_ham, basis, solver, solver_args=solver_args) # # last_dmu += dmu # solver_info = [solver, solver_args] @@ -284,7 +284,7 @@ # dmet.transformResults(rho_emb, energy_emb, basis, imp_ham, \ # lattice=lattice, last_dmu=last_dmu, int_bath=True, \ # solver=solver_info[0], solver_args=solver_info[1]) -# energy_imp_fci = energy_imp * lattice.nscsites # Energy of impurity at FCI level +# energy_imp_fci = energy_imp * lattice.nscsites # energy of impurity at FCI level # energy_imp_scf = get_E_dmet_HF(basis, lattice, imp_ham, last_dmu, solver_info[0]) # energy = kmf.e_tot - kmf.energy_nuc() - energy_imp_scf + energy_imp_fci # @@ -317,7 +317,8 @@ # Initial correlation potential # """ # -# v_cor = dmet.VcorLocal(restricted=True, bogoliubov=False, nscsites=lattice.nscsites, idx_range=lattice.imp_idx) +# v_cor = dmet.VcorLocal(restricted=True, bogoliubov=False, +# nscsites=lattice.nscsites, idx_range=lattice.imp_idx) # v_cor.assign(np.zeros((2, lattice.nscsites, lattice.nscsites))) # return v_cor # @@ -355,14 +356,14 @@ # # import libdmet.dmet.Hubbard as dmet # -# max_iter = 10 # maximum number of iterations -# e_old = 0.0 # initial value of energy -# v_cor = initialize_vcor(lattice) # 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 +# max_iter = 10 # maximum number of iterations +# e_old = 0.0 # initial value of energy +# v_cor = initialize_vcor(lattice) # 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 # # Now we set up the iterations in a loop. We must note that defining an impurity which is a fragment # of the unit cell, necessitates readjusting of the filling value for solution of impurity @@ -377,12 +378,15 @@ # rho, mu, scf_result, imp_ham, basis = construct_impurity_hamiltonian(lattice, # v_cor, filling, mu, last_dmu) # construct impurity Hamiltonian # filling_imp = filling * 0.5 -# rho_emb, energy_emb, imp_ham, last_dmu, solver_info = solve_impurity_hamiltonian(lattice, cell, -# basis, imp_ham, filling_imp, last_dmu, scf_result) # solve impurity Hamiltonian +# # solve impurity Hamiltonian +# rho_emb, energy_emb, imp_ham, last_dmu, solver_info = solve_impurity_hamiltonian(lattice, +# cell, basis, imp_ham, filling_imp, last_dmu, scf_result) +# # include the environment interactions # energy_imp, energy = solve_full_system(lattice, rho_emb, energy_emb, basis, imp_ham, -# last_dmu, solver_info) # include the environment interactions +# last_dmu, solver_info) +# # fit correlation potential # v_cor, dVcor_per_ele = fit_correlation_potential(rho_emb, -# lattice, basis, v_cor) # fit correlation potential +# lattice, basis, v_cor) # # dE = energy_imp - e_old # e_old = energy_imp @@ -411,7 +415,7 @@ # 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 +# h2 = ao2mo.restore(1, h2, norb) # get the correct shape based on permutation symmetry # # Now we generate the qubit Hamiltonian in PennyLane. # @@ -421,7 +425,7 @@ # from pennylane.qchem import one_particle, two_particle, observable # # t = one_particle(h1[0]) -# v = two_particle(np.swapaxes(h2, 1, 3)) # Swap to physicist's notation +# v = two_particle(np.swapaxes(h2, 1, 3)) # swap to physicist's notation # qubit_op = observable([t,v], mapping="jordan_wigner") # # This Hamiltonian can be used in a proper quantum algorithm such as Quantum Phase Estimation (QPE). @@ -429,6 +433,8 @@ # For simplicity, we just diagonalize the Hamiltonian to get the eigenvalues and show that the # lowest eigenvalue matches the energy we obtained for the embedded system above. # +# .. code-block:: python +# # eigval_qubit = qml.eigvals(qml.SparseHamiltonian(qubit_op.sparse_matrix(), wires = qubit_op.wires)) # print("eigenvalue from PennyLane: ", eigval_qubit) # print("embedding energy: ", energy_emb) From fe520f8e2098bc75da7f70fa367b63367e512e09 Mon Sep 17 00:00:00 2001 From: soranjh Date: Fri, 30 May 2025 14:42:50 -0400 Subject: [PATCH 43/62] update implementation --- _static/demonstration_assets/dmet/H8.png | Bin 0 -> 8517 bytes demonstrations/tutorial_dmet_embedding.py | 98 ++++++++++++---------- 2 files changed, 52 insertions(+), 46 deletions(-) create mode 100644 _static/demonstration_assets/dmet/H8.png diff --git a/_static/demonstration_assets/dmet/H8.png b/_static/demonstration_assets/dmet/H8.png new file mode 100644 index 0000000000000000000000000000000000000000..a38cffc319fed8e0a28b7351dd7e0c9ea22586d2 GIT binary patch literal 8517 zcmd^l`9IX(7r*K)6%xvf>^o6o-rus5={bd0K1t*23>XVo7?5&vqs3pwqXqV7hlcavy2C7@Onq7Pt!zSP#KEf-> z^;pnCg*tBwA9}lAYXE$#Cddn*tR}Y_aG)u2FN7aJz zhj7!41P&ht6?<1lt6u+;;DOx**38op-!6SvZu5D$9lkE%9l1r|uxyW2RaIvLUW$@M zm-ho8H#hg9>^&NKdV25dTT$dbvU-#%WF2c!I2T!$XxMRwtm`SZ{WpH;|KDNDY+ZF* zST?(<4`#EP<(Nh>3*<~jQ=U7XhK_DzXy}QJ4LCm;DCW9{*l*&L`okk2fco*{sez$k zPM?Cqnln3dQd{!mQuyyT8Jn9Tv9Ynww6&XCo;c|x#K&i&03q>j^Hm2?0Iv2mlhsH& zV1~@591jl<)X&emu0A7q=f5H1GJ+t@b=NC3Cr!=Ud-q;i02F%Ak8_~sAHZfW!jjXF znwpw7U0hr;SJS-DB&4OKkt8=zr^Av?SI4R)1RYn3qlt}+)701RS@E&jZV->g^z^K+ zujdsNMdu}paeF_Tm>1{#BlQ#atmw;^cQ~AmBKzPGrtH{^GzjR{0?vSDUwDSW4;7fg%s~3`}d` z>@uY#PG-7%D=SXK^9yWsevLcIOIAnQRXAE-au;hAEel_ieAv1akKu>i;7U>p(0iX2 z_h7Oml(LrkfglJZaOZ}ln1Zu+x;tK#o8H{qT-IO?2ZC`dKAv&O3c>(m8o$4}o1tb_ zhhCu;ZglBH?Q;WZtkXe{@pZ_|%#Q`NY59k`Zgakw=RNmb{xUnsz7Ds$Bl%FPCgk_n z2j7ue;bN=jnoeqRLPA0rTiQYP_Tgh=#)-LZt1IJ)mB)XCvYMiqvqYFC!D^Bx3fRxuXvqhbILvHk}qGg zaiyPj2bdDn*EcsmZ@-jKp!;35@tBQvE94-Ng_lOgLqYw;eG#NdAMM6#v)0d9B%>8a z2xQUUX3zUPUIGS#`7TA$vGgI_Q!2AW+vHvUCTE|z>ySE+8m{e3$Ho?#j?WEy$A4kErX1>C0d$gG@q_uwP zxGq!B(3p}AYf!9OhqCf{@##b*L~3%<%vT;nMp9=d536!ub~`B=vGUyvglnesT&Zms zz9nY4mMG1@WZZx@#asW-$hCd(F$sKWb6oA+Y3}1wy#}Rn#!Kht=d;QOW`jaWT-F;D zCHB;9UpKr90PV<0J=+9223NcWaVN=i9*jkYE=IV`HiVtEOv??j-j0?FK9EIRf|4q0 z__RvhB-#Q{UQQou8(KUa^;Dx`a^xNpe2wT*`jZ7gv1(bNFL7y@W5t|9`$L(?FP2` zW(5QXXP-nF1|Op4mYjnunER{~+9AT*({T-aE6=Hg{=jQD*-q5yYHJJ65eFR3mX7OFeXy6E7S#;#aT$~f>|9gT(N$>hcjt>g z^~7IFuv8RELBN^P4Zo_RK{a<$!LifrdG_Ih1vt70-i=bIrFM5#i>cjm-dv;GF+sy+ zI7r`vghWJsBjaH=@OA6k>kA5VLD^K7TVhY~%F#t`{Q(Nm)Xz*+@pPg`n>N0e(H@KS zV4`xLmiC(4qvPY_{h1#2wGo@Z|GlE#UMWgIb~L?f>bB_7nKLQBd2CmKBNUvLmgbut z0EcJxuwQZ^b_+DT=XP9zjabBj^MvXXa^$)usBPxk+_i~B4MJXFQ{aGjbf+ErC$?UgB`<&vISee2lLa$qiU73O=&ANL|JC6JO6o2-n*7 zZ7sGY#1lf_vc##AYEG4ZMjdVxiE z$ne=fMn^}JI_S{L7l{(M(fA7m~1BpBV&QrsTA z{P#{$Pr%7~5$OO7#(a;}Unps09zo~+o)(Qj!uw>rzShPaIaEB)MeAv5_OgDCa?TBi zqH5a%T2T`^>xt61$Lc=FYs_%1@!@GH)sYK;(4clfX{nnzSfMyvOjh) zYQeB!lI-k1>#Nq5*X1=yOirf1IE~C8H51yxy*sZpjKs}0e9O4o*>&)r z*j|Q@+gi;s)#7iQa1Y^Fzjcf6J`2lIcLr>Cvf`5F6f-zKAgBzxDbSnm@Na*DB&|LL4~&a8+J*$OANuzEe(`+c?G3TF_S-KNk~H#hZ(zRo-z>|OBGSsQ8WI=;qE2x z`z-qVL5N+-DC4=LW;kDzjA%lmooz!15Sa#r<~UV)12#+^^4!fjaholu7KtOH@nRly znO+m898&^)SO}6`F^aBt91zSeLS*JT;2S;q_gtLxzS=4tPlJeKzCC|%2te*9r(UYF z+R8$3&bzIGiVLIFd!G%gt(DKcQ@))SWDt|kn|VqImf6L75Q_AjqVW@J?Huqg$`R)Sq|(m`}Qh%-)>MY@IdhL;7`&kT-!Yx(#d*S!#MNxLQnC1 z+YN7VX4}c?f`MqIwdLOHZ3n*)!|%^ohz}~X|GKSN0IwH9v*5rMtWo7LMakFbPo)z+i{_|X%A^I@0R zym?*VJsI2U!wm;GAsV`aJMNR6g}N-Mv%!5zMxLIaiqYEVGAU7O2C$!=XOfKi-LY|$*bt9-^{6?q_SeYBlIg&HLSmxN zfg__r7G~GjGshbO>##Rxh}@K&(t^S2eV;fDsBzQ(WkJEWy=1okqCjPqEd!!nPDaB3 z%kM`j?%(R`6|xTfhF*P$!tjUs&(pm0$ZZi3PsJgfXbK;$bgPtotF7g0UH=eNvec90 z+oGT+0%MNyTs_v!41<0mmB>!~)^~7Nith5ov|H`cXQ$l>ZlYl+mSFIh4E9vzi?zf+c#l_l%-6%}*lI%q?rv!}4espXZYO{{wp%M==tgHt31d4REg`BcJ6U@NQ&vW8!W>gyBjOv1bc%+gX1b$|UG=ett z!AUC_Y+9reb#--k=&5l0Jx|PymBCWcYf*R&?)-3%x!_O|)`q`z<^yGZ`SyPgRj%iT z$Dy;J%-+-LBE^V~YV-TeR4yK`DHK+T?S@5qzr^ownO4gdD;C=6lH&H5D&~Jr3epzo z@ttGSgt5h#k?hU;orcwaKcRh@jfZ{Zo_~9PWEXdG;!q==fj8GToSW6wBK3Wi&_yow8z?`y9A~nDI7RZFhA8lB-&qlXAVL)Hu4mnZ2bUU=7WWe8n8E0qVQg z{Zlz!y)kRhG5D}|)dGNtNvA9d=DqjP!;zUPYAm%9G`)xWeYHuQ0h%+)mr`N`BXF`s zcw1s`fr!i_m8PjA@qI%*Ua3MWU?=00uI6jj>p3p=+D~s|TaC^%zv`xa` z2PmlCZW2KHaT6k*d1Lr@xi+s!P1WuVfvjfl3KXmZ`}O+GzK8@%^m(v>!&F@)az<5? zpa(po6Ii->C-aY8e@lpnbrsu4Yh3Z8q-)rq-dqRmcHYx|) zl$~Ayz!+q_j%COO4*PlNOTQP6_mI0_#J#JbWCtJo(eXawz!SH!yo!gG3Zu`c2IUoY zHUxN^(fO}q{l9eh5Y0+IE5Er|aX$>n%PRYc|} zvhST8Lyz`gW`a9jvuxLADBKP&EuD&8v_A07{FZ3q?FL`@0N(M7N!HsNR$N|NR|4rOyM5E72W;Rycz_*ddK)SV2(LY@T5x)5242cPj zt7$!l-d6W2xF;v?!9A@JC7|W98#%aY`L*rh%D_Rwf)?yZ?y`$W;R4Cr8@AWzp#%b1 zKb1KHP1Ics(4IF3JM|W=l2cFhGme-|gz$Bm6i0WDMJIqX-Qq>HbCnKu(+iK7j1?{& z?RgpUE}$&i*~_^e8%ZngD^oKEqr}Qc!DP>X*FAW`;$&@o^F~C5-ewG<&nzr8r?H~Q zVg9op0Afv9m_A=2nxxR6XhL{@Co->|&w(Nrp8)o+NgS^j;8qAmej=f!e!OR)TD zs_!HwfwC^7BY<8TPOL9%pI=x#O=X#=i`fj!q83{-xMD2ZFztEP?FKOpMh_jE+b(2if;W~+3dzgidvZATcd`uyAwSoW8=kF+HA z-}Dc@+P==sBdUNvJgGoSR>UR03tRVt1S=?q4T|>O8W5{)e(Tt z=Rf!uS!;!-X2yHRM!IGy4}|-KXeLcVbR}-V+Ti+1D{@z2W3$0Z)X$C0pSnb$;1$05 z!CgTtg8e(s%@@zs&5$g7-D)4!h%soT^@+^gixG0-^PsP&{;fy#Eo$m751#SOE=@aB z8Y3hq!+=I<_YxBV+Rj=mzsA+Xz}S4}(pcPyHjYgX3PrFTbK^Jl?i zrB}PwP0S3IohPfE3=yW~&*A_eNPyY>Wc9UNr6g$rcnzc1Z>3zzz1?v8{V16vzc_8?3fMLT_o~OPuO-55qOzk(Y|zBo8gnS@3Itym z_F&@u*o%JtSv}dPfVt@)gC-{@r<XHx%(iLTl`OWT;=BXfT0O#hXa}N%sMP}k%blacQ@- zL)wQw%hWhadMks1ujJ#$H!J(M1Y@Nb2?|PNZJvaqhF;A#*~q>=Eh>gKBWr7RtgDt_ zT^5^M+$&mG3bTi!W?n|X{_4N9rMjlZtm@M@#v$4@&xLb&C?^CxP=&hBDnJ~&AQHQO4Jpp#7KxFK@u48M-@jr#E7TYHV$$3K$gV1;*NvV&QBYO{e|_1_rEp z3cZrLd;30(m&f2JZzA4Qg-zn88$Cf*b@xwb=xMG(4r0hzjd<`>Ab{nsmZbjZ8&1B2@Wn#u2DU#v}!Jty$0*`*RG(0P5Hk7Tz-d3r7Cfl$77_|1~vx<${LB zMzHv425_C9jMTW&h+yc3fk)edxwtsw;!%2>m~QHGt@kM{BJzo?PfwA046~9nHh~ zj0>UmMK*bkZ~=lElORbLNx>K+ynIgO~5MJ$^wdz3HwwH{VRU-AWpOkDRXp>T|v) zCfd=~+1C>ITAc+pt_hGL=B6+h*YUxV+a$lR$8SD`E8ZHmq{*E+REMx!>)Z-)T{Q)g z|2srv$Y(!-ZP_I+I(Uvr+NRxZ4CWyYI|~J?Q3l*~A_8AeblBR+IPj>X3b!`2q*knl zI#^FkRC$-?`P*-uKHHk=xIcGOIdo0kV+uNx9TG+iR*t>3C)9gW9KLri>Lid~0x#Xr z+8*fty{>ABo}rUX6@Q#M)fzFH%Xl`xw$ZqP+34-{4)t!XUpfpF68V|W4NAx}RAAoT zvUhWQugZO;yuQ~>Hya!L=0kZ-sTbSYtb55sof9L8Gyt+c@>gW1i=-sIWP*rKe~Zqm zVT->_XUoTsdP zV%CAOJA7$I4t0bs?oKRQ`Ui*&C_JkwlZ_eju+P!hg>BpC`Mo`^0IhE0>kVGK5OZ$a z-`f+!4)V^1gy)s>t4E#0bblhRUYkvS_PbQz7T1{HUBsHl>&55*f>b~YArS>yzYyrG z+j6mb6|bHzDJ{J>S`m`dX~lG&rxt%*i&^HWsSZ1`A%^i8O{)B?mdEnl676fjd#T4S zEG-pFGSnXNGQ|xI5C2f11LN}a;@Un?#-CtsptwqXwZn8E?0k~5T6#oY;nS?RY6Xt{If4R7}8W|^hB`E$EoW(5PuT&7aACq)> z+sMeMCNOaSDY;Z{Wo4y!u+zEee!rl{r2AQAb|o^@8saMM`#C3m!9fHB-ETe)eM{bz zV}0n7-SK2DYq$22DBrAqII>c1%WK-vAe;kC)j;qwT?xwmrK-TJ((~n^Xyb7whwbiS zca49=&zDV2P4ENMoPAG>hrE?j{C~nXo5e$=Bs%@;v(Q^8$Y<7cqJ-7Rijua z_rElfOQ~g5wuMJyBzYc%Ax4pu<451>>h^}U zK~+J=?Dwad);Z9)O_`++EB}45YI^IAudDJ}csldn1z5+#1fT%hUQRQCJx4Sp)a2h} zC}gQ;%O_J@)qHXP{HU$1HNo*6<>s>c6K4Cdp!TO$4%A9KsYt7sUYs@nWQ$FIC}PtV zj4@$()M(q1GalV!;Qzh1;l2cRv-$p7r1)S$iC7ITN0mGIz+lQGcCv5t)&HpHFy68M xN#vvdCs^vrZ7weIA%c{DX94~%qSdD_sSLpdCfVLu;biM5G}ZJ}%b(hY{~wYP(6Rsk literal 0 HcmV?d00001 diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index 83a698e089..d6a2ee050c 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -28,7 +28,7 @@ # # Theory # ------ -# The wave function for an embedded system composed of an impurity and an environment can be +# The wavefunction for an embedded system composed of an impurity and an environment can be # represented as [#SWouters]_: # # .. math:: @@ -39,7 +39,7 @@ # :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 as: +# and rearrange the wavefunctions as: # # .. math:: # @@ -60,7 +60,7 @@ # \hat{H}_{emb} = \hat{P}^{\dagger} \hat{H} \hat{P}, # # where :math:`P = \sum_{\alpha \beta} | A_{\alpha} B_{\beta} \rangle \langle A_{\alpha} B_{\beta}|` -# is a projection operator. A key point about this representation is that the wave function, +# is a projection operator. A key point about this representation is that the wavefunction, # :math:`|\Psi \rangle`, is the ground state of both the full system Hamiltonian :math:`\hat{H}` and # the smaller embedded Hamiltonian :math:`\hat{H}_{\text{emb}}` [#Mineh]_. # @@ -76,11 +76,10 @@ # :math:`P`, which is used to construct the embedded Hamiltonian. Then, accurate methods such as # post-Hartree-Fock methods, exact diagonalisation, or accurate quantum algorithms are employed # to find the energy spectrum of the embedded Hamiltonian. The results are used to -# re-construct the projector and the process is repeated until the wave function converges. +# re-construct the projector and the process is repeated until the wavefunction converges. # -# Let's now take a look at the implementation of these steps for a toy system with 8 Hydrogen atoms. -# We use the programs PySCF [#pyscf]_ and libDMET [#libdmet, #libdmet2]_ which can be installed -# with +# Let's now take implement these steps for a linear chain of 8 Hydrogen atoms. We will use the +# programs PySCF [#pyscf]_ and libDMET [#libdmet, #libdmet2]_ which can be installed with # # .. code-block:: python # @@ -89,11 +88,17 @@ # # Constructing the system # ^^^^^^^^^^^^^^^^^^^^^^^ -# We begin by defining a finite system containing a hydrogen chain with 8 atoms using PySCF. -# This is done by creating a ``Cell`` object containing 8 Hydrogen atoms. The system is arranged -# with a central :math:`H_4` chain featuring a uniform 0.75 Å H-H bond length, flanked by two -# :math:`H_2` molecules at its termini. Then, we construct a ``Lattice`` object from the libDMET -# library, associating it with the defined cell. +# We begin by defining a finite system containing a hydrogen chain with 8 atoms using PySCF. This is +# done by creating a ``Cell`` object containing the Hydrogen atoms. We construct the system to have +# a central :math:`H_4` chain with a uniform :math:`0.75` Å :math:`H-H` bond length, flanked by two +# :math:`H_2` molecules at its termini. +# +# .. figure:: ../_static/demonstration_assets/dmet/H8.png +# :align: center +# :width: 70% +# :target: javascript:void(0) +# +# Then, we construct a ``Lattice`` object using libDMET and associate it with the defined cell. # # .. code-block:: python # @@ -119,7 +124,7 @@ # cell.basis = '321g' # cell.build() # -# kmesh = [1, 1, 1] # number of k-points in xyz direction +# kmesh = [1, 1, 1] # number of k-points in xyz direction # # lattice = lattice.Lattice(cell, kmesh) # filling = cell.nelectron / (lattice.nscsites * 2.0) @@ -145,12 +150,11 @@ # # Partitioning the orbital space # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -# Now that we have an approximate description of our system, we can start obtaining the impurity and -# bath orbitals. This requires the localization of the basis of orbitals. The use of localized basis -# provides a convenient way to understand the contribution of each atom to properties of the full -# system. We can use any localized basis such as molecular orbitals (MO) or intrinsic atomic -# orbitals (IAO) [#SWouters]_. Here, we rotate the one-electron and two-electron integrals into -# the IAO basis. +# Now that we have a full description of our system, we can start obtaining the impurity and +# bath orbitals. We will use a localized orbital basis which provides a convenient way to understand +# the contribution of each atom to the properties of the full system. We can use any localized basis +# such as molecular orbitals (MO) or intrinsic atomic orbitals (IAO) [#SWouters]_. Here, we rotate +# the one-electron and two-electron integrals into the IAO basis. # # .. code-block:: python # @@ -178,17 +182,17 @@ # lattice.set_val_virt_core(imp_idx, bath_idx, ncore) # # Now that we have a description of our impurity, bath and environment orbitals, we can implement -# the iterative process of DMET. +# our DMET simulation. # # Self-Consistent DMET # ^^^^^^^^^^^^^^^^^^^^ -# The DMET calculations are performed by repeating four steps iteratively: First construct an +# The DMET calculations are performed by repeating four steps iteratively: construct an # impurity Hamiltonian, solve the impurity Hamiltonian, compute the full system energy and finally # update the interactions between the impurity and its environment. To simplify the calculations, we -# create dedicated functions for each step and implement them in a self-consistent loop. Note that -# if we only perform one step of the iteration the process is referred to as single-shot DMET. +# create dedicated functions for each step and implement them in a self-consistent loop. If we only +# perform one iteration, the process is referred to as single-shot DMET. # -# We first need to construct the impurity Hamiltonian. +# We now construct the impurity Hamiltonian. # # .. code-block:: python # @@ -290,20 +294,23 @@ # # return energy_imp_fci, energy # -# Note here that the effect of environment included in this step is at the mean field level. So if -# we stop the iteration here, the results will be that of the single-shot DMET. +# Note here that the effect of the environment included in this step is at the mean field 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. To do that, a correlation potential is introduced to account for the interactions -# between the impurity and its environment, which can be represented as +# between the impurity and its environment, which can be represented in terms of creation, +# :math:`a^{\dagger}`, and annihilation , :math:`a`, operators as # # .. math:: # -# C_x = \sum_{kl} u_{kl}^{x}a_k^{\dagger}a_l +# C = \sum_{kl} u_{kl} a_k^{\dagger} a_l. # -# We start with an initial guess of zero for the :math:`u` here, 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. +# We start with an initial guess of zero for the coefficient matrix :math:`u` and optimize it by +# minimizing the difference between density matrices obtained from the mean field Hamiltonian and +# the impurity Hamiltonian. +# +# We define the following functions to initialize the correlation potential and optimize it. # # .. code-block:: python # @@ -344,12 +351,12 @@ # 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. +# the final results. # # We set up the 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. Also, since dividing the system into multiple fragments -# might lead to wrong number of electrons, we denfine and check a chemical potential :math:`\mu` +# might lead to wrong number of electrons, we define and check a chemical potential :math:`\mu` # as well. # # .. code-block:: python @@ -365,7 +372,7 @@ # mu = 0 # initial chemical potential # last_dmu = 0.0 # change in chemical potential # -# Now we set up the iterations in a loop. We must note that defining an impurity which is a fragment +# Now we set up the iterations in a loop. Note that defining an impurity which is a fragment # of the unit cell, necessitates readjusting of the filling value for solution of impurity # Hamiltonian. This filling value represents the average electron occupation, which scales # proportional to the fraction of the unit cell included, while taking into account the different @@ -399,11 +406,11 @@ # # Quantum DMET # ^^^^^^^^^^^^ -# Our implementation of DMET used FCI to accurately treat the impurity subsystem. The cost of using -# a high-level solver such as FCI increases exponentially with the system size which limits the -# number of orbitals we can have in the impurity. One way to solve this problem is to use a quantum -# algorithm as our accurate solver. We now convert our impurity Hamiltonian to a qubit Hamiltonian -# that can be used in a quantum algorithm using PennyLane. +# Our implementation of DMET used full configuration interaction (FCI) to accurately treat the +# impurity subsystem. The cost of using a high-level solver such as FCI increases exponentially with +# the system size which limits the number of orbitals we can have in the impurity. One way to solve +# this problem is to use a quantum algorithm as our accurate solver. We now convert our impurity +# Hamiltonian to a qubit Hamiltonian that can be used in a quantum algorithm using PennyLane. # # The hamiltonian object we generated above contains one-body and two-body integrals along with the # nuclear repulsion energy which can be accessed and used to construct the qubit Hamiltonian. We @@ -428,10 +435,9 @@ # v = two_particle(np.swapaxes(h2, 1, 3)) # swap to physicist's notation # qubit_op = observable([t,v], mapping="jordan_wigner") # -# This Hamiltonian can be used in a proper quantum algorithm such as Quantum Phase Estimation (QPE). -# -# For simplicity, we just diagonalize the Hamiltonian to get the eigenvalues and show that the -# lowest eigenvalue matches the energy we obtained for the embedded system above. +# This Hamiltonian can be used in a quantum algorithm such as Quantum Phase Estimation. For +# simplicity, we just diagonalize the Hamiltonian to get the eigenvalues and show that the lowest +# eigenvalue matches the energy we obtained for the embedded system above. # # .. code-block:: python # @@ -452,15 +458,15 @@ # The density matrix embedding theory is a robust method designed to tackle simulation of complex # systems by partitioning them into manageable subsystems. It is particularly well suited for # studying the ground state properties of strongly correlated materials and molecules. DMET offers a -# compelling alternative to dynamic quantum embedding schemes such as dynamic mean field theory -# (DMFT). By employing the density matrix for embedding instead of the Green's function and +# compelling alternative to dynamic quantum embedding schemes such as dynamic mean field theory. By +# employing the density matrix for embedding instead of the Green's function and # utilizing Schmidt decomposition to get a limited number of bath orbitals, DMET achieves a # significant reduction in computational resources. Furthermore, a major strength lies in its # compatibility with quantum algorithms, enabling the accurate study of smaller, strongly correlated # subsystems on quantum computers while the environment is studied classically. Its successful # application to a wide range of strongly correlated molecular and periodic systems underscores its # power and versatility in electronic structure theory, paving the way for hybrid quantum-classical -# simulations of challenging materials. [#DMETQC]_ +# simulations of challenging materials [#DMETQC]_. # # # References From aeef96999f8d2d8c6b4ec0927c179548b2d9553a Mon Sep 17 00:00:00 2001 From: soranjh Date: Fri, 30 May 2025 14:54:56 -0400 Subject: [PATCH 44/62] update refs --- demonstrations/tutorial_dmet_embedding.py | 31 +++++++++++++---------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index d6a2ee050c..35cb8738c6 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -473,29 +473,32 @@ # ---------- # # .. [#SWouters] -# Sebastian Wouters, Carlos A. Jiménez-Hoyos, *et al.*, -# "A practical guide to density matrix embedding theory in quantum chemistry." -# `ArXiv `__. +# S. Wouters, C. A. Jiménez-Hoyos, *et al.*, +# "A practical guide to density matrix embedding theory in quantum chemistry", +# `arXiv:1603.08443 `__. # # .. [#Mineh] # Lana Mineh, Ashley Montanaro, -# "Solving the Hubbard model using density matrix embedding theory and the variational quantum eigensolver." -# `ArXiv `__. +# "Solving the Hubbard model using density matrix embedding theory and the variational quantum eigensolver", +# `arXiv:2108.08611 `__. # # .. [#pyscf] -# Qiming Sun, Xing Zhang, *et al.*, "Recent developments in the PySCF program package." -# `ArXiv `__. +# Q. Sun, X. Zhang, *et al.*, +# "Recent developments in the PySCF program package", +# `arXiv:2002.12531 `__. # # .. [#libdmet] -# Zhi-Hao Cui, Tianyu Zhu, *et al.*, "Efficient Implementation of Ab Initio Quantum Embedding in Periodic Systems: Density Matrix Embedding Theory." -# `ArXiv `__. +# Z. Cui, T. Zhu, *et al.*, +# "Efficient Implementation of Ab Initio Quantum Embedding in Periodic Systems: Density Matrix Embedding Theory", +# `arXiv:1909.08596 `__. # # .. [#libdmet2] -# Tianyu Zhu, Zhi-Hao Cui, *et al.*, "Efficient Formulation of Ab Initio Quantum Embedding in Periodic Systems: Dynamical Mean-Field Theory." -# `ArXiv `__. -# +# T. Zhu, Z. Cui, *et al.*, +# "Efficient Formulation of Ab Initio Quantum Embedding in Periodic Systems: Dynamical Mean-Field Theory", +# `arXiv:1909.08592 `__. # # .. [#DMETQC] -# Changsu Cao,Jinzhao Sun, *et al.*, "Ab initio simulation of complex solids on a quantum computer with orbital-based multifragment density matrix embedding" -# `ArXiv `__. +# C. Cao, J. Sun, *et al.*, +# "Ab initio simulation of complex solids on a quantum computer with orbital-based multifragment density matrix embedding", +# `arXiv:2209.03202 `__. # From 0d0f2d80472060dd1a42c051c968ebb235203248 Mon Sep 17 00:00:00 2001 From: soranjh Date: Fri, 30 May 2025 15:37:12 -0400 Subject: [PATCH 45/62] update format --- demonstrations/tutorial_dmet_embedding.py | 25 ++++++++--------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index 35cb8738c6..fae59b0a27 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -435,23 +435,14 @@ # v = two_particle(np.swapaxes(h2, 1, 3)) # swap to physicist's notation # qubit_op = observable([t,v], mapping="jordan_wigner") # -# This Hamiltonian can be used in a quantum algorithm such as Quantum Phase Estimation. For -# simplicity, we just diagonalize the Hamiltonian to get the eigenvalues and show that the lowest -# eigenvalue matches the energy we obtained for the embedded system above. -# -# .. code-block:: python -# -# eigval_qubit = qml.eigvals(qml.SparseHamiltonian(qubit_op.sparse_matrix(), wires = qubit_op.wires)) -# print("eigenvalue from PennyLane: ", eigval_qubit) -# print("embedding energy: ", energy_emb) -# -# 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 the ``solve_full_system`` function. The qubit -# Hamiltonian is particularly relevant for a hybrid version of DMET, where classical mean field -# calculations are coupled with a quantum algorithm for the self-consistent solver. To further -# reduce the quantum resources, an alternative strategy will be using a classical solver for the -# iterative self-consistency between the impurity and the environment and treat the resulting -# converged impurity Hamiltonian with a quantum algorithm. +# This Hamiltonian can be used in a quantum algorithm such as quantum phase estimation. We can get +# ground state energy for the system by solving for the full system as done above in the +# self-consistency loop using the ``solve_full_system`` function. The qubit Hamiltonian is +# particularly relevant for a hybrid version of DMET, where classical mean field calculations are +# coupled with a quantum algorithm for the self-consistent solver. To further reduce the quantum +# resources, an alternative strategy will be using a classical solver for the iterative +# self-consistency between the impurity and the environment and treat the resulting converged +# impurity Hamiltonian with a quantum algorithm. # # Conclusion # ^^^^^^^^^^ From 48f249750e49483a656d3a4c2c629b0b69cb9832 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan Date: Mon, 2 Jun 2025 09:29:11 -0400 Subject: [PATCH 46/62] Modified variable names --- demonstrations/tutorial_dmet_embedding.py | 76 +++++++++++------------ 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index fae59b0a27..85ba9a2f3f 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -108,9 +108,9 @@ # # cell = gto.Cell() # cell.unit = 'Angstrom' -# cell.a = ''' 12.0 0.0 0.0 -# 0.0 12.0 0.0 -# 0.0 0.0 12.0 ''' # lattice vectors of the unit cell +# cell.a = ''' 15.0 0.0 0.0 +# 0.0 15.0 0.0 +# 0.0 0.0 15.0 ''' # lattice vectors of the unit cell # # cell.atom = ''' H 0.0 0.0 0.0 # H 0.0 0.0 0.75 @@ -128,7 +128,6 @@ # # lattice = lattice.Lattice(cell, kmesh) # filling = cell.nelectron / (lattice.nscsites * 2.0) -# kpts = lattice.kpts # # # Performing mean field calculations @@ -138,10 +137,10 @@ # # .. code-block:: python # -# gdf = df.GDF(cell, kpts) +# gdf = df.GDF(cell, lattice.kpts) # gdf._cderi_to_save = 'gdf_ints.h5' # output file for the integrals # gdf.build() # compute the integrals -# kmf = scf.KRHF(cell, kpts, exxdiv=None).density_fit() +# kmf = scf.KRHF(cell, lattice.kpts, exxdiv=None).density_fit() # kmf.with_df = gdf # use density-fitted integrals # kmf.with_df._cderi = 'gdf_ints.h5' # input file for the integrals # kmf.kernel() # run Hartree-Fock @@ -160,10 +159,10 @@ # # from libdmet.basis_transform import make_basis # -# c_ao_iao, _, _ = make_basis.get_C_ao_lo_iao( +# ao_to_iao_transform, _, _ = make_basis.get_C_ao_lo_iao( # lattice, kmf, minao="MINAO", full_return=True) -# c_ao_lo = lattice.symmetrize_lo(c_ao_iao) -# lattice.set_Ham(kmf, gdf, c_ao_lo, eri_symmetry=4) # rotate to IAO basis +# ao_to_lo_transform = lattice.symmetrize_lo(ao_to_iao_transform) +# lattice.set_Ham(kmf, gdf, ao_to_lo_transform, eri_symmetry=4) # rotate to IAO basis # # Next, we identify 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 @@ -174,12 +173,11 @@ # # from libdmet.lo.iao import get_labels, get_idx # -# aoind = cell.aoslice_by_atom() -# labels, val_labels, virt_labels = get_labels(cell, minao="MINAO") +# orb_labels, val_labels, virt_labels = get_labels(cell, minao="MINAO") # imp_idx = get_idx(val_labels, atom_num=[2,3,4,5]) # bath_idx = get_idx(virt_labels, atom_num=[2,3,4,5], offset=len(val_labels)) -# ncore = [] -# lattice.set_val_virt_core(imp_idx, bath_idx, ncore) +# core_idx = [] +# lattice.set_val_virt_core(imp_idx, bath_idx, core_idx) # # Now that we have a description of our impurity, bath and environment orbitals, we can implement # our DMET simulation. @@ -215,9 +213,9 @@ # basis: rotation matrix for embedding basis # """ # -# rho, mu, scf_result = dmet.HartreeFock(lattice, v_cor, filling, mu, +# rho, mu, scf_result = dmet.HartreeFock(lattice, v_corr, filling, mu, # ires=True) -# imp_ham, _, basis = dmet.ConstructImpHam(lattice, rho, v_cor, int_bath=int_bath) +# imp_ham, _, basis = dmet.ConstructImpHam(lattice, rho, v_corr, int_bath=int_bath) # imp_ham = dmet.apply_dmu(lattice, imp_ham, basis, last_dmu) # # return rho, mu, scf_result, imp_ham, basis @@ -314,7 +312,7 @@ # # .. code-block:: python # -# def initialize_vcor(lattice): +# def initialize_vcorr(lattice): # r"""A function to initialize the correlation potential # # Args: @@ -324,31 +322,31 @@ # Initial correlation potential # """ # -# v_cor = dmet.VcorLocal(restricted=True, bogoliubov=False, +# v_corr = dmet.VcorLocal(restricted=True, bogoliubov=False, # nscsites=lattice.nscsites, idx_range=lattice.imp_idx) -# v_cor.assign(np.zeros((2, lattice.nscsites, lattice.nscsites))) -# return v_cor +# v_corr.assign(np.zeros((2, lattice.nscsites, lattice.nscsites))) +# return v_corr # -# def fit_correlation_potential(rho_emb, lattice, basis, v_cor): +# def fit_correlation_potential(rho_emb, lattice, basis, v_corr): # r"""A function to solve impurity Hamiltonian # # Args: # rho_emb: density matrix for embedded system # lattice: Lattice object containing information about the system # basis: rotation matrix for embedding basis -# v_cor: correlation potential +# v_corr: correlation potential # # Returns: -# v_cor: correlation potential -# dVcor_per_ele: change in correlation potential per electron +# v_corr: correlation potential +# dVcorr_per_ele: change in correlation potential per electron # """ # -# vcor_new, err = dmet.FitVcor(rho_emb, lattice, basis, \ -# v_cor, beta=np.inf, filling=filling, MaxIter1=300, MaxIter2=0) +# vcorr_new, _ = dmet.FitVcor(rho_emb, lattice, basis, \ +# v_corr, 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 +# dVcorr_per_ele = np.max(np.abs(vcorr_new.param - v_corr.param)) +# v_corr.update(vcorr_new.param) +# return v_corr, dVcorr_per_ele # # Now, we have defined all the ingredients of DMET. We can set up the self-consistency loop to get # the final results. @@ -363,11 +361,11 @@ # # import libdmet.dmet.Hubbard as dmet # -# max_iter = 10 # maximum number of iterations +# max_iter = 20 # maximum number of iterations # e_old = 0.0 # initial value of energy -# v_cor = initialize_vcor(lattice) # 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 +# v_corr = initialize_vcorr(lattice)# initial value of correlation potential +# dVcorr_per_ele = None # initial value of correlation potential per electron +# vcorr_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 @@ -383,7 +381,7 @@ # # for i in range(max_iter): # rho, mu, scf_result, imp_ham, basis = construct_impurity_hamiltonian(lattice, -# v_cor, filling, mu, last_dmu) # construct impurity Hamiltonian +# v_corr, filling, mu, last_dmu) # construct impurity Hamiltonian # filling_imp = filling * 0.5 # # solve impurity Hamiltonian # rho_emb, energy_emb, imp_ham, last_dmu, solver_info = solve_impurity_hamiltonian(lattice, @@ -392,12 +390,12 @@ # energy_imp, energy = solve_full_system(lattice, rho_emb, energy_emb, basis, imp_ham, # last_dmu, solver_info) # # fit correlation potential -# v_cor, dVcor_per_ele = fit_correlation_potential(rho_emb, -# lattice, basis, v_cor) +# v_corr, dVcorr_per_ele = fit_correlation_potential(rho_emb, +# lattice, basis, v_corr) # # dE = energy_imp - e_old # e_old = energy_imp -# if dVcor_per_ele < vcor_tol and abs(dE) < energy_tol: +# if dVcorr_per_ele < vcorr_tol and abs(dE) < energy_tol: # print("DMET Converged") # print("DMET Energy per cell: ", energy) # break @@ -431,9 +429,9 @@ # import pennylane as qml # from pennylane.qchem import one_particle, two_particle, observable # -# 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") +# one_elec = one_particle(h1[0]) +# two_elec = two_particle(np.swapaxes(h2, 1, 3)) # swap to physicist's notation +# qubit_op = observable([one_elec,two_elec], mapping="jordan_wigner") # # This Hamiltonian can be used in a quantum algorithm such as quantum phase estimation. We can get # ground state energy for the system by solving for the full system as done above in the From 2fdee44a533f0f45eec79d7dca40c757d2180a10 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan Date: Fri, 6 Jun 2025 10:20:45 -0400 Subject: [PATCH 47/62] Addressed comments --- demonstrations/tutorial_dmet_embedding.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index 85ba9a2f3f..3c27617538 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -57,14 +57,14 @@ # # .. math:: # -# \hat{H}_{emb} = \hat{P}^{\dagger} \hat{H} \hat{P}, +# \hat{H}_{\text{emb}} = P^{\dagger} \hat{H} P, # # where :math:`P = \sum_{\alpha \beta} | A_{\alpha} B_{\beta} \rangle \langle A_{\alpha} B_{\beta}|` # is a projection operator. A key point about this representation is that the wavefunction, # :math:`|\Psi \rangle`, is the ground state of both the full system Hamiltonian :math:`\hat{H}` and # the smaller embedded Hamiltonian :math:`\hat{H}_{\text{emb}}` [#Mineh]_. # -# Note that the Schmidt decomposition requires apriori knowledge of the wavefunction. To alleviate +# Note that the Schmidt decomposition requires a priori knowledge of the wavefunction. To alleviate # this, DMET operates through a systematic iterative approach, starting with a mean field description # of the wavefunction and refining it through feedback from solution of the impurity Hamiltonian. # @@ -244,7 +244,7 @@ # imp_ham: impurity Hamiltonian # last_dmu: change in chemical potential from last iterations # solver_info: a list containing information about the solver -# """ +# """ # # solver = dmet.impurity_solver.FCI(restricted=True, tol=1e-8) # impurity solver # basis_k = lattice.R2k_basis(basis) # basis in k-space @@ -298,7 +298,7 @@ # In the self-consistent DMET, the interaction between the environment and the impurity is improved # iteratively. To do that, a correlation potential is introduced to account for the interactions # between the impurity and its environment, which can be represented in terms of creation, -# :math:`a^{\dagger}`, and annihilation , :math:`a`, operators as +# :math:`a^{\dagger}`, and annihilation, :math:`a`, operators as # # .. math:: # @@ -470,7 +470,7 @@ # Lana Mineh, Ashley Montanaro, # "Solving the Hubbard model using density matrix embedding theory and the variational quantum eigensolver", # `arXiv:2108.08611 `__. -# +# # .. [#pyscf] # Q. Sun, X. Zhang, *et al.*, # "Recent developments in the PySCF program package", From cb25280c4bbac96e03ef89bf4a04c3708d8367f9 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan Date: Mon, 9 Jun 2025 11:43:25 -0400 Subject: [PATCH 48/62] fixed reference --- 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 3c27617538..ad8a8a12ab 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -79,7 +79,7 @@ # re-construct the projector and the process is repeated until the wavefunction converges. # # Let's now take implement these steps for a linear chain of 8 Hydrogen atoms. We will use the -# programs PySCF [#pyscf]_ and libDMET [#libdmet, #libdmet2]_ which can be installed with +# programs PySCF [#pyscf]_ and libDMET [#libdmet]_ #libdmet2]_ which can be installed with # # .. code-block:: python # From a6aa1c7abe08ee7801d0b48023a5ef90d703c111 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan Date: Mon, 9 Jun 2025 12:05:52 -0400 Subject: [PATCH 49/62] fixed reference --- 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 ad8a8a12ab..1b50f1f006 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -79,7 +79,7 @@ # re-construct the projector and the process is repeated until the wavefunction converges. # # Let's now take implement these steps for a linear chain of 8 Hydrogen atoms. We will use the -# programs PySCF [#pyscf]_ and libDMET [#libdmet]_ #libdmet2]_ which can be installed with +# programs PySCF [#pyscf]_ and libDMET [#libdmet]_ [#libdmet2]_ which can be installed with # # .. code-block:: python # From 1123a9b762a78ea16178fb05796d2b4623c6ecdc Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:02:12 -0400 Subject: [PATCH 50/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: ixfoduap <40441298+ixfoduap@users.noreply.github.com> --- demonstrations/tutorial_dmet_embedding.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index 1b50f1f006..8a63172d33 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -8,10 +8,10 @@ interaction or coupled cluster, 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 methods is to divide the system -into two parts: an impurity which is a strongly correlated subsystem that requires a high accuracy -description and an environment which can be treated with a more approximate but computationally +Embedding theories provide a path to simulate materials with a balance of accuracy and efficiency. +The core idea is to divide the system +into two parts: an impurity, which is a strongly correlated subsystem that requires a high accuracy +description, and an environment, which can be treated with a more approximate but computationally efficient level of theory. .. figure:: ../_static/demo_thumbnails/opengraph_demo_thumbnails/OGthumbnail_qdet_embedding.png From 9771521f2a86fe24497451aafe9815ff587fb0c9 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:02:25 -0400 Subject: [PATCH 51/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: ixfoduap <40441298+ixfoduap@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 8a63172d33..b5daec7c25 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -21,7 +21,7 @@ """ ############################################# -# In this demo, we will learn density matrix embedding theory (DMET) [#SWouters]_, a +# In this demo, we will describe density matrix embedding theory (DMET) [#SWouters]_, a # wavefunction-based approach that embeds the ground state density matrix. We provide a brief # introduction of the method and demonstrate how to run DMET calculations to construct a Hamiltonian # that can be used in quantum algorithms using PennyLane. From b3d333d694a3dfbe41d0a5c27c7962508745c94b Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:02:36 -0400 Subject: [PATCH 52/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: ixfoduap <40441298+ixfoduap@users.noreply.github.com> --- demonstrations/tutorial_dmet_embedding.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demonstrations/tutorial_dmet_embedding.py b/demonstrations/tutorial_dmet_embedding.py index b5daec7c25..9ad42dea39 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -35,8 +35,8 @@ # # | \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 +# where :math:`I_i` and :math:`E_j` are respectively the basis states of the impurity :math:`I` and environment +# :math:`E`, :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 wavefunctions as: From 3374bcab09f75346bb01220a6fa0685d73345e87 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:02:50 -0400 Subject: [PATCH 53/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: ixfoduap <40441298+ixfoduap@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 9ad42dea39..c585aa05a3 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -53,7 +53,7 @@ # function. # # We are now able to project the full Hamiltonian to the space of impurity and bath states, known as -# embedding space: +# the embedding space: # # .. math:: # From 3ac19d5a14977dfcd1af5a4753de6f835deab046 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:04:01 -0400 Subject: [PATCH 54/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: ixfoduap <40441298+ixfoduap@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 c585aa05a3..a1caed72b9 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -49,7 +49,7 @@ # :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 [#Mineh]_. Note # that the number of bath states is equal to the number of fragment states, regardless of the size -# of the environment. This new decomposition is the Schmidt decomposition of the system wave +# of the environment. This representation is simply 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 From 52908fe4b3b59896406edc398546c5403070061e Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:04:29 -0400 Subject: [PATCH 55/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: ixfoduap <40441298+ixfoduap@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 a1caed72b9..6cdef31a43 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -64,7 +64,7 @@ # :math:`|\Psi \rangle`, is the ground state of both the full system Hamiltonian :math:`\hat{H}` and # the smaller embedded Hamiltonian :math:`\hat{H}_{\text{emb}}` [#Mineh]_. # -# Note that the Schmidt decomposition requires a priori knowledge of the wavefunction. To alleviate +# Note that the Schmidt decomposition requires a priori knowledge of the ground-state wavefunction. To alleviate # this, DMET operates through a systematic iterative approach, starting with a mean field description # of the wavefunction and refining it through feedback from solution of the impurity Hamiltonian. # From bddbc8ba6783baf72f4edffc6479dcd0dff75834 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:04:38 -0400 Subject: [PATCH 56/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: ixfoduap <40441298+ixfoduap@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 6cdef31a43..570c1261db 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -410,7 +410,7 @@ # this problem is to use a quantum algorithm as our accurate solver. We now convert our impurity # Hamiltonian to a qubit Hamiltonian that can be used in a quantum algorithm using PennyLane. # -# The hamiltonian object we generated above contains one-body and two-body integrals along with the +# The Hamiltonian object we generated above contains one-body and two-body integrals along with the # nuclear repulsion energy which can be accessed and used to construct the qubit Hamiltonian. We # first extract the information we need. # From a70f0724ed1f2b60ea661496c6e09d3db52c2c5e Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:04:59 -0400 Subject: [PATCH 57/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: ixfoduap <40441298+ixfoduap@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 570c1261db..cb9eac61cc 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -66,7 +66,7 @@ # # Note that the Schmidt decomposition requires a priori knowledge of the ground-state wavefunction. To alleviate # this, DMET operates through a systematic iterative approach, starting with a mean field description -# of the wavefunction and refining it through feedback from solution of the impurity Hamiltonian. +# of the wavefunction and refining it through feedback from solutions of the impurity Hamiltonian, as we describe below. # # Implementation # -------------- From b9b125faa252b106f3bdbab4927d95afb84a2b6b Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:06:11 -0400 Subject: [PATCH 58/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: ixfoduap <40441298+ixfoduap@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 cb9eac61cc..9287655ed4 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -74,7 +74,7 @@ # Subsequently, this approximate wavefunction is partitioned with Schmidt decomposition to get # the impurity and bath orbitals. These orbitals are then employed to define an approximate projector # :math:`P`, which is used to construct the embedded Hamiltonian. Then, accurate methods such as -# post-Hartree-Fock methods, exact diagonalisation, or accurate quantum algorithms are employed +# quantum algorithms are employed # to find the energy spectrum of the embedded Hamiltonian. The results are used to # re-construct the projector and the process is repeated until the wavefunction converges. # From 2efb8be0f80e88646f51c4cc7d8be35c6429e6ff Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:06:29 -0400 Subject: [PATCH 59/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: ixfoduap <40441298+ixfoduap@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 9287655ed4..823891b499 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -78,7 +78,7 @@ # to find the energy spectrum of the embedded Hamiltonian. The results are used to # re-construct the projector and the process is repeated until the wavefunction converges. # -# Let's now take implement these steps for a linear chain of 8 Hydrogen atoms. We will use the +# Let's now implement these steps for a linear chain of 8 Hydrogen atoms. We will use the # programs PySCF [#pyscf]_ and libDMET [#libdmet]_ [#libdmet2]_ which can be installed with # # .. code-block:: python From d67e59cd8350436cd0117b9d5932d9a1b993520f Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:06:47 -0400 Subject: [PATCH 60/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: ixfoduap <40441298+ixfoduap@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 823891b499..2b320b0ce1 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -91,7 +91,7 @@ # We begin by defining a finite system containing a hydrogen chain with 8 atoms using PySCF. This is # done by creating a ``Cell`` object containing the Hydrogen atoms. We construct the system to have # a central :math:`H_4` chain with a uniform :math:`0.75` Å :math:`H-H` bond length, flanked by two -# :math:`H_2` molecules at its termini. +# :math:`H_2` molecules at its endpoints. # # .. figure:: ../_static/demonstration_assets/dmet/H8.png # :align: center From dae926d643c58665c38777c5d065829ad91c78ce Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:07:11 -0400 Subject: [PATCH 61/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: ixfoduap <40441298+ixfoduap@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 2b320b0ce1..86a19d5ffb 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -167,7 +167,7 @@ # Next, we identify 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 # central :math:`H_4` chain in the impurity, while the bath contains the :math:`2s` orbitals, and -# the orbitals belonging to the terminal Hydrogen molecules form the unentangled environment. +# the orbitals belonging to the terminal Hydrogen molecules form the environment. # # .. code-block:: python # From 2481434493ed794eb595b0776fbd879bce6c7cb2 Mon Sep 17 00:00:00 2001 From: Diksha Dhawan <40900030+ddhawan11@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:07:35 -0400 Subject: [PATCH 62/62] Update demonstrations/tutorial_dmet_embedding.py Co-authored-by: ixfoduap <40441298+ixfoduap@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 86a19d5ffb..0a952109ac 100644 --- a/demonstrations/tutorial_dmet_embedding.py +++ b/demonstrations/tutorial_dmet_embedding.py @@ -354,7 +354,7 @@ # We set up the 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. Also, since dividing the system into multiple fragments -# might lead to wrong number of electrons, we define and check a chemical potential :math:`\mu` +# might lead to the wrong number of electrons, we define and check a chemical potential :math:`\mu` # as well. # # .. code-block:: python