def process_fermi_hubbard_hopping(constituents):
    for c in constituents:
        if c in ['down', 'up']:
            spin_type = c
        elif c[0] == 'd':
            num_sites = int(c[1:])
        else:
            sites = [int(s) for s in c.split('h')]

    i_idx = 2 * (sites[0] - 1) - 2  # 2i -2
    j_idx = 2 * (sites[1] - 1) - 2  # 2j -2
    if spin_type == 'down':
        i_idx = 2 * (sites[0] - 1)
        j_idx = 2 * (sites[1] - 1)
    elif spin_type == 'up':
        i_idx = 2 * (sites[0]) - 1
        j_idx = 2 * (sites[1]) - 1

    dimensional_description = "{}".format(2 * num_sites - 1)
    dimensional_fermion_op = FermionOperator(dimensional_description)

    hopping_term = FermionOperator(((i_idx, 1), (j_idx, 0)))
    hopping_term += FermionOperator(((j_idx, 1), (i_idx, 0)))
    hopping_term += dimensional_fermion_op

    mtx = jordan_wigner_mtx(hopping_term) - \
        jordan_wigner_mtx(dimensional_fermion_op)
    return np.array(mtx)
Beispiel #2
0
    def test_jw_restrict_operator_hopping_to_1_particle(self):
        hop = FermionOperator('3^ 1') + FermionOperator('1^ 3')
        hop_sparse = jordan_wigner_sparse(hop, n_qubits=4)
        hop_restrict = jw_number_restrict_operator(hop_sparse, 1, n_qubits=4)
        expected = csc_matrix(([1, 1], ([0, 2], [2, 0])), shape=(4, 4))

        self.assertTrue(numpy.allclose(hop_restrict.A, expected.A))
Beispiel #3
0
    def test_bravyi_kitaev_transform(self):
        # Check that the QubitOperators are two-term.
        lowering = bravyi_kitaev(FermionOperator(((3, 0), )))
        raising = bravyi_kitaev(FermionOperator(((3, 1), )))
        self.assertEqual(len(raising.terms), 2)
        self.assertEqual(len(lowering.terms), 2)

        #  Test the locality invariant for N=2^d qubits
        # (c_j majorana is always log2N+1 local on qubits)
        n_qubits = 16
        invariant = numpy.log2(n_qubits) + 1
        for index in range(n_qubits):
            operator = bravyi_kitaev(FermionOperator(((index, 0), )), n_qubits)
            qubit_terms = operator.terms.items()  # Get the majorana terms.

            for item in qubit_terms:
                coeff = item[1]

                #  Identify the c majorana terms by real
                #  coefficients and check their length.
                if not isinstance(coeff, complex):
                    self.assertEqual(len(item[0]), invariant)

        #  Hardcoded coefficient test on 16 qubits
        lowering = bravyi_kitaev(FermionOperator(((9, 0), )), n_qubits)
        raising = bravyi_kitaev(FermionOperator(((9, 1), )), n_qubits)

        correct_operators_c = ((7, 'Z'), (8, 'Z'), (9, 'X'), (11, 'X'), (15,
                                                                         'X'))
        correct_operators_d = ((7, 'Z'), (9, 'Y'), (11, 'X'), (15, 'X'))

        self.assertEqual(lowering.terms[correct_operators_c], 0.5)
        self.assertEqual(lowering.terms[correct_operators_d], 0.5j)
        self.assertEqual(raising.terms[correct_operators_d], -0.5j)
        self.assertEqual(raising.terms[correct_operators_c], 0.5)
