Esempio n. 1
0
def test_fci_energy():
    filename = os.path.join(DATA_DIRECTORY, "H2_sto-3g_singlet_0.7414.hdf5")
    molecule = MolecularData(filename=filename)
    reduced_ham = make_reduced_hamiltonian(
        molecule.get_molecular_hamiltonian(), molecule.n_electrons)
    np_ham = of.get_number_preserving_sparse_operator(
        of.get_fermion_operator(reduced_ham),
        molecule.n_qubits,
        num_electrons=molecule.n_electrons,
        spin_preserving=True)

    w, _ = np.linalg.eigh(np_ham.toarray())
    assert np.isclose(molecule.fci_energy, w[0])

    filename = os.path.join(DATA_DIRECTORY, "H1-Li1_sto-3g_singlet_1.45.hdf5")
    molecule = MolecularData(filename=filename)
    reduced_ham = make_reduced_hamiltonian(
        molecule.get_molecular_hamiltonian(), molecule.n_electrons)
    np_ham = of.get_number_preserving_sparse_operator(
        of.get_fermion_operator(reduced_ham),
        molecule.n_qubits,
        num_electrons=molecule.n_electrons,
        spin_preserving=True)

    w, _ = np.linalg.eigh(np_ham.toarray())
    assert np.isclose(molecule.fci_energy, w[0])
Esempio n. 2
0
    def __init__(self,
                 name,
                 geometry,
                 multiplicity,
                 charge,
                 n_orbitals,
                 n_electrons,
                 basis='sto-3g',
                 frozen_els=None):
        self.name = name
        self.multiplicity = multiplicity
        self.charge = charge
        self.basis = basis
        self.geometry = geometry

        self.molecule_data = MolecularData(geometry=self.geometry,
                                           basis=basis,
                                           multiplicity=self.multiplicity,
                                           charge=self.charge)

        self.molecule_psi4 = run_psi4(
            self.molecule_data, run_fci=True)  # old version of openfermion

        # Hamiltonian transforms
        self.molecule_ham = self.molecule_psi4.get_molecular_hamiltonian()
        self.hf_energy = self.molecule_psi4.hf_energy.item(
        )  # old version of openfermion
        self.fci_energy = self.molecule_psi4.fci_energy.item(
        )  # old version of openfermion

        # TODO: the code below corresponds to the most recent version in the opefermion documentation.
        #  However it has problems with ray???
        # calculate_molecule_psi4 = run_pyscf(self.molecule_data, run_scf=True, run_cisd=True, run_fci=True)
        # self.molecule_ham = calculate_molecule_psi4.get_molecular_hamiltonian()
        # self.hf_energy = calculate_molecule_psi4.hf_energy
        # self.fci_energy = float(calculate_molecule_psi4.fci_energy)
        # del calculate_molecule_psi4

        self.energy_eigenvalues = None  # use this only if calculating excited states

        if frozen_els is None:
            self.n_electrons = n_electrons
            self.n_orbitals = n_orbitals
            self.n_qubits = n_orbitals
            self.fermion_ham = get_fermion_operator(self.molecule_ham)
        else:
            self.n_electrons = n_electrons - len(frozen_els['occupied'])
            self.n_orbitals = n_orbitals - len(frozen_els['occupied']) - len(
                frozen_els['unoccupied'])
            self.n_qubits = self.n_orbitals
            self.fermion_ham = freeze_orbitals(
                get_fermion_operator(self.molecule_ham),
                occupied=frozen_els['occupied'],
                unoccupied=frozen_els['unoccupied'],
                prune=True)
        self.jw_qubit_ham = jordan_wigner(self.fermion_ham)

        # this is used only for calculating excited states. list of [term_index, term_state]
        self.H_lower_state_terms = None
