def test_apply_type_error(self): data = numpy.zeros((2, 2), dtype=numpy.complex128) wfn = Wavefunction([[2, 0, 2]], broken=['spin']) hamil = general_hamiltonian.General((data, )) hamil._conserve_number = False self.assertRaises(TypeError, wfn.apply, hamil) self.assertRaises(TypeError, wfn.time_evolve, 0.1, hamil) wfn = Wavefunction([[2, 0, 2]], broken=['number']) hamil = general_hamiltonian.General((data, )) self.assertRaises(TypeError, wfn.apply, hamil) self.assertRaises(TypeError, wfn.time_evolve, 0.1, hamil) wfn = Wavefunction([[2, 0, 2]]) hamil = get_restricted_hamiltonian((data, )) self.assertRaises(ValueError, wfn.time_evolve, 0.1, hamil, True)
def test_apply_generated_unitary(self): """APply the generated unitary transformation from the fqe namespace """ norb = 4 nele = 3 time = 0.001 ops = FermionOperator('1^ 3^ 5 0', 2.0 - 2.j) + FermionOperator( '0^ 5^ 3 1', 2.0 + 2.j) wfn = fqe.get_number_conserving_wavefunction(nele, norb) wfn.set_wfn(strategy='random') wfn.normalize() reference = fqe.apply_generated_unitary(wfn, time, 'taylor', ops) h1e = numpy.zeros((2 * norb, 2 * norb), dtype=numpy.complex128) h2e = hamiltonian_utils.nbody_matrix(ops, norb) h2e = hamiltonian_utils.antisymm_two_body(h2e) hamil = general_hamiltonian.General(tuple([h1e, h2e])) compute = wfn.apply_generated_unitary(time, 'taylor', hamil) for key in wfn.sectors(): with self.subTest(key=key): diff = reference._civec[key].coeff - compute._civec[key].coeff err = linalg.norm(diff) self.assertTrue(err < 1.e-8)
def test_general_hamiltonian(): """Test some of the functions in General.""" h1e = np.random.rand(5, 5).astype(np.complex128) h1e += h1e.T.conj() test = general_hamiltonian.General((h1e, )) assert test.dim() == 5 assert test.rank() == 2 assert np.allclose(h1e, test.tensor(2)) assert test.quadratic() trans = test.calc_diag_transform() h1e = trans.T.conj() @ h1e @ trans assert np.allclose(h1e, test.transform(trans)) for i in range(h1e.shape[0]): h1e[i, i] = 0.0 assert np.std(h1e) < 1.0e-8 with pytest.raises(TypeError): general_hamiltonian.General("test")
def get_general_hamiltonian(tensors: Tuple[numpy.ndarray, ...], e_0: complex = 0. + 0.j ) -> 'general_hamiltonian.General': """Initialize the most general hamiltonian class. Args: tensors (Tuple[numpy.ndarray, ...]) - tensors for the Hamiltonian elements e_0 (complex) - scalar part of the Hamiltonian """ return general_hamiltonian.General(tensors, e_0=e_0)
def test_nh_energy(): """Checks total relativistic energy with NH.""" eref = -57.681266930627 norb = 6 nele, h1e, h2e = build_nh_data() elec_hamil = general_hamiltonian.General((h1e, h2e)) maxb = min(norb, nele) minb = nele - maxb ndim = int(binom(norb * 2, nele)) hci = np.zeros((ndim, ndim), dtype=np.complex128) for i in range(0, ndim): wfn = fqe.get_number_conserving_wavefunction(nele, norb) cnt = 0 for nbeta in range(minb, maxb + 1): coeff = wfn.get_coeff((nele, nele - 2 * nbeta)) size = coeff.size if cnt <= i < cnt + size: coeff.flat[i - cnt] = 1.0 cnt += size result = wfn.apply(elec_hamil) cnt = 0 for nbeta in range(minb, maxb + 1): coeff = result.get_coeff((nele, nele - 2 * nbeta)) for j in range(coeff.size): hci[cnt + j, i] = coeff.flat[j] cnt += coeff.size assert np.std(hci - hci.T.conj()) < 1.0e-8 eigenvals, eigenvecs = np.linalg.eigh(hci) assert np.isclose(eref, eigenvals[0], atol=1e-8) orig = eigenvecs[:, 0] wfn = fqe.get_number_conserving_wavefunction(nele, norb) cnt = 0 for nbeta in range(minb, maxb + 1): nalpha = nele - nbeta vdata = np.zeros( (int(binom(norb, nalpha)), int(binom(norb, nbeta))), dtype=np.complex128, ) for i in range(vdata.size): vdata.flat[i] = orig[cnt + i] wfn._civec[(nele, nalpha - nbeta)].coeff += vdata cnt += vdata.size hwfn = wfn.apply(elec_hamil) ecalc = fqe.vdot(wfn, hwfn).real assert np.isclose(eref, ecalc, atol=1e-8)
def test_lih_energy(self): """Checking total energy with LiH """ eref = -8.877719570384043 norb = 6 nalpha = 2 nbeta = 2 nele = nalpha + nbeta h1e, h2e, lih_ground = build_lih_data.build_lih_data('energy') elec_hamil = general_hamiltonian.General((h1e, h2e)) wfn = Wavefunction([[nele, nalpha - nbeta, norb]]) wfn.set_wfn(strategy='from_data', raw_data={(nele, nalpha - nbeta): lih_ground}) ecalc = wfn.expectationValue(elec_hamil) self.assertAlmostEqual(eref, ecalc, places=8)
def build_hamiltonian(ops: Union[FermionOperator, hamiltonian.Hamiltonian], norb: int = 0, conserve_number: bool = True, e_0: complex = 0. + 0.j) -> 'hamiltonian.Hamiltonian': """Build a Hamiltonian object for the fqe Args: ops (FermionOperator, hamiltonian.Hamiltonian) - input operator as \ FermionOperator. If a Hamiltonian is passed as an argument, \ this function returns as is. norb (int) - the number of orbitals in the system conserve_number (bool) - whether the operator conserves the number e_0 (complex) - the scalar part of the operator Returns: (hamiltonian.Hamiltonian) - General Hamiltonian that is created from ops """ if isinstance(ops, hamiltonian.Hamiltonian): return ops if isinstance(ops, tuple): validate_tuple(ops) return general_hamiltonian.General(ops, e_0=e_0) if not isinstance(ops, FermionOperator): raise TypeError('Expected FermionOperator' \ ' but received {}.'.format(type(ops))) assert is_hermitian(ops) out: Any if len(ops.terms) <= 2: out = sparse_hamiltonian.SparseHamiltonian(ops, e_0=e_0) else: if not conserve_number: ops = transform_to_spin_broken(ops) ops = normal_ordered(ops) ops_rank, e_0 = split_openfermion_tensor(ops) # type: ignore if norb == 0: for term in ops_rank.values(): ablk, bblk = largest_operator_index(term) norb = max(norb, ablk // 2 + 1, bblk // 2 + 1) else: norb = norb ops_mat = {} maxrank = 0 for rank, term in ops_rank.items(): index = rank // 2 - 1 ops_mat[index] = fermionops_tomatrix(term, norb) maxrank = max(index, maxrank) if len(ops_mat) == 1 and (0 in ops_mat): out = process_rank2_matrix(ops_mat[0], norb=norb, e_0=e_0) elif len(ops_mat) == 1 and \ (1 in ops_mat) and \ check_diagonal_coulomb(ops_mat[1]): out = diagonal_coulomb.DiagonalCoulomb(ops_mat[1], e_0=e_0) else: dtypes = [xx.dtype for xx in ops_mat.values()] dtypes = numpy.unique(dtypes) if len(dtypes) != 1: raise TypeError( "Non-unique coefficient types for input operator") for i in range(maxrank + 1): if i not in ops_mat: mat_dim = tuple([2 * norb for _ in range((i + 1) * 2)]) ops_mat[i] = numpy.zeros(mat_dim, dtype=dtypes[0]) ops_mat2 = [] for i in range(maxrank + 1): ops_mat2.append(ops_mat[i]) out = general_hamiltonian.General(tuple(ops_mat2), e_0=e_0) out._conserve_number = conserve_number return out