Skip to content

Commit 544b3d9

Browse files
idk3babbush
authored andcommitted
Allow constant in jellium; gitignore profiling files (#119)
* Added code and tests for Madelung constant; profiling files to gitignore * Increase test coverage
1 parent 79d3da0 commit 544b3d9

File tree

5 files changed

+95
-19
lines changed

5 files changed

+95
-19
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,5 @@ ENV/
7070

7171
# mkdocs documentation
7272
/site
73+
74+
*.lprof

src/fermilib/utils/_jellium.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,14 +249,16 @@ def plane_wave_potential(grid, spinless=False):
249249

250250

251251
def dual_basis_jellium_model(grid, spinless=False,
252-
kinetic=True, potential=True):
252+
kinetic=True, potential=True,
253+
include_constant=False):
253254
"""Return jellium Hamiltonian in the dual basis of arXiv:1706.00023
254255
255256
Args:
256257
grid (Grid): The discretization to use.
257258
spinless (bool): Whether to use the spinless model or not.
258259
kinetic (bool): Whether to include kinetic terms.
259260
potential (bool): Whether to include potential terms.
261+
include_constant (bool): Whether to include the Madelung constant.
260262
261263
Returns:
262264
operator (FermionOperator)
@@ -325,6 +327,10 @@ def dual_basis_jellium_model(grid, spinless=False,
325327
operator += FermionOperator(operators,
326328
potential_coefficient)
327329

330+
# Include the Madelung constant if requested.
331+
if include_constant:
332+
operator += FermionOperator.identity() * (2.8372 / grid.scale)
333+
328334
# Return.
329335
return operator
330336

@@ -355,14 +361,16 @@ def dual_basis_potential(grid, spinless=False):
355361
return dual_basis_jellium_model(grid, spinless, False, True)
356362

357363

358-
def jellium_model(grid, spinless=False, plane_wave=True):
364+
def jellium_model(grid, spinless=False, plane_wave=True,
365+
include_constant=False):
359366
"""Return jellium Hamiltonian as FermionOperator class.
360367
361368
Args:
362369
grid (fermilib.utils.Grid): The discretization to use.
363370
spinless (bool): Whether to use the spinless model or not.
364371
plane_wave (bool): Whether to return in momentum space (True)
365372
or position space (False).
373+
include_constant (bool): Whether to include the Madelung constant.
366374
367375
Returns:
368376
FermionOperator: The Hamiltonian of the model.
@@ -372,15 +380,20 @@ def jellium_model(grid, spinless=False, plane_wave=True):
372380
hamiltonian += plane_wave_potential(grid, spinless)
373381
else:
374382
hamiltonian = dual_basis_jellium_model(grid, spinless)
383+
# Include the Madelung constant if requested.
384+
if include_constant:
385+
hamiltonian += FermionOperator.identity() * (2.8372 / grid.scale)
375386
return hamiltonian
376387

377388

