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)))
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)
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)))
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)))
def sz_operator(n_spatial_orbitals, up_map=up_index, down_map=down_index): """Return the sz operator. .. math:: \\begin{align} S^{z} = \\frac{1}{2}\sum_{i = 1}^{n}(n_{i, \\alpha} - n_{i, \\beta}) \\end{align} Args: n_spatial_orbitals: number of spatial orbitals (n_qubits // 2). up_map: function mapping a spatial index to a spin-orbital index. Default is the canonical spin-up corresponds to even spin-orbitals and spin-down corresponds to odd spin-orbitals down_map: function mapping spatial index to spin-orbital index. Default is canonical spin-up corresponds to even spin-orbitals and spin-down corresponds to odd spin-orbitals. Returns: operator (FermionOperator): corresponding to the sz operator over n_spatial_orbitals. Warnings: Default assumes a number occupation vector representation with even spin-less fermions corresponding to spin-up (alpha) and odd spin-less fermions corresponding to spin-down (beta). """ if not isinstance(n_spatial_orbitals, int): raise TypeError("n_orbitals must be specified as an integer") operator = FermionOperator() n_spinless_orbitals = 2 * n_spatial_orbitals for ni in range(n_spatial_orbitals): operator += number_operator(n_spinless_orbitals, up_map(ni), 0.5) + \ number_operator(n_spinless_orbitals, down_map(ni), -0.5) return operator
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)
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)
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
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
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
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)
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
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