Ejemplo n.º 1
0
    def test_jw_get_ground_states_by_particle_number_herm_conserving(self):
        # Initialize a particle-number-conserving Hermitian operator
        ferm_op = FermionOperator('0^ 1') + FermionOperator('1^ 0') + \
            FermionOperator('1^ 2') + FermionOperator('2^ 1') + \
            FermionOperator('1^ 3', -.4) + FermionOperator('3^ 1', -.4)
        jw_hamiltonian = jordan_wigner(ferm_op)
        sparse_operator = get_sparse_operator(jw_hamiltonian)
        n_qubits = 4

        # Test each possible particle number
        for particle_number in range(n_qubits):
            # Get the ground energy and ground states at this particle number
            energy, states = jw_get_ground_states_by_particle_number(
                sparse_operator, particle_number)
            # Construct particle number operator
            num_op = get_sparse_operator(number_operator(n_qubits))
            # For each vector returned, make sure that it is indeed an
            # eigenvector of the original operator with the returned eigenvalue
            # and that it has the correct particle number
            for vec in states:
                # Check that it's an eigenvector with the correct eigenvalue
                op_vec_product = sparse_operator.dot(vec)
                difference = op_vec_product - energy * vec
                discrepancy = 0.
                if difference.nnz:
                    discrepancy = max(map(abs, difference.data))
                self.assertAlmostEqual(0., discrepancy)
                # Check that it has the correct particle number
                num = expectation(num_op, vec)
                self.assertAlmostEqual(num, particle_number)
Ejemplo n.º 2
0
    def test_bk_jw_number_operators(self):
        # Check if a number operator has the same spectrum in both
        # JW and BK representations
        n_qubits = 2
        n1 = number_operator(n_qubits, 0)
        n2 = number_operator(n_qubits, 1)
        n = n1 + n2

        jw_n = jordan_wigner(n)
        bk_n = bravyi_kitaev(n)

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

        self.assertAlmostEqual(
            0., numpy.amax(numpy.absolute(jw_spectrum - bk_spectrum)))
Ejemplo n.º 3
0
 def test_jordan_wigner_transm_op(self):
     n = number_operator(self.n_qubits)
     n_jw = jordan_wigner(n)
     self.assertEqual(self.n_qubits + 1, len(n_jw.terms))
     self.assertEqual(self.n_qubits / 2., n_jw.terms[()])
     for qubit in range(self.n_qubits):
         operators = ((qubit, 'Z'), )
         self.assertEqual(n_jw.terms[operators], -0.5)
Ejemplo n.º 4
0
    def test_bk_jw_number_operator(self):
        # Check if number operator has the same spectrum in both
        # BK and JW representations
        n = number_operator(1, 0)
        jw_n = jordan_wigner(n)
        bk_n = bravyi_kitaev(n)

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

        self.assertAlmostEqual(
            0., numpy.amax(numpy.absolute(jw_spectrum - bk_spectrum)))
Ejemplo n.º 5
0
    def test_bk_jw_number_operator_scaled(self):
        # Check if number operator has the same spectrum in both
        # JW and BK representations
        n_qubits = 1
        n = number_operator(n_qubits, 0, coefficient=2)  # eigenspectrum (0,2)
        jw_n = jordan_wigner(n)
        bk_n = bravyi_kitaev(n)

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

        self.assertAlmostEqual(
            0., numpy.amax(numpy.absolute(jw_spectrum - bk_spectrum)))
Ejemplo n.º 6
0
    def test_jw_restrict_jellium_ground_state_integration(self):
        n_qubits = 4
        grid = Grid(dimensions=1, length=n_qubits, scale=1.0)
        jellium_hamiltonian = jordan_wigner_sparse(
            jellium_model(grid, spinless=False))

        #  2 * n_qubits because of spin
        number_sparse = jordan_wigner_sparse(number_operator(2 * n_qubits))

        restricted_number = jw_number_restrict_operator(number_sparse, 2)
        restricted_jellium_hamiltonian = jw_number_restrict_operator(
            jellium_hamiltonian, 2)

        energy, ground_state = get_ground_state(restricted_jellium_hamiltonian)

        number_expectation = expectation(restricted_number, ground_state)
        self.assertAlmostEqual(number_expectation, 2)