Esempio n. 3
0
    def test_fermionic_hamiltonian_from_integrals(self):
        constant = self.molecule.nuclear_repulsion
        doci_constant = constant
        hc, hr1, hr2 = get_doci_from_integrals(
            self.molecule.one_body_integrals, self.molecule.two_body_integrals)

        doci = DOCIHamiltonian(doci_constant, hc, hr1, hr2)

        doci_qubit_op = doci.qubit_operator
        doci_mat = get_sparse_operator(doci_qubit_op).toarray()
        #doci_eigvals, doci_eigvecs = numpy.linalg.eigh(doci_mat)
        doci_eigvals, _ = numpy.linalg.eigh(doci_mat)

        tensors = doci.n_body_tensors
        one_body_tensors, two_body_tensors = tensors[(1, 0)], tensors[(1, 1, 0,
                                                                       0)]
        fermion_op1 = get_fermion_operator(
            InteractionOperator(constant, one_body_tensors,
                                0. * two_body_tensors))

        fermion_op2 = get_fermion_operator(
            InteractionOperator(0, 0 * one_body_tensors,
                                0.5 * two_body_tensors))

        import openfermion as of
        fermion_op1_jw = of.transforms.jordan_wigner(fermion_op1)
        fermion_op2_jw = of.transforms.jordan_wigner(fermion_op2)

        fermion_op_jw = fermion_op1_jw + fermion_op2_jw
        #fermion_eigvals, fermion_eigvecs = numpy.linalg.eigh(
        #    get_sparse_operator(fermion_op_jw).toarray())
        fermion_eigvals, _ = numpy.linalg.eigh(
            get_sparse_operator(fermion_op_jw).toarray())

        for eigval in doci_eigvals:
            assert any(abs(fermion_eigvals -
                           eigval) < 1e-6), "The DOCI spectrum should \
            have been contained in the spectrum of the fermionic operators"

        fermion_diagonal = get_sparse_operator(
            fermion_op_jw).toarray().diagonal()
        qubit_diagonal = doci_mat.diagonal()
        assert numpy.isclose(
            fermion_diagonal[0], qubit_diagonal[0]
        ) and numpy.isclose(
            fermion_diagonal[-1], qubit_diagonal[-1]
        ), "The first and last elements of hte qubit and fermionic diagonal of \
        the Hamiltonian maxtrix should be the same as the vaccum should be \
        mapped to the computational all zero state and the completely filled \
        state should be mapped to the all one state"

        print(fermion_diagonal)
        print(qubit_diagonal)
Esempio n. 4
0
def transform_interaction_operator(transformation: str,
                                   input_operator: Union[str,
                                                         SymbolicOperator]):
    """Transform an interaction operator through either the Bravyi-Kitaev or Jordan-Wigner transformations.
    The results are serialized into a JSON under the files: "transformed-operator.json" and "timing.json"

    ARGS:
        transformation (str): The transformation to use. Either "Jordan-Wigner" or "Bravyi-Kitaev"
        input_operator (Union[str, SymbolicOperator]): The interaction operator to transform
    """
    if isinstance(input_operator, str):
        input_operator = load_interaction_operator(input_operator)

    if transformation == "Jordan-Wigner":
        transformation = jordan_wigner
    elif transformation == "Bravyi-Kitaev":
        input_operator = get_fermion_operator(input_operator)
        transformation = bravyi_kitaev
    else:
        raise RuntimeError("Unrecognized transformation ", transformation)

    start_time = time.time()
    transformed_operator = transformation(input_operator)
    walltime = time.time() - start_time

    save_qubit_operator(transformed_operator, "transformed-operator.json")
    save_timing(walltime, "timing.json")