Beispiel #4
0
def position_potential_operator(n_dimensions,
                                grid_length,
                                length_scale,
                                spinless=False):
    """Return the potential operator in position space second quantization.

    Args:
        n_dimensions: An int giving the number of dimensions for the model.
        grid_length: Int, the number of points in one dimension of the grid.
        length_scale: Float, the real space length of a box dimension.
        spinless: Boole, whether to use the spinless model or not.

    Returns:
        operator: An instance of the FermionOperator class.
    """
    # Initialize.
    n_points = grid_length**n_dimensions
    volume = length_scale**float(n_dimensions)
    prefactor = 2. * numpy.pi / volume
    operator = FermionOperator()
    if spinless:
        spins = [None]
    else:
        spins = [0, 1]

    # Loop once through all lattice sites.
    for grid_indices_a in itertools.product(range(grid_length),
                                            repeat=n_dimensions):
        coordinates_a = position_vector(grid_indices_a, grid_length,
                                        length_scale)
        for grid_indices_b in itertools.product(range(grid_length),
                                                repeat=n_dimensions):
            coordinates_b = position_vector(grid_indices_b, grid_length,
                                            length_scale)
            differences = coordinates_b - coordinates_a

            # Compute coefficient.
            coefficient = 0.
            for momenta_indices in itertools.product(range(grid_length),
                                                     repeat=n_dimensions):
                momenta = momentum_vector(momenta_indices, grid_length,
                                          length_scale)
                if momenta.any():
                    coefficient += (prefactor *
                                    numpy.cos(momenta.dot(differences)) /
                                    momenta.dot(momenta))

            # Loop over spins and identify interacting orbitals.
            for spin_a in spins:
                orbital_a = orbital_id(grid_length, grid_indices_a, spin_a)
                for spin_b in spins:
                    orbital_b = orbital_id(grid_length, grid_indices_b, spin_b)

                    # Add interaction term.
                    if orbital_a != orbital_b:
                        operators = ((orbital_a, 1), (orbital_a, 0),
                                     (orbital_b, 1), (orbital_b, 0))
                        operator += FermionOperator(operators, coefficient)

    return operator
Beispiel #5
0
    def test_bk_jw_majoranas(self):
        # Check if the Majorana operators have the same spectrum
        # irrespectively of the transform.
        n_qubits = 7

        a = FermionOperator(((1, 0), ))
        a_dag = FermionOperator(((1, 1), ))

        c = a + a_dag
        d = 1j * (a_dag - a)

        c_spins = [jordan_wigner(c), bravyi_kitaev(c)]
        d_spins = [jordan_wigner(d), bravyi_kitaev(d)]

        c_sparse = [
            get_sparse_operator(c_spins[0]),
            get_sparse_operator(c_spins[1])
        ]
        d_sparse = [
            get_sparse_operator(d_spins[0]),
            get_sparse_operator(d_spins[1])
        ]

        c_spectrum = [eigenspectrum(c_spins[0]), eigenspectrum(c_spins[1])]
        d_spectrum = [eigenspectrum(d_spins[0]), eigenspectrum(d_spins[1])]

        self.assertAlmostEqual(
            0., numpy.amax(numpy.absolute(d_spectrum[0] - d_spectrum[1])))
Beispiel #6
0
def get_interaction_rdm(qubit_operator, n_qubits=None):
    """Build an InteractionRDM from measured qubit operators.

    Returns: An InteractionRDM object.
    """
    # Avoid circular import.
    from fermilib.transforms import jordan_wigner
    if n_qubits is None:
        n_qubits = count_qubits(qubit_operator)
    one_rdm = numpy.zeros((n_qubits, ) * 2, dtype=complex)
    two_rdm = numpy.zeros((n_qubits, ) * 4, dtype=complex)

    # One-RDM.
    for i, j in itertools.product(range(n_qubits), repeat=2):
        transformed_operator = jordan_wigner(FermionOperator(((i, 1), (j, 0))))
        for term, coefficient in iteritems(transformed_operator.terms):
            if term in qubit_operator.terms:
                one_rdm[i, j] += coefficient * qubit_operator.terms[term]

    # Two-RDM.
    for i, j, k, l in itertools.product(range(n_qubits), repeat=4):
        transformed_operator = jordan_wigner(
            FermionOperator(((i, 1), (j, 1), (k, 0), (l, 0))))
        for term, coefficient in iteritems(transformed_operator.terms):
            if term in qubit_operator.terms:
                two_rdm[i, j, k, l] += coefficient * qubit_operator.terms[term]

    return InteractionRDM(one_rdm, two_rdm)