Ejemplo n.º 7
0
    def test_jw_restrict_operator(self):
        """Test the scheme for restricting JW encoded operators to number"""
        # Make a Hamiltonian that cares mostly about number of electrons
        n_qubits = 6
        target_electrons = 3
        penalty_const = 100.
        number_sparse = jordan_wigner_sparse(number_operator(n_qubits))
        bias_sparse = jordan_wigner_sparse(
            sum([FermionOperator(((i, 1), (i, 0)), 1.0) for i
                 in range(n_qubits)], FermionOperator()))
        hamiltonian_sparse = penalty_const * (
            number_sparse - target_electrons *
            scipy.sparse.identity(2**n_qubits)).dot(
            number_sparse - target_electrons *
            scipy.sparse.identity(2**n_qubits)) + bias_sparse

        restricted_hamiltonian = jw_number_restrict_operator(
            hamiltonian_sparse, target_electrons, n_qubits)
        true_eigvals, _ = eigh(hamiltonian_sparse.A)
        test_eigvals, _ = eigh(restricted_hamiltonian.A)

        self.assertAlmostEqual(norm(true_eigvals[:20] - test_eigvals[:20]),
                               0.0)
Ejemplo n.º 8
0
 def test_is_boson_preserving_number(self):
     op = number_operator(n_modes=5, mode=3, parity=1)
     self.assertTrue(op.is_boson_preserving())
Ejemplo n.º 9
0
 def test_transm_number(self):
     n = number_operator(self.n_qubits, 3)
     n_jw = jordan_wigner(n)
     self.assertEqual(n_jw.terms[((3, 'Z'), )], -0.5)
     self.assertEqual(n_jw.terms[()], 0.5)
     self.assertEqual(len(n_jw.terms), 2)
Ejemplo n.º 10
0
def jw_get_ground_states_by_particle_number(sparse_operator,
                                            particle_number,
                                            sparse=True,
                                            num_eigs=3):
    """For a Jordan-Wigner encoded Hermitian operator, compute the lowest
    eigenvalue and eigenstates at a particular particle number. The operator
    must conserve particle number.

    Args:
        sparse_operator(sparse): A Jordan-Wigner encoded sparse operator.
        particle_number(int): The particle number at which to compute
            ground states.
        sparse(boolean, optional): Whether to use sparse eigensolver.
            Default is True.
        num_eigs(int, optional): The number of eigenvalues to request from the
            sparse eigensolver. Needs to be at least as large as the degeneracy
            of the ground energy in order to obtain all ground states.
            Only used if `sparse=True`. Default is 3.

    Returns:
        ground_energy(float): The lowest eigenvalue of sparse_operator within
            the eigenspace of the number operator corresponding to
            particle_number.

        ground_states(list[ndarray]): A list of the corresponding eigenstates.

    Warning:
        The running time of this method is exponential in the number of qubits.
    """
    # Check if operator is Hermitian
    if not is_hermitian(sparse_operator):
        raise ValueError('sparse_operator must be Hermitian.')

    n_qubits = int(numpy.log2(sparse_operator.shape[0]))

    # Check if operator conserves particle number
    sparse_num_op = jordan_wigner_sparse(number_operator(n_qubits))
    com = commutator(sparse_num_op, sparse_operator)
    if com.nnz:
        maxval = max(map(abs, com.data))
        if maxval > EQ_TOLERANCE:
            raise ValueError('sparse_operator must conserve particle number.')

    # Get the operator restricted to the subspace of the desired
    # particle number
    restricted_operator = jw_number_restrict_operator(sparse_operator,
                                                      particle_number,
                                                      n_qubits)

    if sparse and num_eigs >= restricted_operator.shape[0] - 1:
        # Restricted operator too small for sparse eigensolver
        sparse = False

    # Compute eigenvalues and eigenvectors
    if sparse:
        eigvals, eigvecs = scipy.sparse.linalg.eigsh(restricted_operator,
                                                     k=num_eigs,
                                                     which='SA')
        if abs(max(eigvals) - min(eigvals)) < EQ_TOLERANCE:
            warnings.warn(
                'The lowest {} eigenvalues are degenerate. '
                'There may be more ground states; increase '
                'num_eigs or set sparse=False to get '
                'them.'.format(num_eigs), RuntimeWarning)
    else:
        dense_restricted_operator = restricted_operator.toarray()
        eigvals, eigvecs = numpy.linalg.eigh(dense_restricted_operator)

    # Get the ground energy
    if sparse:
        ground_energy = sorted(eigvals)[0]
    else:
        # No need to sort in the case of dense eigenvalue computation
        ground_energy = eigvals[0]

    # Get the indices of eigenvectors corresponding to the ground energy
    ground_state_indices = numpy.where(
        abs(eigvals - ground_energy) < EQ_TOLERANCE)

    ground_states = list()

    for i in ground_state_indices[0]:
        restricted_ground_state = eigvecs[:, i]
        # Expand this ground state to the whole vector space
        number_indices = jw_number_indices(particle_number, n_qubits)
        expanded_ground_state = scipy.sparse.csc_matrix(
            (restricted_ground_state.flatten(),
             (number_indices, [0] * len(number_indices))),
            shape=(2**n_qubits, 1))
        # Add the expanded ground state to the list
        ground_states.append(expanded_ground_state)

    return ground_energy, ground_states
