Пример #1
0
    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)
Пример #2
0
    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")
Пример #4
0
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)
Пример #6
0
    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)
Пример #7
0
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