Exemple #1
0
def _spinful_fermi_hubbard_model(x_dimension, y_dimension, tunneling, coulomb,
                                 chemical_potential, magnetic_field, periodic,
                                 particle_hole_symmetry):

    # Initialize operator.
    n_sites = x_dimension * y_dimension
    n_spin_orbitals = 2 * n_sites
    hubbard_model = FermionOperator()

    # Loop through sites and add terms.
    for site in range(n_sites):

        # Get indices of right and bottom neighbors
        right_neighbor = _right_neighbor(site, x_dimension, y_dimension,
                                         periodic)
        bottom_neighbor = _bottom_neighbor(site, x_dimension, y_dimension,
                                           periodic)

        # Avoid double-counting edges when one of the dimensions is 2
        # and the system is periodic
        if x_dimension == 2 and periodic and site % 2 == 1:
            right_neighbor = None
        if y_dimension == 2 and periodic and site >= x_dimension:
            bottom_neighbor = None

        # Add hopping terms with neighbors to the right and bottom.
        if right_neighbor is not None:
            hubbard_model += _hopping_term(up_index(site),
                                           up_index(right_neighbor),
                                           -tunneling)
            hubbard_model += _hopping_term(down_index(site),
                                           down_index(right_neighbor),
                                           -tunneling)
        if bottom_neighbor is not None:
            hubbard_model += _hopping_term(up_index(site),
                                           up_index(bottom_neighbor),
                                           -tunneling)
            hubbard_model += _hopping_term(down_index(site),
                                           down_index(bottom_neighbor),
                                           -tunneling)

        # Add local pair Coulomb interaction terms.
        hubbard_model += _coulomb_interaction_term(n_spin_orbitals,
                                                   up_index(site),
                                                   down_index(site), coulomb,
                                                   particle_hole_symmetry)

        # Add chemical potential and magnetic field terms.
        hubbard_model += number_operator(n_spin_orbitals, up_index(site),
                                         -chemical_potential - magnetic_field)
        hubbard_model += number_operator(n_spin_orbitals, down_index(site),
                                         -chemical_potential + magnetic_field)

    return hubbard_model
    def test_number_operator_nosite(self):
        op = number_operator(4, parity=-1)
        expected = (FermionOperator(((0, 1), (0, 0))) + FermionOperator(
            ((1, 1), (1, 0))) + FermionOperator(
                ((2, 1), (2, 0))) + FermionOperator(((3, 1), (3, 0))))
        self.assertEqual(op, expected)

        op = number_operator(4, parity=1)
        expected = (BosonOperator(((0, 1), (0, 0))) + BosonOperator(
            ((1, 1), (1, 0))) + BosonOperator(((2, 1), (2, 0))) + BosonOperator(
                ((3, 1), (3, 0))))
        self.assertTrue(op == expected)
Exemple #3
0
def _coulomb_interaction_term(n_sites,
                              i,
                              j,
                              coefficient,
                              particle_hole_symmetry,
                              bosonic=False):
    op_class = BosonOperator if bosonic else FermionOperator
    number_operator_i = number_operator(n_sites, i, parity=2 * bosonic - 1)
    number_operator_j = number_operator(n_sites, j, parity=2 * bosonic - 1)
    if particle_hole_symmetry:
        number_operator_i -= op_class((), 0.5)
        number_operator_j -= op_class((), 0.5)
    return coefficient * number_operator_i * number_operator_j
Exemple #4
0
def _spinless_fermi_hubbard_model(x_dimension, y_dimension, tunneling, coulomb,
                                  chemical_potential, magnetic_field, periodic,
                                  particle_hole_symmetry):

    # Initialize operator.
    n_sites = x_dimension * y_dimension
    hubbard_model = FermionOperator()

    # Loop through sites and add terms.
    for site in range(n_sites):

        # Get indices of right and bottom neighbors
        right_neighbor = _right_neighbor(site, x_dimension, y_dimension,
                                         periodic)
        bottom_neighbor = _bottom_neighbor(site, x_dimension, y_dimension,
                                           periodic)

        # Avoid double-counting edges when one of the dimensions is 2
        # and the system is periodic
        if x_dimension == 2 and periodic and site % 2 == 1:
            right_neighbor = None
        if y_dimension == 2 and periodic and site >= x_dimension:
            bottom_neighbor = None

        # Add terms that couple with neighbors to the right and bottom.
        if right_neighbor is not None:
            # Add hopping term
            hubbard_model += _hopping_term(site, right_neighbor, -tunneling)
            # Add local Coulomb interaction term
            hubbard_model += _coulomb_interaction_term(n_sites, site,
                                                       right_neighbor, coulomb,
                                                       particle_hole_symmetry)
        if bottom_neighbor is not None:
            # Add hopping term
            hubbard_model += _hopping_term(site, bottom_neighbor, -tunneling)
            # Add local Coulomb interaction term
            hubbard_model += _coulomb_interaction_term(n_sites, site,
                                                       bottom_neighbor,
                                                       coulomb,
                                                       particle_hole_symmetry)

        # Add chemical potential. The magnetic field doesn't contribute.
        hubbard_model += number_operator(n_sites, site, -chemical_potential)

    return hubbard_model
