def compute_lambda(pyscf_mf, sf_factors): """ Compute lambda for Hamiltonian using SF method of Berry, et al. Args: pyscf_mf - PySCF mean field object sf_factors (ndarray) - (N x N x rank) array of SF factors from rank reduction of ERI Returns: lambda_tot (float) - lambda value for the single factorized Hamiltonian """ # grab tensors from pyscf_mf object h1, eri_full, _, _, _ = pyscf_to_cas(pyscf_mf) # Effective one electron operator contribution T = h1 - 0.5 * np.einsum("pqqs->ps", eri_full, optimize=True) +\ np.einsum("pqrr->pq", eri_full, optimize = True) lambda_T = np.sum(np.abs(T)) # Two electron operator contributions lambda_W = 0.25 * np.einsum( "ijP,klP->", np.abs(sf_factors), np.abs(sf_factors), optimize=True) lambda_tot = lambda_T + lambda_W return lambda_tot
def compute_lambda(pyscf_mf, df_factors): """ Compute lambda for Hamiltonian using DF method of von Burg, et al. Args: pyscf_mf - Pyscf mean field object df_factors (ndarray) - (N x N x rank) array of DF factors from ERI Returns: lambda_tot (float) - lambda value for the single factorized Hamiltonian """ # grab tensors from pyscf_mf object h1, eri_full, _, _, _ = pyscf_to_cas(pyscf_mf) # one body contributions T = h1 - 0.5 * np.einsum("illj->ij", eri_full) + np.einsum( "llij->ij", eri_full) e, _ = np.linalg.eigh(T) lambda_T = np.sum(np.abs(e)) # two body contributions lambda_F = 0.0 for vector in range(df_factors.shape[2]): Lij = df_factors[:, :, vector] #e, v = np.linalg.eigh(Lij) e = np.linalg.eigvalsh(Lij) # just need eigenvals lambda_F += 0.25 * np.sum(np.abs(e))**2 lambda_tot = lambda_T + lambda_F return lambda_tot
def test_full_ccsd_t(self): """ Test resource_estimates full CCSD(T) from h1/eri/ecore tensors matches regular PySCF CCSD(T) """ for scf_type in ['rhf', 'rohf']: mol = gto.Mole() mol.atom = 'H 0 0 0; F 0 0 1.1' mol.charge = 0 if scf_type == 'rhf': mol.spin = 0 elif scf_type == 'rohf': mol.spin = 2 mol.basis = 'ccpvtz' mol.symmetry = False mol.build() if scf_type == 'rhf': mf = scf.RHF(mol) elif scf_type == 'rohf': mf = scf.ROHF(mol) mf.init_guess = 'mindo' mf.conv_tol = 1e-10 mf.kernel() mf = stability(mf) # Do PySCF CCSD(T) mycc = cc.CCSD(mf) mycc.max_cycle = 500 mycc.conv_tol = 1E-9 mycc.conv_tol_normt = 1E-5 mycc.diis_space = 24 mycc.diis_start_cycle = 4 mycc.kernel() et = mycc.ccsd_t() pyscf_escf = mf.e_tot pyscf_ecor = mycc.e_corr + et pyscf_etot = pyscf_escf + pyscf_ecor pyscf_results = np.array([pyscf_escf, pyscf_ecor, pyscf_etot]) n_elec = mol.nelectron n_orb = mf.mo_coeff[0].shape[-1] resource_estimates_results = ccsd_t( *pyscf_to_cas(mf, n_orb, n_elec)) resource_estimates_results = np.asarray(resource_estimates_results) # ignore relative tolerance, we just want absolute tolerance assert np.allclose(pyscf_results, resource_estimates_results, rtol=1E-14)
def test_reduced_ccsd_t(self): """ Test resource_estimates reduced (2e space) CCSD(T) from tensors matches PySCF CAS(2e,No) """ for scf_type in ['rhf', 'rohf']: mol = gto.Mole() mol.atom = 'H 0 0 0; F 0 0 1.1' mol.charge = 0 if scf_type == 'rhf': mol.spin = 0 elif scf_type == 'rohf': mol.spin = 2 mol.basis = 'ccpvtz' mol.symmetry = False mol.build() if scf_type == 'rhf': mf = scf.RHF(mol) elif scf_type == 'rohf': mf = scf.ROHF(mol) mf.init_guess = 'mindo' mf.conv_tol = 1e-10 mf.kernel() mf = stability(mf) # PySCF CAS(No,2e) for 2 electrons CCSD (and so CCSD(T)) is exact n_elec = 2 # electrons n_orb = mf.mo_coeff[0].shape[-1] - mf.mol.nelectron - n_elec mycas = mf.CASCI(n_orb, n_elec).run() pyscf_etot = mycas.e_tot # Don't do triples (it's zero anyway for 2e) b/c div by zero w/ ROHF _, _, resource_estimates_etot = ccsd_t(*pyscf_to_cas( mf, n_orb, n_elec), no_triples=True) # ignore relative tolerance, we just want absolute tolerance assert np.isclose(pyscf_etot, resource_estimates_etot, rtol=1E-14)
def generate_costing_table(pyscf_mf, name='molecule', nthc_range=None, dE=0.001, chi=10, beta=20, save_thc=False, use_kernel=True, no_triples=False, **kwargs): """ Print a table to file for testing how various THC thresholds impact cost, accuracy, etc. Args: pyscf_mf - PySCF mean field object name (str) - file will be saved to 'thc_factorization_<name>.txt' nthc_range (list of ints) - list of number of THC vectors to retain dE (float) - max allowable phase error (default: 0.001) chi (int) - number of bits for repr of coefficients (default: 10) beta (int) - number of bits for rotations (default: 20) save_thc (bool) - if True, save the THC factors (leaf and central only) use_kernel (bool) - re-do SCF prior to estimating CCSD(T) error? Will use canonical orbitals and full ERIs for the one-body contributions, using rank-reduced ERIs for two-body no_triples (bool) - if True, skip the (T) correction, doing only CCSD kwargs: additional keyword arguments to pass to thc.factorize() Returns: None """ if nthc_range is None: nthc_range = [250, 300, 350] DE = dE # max allowable phase error CHI = chi # number of bits for representation of coefficients BETA = beta # number of bits for the rotations if isinstance(pyscf_mf, scf.rohf.ROHF): num_alpha, num_beta = pyscf_mf.nelec assert num_alpha + num_beta == pyscf_mf.mol.nelectron else: assert pyscf_mf.mol.nelectron % 2 == 0 num_alpha = pyscf_mf.mol.nelectron // 2 num_beta = num_alpha num_orb = len(pyscf_mf.mo_coeff) num_spinorb = num_orb * 2 cas_info = "CAS((%sa, %sb), %so)" % (num_alpha, num_beta, num_orb) try: assert num_orb**4 == len(pyscf_mf._eri.flatten()) except AssertionError: # ERIs are not in correct form in pyscf_mf._eri, so this is a quick prep _, pyscf_mf = cas_to_pyscf(*pyscf_to_cas(pyscf_mf)) # Reference calculation (eri_rr= None is full rank / exact ERIs) escf, ecor, etot = factorized_ccsd_t(pyscf_mf, eri_rr=None, use_kernel=use_kernel, no_triples=no_triples) exact_etot = etot filename = 'thc_factorization_' + name + '.txt' with open(filename, 'w') as f: print("\n THC factorization data for '" + name + "'.", file=f) print(" [*] using " + cas_info, file=f) print(" [+] E(SCF): %18.8f" % escf, file=f) if no_triples: print(" [+] Active space CCSD E(cor): %18.8f" % ecor, file=f) print(" [+] Active space CCSD E(tot): %18.8f" % etot, file=f) else: print(" [+] Active space CCSD(T) E(cor): %18.8f" % ecor, file=f) print(" [+] Active space CCSD(T) E(tot): %18.8f" % etot, file=f) print("{}".format('=' * 111), file=f) if no_triples: print("{:^12} {:^18} {:^24} {:^12} {:^20} {:^20}".format( 'M', '||ERI - THC||', 'CCSD error (mEh)', 'lambda', 'Toffoli count', 'logical qubits'), file=f) else: print("{:^12} {:^18} {:^24} {:^12} {:^20} {:^20}".format( 'M', '||ERI - THC||', 'CCSD(T) error (mEh)', 'lambda', 'Toffoli count', 'logical qubits'), file=f) print("{}".format('-' * 111), file=f) for nthc in nthc_range: # First, up: lambda and CCSD(T) if save_thc: fname = name + '_nTHC_' + str(nthc).zfill( 5) # will save as HDF5 and add .h5 extension else: fname = None eri_rr, thc_leaf, thc_central, info = thc.factorize( pyscf_mf._eri, nthc, thc_save_file=fname, **kwargs) lam = thc.compute_lambda(pyscf_mf, thc_leaf, thc_central)[0] escf, ecor, etot = factorized_ccsd_t(pyscf_mf, eri_rr, use_kernel=use_kernel, no_triples=no_triples) error = (etot - exact_etot) * 1E3 # to mEh l2_norm_error_eri = np.linalg.norm( eri_rr - pyscf_mf._eri) # ERI reconstruction error # now do costing stps1 = thc.compute_cost(num_spinorb, lam, DE, chi=CHI, beta=BETA, M=nthc, stps=20000)[0] _, thc_total_cost, thc_logical_qubits = thc.compute_cost(num_spinorb, lam, DE, chi=CHI, beta=BETA, M=nthc, stps=stps1) with open(filename, 'a') as f: print( "{:^12} {:^18.4e} {:^24.2f} {:^12.1f} {:^20.1e} {:^20}".format( nthc, l2_norm_error_eri, error, lam, thc_total_cost, thc_logical_qubits), file=f) with open(filename, 'a') as f: print("{}".format('=' * 111), file=f) with open(filename, 'a') as f: print("THC factorization settings at exit:", file=f) for key, value in info.items(): print("\t", key, value, file=f)
def generate_costing_table(pyscf_mf, name='molecule', rank_range=range(50, 401, 25), chi=10, dE=0.001, use_kernel=True, no_triples=False): """ Print a table to file for how various SF ranks impact cost, acc., etc. Args: pyscf_mf - PySCF mean field object name (str) - file will be saved to 'single_factorization_<name>.txt' rank_range (list of ints) - list number of vectors to retain in SF alg dE (float) - max allowable phase error (default: 0.001) chi (int) - number of bits for representation of coefficients (default: 10) use_kernel (bool) - re-do SCF prior to estimating CCSD(T) error? Will use canonical orbitals and full ERIs for the one-body contributions, using rank-reduced ERIs for two-body no_triples (bool) - if True, skip the (T) correction, doing only CCSD Returns: None """ DE = dE # max allowable phase error CHI = chi # number of bits for representation of coefficients if isinstance(pyscf_mf, scf.rohf.ROHF): num_alpha, num_beta = pyscf_mf.nelec assert num_alpha + num_beta == pyscf_mf.mol.nelectron else: assert pyscf_mf.mol.nelectron % 2 == 0 num_alpha = pyscf_mf.mol.nelectron // 2 num_beta = num_alpha num_orb = len(pyscf_mf.mo_coeff) num_spinorb = num_orb * 2 cas_info = "CAS((%sa, %sb), %so)" % (num_alpha, num_beta, num_orb) try: assert num_orb**4 == len(pyscf_mf._eri.flatten()) except AssertionError: # ERIs are not in correct form in pyscf_mf._eri, so this is a quick prep _, pyscf_mf = cas_to_pyscf(*pyscf_to_cas(pyscf_mf)) # Reference calculation (eri_rr = None is full rank / exact ERIs) escf, ecor, etot = factorized_ccsd_t(pyscf_mf, eri_rr=None, use_kernel=use_kernel, no_triples=no_triples) exact_etot = etot filename = 'single_factorization_' + name + '.txt' with open(filename, 'w') as f: print("\n Single low rank factorization data for '" + name + "'.", file=f) print(" [*] using " + cas_info, file=f) print(" [+] E(SCF): %18.8f" % escf, file=f) if no_triples: print(" [+] Active space CCSD E(cor): %18.8f" % ecor, file=f) print(" [+] Active space CCSD E(tot): %18.8f" % etot, file=f) else: print(" [+] Active space CCSD(T) E(cor): %18.8f" % ecor, file=f) print(" [+] Active space CCSD(T) E(tot): %18.8f" % etot, file=f) print("{}".format('=' * 108), file=f) if no_triples: print("{:^12} {:^18} {:^12} {:^24} {:^20} {:^20}".format('L',\ '||ERI - SF||','lambda','CCSD error (mEh)',\ 'logical qubits', 'Toffoli count'),file=f) else: print("{:^12} {:^18} {:^12} {:^24} {:^20} {:^20}".format('L',\ '||ERI - SF||','lambda','CCSD(T) error (mEh)',\ 'logical qubits', 'Toffoli count'),file=f) print("{}".format('-' * 108), file=f) for rank in rank_range: # First, up: lambda and CCSD(T) eri_rr, LR = sf.factorize(pyscf_mf._eri, rank) lam = sf.compute_lambda(pyscf_mf, LR) escf, ecor, etot = factorized_ccsd_t(pyscf_mf, eri_rr, use_kernel=use_kernel, no_triples=no_triples) error = (etot - exact_etot) * 1E3 # to mEh l2_norm_error_eri = np.linalg.norm( eri_rr - pyscf_mf._eri) # eri reconstruction error # now do costing stps1 = sf.compute_cost(num_spinorb, lam, DE, L=rank, chi=CHI, stps=20000)[0] _, sf_total_cost, sf_logical_qubits = sf.compute_cost(num_spinorb, lam, DE, L=rank, chi=CHI, stps=stps1) with open(filename, 'a') as f: print( "{:^12} {:^18.4e} {:^12.1f} {:^24.2f} {:^20} {:^20.1e}".format( rank, l2_norm_error_eri, lam, error, sf_logical_qubits, sf_total_cost), file=f) with open(filename, 'a') as f: print("{}".format('=' * 108), file=f)
def compute_lambda(pyscf_mf, etaPp: np.ndarray, MPQ: np.ndarray, use_eri_thc_for_t=False): """ Compute lambda thc Args: pyscf_mf - PySCF mean field object etaPp - leaf tensor for THC that is dim(nthc x norb). The nthc and norb is inferred from this quantity. MPQ - central tensor for THC factorization. dim(nthc x nthc) Returns: """ nthc = etaPp.shape[0] # grab tensors from pyscf_mf object h1, eri_full, _, _, _ = pyscf_to_cas(pyscf_mf) # computing Least-squares THC residual CprP = np.einsum("Pp,Pr->prP", etaPp, etaPp) # this is einsum('mp,mq->pqm', etaPp, etaPp) BprQ = np.tensordot(CprP, MPQ, axes=([2], [0])) Iapprox = np.tensordot(CprP, np.transpose(BprQ), axes=([2], [0])) deri = eri_full - Iapprox res = 0.5 * np.sum((deri)**2) # NOTE: remove in future once we resolve why it was used in the first place. # NOTE: see T construction for details. eri_thc = np.einsum("Pp,Pr,Qq,Qs,PQ->prqs", etaPp, etaPp, etaPp, etaPp, MPQ, optimize=True) # projecting into the THC basis requires each THC factor mu to be nrmlzd. # we roll the normalization constant into the central tensor zeta SPQ = etaPp.dot( etaPp.T) # (nthc x norb) x (norb x nthc) -> (nthc x nthc) metric cP = np.diag( np.diag(SPQ) ) # grab diagonal elements. equivalent to np.diag(np.diagonal(SPQ)) # no sqrts because we have two normalized THC vectors (index by mu and nu) # on each side. MPQ_normalized = cP.dot(MPQ).dot(cP) # get normalized zeta in Eq. 11 & 12 lambda_z = np.sum(np.abs(MPQ_normalized)) * 0.5 # Eq. 13 # NCR: originally Joonho's code add np.einsum('llij->ij', eri_thc) # NCR: I don't know how much this matters. if use_eri_thc_for_t: # use eri_thc for second coulomb contraction. This was in the original # code which is different than what the paper says. T = h1 - 0.5 * np.einsum("illj->ij", eri_full) + np.einsum( "llij->ij", eri_thc) # Eq. 3 + Eq. 18 else: T = h1 - 0.5 * np.einsum("illj->ij", eri_full) + np.einsum( "llij->ij", eri_full) # Eq. 3 + Eq. 18 #e, v = np.linalg.eigh(T) e = np.linalg.eigvalsh(T) # only need eigenvalues lambda_T = np.sum( np.abs(e)) # Eq. 19. NOTE: sum over spin orbitals removes 1/2 factor lambda_tot = lambda_z + lambda_T # Eq. 20 #return nthc, np.sqrt(res), res, lambda_T, lambda_z, lambda_tot return lambda_tot, nthc, np.sqrt(res), res, lambda_T, lambda_z