Esempio n. 5
0
def test_erpa_eom_ham_h2():
    filename = os.path.join(DATA_DIRECTORY, "H2_sto-3g_singlet_0.7414.hdf5")
    molecule = MolecularData(filename=filename)
    reduced_ham = make_reduced_hamiltonian(
        molecule.get_molecular_hamiltonian(), molecule.n_electrons)
    rha_fermion = of.get_fermion_operator(reduced_ham)
    permuted_hijkl = np.einsum('ijlk', reduced_ham.two_body_tensor)
    opdm = np.diag([1] * molecule.n_electrons + [0] *
                   (molecule.n_qubits - molecule.n_electrons))
    tpdm = 2 * of.wedge(opdm, opdm, (1, 1), (1, 1))
    rdms = of.InteractionRDM(opdm, tpdm)
    dim = reduced_ham.one_body_tensor.shape[0] // 2
    full_basis = {}  # erpa basis.  A, B basis in RPA language
    cnt = 0
    for p, q in product(range(dim), repeat=2):
        if p < q:
            full_basis[(p, q)] = cnt
            full_basis[(q, p)] = cnt + dim * (dim - 1) // 2
            cnt += 1
    for rkey in full_basis.keys():
        p, q = rkey
        for ckey in full_basis.keys():
            r, s = ckey
            for sigma, tau in product([0, 1], repeat=2):
                test = erpa_eom_hamiltonian(permuted_hijkl, tpdm,
                                            2 * q + sigma, 2 * p + sigma,
                                            2 * r + tau, 2 * s + tau).real
                qp_op = of.FermionOperator(
                    ((2 * q + sigma, 1), (2 * p + sigma, 0)))
                rs_op = of.FermionOperator(
                    ((2 * r + tau, 1), (2 * s + tau, 0)))
                erpa_op = of.normal_ordered(
                    of.commutator(qp_op, of.commutator(rha_fermion, rs_op)))
                true = rdms.expectation(of.get_interaction_operator(erpa_op))
                assert np.isclose(true, test)
Esempio n. 6
0
def apply_fermionic_constraints(interaction_operator: InteractionOperator,
                                number_of_particles: int) -> None:
    fermion_operator = get_fermion_operator(
        load_interaction_operator(interaction_operator))
    result = apply_constraints(fermion_operator, number_of_particles)
    save_interaction_operator(get_interaction_operator(result),
                              "output_operator.json")
Esempio n. 7
0
 def test_get_diagonal_component_polynomial_tensor(self):
     fermion_op = FermionOperator("0^ 1^ 2^ 0 1 2", 1.0)
     fermion_op += FermionOperator("0^ 1^ 2^ 0 1 3", 2.0)
     fermion_op += FermionOperator((), 3.0)
     polynomial_tensor = get_polynomial_tensor(fermion_op)
     diagonal_op, remainder_op = get_diagonal_component(polynomial_tensor)
     self.assertTrue((diagonal_op + remainder_op) == polynomial_tensor)
     diagonal_qubit_op = jordan_wigner(get_fermion_operator(diagonal_op))
     remainder_qubit_op = jordan_wigner(get_fermion_operator(remainder_op))
     for term in diagonal_qubit_op.terms:
         for pauli in term:
             self.assertTrue(pauli[1] == "Z")
     for term in remainder_qubit_op.terms:
         is_diagonal = True
         for pauli in term:
             if pauli[1] != "Z":
                 is_diagonal = False
                 break
         self.assertFalse(is_diagonal)
Esempio n. 8
0
def test_spin_symmetric_bogoliubov_transform(
        n_spatial_orbitals,
        conserves_particle_number,
        atol=5e-5):
    n_qubits = 2*n_spatial_orbitals
    qubits = LineQubit.range(n_qubits)

    # Initialize a random quadratic Hamiltonian
    quad_ham = random_quadratic_hamiltonian(
            n_spatial_orbitals,
            conserves_particle_number,
            real=True,
            expand_spin=True,
            seed=28166)

    # Reorder the Hamiltonian and get sparse matrix
    quad_ham = openfermion.get_quadratic_hamiltonian(
            openfermion.reorder(
                openfermion.get_fermion_operator(quad_ham),
                openfermion.up_then_down)
    )
    quad_ham_sparse = get_sparse_operator(quad_ham)

    # Compute the orbital energies and transformation_matrix
    up_orbital_energies, _, _ = (
            quad_ham.diagonalizing_bogoliubov_transform(spin_sector=0))
    down_orbital_energies, _, _ = (
            quad_ham.diagonalizing_bogoliubov_transform(spin_sector=1))
    _, transformation_matrix, _ = (
            quad_ham.diagonalizing_bogoliubov_transform())

    # Pick some orbitals to occupy
    up_orbitals = list(range(2))
    down_orbitals = [0, 2, 3]
    energy = sum(up_orbital_energies[up_orbitals]) + sum(
            down_orbital_energies[down_orbitals]) + quad_ham.constant

    # Construct initial state
    initial_state = (
            sum(2**(n_qubits - 1 - int(i)) for i in up_orbitals)
            + sum(2**(n_qubits - 1 - int(i+n_spatial_orbitals))
                  for i in down_orbitals)
    )

    # Apply the circuit
    circuit = cirq.Circuit.from_ops(
            bogoliubov_transform(
                qubits, transformation_matrix, initial_state=initial_state))
    state = circuit.apply_unitary_effect_to_state(initial_state)

    # Check that the result is an eigenstate with the correct eigenvalue
    numpy.testing.assert_allclose(
            quad_ham_sparse.dot(state), energy * state, atol=atol)
