def trans(ci1, aindex, bindex, nea, neb): if aindex is None or bindex is None: return None t1 = numpy.zeros((cistring.num_strings(norb,nea), cistring.num_strings(norb,neb))) for i in range(norb): signa = aindex[:,i,1] signb = bindex[:,i,1] maska = numpy.where(signa!=0)[0] maskb = numpy.where(signb!=0)[0] ida = aindex[maska,i,0] idb = bindex[maskb,i,0] citmp = pyscf.lib.take_2d(fcivec, maska, maskb) citmp = numpy.einsum('i,j,ij->ij', signa[maska], signb[maskb], citmp) #: t1[ida.reshape(-1,1),idb] += citmp pyscf.lib.takebak_2d_(t1, citmp, ida, idb) for i in range(norb): signa = aindex[:,i,1] signb = bindex[:,i,1] maska = numpy.where(signa!=0)[0] maskb = numpy.where(signb!=0)[0] ida = aindex[maska,i,0] idb = bindex[maskb,i,0] citmp = pyscf.lib.take_2d(t1, ida, idb) citmp = numpy.einsum('i,j,ij->ij', signa[maska], signb[maskb], citmp) #: ci1[maska.reshape(-1,1), maskb] += citmp pyscf.lib.takebak_2d_(ci1, citmp, maska, maskb)
def get_init_guess(norb, nelec, nroots, hdiag): '''Initial guess is the single Slater determinant ''' if isinstance(nelec, (int, numpy.number)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) # The "nroots" lowest determinats based on energy expectation value. ci0 = [] try: addrs = numpy.argpartition(hdiag, nroots-1)[:nroots] except AttributeError: addrs = numpy.argsort(hdiag)[:nroots] for addr in addrs: x = numpy.zeros((na*nb)) x[addr] = 1 ci0.append(x.ravel()) # Add noise ci0[0][0 ] += 1e-5 ci0[0][-1] -= 1e-5 return ci0
def get_init_guess(norb, nelec, nroots, hdiag): '''Initial guess is the single Slater determinant ''' neleca, nelecb = _unpack_nelec(nelec) na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) return _get_init_guess(na, nb, nroots, hdiag)
def exdiagH(h1e, g2e, norb, nelec, writefile=True): ''' exactly diagonalize the hamiltonian. ''' h2e = direct_spin1.absorb_h1e(h1e, g2e, norb, nelec, .5) if isinstance(nelec, (int, np.integer)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec naa = cistring.num_strings(norb, neleca) nbb = cistring.num_strings(norb, nelecb) ndim = naa*nbb eyebas = np.eye(ndim, ndim) def hop(c): hc = direct_spin1.contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) Hmat = [] for i in range(ndim): hc = hop(eyebas[i].copy()) Hmat.append(hc) Hmat = np.asarray(Hmat) # Hmat = Hmat.T.copy() ew, ev = nl.eigh(Hmat.T) if writefile: np.savetxt("cards/eignE.dat", ew, fmt="%10.10f") np.savetxt("cards/eignV.dat", ev, fmt="%10.10f") return ew, ev
def contract_2e_hubbard(u, fcivec, norb, nelec, opt=None): if isinstance(nelec, (int, numpy.number)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec u_aa, u_ab, u_bb = u strsa = numpy.asarray(cistring.gen_strings4orblist(range(norb), neleca)) strsb = numpy.asarray(cistring.gen_strings4orblist(range(norb), nelecb)) na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) fcivec = fcivec.reshape(na,nb) fcinew = numpy.zeros_like(fcivec) if u_aa != 0: # u * n_alpha^+ n_alpha for i in range(norb): maska = (strsa & (1<<i)) > 0 fcinew[maska] += u_aa * fcivec[maska] if u_ab != 0: # u * (n_alpha^+ n_beta + n_beta^+ n_alpha) for i in range(norb): maska = (strsa & (1<<i)) > 0 maskb = (strsb & (1<<i)) > 0 fcinew[maska[:,None]&maskb] += 2*u_ab * fcivec[maska[:,None]&maskb] if u_bb != 0: # u * n_beta^+ n_beta for i in range(norb): maskb = (strsb & (1<<i)) > 0 fcinew[:,maskb] += u_bb * fcivec[:,maskb] return fcinew
def from_fcivec(ci0, norb, nelec, frozen=0): '''Extract CISD coefficients from FCI coefficients''' if frozen is not 0: raise NotImplementedError if isinstance(nelec, (int, numpy.number)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec norba = norbb = norb nocc = nocca, noccb = neleca, nelecb nvira = norba - nocca nvirb = norbb - noccb t1addra, t1signa = cisd.tn_addrs_signs(norba, nocca, 1) t1addrb, t1signb = cisd.tn_addrs_signs(norbb, noccb, 1) na = cistring.num_strings(norba, nocca) nb = cistring.num_strings(norbb, noccb) ci0 = ci0.reshape(na,nb) c0 = ci0[0,0] c1a = (ci0[t1addra,0] * t1signa).reshape(nocca,nvira) c1b = (ci0[0,t1addrb] * t1signb).reshape(noccb,nvirb) c2ab = numpy.einsum('i,j,ij->ij', t1signa, t1signb, ci0[t1addra[:,None],t1addrb]) c2ab = c2ab.reshape(nocca,nvira,noccb,nvirb).transpose(0,2,1,3) t2addra, t2signa = cisd.tn_addrs_signs(norba, nocca, 2) t2addrb, t2signb = cisd.tn_addrs_signs(norbb, noccb, 2) c2aa = (ci0[t2addra,0] * t2signa).reshape(nocca*(nocca-1)//2, nvira*(nvira-1)//2) c2aa = _unpack_4fold(c2aa, nocca, nvira) c2bb = (ci0[0,t2addrb] * t2signb).reshape(noccb*(noccb-1)//2, nvirb*(nvirb-1)//2) c2bb = _unpack_4fold(c2bb, noccb, nvirb) return amplitudes_to_cisdvec(c0, (c1a,c1b), (c2aa,c2ab,c2bb))
def make_rdm12e(fcivec, nsite, nelec): if isinstance(nelec, (int, numpy.number)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec link_indexa = cistring.gen_linkstr_index(range(nsite), neleca) link_indexb = cistring.gen_linkstr_index(range(nsite), nelecb) na = cistring.num_strings(nsite, neleca) nb = cistring.num_strings(nsite, nelecb) ci0 = fcivec.reshape(na,nb,-1) rdm1 = numpy.zeros((nsite,nsite)) rdm2 = numpy.zeros((nsite,nsite,nsite,nsite)) for str0 in range(na): t1 = numpy.zeros((nsite,nsite,nb)+ci0.shape[2:]) for a, i, str1, sign in link_indexa[str0]: t1[i,a,:] += sign * ci0[str1,:] for k, tab in enumerate(link_indexb): for a, i, str1, sign in tab: t1[i,a,k] += sign * ci0[str0,str1] rdm1 += numpy.einsum('mp,ijmp->ij', ci0[str0], t1) # i^+ j|0> => <0|j^+ i, so swap i and j #:rdm2 += numpy.einsum('ijmp,klmp->jikl', t1, t1) tmp = lib.dot(t1.reshape(nsite**2,-1), t1.reshape(nsite**2,-1).T) rdm2 += tmp.reshape((nsite,)*4).transpose(1,0,2,3) rdm1, rdm2 = pyscf.fci.rdm.reorder_rdm(rdm1, rdm2, True) return rdm1, rdm2
def _make_rdm2_abba(fcivec, norb, nelec): if isinstance(nelec, (int, numpy.integer)): neleca = nelecb = nelec // 2 else: neleca, nelecb = nelec if nelecb == norb or neleca == 0: # no intermediate determinants return numpy.zeros((norb,norb,norb,norb)) acre_index = cistring.gen_cre_str_index(range(norb), neleca-1) bdes_index = cistring.gen_des_str_index(range(norb), nelecb+1) instra = cistring.num_strings(norb, neleca-1) nb = cistring.num_strings(norb, nelecb) dm1 = numpy.empty((norb,norb)) dm2 = numpy.empty((norb,norb,norb,norb)) fn = _ctypes.dlsym(librdm._handle, 'FCIdm2_abba_kern') librdm.FCIspindm12_drv(ctypes.c_void_p(fn), dm1.ctypes.data_as(ctypes.c_void_p), dm2.ctypes.data_as(ctypes.c_void_p), fcivec.ctypes.data_as(ctypes.c_void_p), fcivec.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(norb), ctypes.c_int(instra), ctypes.c_int(nb), ctypes.c_int(neleca), ctypes.c_int(nelecb), acre_index.ctypes.data_as(ctypes.c_void_p), bdes_index.ctypes.data_as(ctypes.c_void_p)) return dm2
def get_init_guess(norb, nelec, nroots, hdiag): if isinstance(nelec, (int, numpy.integer)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) init_strs = [] iroot = 0 for addr in numpy.argsort(hdiag): addra = addr // nb addrb = addr % nb if (addrb,addra) not in init_strs: # avoid initial guess linear dependency init_strs.append((addra,addrb)) iroot += 1 if iroot >= nroots: break ci0 = [] for addra,addrb in init_strs: x = numpy.zeros((na,nb)) if addra == addrb == 0: x[addra,addrb] = 1 else: x[addra,addrb] = x[addrb,addra] = numpy.sqrt(.5) ci0.append(x.ravel()) return ci0
def contract_2e(eri, fcivec, norb, nelec, opt=None): if isinstance(nelec, (int, numpy.integer)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec link_indexa = cistring.gen_linkstr_index(range(norb), neleca) link_indexb = cistring.gen_linkstr_index(range(norb), nelecb) na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) fcivec = fcivec.reshape(na,nb) t1 = numpy.zeros((norb,norb,na,nb)) for str0, tab in enumerate(link_indexa): for a, i, str1, sign in tab: t1[a,i,str1] += sign * fcivec[str0] for str0, tab in enumerate(link_indexb): for a, i, str1, sign in tab: t1[a,i,:,str1] += sign * fcivec[:,str0] t1 = numpy.dot(eri.reshape(norb*norb,-1), t1.reshape(norb*norb,-1)) t1 = t1.reshape(norb,norb,na,nb) fcinew = numpy.zeros_like(fcivec) for str0, tab in enumerate(link_indexa): for a, i, str1, sign in tab: fcinew[str1] += sign * t1[a,i,str0] for str0, tab in enumerate(link_indexb): for a, i, str1, sign in tab: fcinew[:,str1] += sign * t1[a,i,:,str0] return fcinew
def contract_2e(eri, fcivec, norb, nelec, opt=None): if isinstance(nelec, (int, numpy.integer)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec link_indexa = cistring.gen_linkstr_index(range(norb), neleca) link_indexb = cistring.gen_linkstr_index(range(norb), nelecb) na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) ci0 = fcivec.reshape(na,nb) t1 = numpy.zeros((norb,norb,na,nb)) for str0, tab in enumerate(link_indexa): for a, i, str1, sign in tab: t1[a,i,str1] += sign * ci0[str0] for str0, tab in enumerate(link_indexb): for a, i, str1, sign in tab: t1[a,i,:,str1] += sign * ci0[:,str0] t1 = lib.einsum('bjai,aiAB->bjAB', eri.reshape([norb]*4), t1) fcinew = numpy.zeros_like(ci0) for str0, tab in enumerate(link_indexa): for a, i, str1, sign in tab: fcinew[str1] += sign * t1[a,i,str0] for str0, tab in enumerate(link_indexb): for a, i, str1, sign in tab: fcinew[:,str1] += sign * t1[a,i,:,str0] return fcinew.reshape(fcivec.shape)
def trans(ci1, aindex, bindex, nea, neb): if aindex is None or bindex is None: return None t1 = numpy.zeros((cistring.num_strings(norb,nea), cistring.num_strings(norb,neb))) for i in range(norb): signa = aindex[:,i,1] signb = bindex[:,i,1] maska = numpy.where(signa!=0)[0] maskb = numpy.where(signb!=0)[0] addra = aindex[maska,i,0] addrb = bindex[maskb,i,0] citmp = lib.take_2d(fcivec, maska, maskb) citmp *= signa[maska].reshape(-1,1) citmp *= signb[maskb] #: t1[addra.reshape(-1,1),addrb] += citmp lib.takebak_2d(t1, citmp, addra, addrb) for i in range(norb): signa = aindex[:,i,1] signb = bindex[:,i,1] maska = numpy.where(signa!=0)[0] maskb = numpy.where(signb!=0)[0] addra = aindex[maska,i,0] addrb = bindex[maskb,i,0] citmp = lib.take_2d(t1, addra, addrb) citmp *= signa[maska].reshape(-1,1) citmp *= signb[maskb] #: ci1[maska.reshape(-1,1), maskb] += citmp lib.takebak_2d(ci1, citmp, maska, maskb)
def make_rdm12e(fcivec, nsite, nelec): '''1-electron and 2-electron density matrices dm_pq = <|p^+ q|> dm_{pqrs} = <|p^+ r^+ q s|> (note 2pdm is ordered in chemist notation) ''' neleca, nelecb = _unpack_nelec(nelec) link_indexa = cistring.gen_linkstr_index(range(nsite), neleca) link_indexb = cistring.gen_linkstr_index(range(nsite), nelecb) na = cistring.num_strings(nsite, neleca) nb = cistring.num_strings(nsite, nelecb) ci0 = fcivec.reshape(na,nb,-1) rdm1 = numpy.zeros((nsite,nsite)) rdm2 = numpy.zeros((nsite,nsite,nsite,nsite)) for str0 in range(na): t1 = numpy.zeros((nsite,nsite,nb)+ci0.shape[2:]) for a, i, str1, sign in link_indexa[str0]: t1[i,a,:] += sign * ci0[str1,:] for k, tab in enumerate(link_indexb): for a, i, str1, sign in tab: t1[i,a,k] += sign * ci0[str0,str1] rdm1 += numpy.einsum('mp,ijmp->ij', ci0[str0], t1) # i^+ j|0> => <0|j^+ i, so swap i and j #:rdm2 += numpy.einsum('ijmp,klmp->jikl', t1, t1) tmp = lib.dot(t1.reshape(nsite**2,-1), t1.reshape(nsite**2,-1).T) rdm2 += tmp.reshape((nsite,)*4).transpose(1,0,2,3) rdm1, rdm2 = rdm.reorder_rdm(rdm1, rdm2, True) return rdm1, rdm2
def ft_rdm1s(h1e, g2e, norb, nelec, T, m=50, nsamp=40, Tmin=10e-4): '''rdm of spin a and b at temperature T ''' if T < Tmin: e, c = kernel(h1e, g2e, norb, nelec) rdma, rdmb = direct_spin1.make_rdm1s(c, norb, nelec) return rdma, rdmb h2e = direct_spin1.absorb_h1e(h1e, g2e, norb, nelec, .5) if isinstance(nelec, (int, numpy.integer)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) def vecgen(n1=na, n2=nb): ci0 = numpy.random.randn(n1, n2) # ci0[0, 0] = 1. return ci0.reshape(-1) def hop(c): hc = direct_spin1.contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) def qud(v1, v2): dma, dmb = direct_spin1.trans_rdm1s(v1, v2, norb, nelec) return dma, dmb # rdma, rdmb = flan.ht_rdm1s(qud, hop, vecgen, T, norb, m, nsamp) rdma, rdmb = flan.ftlan_rdm1s(qud, hop, vecgen, T, norb, m, nsamp) return rdma, rdmb
def kernal_hubbard(t, u, norb, nelec): if isinstance(nelec, (int, numpy.integer)): neleca = nelec//2 nelecb = nelec - neleca else: neleca, nelecb = nelec na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) def mk_tridiag(t, norb): tmat = numpy.ones(norb-1) * (-t) res = numpy.diag(tmat, -1) + numpy.diag(tmat, 1) res[0, norb-1] = -t res[norb-1, 0] = -t return res f1e = mk_tridiag(t, norb) print f1e U = (0., u, 0.) def hop(c): hc = contract_2e_hubbard(U, c, norb, nelec)\ +contract_1e(f1e, c, norb, nelec) return hc.reshape(-1) ci0 = numpy.random.random((na, nb)) hdiag = make_hdiag_hubbard(f1e, u, norb, nelec) print "hdiag:,\n", hdiag precond = lambda x, e, *args: x/(hdiag-e+1e-4) e, c = pyscf.lib.davidson(hop, ci0.reshape(-1), precond) return e
def kernel(h1e, eri, norb, nelec, ecore=0, verbose=logger.NOTE): if isinstance(nelec, (int, numpy.integer)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec h2e = direct_spin1.absorb_h1e(h1e, eri, norb, nelec, .5) namax = cistring.num_strings(norb, neleca) nbmax = cistring.num_strings(norb, nelecb) myci = SelectedCI() strsa = [int('1'*neleca, 2)] strsb = [int('1'*nelecb, 2)] ci_strs = (strsa, strsb) ci0 = numpy.ones((1,1)) ci0, ci_strs = enlarge_space(myci, (ci0, ci_strs), h2e, norb, nelec) def all_linkstr_index(ci_strs): cd_indexa = cre_des_linkstr(ci_strs[0], norb, neleca) dd_indexa = des_des_linkstr(ci_strs[0], norb, neleca) cd_indexb = cre_des_linkstr(ci_strs[1], norb, nelecb) dd_indexb = des_des_linkstr(ci_strs[1], norb, nelecb) return cd_indexa, dd_indexa, cd_indexb, dd_indexb def hop(c): hc = contract_2e(h2e, (c, ci_strs), norb, nelec, link_index) return hc.reshape(-1) precond = lambda x, e, *args: x/(hdiag-e+1e-4) e_last = 0 tol = 1e-2 conv = False for icycle in range(norb): tol = max(tol*1e-2, myci.float_tol) link_index = all_linkstr_index(ci_strs) hdiag = make_hdiag(h1e, eri, ci_strs, norb, nelec) e, ci0 = lib.davidson(hop, ci0.reshape(-1), precond, tol=tol, verbose=verbose) print('icycle %d ci.shape %s E = %.15g' % (icycle, (len(ci_strs[0]), len(ci_strs[1])), e)) if ci0.shape == (namax,nbmax) or abs(e-e_last) < myci.float_tol*10: conv = True break ci1, ci_strs = enlarge_space(myci, (ci0, ci_strs), h2e, norb, nelec) if ci1.size < ci0.size*1.02: conv = True break e_last = e ci0 = ci1 link_index = all_linkstr_index(ci_strs) hdiag = make_hdiag(h1e, eri, ci_strs, norb, nelec) e, ci0 = lib.davidson(hop, ci0.reshape(-1), precond, tol=myci.conv_tol, verbose=verbose) na = len(ci_strs[0]) nb = len(ci_strs[1]) return e+ecore, (ci0.reshape(na,nb), ci_strs)
def from_fci(fcivec, ci_strs, norb, nelec): fcivec, nelec, ci_strs = _unpack(fcivec, nelec, ci_strs) addrsa = [cistring.str2addr(norb, nelec[0], x) for x in ci_strs[0]] addrsb = [cistring.str2addr(norb, nelec[1], x) for x in ci_strs[1]] na = cistring.num_strings(norb, nelec[0]) nb = cistring.num_strings(norb, nelec[1]) fcivec = fcivec.reshape(na,nb) civec = lib.take_2d(fcivec, addrsa, addrsb) return _as_SCIvector(civec, ci_strs)
def to_fci(civec_strs, norb, nelec): ci_coeff, nelec, ci_strs = _unpack(civec_strs, nelec) addrsa = [cistring.str2addr(norb, nelec[0], x) for x in ci_strs[0]] addrsb = [cistring.str2addr(norb, nelec[1], x) for x in ci_strs[1]] na = cistring.num_strings(norb, nelec[0]) nb = cistring.num_strings(norb, nelec[1]) ci0 = numpy.zeros((na,nb)) lib.takebak_2d(ci0, ci_coeff, addrsa, addrsb) return ci0
def make_shape(nsite, nelec, nphonon): if isinstance(nelec, (int, numpy.number)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec na = cistring.num_strings(nsite, neleca) nb = cistring.num_strings(nsite, nelecb) return (na,nb)+(nphonon+1,)*nsite
def initguess_triplet(norb, nelec, binstring): '''Generate a triplet initial guess for FCI solver ''' neleca, nelecb = _unpack(nelec) na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) addr = cistring.str2addr(norb, neleca, int(binstring,2)) ci0 = numpy.zeros((na,nb)) ci0[addr,0] = numpy.sqrt(.5) ci0[0,addr] =-numpy.sqrt(.5) return ci0
def initguess_triplet(norb, nelec, binstring): if isinstance(nelec, (int, numpy.integer)): neleca = nelecb = nelec//2 else: neleca, nelecb = nelec na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) addr = cistring.str2addr(norb, neleca, int(binstring,2)) ci0 = numpy.zeros((na,nb)) ci0[addr,0] = numpy.sqrt(.5) ci0[0,addr] =-numpy.sqrt(.5) return ci0
def contract_2e_hubbard(u, fcivec, norb, nelec, opt=None): if isinstance(nelec, (int, numpy.number)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec u_aa, u_ab, u_bb = u strsa = cistring.gen_strings4orblist(range(norb), neleca) strsb = cistring.gen_strings4orblist(range(norb), nelecb) na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) fcivec = fcivec.reshape(na,nb) t1a = numpy.zeros((norb,na,nb)) t1b = numpy.zeros((norb,na,nb)) fcinew = numpy.zeros_like(fcivec) for addr, s in enumerate(strsa): for i in range(norb): if s & (1<<i): t1a[i,addr] += fcivec[addr] for addr, s in enumerate(strsb): for i in range(norb): if s & (1<<i): t1b[i,:,addr] += fcivec[:,addr] if u_aa != 0: # u * n_alpha^+ n_alpha for addr, s in enumerate(strsa): for i in range(norb): if s & (1<<i): fcinew[addr] += t1a[i,addr] * u_aa if u_ab != 0: # u * n_alpha^+ n_beta for addr, s in enumerate(strsa): for i in range(norb): if s & (1<<i): fcinew[addr] += t1b[i,addr] * u_ab # u * n_beta^+ n_alpha for addr, s in enumerate(strsb): for i in range(norb): if s & (1<<i): fcinew[:,addr] += t1a[i,:,addr] * u_ab if u_bb != 0: # u * n_beta^+ n_beta for addr, s in enumerate(strsb): for i in range(norb): if s & (1<<i): fcinew[:,addr] += t1b[i,:,addr] * u_bb return fcinew
def kernel_ft(h1e, g2e, norb, nelec, T, m=50, nsamp=40): '''E at temperature T ''' h2e = absorb_h1e(h1e, g2e, norb, nelec, .5) neleca, nelecb = nelec na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) def vecgen(n1=na, n2=nb): ci0 = numpy.random.rand(n1, n2) return ci0.reshape(-1) def hop(c): hc = contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) E = ftlan_E(hop, vecgen, T, m, nsamp) return E
def pspace(h1e, eri, norb, nelec, hdiag, np=400): if isinstance(nelec, (int, numpy.integer)): neleca = nelec//2 else: neleca, nelecb = nelec assert(neleca == nelecb) h1e = numpy.ascontiguousarray(h1e) eri = pyscf.ao2mo.restore(1, eri, norb) na = cistring.num_strings(norb, neleca) addr = numpy.argsort(hdiag)[:np] # symmetrize addra/addrb addra = addr // na addrb = addr % na stra = numpy.array([cistring.addr2str(norb,neleca,ia) for ia in addra], dtype=numpy.long) strb = numpy.array([cistring.addr2str(norb,neleca,ib) for ib in addrb], dtype=numpy.long) np = len(addr) h0 = numpy.zeros((np,np)) libfci.FCIpspace_h0tril(h0.ctypes.data_as(ctypes.c_void_p), h1e.ctypes.data_as(ctypes.c_void_p), eri.ctypes.data_as(ctypes.c_void_p), stra.ctypes.data_as(ctypes.c_void_p), strb.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(norb), ctypes.c_int(np)) for i in range(np): h0[i,i] = hdiag[addr[i]] h0 = pyscf.lib.hermi_triu_(h0) return addr, h0
def pspace(h1e, eri, norb, nelec, hdiag, np=400): '''pspace Hamiltonian to improve Davidson preconditioner. See, CPL, 169, 463 ''' if isinstance(nelec, (int, numpy.integer)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec h1e = numpy.ascontiguousarray(h1e) eri = pyscf.ao2mo.restore(1, eri, norb) nb = cistring.num_strings(norb, nelecb) addr = numpy.argsort(hdiag)[:np] addra = addr // nb addrb = addr % nb stra = numpy.array([cistring.addr2str(norb,neleca,ia) for ia in addra], dtype=numpy.uint64) strb = numpy.array([cistring.addr2str(norb,nelecb,ib) for ib in addrb], dtype=numpy.uint64) np = len(addr) h0 = numpy.zeros((np,np)) libfci.FCIpspace_h0tril(h0.ctypes.data_as(ctypes.c_void_p), h1e.ctypes.data_as(ctypes.c_void_p), eri.ctypes.data_as(ctypes.c_void_p), stra.ctypes.data_as(ctypes.c_void_p), strb.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(norb), ctypes.c_int(np)) for i in range(np): h0[i,i] = hdiag[addr[i]] h0 = pyscf.lib.hermi_triu_(h0) return addr, h0
def cre_a(ci0, norb, neleca_nelecb, ap_id): r'''Construct (N+1)-electron wavefunction by adding an alpha electron in the N-electron wavefunction. ... math:: |N+1\rangle = \hat{a}^+_p |N\rangle Args: ci0 : 2D array CI coefficients, row for alpha strings and column for beta strings. norb : int Number of orbitals. (neleca,nelecb) : (int,int) Number of (alpha, beta) electrons of the input CI function ap_id : int Orbital index (0-based), for the creation operator Returns: 2D array, row for alpha strings and column for beta strings. Note it has different number of rows to the input CI coefficients. ''' neleca, nelecb = neleca_nelecb if neleca >= norb: return numpy.zeros((0, ci0.shape[1])) cre_index = cistring.gen_cre_str_index(range(norb), neleca) na_ci1 = cistring.num_strings(norb, neleca+1) ci1 = numpy.zeros((na_ci1, ci0.shape[1])) entry_has_ap = (cre_index[:,:,0] == ap_id) addr_ci0 = numpy.any(entry_has_ap, axis=1) addr_ci1 = cre_index[entry_has_ap,2] sign = cre_index[entry_has_ap,3] ci1[addr_ci1] = sign.reshape(-1,1) * ci0[addr_ci0] return ci1
def des_b(ci0, norb, neleca_nelecb, ap_id): r'''Construct (N-1)-electron wavefunction by removing a beta electron from N-electron wavefunction. Args: ci0 : 2D array CI coefficients, row for alpha strings and column for beta strings. norb : int Number of orbitals. (neleca,nelecb) : (int,int) Number of (alpha, beta) electrons of the input CI function ap_id : int Orbital index (0-based), for the annihilation operator Returns: 2D array, row for alpha strings and column for beta strings. Note it has different number of columns to the input CI coefficients. ''' neleca, nelecb = neleca_nelecb if nelecb <= 0: return numpy.zeros((ci0.shape[0], 0)) des_index = cistring.gen_des_str_index(range(norb), nelecb) nb_ci1 = cistring.num_strings(norb, nelecb-1) ci1 = numpy.zeros((ci0.shape[0], nb_ci1)) entry_has_ap = (des_index[:,:,1] == ap_id) addr_ci0 = numpy.any(entry_has_ap, axis=1) addr_ci1 = des_index[entry_has_ap,2] sign = des_index[entry_has_ap,3] # This sign prefactor accounts for interchange of operators with alpha and beta spins if neleca % 2 == 1: sign *= -1 ci1[:,addr_ci1] = ci0[:,addr_ci0] * sign return ci1
def cre_b(ci0, norb, nelec, ap_id): r'''Construct (N+1)-electron wavefunction by adding a beta electron in the N-electron wavefunction. Args: ci0 : 2D array CI coefficients, row for alpha strings and column for beta strings. norb : int Number of orbitals. nelec : int or 2-item list Number of electrons, or 2-item list for (alpha, beta) electrons ap_id : int Orbital index (0-based), for the creation operator Returns: 2D array, row for alpha strings and column for beta strings. Note it has different number of columns to the input CI coefficients. ''' if isinstance(nelec, (int, numpy.integer)): neleca = nelecb = nelec // 2 else: neleca, nelecb = nelec cre_index = cistring.gen_cre_str_index(range(norb), nelecb) nb_ci1 = cistring.num_strings(norb, nelecb+1) ci1 = numpy.zeros((ci0.shape[0], nb_ci1)) entry_has_ap = (cre_index[:,:,0] == ap_id) addr_ci0 = numpy.any(entry_has_ap, axis=1) addr_ci1 = cre_index[entry_has_ap,2] sign = cre_index[entry_has_ap,3] # This sign prefactor accounts for interchange of operators with alpha and beta spins if neleca % 2 == 1: sign *= -1 ci1[:,addr_ci1] = ci0[:,addr_ci0] * sign return ci1
def pspace(h1e, eri, norb, nelec, hdiag, np=400): '''pspace Hamiltonian to improve Davidson preconditioner. See, CPL, 169, 463 ''' neleca, nelecb = _unpack_nelec(nelec) h1e = numpy.ascontiguousarray(h1e) eri = ao2mo.restore(1, eri, norb) nb = cistring.num_strings(norb, nelecb) if hdiag.size < np: addr = numpy.arange(hdiag.size) else: try: addr = numpy.argpartition(hdiag, np-1)[:np] except AttributeError: addr = numpy.argsort(hdiag)[:np] addra, addrb = divmod(addr, nb) stra = numpy.array([cistring.addr2str(norb,neleca,ia) for ia in addra], dtype=numpy.uint64) strb = numpy.array([cistring.addr2str(norb,nelecb,ib) for ib in addrb], dtype=numpy.uint64) np = len(addr) h0 = numpy.zeros((np,np)) libfci.FCIpspace_h0tril(h0.ctypes.data_as(ctypes.c_void_p), h1e.ctypes.data_as(ctypes.c_void_p), eri.ctypes.data_as(ctypes.c_void_p), stra.ctypes.data_as(ctypes.c_void_p), strb.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(norb), ctypes.c_int(np)) for i in range(np): h0[i,i] = hdiag[addr[i]] h0 = lib.hermi_triu(h0) return addr, h0
def get_init_guess(norb, nelec, nroots, hdiag): if isinstance(nelec, (int, numpy.integer)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) ci0 = [] iroot = 0 for addr in numpy.argsort(hdiag): x = numpy.zeros((na*nb)) x[addr] = 1 ci0.append(x.ravel()) iroot += 1 if iroot >= nroots: break return ci0
def des_b(ci0, norb, neleca_nelecb, ap_id): r'''Construct (N-1)-electron wavefunction by removing a beta electron from N-electron wavefunction. Args: ci0 : 2D array CI coefficients, row for alpha strings and column for beta strings. norb : int Number of orbitals. (neleca,nelecb) : (int,int) Number of (alpha, beta) electrons of the input CI function ap_id : int Orbital index (0-based), for the annihilation operator Returns: 2D array, row for alpha strings and column for beta strings. Note it has different number of columns to the input CI coefficients. ''' neleca, nelecb = neleca_nelecb if ci0.ndim == 1: ci0 = ci0.reshape(cistring.num_strings(norb, neleca), cistring.num_strings(norb, nelecb)) if nelecb <= 0: return numpy.zeros((ci0.shape[0], 0)) des_index = cistring.gen_des_str_index(range(norb), nelecb) nb_ci1 = cistring.num_strings(norb, nelecb - 1) ci1 = numpy.zeros((ci0.shape[0], nb_ci1)) entry_has_ap = (des_index[:, :, 1] == ap_id) addr_ci0 = numpy.any(entry_has_ap, axis=1) addr_ci1 = des_index[entry_has_ap, 2] sign = des_index[entry_has_ap, 3] # This sign prefactor accounts for interchange of operators with alpha and beta spins if neleca % 2 == 1: sign *= -1 ci1[:, addr_ci1] = ci0[:, addr_ci0] * sign return ci1
def guess_wfnsym(ci, norb, nelec, orbsym): '''Guess the wavefunction symmetry based on the non-zero elements in the given CI coefficients. Args: ci : 2D array CI coefficients, row for alpha strings and column for beta strings. norb : int Number of orbitals. nelec : int or 2-item list Number of electrons, or 2-item list for (alpha, beta) electrons orbsym : list of int The irrep ID for each orbital. Returns: Irrep ID ''' neleca, nelecb = _unpack(nelec) na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) if isinstance(ci, numpy.ndarray) and ci.ndim <= 2: assert (ci.size == na * nb) idx = numpy.argmax(ci) else: assert (ci[0].size == na * nb) idx = ci[0].argmax() stra = cistring.addr2str(norb, neleca, idx // nb) strb = cistring.addr2str(norb, nelecb, idx % nb) airrep = 0 birrep = 0 for i in range(norb): if (stra & (1 << i)): airrep ^= orbsym[i] if (strb & (1 << i)): birrep ^= orbsym[i] return airrep ^ birrep
def cre_b(ci0, norb, neleca_nelecb, ap_id): r'''Construct (N+1)-electron wavefunction by adding a beta electron in the N-electron wavefunction. Args: ci0 : 2D array CI coefficients, row for alpha strings and column for beta strings. norb : int Number of orbitals. (neleca,nelecb) : (int,int) Number of (alpha, beta) electrons of the input CI function ap_id : int Orbital index (0-based), for the creation operator Returns: 2D array, row for alpha strings and column for beta strings. Note it has different number of columns to the input CI coefficients. ''' neleca, nelecb = neleca_nelecb if nelecb >= norb: return numpy.zeros_like(ci0) if ci0.ndim == 1: ci0 = ci0.reshape(cistring.num_strings(norb, neleca), cistring.num_strings(norb, nelecb)) cre_index = cistring.gen_cre_str_index(range(norb), nelecb) nb_ci1 = cistring.num_strings(norb, nelecb + 1) ci1 = numpy.zeros((ci0.shape[0], nb_ci1), dtype=ci0[0, 0].__class__) entry_has_ap = (cre_index[:, :, 0] == ap_id) addr_ci0 = numpy.any(entry_has_ap, axis=1) addr_ci1 = cre_index[entry_has_ap, 2] sign = cre_index[entry_has_ap, 3].astype(complex) # This sign prefactor accounts for interchange of operators with alpha and beta spins if neleca % 2 == 1: sign *= -1 ci1[:, addr_ci1] = ci0[:, addr_ci0] * sign return ci1
def from_fcivec(ci0, norb, nelec, frozen=0): '''Extract CISD coefficients from FCI coefficients''' if frozen is not 0: raise NotImplementedError if isinstance(nelec, (int, numpy.number)): nelecb = nelec // 2 neleca = nelec - nelecb else: neleca, nelecb = nelec norba = norbb = norb nocc = nocca, noccb = neleca, nelecb nvira = norba - nocca nvirb = norbb - noccb t1addra, t1signa = cisd.tn_addrs_signs(norba, nocca, 1) t1addrb, t1signb = cisd.tn_addrs_signs(norbb, noccb, 1) na = cistring.num_strings(norba, nocca) nb = cistring.num_strings(norbb, noccb) ci0 = ci0.reshape(na, nb) c0 = ci0[0, 0] c1a = (ci0[t1addra, 0] * t1signa).reshape(nocca, nvira) c1b = (ci0[0, t1addrb] * t1signb).reshape(noccb, nvirb) c2ab = numpy.einsum('i,j,ij->ij', t1signa, t1signb, ci0[t1addra[:, None], t1addrb]) c2ab = c2ab.reshape(nocca, nvira, noccb, nvirb).transpose(0, 2, 1, 3) t2addra, t2signa = cisd.tn_addrs_signs(norba, nocca, 2) t2addrb, t2signb = cisd.tn_addrs_signs(norbb, noccb, 2) c2aa = (ci0[t2addra, 0] * t2signa).reshape(nocca * (nocca - 1) // 2, nvira * (nvira - 1) // 2) c2aa = _unpack_4fold(c2aa, nocca, nvira) c2bb = (ci0[0, t2addrb] * t2signb).reshape(noccb * (noccb - 1) // 2, nvirb * (nvirb - 1) // 2) c2bb = _unpack_4fold(c2bb, noccb, nvirb) return amplitudes_to_cisdvec(c0, (c1a, c1b), (c2aa, c2ab, c2bb))
def __init__(self, mc, state=None): self.__dict__.update (mc.__dict__) nmo = mc.mo_coeff.shape[-1] self.ngorb = np.count_nonzero (mc.uniq_var_indices (nmo, mc.ncore, mc.ncas, mc.frozen)) self.nroots = mc.fcisolver.nroots neleca, nelecb = _unpack_nelec (mc.nelecas) self.spin_states = [neleca - nelecb,] * self.nroots self.na_states = [cistring.num_strings (mc.ncas, neleca),] * self.nroots self.nb_states = [cistring.num_strings (mc.ncas, nelecb),] * self.nroots if isinstance (mc.fcisolver, StateAverageMixFCISolver): self.nroots = p0 = 0 for solver in mc.fcisolver.fcisolvers: self.nroots += solver.nroots nea, neb = mc.fcisolver._get_nelec (solver, (neleca, nelecb)) self.spin_states[p0:self.nroots] = (nea - neb for x in range (solver.nroots)) self.na_states[p0:self.nroots] = (cistring.num_strings (mc.ncas, nea) for x in range (solver.nroots)) self.nb_states[p0:self.nroots] = (cistring.num_strings (mc.ncas, neb) for x in range (solver.nroots)) p0 = self.nroots self.nci = sum ([na * nb for na, nb in zip (self.na_states, self.nb_states)]) if state is not None: self.state = state elif hasattr (mc, 'nuc_grad_state'): self.state = mc.nuc_grad_state else: self.state = None self.eris = None self.weights = np.array ([1]) try: self.e_states = np.asarray (mc.e_states) except AttributeError as e: self.e_states = np.asarray (mc.e_tot) if isinstance (mc, StateAverageMCSCFSolver): self.weights = np.asarray (mc.weights) assert (len (self.weights) == self.nroots), '{} {} {}'.format (mc.fcisolver.__class__, self.weights, self.nroots) lagrange.Gradients.__init__(self, mc, self.ngorb+self.nci) self.max_cycle = mc.max_cycle_macro
def kernel(h1e, eri, norb, nelec, ecore=0): h2e = absorb_h1e(h1e, eri, norb, nelec, .5) na = cistring.num_strings(norb, nelec // 2) ci0 = numpy.zeros((na, na)) ci0[0, 0] = 1 def hop(c): hc = contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) hdiag = make_hdiag(h1e, eri, norb, nelec) precond = lambda x, e, *args: x / (hdiag - e + 1e-4) e, c = lib.davidson(hop, ci0.reshape(-1), precond) return e + ecore
def from_fcivec(ci0, norb, nelec, frozen=0): from pyscf.ci.gcisd import t2strs if frozen is not 0: raise NotImplementedError if isinstance(nelec, (int, numpy.number)): nelecb = nelec // 2 neleca = nelec - nelecb else: neleca, nelecb = nelec norba = norbb = norb nocc = nocca, noccb = neleca, nelecb nvira = norba - nocca nvirb = norbb - noccb t1addra, t1signa = cisd.t1strs(norba, nocca) t1addrb, t1signb = cisd.t1strs(norbb, noccb) na = cistring.num_strings(norba, nocca) nb = cistring.num_strings(norbb, noccb) ci0 = ci0.reshape(na, nb) c0 = ci0[0, 0] c1a = ((ci0[t1addra, 0] * t1signa).reshape(nvira, nocca).T)[::-1] c1b = ((ci0[0, t1addrb] * t1signb).reshape(nvirb, noccb).T)[::-1] c2ab = numpy.einsum('i,j,ij->ij', t1signa, t1signb, ci0[t1addra][:, t1addrb]) c2ab = c2ab.reshape(nvira, nocca, nvirb, noccb).transpose(1, 3, 0, 2) c2ab = c2ab[::-1, ::-1] t2addra, t2signa = t2strs(norba, nocca) c2aa = (ci0[t2addra, 0] * t2signa).reshape(nvira * (nvira - 1) // 2, -1).T c2aa = _unpack_4fold(c2aa[::-1], nocca, nvira) t2addrb, t2signb = t2strs(norbb, noccb) c2bb = (ci0[0, t2addrb] * t2signb).reshape(nvirb * (nvirb - 1) // 2, -1).T c2bb = _unpack_4fold(c2bb[::-1], noccb, nvirb) return amplitudes_to_cisdvec(c0, (c1a, c1b), (c2aa, c2ab, c2bb))
def make_rdm12(fcivec, norb, nelec, opt=None): link_index = cistring.gen_linkstr_index(range(norb), nelec) na = cistring.num_strings(norb, nelec) rdm1 = numpy.zeros((norb, norb), dtype=numpy.complex128) rdm2 = numpy.zeros((norb, norb, norb, norb), dtype=numpy.complex128) t1 = numpy.zeros((na, norb, norb), dtype=numpy.complex128) for str0, tab in enumerate(link_index): for a, i, str1, sign in link_index[str0]: t1[str1, i, a] += sign * fcivec[str0] rdm1 += numpy.einsum('m,mij->ij', fcivec.conj(), t1) #i^+ j|0> => <0|j^+ i, so swap i and j rdm2 += numpy.einsum('mij,mkl->jikl', t1.conj(), t1) return reorder_rdm(rdm1, rdm2)
def setUpModule(): global ci_strs, ci_coeff, civec_strs, eri, h1, spin0_ci_strs, spin0_ci_coeff global norb, nelec norb = 6 nelec = 6 na = cistring.num_strings(norb, nelec // 2) ci_strs = [[0b111, 0b1011, 0b10101], [0b111, 0b1011, 0b1101]] numpy.random.seed(12) ci_coeff = (numpy.random.random( (len(ci_strs[0]), len(ci_strs[1]))) - .2)**3 civec_strs = selected_ci._as_SCIvector(ci_coeff, ci_strs) nn = norb * (norb + 1) // 2 eri = (numpy.random.random(nn * (nn + 1) // 2) - .2)**3 h1 = numpy.random.random((norb, norb)) h1 = h1 + h1.T spin0_ci_strs = [[0b111, 0b1011, 0b10101], [0b111, 0b1011, 0b10101]] spin0_ci_coeff = ci_coeff + ci_coeff.T
def make_rdm12(civec, norb, nelec, link_index=None, reorder=True): if isinstance(nelec, (int, numpy.integer)): nelecb = nelec // 2 neleca = nelec - nelecb else: neleca, nelecb = nelec assert (neleca == nelecb) if link_index is None: link_index = cistring.gen_linkstr_index(range(norb), neleca) na = cistring.num_strings(norb, neleca) t1 = numpy.zeros((norb, na)) t2 = numpy.zeros((norb, norb, na)) #:for str0, tab in enumerate(link_index): #: for a, i, str1, sign in tab: #: if a == i: #: t1[i,str1] += civec[str0] #: else: #: t2[a,i,str1] += civec[str0] link1 = link_index[link_index[:, :, 0] == link_index[:, :, 1]].reshape(na, -1, 4) link2 = link_index[link_index[:, :, 0] != link_index[:, :, 1]].reshape( na, -1, 4) t1[link1[:, :, 1], link1[:, :, 2]] = civec[:, None] t2[link2[:, :, 0], link2[:, :, 1], link2[:, :, 2]] = civec[:, None] idx = numpy.arange(norb) dm2 = numpy.zeros([norb] * 4) # Assign to dm2[i,j,i,j] dm2[idx[:, None], idx, idx[:, None], idx] += 2 * numpy.einsum('ijp,p->ij', t2, civec) # Assign to dm2[i,j,j,i] dm2[idx[:, None], idx, idx, idx[:, None]] += 2 * numpy.einsum('ijp,ijp->ij', t2, t2) # Assign to dm2[i,i,j,j] dm2[idx[:, None], idx[:, None], idx, idx] += 4 * numpy.einsum('ip,jp->ij', t1, t1) dm1 = numpy.einsum('ijkk->ij', dm2) / (neleca + nelecb) if reorder: dm1, dm2 = rdm.reorder_rdm(dm1, dm2, inplace=True) return dm1, dm2
def contract_2e(eri, fcivec, norb, nelec, opt=None): link_indexa = cistring.gen_linkstr_index_o0(range(norb), nelec) na = cistring.num_strings(norb, nelec) ci0 = fcivec t1 = numpy.zeros((norb, norb, na), dtype=numpy.complex128) for str0, tab in enumerate(link_indexa): for a, i, str1, sign in tab: t1[a, i, str1] += sign * ci0[str0] t1 = numpy.dot(eri.reshape(norb * norb, -1), t1.reshape(norb * norb, -1)) t1 = t1.reshape(norb, norb, na) fcinew = numpy.zeros_like(ci0, dtype=numpy.complex128) for str0, tab in enumerate(link_indexa): for a, i, str1, sign in tab: fcinew[str1] += sign * t1[a, i, str0] return fcinew.reshape(fcivec.shape)
def _guess_nelec_f (fci, norb, nelec, norb_f, h1, h2): # Pick electron distribution by the lowest-energy single determinant nelec = direct_spin1._unpack_nelec (nelec) hdiag = fci.make_hdiag (h1, h2, norb, nelec) ndetb = cistring.num_strings (norb, nelec[1]) addr_dp = np.divmod (np.argmin (hdiag), ndetb) str_dp = [cistring.addr2str (norb, n, c) for n,c in zip (nelec, addr_dp)] nelec_f = [] for n in norb_f: ndet = 2**n c = np.zeros ((ndet, ndet)) det = np.array ([str_dp[0] % ndet, str_dp[1] % ndet], dtype=np.integer) str_dp = [str_dp[0] // ndet, str_dp[1] // ndet] ne = [0,0] for spin in range (2): for iorb in range (n): ne[spin] += int (bool ((det[spin] & (1 << iorb)))) nelec_f.append (ne) return nelec_f
def kernel(h1e, g2e, norb, nelec): na = cistring.num_strings(norb, nelec) h2e = absorb_h1e(h1e, g2e, norb, nelec, .5) def hop(c): hc = contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) hdiag = make_hdiag(h1e, g2e, norb, nelec) precond = lambda x, e, *args: x / (hdiag - e + 1e-4) ci0 = numpy.random.random(na) ci0 /= numpy.linalg.norm(ci0) #e, c = pyscf.lib.davidson(hop, ci0, precond, max_space=100) e, c = pyscf.lib.davidson(hop, ci0, precond) return e, c
def make_rdm12(fcivec, norb, nelec, opt=None): link_index = cistring.gen_linkstr_index(range(norb), nelec // 2) na = cistring.num_strings(norb, nelec // 2) fcivec = fcivec.reshape(na, na) rdm1 = numpy.zeros((norb, norb)) rdm2 = numpy.zeros((norb, norb, norb, norb)) for str0, tab in enumerate(link_index): t1 = numpy.zeros((na, norb, norb)) for a, i, str1, sign in link_index[str0]: t1[:, i, a] += sign * fcivec[str1, :] for k, tab in enumerate(link_index): for a, i, str1, sign in tab: t1[k, i, a] += sign * fcivec[str0, str1] rdm1 += numpy.einsum('m,mij->ij', fcivec[str0], t1) # i^+ j|0> => <0|j^+ i, so swap i and j rdm2 += numpy.einsum('mij,mkl->jikl', t1, t1) return reorder_rdm(rdm1, rdm2)
def kernel(h1e, g2e, norb, nelec): h2e = direct_spin1.absorb_h1e(h1e, g2e, norb, nelec, .5) if isinstance(nelec, (int, numpy.integer)): neleca = nelec // 2 else: neleca = nelec[0] na = cistring.num_strings(norb, neleca) ci0 = numpy.zeros((na, na)) ci0[0, 0] = 1 def hop(c): hc = direct_spin1.contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) hdiag = direct_spin1.make_hdiag(h1e, g2e, norb, nelec) precond = lambda x, e, *args: x / (hdiag - e + 1e-4) e, c = pyscf.lib.davidson(hop, ci0.reshape(-1), precond) return e, c
def kernel_ref(h1e, eri, norb, nelec, ecore=0, **kwargs): if isinstance(nelec, (int, numpy.integer)): nelecb = nelec // 2 neleca = nelec - nelecb else: neleca, nelecb = nelec h2e = direct_spin1.absorb_h1e(h1e, eri, norb, nelec, .5) h2e = ao2mo.restore(1, h2e, norb) na = cistring.num_strings(norb, neleca) ci0 = numpy.zeros(na) ci0[0] = 1 link_index = cistring.gen_linkstr_index(range(norb), neleca) def hop(c): return contract_2e_ref(h2e, c, norb, nelec, link_index) hdiag = make_hdiag(h1e, eri, norb, nelec) precond = lambda x, e, *args: x / (hdiag - e + 1e-4) e, c = lib.davidson(hop, ci0.reshape(-1), precond, **kwargs) return e + ecore
def fci_simple(mol, m, lam=1.0): norb = m.mo_coeff.shape[1] nelec = mol.nelectron f = m.get_fock() hprime = f + lam * (m.get_hcore() - f) h1e = reduce(numpy.dot, (m.mo_coeff.T, hprime, m.mo_coeff)) eri = ao2mo.kernel(m._eri, m.mo_coeff, compact=False) eri = lam * eri.reshape(norb, norb, norb, norb) h2e = fci_slow.absorb_h1e(h1e, eri, norb, nelec, .5) na = cistring.num_strings(norb, nelec // 2) N = na * na assert (N < 2000) H = numpy.zeros((N, N)) I = numpy.identity(N) for i in range(N): hc = fci_slow.contract_2e(h2e, I[:, i], norb, nelec) hc.reshape(-1) H[:, i] = hc e, v = numpy.linalg.eigh(H) #print(e[0] + mol.energy_nuc()) return e[0] + mol.energy_nuc()
def make_rdm1(civec, norb, nelec, link_index=None): if isinstance(nelec, (int, numpy.integer)): nelecb = nelec // 2 neleca = nelec - nelecb else: neleca, nelecb = nelec assert (neleca == nelecb) if link_index is None: link_index = cistring.gen_linkstr_index(range(norb), neleca) na = cistring.num_strings(norb, neleca) t1 = numpy.zeros((norb, na)) #:for str0, tab in enumerate(link_index): #: for a, i, str1, sign in tab: #: if a == i: #: t1[i,str1] += civec[str0] link1 = link_index[link_index[:, :, 0] == link_index[:, :, 1]].reshape(na, -1, 4) t1[link1[:, :, 1], link1[:, :, 2]] = civec[:, None] dm1 = numpy.diag(numpy.einsum('ip,p->i', t1, civec)) * 2 return dm1
def pspace(h1e, eri, norb, nelec, hdiag=None, np=400): neleca, nelecb = direct_spin1._unpack_nelec(nelec) h1e_a = numpy.ascontiguousarray(h1e[0]) h1e_b = numpy.ascontiguousarray(h1e[1]) g2e_aa = ao2mo.restore(1, eri[0], norb) g2e_ab = ao2mo.restore(1, eri[1], norb) g2e_bb = ao2mo.restore(1, eri[2], norb) if hdiag is None: hdiag = make_hdiag(h1e, eri, norb, nelec) if hdiag.size < np: addr = numpy.arange(hdiag.size) else: try: addr = numpy.argpartition(hdiag, np-1)[:np] except AttributeError: addr = numpy.argsort(hdiag)[:np] nb = cistring.num_strings(norb, nelecb) addra = addr // nb addrb = addr % nb stra = cistring.addrs2str(norb, neleca, addra) strb = cistring.addrs2str(norb, nelecb, addrb) np = len(addr) h0 = numpy.zeros((np,np)) libfci.FCIpspace_h0tril_uhf(h0.ctypes.data_as(ctypes.c_void_p), h1e_a.ctypes.data_as(ctypes.c_void_p), h1e_b.ctypes.data_as(ctypes.c_void_p), g2e_aa.ctypes.data_as(ctypes.c_void_p), g2e_ab.ctypes.data_as(ctypes.c_void_p), g2e_bb.ctypes.data_as(ctypes.c_void_p), stra.ctypes.data_as(ctypes.c_void_p), strb.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(norb), ctypes.c_int(np)) for i in range(np): h0[i,i] = hdiag[addr[i]] h0 = lib.hermi_triu(h0) return addr, h0
def to_fci(cisdvec, norb, nelec): if isinstance(nelec, (int, numpy.number)): nelecb = nelec // 2 neleca = nelec - nelecb else: neleca, nelecb = nelec nocc = neleca nvir = norb - nocc c0 = cisdvec[0] c1 = cisdvec[1:nocc * nvir + 1].reshape(nocc, nvir) c2 = cisdvec[nocc * nvir + 1:].reshape(nocc, nocc, nvir, nvir) t1addr, t1sign = t1strs(norb, nocc) na = cistring.num_strings(norb, nocc) fcivec = numpy.zeros((na, na)) fcivec[0, 0] = c0 c1 = c1[::-1].T.ravel() fcivec[0, t1addr] = fcivec[t1addr, 0] = c1 * t1sign c2ab = c2[::-1, ::-1].transpose(2, 0, 3, 1).reshape(nocc * nvir, -1) c2ab = numpy.einsum('i,j,ij->ij', t1sign, t1sign, c2ab) lib.takebak_2d(fcivec, c2ab, t1addr, t1addr) if nocc > 1 and nvir > 1: hf_str = int('1' * nocc, 2) for a in range(nocc, norb): for b in range(nocc, a): for i in reversed(range(1, nocc)): for j in reversed(range(i)): c2aa = c2[i, j, a - nocc, b - nocc] - c2[j, i, a - nocc, b - nocc] str1 = hf_str ^ (1 << j) | (1 << b) c2aa *= cistring.cre_des_sign(b, j, hf_str) c2aa *= cistring.cre_des_sign(a, i, str1) str1 ^= (1 << i) | (1 << a) addr = cistring.str2addr(norb, nocc, str1) fcivec[0, addr] = fcivec[addr, 0] = c2aa return fcivec
def pspace(h1e, eri, norb, nelec, hdiag, np=400): '''pspace Hamiltonian to improve Davidson preconditioner. See, CPL, 169, 463 ''' if isinstance(nelec, (int, numpy.number)): nelecb = nelec // 2 neleca = nelec - nelecb else: neleca, nelecb = nelec h1e = numpy.ascontiguousarray(h1e) eri = pyscf.ao2mo.restore(1, eri, norb) nb = cistring.num_strings(norb, nelecb) if hdiag.size < np: addr = numpy.arange(hdiag.size) else: try: addr = numpy.argpartition(hdiag, np - 1)[:np] except AttributeError: addr = numpy.argsort(hdiag)[:np] addra, addrb = divmod(addr, nb) stra = numpy.array([cistring.addr2str(norb, neleca, ia) for ia in addra], dtype=numpy.uint64) strb = numpy.array([cistring.addr2str(norb, nelecb, ib) for ib in addrb], dtype=numpy.uint64) np = len(addr) h0 = numpy.zeros((np, np)) libfci.FCIpspace_h0tril(h0.ctypes.data_as(ctypes.c_void_p), h1e.ctypes.data_as(ctypes.c_void_p), eri.ctypes.data_as(ctypes.c_void_p), stra.ctypes.data_as(ctypes.c_void_p), strb.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(norb), ctypes.c_int(np)) for i in range(np): h0[i, i] = hdiag[addr[i]] h0 = pyscf.lib.hermi_triu(h0) return addr, h0
def symm_initguess(norb, nelec, orbsym, wfnsym=0, irrep_nelec=None): '''Generate CI wavefunction initial guess which has the given symmetry. Args: norb : int Number of orbitals. nelec : int or 2-item list Number of electrons, or 2-item list for (alpha, beta) electrons orbsym : list of int The irrep ID for each orbital. Kwags: wfnsym : int The irrep ID of target symmetry irrep_nelec : dict Freeze occupancy for certain irreps Returns: CI coefficients 2D array which has the target symmetry. ''' neleca, nelecb = _unpack(nelec) orbsym = numpy.asarray(orbsym) if not isinstance(orbsym[0], numpy.number): raise RuntimeError('TODO: convert irrep symbol to irrep id') na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) ci1 = numpy.zeros((na, nb)) ######################## # pass 1: The fixed occs orbleft = numpy.ones(norb, dtype=bool) stra = numpy.zeros(norb, dtype=bool) strb = numpy.zeros(norb, dtype=bool) if irrep_nelec is not None: for k, n in irrep_nelec.items(): orbleft[orbsym == k] = False if isinstance(n, (int, numpy.number)): idx = numpy.where(orbsym == k)[0][:n // 2] stra[idx] = True strb[idx] = True else: na, nb = n stra[numpy.where(orbsym == k)[0][:na]] = True strb[numpy.where(orbsym == k)[0][:nb]] = True if (na - nb) % 2: wfnsym ^= k orbleft = numpy.where(orbleft)[0] neleca_left = neleca - stra.sum() nelecb_left = nelecb - strb.sum() spin = neleca_left - nelecb_left assert (neleca_left >= 0) assert (nelecb_left >= 0) assert (spin >= 0) ######################## # pass 2: search pattern def gen_str_iter(orb_list, nelec): if nelec == 1: for i in orb_list: yield [i] elif nelec >= len(orb_list): yield orb_list else: restorb = orb_list[1:] #yield from gen_str_iter(restorb, nelec) for x in gen_str_iter(restorb, nelec): yield x for x in gen_str_iter(restorb, nelec - 1): yield [orb_list[0]] + x # search for alpha and beta pattern which match to the required symmetry def query(target, nelec_atmost, spin, orbsym): norb = len(orbsym) for excite_level in range(1, nelec_atmost + 1): for beta_only in gen_str_iter(range(norb), excite_level): alpha_allow = [i for i in range(norb) if i not in beta_only] alpha_orbsym = orbsym[alpha_allow] alpha_target = target for i in beta_only: alpha_target ^= orbsym[i] alpha_only = symm.route(alpha_target, spin + excite_level, alpha_orbsym) if alpha_only: alpha_only = [alpha_allow[i] for i in alpha_only] return alpha_only, beta_only raise RuntimeError('No pattern found for wfn irrep %s over orbsym %s' % (target, orbsym)) if spin == 0: aonly = bonly = [] if wfnsym != 0: aonly, bonly = query(wfnsym, neleca_left, spin, orbsym[orbleft]) else: # 1. assume "nelecb_left" doubly occupied orbitals # search for alpha pattern which match to the required symmetry aonly, bonly = orbleft[symm.route(wfnsym, spin, orbsym[orbleft])], [] # dcompose doubly occupied orbitals, search for alpha and beta pattern if len(aonly) != spin: aonly, bonly = query(wfnsym, neleca_left, spin, orbsym[orbleft]) ndocc = neleca_left - len(aonly) # == nelecb_left - len(bonly) docc_allow = numpy.ones(len(orbleft), dtype=bool) docc_allow[aonly] = False docc_allow[bonly] = False docclst = orbleft[numpy.where(docc_allow)[0]][:ndocc] stra[docclst] = True strb[docclst] = True def find_addr_(stra, aonly, nelec): stra[orbleft[aonly]] = True return cistring.str2addr(norb, nelec, ('%i' * norb) % tuple(stra)[::-1]) if bonly: if spin > 0: aonly, socc_only = aonly[:-spin], aonly[-spin:] stra[orbleft[socc_only]] = True stra1 = stra.copy() strb1 = strb.copy() addra = find_addr_(stra, aonly, neleca) addrb = find_addr_(strb, bonly, nelecb) addra1 = find_addr_(stra1, bonly, neleca) addrb1 = find_addr_(strb1, aonly, nelecb) ci1[addra, addrb] = ci1[addra1, addrb1] = numpy.sqrt(.5) else: addra = find_addr_(stra, aonly, neleca) addrb = find_addr_(strb, bonly, nelecb) ci1[addra, addrb] = 1 # target = 0 # for i,k in enumerate(stra): # if k: # target ^= orbsym[i] # for i,k in enumerate(strb): # if k: # target ^= orbsym[i] # print target return ci1
def make_shape(nsite, nelec, nphonon): neleca, nelecb = _unpack_nelec(nelec) na = cistring.num_strings(nsite, neleca) nb = cistring.num_strings(nsite, nelecb) return (na, nb) + (nphonon + 1, ) * nsite
return self.link_index[(norb, nelec)] if __name__ == '__main__': from functools import reduce from pyscf import gto from pyscf import scf from pyscf.fci import direct_spin1 def contract_2e_ref(eri, fcivec, norb, nelec, *args, **kwargs): hc = direct_spin1.contract_2e(eri, numpy.diag(fcivec), norb, nelec) return hc.diagonal() norb = 6 nelec = 3 na = cistring.num_strings(norb, nelec) numpy.random.seed(2) eri = numpy.random.random((norb, ) * 4) eri = ao2mo.restore(1, ao2mo.restore(8, eri, norb), norb) ci0 = numpy.random.random(na) ci0 *= 1. / numpy.linalg.norm(ci0) ci1 = contract_2e(eri, ci0, norb, (nelec, nelec)) ci1ref = contract_2e_ref(eri, ci0, norb, (nelec, nelec)) print(abs(ci1 - ci1ref).max()) dm1, dm2 = make_rdm12(ci0, norb, (nelec, nelec), reorder=False) print(numpy.einsum('ijkl,ijkl', dm2, eri) - ci1.dot(ci0)) print(abs(dm1 - make_rdm1(ci0, norb, (nelec, nelec))).max()) mol = gto.Mole() mol.verbose = 0
ss = spin_square(ci0, norb, nelec) print(ss) ss = spin_square0(ci0, norb, nelec) print(ss) ss = local_spin(ci0, norb, nelec, m.mo_coeff, m.get_ovlp(), range(5)) print('local spin for H1..H5 = 0.998988389', ss[0]) ci1 = numpy.zeros((4, 4)) ci1[0, 0] = 1 print(spin_square(ci1, 4, (3, 1))) print(spin_square0(ci1, 4, (3, 1))) print(numpy.einsum('ij,ij->', ci1, contract_ss(ci1, 4, (3, 1))), spin_square(ci1, 4, (3, 1))[0]) numpy.random.seed(1) n = cistring.num_strings(6, 3) ci0 = numpy.random.random((n, n)) print(numpy.einsum('ij,ij->', ci0, contract_ss(ci0, 6, 6)), spin_square(ci0, 6, 6)[0]) na = cistring.num_strings(6, 4) nb = cistring.num_strings(6, 2) ci0 = numpy.random.random((na, nb)) print(numpy.einsum('ij,ij->', ci0, contract_ss(ci0, 6, (4, 2))), spin_square(ci0, 6, (4, 2))[0]) print('----------') mol = gto.Mole() mol.verbose = 0 mol.output = None
def contract_ss(fcivec, norb, nelec): '''Contract spin square operator with FCI wavefunction :math:`S^2 |CI>` ''' neleca, nelecb = _unpack_nelec(nelec) na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) fcivec = fcivec.reshape(na, nb) def gen_map(fstr_index, nelec, des=True): a_index = fstr_index(range(norb), nelec) amap = numpy.zeros((a_index.shape[0], norb, 2), dtype=numpy.int32) if des: for k, tab in enumerate(a_index): amap[k, tab[:, 1]] = tab[:, 2:] else: for k, tab in enumerate(a_index): amap[k, tab[:, 0]] = tab[:, 2:] return amap if neleca > 0: ades = gen_map(cistring.gen_des_str_index, neleca) else: ades = None if nelecb > 0: bdes = gen_map(cistring.gen_des_str_index, nelecb) else: bdes = None if neleca < norb: acre = gen_map(cistring.gen_cre_str_index, neleca, False) else: acre = None if nelecb < norb: bcre = gen_map(cistring.gen_cre_str_index, nelecb, False) else: bcre = None def trans(ci1, aindex, bindex, nea, neb): if aindex is None or bindex is None: return None t1 = numpy.zeros( (cistring.num_strings(norb, nea), cistring.num_strings(norb, neb))) for i in range(norb): signa = aindex[:, i, 1] signb = bindex[:, i, 1] maska = numpy.where(signa != 0)[0] maskb = numpy.where(signb != 0)[0] addra = aindex[maska, i, 0] addrb = bindex[maskb, i, 0] citmp = lib.take_2d(fcivec, maska, maskb) citmp *= signa[maska].reshape(-1, 1) citmp *= signb[maskb] #: t1[addra.reshape(-1,1),addrb] += citmp lib.takebak_2d(t1, citmp, addra, addrb) for i in range(norb): signa = aindex[:, i, 1] signb = bindex[:, i, 1] maska = numpy.where(signa != 0)[0] maskb = numpy.where(signb != 0)[0] addra = aindex[maska, i, 0] addrb = bindex[maskb, i, 0] citmp = lib.take_2d(t1, addra, addrb) citmp *= signa[maska].reshape(-1, 1) citmp *= signb[maskb] #: ci1[maska.reshape(-1,1), maskb] += citmp lib.takebak_2d(ci1, citmp, maska, maskb) ci1 = numpy.zeros((na, nb)) trans(ci1, ades, bcre, neleca - 1, nelecb + 1) # S+*S- trans(ci1, acre, bdes, neleca + 1, nelecb - 1) # S-*S+ ci1 *= .5 ci1 += (neleca - nelecb)**2 * .25 * fcivec return ci1
mol.build() m = scf.UHF(mol) ehf = m.scf() cis = FCISolver(mol) norb = m.mo_energy[0].size nea = (mol.nelectron + 1) // 2 neb = (mol.nelectron - 1) // 2 nelec = (nea, neb) mo_a = m.mo_coeff[0] mo_b = m.mo_coeff[1] h1e_a = reduce(numpy.dot, (mo_a.T, m.get_hcore(), mo_a)) h1e_b = reduce(numpy.dot, (mo_b.T, m.get_hcore(), mo_b)) g2e_aa = ao2mo.incore.general(m._eri, (mo_a, ) * 4, compact=False) g2e_aa = g2e_aa.reshape(norb, norb, norb, norb) g2e_ab = ao2mo.incore.general(m._eri, (mo_a, mo_a, mo_b, mo_b), compact=False) g2e_ab = g2e_ab.reshape(norb, norb, norb, norb) g2e_bb = ao2mo.incore.general(m._eri, (mo_b, ) * 4, compact=False) g2e_bb = g2e_bb.reshape(norb, norb, norb, norb) h1e = (h1e_a, h1e_b) eri = (g2e_aa, g2e_ab, g2e_bb) na = cistring.num_strings(norb, nea) nb = cistring.num_strings(norb, neb) numpy.random.seed(15) fcivec = numpy.random.random((na, nb)) e = kernel(h1e, eri, norb, nelec)[0] print(e, e - -8.65159903476)
] mol.basis = { 'H': 'sto-3g', 'O': 'sto-3g', } mol.symmetry = 1 mol.build() m = scf.RHF(mol) ehf = m.scf() norb = m.mo_coeff.shape[1] nelec = mol.nelectron - 1 h1e = reduce(numpy.dot, (m.mo_coeff.T, scf.hf.get_hcore(mol), m.mo_coeff)) eri = ao2mo.incore.full(m._eri, m.mo_coeff) numpy.random.seed(1) na = cistring.num_strings(norb, nelec // 2 + 1) nb = cistring.num_strings(norb, nelec // 2) fcivec = numpy.random.random((na, nb)) orbsym = symm.label_orb_symm(mol, mol.irrep_id, mol.symm_orb, m.mo_coeff) cis = FCISolver(mol) cis.orbsym = orbsym fcivec = addons.symmetrize_wfn(fcivec, norb, nelec, cis.orbsym, wfnsym=0) ci1 = cis.contract_2e(eri, fcivec, norb, nelec, orbsym=cis.orbsym, wfnsym=0) ci1ref = direct_spin1.contract_2e(eri, fcivec, norb, nelec)
def to_fcivec(cisdvec, norb, nelec, frozen=0): '''Convert CISD coefficients to FCI coefficients''' if isinstance(nelec, (int, numpy.number)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec frozena_mask = numpy.zeros(norb, dtype=bool) frozenb_mask = numpy.zeros(norb, dtype=bool) if isinstance(frozen, (int, numpy.integer)): nfroza = nfrozb = frozen frozena_mask[:frozen] = True frozenb_mask[:frozen] = True else: nfroza = len(frozen[0]) nfrozb = len(frozen[1]) frozena_mask[frozen[0]] = True frozenb_mask[frozen[1]] = True # if nfroza != nfrozb: # raise NotImplementedError nocca = numpy.count_nonzero(~frozena_mask[:neleca]) noccb = numpy.count_nonzero(~frozenb_mask[:nelecb]) nmo = nmoa, nmob = norb - nfroza, norb - nfrozb nocc = nocca, noccb nvira, nvirb = nmoa - nocca, nmob - noccb c0, c1, c2 = cisdvec_to_amplitudes(cisdvec, nmo, nocc) c1a, c1b = c1 c2aa, c2ab, c2bb = c2 t1addra, t1signa = cisd.tn_addrs_signs(nmoa, nocca, 1) t1addrb, t1signb = cisd.tn_addrs_signs(nmob, noccb, 1) na = cistring.num_strings(nmoa, nocca) nb = cistring.num_strings(nmob, noccb) fcivec = numpy.zeros((na,nb)) fcivec[0,0] = c0 fcivec[t1addra,0] = c1a.ravel() * t1signa fcivec[0,t1addrb] = c1b.ravel() * t1signb c2ab = c2ab.transpose(0,2,1,3).reshape(nocca*nvira,-1) c2ab = numpy.einsum('i,j,ij->ij', t1signa, t1signb, c2ab) fcivec[t1addra[:,None],t1addrb] = c2ab if nocca > 1 and nvira > 1: ooidx = numpy.tril_indices(nocca, -1) vvidx = numpy.tril_indices(nvira, -1) c2aa = c2aa[ooidx][:,vvidx[0],vvidx[1]] t2addra, t2signa = cisd.tn_addrs_signs(nmoa, nocca, 2) fcivec[t2addra,0] = c2aa.ravel() * t2signa if noccb > 1 and nvirb > 1: ooidx = numpy.tril_indices(noccb, -1) vvidx = numpy.tril_indices(nvirb, -1) c2bb = c2bb[ooidx][:,vvidx[0],vvidx[1]] t2addrb, t2signb = cisd.tn_addrs_signs(nmob, noccb, 2) fcivec[0,t2addrb] = c2bb.ravel() * t2signb if nfroza == nfrozb == 0: return fcivec assert(norb < 63) strsa = cistring.gen_strings4orblist(range(norb), neleca) strsb = cistring.gen_strings4orblist(range(norb), nelecb) na = len(strsa) nb = len(strsb) count_a = numpy.zeros(na, dtype=int) count_b = numpy.zeros(nb, dtype=int) parity_a = numpy.zeros(na, dtype=bool) parity_b = numpy.zeros(nb, dtype=bool) core_a_mask = numpy.ones(na, dtype=bool) core_b_mask = numpy.ones(nb, dtype=bool) for i in range(norb): if frozena_mask[i]: if i < neleca: core_a_mask &= (strsa & (1<<i)) != 0 parity_a ^= (count_a & 1) == 1 else: core_a_mask &= (strsa & (1<<i)) == 0 else: count_a += (strsa & (1<<i)) != 0 if frozenb_mask[i]: if i < nelecb: core_b_mask &= (strsb & (1<<i)) != 0 parity_b ^= (count_b & 1) == 1 else: core_b_mask &= (strsb & (1<<i)) == 0 else: count_b += (strsb & (1<<i)) != 0 sub_strsa = strsa[core_a_mask & (count_a == nocca)] sub_strsb = strsb[core_b_mask & (count_b == noccb)] addrsa = cistring.strs2addr(norb, neleca, sub_strsa) addrsb = cistring.strs2addr(norb, nelecb, sub_strsb) fcivec1 = numpy.zeros((na,nb)) fcivec1[addrsa[:,None],addrsb] = fcivec fcivec1[parity_a,:] *= -1 fcivec1[:,parity_b] *= -1 return fcivec1
def to_fcivec(cisdvec, norb, nelec, frozen=None): '''Convert CISD coefficients to FCI coefficients''' if isinstance(nelec, (int, numpy.number)): nelecb = nelec // 2 neleca = nelec - nelecb else: neleca, nelecb = nelec assert (neleca == nelecb) frozen_mask = numpy.zeros(norb, dtype=bool) if frozen is None: nfroz = 0 elif isinstance(frozen, (int, numpy.integer)): nfroz = frozen frozen_mask[:frozen] = True else: nfroz = len(frozen) frozen_mask[frozen] = True nocc = numpy.count_nonzero(~frozen_mask[:neleca]) nmo = norb - nfroz nvir = nmo - nocc c0, c1, c2 = cisdvec_to_amplitudes(cisdvec, nmo, nocc) t1addr, t1sign = tn_addrs_signs(nmo, nocc, 1) na = cistring.num_strings(nmo, nocc) fcivec = numpy.zeros((na, na)) fcivec[0, 0] = c0 fcivec[0, t1addr] = fcivec[t1addr, 0] = c1.ravel() * t1sign c2ab = c2.transpose(0, 2, 1, 3).reshape(nocc * nvir, -1) c2ab = numpy.einsum('i,j,ij->ij', t1sign, t1sign, c2ab) fcivec[t1addr[:, None], t1addr] = c2ab if nocc > 1 and nvir > 1: c2aa = c2 - c2.transpose(1, 0, 2, 3) ooidx = numpy.tril_indices(nocc, -1) vvidx = numpy.tril_indices(nvir, -1) c2aa = c2aa[ooidx][:, vvidx[0], vvidx[1]] t2addr, t2sign = tn_addrs_signs(nmo, nocc, 2) fcivec[0, t2addr] = fcivec[t2addr, 0] = c2aa.ravel() * t2sign if nfroz == 0: return fcivec assert (norb < 63) strs = cistring.gen_strings4orblist(range(norb), neleca) na = len(strs) count = numpy.zeros(na, dtype=int) parity = numpy.zeros(na, dtype=bool) core_mask = numpy.ones(na, dtype=bool) # During the loop, count saves the number of occupied orbitals that # lower (with small orbital ID) than the present orbital i. # Moving all the frozen orbitals to the beginning of the orbital list # (before the occupied orbitals) leads to parity odd (= True, with # negative sign) or even (= False, with positive sign). for i in range(norb): if frozen_mask[i]: if i < neleca: # frozen occupied orbital should be occupied core_mask &= (strs & (1 << i)) != 0 parity ^= (count & 1) == 1 else: # frozen virtual orbital should not be occupied. # parity is not needed since it's unoccupied core_mask &= (strs & (1 << i)) == 0 else: count += (strs & (1 << i)) != 0 sub_strs = strs[core_mask & (count == nocc)] addrs = cistring.strs2addr(norb, neleca, sub_strs) fcivec1 = numpy.zeros((na, na)) fcivec1[addrs[:, None], addrs] = fcivec fcivec1[parity, :] *= -1 fcivec1[:, parity] *= -1 return fcivec1