def test_lasuccsd_total_energy (self): mc = mcscf.CASCI (mf, 4, 4) mc.mo_coeff = las.mo_coeff mc.fcisolver = lasuccsd.FCISolver (mol) mc.fcisolver.norb_f = [2,2] mc.kernel () with self.subTest (from_='reported'): self.assertAlmostEqual (mc.e_tot, ref.e_tot, 6) psi = mc.fcisolver.psi x = psi.x h1, h0 = mc.get_h1eff () h2 = mc.get_h2eff () h = [h0, h1, h2] energy, gradient = psi.e_de (x, h) with self.subTest (from_='obj fn'): self.assertAlmostEqual (energy, mc.e_tot, 9) c = np.squeeze (fockspace.fock2hilbert (psi.get_fcivec (x), 4, (2,2))) h2eff = direct_spin1.absorb_h1e (h1, h2, 4, (2,2), 0.5) hc = direct_spin1.contract_2e (h2eff, c, 4, (2,2)) chc = c.conj ().ravel ().dot (hc.ravel ()) + h0 with self.subTest (from_='h2 contraction'): self.assertAlmostEqual (chc, mc.e_tot, 9) c_f = psi.ci_f for ifrag, c in enumerate (c_f): heff = psi.get_dense_heff (x, h, ifrag) hc = np.dot (heff.full, c.ravel ()) chc = np.dot (c.conj ().ravel (), hc) with self.subTest (from_='frag {} Fock-space dense effective Hamiltonian'.format (ifrag)): self.assertAlmostEqual (chc, mc.e_tot, 9) heff, _ = heff.get_number_block ((1,1),(1,1)) c = np.squeeze (fockspace.fock2hilbert (c, 2, (1,1))).ravel () hc = np.dot (heff, c) chc = np.dot (c.conj (), hc) with self.subTest (from_='frag {} Hilbert-space dense effective Hamiltonian'.format (ifrag)): self.assertAlmostEqual (chc, mc.e_tot, 9)
def make_rdm1 (fci, fcivec, norb, nelec, **kwargs): dm1 = np.zeros ((norb, norb)) for nelec in product (range (norb+1), repeat=2): ci = fockspace.fock2hilbert (fcivec, norb, nelec) d = direct_spin1.make_rdm1 (ci, norb, nelec, **kwargs) dm1 += d return dm1
def transform_ci_for_orbital_rotation (fci, ci, norb, nelec, umat): fcivec = np.zeros_like (ci) for ne in product (range (norb+1), repeat=2): c = np.squeeze (fockspace.fock2hilbert (ci, norb, ne)) c = fci_addons.transform_ci_for_orbital_rotation (c, norb, ne, umat) fcivec += np.squeeze (fockspace.hilbert2fock (c, norb, ne)) return fcivec
def make_rdm1s (fci, fcivec, norb, nelec, **kwargs): dm1a = np.zeros ((norb,norb)) dm1b = np.zeros ((norb,norb)) for nelec in product (range (norb+1), repeat=2): ci = fockspace.fock2hilbert (fcivec, norb, nelec) da, db = direct_spin1.make_rdm1s (ci, norb, nelec, **kwargs) dm1a += da dm1b += db return dm1a, dm1b
def spin_square (fci, fcivec, norb, nelec): ss = 0.0 for ne in product (range (norb+1), repeat=2): c = fockspace.fock2hilbert (fcivec, norb, ne) ssc = spin_op.contract_ss (c, norb, ne) ss += c.conj ().ravel ().dot (ssc.ravel ()) s = np.sqrt(ss+.25) - .5 multip = s*2+1 return ss, multip
def contract_h2 (self, h, ci, norb=None): if norb is None: norb = self.norb hci = h[0] * ci for neleca, nelecb in product (range (norb+1), repeat=2): nelec = (neleca, nelecb) h2eff = self.fcisolver.absorb_h1e (h[1], h[2], norb, nelec, 0.5) ci_h = np.squeeze (fockspace.fock2hilbert (ci, norb, nelec)) hc = direct_spin1.contract_2e (h2eff, ci_h, norb, nelec) hci += np.squeeze (fockspace.hilbert2fock (hc, norb, nelec)) return hci
def check_ci0_constr (self): norb, nelec = self.norb, self.nelec ci0 = self.dp_ci (self.ci_f) neleca_min = max (0, nelec-norb) neleca_max = min (norb, nelec) w = 0.0 for neleca in range (neleca_min, neleca_max+1): nelecb = nelec - neleca c = fockspace.fock2hilbert (ci0, norb, (neleca,nelecb)).ravel () w += c.conj ().dot (c) return w>1e-8
def test_s2(self): for norb, c, uop in zip(range(2, 5), c_list, uop_s_list): ssc_ref = np.zeros_like(c) for nelec in product(range(norb + 1), repeat=2): c_h = np.squeeze(fockspace.fock2hilbert(c, norb, nelec)) ssc_h = direct_spin1.contract_ss(c_h, norb, nelec) ssc_ref += fockspace.hilbert2fock(ssc_h, norb, nelec).ravel() ssc = contract_s2(c, norb) with self.subTest(norb=norb, checking='s2 op'): self.assertAlmostEqual(lib.fp(ssc), lib.fp(ssc_ref), 6) uc = uop(c) ussc = uop(ssc) ssuc = contract_s2(uc, norb) commutator = ussc - ssuc with self.subTest(norb=norb, checking='singles operator symmetry'): self.assertLessEqual(linalg.norm(commutator), 1e-8)
def test_ham(self): for norb in range(2, 5): npair = norb * (norb + 1) // 2 c = np.random.rand(2**(2 * norb)) c /= linalg.norm(c) h0 = np.random.rand(1)[0] h1 = np.random.rand(norb, norb) h2 = np.random.rand(npair, npair) h1 += h1.T h2 += h2.T hc_ref = np.zeros_like(c) for nelec in product(range(norb + 1), repeat=2): c_h = np.squeeze(fockspace.fock2hilbert(c, norb, nelec)) h2eff = direct_spin1.absorb_h1e(h1, h2, norb, nelec, 0.5) hc_h = h0 * c_h + direct_spin1.contract_2e( h2eff, c_h, norb, nelec) hc_ref += fockspace.hilbert2fock(hc_h, norb, nelec).ravel() h1 = h1[np.tril_indices(norb)] hc_test = _op1h_spinsym(norb, [h0, h1, h2], c) with self.subTest(norb=norb): self.assertAlmostEqual(lib.fp(hc_test), lib.fp(hc_ref), 6)
def pbin (n, k=norb): s = bin (n)[2:] m = (2*k) - len (s) if m: s = ''.join (['0',]*m) + s return s psi = np.zeros (2**(2*norb)) psi[51] = 1.0 from pyscf.fci import cistring, spin_op from mrh.exploratory.citools import fockspace t1_rand = np.random.rand (norb,norb) t2_rand = np.random.rand (norb,norb,norb,norb) uop_s = get_uccs_op (norb, t1=t1_rand) upsi = uop_s (psi) upsi_h = fockspace.fock2hilbert (upsi, norb, nelec) uTupsi = uop_s (upsi, transpose=True) for ix in range (2**(2*norb)): if np.any (np.abs ([psi[ix], upsi[ix], uTupsi[ix]]) > 1e-8): print (pbin (ix), psi[ix], upsi[ix], uTupsi[ix]) print ("<psi|psi> =",psi.dot (psi), "<psi|U|psi> =",psi.dot (upsi),"<psi|U'U|psi> =",upsi.dot (upsi)) print ("<psi|S**2|psi> =",spin_square (psi, norb)[0], "<psi|U'S**2U|psi> =",spin_square (upsi, norb)[0],spin_op.spin_square (upsi_h, norb, nelec)[0]) uop_sd = get_uccsd_op (norb) x_rand = (1 - 2*np.random.rand (uop_sd.ngen_uniq)) * math.pi/4 uop_sd.set_uniq_amps_(x_rand) upsi = uop_sd (psi) upsi_h = fockspace.fock2hilbert (upsi, norb, nelec) uTupsi = uop_sd (upsi, transpose=True) for ix in range (2**(2*norb)):
fcivec = psi.get_fcivec() # |LASUCC> itself as a CI vector ss, multip = mc.fcisolver.spin_square(fcivec, 4, 'ThisArgDoesntMatter') print("<LASUCC|S^2|LASUCC> = {:.3f}; apparent S = {:.1f}".format( ss, 0.5 * (multip - 1))) print("But is that really the case?") print("Singlet weight: {:.2f}".format( fockspace.hilbert_sector_weight(fcivec, 4, (2, 2), 1))) print("Triplet weight: {:.2f}".format( fockspace.hilbert_sector_weight(fcivec, 4, (2, 2), 3))) print("Quintet weight: {:.2f}".format( fockspace.hilbert_sector_weight(fcivec, 4, (2, 2), 5))) print("Oh well, I guess it couldn't have been anything else.\n") ci_f = psi.ci_f # list of optimized CI vectors for each fragment ci_h = [fockspace.fock2hilbert(c, 2, (1, 1)) for c in ci_f] w_nb = [ linalg.norm(c_f)**2 - linalg.norm(c_h)**2 for (c_f, c_h) in zip(ci_f, ci_h) ] print(("Wave function weight outside of the singlet 2-electron " "Hilbert space")) print(("(If these numbers are nonzero, then my implementation " "of UCC doesn't pointlessly waste memory)")) for ix in range(2): print("Fragment {}: {:.1e}".format(ix, w_nb[ix])) # U'HU for a single fragment can be retrieved as a # LASUCCEffectiveHamiltonian object, which is just the ndarray (in # the member "full") and some convenience functions heff = psi.get_dense_heff(x, h, 0)