Esempio n. 9
0
    def __init__(self,
                 oei: np.ndarray,
                 tei: np.ndarray,
                 operator_pool,
                 n_alpha: int,
                 n_beta: int,
                 iter_max=30,
                 verbose=True,
                 stopping_epsilon=1.0E-3,
                 delta_e_eps=1.0E-6):
        """
        ADAPT-VQE object.

        Args:
            oei: one electron integrals in the spatial basis
            tei: two-electron integrals in the spatial basis
            operator_pool: Object with .op_pool that is a list of antihermitian
                           FermionOperators
            n_alpha: Number of alpha-electrons
            n_beta: Number of beta-electrons
            iter_max: Maximum ADAPT-VQE steps to take
            verbose: Print the iteration information
            stopping_epsilon: define the <[G, H]> value that triggers stopping

        """
        elec_hamil = RestrictedHamiltonian((oei, np.einsum("ijlk",
                                                           -0.5 * tei)))
        soei, stei = spinorb_from_spatial(oei, tei)
        astei = np.einsum('ijkl', stei) - np.einsum('ijlk', stei)
        molecular_hamiltonian = InteractionOperator(0, soei, 0.25 * astei)

        reduced_ham = make_reduced_hamiltonian(molecular_hamiltonian,
                                               n_alpha + n_beta)
        self.reduced_ham = reduced_ham
        self.k2_ham = of.get_fermion_operator(reduced_ham)
        self.k2_fop = build_hamiltonian(self.k2_ham,
                                        elec_hamil.dim(),
                                        conserve_number=True)
        self.elec_hamil = elec_hamil
        self.iter_max = iter_max
        self.sdim = elec_hamil.dim()
        # change to use multiplicity to derive this for open shell
        self.nalpha = n_alpha
        self.nbeta = n_beta
        self.sz = self.nalpha - self.nbeta
        self.nele = self.nalpha + self.nbeta
        self.verbose = verbose
        self.operator_pool = operator_pool
        self.stopping_eps = stopping_epsilon
        self.delta_e_eps = delta_e_eps
Esempio n. 10
0
def test_prepare_gaussian_state_with_spin_symmetry(n_spatial_orbitals,
                                                   conserves_particle_number,
                                                   occupied_orbitals,
                                                   initial_state,
                                                   atol=1e-5):

    n_qubits = 2 * n_spatial_orbitals
    qubits = LineQubit.range(n_qubits)

    # Initialize a random quadratic Hamiltonian
    quad_ham = random_quadratic_hamiltonian(
            n_spatial_orbitals,
            conserves_particle_number,
            real=True,
            expand_spin=True,
            seed=639)

    # Reorder the Hamiltonian and get sparse matrix
    quad_ham = openfermion.get_quadratic_hamiltonian(
            openfermion.reorder(
                openfermion.get_fermion_operator(quad_ham),
                openfermion.up_then_down)
    )
    quad_ham_sparse = get_sparse_operator(quad_ham)

    # Compute the energy of the desired state
    energy = 0.0
    for spin_sector in range(2):
        orbital_energies, _, _ = (
            quad_ham.diagonalizing_bogoliubov_transform(
                spin_sector=spin_sector)
        )
        energy += sum(orbital_energies[i]
                      for i in occupied_orbitals[spin_sector])
    energy += quad_ham.constant

    # Get the state using a circuit simulation
    circuit = cirq.Circuit.from_ops(
            prepare_gaussian_state(
                qubits, quad_ham, occupied_orbitals,
                initial_state=initial_state))

    if isinstance(initial_state, list):
        initial_state = sum(1 << (n_qubits - 1 - i) for i in initial_state)
    state = circuit.apply_unitary_effect_to_state(initial_state)

    # Check that the result is an eigenstate with the correct eigenvalue
    numpy.testing.assert_allclose(
            quad_ham_sparse.dot(state), energy * state, atol=atol)
