예제 #1
0
    def test_apply_individual_nbody_error(self):
        fop = FermionOperator('1^ 0')
        fop += FermionOperator('2^ 0')
        fop += FermionOperator('2^ 1')
        hamil = sparse_hamiltonian.SparseHamiltonian(fop)
        wfn = Wavefunction([[2, 0, 2]], broken=['spin'])
        self.assertRaises(ValueError, wfn._apply_individual_nbody, hamil)
        self.assertRaises(ValueError, wfn._evolve_individual_nbody, 0.1, hamil)

        fop = FermionOperator('1^ 0')
        fop += FermionOperator('2^ 0')
        hamil = sparse_hamiltonian.SparseHamiltonian(fop)
        self.assertRaises(ValueError, wfn._evolve_individual_nbody, 0.1, hamil)

        fop = FermionOperator('1^ 0', 1.0)
        fop += FermionOperator('0^ 1', 0.9)
        hamil = sparse_hamiltonian.SparseHamiltonian(fop)
        self.assertRaises(ValueError, wfn._evolve_individual_nbody, 0.1, hamil)

        fop = FermionOperator('1^ 0^')
        hamil = sparse_hamiltonian.SparseHamiltonian(fop)
        self.assertRaises(ValueError, wfn._apply_individual_nbody, hamil)
        self.assertRaises(ValueError, wfn._evolve_individual_nbody, 0.1, hamil)

        self.assertRaises(TypeError, wfn._evolve_individual_nbody, 0.1, 1)
def test_sparse():
    """Test some of the functions in SparseHamiltonian."""
    oper = FermionOperator('0 0^')
    oper += FermionOperator('1 1^')
    test = sparse_hamiltonian.SparseHamiltonian(oper)
    assert test.rank() == 2
    test = sparse_hamiltonian.SparseHamiltonian(oper, False)
    assert not test.is_individual()
예제 #3
0
    def test_apply_nbody(self):
        wfn = Wavefunction([[2, 0, 2]])
        wfn.set_wfn(strategy='random')

        fac = 3.14
        fop = FermionOperator('1^ 1', fac)
        hamil = sparse_hamiltonian.SparseHamiltonian(fop)
        out1 = wfn._apply_few_nbody(hamil)

        fop = FermionOperator('1 1^', fac)
        hamil = sparse_hamiltonian.SparseHamiltonian(fop)
        out2 = wfn._apply_few_nbody(hamil)
        out2.scale(-1.0)
        out2.ax_plus_y(fac, wfn)
        self.assertTrue((out1 - out2).norm() < 1.0e-8)
예제 #4
0
    def rdm(
        self,
        string: str,
        brawfn: Optional['Wavefunction'] = None
    ) -> Union[complex, numpy.ndarray]:
        """ Returns rank-1 RDM. The operator order is specified by string.
        Note that, if the entire RDM is requested for N-broken wave function,
        this returns a packed format.

        Args:
            string (str) - character strings that specify the quantity to be computed

            brawfn (Wavefunction) - bra-side wave function for transition RDM (optional)

        Returns:
            Resulting RDM in numpy.ndarray or element in complex
        """
        rank = len(string.split()) // 2
        if any(char.isdigit() for char in string):
            result = self.apply(sparse_hamiltonian.SparseHamiltonian(string))
            if brawfn is None:
                return vdot(self, result)
            return vdot(brawfn, result)

        fqe_ops_utils.validate_rdm_string(string)
        rdm = list(self._compute_rdm(rank, brawfn))
        return wick(string, rdm, self._conserve_spin)
예제 #5
0
    def expectationValue(
            self,
            ops: Union['fqe_operator.FqeOperator', 'hamiltonian.Hamiltonian'],
            brawfn: 'Wavefunction' = None) -> Union[complex, numpy.ndarray]:
        """Calculates expectation values given operators

        Args:
            ops (FqeOperator or Hamiltonian) - operator for which the expectation value is \
                computed

            brawfn (Wavefunction) - bra-side wave function for transition quantity (optional)

        Returns:
            (complex or numpy.ndarray) - resulting expectation value or RDM
        """
        if isinstance(ops, fqe_operator.FqeOperator):
            if brawfn:
                return ops.contract(brawfn, self)
            return ops.contract(self, self)

        if isinstance(ops, str):
            if any(char.isdigit() for char in ops):
                ops = sparse_hamiltonian.SparseHamiltonian(ops)
            else:
                return self.rdm(ops, brawfn=brawfn)

        if not isinstance(ops, hamiltonian.Hamiltonian):
            raise TypeError('Expected an Fqe Hamiltonian or Operator' \
                            ' but recieved {}'.format(type(ops)))
        workwfn = self.apply(ops)

        if brawfn:
            return vdot(brawfn, workwfn)
        return vdot(self, workwfn)
예제 #6
0
def get_sparse_hamiltonian(operators: Union['FermionOperator', str],
                           conserve_spin: bool = True,
                           e_0: complex = 0. + 0.j
                          ) -> 'sparse_hamiltonian.SparseHamiltonian':
    """Initialize the sparse hamiltonaian

    Args:
        operators (Union[FermionOperator, str]) - the FermionOperator to be used to \
            initialize the sparse Hamiltonian

        conserve_spin (bool) - whether the Hamiltonian conserves Sz

        e_0 (complex) - scalar part of the Hamiltonian
    """
    return sparse_hamiltonian.SparseHamiltonian(operators,
                                                conserve_spin=conserve_spin,
                                                e_0=e_0)
예제 #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