1919from fermilib .ops import FermionOperator
2020from fermilib .utils ._grid import Grid
2121from 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 )
2324from fermilib .utils ._molecular_data import periodic_hash_table
2425
26+ from projectq .ops import QubitOperator
27+
2528
2629def 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
0 commit comments