Esempio n. 11
0
def get_molecular_Hamiltonian(geometry=[('H', (0.0, 0.0, 0.0)),
                                        ('H', (0.0, 0.0, 0.7414))],
                              basis='sto-3g',
                              multiplicity=1,
                              charge=0):
    # Perform electronic structure calculations and obtain Hamiltonian as an InteractionOperator
    hamiltonian = ofpyscf.generate_molecular_hamiltonian(
        geometry, basis, multiplicity, charge)

    # Convert to a FermionOperator
    hamiltonian_ferm_op = of.get_fermion_operator(hamiltonian)

    mol_qubit_hamiltonianBK = bravyi_kitaev(
        hamiltonian_ferm_op
    )  # JW is exponential in the maximum locality of the original FermionOperator.
    mol_matrix = get_sparse_operator(mol_qubit_hamiltonianBK).todense()
    return mol_matrix
Esempio n. 12
0
def transform_interaction_operator(transformation, input_operator):
    input_operator = load_interaction_operator(input_operator)

    if transformation == "Jordan-Wigner":
        transformation = jordan_wigner
    elif transformation == "Bravyi-Kitaev":
        input_operator = get_fermion_operator(input_operator)
        transformation = bravyi_kitaev
    else:
        raise RuntimeError("Unrecognized transformation ", transformation)

    start_time = time.time()
    transformed_operator = transformation(input_operator)
    walltime = time.time() - start_time

    save_qubit_operator(transformed_operator, "transformed-operator.json")
    save_timing(walltime, "timing.json")
Esempio n. 13
0
def diagonal_coulomb_potential_and_kinetic_terms_as_arrays(hamiltonian):
    """Give the potential and kinetic terms of a diagonal Coulomb Hamiltonian
    as arrays.

    Args:
        hamiltonian (FermionOperator): The diagonal Coulomb Hamiltonian to
                                       separate the potential and kinetic terms
                                       for. Identity is arbitrarily chosen
                                       to be part of the potential.

    Returns:
        Tuple of (potential_terms, kinetic_terms). Both elements of the tuple
        are numpy arrays of FermionOperators.
    """
    if not isinstance(hamiltonian, FermionOperator):
        try:
            hamiltonian = normal_ordered(get_fermion_operator(hamiltonian))
        except TypeError:
            raise TypeError('hamiltonian must be either a FermionOperator '
                            'or DiagonalCoulombHamiltonian.')

    potential = FermionOperator.zero()
    kinetic = FermionOperator.zero()

    for term, coeff in iteritems(hamiltonian.terms):
        acted = set(term[i][0] for i in range(len(term)))
        if len(acted) == len(term) / 2:
            potential += FermionOperator(term, coeff)
        else:
            kinetic += FermionOperator(term, coeff)

    potential_terms = numpy.array([
        FermionOperator(term, coeff)
        for term, coeff in iteritems(potential.terms)
    ])

    kinetic_terms = numpy.array([
        FermionOperator(term, coeff)
        for term, coeff in iteritems(kinetic.terms)
    ])

    return (potential_terms, kinetic_terms)
#   limitations under the License.

import numpy
import pytest

import cirq
import openfermion
from openfermion import random_diagonal_coulomb_hamiltonian

from openfermioncirq import HamiltonianObjective

# Construct a Hamiltonian for testing
test_hamiltonian = random_diagonal_coulomb_hamiltonian(4,
                                                       real=True,
                                                       seed=26191)
test_fermion_op = openfermion.get_fermion_operator(test_hamiltonian)


def test_hamiltonian_objective_value():

    obj = HamiltonianObjective(test_hamiltonian)
    obj_linear_op = HamiltonianObjective(test_hamiltonian, use_linear_op=True)
    hamiltonian_sparse = openfermion.get_sparse_operator(test_hamiltonian)

    simulator = cirq.google.XmonSimulator()
    qubits = cirq.LineQubit.range(4)
    numpy.random.seed(10581)
    result = simulator.simulate(cirq.testing.random_circuit(qubits, 5, 0.8),
                                qubit_order=qubits)
    correct_val = openfermion.expectation(hamiltonian_sparse,
                                          result.final_state)