Ejemplo n.º 11
0
def reverse_jordan_wigner(qubit_operator, n_qubits=None):
    """Transforms a QubitOperator into a FermionOperator using the
    Jordan-Wigner transform.

    Operators are mapped as follows:
    Z_j -> I - 2 a^\dagger_j a_j
    X_j -> (a^\dagger_j + a_j) Z_{j-1} Z_{j-2} .. Z_0
    Y_j -> i (a^\dagger_j - a_j) Z_{j-1} Z_{j-2} .. Z_0

    Args:
        qubit_operator: the QubitOperator to be transformed.
        n_qubits: the number of qubits term acts on. If not set, defaults
                to the maximum qubit number acted on by term.

    Returns:
        transformed_term: An instance of the FermionOperator class.

    Raises:
        TypeError: Input must be a QubitOperator.
        TypeError: Invalid number of qubits specified.
        TypeError: Pauli operators must be X, Y or Z.
    """
    if not isinstance(qubit_operator, QubitOperator):
        raise TypeError('Input must be a QubitOperator.')
    if n_qubits is None:
        n_qubits = count_qubits(qubit_operator)
    if n_qubits < count_qubits(qubit_operator):
        raise ValueError('Invalid number of qubits specified.')

    # Loop through terms.
    transformed_operator = FermionOperator()
    for term in qubit_operator.terms:
        transformed_term = FermionOperator(())
        if term:
            working_term = QubitOperator(term)
            pauli_operator = term[-1]
            while pauli_operator is not None:

                # Handle Pauli Z.
                if pauli_operator[1] == 'Z':
                    transformed_pauli = FermionOperator(
                        ()) + number_operator(n_qubits, pauli_operator[0], -2.)

                # Handle Pauli X and Y.
                else:
                    raising_term = FermionOperator(((pauli_operator[0], 1), ))
                    lowering_term = FermionOperator(((pauli_operator[0], 0), ))
                    if pauli_operator[1] == 'Y':
                        raising_term *= 1.j
                        lowering_term *= -1.j

                    transformed_pauli = raising_term + lowering_term

                    # Account for the phase terms.
                    for j in reversed(range(pauli_operator[0])):
                        z_term = QubitOperator(((j, 'Z'), ))
                        working_term = z_term * working_term
                    term_key = list(working_term.terms)[0]
                    transformed_pauli *= working_term.terms[term_key]
                    working_term.terms[list(working_term.terms)[0]] = 1.

                # Get next non-identity operator acting below 'working_qubit'.
                assert len(working_term.terms) == 1
                working_qubit = pauli_operator[0] - 1
                for working_operator in reversed(list(working_term.terms)[0]):
                    if working_operator[0] <= working_qubit:
                        pauli_operator = working_operator
                        break
                    else:
                        pauli_operator = None

                # Multiply term by transformed operator.
                transformed_term *= transformed_pauli

        # Account for overall coefficient
        transformed_term *= qubit_operator.terms[term]
        transformed_operator += transformed_term
    return transformed_operator
