Ejemplo n.º 1
0
def expectation_one_body_db_operator_computational_basis_state(
        dual_basis_action, plane_wave_occ_orbitals, grid, spinless):
    """Compute expectation value of a 1-body dual-basis operator with a
    plane wave computational basis state.

    Args:
        dual_basis_action: Dual-basis action of FermionOperator to
                           evaluate expectation value of.
        plane_wave_occ_orbitals (list): list of occupied plane-wave orbitals.
        grid (openfermion.utils.Grid): The grid used for discretization.
        spinless (bool): Whether the system is spinless.

    Returns:
        A real float giving the expectation value.
    """
    expectation_value = 0.0

    r_p = position_vector(
        grid_indices(dual_basis_action[0][0], grid, spinless), grid)
    r_q = position_vector(
        grid_indices(dual_basis_action[1][0], grid, spinless), grid)

    for orbital in plane_wave_occ_orbitals:
        # If there's spin, p and q have to have the same parity (spin),
        # and the new orbital has to have the same spin as these.
        k_orbital = momentum_vector(grid_indices(orbital, grid, spinless),
                                    grid)
        # The Fourier transform is spin-conserving. This means that p, q,
        # and the new orbital all have to have the same spin (parity).
        if spinless or (dual_basis_action[0][0] % 2 ==
                        dual_basis_action[1][0] % 2 == orbital % 2):
            expectation_value += numpy.exp(-1j * k_orbital.dot(r_p - r_q))

    return expectation_value
Ejemplo n.º 2
0
def _fourier_transform_helper(hamiltonian, grid, spinless, phase_factor,
                              vec_func_1, vec_func_2):
    hamiltonian_t = FermionOperator.zero()
    normalize_factor = numpy.sqrt(1.0 / float(grid.num_points()))

    for term in hamiltonian.terms:
        transformed_term = FermionOperator.identity()
        for ladder_op_mode, ladder_op_type in term:
            indices_1 = grid_indices(ladder_op_mode, grid, spinless)
            vec1 = vec_func_1(indices_1, grid)
            new_basis = FermionOperator.zero()
            for indices_2 in grid.all_points_indices():
                vec2 = vec_func_2(indices_2, grid)
                spin = None if spinless else ladder_op_mode % 2
                orbital = orbital_id(grid, indices_2, spin)
                exp_index = phase_factor * 1.0j * numpy.dot(vec1, vec2)
                if ladder_op_type == 1:
                    exp_index *= -1.0

                element = FermionOperator(((orbital, ladder_op_type), ),
                                          numpy.exp(exp_index))
                new_basis += element

            new_basis *= normalize_factor
            transformed_term *= new_basis

        # Coefficient.
        transformed_term *= hamiltonian.terms[term]

        hamiltonian_t += transformed_term

    return hamiltonian_t
Ejemplo n.º 3
0
def expectation_two_body_db_operator_computational_basis_state(
        dual_basis_action, plane_wave_occ_orbitals, grid, spinless):
    """Compute expectation value of a 2-body dual-basis operator with a
    plane wave computational basis state.

    Args:
        dual_basis_action: Dual-basis action of FermionOperator to
                           evaluate expectation value of.
        plane_wave_occ_orbitals (list): list of occupied plane-wave orbitals.
        grid (openfermion.utils.Grid): The grid used for discretization.
        spinless (bool): Whether the system is spinless.

    Returns:
        A float giving the expectation value.
    """
    expectation_value = 0.0

    r = {}
    for i in range(4):
        r[i] = position_vector(
            grid_indices(dual_basis_action[i][0], grid, spinless), grid)

    rr = {}
    k_map = {}
    for i in range(2):
        rr[i] = {}
        k_map[i] = {}
        for j in range(2, 4):
            rr[i][j] = r[i] - r[j]
            k_map[i][j] = {}

    # Pre-computations.
    for o in plane_wave_occ_orbitals:
        k = momentum_vector(grid_indices(o, grid, spinless), grid)
        for i in range(2):
            for j in range(2, 4):
                k_map[i][j][o] = k.dot(rr[i][j])

    for orbital1 in plane_wave_occ_orbitals:
        k1ac = k_map[0][2][orbital1]
        k1ad = k_map[0][3][orbital1]

        for orbital2 in plane_wave_occ_orbitals:
            if orbital1 != orbital2:
                k2bc = k_map[1][2][orbital2]
                k2bd = k_map[1][3][orbital2]

                # The Fourier transform is spin-conserving. This means that
                # the parity of the orbitals involved in the transition must
                # be the same.
                if spinless or ((dual_basis_action[0][0] % 2 ==
                                 dual_basis_action[3][0] % 2 == orbital1 % 2)
                                and
                                (dual_basis_action[1][0] % 2 ==
                                 dual_basis_action[2][0] % 2 == orbital2 % 2)):
                    value = numpy.exp(-1j * (k1ad + k2bc))

                    # Add because it came from two anti-commutations.
                    expectation_value += value

                # The Fourier transform is spin-conserving. This means that
                # the parity of the orbitals involved in the transition must
                # be the same.
                if spinless or ((dual_basis_action[0][0] % 2 ==
                                 dual_basis_action[2][0] % 2 == orbital1 % 2)
                                and
                                (dual_basis_action[1][0] % 2 ==
                                 dual_basis_action[3][0] % 2 == orbital2 % 2)):
                    value = numpy.exp(-1j * (k1ac + k2bd))

                    # Subtract because it came from a single anti-commutation.
                    expectation_value -= value

    return expectation_value
