Skip to content

Commit d43dcb8

Browse files
Spaceenterbabbush
authored andcommitted
add jordan wigner for _plane_wave_hamiltonian (#61)
1 parent 9a87ba1 commit d43dcb8

File tree

3 files changed

+82
-5
lines changed

3 files changed

+82
-5
lines changed

src/fermilib/utils/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030

3131
from ._plane_wave_hamiltonian import (inverse_fourier_transform,
3232
fourier_transform,
33-
plane_wave_hamiltonian)
33+
plane_wave_hamiltonian,
34+
jordan_wigner_dual_basis_hamiltonian)
3435

3536
from ._sparse_tools import (expectation,
3637
get_density_matrix,

src/fermilib/utils/_plane_wave_hamiltonian.py

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@
1919
from fermilib.ops import FermionOperator
2020
from fermilib.utils._grid import Grid
2121
from fermilib.utils._jellium import (orbital_id, grid_indices, position_vector,
22-
momentum_vector, jellium_model)
22+
momentum_vector, jellium_model,
23+
jordan_wigner_position_jellium)
2324
from fermilib.utils._molecular_data import periodic_hash_table
2425

26+
from projectq.ops import QubitOperator
27+
2528

2629
def dual_basis_u_operator(grid, geometry, spinless):
2730
"""Return the external potential operator in plane wave dual basis.
@@ -118,7 +121,7 @@ def plane_wave_u_operator(grid, geometry, spinless):
118121
return operator
119122

120123

121-
def plane_wave_hamiltonian(grid, geometry,
124+
def plane_wave_hamiltonian(grid, geometry=None,
122125
spinless=False, momentum_space=True):
123126
"""Returns Hamiltonian as FermionOperator class.
124127
@@ -134,14 +137,17 @@ def plane_wave_hamiltonian(grid, geometry,
134137
Returns:
135138
FermionOperator: The hamiltonian.
136139
"""
140+
jellium_op = jellium_model(grid, spinless, momentum_space)
141+
142+
if geometry is None:
143+
return jellium_op
144+
137145
for item in geometry:
138146
if len(item[1]) != grid.dimensions:
139147
raise ValueError("Invalid geometry coordinate.")
140148
if item[0] not in periodic_hash_table:
141149
raise ValueError("Invalid nuclear element.")
142150

143-
jellium_op = jellium_model(grid, spinless, momentum_space)
144-
145151
if momentum_space:
146152
external_potential = plane_wave_u_operator(grid, geometry, spinless)
147153
else:
@@ -244,3 +250,59 @@ def _fourier_transform_helper(hamiltonian, grid, spinless,
244250
hamiltonian_t += transformed_term
245251

246252
return hamiltonian_t
253+
254+
255+
def jordan_wigner_dual_basis_hamiltonian(grid, geometry=None, spinless=False):
256+
"""Return the dual basis Hamiltonian as QubitOperator.
257+
258+
Args:
259+
grid (Grid): The discretization to use.
260+
geometry: A list of tuples giving the coordinates of each atom.
261+
example is [('H', (0, 0, 0)), ('H', (0, 0, 0.7414))].
262+
Distances in atomic units. Use atomic symbols to specify atoms.
263+
spinless (bool): Whether to use the spinless model or not.
264+
265+
Returns:
266+
hamiltonian (QubitOperator)
267+
"""
268+
jellium_op = jordan_wigner_position_jellium(grid, spinless)
269+
270+
if geometry is None:
271+
return jellium_op
272+
273+
for item in geometry:
274+
if len(item[1]) != grid.dimensions:
275+
raise ValueError("Invalid geometry coordinate.")
276+
if item[0] not in periodic_hash_table:
277+
raise ValueError("Invalid nuclear element.")
278+
279+
n_orbitals = grid.num_points()
280+
volume = grid.volume_scale()
281+
if spinless:
282+
n_qubits = n_orbitals
283+
else:
284+
n_qubits = 2 * n_orbitals
285+
prefactor = -2 * numpy.pi / volume
286+
external_potential = QubitOperator()
287+
288+
for k_indices in grid.all_points_indices():
289+
momenta = momentum_vector(k_indices, grid)
290+
momenta_squared = momenta.dot(momenta)
291+
if momenta_squared < EQ_TOLERANCE:
292+
continue
293+
294+
for p in range(n_qubits):
295+
index_p = grid_indices(p, grid, spinless)
296+
coordinate_p = position_vector(index_p, grid)
297+
298+
for nuclear_term in geometry:
299+
coordinate_j = numpy.array(nuclear_term[1], float)
300+
301+
exp_index = 1.0j * momenta.dot(coordinate_j - coordinate_p)
302+
coefficient = (prefactor / momenta_squared *
303+
periodic_hash_table[nuclear_term[0]] *
304+
numpy.exp(exp_index))
305+
external_potential += (QubitOperator((), coefficient) -
306+
QubitOperator(((p, 'Z'),), coefficient))
307+
308+
return jellium_op + external_potential

src/fermilib/utils/_plane_wave_hamiltonian_test.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
inverse_fourier_transform,
2727
plane_wave_u_operator,
2828
dual_basis_u_operator,
29+
jordan_wigner_dual_basis_hamiltonian,
2930
)
3031

3132

@@ -89,6 +90,19 @@ def test_plane_wave_hamiltonian_integration(self):
8990
h_plane_wave_spectrum - h_dual_basis_spectrum))
9091
self.assertAlmostEqual(diff, 0)
9192

93+
def test_jordan_wigner_dual_basis_hamiltonian(self):
94+
grid = Grid(dimensions=2, length=3, scale=1.)
95+
spinless = True
96+
geometry = [('H', (0, 0)), ('H', (0.5, 0.8))]
97+
98+
fermion_hamiltonian = plane_wave_hamiltonian(grid, geometry, spinless,
99+
False)
100+
qubit_hamiltonian = jordan_wigner(fermion_hamiltonian)
101+
102+
test_hamiltonian = jordan_wigner_dual_basis_hamiltonian(grid, geometry,
103+
spinless)
104+
self.assertTrue(test_hamiltonian.isclose(qubit_hamiltonian))
105+
92106

93107
# Run test.
94108
if __name__ == '__main__':

0 commit comments

Comments
 (0)