Ejemplo n.º 12
0
def mean_field_dwave(x_dimension,
                     y_dimension,
                     tunneling,
                     sc_gap,
                     chemical_potential=0.,
                     periodic=True):
    """Return symbolic representation of a BCS mean-field d-wave Hamiltonian.

    The Hamiltonians of this model live on a grid of dimensions
    `x_dimension` x `y_dimension`.
    The grid can have periodic boundary conditions or not.
    Each site on the grid can have an "up" fermion and a "down" fermion.
    Therefore, there are a total of `2N` spin-orbitals,
    where `N = x_dimension * y_dimension` is the number of sites.

    The Hamiltonian for this model has the form

    .. math::

        \\begin{align}
        H = &- t \sum_{\langle i,j \\rangle} \sum_\sigma
                (a^\dagger_{i, \sigma} a_{j, \sigma} +
                 a^\dagger_{j, \sigma} a_{i, \sigma})
            - \mu \sum_i \sum_{\sigma} a^\dagger_{i, \sigma} a_{i, \sigma}
            \\\\
            &- \sum_{\langle i,j \\rangle} \Delta_{ij}
              (a^\dagger_{i, \\uparrow} a^\dagger_{j, \downarrow} -
               a^\dagger_{i, \downarrow} a^\dagger_{j, \\uparrow} +
               a_{j, \downarrow} a_{i, \\uparrow} -
               a_{j, \\uparrow} a_{i, \downarrow})
        \\end{align}

    where

        - The indices :math:`\langle i, j \\rangle` run over pairs
          :math:`i` and :math:`j` of sites that are connected to each other
          in the grid
        - :math:`\sigma \in \\{\\uparrow, \downarrow\\}` is the spin
        - :math:`t` is the tunneling amplitude
        - :math:`\Delta_{ij}` is equal to :math:`+\Delta/2` for
          horizontal edges and :math:`-\Delta/2` for vertical edges,
          where :math:`\Delta` is the superconducting gap.
        - :math:`\mu` is the chemical potential

    Args:
        x_dimension (int): The width of the grid.
        y_dimension (int): The height of the grid.
        tunneling (float): The tunneling amplitude :math:`t`.
        sc_gap (float): The superconducting gap :math:`\Delta`
        chemical_potential (float, optional): The chemical potential
            :math:`\mu` at each site. Default value is 0.
        periodic (bool, optional): If True, add periodic boundary conditions.
            Default is True.

    Returns:
        mean_field_dwave_model: An instance of the FermionOperator class.
    """
    # Initialize fermion operator class.
    n_sites = x_dimension * y_dimension
    n_spin_orbitals = 2 * n_sites
    mean_field_dwave_model = FermionOperator()

    # Loop through sites and add terms.
    for site in range(n_sites):
        # Add chemical potential
        mean_field_dwave_model += number_operator(n_spin_orbitals,
                                                  up_index(site),
                                                  -chemical_potential)
        mean_field_dwave_model += number_operator(n_spin_orbitals,
                                                  down_index(site),
                                                  -chemical_potential)

        # Index coupled orbitals.
        right_neighbor = site + 1
        bottom_neighbor = site + x_dimension
        # Account for periodic boundaries.
        if periodic:
            if (x_dimension > 2) and ((site + 1) % x_dimension == 0):
                right_neighbor -= x_dimension
            if (y_dimension > 2) and (site + x_dimension + 1 > n_sites):
                bottom_neighbor -= x_dimension * y_dimension

        # Add transition to neighbor on right
        if (site + 1) % x_dimension or (periodic and x_dimension > 2):
            # Add spin-up hopping term.
            operators = ((up_index(site), 1), (up_index(right_neighbor), 0))
            hopping_term = FermionOperator(operators, -tunneling)
            mean_field_dwave_model += hopping_term
            mean_field_dwave_model += hermitian_conjugated(hopping_term)
            # Add spin-down hopping term
            operators = ((down_index(site), 1), (down_index(right_neighbor),
                                                 0))
            hopping_term = FermionOperator(operators, -tunneling)
            mean_field_dwave_model += hopping_term
            mean_field_dwave_model += hermitian_conjugated(hopping_term)

            # Add pairing term
            operators = ((up_index(site), 1), (down_index(right_neighbor), 1))
            pairing_term = FermionOperator(operators, sc_gap / 2.)
            operators = ((down_index(site), 1), (up_index(right_neighbor), 1))
            pairing_term += FermionOperator(operators, -sc_gap / 2.)
            mean_field_dwave_model -= pairing_term
            mean_field_dwave_model -= hermitian_conjugated(pairing_term)

        # Add transition to neighbor below.
        if site + x_dimension + 1 <= n_sites or (periodic and y_dimension > 2):
            # Add spin-up hopping term.
            operators = ((up_index(site), 1), (up_index(bottom_neighbor), 0))
            hopping_term = FermionOperator(operators, -tunneling)
            mean_field_dwave_model += hopping_term
            mean_field_dwave_model += hermitian_conjugated(hopping_term)
            # Add spin-down hopping term
            operators = ((down_index(site), 1), (down_index(bottom_neighbor),
                                                 0))
            hopping_term = FermionOperator(operators, -tunneling)
            mean_field_dwave_model += hopping_term
            mean_field_dwave_model += hermitian_conjugated(hopping_term)

            # Add pairing term
            operators = ((up_index(site), 1), (down_index(bottom_neighbor), 1))
            pairing_term = FermionOperator(operators, -sc_gap / 2.)
            operators = ((down_index(site), 1), (up_index(bottom_neighbor), 1))
            pairing_term += FermionOperator(operators, sc_gap / 2.)
            mean_field_dwave_model -= pairing_term
            mean_field_dwave_model -= hermitian_conjugated(pairing_term)
    # Return.
    return mean_field_dwave_model
