def cre_des_linkstr(strs, norb, nelec): addrs = dict(zip(strs, range(len(strs)))) nvir = norb - nelec link_index = numpy.zeros((len(addrs), nelec + nelec * nvir, 4), dtype=int) link_index[:, :, 0] = -1 for i0, str1 in enumerate(strs): occ = [] vir = [] for i in range(norb): if str1 & (1 << i): occ.append(i) else: vir.append(i) k = 0 for i in occ: link_index[i0, k] = (i, i, i0, 1) k += 1 for a in vir: for i in occ: str0 = str1 ^ (1 << i) | (1 << a) if str0 in addrs: # [cre, des, targetddress, parity] link_index[i0, k] = (a, i, addrs[str0], cistring.cre_des_sign(a, i, str1)) k += 1 return link_index
def cre_des_linkstr(strs, norb, nelec): addrs = dict(zip(strs, range(len(strs)))) nvir = norb - nelec link_index = numpy.zeros((len(addrs), nelec + nelec * nvir, 4), dtype=numpy.int32) for i0, str1 in enumerate(strs): occ = [] vir = [] for i in range(norb): if str1 & (1 << i): occ.append(i) else: vir.append(i) k = 0 for i in occ: link_index[i0, k] = (i, i, i0, 1) k += 1 for a in vir: for i in occ: str0 = str1 ^ (1 << i) | (1 << a) if str0 in addrs: # [cre, des, targetddress, parity] link_index[i0, k] = (a, i, addrs[str0], cistring.cre_des_sign(a, i, str1)) k += 1 return link_index
def t2strs(norb, nelec): nocc = nelec hf_str = int('1'*nocc, 2) addrs = [] signs = [] for a in range(nocc+1, norb): for b in range(nocc, a): for i in reversed(range(1,nocc)): for j in reversed(range(i)): str1 = hf_str ^ (1 << j) | (1 << b) sign = cistring.cre_des_sign(b, j, hf_str) sign*= cistring.cre_des_sign(a, i, str1) str1^= (1 << i) | (1 << a) addrs.append(cistring.str2addr(norb, nelec, str1)) signs.append(sign) return numpy.asarray(addrs), numpy.asarray(signs)
def t1strs(norb, nelec): nocc = nelec hf_str = int('1' * nocc, 2) addrs = [] signs = [] for a in range(nocc, norb): for i in reversed(range(nocc)): str1 = hf_str ^ (1 << i) | (1 << a) addrs.append(cistring.str2addr(norb, nelec, str1)) signs.append(cistring.cre_des_sign(a, i, hf_str)) return numpy.asarray(addrs), numpy.asarray(signs)
def t1strs(norb, nelec): nocc = nelec hf_str = int('1'*nocc, 2) addrs = [] signs = [] for a in range(nocc, norb): for i in reversed(range(nocc)): str1 = hf_str ^ (1 << i) | (1 << a) addrs.append(cistring.str2addr(norb, nelec, str1)) signs.append(cistring.cre_des_sign(a, i, hf_str)) return numpy.asarray(addrs), numpy.asarray(signs)
def t1strs(norb, nelec): '''FCI strings (address) for CIS single-excitation amplitues''' nocc = nelec hf_str = int('1' * nocc, 2) addrs = [] signs = [] for a in range(nocc, norb): for i in reversed(range(nocc)): str1 = hf_str ^ (1 << i) | (1 << a) addrs.append(cistring.str2addr(norb, nelec, str1)) signs.append(cistring.cre_des_sign(a, i, hf_str)) return numpy.asarray(addrs), numpy.asarray(signs)
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 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 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