Ejemplo n.º 4
0
def expectation_three_body_db_operator_computational_basis_state(
        dual_basis_action, plane_wave_occ_orbitals, grid, spinless):
    """Compute expectation value of a 3-body dual-basis operator with a
    plane wave computational basis state.

    Args:
        dual_basis_action: Dual-basis action of FermionOperator to
                           evaluate expectation value of.
        plane_wave_occ_orbitals (list): list of occupied plane-wave orbitals.
        grid (openfermion.utils.Grid): The grid used for discretization.
        spinless (bool): Whether the system is spinless.

    Returns:
        A float giving the expectation value.
    """
    expectation_value = 0.0

    r = {}
    for i in range(6):
        r[i] = position_vector(
            grid_indices(dual_basis_action[i][0], grid, spinless), grid)

    rr = {}
    k_map = {}
    for i in range(3):
        rr[i] = {}
        k_map[i] = {}
        for j in range(3, 6):
            rr[i][j] = r[i] - r[j]
            k_map[i][j] = {}

    # Pre-computations.
    for o in plane_wave_occ_orbitals:
        k = momentum_vector(grid_indices(o, grid, spinless), grid)
        for i in range(3):
            for j in range(3, 6):
                k_map[i][j][o] = k.dot(rr[i][j])

    for orbital1 in plane_wave_occ_orbitals:
        k1ad = k_map[0][3][orbital1]
        k1ae = k_map[0][4][orbital1]
        k1af = k_map[0][5][orbital1]

        for orbital2 in plane_wave_occ_orbitals:
            if orbital1 != orbital2:
                k2bd = k_map[1][3][orbital2]
                k2be = k_map[1][4][orbital2]
                k2bf = k_map[1][5][orbital2]

                for orbital3 in plane_wave_occ_orbitals:
                    if orbital1 != orbital3 and orbital2 != orbital3:
                        k3cd = k_map[2][3][orbital3]
                        k3ce = k_map[2][4][orbital3]
                        k3cf = k_map[2][5][orbital3]

                        # Handle \delta_{ad} \delta_{bf} \delta_{ce} after FT.
                        # The Fourier transform is spin-conserving.
                        if spinless or (
                            (dual_basis_action[0][0] % 2 ==
                             dual_basis_action[3][0] % 2 == orbital1 % 2) and
                            (dual_basis_action[1][0] % 2 ==
                             dual_basis_action[5][0] % 2 == orbital2 % 2) and
                            (dual_basis_action[2][0] % 2 ==
                             dual_basis_action[4][0] % 2 == orbital3 % 2)):
                            expectation_value += numpy.exp(
                                -1j * (k1ad + k2bf + k3ce))

                        # Handle -\delta_{ad} \delta_{be} \delta_{cf} after FT.
                        # The Fourier transform is spin-conserving.
                        if spinless or (
                            (dual_basis_action[0][0] % 2 ==
                             dual_basis_action[3][0] % 2 == orbital1 % 2) and
                            (dual_basis_action[1][0] % 2 ==
                             dual_basis_action[4][0] % 2 == orbital2 % 2) and
                            (dual_basis_action[2][0] % 2 ==
                             dual_basis_action[5][0] % 2 == orbital3 % 2)):
                            expectation_value -= numpy.exp(
                                -1j * (k1ad + k2be + k3cf))

                        # Handle -\delta_{ae} \delta_{bf} \delta_{cd} after FT.
                        # The Fourier transform is spin-conserving.
                        if spinless or (
                            (dual_basis_action[0][0] % 2 ==
                             dual_basis_action[4][0] % 2 == orbital1 % 2) and
                            (dual_basis_action[1][0] % 2 ==
                             dual_basis_action[5][0] % 2 == orbital2 % 2) and
                            (dual_basis_action[2][0] % 2 ==
                             dual_basis_action[3][0] % 2 == orbital3 % 2)):
                            expectation_value -= numpy.exp(
                                -1j * (k1ae + k2bf + k3cd))

                        # Handle \delta_{ae} \delta_{bd} \delta_{cf} after FT.
                        # The Fourier transform is spin-conserving.
                        if spinless or (
                            (dual_basis_action[0][0] % 2 ==
                             dual_basis_action[4][0] % 2 == orbital1 % 2) and
                            (dual_basis_action[1][0] % 2 ==
                             dual_basis_action[3][0] % 2 == orbital2 % 2) and
                            (dual_basis_action[2][0] % 2 ==
                             dual_basis_action[5][0] % 2 == orbital3 % 2)):
                            expectation_value += numpy.exp(
                                -1j * (k1ae + k2bd + k3cf))

                        # Handle \delta_{af} \delta_{be} \delta_{cd} after FT.
                        # The Fourier transform is spin-conserving.
                        if spinless or (
                            (dual_basis_action[0][0] % 2 ==
                             dual_basis_action[5][0] % 2 == orbital1 % 2) and
                            (dual_basis_action[1][0] % 2 ==
                             dual_basis_action[4][0] % 2 == orbital2 % 2) and
                            (dual_basis_action[2][0] % 2 ==
                             dual_basis_action[3][0] % 2 == orbital3 % 2)):
                            expectation_value += numpy.exp(
                                -1j * (k1af + k2be + k3cd))

                        # Handle -\delta_{af} \delta_{bd} \delta_{ce} after FT.
                        # The Fourier transform is spin-conserving.
                        if spinless or (
                            (dual_basis_action[0][0] % 2 ==
                             dual_basis_action[5][0] % 2 == orbital1 % 2) and
                            (dual_basis_action[1][0] % 2 ==
                             dual_basis_action[3][0] % 2 == orbital2 % 2) and
                            (dual_basis_action[2][0] % 2 ==
                             dual_basis_action[4][0] % 2 == orbital3 % 2)):
                            expectation_value -= numpy.exp(
                                -1j * (k1af + k2bd + k3ce))

    return expectation_value