Ejemplo n.º 13
0
 def test_is_two_body_number_conserving_number(self):
     op = number_operator(5, 3)
     self.assertTrue(op.is_two_body_number_conserving())
Ejemplo n.º 14
0
def fermi_hubbard(x_dimension,
                  y_dimension,
                  tunneling,
                  coulomb,
                  chemical_potential=0.,
                  magnetic_field=0.,
                  periodic=True,
                  spinless=False,
                  particle_hole_symmetry=False,
                  up_map=up_index,
                  down_map=down_index):
    """Return symbolic representation of a Fermi-Hubbard Hamiltonian.

    The idea of this model is that some fermions move around on a grid and the
    energy of the model depends on where the fermions are.
    The Hamiltonians of this model live on a grid of dimensions
    `x_dimension` x `y_dimension`.
    The grid can have periodic boundary conditions or not.
    In the standard Fermi-Hubbard model (which we call the "spinful" model),
    there is room for an "up" fermion and a "down" fermion at each site on the
    grid. In this model, there are a total of `2N` spin-orbitals,
    where `N = x_dimension * y_dimension` is the number of sites.
    In the spinless model, there is only one spin-orbital per site
    for a total of `N`.

    The Hamiltonian for the spinful model has the form

    .. math::

        \\begin{align}
        H = &- t \sum_{\langle i,j \\rangle} \sum_{\sigma}
                     (a^\dagger_{i, \sigma} a_{j, \sigma} +
                      a^\dagger_{j, \sigma} a_{i, \sigma})
             + U \sum_{i} a^\dagger_{i, \\uparrow} a_{i, \\uparrow}
                         a^\dagger_{j, \downarrow} a_{j, \downarrow}
            \\\\
            &- \mu \sum_i \sum_{\sigma} a^\dagger_{i, \sigma} a_{i, \sigma}
             - h \sum_i (a^\dagger_{i, \\uparrow} a_{i, \\uparrow} -
                       a^\dagger_{i, \downarrow} a_{i, \downarrow})
        \\end{align}

    where

        - The indices :math:`\langle i, j \\rangle` run over pairs
          :math:`i` and :math:`j` of sites that are connected to each other
          in the grid
        - :math:`\sigma \in \\{\\uparrow, \downarrow\\}` is the spin
        - :math:`t` is the tunneling amplitude
        - :math:`U` is the Coulomb potential
        - :math:`\mu` is the chemical potential
        - :math:`h` is the magnetic field

    One can also construct the Hamiltonian for the spinless model, which
    has the form

    .. math::

        H = - t \sum_{k=1}^{N-1} (a_k^\dagger a_{k + 1} + a_{k+1}^\dagger a_k)
            + U \sum_{k=1}^{N-1} a_k^\dagger a_k a_{k+1}^\dagger a_{k+1}
            - \mu \sum_{k=1}^N a_k^\dagger a_k.

    Args:
        x_dimension (int): The width of the grid.
        y_dimension (int): The height of the grid.
        tunneling (float): The tunneling amplitude :math:`t`.
        coulomb (float): The attractive local interaction strength :math:`U`.
        chemical_potential (float, optional): The chemical potential
            :math:`\mu` at each site. Default value is 0.
        magnetic_field (float, optional): The magnetic field :math:`h`
            at each site. Default value is 0. Ignored for the spinless case.
        periodic (bool, optional): If True, add periodic boundary conditions.
            Default is True.
        spinless (bool, optional): If True, return a spinless Fermi-Hubbard
            model. Default is False.
        particle_hole_symmetry (bool, optional): If False, the repulsion
            term corresponds to:

            .. math::

                U \sum_{k=1}^{N-1} a_k^\dagger a_k a_{k+1}^\dagger a_{k+1}

            If True, the repulsion term is replaced by:

            .. math::

                U \sum_{k=1}^{N-1} (a_k^\dagger a_k - \\frac12)
                                   (a_{k+1}^\dagger a_{k+1} - \\frac12)

            which is unchanged under a particle-hole transformation.
            Default is False

    Returns:
        hubbard_model: An instance of the FermionOperator class.
    """
    tunneling = float(tunneling)
    coulomb = float(coulomb)
    chemical_potential = float(chemical_potential)
    magnetic_field = float(magnetic_field)

    # Initialize fermion operator class.
    n_sites = x_dimension * y_dimension
    n_spin_orbitals = n_sites

    if not spinless:
        n_spin_orbitals *= 2

    hubbard_model = FermionOperator.zero()

    # Select particle-hole symmetry
    if particle_hole_symmetry:
        coulomb_shift = FermionOperator((), 0.5)
    else:
        coulomb_shift = FermionOperator.zero()

    # Loop through sites and add terms.
    for site in range(n_sites):
        # Add chemical potential to the spinless case. The magnetic field
        # doesn't contribute.
        if spinless and chemical_potential:
            hubbard_model += number_operator(n_spin_orbitals, site,
                                             -chemical_potential)

        # With spin, add the chemical potential and magnetic field terms.
        elif not spinless:
            hubbard_model += number_operator(
                n_spin_orbitals, up_map(site),
                -chemical_potential - magnetic_field)
            hubbard_model += number_operator(
                n_spin_orbitals, down_map(site),
                -chemical_potential + magnetic_field)

            # Add local pair interaction terms.
            operator_1 = number_operator(n_spin_orbitals,
                                         up_map(site)) - coulomb_shift
            operator_2 = number_operator(n_spin_orbitals,
                                         down_map(site)) - coulomb_shift
            hubbard_model += coulomb * operator_1 * operator_2

        # Index coupled orbitals.
        right_neighbor = site + 1
        bottom_neighbor = site + x_dimension

        # Account for periodic boundaries.
        if periodic:
            if (x_dimension > 2) and ((site + 1) % x_dimension == 0):
                right_neighbor -= x_dimension
            if (y_dimension > 2) and (site + x_dimension + 1 > n_sites):
                bottom_neighbor -= x_dimension * y_dimension

        # Add transition to neighbor on right.
        if (right_neighbor) % x_dimension or (periodic and x_dimension > 2):
            if spinless:
                # Add Coulomb term.
                operator_1 = number_operator(n_spin_orbitals, site,
                                             1.0) - coulomb_shift
                operator_2 = number_operator(n_spin_orbitals, right_neighbor,
                                             1.0) - coulomb_shift
                hubbard_model += coulomb * operator_1 * operator_2

                # Add hopping term.
                operators = ((site, 1), (right_neighbor, 0))

            else:
                # Add hopping term.
                operators = ((up_map(site), 1), (up_map(right_neighbor), 0))
                hopping_term = FermionOperator(operators, -tunneling)
                hubbard_model += hopping_term
                hubbard_model += hermitian_conjugated(hopping_term)

                operators = ((down_map(site), 1), (down_map(right_neighbor),
                                                   0))

            hopping_term = FermionOperator(operators, -tunneling)
            hubbard_model += hopping_term
            hubbard_model += hermitian_conjugated(hopping_term)

        # Add transition to neighbor below.
        if site + x_dimension + 1 <= n_sites or (periodic and y_dimension > 2):
            if spinless:
                # Add Coulomb term.
                operator_1 = number_operator(n_spin_orbitals,
                                             site) - coulomb_shift
                operator_2 = number_operator(n_spin_orbitals,
                                             bottom_neighbor) - coulomb_shift
                hubbard_model += coulomb * operator_1 * operator_2

                # Add hopping term.
                operators = ((site, 1), (bottom_neighbor, 0))

            else:
                # Add hopping term.
                operators = ((up_map(site), 1), (up_map(bottom_neighbor), 0))
                hopping_term = FermionOperator(operators, -tunneling)
                hubbard_model += hopping_term
                hubbard_model += hermitian_conjugated(hopping_term)

                operators = ((down_map(site), 1), (down_map(bottom_neighbor),
                                                   0))

            hopping_term = FermionOperator(operators, -tunneling)
            hubbard_model += hopping_term
            hubbard_model += hermitian_conjugated(hopping_term)

    return hubbard_model