def mean_field_dwave(x_dimension,
                     y_dimension,
                     tunneling,
                     sc_gap,
                     chemical_potential=0.,
                     periodic=True):
    r"""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
 def test_bad_parity(self):
     with self.assertRaises(ValueError):
         number_operator(4, parity=2)
    def test_fermion_number_operator_site(self):
        op = number_operator(3, 2, 1j, -1)
        self.assertEqual(op, FermionOperator(((2, 1), (2, 0))) * 1j)

        op = number_operator(3, 2, 1j, 1)
        self.assertTrue(op == BosonOperator(((2, 1), (2, 0))) * 1j)
def reverse_jordan_wigner(qubit_operator, n_qubits=None):
    r"""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 = op_utils.count_qubits(qubit_operator)
    if n_qubits < op_utils.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
Exemple #9
0
def bose_hubbard(x_dimension,
                 y_dimension,
                 tunneling,
                 interaction,
                 chemical_potential=0.,
                 dipole=0.,
                 periodic=True):
    r"""Return symbolic representation of a Bose-Hubbard Hamiltonian.

    In this model, bosons move around on a lattice, and the
    energy of the model depends on where the bosons are.

    The lattice is described by a 2D grid, with dimensions
    `x_dimension` x `y_dimension`. It is also possible to specify
    if the grid has periodic boundary conditions or not.

    The Hamiltonian for the Bose-Hubbard model has the form

    .. math::

        H = - t \sum_{\langle i, j \rangle} (b_i^\dagger b_j + b_j^\dagger b_i)
         + V \sum_{\langle i, j \rangle} b_i^\dagger b_i b_j^\dagger b_j
         + \frac{U}{2} \sum_i b_i^\dagger b_i (b_i^\dagger b_i - 1)
         - \mu \sum_i b_i^\dagger b_i.

    where

        - The indices :math:`\langle i, j \rangle` run over pairs
          :math:`i` and :math:`j` of nodes that are connected to each other
          in the grid
        - :math:`t` is the tunneling amplitude
        - :math:`U` is the on-site interaction potential
        - :math:`\mu` is the chemical potential
        - :math:`V` is the dipole or nearest-neighbour interaction 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`.
        interaction (float): The attractive local interaction
            strength :math:`U`.
        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.
        dipole (float): The attractive dipole interaction strength :math:`V`.

    Returns:
        bose_hubbard_model: An instance of the BosonOperator class.
    """

    # Initialize operator.
    n_sites = x_dimension * y_dimension
    hubbard_model = BosonOperator()

    # Loop through sites and add terms.
    for site in range(n_sites):

        # Get indices of right and bottom neighbors
        right_neighbor = _right_neighbor(site, x_dimension, y_dimension,
                                         periodic)
        bottom_neighbor = _bottom_neighbor(site, x_dimension, y_dimension,
                                           periodic)

        # Avoid double-counting edges when one of the dimensions is 2
        # and the system is periodic
        if x_dimension == 2 and periodic and site % 2 == 1:
            right_neighbor = None
        if y_dimension == 2 and periodic and site >= x_dimension:
            bottom_neighbor = None

        # Add terms that couple with neighbors to the right and bottom.
        if right_neighbor is not None:
            # Add hopping term
            hubbard_model += _hopping_term(site,
                                           right_neighbor,
                                           -tunneling,
                                           bosonic=True)
            # Add local Coulomb interaction term
            hubbard_model += _coulomb_interaction_term(
                n_sites,
                site,
                right_neighbor,
                dipole,
                particle_hole_symmetry=False,
                bosonic=True)
        if bottom_neighbor is not None:
            # Add hopping term
            hubbard_model += _hopping_term(site,
                                           bottom_neighbor,
                                           -tunneling,
                                           bosonic=True)
            # Add local Coulomb interaction term
            hubbard_model += _coulomb_interaction_term(
                n_sites,
                site,
                bottom_neighbor,
                dipole,
                particle_hole_symmetry=False,
                bosonic=True)

        # Add on-site interaction.
        hubbard_model += (
            number_operator(n_sites, site, 0.5 * interaction, parity=1) *
            (number_operator(n_sites, site, parity=1) - BosonOperator(())))

        # Add chemical potential.
        hubbard_model += number_operator(n_sites,
                                         site,
                                         -chemical_potential,
                                         parity=1)

    return hubbard_model