Skip to content

Commit

Permalink
Added hubbard model with particle-hole symmetry (#68)
Browse files Browse the repository at this point in the history
* Added hubbard model with particle-hole symmetry

* Make PHS Hamiltonian a functionality of the original fermi_hubbard function
  • Loading branch information
Jhonathan Romero Fontalvo authored and babbush committed Oct 20, 2017
1 parent a52d454 commit 27ad557
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 17 deletions.
39 changes: 29 additions & 10 deletions src/openfermion/hamiltonians/_hubbard.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ def down_index(index):

def fermi_hubbard(x_dimension, y_dimension, tunneling, coulomb,
chemical_potential=None, magnetic_field=None,
periodic=True, spinless=False):
periodic=True, spinless=False,
particle_hole_symmetry=False):
"""Return symbolic representation of a Fermi-Hubbard Hamiltonian.
Args:
Expand All @@ -76,6 +77,13 @@ def fermi_hubbard(x_dimension, y_dimension, tunneling, coulomb,
spinless: An optional Boolean. If False, each site has spin up
orbitals and spin down orbitals. If True, return a spinless
Fermi-Hubbard model.
particle_hole_symmetry: an optional Boolean. If False, the repulsion
term corresponds to:
coulomb 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:
coulomb sum_{k=1}^{N-1} (a_k^dagger a_k - 1/2)
(a_{k+1}^dagger a_{k+1} - 1/2)
which is unchanged under a particle-hole transformation.
verbose: An optional Boolean. If True, print all second quantized
terms.
Expand All @@ -89,6 +97,11 @@ def fermi_hubbard(x_dimension, y_dimension, tunneling, coulomb,
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):
Expand Down Expand Up @@ -118,9 +131,11 @@ def fermi_hubbard(x_dimension, y_dimension, tunneling, coulomb,

# Add local pair interaction terms.
if not spinless:
operators = ((up_index(site), 1), (up_index(site), 0),
(down_index(site), 1), (down_index(site), 0))
hubbard_model += FermionOperator(operators, coulomb)
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
Expand All @@ -137,9 +152,11 @@ def fermi_hubbard(x_dimension, y_dimension, tunneling, coulomb,
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)
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))
Expand All @@ -163,9 +180,11 @@ def fermi_hubbard(x_dimension, y_dimension, tunneling, coulomb,
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)
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))
Expand Down
59 changes: 52 additions & 7 deletions src/openfermion/hamiltonians/_hubbard_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ def setUp(self):

def test_two_by_two_spinful(self):

# Initialize the Hamiltonian.
# Initialize the Hamiltonians.
hubbard_model = fermi_hubbard(
self.x_dimension, self.y_dimension, self.tunneling, self.coulomb,
self.chemical_potential, self.magnetic_field,
self.periodic, self.spinless)
self.periodic, self.spinless, False)

# Check up spin on site terms.
self.assertAlmostEqual(hubbard_model.terms[((0, 1), (0, 0))], -.75)
Expand Down Expand Up @@ -84,29 +84,74 @@ def test_two_by_two_spinful(self):
self.assertAlmostEqual(hubbard_model.terms[((6, 1), (6, 0),
(7, 1), (7, 0))], 1.)

def test_two_by_two_spinful_phs(self):
hubbard_model = fermi_hubbard(
self.x_dimension, self.y_dimension, self.tunneling, self.coulomb,
self.chemical_potential, self.magnetic_field,
self.periodic, self.spinless, False)

hubbard_model_phs = fermi_hubbard(
self.x_dimension, self.y_dimension, self.tunneling, self.coulomb,
self.chemical_potential, self.magnetic_field,
self.periodic, self.spinless, True)

# Compute difference between the models with and without
# spin symmetry.
difference = hubbard_model_phs - hubbard_model

# Check constant term in difference.
self.assertAlmostEqual(difference.terms[()], 1.0)

# Check up spin on site terms in difference.
self.assertAlmostEqual(difference.terms[((0, 1), (0, 0))], -.50)
self.assertAlmostEqual(difference.terms[((2, 1), (2, 0))], -.50)
self.assertAlmostEqual(difference.terms[((4, 1), (4, 0))], -.50)
self.assertAlmostEqual(difference.terms[((6, 1), (6, 0))], -.50)

# Check down spin on site terms in difference.
self.assertAlmostEqual(difference.terms[((1, 1), (1, 0))], -.50)
self.assertAlmostEqual(difference.terms[((3, 1), (3, 0))], -.50)
self.assertAlmostEqual(difference.terms[((5, 1), (5, 0))], -.50)
self.assertAlmostEqual(difference.terms[((7, 1), (7, 0))], -.50)

def test_two_by_two_spinful_periodic_rudimentary(self):
hubbard_model = fermi_hubbard(
self.x_dimension, self.y_dimension, self.tunneling, self.coulomb,
self.chemical_potential, self.magnetic_field,
periodic=True, spinless=False)
periodic=True, spinless=False, particle_hole_symmetry=False)

hubbard_model = fermi_hubbard(
self.x_dimension, self.y_dimension, self.tunneling, self.coulomb,
self.chemical_potential, self.magnetic_field,
periodic=True, spinless=False, particle_hole_symmetry=True)

def test_two_by_two_spinful_aperiodic_rudimentary(self):
hubbard_model = fermi_hubbard(
self.x_dimension, self.y_dimension, self.tunneling, self.coulomb,
self.chemical_potential, self.magnetic_field,
periodic=False, spinless=False)
periodic=False, spinless=False, particle_hole_symmetry=False)

hubbard_model = fermi_hubbard(
self.x_dimension, self.y_dimension, self.tunneling, self.coulomb,
self.chemical_potential, self.magnetic_field,
periodic=False, spinless=False, particle_hole_symmetry=True)

def test_two_by_two_spinless_periodic_rudimentary(self):
hubbard_model = fermi_hubbard(
self.x_dimension, self.y_dimension, self.tunneling, self.coulomb,
self.chemical_potential, self.magnetic_field,
periodic=True, spinless=True)
periodic=True, spinless=True, particle_hole_symmetry=False)

hubbard_model = fermi_hubbard(
self.x_dimension, self.y_dimension, self.tunneling, self.coulomb,
self.chemical_potential, self.magnetic_field,
periodic=True, spinless=True, particle_hole_symmetry=True)

def test_two_by_three_spinless_periodic_rudimentary(self):
hubbard_model = fermi_hubbard(
2, 3, self.tunneling, self.coulomb,
self.chemical_potential, self.magnetic_field,
periodic=True, spinless=True)
periodic=True, spinless=True, particle_hole_symmetry=False)
# Check up top/bottom hopping terms.
self.assertAlmostEqual(hubbard_model.terms[((4, 1), (0, 0))],
-self.tunneling)
Expand All @@ -115,7 +160,7 @@ def test_three_by_two_spinless_periodic_rudimentary(self):
hubbard_model = fermi_hubbard(
3, 2, self.tunneling, self.coulomb,
self.chemical_potential, self.magnetic_field,
periodic=True, spinless=True)
periodic=True, spinless=True, particle_hole_symmetry=False)
# Check up top/bottom hopping terms.
self.assertAlmostEqual(hubbard_model.terms[((2, 1), (0, 0))],
-self.tunneling)

0 comments on commit 27ad557

Please sign in to comment.