Beispiel #7
0
def plane_wave_kinetic(grid, spinless=False):
    """Return the kinetic energy operator in the plane wave basis.

    Args:
        grid (fermilib.utils.Grid): The discretization to use.
        spinless (bool): Whether to use the spinless model or not.

    Returns:
        FermionOperator: The kinetic momentum operator.
    """
    # Initialize.
    operator = FermionOperator()
    spins = [None] if spinless else [0, 1]

    # Loop once through all plane waves.
    for momenta_indices in grid.all_points_indices():
        momenta = momentum_vector(momenta_indices, grid)
        coefficient = momenta.dot(momenta) / 2.

        # Loop over spins.
        for spin in spins:
            orbital = orbital_id(grid, momenta_indices, spin)

            # Add interaction term.
            operators = ((orbital, 1), (orbital, 0))
            operator += FermionOperator(operators, coefficient)

    return operator
Beispiel #8
0
    def test_zero(self):
        n_qubits = 5
        transmed_i = reverse_jordan_wigner(QubitOperator(), n_qubits)
        expected_i = FermionOperator()
        self.assertTrue(transmed_i.isclose(expected_i))

        retransmed_i = jordan_wigner(transmed_i)
        self.assertTrue(expected_i.isclose(retransmed_i))
Beispiel #9
0
    def test_ccr_offsite_even_cc(self):
        c2 = FermionOperator(((2, 1), ))
        c4 = FermionOperator(((4, 1), ))
        self.assertTrue(
            normal_ordered(c2 * c4).isclose(normal_ordered(-c4 * c2)))

        self.assertTrue(
            jordan_wigner(c2 * c4).isclose(jordan_wigner(-c4 * c2)))
Beispiel #10
0
    def test_ccr_offsite_odd_cc(self):
        c1 = FermionOperator(((1, 1), ))
        c4 = FermionOperator(((4, 1), ))
        self.assertTrue(
            normal_ordered(c1 * c4).isclose(normal_ordered(-c4 * c1)))

        self.assertTrue(
            jordan_wigner(c1 * c4).isclose(jordan_wigner(-c4 * c1)))
Beispiel #11
0
    def test_ccr_offsite_even_aa(self):
        a2 = FermionOperator(((2, 0), ))
        a4 = FermionOperator(((4, 0), ))
        self.assertTrue(
            normal_ordered(a2 * a4).isclose(normal_ordered(-a4 * a2)))

        self.assertTrue(
            jordan_wigner(a2 * a4).isclose(jordan_wigner(-a4 * a2)))
Beispiel #12
0
    def test_ccr_offsite_odd_aa(self):
        a1 = FermionOperator(((1, 0), ))
        a4 = FermionOperator(((4, 0), ))
        self.assertTrue(
            normal_ordered(a1 * a4).isclose(normal_ordered(-a4 * a1)))

        self.assertTrue(
            jordan_wigner(a1 * a4).isclose(jordan_wigner(-a4 * a1)))
Beispiel #13
0
 def test_get_interaction_operator_one_body_twoterm(self):
     interaction_operator = get_interaction_operator(
         FermionOperator('2^ 3', -2j) + FermionOperator('3^ 2', 3j),
         self.n_qubits)
     one_body = numpy.zeros((self.n_qubits, self.n_qubits), complex)
     one_body[2, 3] = -2j
     one_body[3, 2] = 3j
     self.assertEqual(interaction_operator,
                      InteractionOperator(0.0, one_body, self.two_body))
