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(nelec) strsa = numpy.asarray(cistring.make_strings(range(norb), neleca)) strsb = numpy.asarray(cistring.make_strings(range(norb), nelecb)) if isinstance(ci, numpy.ndarray) and ci.ndim <= 2: wfnsym = _guess_wfnsym(ci, strsa, strsb, orbsym) else: wfnsym = [_guess_wfnsym(c, strsa, strsb, orbsym) for c in ci] if any(wfnsym[0] != x for x in wfnsym): warnings.warn('Different wfnsym %s found in different CI vecotrs' % wfnsym) wfnsym = wfnsym[0] return wfnsym
def symmetrize_wfn(ci, norb, nelec, orbsym, wfnsym=0): '''Symmetrize the CI wavefunction by zeroing out the determinants which do not have the right symmetry. 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. Kwags: wfnsym : int The irrep ID of target symmetry Returns: 2D array which is the symmetrized CI coefficients ''' neleca, nelecb = _unpack_nelec(nelec) strsa = numpy.asarray(cistring.make_strings(range(norb), neleca)) strsb = numpy.asarray(cistring.make_strings(range(norb), nelecb)) return _symmetrize_wfn(ci, strsa, strsb, orbsym, wfnsym)
def gen_frag_basis (psi, ifrag, ci_f=None, nelec=None): if ci_f is None: ci_f = psi.ci0_f norb, norb_f, nfrag = psi.norb, psi.norb_f, psi.nfrag ci0 = np.ones ([1,1], dtype=ci_f[0].dtype) n = 0 for jfrag, (c, dn) in enumerate (zip (ci_f, norb_f)): if (ifrag == jfrag): continue n += dn ndet = 2**n ci0 = np.multiply.outer (c, ci0).transpose (0,2,1,3).reshape (ndet, ndet) n = norb_f[ifrag] ndet = 2**norb ci1 = np.empty ((ndet, ndet), dtype=ci_f[0].dtype) norb0 = sum (norb_f[ifrag+1:]) if ifrag+1<nfrag else 0 norb1 = norb_f[ifrag] norb2 = sum (norb_f[:ifrag]) if ifrag>0 else 0 ndet0, ndet1, ndet2 = 2**norb0, 2**norb1, 2**norb2 deta_gen, detb_gen = range (ndet1), range (ndet1) if nelec is not None: nelec = _unpack_nelec (nelec) deta_gen = make_strings (range (norb1), nelec[0]) detb_gen = make_strings (range (norb1), nelec[1]) for ideta, idetb in product (deta_gen, detb_gen): ci1[:,:] = 0 ci1 = ci1.reshape (ndet0, ndet1, ndet2, ndet0, ndet1, ndet2) ci1[:,ideta,:,:,idetb,:] = ci0.reshape (ndet0, ndet2, ndet0, ndet2) ci1 = ci1.reshape (ndet, ndet) ci1 = psi.fermion_spin_shuffle (ci1) yield ideta, idetb, ci1
def guess_wfnsym(self, norb, nelec, fcivec=None, orbsym=None, wfnsym=None, **kwargs): ''' Guess point group symmetry of the FCI wavefunction. If fcivec is given, the symmetry of fcivec is used. Otherwise the symmetry is based on the HF determinant. ''' if orbsym is None: orbsym = self.orbsym verbose = kwargs.get('verbose', None) log = logger.new_logger(self, verbose) nelec = _unpack_nelec(nelec, self.spin) if fcivec is None: # guess wfnsym if initial guess is not given wfnsym = _id_wfnsym(self, norb, nelec, orbsym, wfnsym) log.debug('Guessing CI wfn symmetry = %s', wfnsym) elif wfnsym is None: wfnsym = addons.guess_wfnsym(fcivec, norb, nelec, orbsym) log.debug('Guessing CI wfn symmetry = %s', wfnsym) else: # verify if the input wfnsym is consistent with the symmetry of fcivec neleca, nelecb = nelec strsa = numpy.asarray(cistring.make_strings(range(norb), neleca)) strsb = numpy.asarray(cistring.make_strings(range(norb), nelecb)) na, nb = strsa.size, strsb.size orbsym_in_d2h = numpy.asarray(orbsym) % 10 airreps = numpy.zeros(na, dtype=numpy.int32) birreps = numpy.zeros(nb, dtype=numpy.int32) for i, ir in enumerate(orbsym_in_d2h): airreps[numpy.bitwise_and(strsa, 1 << i) > 0] ^= ir birreps[numpy.bitwise_and(strsb, 1 << i) > 0] ^= ir wfnsym = _id_wfnsym(self, norb, nelec, orbsym, wfnsym) mask = (airreps.reshape(-1, 1) ^ birreps) == wfnsym if isinstance(fcivec, numpy.ndarray) and fcivec.ndim <= 2: fcivec = [fcivec] if all(abs(c.reshape(na, nb)[mask]).max() < 1e-5 for c in fcivec): raise RuntimeError( 'Input wfnsym is not consistent with fcivec coefficients') return wfnsym
def test_spin0_contract_2e_symm(self): norb, nelec = 7, (4,4) strs = cistring.make_strings(range(norb), nelec[0]) numpy.random.seed(11) mask = numpy.random.random(len(strs)) > .3 strsa = strs[mask] ci_strs = (strsa, strsa) na = len(strsa) ci_coeff = numpy.random.random((na,na)) ci_coeff = ci_coeff + ci_coeff.T civec_strs = selected_ci._as_SCIvector(ci_coeff, ci_strs) orbsym = (numpy.random.random(norb) * 4).astype(int) nn = norb*(norb+1)//2 eri = ao2mo.restore(1, (numpy.random.random(nn*(nn+1)//2)-.2)**3, norb) oosym = orbsym[:,None] ^ orbsym oosym = oosym.reshape(-1,1) ^ oosym.ravel() eri[oosym.reshape([norb]*4)!=0] = 0 ci0 = fci.selected_ci.to_fci(civec_strs, norb, nelec) ci0 = fci.addons.symmetrize_wfn(ci0, norb, nelec, orbsym) civec_strs = fci.selected_ci.from_fci(ci0, civec_strs._strs, norb, nelec) myci = selected_ci_spin0_symm.SCI() e1 = numpy.dot(civec_strs.ravel(), myci.contract_2e(eri, civec_strs, norb, nelec, orbsym=orbsym).ravel()) e2 = numpy.dot(ci0.ravel(), direct_spin1_symm.contract_2e(eri, ci0, norb, nelec, orbsym=orbsym).ravel()) self.assertAlmostEqual(e1, e2, 9)
def test_rdm_2e(self): norb, nelec = 10, 1 strs = cistring.make_strings(range(norb), nelec) numpy.random.seed(11) mask = numpy.random.random(len(strs)) > .6 strsa = strs[mask] mask = numpy.random.random(len(strs)) > .7 strsb = strs[mask] ci_strs = (strsa, strsb) ci_coeff = selected_ci._as_SCIvector(numpy.random.random((len(strsa),len(strsb))), ci_strs) ci0 = selected_ci.to_fci(ci_coeff, norb, (nelec,nelec)) dm1ref, dm2ref = direct_spin1.make_rdm12s(ci0, norb, (nelec,nelec)) dm1 = selected_ci.make_rdm1s(ci_coeff, norb, (nelec,nelec)) self.assertAlmostEqual(abs(dm1[0]-dm1ref[0]).sum(), 0, 9) self.assertAlmostEqual(abs(dm1[1]-dm1ref[1]).sum(), 0, 9) dm2 = selected_ci.make_rdm2s(ci_coeff, norb, (nelec,nelec)) self.assertAlmostEqual(abs(dm2[0]-dm2ref[0]).sum(), 0, 9) self.assertAlmostEqual(abs(dm2[1]-dm2ref[1]).sum(), 0, 9) self.assertAlmostEqual(abs(dm2[2]-dm2ref[2]).sum(), 0, 9) ci1_coeff = selected_ci._as_SCIvector(numpy.random.random((len(strsa),len(strsb))), ci_strs) ci1 = selected_ci.to_fci(ci1_coeff, norb, (nelec,nelec)) dm1ref, dm2ref = direct_spin1.trans_rdm12s(ci1, ci0, norb, (nelec,nelec)) dm1 = selected_ci.trans_rdm1s(ci1_coeff, ci_coeff, norb, (nelec,nelec)) self.assertAlmostEqual(abs(dm1[0]-dm1ref[0]).sum(), 0, 9) self.assertAlmostEqual(abs(dm1[1]-dm1ref[1]).sum(), 0, 9)
def test_contract_2e_1(self): myci = selected_ci.SCI() nelec = (4,3) strsa = cistring.make_strings(range(norb), nelec[0]) strsb = cistring.make_strings(range(norb), nelec[1]) ci0 = selected_ci._as_SCIvector(numpy.random.random((len(strsa),len(strsb))), (strsa,strsb)) h2 = ao2mo.restore(1, eri, norb) c1 = myci.contract_2e(h2, ci0, norb, nelec) c2 = direct_spin1.contract_2e(h2, ci0, norb, nelec) self.assertAlmostEqual(float(abs(c1-c2).sum()), 0, 9) dm1_1 = myci.make_rdm1(c1, norb, nelec) dm1_2 = direct_spin1.make_rdm1(c2, norb, nelec) self.assertAlmostEqual(abs(dm1_1 - dm1_2).sum(), 0, 9) dm2_1 = myci.make_rdm12(c1, norb, nelec)[1] dm2_2 = direct_spin1.make_rdm12(c2, norb, nelec)[1] self.assertAlmostEqual(abs(dm2_1 - dm2_2).sum(), 0, 9)
def test_spin0_contract_2e_symm(self): norb, nelec = 7, (4, 4) strs = cistring.make_strings(range(norb), nelec[0]) numpy.random.seed(11) mask = numpy.random.random(len(strs)) > .3 strsa = strs[mask] ci_strs = (strsa, strsa) na = len(strsa) ci_coeff = numpy.random.random((na, na)) ci_coeff = ci_coeff + ci_coeff.T civec_strs = selected_ci._as_SCIvector(ci_coeff, ci_strs) orbsym = (numpy.random.random(norb) * 4).astype(int) nn = norb * (norb + 1) // 2 eri = ao2mo.restore(1, (numpy.random.random(nn * (nn + 1) // 2) - .2)**3, norb) oosym = orbsym[:, None] ^ orbsym oosym = oosym.reshape(-1, 1) ^ oosym.ravel() eri[oosym.reshape([norb] * 4) != 0] = 0 ci0 = fci.selected_ci.to_fci(civec_strs, norb, nelec) ci0 = fci.addons.symmetrize_wfn(ci0, norb, nelec, orbsym) civec_strs = fci.selected_ci.from_fci(ci0, civec_strs._strs, norb, nelec) myci = selected_ci_spin0_symm.SCI() e1 = numpy.dot( civec_strs.ravel(), myci.contract_2e(eri, civec_strs, norb, nelec, orbsym=orbsym).ravel()) e2 = numpy.dot( ci0.ravel(), direct_spin1_symm.contract_2e(eri, ci0, norb, nelec, orbsym=orbsym).ravel()) self.assertAlmostEqual(e1, e2, 9)
def test_guess_wfnsym(self): norb, nelec = 7, (4, 4) strs = cistring.make_strings(range(norb), nelec[0]) numpy.random.seed(11) mask = numpy.random.random(len(strs)) > .3 strsa = strs[mask] mask = numpy.random.random(len(strs)) > .2 strsb = strs[mask] ci_strs = (strsa, strsb) ci0 = selected_ci._as_SCIvector( numpy.random.random((len(strsa), len(strsb))), ci_strs) fake_mol = gto.M() fake_mol.groupname = 'C2v' cis = selected_ci_symm.SelectedCI(fake_mol) cis.orbsym = orbsym = (numpy.random.random(norb) * 4).astype(int) self.assertEqual(cis.guess_wfnsym(norb, nelec), 0) self.assertEqual(cis.guess_wfnsym(norb, nelec, ci0), 3) self.assertEqual(cis.guess_wfnsym(norb, nelec, ci0, wfnsym=0), 0) self.assertEqual(cis.guess_wfnsym(norb, nelec, ci0, wfnsym='B2'), 3) ci0[:] = 0 self.assertRaises(RuntimeError, cis.guess_wfnsym, norb, nelec, ci0, wfnsym=1)
def test_rdm_2e(self): norb, nelec = 10, 1 strs = cistring.make_strings(range(norb), nelec) numpy.random.seed(11) mask = numpy.random.random(len(strs)) > .6 strsa = strs[mask] mask = numpy.random.random(len(strs)) > .7 strsb = strs[mask] ci_strs = (strsa, strsb) ci_coeff = selected_ci._as_SCIvector( numpy.random.random((len(strsa), len(strsb))), ci_strs) ci0 = selected_ci.to_fci(ci_coeff, norb, (nelec, nelec)) dm1ref, dm2ref = direct_spin1.make_rdm12s(ci0, norb, (nelec, nelec)) dm1 = selected_ci.make_rdm1s(ci_coeff, norb, (nelec, nelec)) self.assertAlmostEqual(abs(dm1[0] - dm1ref[0]).sum(), 0, 9) self.assertAlmostEqual(abs(dm1[1] - dm1ref[1]).sum(), 0, 9) dm2 = selected_ci.make_rdm2s(ci_coeff, norb, (nelec, nelec)) self.assertAlmostEqual(abs(dm2[0] - dm2ref[0]).sum(), 0, 9) self.assertAlmostEqual(abs(dm2[1] - dm2ref[1]).sum(), 0, 9) self.assertAlmostEqual(abs(dm2[2] - dm2ref[2]).sum(), 0, 9) ci1_coeff = selected_ci._as_SCIvector( numpy.random.random((len(strsa), len(strsb))), ci_strs) ci1 = selected_ci.to_fci(ci1_coeff, norb, (nelec, nelec)) dm1ref, dm2ref = direct_spin1.trans_rdm12s(ci1, ci0, norb, (nelec, nelec)) dm1 = selected_ci.trans_rdm1s(ci1_coeff, ci_coeff, norb, (nelec, nelec)) self.assertAlmostEqual(abs(dm1[0] - dm1ref[0]).sum(), 0, 9) self.assertAlmostEqual(abs(dm1[1] - dm1ref[1]).sum(), 0, 9)
def test_des_linkstr1(self): norb, nelec = 10, 4 strs = cistring.make_strings(range(norb), nelec) numpy.random.seed(11) mask = numpy.random.random(len(strs)) > .6 strs = strs[mask] c_index0 = gen_cre_linkstr(strs, norb, nelec) c_index1 = selected_ci.gen_cre_linkstr(strs, norb, nelec) c_index1[:, :, 1] = 0 self.assertTrue(numpy.all(c_index0 == c_index1))
def test_des_linkstr(self): norb, nelec = 10, 4 strs = cistring.make_strings(range(norb), nelec) numpy.random.seed(11) mask = numpy.random.random(len(strs)) > .6 strs = strs[mask] c_index0 = gen_cre_linkstr(strs, norb, nelec) c_index1 = selected_ci.gen_cre_linkstr(strs, norb, nelec) c_index1[:,:,1] = 0 self.assertTrue(numpy.all(c_index0 == c_index1))
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(nelec) strsa = numpy.asarray(cistring.make_strings(range(norb), neleca)) strsb = numpy.asarray(cistring.make_strings(range(norb), nelecb)) return _guess_wfnsym(ci, strsa, strsb, orbsym)
def test_des_des_linkstr(self): norb, nelec = 10, 4 strs = cistring.make_strings(range(norb), nelec) numpy.random.seed(11) mask = numpy.random.random(len(strs)) > .4 strs = strs[mask] dd_index0 = des_des_linkstr(strs, norb, nelec) dd_index1 = selected_ci.des_des_linkstr(strs, norb, nelec) self.assertTrue(numpy.all(dd_index0 == dd_index1)) dd_index0 = des_des_linkstr_tril(strs, norb, nelec) dd_index1 = selected_ci.des_des_linkstr_tril(strs, norb, nelec) dd_index1[:,:,1] = 0 self.assertTrue(numpy.all(dd_index0 == dd_index1))
def test_des_des_linkstr(self): norb, nelec = 10, 4 strs = cistring.make_strings(range(norb), nelec) numpy.random.seed(11) mask = numpy.random.random(len(strs)) > .4 strs = strs[mask] dd_index0 = des_des_linkstr(strs, norb, nelec) dd_index1 = selected_ci.des_des_linkstr(strs, norb, nelec) self.assertTrue(numpy.all(dd_index0 == dd_index1)) dd_index0 = des_des_linkstr_tril(strs, norb, nelec) dd_index1 = selected_ci.des_des_linkstr_tril(strs, norb, nelec) dd_index1[:, :, 1] = 0 self.assertTrue(numpy.all(dd_index0 == dd_index1))
def test_spin_square(self): norb, nelec = 10, 4 strs = cistring.make_strings(range(norb), nelec) numpy.random.seed(11) mask = numpy.random.random(len(strs)) > .6 strsa = strs[mask] mask = numpy.random.random(len(strs)) > .7 strsb = strs[mask] ci_strs = (strsa, strsb) ci_coeff = selected_ci._as_SCIvector(numpy.random.random((len(strsa),len(strsb))), ci_strs) ci0 = selected_ci.to_fci(ci_coeff, norb, (nelec,nelec)) ss0 = selected_ci.spin_square(ci_coeff, norb, (nelec,nelec)) ss1 = spin_op.spin_square0(ci0, norb, (nelec,nelec)) self.assertAlmostEqual(ss0[0], ss1[0], 9)
def test_select_strs(self): myci = selected_ci.SCI() myci.select_cutoff = 1e-3 norb, nelec = 10, 4 strs = cistring.make_strings(range(norb), nelec) numpy.random.seed(11) mask = numpy.random.random(len(strs)) > .8 strs = strs[mask] nn = norb*(norb+1)//2 eri = (numpy.random.random(nn*(nn+1)//2)-.2)**3 eri[eri<.1] *= 3e-3 eri = ao2mo.restore(1, eri, norb) eri_pq_max = abs(eri.reshape(norb**2,-1)).max(axis=1).reshape(norb,norb) civec_max = numpy.random.random(len(strs)) strs_add0 = select_strs(myci, eri, eri_pq_max, civec_max, strs, norb, nelec) strs_add1 = selected_ci.select_strs(myci, eri, eri_pq_max, civec_max, strs, norb, nelec) self.assertTrue(numpy.all(strs_add0 == strs_add1))
def transform_ci(ci, nelec, u): '''Transform CI coefficients to the representation in new one-particle basis. Solving CI problem for Hamiltonian h1, h2 defined in old basis, CI_old = fci.kernel(h1, h2, ...) Given orbital rotation u, the CI problem can be either solved by transforming the Hamiltonian, or transforming the coefficients. CI_new = fci.kernel(u^T*h1*u, ...) = transform_ci_for_orbital_rotation(CI_old, u) Args: u : 2D array or a list of 2D array the orbital rotation to transform the old one-particle basis to new one-particle basis. If u is not a squared matrix, the resultant CI coefficients array may have different shape to the input CI coefficients. ''' neleca, nelecb = _unpack_nelec(nelec) if isinstance(u, numpy.ndarray) and u.ndim == 2: ua = ub = u assert ua.shape == ub.shape else: ua, ub = u norb_old, norb_new = ua.shape na_old = cistring.num_strings(norb_old, neleca) nb_old = cistring.num_strings(norb_old, nelecb) na_new = cistring.num_strings(norb_new, neleca) nb_new = cistring.num_strings(norb_new, nelecb) ci = ci.reshape(na_old, nb_old) one_particle_strs_old = numpy.asarray([1 << i for i in range(norb_old)]) one_particle_strs_new = numpy.asarray([1 << i for i in range(norb_new)]) if neleca == 0: trans_ci_a = numpy.ones((1, 1)) else: trans_ci_a = numpy.zeros((na_old, na_new)) strs_old = numpy.asarray(cistring.make_strings(range(norb_old), neleca)) # Unitary transformation array trans_ci is the overlap between two sets of CI basis. occ_masks_old = (strs_old[:, None] & one_particle_strs_old) != 0 if norb_old == norb_new: occ_masks_new = occ_masks_old else: strs_new = numpy.asarray( cistring.make_strings(range(norb_new), neleca)) occ_masks_new = (strs_new[:, None] & one_particle_strs_new) != 0 # Perform #for i in range(na_old): # old basis # for j in range(na_new): # new basis # uij = u[occ_masks_old[i]][:,occ_masks_new[j]] # trans_ci_a[i,j] = numpy.linalg.det(uij) occ_idx_all_strs = numpy.where(occ_masks_new)[1].reshape( na_new, neleca) for i in range(na_old): ui = ua[occ_masks_old[i]].T.copy() minors = ui[occ_idx_all_strs] trans_ci_a[i, :] = numpy.linalg.det(minors) if neleca == nelecb and numpy.allclose(ua, ub): trans_ci_b = trans_ci_a elif nelecb == 0: trans_ci_b = numpy.ones((1, 1)) else: trans_ci_b = numpy.zeros((nb_old, nb_new)) strs_old = numpy.asarray(cistring.make_strings(range(norb_old), nelecb)) occ_masks_old = (strs_old[:, None] & one_particle_strs_old) != 0 if norb_old == norb_new: occ_masks_new = occ_masks_old else: strs_new = numpy.asarray( cistring.make_strings(range(norb_new), nelecb)) occ_masks_new = (strs_new[:, None] & one_particle_strs_new) != 0 occ_idx_all_strs = numpy.where(occ_masks_new)[1].reshape( nb_new, nelecb) for i in range(nb_old): ui = ub[occ_masks_old[i]].T.copy() minors = ui[occ_idx_all_strs] trans_ci_b[i, :] = numpy.linalg.det(minors) # Transform old basis to new basis for all alpha-electron excitations ci = lib.dot(trans_ci_a.T, ci) # Transform old basis to new basis for all beta-electron excitations ci = lib.dot(ci, trans_ci_b) return ci
def transform_ci_for_orbital_rotation(ci, norb, nelec, u): '''Transform CI coefficients to the representation in new one-particle basis. Solving CI problem for Hamiltonian h1, h2 defined in old basis, CI_old = fci.kernel(h1, h2, ...) Given orbital rotation u, the CI problem can be either solved by transforming the Hamiltonian, or transforming the coefficients. CI_new = fci.kernel(u^T*h1*u, ...) = transform_ci_for_orbital_rotation(CI_old, u) Args: u : 2D array or a list of 2D array the orbital rotation to transform the old one-particle basis to new one-particle basis ''' neleca, nelecb = _unpack(nelec) strsa = numpy.asarray(cistring.make_strings(range(norb), neleca)) strsb = numpy.asarray(cistring.make_strings(range(norb), nelecb)) one_particle_strs = numpy.asarray([1 << i for i in range(norb)]) na = len(strsa) nb = len(strsb) if isinstance(u, numpy.ndarray) and u.ndim == 2: ua = ub = u else: ua, ub = u if neleca == 0: trans_ci_a = numpy.ones((1, 1)) else: # Unitary transformation array trans_ci is the overlap between two sets of CI basis. occ_masks = (strsa[:, None] & one_particle_strs) != 0 trans_ci_a = numpy.zeros((na, na)) #for i in range(na): # for old basis # for j in range(na): # uij = u[occ_masks[i]][:,occ_masks[j]] # trans_ci_a[i,j] = numpy.linalg.det(uij) occ_idx_all_strs = numpy.where(occ_masks)[1].reshape(na, neleca) for i in range(na): ui = ua[occ_masks[i]].T.copy() minors = ui[occ_idx_all_strs] trans_ci_a[i, :] = numpy.linalg.det(minors) if neleca == nelecb and numpy.allclose(ua, ub): trans_ci_b = trans_ci_a else: if nelecb == 0: trans_ci_b = numpy.ones((1, 1)) else: occ_masks = (strsb[:, None] & one_particle_strs) != 0 trans_ci_b = numpy.zeros((nb, nb)) #for i in range(nb): # for j in range(nb): # uij = u[occ_masks[i]][:,occ_masks[j]] # trans_ci_b[i,j] = numpy.linalg.det(uij) occ_idx_all_strs = numpy.where(occ_masks)[1].reshape(nb, nelecb) for i in range(nb): ui = ub[occ_masks[i]].T.copy() minors = ui[occ_idx_all_strs] trans_ci_b[i, :] = numpy.linalg.det(minors) # Transform old basis to new basis for all alpha-electron excitations ci = lib.dot(trans_ci_a.T, ci.reshape(na, nb)) # Transform old basis to new basis for all beta-electron excitations ci = lib.dot(ci.reshape(na, nb), trans_ci_b) return ci
def transform_ci_for_orbital_rotation(ci, norb, nelec, u): '''Transform CI coefficients to the representation in new one-particle basis. Solving CI problem for Hamiltonian h1, h2 defined in old basis, CI_old = fci.kernel(h1, h2, ...) Given orbital rotation u, the CI problem can be either solved by transforming the Hamiltonian, or transforming the coefficients. CI_new = fci.kernel(u^T*h1*u, ...) = transform_ci_for_orbital_rotation(CI_old, u) Args: u : 2D array or a list of 2D array the orbital rotation to transform the old one-particle basis to new one-particle basis ''' neleca, nelecb = _unpack_nelec(nelec) strsa = numpy.asarray(cistring.make_strings(range(norb), neleca)) strsb = numpy.asarray(cistring.make_strings(range(norb), nelecb)) one_particle_strs = numpy.asarray([1<<i for i in range(norb)]) na = len(strsa) nb = len(strsb) assert(ci.shape == (na, nb)) if isinstance(u, numpy.ndarray) and u.ndim == 2: ua = ub = u else: ua, ub = u if neleca == 0: trans_ci_a = numpy.ones((1,1)) else: # Unitary transformation array trans_ci is the overlap between two sets of CI basis. occ_masks = (strsa[:,None] & one_particle_strs) != 0 trans_ci_a = numpy.zeros((na,na)) #for i in range(na): # for old basis # for j in range(na): # uij = u[occ_masks[i]][:,occ_masks[j]] # trans_ci_a[i,j] = numpy.linalg.det(uij) occ_idx_all_strs = numpy.where(occ_masks)[1].reshape(na,neleca) for i in range(na): ui = ua[occ_masks[i]].T.copy() minors = ui[occ_idx_all_strs] trans_ci_a[i,:] = numpy.linalg.det(minors) if neleca == nelecb and numpy.allclose(ua, ub): trans_ci_b = trans_ci_a else: if nelecb == 0: trans_ci_b = numpy.ones((1,1)) else: occ_masks = (strsb[:,None] & one_particle_strs) != 0 trans_ci_b = numpy.zeros((nb,nb)) #for i in range(nb): # for j in range(nb): # uij = u[occ_masks[i]][:,occ_masks[j]] # trans_ci_b[i,j] = numpy.linalg.det(uij) occ_idx_all_strs = numpy.where(occ_masks)[1].reshape(nb,nelecb) for i in range(nb): ui = ub[occ_masks[i]].T.copy() minors = ui[occ_idx_all_strs] trans_ci_b[i,:] = numpy.linalg.det(minors) # Transform old basis to new basis for all alpha-electron excitations ci = lib.dot(trans_ci_a.T, ci.reshape(na,nb)) # Transform old basis to new basis for all beta-electron excitations ci = lib.dot(ci.reshape(na,nb), trans_ci_b) return ci