コード例 #1
0
    def test_jordan_wigner_interaction_op_with_zero_term(self):
        test_op = FermionOperator('1^ 2^ 3 4')
        test_op += hermitian_conjugated(test_op)

        interaction_op = get_interaction_operator(test_op)
        interaction_op.constant = 0.0

        retransformed_test_op = reverse_jordan_wigner(
            jordan_wigner(interaction_op))
コード例 #2
0
    def test_jordan_wigner_twobody_interaction_op_allunique(self):
        test_op = FermionOperator('1^ 2^ 3 4')
        test_op += hermitian_conjugated(test_op)

        retransformed_test_op = reverse_jordan_wigner(
            jordan_wigner(get_interaction_operator(test_op)))

        self.assertTrue(
            normal_ordered(retransformed_test_op).isclose(
                normal_ordered(test_op)))
コード例 #3
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)))
コード例 #4
0
def test_qubitop_to_paulisum():
    """
    Conversion of QubitOperator; accuracy test
    """
    hop_term = FermionOperator(((2, 1), (0, 0)))
    term = hop_term + hermitian_conjugated(hop_term)

    pauli_term = jordan_wigner(term)

    forest_term = qubitop_to_pyquilpauli(pauli_term)
    ground_truth = PauliTerm("X", 0) * PauliTerm("Z", 1) * PauliTerm("X", 2)
    ground_truth += PauliTerm("Y", 0) * PauliTerm("Z", 1) * PauliTerm("Y", 2)
    ground_truth *= 0.5

    assert ground_truth == forest_term
コード例 #5
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))
コード例 #6
0
    def test_jordan_wigner_two_body(self):
        # Make sure it agrees with jordan_wigner(FermionTerm).
        for p in range(self.n_qubits):
            for q in range(self.n_qubits):
                for r in range(self.n_qubits):
                    for s in range(self.n_qubits):
                        # Get test qubit operator.
                        test_operator = jordan_wigner_two_body(p, q, r, s)

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

                        self.assertTrue(test_operator.isclose(correct_op),
                                        str(test_operator - correct_op))