Beispiel #14
0
def benchmark_fermion_math_and_normal_order(n_qubits, term_length, power):
    """Benchmark both arithmetic operators and normal ordering on fermions.

    The idea is we generate two random FermionTerms, A and B, each acting
    on n_qubits with term_length operators. We then compute
    (A + B) ** power. This is costly that is the first benchmark. The second
    benchmark is in normal ordering whatever comes out.

    Args:
        n_qubits: The number of qubits on which these terms act.
        term_length: The number of operators in each term.
        power: Int, the exponent to which to raise sum of the two terms.

    Returns:
        runtime_math: The time it takes to perform (A + B) ** power
        runtime_normal_order: The time it takes to perform
            FermionOperator.normal_order()
    """
    # Generate random operator strings.
    operators_a = [(numpy.random.randint(n_qubits), numpy.random.randint(2))]
    operators_b = [(numpy.random.randint(n_qubits), numpy.random.randint(2))]
    for operator_number in range(term_length):

        # Make sure the operator is not trivially zero.
        operator_a = (numpy.random.randint(n_qubits), numpy.random.randint(2))
        while operator_a == operators_a[-1]:
            operator_a = (numpy.random.randint(n_qubits),
                          numpy.random.randint(2))
        operators_a += [operator_a]

        # Do the same for the other operator.
        operator_b = (numpy.random.randint(n_qubits), numpy.random.randint(2))
        while operator_b == operators_b[-1]:
            operator_b = (numpy.random.randint(n_qubits),
                          numpy.random.randint(2))
        operators_b += [operator_b]

    # Initialize FermionTerms and then sum them together.
    fermion_term_a = FermionOperator(tuple(operators_a),
                                     float(numpy.random.randn()))
    fermion_term_b = FermionOperator(tuple(operators_b),
                                     float(numpy.random.randn()))
    fermion_operator = fermion_term_a + fermion_term_b

    # Exponentiate.
    start_time = time.time()
    fermion_operator **= power
    runtime_math = time.time() - start_time

    # Normal order.
    start_time = time.time()
    normal_ordered(fermion_operator)
    runtime_normal_order = time.time() - start_time

    # Return.
    return runtime_math, runtime_normal_order
Beispiel #15
0
def plane_wave_u_operator(n_dimensions, grid_length, length_scale,
                          nuclear_charges, spinless):
    """Return the external potential operator in plane wave basis.

    Args:
        n_dimensions: An int giving the number of dimensions for the model.
        grid_length: Int, the number of points in one dimension of the grid.
        length_scale: Float, the real space length of a box dimension.
        nuclear_charges: 3D int array, the nuclear charges.
        spinless: Bool, whether to use the spinless model or not.

    Returns:
        operator: An instance of the FermionOperator class.
    """
    n_points = grid_length**n_dimensions
    volume = length_scale**float(n_dimensions)
    prefactor = -4.0 * numpy.pi / volume
    operator = None
    if spinless:
        spins = [None]
    else:
        spins = [0, 1]

    for grid_indices_p in itertools.product(range(grid_length),
                                            repeat=n_dimensions):
        for grid_indices_q in itertools.product(range(grid_length),
                                                repeat=n_dimensions):
            shift = grid_length // 2
            grid_indices_p_q = [
                (grid_indices_p[i] - grid_indices_q[i] + shift) % grid_length
                for i in range(n_dimensions)
            ]
            momenta_p_q = momentum_vector(grid_indices_p_q, grid_length,
                                          length_scale)
            momenta_p_q_squared = momenta_p_q.dot(momenta_p_q)
            if momenta_p_q_squared < EQ_TOLERANCE:
                continue

            for grid_indices_j in itertools.product(range(grid_length),
                                                    repeat=n_dimensions):
                coordinate_j = position_vector(grid_indices_j, grid_length,
                                               length_scale)
                exp_index = 1.0j * momenta_p_q.dot(coordinate_j)
                coefficient = prefactor / momenta_p_q_squared * \
                    nuclear_charges[grid_indices_j] * numpy.exp(exp_index)

                for spin in spins:
                    orbital_p = orbital_id(grid_length, grid_indices_p, spin)
                    orbital_q = orbital_id(grid_length, grid_indices_q, spin)
                    operators = ((orbital_p, 1), (orbital_q, 0))
                    if operator is None:
                        operator = FermionOperator(operators, coefficient)
                    else:
                        operator += FermionOperator(operators, coefficient)

    return operator