Ejemplo n.º 15
0
 def test_number_operator_nosite(self):
     op = number_operator(4)
     expected = (FermionOperator(((0, 1), (0, 0))) + FermionOperator(
         ((1, 1), (1, 0))) + FermionOperator(
             ((2, 1), (2, 0))) + FermionOperator(((3, 1), (3, 0))))
     self.assertTrue(op.isclose(expected))
Ejemplo n.º 16
0
 def test_number_operator_site(self):
     op = number_operator(3, 2, 1j)
     self.assertTrue(op.isclose(FermionOperator(((2, 1), (2, 0))) * 1j))
Ejemplo n.º 17
0
 def test_is_molecular_term_number(self):
     op = number_operator(n_orbitals=5, orbital=3)
     self.assertTrue(op.is_molecular_term())
Ejemplo n.º 18
0
 def test_normal_ordered_number_reversed(self):
     n_term_rev2 = FermionOperator(((2, 0), (2, 1)))
     number_op2 = number_operator(3, 2)
     expected = FermionOperator(()) - number_op2
     self.assertTrue(normal_ordered(n_term_rev2).isclose(expected))
Ejemplo n.º 19
0
 def test_boson_number_reversed(self):
     n_term_rev2 = BosonOperator(((2, 0), (2, 1)))
     number_op2 = number_operator(3, 2, parity=1)
     expected = BosonOperator(()) + number_op2
     self.assertTrue(normal_ordered(n_term_rev2) == expected)