378-
def jordan_wigner_dual_basis_jellium(grid, spinless=False):
389+
def jordan_wigner_dual_basis_jellium(grid, spinless=False,
390+
include_constant=False):
379391
"""Return the jellium Hamiltonian as QubitOperator in the dual basis.
380392
381393
Args:
382394
grid (Grid): The discretization to use.
383395
spinless (bool): Whether to use the spinless model or not.
396+
include_constant (bool): Whether to include the Madelung constant.
384397
385398
Returns:
386399
hamiltonian (QubitOperator)
@@ -471,5 +484,9 @@ def jordan_wigner_dual_basis_jellium(grid, spinless=False):
471484
hamiltonian += QubitOperator(xzx_operators, term_coefficient)
472485
hamiltonian += QubitOperator(yzy_operators, term_coefficient)
473486

487+
# Include the Madelung constant if requested.
488+
if include_constant:
489+
hamiltonian += QubitOperator((),) * (2.8372 / grid.scale)
490+
474491
# Return Hamiltonian.
475492
return hamiltonian

src/fermilib/utils/_jellium_test.py

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616

1717
import numpy
1818

19+
from fermilib.ops import FermionOperator
1920
from fermilib.transforms import jordan_wigner
2021
from fermilib.utils import count_qubits, eigenspectrum, Grid
2122
from fermilib.utils._jellium import (
23+
dual_basis_jellium_model,
2224
dual_basis_kinetic,
2325
dual_basis_potential,
2426
jellium_model,
@@ -31,6 +33,8 @@
3133
position_vector,
3234
)
3335

36+
from projectq.ops import QubitOperator
37+
3438

3539
class JelliumTest(unittest.TestCase):
3640

@@ -169,6 +173,31 @@ def test_model_integration(self):
169173
numpy.absolute(momentum_spectrum - position_spectrum))
170174
self.assertAlmostEqual(difference, 0.)
171175

176+
def test_model_integration_with_constant(self):
177+
# Compute Hamiltonian in both momentum and position space.
178+
length_scale = 0.7
179+
180+
grid = Grid(dimensions=2, length=3, scale=length_scale)
181+
spinless = True
182+
183+
# Include the Madelung constant in the momentum but not the position
184+
# Hamiltonian.
185+
momentum_hamiltonian = jellium_model(grid, spinless, True,
186+
include_constant=True)
187+
position_hamiltonian = jellium_model(grid, spinless, False)
188+
189+
# Diagonalize and confirm the same energy.
190+
jw_momentum = jordan_wigner(momentum_hamiltonian)
191+
jw_position = jordan_wigner(position_hamiltonian)
192+
momentum_spectrum = eigenspectrum(jw_momentum)
193+
position_spectrum = eigenspectrum(jw_position)
194+
195+
# Confirm momentum spectrum is shifted 2.8372 / length_scale higher.
196+
max_difference = numpy.amax(momentum_spectrum - position_spectrum)
197+
min_difference = numpy.amax(momentum_spectrum - position_spectrum)
198+
self.assertAlmostEqual(max_difference, 2.8372 / length_scale)
199+
self.assertAlmostEqual(min_difference, 2.8372 / length_scale)
200+
172201
def test_coefficients(self):
173202

174203
# Test that the coefficients post-JW transform are as claimed in paper.
@@ -278,9 +307,11 @@ def test_jordan_wigner_dual_basis_jellium(self):
278307
grid = Grid(dimensions=2, length=3, scale=1.)
279308
spinless = True
280309

281-
# Compute fermionic Hamiltonian.
282-
fermion_hamiltonian = jellium_model(grid, spinless, False)
310+
# Compute fermionic Hamiltonian. Include then subtract constant.
311+
fermion_hamiltonian = dual_basis_jellium_model(
312+
grid, spinless, include_constant=True)
283313
qubit_hamiltonian = jordan_wigner(fermion_hamiltonian)
314+
qubit_hamiltonian -= QubitOperator((), 2.8372)
284315

285316
# Compute Jordan-Wigner Hamiltonian.
286317
test_hamiltonian = jordan_wigner_dual_basis_jellium(grid, spinless)
@@ -296,3 +327,18 @@ def test_jordan_wigner_dual_basis_jellium(self):
296327
num_nonzeros = sum(1 for coeff in qubit_hamiltonian.terms.values() if
297328
coeff != 0.0)
298329
self.assertTrue(num_nonzeros <= paper_n_terms)
330+
331+
def test_jordan_wigner_dual_basis_jellium_constant_shift(self):
332+
length_scale = 0.6
333+
grid = Grid(dimensions=2, length=3, scale=length_scale)
334+
spinless = True
335+
336+
hamiltonian_without_constant = jordan_wigner_dual_basis_jellium(
337+
grid, spinless, include_constant=False)
338+
hamiltonian_with_constant = jordan_wigner_dual_basis_jellium(
339+
grid, spinless, include_constant=True)
340+
341+
difference = hamiltonian_with_constant - hamiltonian_without_constant
342+
expected = FermionOperator.identity() * (2.8372 / length_scale)
343+
344+
self.assertTrue(expected.isclose(difference))

src/fermilib/utils/_plane_wave_hamiltonian.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,8 @@ def plane_wave_external_potential(grid, geometry, spinless):
158158

159159

160160
def plane_wave_hamiltonian(grid, geometry=None,
161-
spinless=False, plane_wave=True):
161+
spinless=False, plane_wave=True,
162+
include_constant=False):
162163
"""Returns Hamiltonian as FermionOperator class.
163164
164165
Args:
@@ -169,11 +170,12 @@ def plane_wave_hamiltonian(grid, geometry=None,
169170
spinless (bool): Whether to use the spinless model or not.
170171
plane_wave (bool): Whether to return in plane wave basis (True)
171172
or plane wave dual basis (False).
173+
include_constant (bool): Whether to include the Madelung constant.
172174
173175
Returns:
174176
FermionOperator: The hamiltonian.
175177
"""
176-
jellium_op = jellium_model(grid, spinless, plane_wave)
178+
jellium_op = jellium_model(grid, spinless, plane_wave, include_constant)
177179

178180
if geometry is None:
179181
return jellium_op
@@ -283,7 +285,8 @@ def _fourier_transform_helper(hamiltonian,
283285
return hamiltonian_t
284286

285287

286-
def jordan_wigner_dual_basis_hamiltonian(grid, geometry=None, spinless=False):
288+
def jordan_wigner_dual_basis_hamiltonian(grid, geometry=None, spinless=False,
289+
include_constant=False):
287290
"""Return the dual basis Hamiltonian as QubitOperator.
288291
289292
Args:
@@ -292,11 +295,13 @@ def jordan_wigner_dual_basis_hamiltonian(grid, geometry=None, spinless=False):
292295
example is [('H', (0, 0, 0)), ('H', (0, 0, 0.7414))].
293296
Distances in atomic units. Use atomic symbols to specify atoms.
294297
spinless (bool): Whether to use the spinless model or not.
298+
include_constant (bool): Whether to include the Madelung constant.
295299
296300
Returns:
297301
hamiltonian (QubitOperator)
298302
"""
299-
jellium_op = jordan_wigner_dual_basis_jellium(grid, spinless)
303+
jellium_op = jordan_wigner_dual_basis_jellium(
304+
grid, spinless, include_constant)
300305

301306
if geometry is None:
302307
return jellium_op

src/fermilib/utils/_plane_wave_hamiltonian_test.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -117,21 +117,27 @@ def test_plane_wave_hamiltonian_integration(self):
117117
length_set = [3, 4]
118118
spinless_set = [True, False]
119119
geometry = [('H', (0,)), ('H', (0.8,))]
120+
length_scale = 1.1
121+
120122
for l in length_set:
121123
for spinless in spinless_set:
122-
grid = Grid(dimensions=1, scale=1.0, length=l)
123-
h_plane_wave = plane_wave_hamiltonian(grid, geometry, spinless,
124-
True)
124+
grid = Grid(dimensions=1, scale=length_scale, length=l)
125+
h_plane_wave = plane_wave_hamiltonian(
126+
grid, geometry, spinless, True, include_constant=True)
125127
h_dual_basis = plane_wave_hamiltonian(grid, geometry, spinless,
126128
False)
127129
jw_h_plane_wave = jordan_wigner(h_plane_wave)
128130
jw_h_dual_basis = jordan_wigner(h_dual_basis)
129131
h_plane_wave_spectrum = eigenspectrum(jw_h_plane_wave)
130132
h_dual_basis_spectrum = eigenspectrum(jw_h_dual_basis)
131133

132-
diff = numpy.amax(numpy.absolute(
133-
h_plane_wave_spectrum - h_dual_basis_spectrum))
134-
self.assertAlmostEqual(diff, 0)
134+
max_diff = numpy.amax(
135+
h_plane_wave_spectrum - h_dual_basis_spectrum)
136+
min_diff = numpy.amin(
137+
h_plane_wave_spectrum - h_dual_basis_spectrum)
138+
139+
self.assertAlmostEqual(max_diff, 2.8372 / length_scale)
140+
self.assertAlmostEqual(min_diff, 2.8372 / length_scale)
135141

136142
def test_plane_wave_hamiltonian_default_to_jellium_with_no_geometry(self):
137143
grid = Grid(dimensions=1, scale=1.0, length=4)
@@ -154,12 +160,12 @@ def test_jordan_wigner_dual_basis_hamiltonian(self):
154160
spinless = True
155161
geometry = [('H', (0, 0)), ('H', (0.5, 0.8))]
156162

157-
fermion_hamiltonian = plane_wave_hamiltonian(grid, geometry, spinless,
158-
False)
163+
fermion_hamiltonian = plane_wave_hamiltonian(
164+
grid, geometry, spinless, False, include_constant=True)
159165
qubit_hamiltonian = jordan_wigner(fermion_hamiltonian)
160166

161-
test_hamiltonian = jordan_wigner_dual_basis_hamiltonian(grid, geometry,
162-
spinless)
167+
test_hamiltonian = jordan_wigner_dual_basis_hamiltonian(
168+
grid, geometry, spinless, include_constant=True)
163169
self.assertTrue(test_hamiltonian.isclose(qubit_hamiltonian))
164170

165171
def test_jordan_wigner_dual_basis_hamiltonian_default_to_jellium(self):

0 commit comments

Comments
 (0)