Beispiel #16
0
    def test_z(self):
        pauli_z = QubitOperator(((2, 'Z'), ))
        transmed_z = reverse_jordan_wigner(pauli_z)

        expected = (FermionOperator(()) + FermionOperator(
            ((2, 1), (2, 0)), -2.))
        self.assertTrue(transmed_z.isclose(expected))

        retransmed_z = jordan_wigner(transmed_z)
        self.assertTrue(pauli_z.isclose(retransmed_z))
Beispiel #17
0
 def test_ccr_onsite(self):
     c1 = FermionOperator(((1, 1), ))
     a1 = hermitian_conjugated(c1)
     self.assertTrue(
         normal_ordered(
             c1 *
             a1).isclose(FermionOperator(()) - normal_ordered(a1 * c1)))
     self.assertTrue(
         jordan_wigner(
             c1 * a1).isclose(QubitOperator(()) - jordan_wigner(a1 * c1)))
Beispiel #18
0
def uccsd_operator(single_amplitudes, double_amplitudes, anti_hermitian=True):
    """Create a fermionic operator that is the generator of uccsd.

    This a the most straight-forward method to generate UCCSD operators,
    however it is slightly inefficient. In particular, it parameterizes
    all possible excitations, so it represents a generalized unitary coupled
    cluster ansatz, but also does not explicitly enforce the uniqueness
    in parametrization, so it is redundant. For example there will be a linear
    dependency in the ansatz of single_amplitudes[i,j] and
    single_amplitudes[j,i].

    Args:
        single_amplitudes(list or ndarray): list of lists with each sublist
            storing a list of indices followed by single excitation amplitudes
            i.e. [[[i,j],t_ij], ...] OR [NxN] array storing single excitation
            amplitudes corresponding to
            t[i,j] * (a_i^\dagger a_j - H.C.)
        double_amplitudes(list or ndarray): list of lists with each sublist
            storing a list of indices followed by double excitation amplitudes
            i.e. [[[i,j,k,l],t_ijkl], ...] OR [NxNxNxN] array storing double
            excitation amplitudes corresponding to
            t[i,j,k,l] * (a_i^\dagger a_j a_k^\dagger a_l - H.C.)
        anti_hermitian(Bool): Flag to generate only normal CCSD operator
            rather than unitary variant, primarily for testing

    Returns:
        uccsd_generator(FermionOperator): Anti-hermitian fermion operator that
        is the generator for the uccsd wavefunction.
    """

    uccsd_generator = FermionOperator()

    # Re-format inputs (ndarrays to lists) if necessary
    if (isinstance(single_amplitudes, numpy.ndarray) or
            isinstance(double_amplitudes, numpy.ndarray)):
        single_amplitudes, double_amplitudes = convert_amplitude_format(
            single_amplitudes,
            double_amplitudes)

    # Add single excitations
    for (i, j), t_ij in single_amplitudes:
        i, j = int(i), int(j)
        uccsd_generator += FermionOperator(((i, 1), (j, 0)), t_ij)
        if anti_hermitian:
            uccsd_generator += FermionOperator(((j, 1), (i, 0)), -t_ij)

    # Add double excitations
    for (i, j, k, l), t_ijkl in double_amplitudes:
        i, j, k, l = int(i), int(j), int(k), int(l)
        uccsd_generator += FermionOperator(
            ((i, 1), (j, 0), (k, 1), (l, 0)), t_ijkl)
        if anti_hermitian:
            uccsd_generator += FermionOperator(
                ((l, 1), (k, 0), (j, 1), (i, 0)), -t_ijkl)
    return uccsd_generator
