Exemplo n.º 1
0
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
Exemplo n.º 2
0
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
Exemplo n.º 3
0
    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)
Exemplo n.º 4
0
    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)
Exemplo n.º 5
0
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)
Exemplo n.º 7
0
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