def csdstrs2csdaddrs(norb, neleca, nelecb, csdstrs): assert (len(csdstrs[0]) == len(csdstrs[1])) assert (len(csdstrs[0]) == len(csdstrs[2])) assert (len(csdstrs[0]) == len(csdstrs[3])) min_npair, npair_offset, npair_dconf_size, npair_sconf_size, npair_spins_size = get_csdaddrs_shape( norb, neleca, nelecb) csdaddrs = np.empty(len(csdstrs[0]), dtype=np.int32) for npair, offset, dconf_size, sconf_size, spins_size in zip( range(min_npair, min(neleca, nelecb) + 1), npair_offset, npair_dconf_size, npair_sconf_size, npair_spins_size): nspins = neleca + nelecb - 2 * npair nup = (nspins + neleca - nelecb) // 2 assert ((nspins + neleca - nelecb) % 2 == 0) idx = (csdstrs[0] == npair) dconf_addr = cistring.strs2addr(norb, npair, csdstrs[1, idx]) sconf_addr = cistring.strs2addr(norb - npair, nspins, csdstrs[2, idx]) spins_addr = cistring.strs2addr(nspins, nup, csdstrs[3, idx]) csdaddrs[idx] = np.asarray([ offset + (dconf * sconf_size * spins_size) + (sconf * spins_size) + spins for dconf, sconf, spins in zip(dconf_addr, sconf_addr, spins_addr) ], dtype=np.int32) return csdaddrs
def tn_addrs_signs(norb, nelec, n_excite): '''Compute the FCI strings (address) for CIS n-excitation amplitudes and the signs of the coefficients when transferring the reference from physics vacuum to HF vacuum. ''' if n_excite > nelec: print("Warning: Not enough occupied orbitals to excite.") return [0], [0] nocc = nelec hole_strs = cistring.gen_strings4orblist(range(nocc), nocc - n_excite) # For HF vacuum, hole operators are ordered from low-lying to high-lying # orbitals. It leads to the opposite string ordering. hole_strs = hole_strs[::-1] hole_sum = numpy.zeros(len(hole_strs), dtype=int) for i in range(nocc): hole_at_i = (hole_strs & (1 << i)) == 0 hole_sum[hole_at_i] += i # The hole operators are listed from low-lying to high-lying orbitals # (from left to right). For i-th (0-based) hole operator, the number of # orbitals which are higher than i determines the sign. This number # equals to nocc-(i+1). After removing the highest hole operator, nocc # becomes nocc-1, the sign for next hole operator j will be associated to # nocc-1-(j+1). By iteratively calling this procedure, the overall sign # for annihilating three holes is (-1)**(3*nocc - 6 - sum i) sign = (-1)**(n_excite * nocc - n_excite * (n_excite + 1) // 2 - hole_sum) particle_strs = cistring.gen_strings4orblist(range(nocc, norb), n_excite) strs = hole_strs[:, None] ^ particle_strs addrs = cistring.strs2addr(norb, nocc, strs.ravel()) signs = numpy.vstack([sign] * len(particle_strs)).T.ravel() return addrs, signs
def csdaddrs2ddaddrs (norb, neleca, nelecb, csdaddrs): ''' Inverse operation of ddaddrs2csdaddrs ddaddrs is returned in the format of a contiguous 2d ndarray with shape (naddrs,2), where naddrs is the length of csdaddrs ''' t_start = time.time () csdaddrs = np.asarray (csdaddrs) if not csdaddrs.flags['C_CONTIGUOUS']: csdaddrs = np.ravel (csdaddrs, order='C') t0 = time.time () csdstrs = csdaddrs2csdstrs (norb, neleca, nelecb, csdaddrs) t1 = time.time () ddstrs = csdstrs2ddstrs (norb, neleca, nelecb, csdstrs) t2 = time.time () ddaddrs = np.ascontiguousarray ([cistring.strs2addr (norb, neleca, ddstrs[0]), cistring.strs2addr (norb, nelecb, ddstrs[1])], dtype=np.int32) t3 = time.time () t_tot = time.time () - t_start return ddaddrs
def test_str2addr(self): self.assertEqual(cistring.str2addr(6, 3, int('0b11001' ,2)), 7) self.assertEqual(cistring.str2addr(6, 3, int('0b11010' ,2)), 8) self.assertEqual(cistring.str2addr(7, 4, int('0b110011',2)), 9) self.assertEqual(cistring.str2addr(6, 3, cistring.addr2str(6, 3, 7)), 7) self.assertEqual(cistring.str2addr(6, 3, cistring.addr2str(6, 3, 8)), 8) self.assertEqual(cistring.str2addr(7, 4, cistring.addr2str(7, 4, 9)), 9) self.assertTrue(all(numpy.arange(20) == cistring.strs2addr(6, 3, cistring.addrs2str(6, 3, range(20)))))
def test_str2addr(self): self.assertEqual(cistring.str2addr(6, 3, int('0b11001', 2)), 7) self.assertEqual(cistring.str2addr(6, 3, int('0b11010', 2)), 8) self.assertEqual(cistring.str2addr(7, 4, int('0b110011', 2)), 9) self.assertEqual(cistring.str2addr(6, 3, cistring.addr2str(6, 3, 7)), 7) self.assertEqual(cistring.str2addr(6, 3, cistring.addr2str(6, 3, 8)), 8) self.assertEqual(cistring.str2addr(7, 4, cistring.addr2str(7, 4, 9)), 9) self.assertTrue( all( numpy.arange(20) == cistring.strs2addr( 6, 3, cistring.addrs2str(6, 3, range(20)))))
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
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 assert (neleca == nelecb) frozen_mask = numpy.zeros(norb, dtype=bool) if 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 = t1strs(nmo, nocc) na = cistring.num_strings(nmo, 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, nmo): 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(nmo, nocc, str1) fcivec[0, addr] = fcivec[addr, 0] = c2aa 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