Beispiel #19
0
    def test_yy(self):
        yy = QubitOperator(((2, 'Y'), (3, 'Y')), 2.)
        transmed_yy = reverse_jordan_wigner(yy)
        retransmed_yy = jordan_wigner(transmed_yy)

        expected1 = -(FermionOperator(((2, 1), ), 2.) + FermionOperator(
            ((2, 0), ), 2.))
        expected2 = (FermionOperator(((3, 1), )) - FermionOperator(((3, 0), )))
        expected = expected1 * expected2

        self.assertTrue(yy.isclose(retransmed_yy))
        self.assertTrue(
            normal_ordered(transmed_yy).isclose(normal_ordered(expected)))
Beispiel #20
0
    def test_xy(self):
        xy = QubitOperator(((4, 'X'), (5, 'Y')), -2.j)
        transmed_xy = reverse_jordan_wigner(xy)
        retransmed_xy = jordan_wigner(transmed_xy)

        expected1 = -2j * (FermionOperator(((4, 1), ), 1j) - FermionOperator(
            ((4, 0), ), 1j))
        expected2 = (FermionOperator(((5, 1), )) - FermionOperator(((5, 0), )))
        expected = expected1 * expected2

        self.assertTrue(xy.isclose(retransmed_xy))
        self.assertTrue(
            normal_ordered(transmed_xy).isclose(normal_ordered(expected)))
Beispiel #21
0
    def test_sparse_uccsd_operator_numpy_inputs(self):
        """Test numpy ndarray inputs to uccsd_operator that are sparse"""
        test_orbitals = 30
        sparse_single_amplitudes = numpy.zeros((test_orbitals, test_orbitals))
        sparse_double_amplitudes = numpy.zeros(
            (test_orbitals, test_orbitals, test_orbitals, test_orbitals))

        sparse_single_amplitudes[3, 5] = 0.12345
        sparse_single_amplitudes[12, 4] = 0.44313

        sparse_double_amplitudes[0, 12, 6, 2] = 0.3434
        sparse_double_amplitudes[1, 4, 6, 13] = -0.23423

        generator = uccsd_operator(sparse_single_amplitudes,
                                   sparse_double_amplitudes)

        test_generator = (0.12345 * FermionOperator("3^ 5") +
                          (-0.12345) * FermionOperator("5^ 3") +
                          0.44313 * FermionOperator("12^ 4") +
                          (-0.44313) * FermionOperator("4^ 12") +
                          0.3434 * FermionOperator("0^ 12 6^ 2") +
                          (-0.3434) * FermionOperator("2^ 6 12^ 0") +
                          (-0.23423) * FermionOperator("1^ 4 6^ 13") +
                          0.23423 * FermionOperator("13^ 6 4^ 1"))
        self.assertTrue(test_generator.isclose(generator))
Beispiel #22
0
    def test_bk_jw_hopping_operator(self):
        # Check if the spectrum fits for a single hoppping operator
        n_qubits = 5
        ho = FermionOperator(((1, 1), (4, 0))) + FermionOperator(
            ((4, 1), (1, 0)))
        jw_ho = jordan_wigner(ho)
        bk_ho = bravyi_kitaev(ho)

        # Diagonalize and make sure the spectra are the same.
        jw_spectrum = eigenspectrum(jw_ho)
        bk_spectrum = eigenspectrum(bk_ho)

        self.assertAlmostEqual(
            0., numpy.amax(numpy.absolute(jw_spectrum - bk_spectrum)))
Beispiel #23
0
    def test_yx(self):
        yx = QubitOperator(((0, 'Y'), (1, 'X')), -0.5)
        transmed_yx = reverse_jordan_wigner(yx)
        retransmed_yx = jordan_wigner(transmed_yx)

        expected1 = 1j * (FermionOperator(((0, 1), )) + FermionOperator(
            ((0, 0), )))
        expected2 = -0.5 * (FermionOperator(((1, 1), )) + FermionOperator(
            ((1, 0), )))
        expected = expected1 * expected2

        self.assertTrue(yx.isclose(retransmed_yx))
        self.assertTrue(
            normal_ordered(transmed_yx).isclose(normal_ordered(expected)))