Esempio n. 15
0
def test_first_factorization():
    molecule = build_lih_moleculardata()
    oei, tei = molecule.get_integrals()
    lrt_obj = LowRankTrotter(oei=oei, tei=tei)
    (
        eigenvalues,
        one_body_squares,
        one_body_correction,
    ) = lrt_obj.first_factorization()

    # get true op
    n_qubits = molecule.n_qubits
    fermion_tei = of.FermionOperator()
    test_tei_tensor = np.zeros((n_qubits, n_qubits, n_qubits, n_qubits))
    for p, q, r, s in product(range(oei.shape[0]), repeat=4):
        if np.abs(tei[p, q, r, s]) < EQ_TOLERANCE:
            coefficient = 0.0
        else:
            coefficient = tei[p, q, r, s] / 2.0

        for sigma, tau in product(range(2), repeat=2):
            if 2 * p + sigma == 2 * q + tau or 2 * r + tau == 2 * s + sigma:
                continue
            term = (
                (2 * p + sigma, 1),
                (2 * q + tau, 1),
                (2 * r + tau, 0),
                (2 * s + sigma, 0),
            )
            fermion_tei += of.FermionOperator(term, coefficient=coefficient)
            test_tei_tensor[2 * p + sigma, 2 * q + tau, 2 * r + tau, 2 * s +
                            sigma] = coefficient

    mol_ham = of.InteractionOperator(
        one_body_tensor=np.zeros((n_qubits, n_qubits)),
        two_body_tensor=test_tei_tensor,
        constant=0,
    )

    # check induced norm on operator
    checked_op = of.FermionOperator()
    for (
            p,
            q,
    ) in product(range(n_qubits), repeat=2):
        term = ((p, 1), (q, 0))
        coefficient = one_body_correction[p, q]
        checked_op += of.FermionOperator(term, coefficient)

    # Build back two-body component.
    for l in range(one_body_squares.shape[0]):
        one_body_operator = of.FermionOperator()
        for p, q in product(range(n_qubits), repeat=2):
            term = ((p, 1), (q, 0))
            coefficient = one_body_squares[l, p, q]
            one_body_operator += of.FermionOperator(term, coefficient)
        checked_op += eigenvalues[l] * (one_body_operator**2)

    true_fop = of.normal_ordered(of.get_fermion_operator(mol_ham))
    difference = of.normal_ordered(checked_op - true_fop)
    assert np.isclose(0, difference.induced_norm())
Esempio n. 16
0
    # dummy geometry
    geometry = [["Li", [0, 0, 0], ["H", [0, 0, 1.4]]]]
    charge = 0
    multiplicity = 1
    molecule = of.MolecularData(
        geometry=geometry,
        basis="sto-3g",
        charge=charge,
        multiplicity=multiplicity,
    )
    molecule.one_body_integrals = h1e
    molecule.two_body_integrals = np.einsum("ijlk", -2 * h2e)
    molecular_hamiltonian = molecule.get_molecular_hamiltonian()
    molecular_hamiltonian.constant = 0
    ham_fop = of.get_fermion_operator(molecular_hamiltonian)
    ham_mat = of.get_sparse_operator(of.jordan_wigner(ham_fop)).toarray()

    cirq_ci = fqe.to_cirq(wfn)
    cirq_ci = cirq_ci.reshape((2**12, 1))
    assert np.isclose(cirq_ci.conj().T @ ham_mat @ cirq_ci, ecalc)

    hf_idx = int("111100000000", 2)
    hf_idx2 = int("111001000000", 2)
    hf_vec = np.zeros((2**12, 1))
    hf_vec2 = np.zeros((2**12, 1))
    hf_vec[hf_idx, 0] = 1.0
    hf_vec2[hf_idx2, 0] = 1.0

    # scale diagonal so vacuum has non-zero energy
    ww, vv = davidsonliu(ham_mat + np.eye(ham_mat.shape[0]),