コード例 #7
0
def fermi_hubbard(x_dimension,
                  y_dimension,
                  tunneling,
                  coulomb,
                  chemical_potential=None,
                  magnetic_field=None,
                  periodic=True,
                  spinless=False):
    """Return symbolic representation of a Fermi-Hubbard Hamiltonian.

    Args:
        x_dimension: An integer giving the number of sites in width.
        y_dimension: An integer giving the number of sites in height.
        tunneling: A float giving the tunneling amplitude.
        coulomb: A float giving the attractive local interaction strength.
        chemical_potential: An optional float giving the potential of each
            site. Default value is None.
        magnetic_field: An optional float giving a magnetic field at each
            site. Default value is None.
        periodic: If True, add periodic boundary conditions.
        spinless: An optional Boolean. If False, each site has spin up
            orbitals and spin down orbitals. If True, return a spinless
            Fermi-Hubbard model.
        verbose: An optional Boolean. If True, print all second quantized
            terms.

    Returns:
        hubbard_model: An instance of the FermionOperator class.
    """
    # Initialize fermion operator class.
    n_sites = x_dimension * y_dimension
    if spinless:
        n_spin_orbitals = n_sites
    else:
        n_spin_orbitals = 2 * n_sites
    hubbard_model = FermionOperator((), 0.0)

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

        # Add chemical potential and magnetic field terms.
        if chemical_potential and spinless:
            x_index = site % x_dimension
            y_index = (site - 1) // x_dimension
            sign = (-1.)**(x_index + y_index)
            coefficient = sign * chemical_potential
            hubbard_model += number_operator(n_spin_orbitals, site,
                                             coefficient)

        if chemical_potential and not spinless:
            coefficient = -1. * chemical_potential
            hubbard_model += number_operator(n_spin_orbitals, up(site),
                                             coefficient)
            hubbard_model += number_operator(n_spin_orbitals, down(site),
                                             coefficient)

        if magnetic_field and not spinless:
            coefficient = magnetic_field
            hubbard_model += number_operator(n_spin_orbitals, up(site),
                                             -coefficient)
            hubbard_model += number_operator(n_spin_orbitals, down(site),
                                             coefficient)

        # Add local pair interaction terms.
        if not spinless:
            operators = ((up(site), 1), (up(site), 0), (down(site), 1),
                         (down(site), 0))
            hubbard_model += FermionOperator(operators, coulomb)

        # 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):
            if spinless:
                # Add Coulomb term.
                operators = ((site, 1), (site, 0), (right_neighbor, 1),
                             (right_neighbor, 0))
                hubbard_model += FermionOperator(operators, coulomb)

                # Add hopping term.
                operators = ((site, 1), (right_neighbor, 0))
                hopping_term = FermionOperator(operators, -tunneling)
                hubbard_model += hopping_term
                hubbard_model += hermitian_conjugated(hopping_term)
            else:
                # Add hopping term.
                operators = ((up(site), 1), (up(right_neighbor), 0))
                hopping_term = FermionOperator(operators, -tunneling)
                hubbard_model += hopping_term
                hubbard_model += hermitian_conjugated(hopping_term)
                operators = ((down(site), 1), (down(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.
                operators = ((site, 1), (site, 0), (bottom_neighbor, 1),
                             (bottom_neighbor, 0))
                hubbard_model += FermionOperator(operators, coulomb)

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

    # Return.
    return hubbard_model
コード例 #8
0
ファイル: _hubbard.py プロジェクト: techeye220/OpenFermion
def fermi_hubbard(x_dimension, y_dimension, tunneling, coulomb,
                  chemical_potential=None, magnetic_field=None,
                  periodic=True, spinless=False,
                  particle_hole_symmetry=False):
    """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 (a^\dagger_{i, \\uparrow} a_{i, \\uparrow} +
                         a^\dagger_{i, \downarrow} a_{i, \downarrow})
             - 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}
            + h \sum_{k=1}^N (-1)^k a_k^\dagger a_k
            - \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 None.
        magnetic_field (float, optional): The magnetic field :math:`h`
            at each site. Default value is None.
        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.
    """
    # Initialize fermion operator class.
    n_sites = x_dimension * y_dimension
    if spinless:
        n_spin_orbitals = n_sites
    else:
        n_spin_orbitals = 2 * n_sites
    hubbard_model = FermionOperator((), 0.0)
    # select particle-hole symmetry
    if particle_hole_symmetry:
        coulomb_shift = FermionOperator((), 0.5)
    else:
        coulomb_shift = FermionOperator((), 0.0)

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

        # Add chemical potential and magnetic field terms.
        if chemical_potential and spinless:
            coefficient = -1. * chemical_potential
            hubbard_model += number_operator(
                n_spin_orbitals, site, coefficient)

        if magnetic_field and spinless:
            sign = (-1.) ** (site)
            coefficient = sign * magnetic_field
            hubbard_model += number_operator(
                n_spin_orbitals, site, coefficient)

        if chemical_potential and not spinless:
            coefficient = -1. * chemical_potential
            hubbard_model += number_operator(
                n_spin_orbitals, up_index(site), coefficient)
            hubbard_model += number_operator(
                n_spin_orbitals, down_index(site), coefficient)

        if magnetic_field and not spinless:
            coefficient = magnetic_field
            hubbard_model += number_operator(
                n_spin_orbitals, up_index(site), -coefficient)
            hubbard_model += number_operator(
                n_spin_orbitals, down_index(site), coefficient)

        # Add local pair interaction terms.
        if not spinless:
            operator_1 = number_operator(
                n_spin_orbitals, up_index(site), 1.0) - coulomb_shift
            operator_2 = number_operator(
                n_spin_orbitals, down_index(site), 1.0) - 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 (site + 1) % 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))
                hopping_term = FermionOperator(operators, -tunneling)
                hubbard_model += hopping_term
                hubbard_model += hermitian_conjugated(hopping_term)
            else:
                # Add hopping term.
                operators = ((up_index(site), 1),
                             (up_index(right_neighbor), 0))
                hopping_term = FermionOperator(operators, -tunneling)
                hubbard_model += hopping_term
                hubbard_model += hermitian_conjugated(hopping_term)
                operators = ((down_index(site), 1),
                             (down_index(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, 1.0) - coulomb_shift
                operator_2 = number_operator(
                    n_spin_orbitals, bottom_neighbor, 1.0) - coulomb_shift
                hubbard_model += coulomb * operator_1 * operator_2

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

    # Return.
    return hubbard_model
コード例 #9
0
 def setUp(self):
     self.fermion_term = FermionOperator('1^ 2^ 3 4', -3.17)
     self.fermion_operator = self.fermion_term + hermitian_conjugated(
         self.fermion_term)
     self.qubit_operator = jordan_wigner(self.fermion_operator)
コード例 #10
0
from openfermion.ops import FermionOperator, hermitian_conjugated
from openfermion.transforms import jordan_wigner, bravyi_kitaev
from openfermion.utils import eigenspectrum

# Initialize an operator.
fermion_operator = FermionOperator('2^ 0', 3.17)
fermion_operator += hermitian_conjugated(fermion_operator)
print(fermion_operator)

# Transform to qubits under the Jordan-Wigner transformation and print its spectrum.
jw_operator = jordan_wigner(fermion_operator)
jw_spectrum = eigenspectrum(jw_operator)
print(jw_operator)
print(jw_spectrum)

# Transform to qubits under the Bravyi-Kitaev transformation and print its spectrum.
bk_operator = bravyi_kitaev(fermion_operator)
bk_spectrum = eigenspectrum(bk_operator)
print(bk_operator)
print(bk_spectrum)
コード例 #11
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
コード例 #12
0
 def test_jordan_wigner_twobody_interaction_op_reversal_symmetric(self):
     test_op = FermionOperator('1^ 2^ 2 1')
     test_op += hermitian_conjugated(test_op)
     self.assertTrue(
         jordan_wigner(test_op).isclose(
             jordan_wigner(get_interaction_operator(test_op))))
コード例 #13
0
def meanfield_dwave(x_dimension,
                    y_dimension,
                    tunneling,
                    sc_gap,
                    periodic=True,
                    verbose=False):
    """Return symbolic representation of a BCS mean-field d-wave Hamiltonian.

    Args:
        x_dimension: An integer giving the number of sites in width.
        y_dimension: An integer giving the number of sites in height.
        tunneling: A float giving the tunneling amplitude.
        sc_gap: A float giving the magnitude of the superconducting gap.
        periodic: If True, add periodic boundary conditions.
        verbose: An optional Boolean. If True, print all second quantized
            terms.

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

    # Loop through sites and add terms.
    for site in range(n_sites):
        # 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(site), 1.), (up(right_neighbor), 0.))
            hopping_term = FermionOperator(operators, -tunneling)
            meanfield_dwave_model += hopping_term
            meanfield_dwave_model += hermitian_conjugated(hopping_term)
            # Add spin-down hopping term
            operators = ((down(site), 1.), (down(right_neighbor), 0.))
            hopping_term = FermionOperator(operators, -tunneling)
            meanfield_dwave_model += hopping_term
            meanfield_dwave_model += hermitian_conjugated(hopping_term)

            # Add pairing term
            operators = ((up(site), 1.), (down(right_neighbor), 1.))
            pairing_term = FermionOperator(operators, sc_gap / 2.)
            operators = ((down(site), 1.), (up(right_neighbor), 1.))
            pairing_term += FermionOperator(operators, -sc_gap / 2.)
            meanfield_dwave_model -= pairing_term
            meanfield_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(site), 1.), (up(bottom_neighbor), 0.))
            hopping_term = FermionOperator(operators, -tunneling)
            meanfield_dwave_model += hopping_term
            meanfield_dwave_model += hermitian_conjugated(hopping_term)
            # Add spin-down hopping term
            operators = ((down(site), 1.), (down(bottom_neighbor), 0.))
            hopping_term = FermionOperator(operators, -tunneling)
            meanfield_dwave_model += hopping_term
            meanfield_dwave_model += hermitian_conjugated(hopping_term)

            # Add pairing term
            operators = ((up(site), 1.), (down(bottom_neighbor), 1.))
            pairing_term = FermionOperator(operators, -sc_gap / 2.)
            operators = ((down(site), 1.), (up(bottom_neighbor), 1.))
            pairing_term += FermionOperator(operators, sc_gap / 2.)
            meanfield_dwave_model -= pairing_term
            meanfield_dwave_model -= hermitian_conjugated(pairing_term)
    # Return.
    return meanfield_dwave_model
コード例 #14
0
def apply_constraints(operator, n_fermions, use_scipy=True):
    """Function to use linear programming to apply constraints.

    Args:
        operator(FermionOperator): FermionOperator with only 1- and 2-body
            terms that we wish to vectorize.
        n_fermions(int): The number of particles in the simulation.
        use_scipy(bool): Whether to use scipy (True) or cvxopt (False).

    Returns:
        modified_operator(FermionOperator): The operator with reduced norm
            that has been modified with equality constraints.
    """
    # Get constraint matrix.
    n_orbitals = count_qubits(operator)
    constraints = constraint_matrix(n_orbitals, n_fermions)
    n_constraints, n_terms = constraints.get_shape()

    # Get vectorized operator.
    vectorized_operator = operator_to_vector(operator)
    initial_bound = numpy.sum(numpy.absolute(vectorized_operator[1::]))**2
    print('Initial bound on measurements is %f.' % initial_bound)

    # Get linear programming coefficient vector.
    n_variables = n_constraints + n_terms
    lp_vector = numpy.zeros(n_variables, float)
    lp_vector[-n_terms:] = 1.

    # Get linear programming constraint matrix.
    lp_constraint_matrix = scipy.sparse.dok_matrix((2 * n_terms, n_variables))
    for (i, j), value in constraints.items():
        if j:
            lp_constraint_matrix[j, i] = value
            lp_constraint_matrix[n_terms + j, i] = -value
    for i in range(n_terms):
        lp_constraint_matrix[i, n_constraints + i] = -1.
        lp_constraint_matrix[n_terms + i, n_constraints + i] = -1.

    # Get linear programming constraint vector.
    lp_constraint_vector = numpy.zeros(2 * n_terms, float)
    lp_constraint_vector[:n_terms] = vectorized_operator
    lp_constraint_vector[-n_terms:] = -vectorized_operator

    # Perform linear programming.
    print('Starting linear programming.')
    if use_scipy:
        options = {'maxiter': int(1e6)}
        bound = n_constraints * [(None, None)] + n_terms * [(0, None)]
        solution = scipy.optimize.linprog(c=lp_vector,
                                          A_ub=lp_constraint_matrix.toarray(),
                                          b_ub=lp_constraint_vector,
                                          bounds=bound,
                                          options=options)

        # Analyze results.
        print(solution['message'])
        assert solution['success']
        solution_vector = solution['x']
        objective = solution['fun']**2
        print('Program terminated after %i iterations.' % solution['nit'])

    else:
        # Convert to CVXOpt sparse matrix.
        from cvxopt import matrix, solvers, spmatrix
        lp_vector = matrix(lp_vector)
        lp_constraint_matrix = lp_constraint_matrix.tocoo()
        lp_constraint_matrix = spmatrix(lp_constraint_matrix.data,
                                        lp_constraint_matrix.row.tolist(),
                                        lp_constraint_matrix.col.tolist())
        lp_constraint_vector = matrix(lp_constraint_vector)

        # Run linear programming.
        solution = solvers.lp(c=lp_vector,
                              G=lp_constraint_matrix,
                              h=lp_constraint_vector,
                              solver='glpk')

        # Analyze results.
        print(solution['status'])
        solution_vector = numpy.array(solution['x']).transpose()[0]

    # Alternative bound.
    residuals = solution_vector[-n_terms:]
    alternative_bound = numpy.sum(numpy.absolute(residuals[1::]))**2
    print('Bound implied by solution vector is %f.' % alternative_bound)

    # Make sure residuals are positive.
    for residual in residuals:
        assert residual > -1e-6

    # Get bound on updated Hamiltonian.
    weights = solution_vector[:n_constraints]
    final_vectorized_operator = (vectorized_operator -
                                 constraints.transpose() * weights)
    final_bound = numpy.sum(numpy.absolute(final_vectorized_operator[1::]))**2
    print('Actual bound determined is %f.' % final_bound)

    # Return modified operator.
    modified_operator = vector_to_operator(final_vectorized_operator,
                                           n_orbitals)
    return (modified_operator + hermitian_conjugated(modified_operator)) / 2.