Beispiel #24
0
    def test_jw_restrict_operator_hopping_to_1_particle_default_nqubits(self):
        interaction = (FermionOperator('3^ 2^ 4 1') +
                       FermionOperator('4^ 1^ 3 2'))
        interaction_sparse = jordan_wigner_sparse(interaction, n_qubits=6)
        # n_qubits should default to 6
        interaction_restrict = jw_number_restrict_operator(
            interaction_sparse, 2)

        dim = 6 * 5 / 2  # shape of new sparse array
        # 3^ 2^ 4 1 maps 2**4 + 2 = 18 to 2**3 + 2**2 = 12 and vice versa;
        # in the 2-particle subspace (1, 4) and (2, 3) are 7th and 9th.
        expected = csc_matrix(([-1, -1], ([7, 9], [9, 7])), shape=(dim, dim))

        self.assertTrue(numpy.allclose(interaction_restrict.A, expected.A))
Beispiel #25
0
def uccsd_operator(single_amplitudes, double_amplitudes, anti_hermitian=True):
    """Create a fermionic operator that is the generator of uccsd.

    This a the most straight-forward method to generate UCCSD operators,
    however it is slightly inefficient.  In particular, it parameterizes
    all possible exictations, so it represents a generalized unitary coupled
    cluster ansatz, but also does not explicitly enforce the uniqueness
    in paramterization, so it is redundant. For example there will be a linear
    dependency in the ansatz of single_amplitudes[i,j] and
    single_amplitudes[j,i].

    Args:
        single_amplitudes(ndarray): [NxN] array storing single excitation
            amplitudes corresponding to t[i,j] * (a_i^\dagger a_j + H.C.)
        double_amplitudes(ndarray): [NxNxNxN] array storing double excitation
            amplitudes corresponding to
            t[i,j,k,l] * (a_i^\dagger a_j a_k^\dagger a_l + H.C.)
        anti_hermitian(Bool): Flag to generate only normal CCSD operator
            rather than unitary variant, primarily for testing

    Returns:
        uccsd_generator(FermionOperator): Anti-hermitian fermion operator that
        is the generator for the uccsd wavefunction.
    """
    n_orbitals = single_amplitudes.shape[0]
    assert (n_orbitals == double_amplitudes.shape[0])
    uccsd_generator = FermionOperator()

    # Add single excitations
    for i, j in itertools.product(range(n_orbitals), repeat=2):
        if single_amplitudes[i, j] == 0.:
            continue
        uccsd_generator += FermionOperator(((i, 1), (j, 0)),
                                           single_amplitudes[i, j])
        if (anti_hermitian):
            uccsd_generator += FermionOperator(((j, 1), (i, 0)),
                                               -single_amplitudes[i, j])

        # Add double excitations
    for i, j, k, l in itertools.product(range(n_orbitals), repeat=4):
        if double_amplitudes[i, j, k, l] == 0.:
            continue
        uccsd_generator += FermionOperator(((i, 1), (j, 0), (k, 1), (l, 0)),
                                           double_amplitudes[i, j, k, l])
        if (anti_hermitian):
            uccsd_generator += FermionOperator(
                ((l, 1), (k, 0), (j, 1), (i, 0)),
                -double_amplitudes[i, j, k, l])

    return uccsd_generator
Beispiel #26
0
    def test_xx(self):
        xx = QubitOperator(((3, 'X'), (4, 'X')), 2.)
        transmed_xx = reverse_jordan_wigner(xx)
        retransmed_xx = jordan_wigner(transmed_xx)

        expected1 = (FermionOperator(((3, 1), ), 2.) - FermionOperator(
            ((3, 0), ), 2.))
        expected2 = (FermionOperator(((4, 1), ), 1.) + FermionOperator(
            ((4, 0), ), 1.))
        expected = expected1 * expected2

        self.assertTrue(xx.isclose(retransmed_xx))
        self.assertTrue(
            normal_ordered(transmed_xx).isclose(normal_ordered(expected)))
Beispiel #27
0
    def test_jordan_wigner_one_body(self):
        # Make sure it agrees with jordan_wigner(FermionTerm).
        for p in range(self.n_qubits):
            for q in range(self.n_qubits):
                # Get test qubit operator.
                test_operator = jordan_wigner_one_body(p, q)

                # Get correct qubit operator.
                fermion_term = FermionOperator(((p, 1), (q, 0)))
                correct_op = jordan_wigner(fermion_term)
                hermitian_conjugate = hermitian_conjugated(fermion_term)
                if not fermion_term.isclose(hermitian_conjugate):
                    correct_op += jordan_wigner(hermitian_conjugate)

                self.assertTrue(test_operator.isclose(correct_op))
Beispiel #28
0
def plane_wave_external_potential(grid, geometry, spinless):
    """Return the external potential operator in plane wave basis.

    Args:
        grid (Grid): The discretization to use.
        geometry: A list of tuples giving the coordinates of each atom.
            example is [('H', (0, 0, 0)), ('H', (0, 0, 0.7414))].
            Distances in atomic units. Use atomic symbols to specify atoms.
        spinless: Bool, whether to use the spinless model or not.

    Returns:
        FermionOperator: The plane wave operator.
    """
    prefactor = -4.0 * numpy.pi / grid.volume_scale()
    operator = None
    if spinless:
        spins = [None]
    else:
        spins = [0, 1]

    for indices_p in grid.all_points_indices():
        for indices_q in grid.all_points_indices():
            shift = grid.length // 2
            grid_indices_p_q = [
                (indices_p[i] - indices_q[i] + shift) % grid.length
                for i in range(grid.dimensions)]
            momenta_p_q = momentum_vector(grid_indices_p_q, grid)
            momenta_p_q_squared = momenta_p_q.dot(momenta_p_q)
            if momenta_p_q_squared < EQ_TOLERANCE:
                continue

            for nuclear_term in geometry:
                coordinate_j = numpy.array(nuclear_term[1])
                exp_index = 1.0j * momenta_p_q.dot(coordinate_j)
                coefficient = (prefactor / momenta_p_q_squared *
                               periodic_hash_table[nuclear_term[0]] *
                               numpy.exp(exp_index))

                for spin in spins:
                    orbital_p = orbital_id(grid, indices_p, spin)
                    orbital_q = orbital_id(grid, indices_q, spin)
                    operators = ((orbital_p, 1), (orbital_q, 0))
                    if operator is None:
                        operator = FermionOperator(operators, coefficient)
                    else:
                        operator += FermionOperator(operators, coefficient)

    return operator
Beispiel #29
0
 def test_get_interaction_operator_one_body(self):
     interaction_operator = get_interaction_operator(
         FermionOperator('2^ 2'), self.n_qubits)
     one_body = numpy.zeros((self.n_qubits, self.n_qubits), float)
     one_body[2, 2] = 1.
     self.assertEqual(interaction_operator,
                      InteractionOperator(0.0, one_body, self.two_body))
Beispiel #30
0
    def test_qubit_jw_fermion_integration(self):

        # Initialize a random fermionic operator.
        fermion_operator = FermionOperator(((3, 1), (2, 1), (1, 0), (0, 0)),
                                           -4.3)
        fermion_operator += FermionOperator(((3, 1), (1, 0)), 8.17)
        fermion_operator += 3.2 * FermionOperator()

        # Map to qubits and compare matrix versions.
        qubit_operator = jordan_wigner(fermion_operator)
        qubit_sparse = get_sparse_operator(qubit_operator)
        qubit_spectrum = sparse_eigenspectrum(qubit_sparse)
        fermion_sparse = jordan_wigner_sparse(fermion_operator)
        fermion_spectrum = sparse_eigenspectrum(fermion_sparse)
        self.assertAlmostEqual(
            0., numpy.amax(numpy.absolute(fermion_spectrum - qubit_spectrum)))