tequila-basic 1.9.8__py3-none-any.whl → 1.9.10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. tequila/__init__.py +29 -14
  2. tequila/apps/__init__.py +14 -5
  3. tequila/apps/_unary_state_prep_impl.py +145 -112
  4. tequila/apps/adapt/__init__.py +9 -1
  5. tequila/apps/adapt/adapt.py +154 -113
  6. tequila/apps/krylov/__init__.py +1 -1
  7. tequila/apps/krylov/krylov.py +23 -21
  8. tequila/apps/robustness/helpers.py +10 -6
  9. tequila/apps/robustness/interval.py +238 -156
  10. tequila/apps/unary_state_prep.py +29 -23
  11. tequila/autograd_imports.py +8 -5
  12. tequila/circuit/__init__.py +2 -1
  13. tequila/circuit/_gates_impl.py +135 -67
  14. tequila/circuit/circuit.py +177 -88
  15. tequila/circuit/compiler.py +114 -105
  16. tequila/circuit/gates.py +288 -120
  17. tequila/circuit/gradient.py +35 -23
  18. tequila/circuit/noise.py +83 -74
  19. tequila/circuit/postselection.py +120 -0
  20. tequila/circuit/pyzx.py +10 -6
  21. tequila/circuit/qasm.py +201 -83
  22. tequila/circuit/qpic.py +63 -61
  23. tequila/grouping/binary_rep.py +148 -146
  24. tequila/grouping/binary_utils.py +84 -75
  25. tequila/grouping/compile_groups.py +334 -230
  26. tequila/grouping/ev_utils.py +77 -41
  27. tequila/grouping/fermionic_functions.py +383 -308
  28. tequila/grouping/fermionic_methods.py +170 -123
  29. tequila/grouping/overlapping_methods.py +69 -52
  30. tequila/hamiltonian/paulis.py +12 -13
  31. tequila/hamiltonian/paulistring.py +1 -1
  32. tequila/hamiltonian/qubit_hamiltonian.py +45 -35
  33. tequila/ml/__init__.py +1 -0
  34. tequila/ml/interface_torch.py +19 -16
  35. tequila/ml/ml_api.py +11 -10
  36. tequila/ml/utils_ml.py +12 -11
  37. tequila/objective/__init__.py +8 -3
  38. tequila/objective/braket.py +55 -47
  39. tequila/objective/objective.py +91 -56
  40. tequila/objective/qtensor.py +36 -27
  41. tequila/optimizers/__init__.py +31 -23
  42. tequila/optimizers/_containers.py +11 -7
  43. tequila/optimizers/optimizer_base.py +111 -83
  44. tequila/optimizers/optimizer_gd.py +258 -231
  45. tequila/optimizers/optimizer_gpyopt.py +56 -42
  46. tequila/optimizers/optimizer_scipy.py +157 -112
  47. tequila/quantumchemistry/__init__.py +66 -38
  48. tequila/quantumchemistry/chemistry_tools.py +394 -203
  49. tequila/quantumchemistry/encodings.py +121 -13
  50. tequila/quantumchemistry/madness_interface.py +170 -96
  51. tequila/quantumchemistry/orbital_optimizer.py +86 -40
  52. tequila/quantumchemistry/psi4_interface.py +166 -97
  53. tequila/quantumchemistry/pyscf_interface.py +70 -23
  54. tequila/quantumchemistry/qc_base.py +866 -414
  55. tequila/simulators/__init__.py +0 -3
  56. tequila/simulators/simulator_api.py +258 -106
  57. tequila/simulators/simulator_aqt.py +102 -0
  58. tequila/simulators/simulator_base.py +156 -55
  59. tequila/simulators/simulator_cirq.py +58 -42
  60. tequila/simulators/simulator_cudaq.py +600 -0
  61. tequila/simulators/simulator_ddsim.py +390 -0
  62. tequila/simulators/simulator_mqp.py +30 -0
  63. tequila/simulators/simulator_pyquil.py +190 -171
  64. tequila/simulators/simulator_qibo.py +95 -87
  65. tequila/simulators/simulator_qiskit.py +124 -114
  66. tequila/simulators/simulator_qlm.py +52 -26
  67. tequila/simulators/simulator_qulacs.py +85 -59
  68. tequila/simulators/simulator_spex.py +464 -0
  69. tequila/simulators/simulator_symbolic.py +6 -5
  70. tequila/simulators/test_spex_simulator.py +208 -0
  71. tequila/tools/convenience.py +4 -4
  72. tequila/tools/qng.py +72 -64
  73. tequila/tools/random_generators.py +38 -34
  74. tequila/utils/bitstrings.py +13 -7
  75. tequila/utils/exceptions.py +19 -5
  76. tequila/utils/joined_transformation.py +8 -10
  77. tequila/utils/keymap.py +0 -5
  78. tequila/utils/misc.py +6 -4
  79. tequila/version.py +1 -1
  80. tequila/wavefunction/qubit_wavefunction.py +52 -30
  81. {tequila_basic-1.9.8.dist-info → tequila_basic-1.9.10.dist-info}/METADATA +23 -17
  82. tequila_basic-1.9.10.dist-info/RECORD +93 -0
  83. {tequila_basic-1.9.8.dist-info → tequila_basic-1.9.10.dist-info}/WHEEL +1 -1
  84. tequila_basic-1.9.8.dist-info/RECORD +0 -86
  85. {tequila_basic-1.9.8.dist-info → tequila_basic-1.9.10.dist-info/licenses}/LICENSE +0 -0
  86. {tequila_basic-1.9.8.dist-info → tequila_basic-1.9.10.dist-info}/top_level.txt +0 -0
@@ -5,29 +5,34 @@ from dataclasses import dataclass
5
5
  from copy import deepcopy
6
6
  from numbers import Real
7
7
  import numpy
8
+ from scipy.constants import physical_constants
8
9
 
9
- from tequila import BitString, QCircuit, TequilaException,Variable,compile_circuit
10
+ from tequila import BitString, QCircuit, TequilaException, TequilaWarning, Variable, compile_circuit
10
11
  from tequila.circuit import gates
12
+
11
13
  try:
12
14
  from openfermion.ops.representations import get_active_space_integrals # needs openfermion 1.3
13
15
  except ImportError as E:
14
16
  raise TequilaException("{}\nplease update openfermion to version 1.3 or higher".format(str(E)))
15
17
 
18
+
16
19
  @dataclass
17
20
  class ActiveSpaceData:
18
21
  """
19
22
  Small dataclass to keep the overview in active spaces
20
23
  Class is used internally
21
24
  """
22
- active_orbitals: list = None # active orbitals (spatial, c1)
25
+
26
+ active_orbitals: list = None # active orbitals (spatial, c1)
23
27
  reference_orbitals: list = None # reference orbitals (spatial, c1)
24
28
 
25
29
  def __str__(self):
26
30
  result = "Active Space Data:\n"
27
31
  result += "{key:15} : {value:15} \n".format(key="active_orbitals", value=str(self.active_orbitals))
28
32
  result += "{key:15} : {value:15} \n".format(key="reference_orbitals", value=str(self.reference_orbitals))
29
- result += "{key:15} : {value:15} \n".format(key="active_reference_orbitals",
30
- value=str(self.active_reference_orbitals))
33
+ result += "{key:15} : {value:15} \n".format(
34
+ key="active_reference_orbitals", value=str(self.active_reference_orbitals)
35
+ )
31
36
  return result
32
37
 
33
38
  @property
@@ -50,10 +55,11 @@ class FermionicGateImpl(gates.QubitExcitationImpl):
50
55
  self._name = "FermionicExcitation"
51
56
  self.transformation = transformation
52
57
  self.indices = indices
53
- if not hasattr(indices[0],"__len__"):
54
- self.indices = [(indices[2 * i], indices[2 * i+1]) for i in range(len(indices) // 2)]
58
+ if not hasattr(indices[0], "__len__"):
59
+ self.indices = [(indices[2 * i], indices[2 * i + 1]) for i in range(len(indices) // 2)]
55
60
  self.sign = self.format_excitation_variables(self.indices)
56
61
  self.indices = self.format_excitation_indices(self.indices)
62
+
57
63
  def compile(self, *args, **kwargs):
58
64
  if self.is_convertable_to_qubit_excitation():
59
65
  target = []
@@ -63,9 +69,12 @@ class FermionicGateImpl(gates.QubitExcitationImpl):
63
69
  return gates.QubitExcitation(target=target, angle=self.parameter, control=self.control)
64
70
  else:
65
71
  if self.transformation.lower().strip("_") == "jordanwigner":
66
- return self.fermionic_excitation(angle=self.sign*self.parameter, indices=self.indices, control=self.control,opt=False)
72
+ return self.fermionic_excitation(
73
+ angle=self.sign * self.parameter, indices=self.indices, control=self.control, opt=False
74
+ )
67
75
  else:
68
76
  return gates.Trotterized(generator=self.generator, control=self.control, angle=self.parameter, steps=1)
77
+
69
78
  def format_excitation_indices(self, idx):
70
79
  """
71
80
  Consistent formatting of excitation indices
@@ -78,6 +87,7 @@ class FermionicGateImpl(gates.QubitExcitationImpl):
78
87
  idx = [tuple(sorted(x)) for x in idx]
79
88
  idx = sorted(idx, key=lambda x: x[0])
80
89
  return list(idx)
90
+
81
91
  def format_excitation_variables(self, idx):
82
92
  """
83
93
  Consistent formatting of excitation variable
@@ -88,21 +98,28 @@ class FermionicGateImpl(gates.QubitExcitationImpl):
88
98
  """
89
99
  sig = 1
90
100
  for pair in idx:
91
- if pair[1]>pair[0]:
101
+ if pair[1] > pair[0]:
92
102
  sig *= -1
93
- for pair in range(len(idx)-1):
94
- if idx[pair+1][0]>idx[pair][0]:
103
+ for pair in range(len(idx) - 1):
104
+ if idx[pair + 1][0] > idx[pair][0]:
95
105
  sig *= -1
96
106
  return sig
97
- def cCRy(self, target: int, dcontrol: typing.Union[list, int], control: typing.Union[list, int],
98
- angle: typing.Union[Real, Variable, typing.Hashable], case: int = 1) -> QCircuit:
99
- '''
107
+
108
+ def cCRy(
109
+ self,
110
+ target: int,
111
+ dcontrol: typing.Union[list, int],
112
+ control: typing.Union[list, int],
113
+ angle: typing.Union[Real, Variable, typing.Hashable],
114
+ case: int = 1,
115
+ ) -> QCircuit:
116
+ """
100
117
  Compilation of CRy as on https://doi.org/10.1103/PhysRevA.102.062612
101
118
  If not control passed, Ry returned
102
119
  Parameters
103
120
  ----------
104
121
  case: if 1 employs eq. 12 from the paper, if 0 eq. 13
105
- '''
122
+ """
106
123
  if control is not None and not len(control):
107
124
  control = None
108
125
  if isinstance(dcontrol, int):
@@ -117,26 +134,43 @@ class FermionicGateImpl(gates.QubitExcitationImpl):
117
134
  ctr = deepcopy(dcontrol)
118
135
  ctr.pop(0)
119
136
  if case:
120
- U += self.cCRy(target=target, dcontrol=ctr, angle=angle / 2, case=1, control=control) + gates.H(
121
- aux) + gates.CNOT(target, aux)
122
- U += self.cCRy(target=target, dcontrol=ctr, angle=-angle / 2, case=0, control=control) + gates.CNOT(
123
- target, aux) + gates.H(aux)
137
+ U += (
138
+ self.cCRy(target=target, dcontrol=ctr, angle=angle / 2, case=1, control=control)
139
+ + gates.H(aux)
140
+ + gates.CNOT(target, aux)
141
+ )
142
+ U += (
143
+ self.cCRy(target=target, dcontrol=ctr, angle=-angle / 2, case=0, control=control)
144
+ + gates.CNOT(target, aux)
145
+ + gates.H(aux)
146
+ )
124
147
  else:
125
- U += gates.H(aux) + gates.CNOT(target, aux) + self.cCRy(target=target, dcontrol=ctr, angle=-angle / 2,
126
- case=0, control=control)
127
- U += gates.CNOT(target, aux) + gates.H(aux) + self.cCRy(target=target, dcontrol=ctr, angle=angle / 2,
128
- case=1, control=control)
148
+ U += (
149
+ gates.H(aux)
150
+ + gates.CNOT(target, aux)
151
+ + self.cCRy(target=target, dcontrol=ctr, angle=-angle / 2, case=0, control=control)
152
+ )
153
+ U += (
154
+ gates.CNOT(target, aux)
155
+ + gates.H(aux)
156
+ + self.cCRy(target=target, dcontrol=ctr, angle=angle / 2, case=1, control=control)
157
+ )
129
158
  return U
130
159
 
131
- def fermionic_excitation(self, angle: typing.Union[Real, Variable, typing.Hashable], indices: typing.List,
132
- control: typing.Union[int, typing.List] = None, opt: bool = True) -> QCircuit:
133
- '''
134
- Excitation [(i,j),(k,l)],... compiled following https://doi.org/10.1103/PhysRevA.102.062612
135
- opt: whether to optimized CNOT H CNOT --> Rz Rz CNOT Rz
136
- '''
160
+ def fermionic_excitation(
161
+ self,
162
+ angle: typing.Union[Real, Variable, typing.Hashable],
163
+ indices: typing.List,
164
+ control: typing.Union[int, typing.List] = None,
165
+ opt: bool = True,
166
+ ) -> QCircuit:
167
+ """
168
+ Excitation [(i,j),(k,l)],... compiled following https://doi.org/10.1103/PhysRevA.102.062612
169
+ opt: whether to optimized CNOT H CNOT --> Rz Rz CNOT Rz
170
+ """
137
171
  lto = []
138
172
  lfrom = []
139
- if isinstance(indices,tuple) and not hasattr(indices[0],"__len__"):
173
+ if isinstance(indices, tuple) and not hasattr(indices[0], "__len__"):
140
174
  indices = [(indices[2 * i], indices[2 * i + 1]) for i in range(len(indices) // 2)]
141
175
  for pair in indices:
142
176
  lfrom.append(pair[0])
@@ -165,7 +199,7 @@ class FermionicGateImpl(gates.QubitExcitationImpl):
165
199
  if isinstance(control, int):
166
200
  crt.append(control)
167
201
  else:
168
- crt = crt + control
202
+ crt = crt + [*control]
169
203
  control = []
170
204
  Ur = self.cCRy(target=lto[-1], dcontrol=crt, angle=angle, control=control)
171
205
  Upair2 = Upair.dagger()
@@ -195,12 +229,32 @@ class FermionicGateImpl(gates.QubitExcitationImpl):
195
229
 
196
230
  """
197
231
  return False
198
- if not self.transformation.lower().strip("_") == "jordanwigner": return False
199
- if not len(self.indices) == 2: return False
200
- if not self.indices[0][0] // 2 == self.indices[1][0] // 2: return False
201
- if not self.indices[0][1] // 2 == self.indices[1][1] // 2: return False
232
+ if not self.transformation.lower().strip("_") == "jordanwigner":
233
+ return False
234
+ if not len(self.indices) == 2:
235
+ return False
236
+ if not self.indices[0][0] // 2 == self.indices[1][0] // 2:
237
+ return False
238
+ if not self.indices[0][1] // 2 == self.indices[1][1] // 2:
239
+ return False
202
240
  return True
203
241
 
242
+ def map_qubits(self, qubit_map: dict):
243
+ mapped = deepcopy(self)
244
+ mapped._target = tuple([qubit_map[i] for i in self.target])
245
+ if self.control is not None:
246
+ mapped._control = tuple([qubit_map[i] for i in self.control])
247
+ if hasattr(self, "generator") and self.generator:
248
+ mapped.generator = self.generator.map_qubits(qubit_map=qubit_map)
249
+ if hasattr(self, "generators"):
250
+ mapped.generators = [i.map_qubits(qubit_map=qubit_map) for i in self.generators]
251
+ mapped.finalize()
252
+ if hasattr(self, "generator"):
253
+ mapped.generator = self.generator.map_qubits(qubit_map=qubit_map)
254
+ if hasattr(self, "indices"):
255
+ mapped.indices = [(qubit_map[t[0]], qubit_map[t[1]]) for t in self.indices]
256
+ return mapped
257
+
204
258
 
205
259
  def prepare_product_state(state: BitString) -> QCircuit:
206
260
  """Small convenience function
@@ -228,64 +282,102 @@ def prepare_product_state(state: BitString) -> QCircuit:
228
282
  @dataclass
229
283
  class ParametersQC:
230
284
  """Specialization of ParametersHamiltonian"""
285
+
231
286
  basis_set: str = None # Quantum chemistry basis set
232
- geometry: str = None # geometry of the underlying molecule (units: Angstrom!),
287
+ geometry: str = None # geometry of the underlying molecule,
233
288
  # this can be a filename leading to an .xyz file or the geometry given as a string
289
+ units: str = None # units of the geometry, if nothing is passed it will be set to Angstrom!
234
290
  description: str = ""
235
291
  multiplicity: int = 1
236
292
  charge: int = 0
237
293
  name: str = None
238
294
  frozen_core: bool = True
239
-
295
+
240
296
  def get_number_of_core_electrons(self):
241
297
  result = 0
242
298
  for atom in self.get_atoms():
243
- n=self.get_atom_number(atom)
244
- if n>2:
245
- result += 2
246
- if n>10:
247
- result += 8
248
- if n>18:
249
- result += 18
250
- if n>36:
251
- result += 36
252
- if n>45:
253
- result += 54
254
- if n>86:
255
- result += 86
299
+ n = self.get_atom_number(atom)
300
+ if n > 2:
301
+ result += 2
302
+ if n > 10:
303
+ result += 10 - 2
304
+ if n > 18:
305
+ result += 18 - 10 - 2
306
+ if n > 36:
307
+ result += 36 - 18 - 10 - 2
308
+ if n > 54:
309
+ result += 54 - 36 - 18 - 10 - 2
310
+ if n > 86:
311
+ result += 86 - 54 - 36 - 18 - 10 - 2
256
312
  return result
257
313
 
258
314
  @property
259
- def n_electrons(self, *args, **kwargs):
315
+ def total_n_electrons(self, *args, **kwargs):
260
316
  return self.get_nuc_charge() - self.charge
261
317
 
262
318
  def get_nuc_charge(self):
263
319
  return sum(self.get_atom_number(name=atom) for atom in self.get_atoms())
264
320
 
265
321
  def get_atom_number(self, name):
266
- atom_numbers = {"h": 1, "he": 2, "li": 3, "be": 4, "b": 5, "c": 6, "n": 7, "o": 8, "f": 9, "ne": 10, "na": 11,
267
- "mg": 12, "al": 13, "si": 14, "ph": 15, "s": 16, "cl": 17, "ar": 18}
322
+ atom_numbers = {
323
+ "h": 1,
324
+ "he": 2,
325
+ "li": 3,
326
+ "be": 4,
327
+ "b": 5,
328
+ "c": 6,
329
+ "n": 7,
330
+ "o": 8,
331
+ "f": 9,
332
+ "ne": 10,
333
+ "na": 11,
334
+ "mg": 12,
335
+ "al": 13,
336
+ "si": 14,
337
+ "ph": 15,
338
+ "s": 16,
339
+ "cl": 17,
340
+ "ar": 18,
341
+ }
268
342
  if name.lower() in atom_numbers:
269
343
  return atom_numbers[name.lower()]
270
344
  try:
271
345
  import periodictable as pt
346
+
272
347
  atom = list(name.lower())
273
348
  atom[0] = atom[0].upper()
274
- atom = ''.join(atom)
349
+ atom = "".join(atom)
275
350
  element = pt.elements.symbol(atom)
276
351
  return element.number
277
- except:
352
+ except Exception:
278
353
  raise TequilaException(
279
- "can not assign atomic number to element {}\npip install periodictable will fix it".format(atom))
354
+ "can not assign atomic number to element {}\npip install periodictable will fix it".format(atom)
355
+ )
280
356
 
281
357
  def get_atoms(self):
282
358
  return [x[0] for x in self.get_geometry()]
283
359
 
284
360
  def __post_init__(self, *args, **kwargs):
285
-
286
361
  if self.name is None and self.geometry is None:
287
362
  raise TequilaException(
288
- "no geometry or name given to molecule\nprovide geometry=filename.xyz or geometry=`h 0.0 0.0 0.0\\n...`\nor name=whatever with file whatever.xyz being present")
363
+ "no geometry or name given to molecule\nprovide geometry=filename.xyz or geometry=`h 0.0 0.0 0.0\\n...`\nor name=whatever with file whatever.xyz being present"
364
+ )
365
+ # determine units, default Angstrom
366
+ if self.units is None:
367
+ warnings.warn("Warning: No units passed with geometry, assuming units are angstrom.", TequilaWarning)
368
+ self.units = "angstrom"
369
+ else:
370
+ self.units = self.units.lower()
371
+ if self.units in ["angstrom", "ang", "a", "å"]:
372
+ self.units = "angstrom"
373
+ elif self.units in ["bohr", "atomic units", "au", "a.u."]:
374
+ self.units = "bohr"
375
+ else:
376
+ warnings.warn(
377
+ "Warning: Units passed with geometry not recognized (available units are angstrom or bohr), assuming units are angstrom.",
378
+ TequilaWarning,
379
+ )
380
+ self.units = "angstrom"
289
381
  # auto naming
290
382
  if self.name is None:
291
383
  if ".xyz" in self.geometry:
@@ -315,9 +407,14 @@ class ParametersQC:
315
407
  @property
316
408
  def molecular_data_param(self) -> dict:
317
409
  """:return: Give back all parameters for the MolecularData format from openfermion as dictionary"""
318
- return {'basis': self.basis_set, 'geometry': self.get_geometry(), 'description': self.description,
319
- 'charge': self.charge, 'multiplicity': self.multiplicity, 'filename': self.filename
320
- }
410
+ return {
411
+ "basis": self.basis_set,
412
+ "geometry": self.get_geometry(desired_units="angstrom"),
413
+ "description": self.description,
414
+ "charge": self.charge,
415
+ "multiplicity": self.multiplicity,
416
+ "filename": self.filename,
417
+ }
321
418
 
322
419
  @staticmethod
323
420
  def format_element_name(string):
@@ -335,26 +432,30 @@ class ParametersQC:
335
432
  -------
336
433
 
337
434
  """
338
- assert (len(string) > 0)
339
- assert (isinstance(string, str))
435
+ assert len(string) > 0
436
+ assert isinstance(string, str)
340
437
  fstring = string[0].upper() + string[1:].lower()
341
438
  return fstring
342
439
 
343
440
  @staticmethod
344
- def convert_to_list(geometry):
441
+ def convert_to_list(geometry, initial_units, desired_units):
345
442
  """Convert a molecular structure given as a string into a list suitable for openfermion
346
443
 
347
444
  Parameters
348
445
  ----------
349
446
  geometry :
350
- a string specifying a mol. structure. E.g. geometry="h 0.0 0.0 0.0\n h 0.0 0.0 1.0"
351
-
447
+ a string specifying a mol. structure. E.g. geometry="h 0.0 0.0 0.0\n h 0.0 0.0 1.0",
448
+ initial_units :
449
+ the units of the input geometry
450
+ desired_units :
451
+ the units of the output coordinates
352
452
  Returns
353
453
  -------
354
454
  type
355
- A list with the correct format for openfermion E.g return [ ['h',[0.0,0.0,0.0], [..]]
356
-
455
+ A list with the correct format for openfermion E.g return [ ('h',(0.0,0.0,0.0)), (..)], coordinates are in "desired_units",
456
+ note that openfermion requires coordinates in angstrom
357
457
  """
458
+ c_bohrtoang = physical_constants["Bohr radius"][0] * 10**10
358
459
  result = []
359
460
  # Remove blank lines
360
461
  lines = [l for l in geometry.split("\n") if l]
@@ -367,55 +468,65 @@ class ParametersQC:
367
468
  words += [0.0] * (4 - len(words))
368
469
 
369
470
  try:
370
- tmp = (ParametersQC.format_element_name(words[0]),
371
- (float(words[1]), float(words[2]), float(words[3])))
471
+ if initial_units == desired_units:
472
+ tmp = (
473
+ ParametersQC.format_element_name(words[0]),
474
+ (float(words[1]), float(words[2]), float(words[3])),
475
+ )
476
+ elif initial_units == "angstrom":
477
+ tmp = (
478
+ ParametersQC.format_element_name(words[0]),
479
+ (float(words[1]) / c_bohrtoang, float(words[2]) / c_bohrtoang, float(words[3]) / c_bohrtoang),
480
+ )
481
+ elif initial_units == "bohr":
482
+ tmp = (
483
+ ParametersQC.format_element_name(words[0]),
484
+ (float(words[1]) * c_bohrtoang, float(words[2]) * c_bohrtoang, float(words[3]) * c_bohrtoang),
485
+ )
372
486
  result.append(tmp)
373
487
  except ValueError:
374
488
  print("get_geometry list unknown line:\n ", line, "\n proceed with caution!")
375
489
  return result
376
490
 
377
- def get_geometry_string(self) -> str:
491
+ def get_geometry_string(self, desired_units="angstrom") -> str:
378
492
  """returns the geometry as a string
379
- :return: geometry string
380
-
381
- Parameters
382
- ----------
383
-
384
- Returns
385
- -------
493
+ :return: geometry string, if desired_units is not equal to self.units, the coordinates will be transformed to "desired_units"
386
494
 
387
495
  """
388
- if self.geometry.split('.')[-1] == 'xyz':
389
- geomstring, comment = self.read_xyz_from_file(self.geometry)
390
- if comment is not None:
391
- self.description = comment
392
- return geomstring
393
- else:
394
- return self.geometry
496
+ geom = self.get_geometry(desired_units=desired_units)
497
+ f = ""
498
+ for at in geom:
499
+ f += f"{at[0]} {at[1][0]} {at[1][1]} {at[1][2]}\n"
500
+ return f
395
501
 
396
- def get_geometry(self):
502
+ def get_geometry(self, desired_units="angstrom"):
397
503
  """Returns the geometry
398
504
  If a xyz filename was given the file is read out
399
505
  otherwise it is assumed that the geometry was given as string
400
506
  which is then reformatted as a list usable as input for openfermion
401
507
  :return: geometry as list
402
508
  e.g. [(h,(0.0,0.0,0.35)),(h,(0.0,0.0,-0.35))]
403
- Units: Angstrom!
404
-
405
- Parameters
406
- ----------
407
-
408
- Returns
409
- -------
410
-
509
+ Coordinates are transformed into the "desired_units", note that openfermion requires coordinates in Angstrom!
411
510
  """
412
- if self.geometry.split('.')[-1] == 'xyz':
511
+ desired_units = desired_units.lower()
512
+ if desired_units in ["angstrom", "ang", "a", "å"]:
513
+ desired_units = "angstrom"
514
+ elif desired_units in ["bohr", "atomic units", "au", "a.u."]:
515
+ desired_units = "bohr"
516
+ else:
517
+ warnings.warn(
518
+ "Warning: Desired units not recognized (available units are angstrom or bohr), defaulting to angstrom.",
519
+ TequilaWarning,
520
+ )
521
+ desired_units = "angstrom"
522
+
523
+ if self.geometry.split(".")[-1] == "xyz":
413
524
  geomstring, comment = self.read_xyz_from_file(self.geometry)
414
- if self.description == '':
525
+ if self.description == "":
415
526
  self.description = comment
416
- return self.convert_to_list(geomstring)
527
+ return self.convert_to_list(geomstring, initial_units=self.units, desired_units=desired_units)
417
528
  elif self.geometry is not None:
418
- return self.convert_to_list(self.geometry)
529
+ return self.convert_to_list(self.geometry, initial_units=self.units, desired_units=desired_units)
419
530
  else:
420
531
  raise Exception("Parameters.qc.geometry is None")
421
532
 
@@ -423,37 +534,44 @@ class ParametersQC:
423
534
  def read_xyz_from_file(filename):
424
535
  """Read XYZ filetype for molecular structures
425
536
  https://en.wikipedia.org/wiki/XYZ_file_format
426
- Units: Angstrom!
537
+ Units of the geometry in the file have to be equal to self.units, default for self.units is angstrom.
427
538
 
428
539
  Parameters
429
540
  ----------
430
- filename :
431
- return:
432
-
433
- Returns
434
- -------
541
+ filename of the .xyz file
435
542
 
436
543
  """
437
- with open(filename, 'r') as file:
544
+ with open(filename, "r") as file:
438
545
  content = file.readlines()
439
546
  natoms = int(content[0])
440
- comment = str(content[1]).strip('\n')
441
- coord = ''
547
+ comment = str(content[1]).strip("\n")
548
+ coord = ""
442
549
  for i in range(natoms):
443
550
  coord += content[2 + i]
444
551
  return coord, comment
445
552
 
553
+ def get_xyz(self, desired_units="angstrom") -> str:
554
+ """Returns string for a .xyz file with the coordinates in the "desired_units" """
555
+ geom = self.get_geometry(desired_units=desired_units)
556
+ f = ""
557
+ f += f"{len(geom)}\n"
558
+ f += f"{self.name}\n"
559
+ for at in geom:
560
+ f += f"{at[0]} {at[1][0]} {at[1][1]} {at[1][2]}\n"
561
+ return f
562
+
446
563
 
447
564
  @dataclass
448
565
  class ClosedShellAmplitudes:
449
566
  """
450
- Helper Class for clasical amplitudes
567
+ Helper Class for classical amplitudes
451
568
  used internally
452
569
  """
570
+
453
571
  tIjAb: numpy.ndarray = None
454
572
  tIA: numpy.ndarray = None
455
573
 
456
- def make_parameter_dictionary(self, threshold=1.e-8, screening=True):
574
+ def make_parameter_dictionary(self, threshold=1.0e-8, screening=True):
457
575
  """
458
576
 
459
577
  Parameters
@@ -469,13 +587,16 @@ class ClosedShellAmplitudes:
469
587
  if self.tIjAb is not None:
470
588
  nvirt = self.tIjAb.shape[2]
471
589
  nocc = self.tIjAb.shape[0]
472
- assert (self.tIjAb.shape[1] == nocc and self.tIjAb.shape[3] == nvirt)
590
+ assert self.tIjAb.shape[1] == nocc and self.tIjAb.shape[3] == nvirt
473
591
  for (I, J, A, B), value in numpy.ndenumerate(self.tIjAb):
474
592
  if not numpy.isclose(value, 0.0, atol=threshold) or not screening:
475
593
  variables[(nocc + A, I, nocc + B, J)] = value
476
594
  if self.tIA is not None:
477
595
  nocc = self.tIA.shape[0]
478
- for (I, A), value, in numpy.ndenumerate(self.tIA):
596
+ for (
597
+ (I, A),
598
+ value,
599
+ ) in numpy.ndenumerate(self.tIA):
479
600
  if not numpy.isclose(value, 0.0, atol=threshold) or not screening:
480
601
  variables[(A + nocc, I)] = value
481
602
  return dict(sorted(variables.items(), key=lambda x: numpy.abs(x[1]), reverse=True))
@@ -511,7 +632,7 @@ class Amplitudes:
511
632
  -------
512
633
 
513
634
  """
514
- tijab = cs.tIjAb - numpy.einsum("ijab -> ijba", cs.tIjAb, optimize='greedy')
635
+ tijab = cs.tIjAb - numpy.einsum("ijab -> ijba", cs.tIjAb, optimize="greedy")
515
636
  return cls(tIjAb=cs.tIjAb, tIA=cs.tIA, tiJaB=cs.tIjAb, tia=cs.tIA, tijab=tijab, tIJAB=tijab)
516
637
 
517
638
  tIjAb: numpy.ndarray = None
@@ -521,7 +642,7 @@ class Amplitudes:
521
642
  tIJAB: numpy.ndarray = None
522
643
  tia: numpy.ndarray = None
523
644
 
524
- def make_parameter_dictionary(self, threshold=1.e-8):
645
+ def make_parameter_dictionary(self, threshold=1.0e-8):
525
646
  """
526
647
 
527
648
  Parameters
@@ -539,7 +660,7 @@ class Amplitudes:
539
660
  if self.tIjAb is not None:
540
661
  nvirt = self.tIjAb.shape[2]
541
662
  nocc = self.tIjAb.shape[0]
542
- assert (self.tIjAb.shape[1] == nocc and self.tIjAb.shape[3] == nvirt)
663
+ assert self.tIjAb.shape[1] == nocc and self.tIjAb.shape[3] == nvirt
543
664
 
544
665
  for (I, j, A, b), value in numpy.ndenumerate(self.tIjAb):
545
666
  if not numpy.isclose(value, 0.0, atol=threshold):
@@ -556,11 +677,17 @@ class Amplitudes:
556
677
 
557
678
  if self.tIA is not None:
558
679
  nocc = self.tIjAb.shape[0]
559
- assert (self.tia.shape[0] == nocc)
560
- for (I, A), value, in numpy.ndenumerate(self.tIA):
680
+ assert self.tia.shape[0] == nocc
681
+ for (
682
+ (I, A),
683
+ value,
684
+ ) in numpy.ndenumerate(self.tIA):
561
685
  if not numpy.isclose(value, 0.0, atol=threshold):
562
686
  variables[(2 * (A + nocc), 2 * I)] = value
563
- for (i, a), value, in numpy.ndenumerate(self.tIA):
687
+ for (
688
+ (i, a),
689
+ value,
690
+ ) in numpy.ndenumerate(self.tIA):
564
691
  if not numpy.isclose(value, 0.0, atol=threshold):
565
692
  variables[(2 * (a + nocc) + 1, 2 * i + 1)] = value
566
693
 
@@ -568,7 +695,7 @@ class Amplitudes:
568
695
 
569
696
 
570
697
  class NBodyTensor:
571
- """ Convenience class for handling N-body tensors """
698
+ """Convenience class for handling N-body tensors"""
572
699
 
573
700
  class Ordering:
574
701
  """
@@ -599,7 +726,8 @@ class NBodyTensor:
599
726
  return "of"
600
727
  else:
601
728
  raise TequilaException(
602
- "Unknown two-body tensor scheme {}. Supported are dirac, mulliken, and openfermion".format(scheme))
729
+ "Unknown two-body tensor scheme {}. Supported are dirac, mulliken, and openfermion".format(scheme)
730
+ )
603
731
 
604
732
  def is_phys(self):
605
733
  return self._scheme == "phys"
@@ -616,22 +744,25 @@ class NBodyTensor:
616
744
  def identify_ordering(self, trials=25):
617
745
  if len(self.shape) != 4:
618
746
  return None
619
- chem=False
620
- phys=False
621
- of=False
747
+ chem = False
748
+ phys = False
749
+ of = False
622
750
  if self._verify_ordering_mulliken(trials=trials):
623
- chem=self.Ordering(scheme="mulliken")
751
+ chem = self.Ordering(scheme="mulliken")
624
752
  if self._verify_ordering_dirac(trials=trials):
625
- phys=self.Ordering(scheme="dirac")
753
+ phys = self.Ordering(scheme="dirac")
626
754
  if self._verify_ordering_of(trials=trials):
627
- of=self.Ordering(scheme="openfermion")
628
-
629
- uniqueness = (chem,phys,of)
630
- if not uniqueness.count(False) == 2 and trials<100:
631
- return self.identify_ordering(trials=trials*2)
632
- if chem: return self.Ordering(scheme="chem")
633
- elif phys: return self.Ordering(scheme="phys")
634
- elif of: return self.Ordering(scheme="openfermion")
755
+ of = self.Ordering(scheme="openfermion")
756
+
757
+ uniqueness = (chem, phys, of)
758
+ if not uniqueness.count(False) == 2 and trials < 100:
759
+ return self.identify_ordering(trials=trials * 2)
760
+ if chem:
761
+ return self.Ordering(scheme="chem")
762
+ elif phys:
763
+ return self.Ordering(scheme="phys")
764
+ elif of:
765
+ return self.Ordering(scheme="openfermion")
635
766
  else:
636
767
  raise Exception("NBTensor ordering could not be identified")
637
768
 
@@ -643,10 +774,16 @@ class NBodyTensor:
643
774
  elems = self.elems
644
775
  n = self.shape[0]
645
776
  for _ in range(trials):
646
- idx = numpy.random.randint(0,n,4)
647
- test1 = numpy.isclose(elems[idx[0],idx[1],idx[2],idx[3]],elems[idx[2],idx[1],idx[0],idx[3]], atol=1.e-4)
648
- test2 = numpy.isclose(elems[idx[0],idx[1],idx[2],idx[3]],elems[idx[0],idx[3],idx[2],idx[1]], atol=1.e-4)
649
- test3 = numpy.isclose(elems[idx[0],idx[1],idx[2],idx[3]],elems[idx[2],idx[3],idx[0],idx[1]], atol=1.e-4)
777
+ idx = numpy.random.randint(0, n, 4)
778
+ test1 = numpy.isclose(
779
+ elems[idx[0], idx[1], idx[2], idx[3]], elems[idx[2], idx[1], idx[0], idx[3]], atol=1.0e-4
780
+ )
781
+ test2 = numpy.isclose(
782
+ elems[idx[0], idx[1], idx[2], idx[3]], elems[idx[0], idx[3], idx[2], idx[1]], atol=1.0e-4
783
+ )
784
+ test3 = numpy.isclose(
785
+ elems[idx[0], idx[1], idx[2], idx[3]], elems[idx[2], idx[3], idx[0], idx[1]], atol=1.0e-4
786
+ )
650
787
  if not (test1 and test2 and test3):
651
788
  return False
652
789
 
@@ -659,10 +796,16 @@ class NBodyTensor:
659
796
  elems = self.elems
660
797
  n = self.shape[0]
661
798
  for _ in range(trials):
662
- idx = numpy.random.randint(0,n,4)
663
- test1 = numpy.isclose(elems[idx[0],idx[1],idx[2],idx[3]],elems[idx[1],idx[0],idx[2],idx[3]], atol=1.e-4)
664
- test2 = numpy.isclose(elems[idx[0],idx[1],idx[2],idx[3]],elems[idx[0],idx[1],idx[3],idx[2]], atol=1.e-4)
665
- test3 = numpy.isclose(elems[idx[0],idx[1],idx[2],idx[3]],elems[idx[1],idx[0],idx[3],idx[2]], atol=1.e-4)
799
+ idx = numpy.random.randint(0, n, 4)
800
+ test1 = numpy.isclose(
801
+ elems[idx[0], idx[1], idx[2], idx[3]], elems[idx[1], idx[0], idx[2], idx[3]], atol=1.0e-4
802
+ )
803
+ test2 = numpy.isclose(
804
+ elems[idx[0], idx[1], idx[2], idx[3]], elems[idx[0], idx[1], idx[3], idx[2]], atol=1.0e-4
805
+ )
806
+ test3 = numpy.isclose(
807
+ elems[idx[0], idx[1], idx[2], idx[3]], elems[idx[1], idx[0], idx[3], idx[2]], atol=1.0e-4
808
+ )
666
809
  if not (test1 and test2 and test3):
667
810
  return False
668
811
 
@@ -675,17 +818,29 @@ class NBodyTensor:
675
818
  elems = self.elems
676
819
  n = self.shape[0]
677
820
  for _ in range(trials):
678
- idx = numpy.random.randint(0,n,4)
679
- test1 = numpy.isclose(elems[idx[0],idx[1],idx[2],idx[3]],elems[idx[3],idx[1],idx[2],idx[0]], atol=1.e-4)
680
- test2 = numpy.isclose(elems[idx[0],idx[1],idx[2],idx[3]],elems[idx[0],idx[2],idx[1],idx[3]], atol=1.e-4)
681
- test3 = numpy.isclose(elems[idx[0],idx[1],idx[2],idx[3]],elems[idx[3],idx[2],idx[1],idx[0]], atol=1.e-4)
821
+ idx = numpy.random.randint(0, n, 4)
822
+ test1 = numpy.isclose(
823
+ elems[idx[0], idx[1], idx[2], idx[3]], elems[idx[3], idx[1], idx[2], idx[0]], atol=1.0e-4
824
+ )
825
+ test2 = numpy.isclose(
826
+ elems[idx[0], idx[1], idx[2], idx[3]], elems[idx[0], idx[2], idx[1], idx[3]], atol=1.0e-4
827
+ )
828
+ test3 = numpy.isclose(
829
+ elems[idx[0], idx[1], idx[2], idx[3]], elems[idx[3], idx[2], idx[1], idx[0]], atol=1.0e-4
830
+ )
682
831
  if not (test1 and test2 and test3):
683
832
  return False
684
833
 
685
834
  return True
686
835
 
687
- def __init__(self, elems: numpy.ndarray = None, active_indices: list = None, ordering: str = None,
688
- size_full: int = None, verify=False):
836
+ def __init__(
837
+ self,
838
+ elems: numpy.ndarray = None,
839
+ active_indices: list = None,
840
+ ordering: str = None,
841
+ size_full: int = None,
842
+ verify=False,
843
+ ):
689
844
  """
690
845
  Parameters
691
846
  ----------
@@ -728,10 +883,14 @@ class NBodyTensor:
728
883
  if ordering is None:
729
884
  ordering = self.identify_ordering()
730
885
  elif verify:
731
- try: # some RDMs are really sloppy (depends on backend)
732
- auto_ordering=self.identify_ordering()
886
+ try: # some RDMs are really sloppy (depends on backend)
887
+ auto_ordering = self.identify_ordering()
733
888
  if auto_ordering is not ordering:
734
- warnings.warn("Auto identified ordering of NBTensor does not match given ordering: {} vs {}".format(auto_ordering, ordering))
889
+ warnings.warn(
890
+ "Auto identified ordering of NBTensor does not match given ordering: {} vs {}".format(
891
+ auto_ordering, ordering
892
+ )
893
+ )
735
894
  except Exception as E:
736
895
  warnings.warn("could not verify odering {}".format(ordering))
737
896
  self.ordering = self.Ordering(ordering)
@@ -764,8 +923,10 @@ class NBodyTensor:
764
923
  """
765
924
  # Check if index list has correct size
766
925
  if len(idx_lists) != self.order:
767
- raise Exception("Need to pass an index list for each dimension!" +
768
- " Length of idx_lists needs to match order of tensor.")
926
+ raise Exception(
927
+ "Need to pass an index list for each dimension!"
928
+ + " Length of idx_lists needs to match order of tensor."
929
+ )
769
930
 
770
931
  # Perform slicing via numpy.take
771
932
  out = self.elems
@@ -776,13 +937,12 @@ class NBodyTensor:
776
937
  return out
777
938
 
778
939
  def set_index_lists(self):
779
- """ Set passive and full index lists based on class inputs """
940
+ """Set passive and full index lists based on class inputs"""
780
941
  tmp_size = self._size_full
781
942
  if self._size_full is None:
782
943
  tmp_size = self.elems.shape[0]
783
944
 
784
- self._passive_indices = [i for i in range(tmp_size)
785
- if i not in self.active_indices]
945
+ self._passive_indices = [i for i in range(tmp_size) if i not in self.active_indices]
786
946
  self._full_indices = [i for i in range(tmp_size)]
787
947
 
788
948
  def sub_str(self, name: str) -> numpy.ndarray:
@@ -821,11 +981,11 @@ class NBodyTensor:
821
981
  idx_lists = []
822
982
  # Parse name as string of space indices
823
983
  for char in name:
824
- if char.lower() == 'a':
984
+ if char.lower() == "a":
825
985
  idx_lists.append(self.active_indices)
826
- elif char.lower() == 'p':
986
+ elif char.lower() == "p":
827
987
  idx_lists.append(self._passive_indices)
828
- elif char.lower() == 'f':
988
+ elif char.lower() == "f":
829
989
  if self._size_full is None:
830
990
  idx_lists.append(None)
831
991
  else:
@@ -837,7 +997,7 @@ class NBodyTensor:
837
997
 
838
998
  return out
839
999
 
840
- def reorder(self, to: str = 'of'):
1000
+ def reorder(self, to: str = "of"):
841
1001
  """
842
1002
  Function to reorder tensors according to some convention.
843
1003
 
@@ -864,7 +1024,7 @@ class NBodyTensor:
864
1024
  -------
865
1025
  """
866
1026
  if self.order != 4:
867
- warnings.warn('Reordering currently only implemented for two-body tensors.')
1027
+ warnings.warn("Reordering currently only implemented for two-body tensors.")
868
1028
  return self
869
1029
 
870
1030
  to = self.Ordering(scheme=to)
@@ -873,21 +1033,21 @@ class NBodyTensor:
873
1033
  return self
874
1034
  elif self.ordering.is_chem():
875
1035
  if to.is_of():
876
- self.elems = numpy.einsum("psqr -> pqrs", self.elems, optimize='greedy')
1036
+ self.elems = numpy.einsum("psqr -> pqrs", self.elems, optimize="greedy")
877
1037
  elif to.is_phys():
878
- self.elems = numpy.einsum("prqs -> pqrs", self.elems, optimize='greedy')
1038
+ self.elems = numpy.einsum("prqs -> pqrs", self.elems, optimize="greedy")
879
1039
  elif self.ordering.is_of():
880
1040
  if to.is_chem():
881
- self.elems = numpy.einsum("pqrs -> psqr", self.elems, optimize='greedy')
1041
+ self.elems = numpy.einsum("pqrs -> psqr", self.elems, optimize="greedy")
882
1042
  elif to.is_phys():
883
- self.elems = numpy.einsum("pqrs -> pqsr", self.elems, optimize='greedy')
1043
+ self.elems = numpy.einsum("pqrs -> pqsr", self.elems, optimize="greedy")
884
1044
  elif self.ordering.is_phys():
885
1045
  if to.is_chem():
886
- self.elems = numpy.einsum("pqrs -> prqs", self.elems, optimize='greedy')
1046
+ self.elems = numpy.einsum("pqrs -> prqs", self.elems, optimize="greedy")
887
1047
  elif to.is_of():
888
- self.elems = numpy.einsum("pqsr -> pqrs", self.elems, optimize='greedy')
1048
+ self.elems = numpy.einsum("pqsr -> pqrs", self.elems, optimize="greedy")
889
1049
 
890
- self.ordering=to
1050
+ self.ordering = to
891
1051
  return self
892
1052
 
893
1053
 
@@ -908,7 +1068,14 @@ class OrbitalData:
908
1068
  self.occ = 2.0 # mark as reference
909
1069
 
910
1070
  def __str__(self):
911
- return "{"+"{}".format("".join(["{}:{}, ".format(k,v) for k,v in self.__dict__.items() if v is not None])).rstrip().rstrip(",")+"}"
1071
+ return (
1072
+ "{"
1073
+ + "{}".format("".join(["{}:{}, ".format(k, v) for k, v in self.__dict__.items() if v is not None]))
1074
+ .rstrip()
1075
+ .rstrip(",")
1076
+ + "}"
1077
+ )
1078
+
912
1079
 
913
1080
  class IntegralManager:
914
1081
  """
@@ -916,19 +1083,31 @@ class IntegralManager:
916
1083
  All integrals are held in their original basis, the corresponding mo-coefficients have to be passed down
917
1084
  and are usually held by the QuantumChemistryBaseClass
918
1085
  """
1086
+
919
1087
  _overlap_integrals: numpy.ndarray = None
920
1088
  _one_body_integrals: numpy.ndarray = None
921
1089
  _two_body_integrals: NBodyTensor = None
922
1090
  _constant_term: float = None
923
1091
  _basis_name: str = "unknown"
924
- _orbital_type: str = "unknown" # e.g. "HF", "PNO", "native"
1092
+ _orbital_type: str = "unknown" # e.g. "HF", "PNO", "native"
925
1093
  _orbital_coefficients: numpy.ndarray = None
926
1094
  _active_space: ActiveSpaceData = None
927
1095
  _orbitals: typing.List[OrbitalData] = None
928
1096
 
929
- def __init__(self, one_body_integrals, two_body_integrals,
930
- basis_name="unknown", orbital_type="unknown",
931
- constant_term=0.0, orbital_coefficients=None, active_space=None, overlap_integrals=None, orbitals=None, *args, **kwargs):
1097
+ def __init__(
1098
+ self,
1099
+ one_body_integrals,
1100
+ two_body_integrals,
1101
+ basis_name="unknown",
1102
+ orbital_type="unknown",
1103
+ constant_term=0.0,
1104
+ orbital_coefficients=None,
1105
+ active_space=None,
1106
+ overlap_integrals=None,
1107
+ orbitals=None,
1108
+ *args,
1109
+ **kwargs,
1110
+ ):
932
1111
  self._one_body_integrals = one_body_integrals
933
1112
  self._two_body_integrals = two_body_integrals
934
1113
  self._constant_term = constant_term
@@ -942,7 +1121,9 @@ class IntegralManager:
942
1121
  except Exception as E:
943
1122
  raise TequilaException(
944
1123
  "{}\ntwo_body_integrals given in wrong format. Needs to be a tq.chemistry.NBodyTensor in chem ordering.\n{} with ordering={}".format(
945
- str(E), str(type(two_body_integrals)), str(two_body_integrals.ordering)))
1124
+ str(E), str(type(two_body_integrals)), str(two_body_integrals.ordering)
1125
+ )
1126
+ )
946
1127
 
947
1128
  for i in range(4):
948
1129
  assert self._one_body_integrals.shape[0] == self._two_body_integrals.elems.shape[i]
@@ -963,7 +1144,7 @@ class IntegralManager:
963
1144
 
964
1145
  self._orbitals = orbitals
965
1146
  self.active_space = active_space
966
-
1147
+
967
1148
  def get_orthonormalized_orbital_coefficients(self):
968
1149
  """
969
1150
  Computes orbitals in this basis that are orthonormal (through loewdin orthonormalization)
@@ -998,7 +1179,7 @@ class IntegralManager:
998
1179
  self._active_space = other
999
1180
  for x in self._orbitals:
1000
1181
  x.idx = None
1001
- for ii,i in enumerate(other.active_orbitals):
1182
+ for ii, i in enumerate(other.active_orbitals):
1002
1183
  self._orbitals[i].idx = ii
1003
1184
 
1004
1185
  @property
@@ -1007,7 +1188,9 @@ class IntegralManager:
1007
1188
 
1008
1189
  @property
1009
1190
  def active_reference_orbitals(self):
1010
- return [self._orbitals[i] for i in self.active_space.active_orbitals if i in self.active_space.reference_orbitals]
1191
+ return [
1192
+ self._orbitals[i] for i in self.active_space.active_orbitals if i in self.active_space.reference_orbitals
1193
+ ]
1011
1194
 
1012
1195
  @property
1013
1196
  def overlap_integrals(self):
@@ -1060,23 +1243,26 @@ class IntegralManager:
1060
1243
  def orbital_coefficients(self, other):
1061
1244
  self.verify_orbital_coefficients(orbital_coefficients=other)
1062
1245
  self._orbital_coefficients = other
1063
- for i,x in enumerate(self._orbitals):
1246
+ for i, x in enumerate(self._orbitals):
1064
1247
  y = OrbitalData(idx=x.idx, idx_total=x.idx_total)
1065
1248
  self._orbitals[i] = y
1066
-
1249
+
1067
1250
  def transform_to_native_orbitals(self):
1068
1251
  """
1069
1252
  Transform orbitals to orthonormal functions closest to the native basis
1070
1253
  """
1071
1254
  c = self.get_orthonormalized_orbital_coefficients()
1072
- self.orbital_coefficients=c
1073
- self._orbital_type="orthonormalized-{}-basis".format(self._basis_name)
1255
+ self.orbital_coefficients = c
1256
+ self._orbital_type = "orthonormalized-{}-basis".format(self._basis_name)
1074
1257
 
1075
1258
  def is_unitary(self, U):
1076
- if len(U.shape) != 2: return False
1077
- if U.shape[0] != U.shape[1]: return False
1259
+ if len(U.shape) != 2:
1260
+ return False
1261
+ if U.shape[0] != U.shape[1]:
1262
+ return False
1078
1263
  test = (U.conj().T).dot(U) - numpy.eye(U.shape[0])
1079
- if not numpy.isclose(numpy.linalg.norm(test), 0.0): return False
1264
+ if not numpy.isclose(numpy.linalg.norm(test), 0.0):
1265
+ return False
1080
1266
  return True
1081
1267
 
1082
1268
  def transform_orbitals(self, U, name=None):
@@ -1097,7 +1283,9 @@ class IntegralManager:
1097
1283
  else:
1098
1284
  self._orbital_type = name
1099
1285
 
1100
- def get_integrals(self, orbital_coefficients=None, ordering="openfermion", ignore_active_space=False, *args, **kwargs):
1286
+ def get_integrals(
1287
+ self, orbital_coefficients=None, ordering="openfermion", ignore_active_space=False, *args, **kwargs
1288
+ ):
1101
1289
  """
1102
1290
  Get all molecular integrals in given orbital basis (determined by orbital_coefficients in self or the ones passed here)
1103
1291
  active space is considered if not explicitly ignored
@@ -1118,12 +1306,14 @@ class IntegralManager:
1118
1306
  h = self._get_transformed_one_body_integrals(orbital_coefficients=orbital_coefficients)
1119
1307
  g = self._get_transformed_two_body_integrals(orbital_coefficients=orbital_coefficients, ordering=ordering)
1120
1308
  if not ignore_active_space and self._active_space is not None:
1121
-
1122
1309
  g = g.reorder(to="openfermion").elems
1123
1310
 
1124
- active_integrals = get_active_space_integrals(one_body_integrals=h, two_body_integrals=g,
1125
- occupied_indices=self._active_space.frozen_reference_orbitals,
1126
- active_indices=self._active_space.active_orbitals)
1311
+ active_integrals = get_active_space_integrals(
1312
+ one_body_integrals=h,
1313
+ two_body_integrals=g,
1314
+ occupied_indices=self._active_space.frozen_reference_orbitals,
1315
+ active_indices=self._active_space.active_orbitals,
1316
+ )
1127
1317
 
1128
1318
  c = active_integrals[0] + c
1129
1319
 
@@ -1138,8 +1328,8 @@ class IntegralManager:
1138
1328
  elif verify:
1139
1329
  assert self.verify_orbital_coefficients(orbital_coefficients=orbital_coefficients)
1140
1330
  h = self.one_body_integrals
1141
- h = numpy.einsum("ix, xj -> ij", h, orbital_coefficients, optimize='greedy')
1142
- h = numpy.einsum("xj, xi -> ij", h, orbital_coefficients, optimize='greedy')
1331
+ h = numpy.einsum("ix, xj -> ij", h, orbital_coefficients, optimize="greedy")
1332
+ h = numpy.einsum("xj, xi -> ij", h, orbital_coefficients, optimize="greedy")
1143
1333
 
1144
1334
  return h
1145
1335
 
@@ -1151,16 +1341,16 @@ class IntegralManager:
1151
1341
 
1152
1342
  g = self.two_body_integrals
1153
1343
  g = g.reorder("chem").elems
1154
- g = numpy.einsum("ijkx, xl -> ijkl", g, orbital_coefficients, optimize='greedy')
1155
- g = numpy.einsum("ijxl, xk -> ijkl", g, orbital_coefficients, optimize='greedy')
1156
- g = numpy.einsum("ixkl, xj -> ijkl", g, orbital_coefficients, optimize='greedy')
1157
- g = numpy.einsum("xjkl, xi -> ijkl", g, orbital_coefficients, optimize='greedy')
1158
- g = NBodyTensor(elems=numpy.asarray(g), ordering='chem')
1344
+ g = numpy.einsum("ijkx, xl -> ijkl", g, orbital_coefficients, optimize="greedy")
1345
+ g = numpy.einsum("ijxl, xk -> ijkl", g, orbital_coefficients, optimize="greedy")
1346
+ g = numpy.einsum("ixkl, xj -> ijkl", g, orbital_coefficients, optimize="greedy")
1347
+ g = numpy.einsum("xjkl, xi -> ijkl", g, orbital_coefficients, optimize="greedy")
1348
+ g = NBodyTensor(elems=numpy.asarray(g), ordering="chem")
1159
1349
  g = g.reorder(to=ordering)
1160
1350
 
1161
1351
  return g
1162
1352
 
1163
- def verify_orbital_coefficients(self, orbital_coefficients, tolerance=1.e-5):
1353
+ def verify_orbital_coefficients(self, orbital_coefficients, tolerance=1.0e-5):
1164
1354
  """
1165
1355
  Verify if orbital coefficients are valid (i.e. if they define a orthonormal set of orbitals)
1166
1356
  Parameters
@@ -1174,11 +1364,11 @@ class IntegralManager:
1174
1364
 
1175
1365
  """
1176
1366
  S = self.overlap_integrals
1177
- St = numpy.einsum("ix, xj -> ij", S, orbital_coefficients, optimize='greedy')
1178
- St = numpy.einsum("xj, xi -> ij", St, orbital_coefficients, optimize='greedy')
1367
+ St = numpy.einsum("ix, xj -> ij", S, orbital_coefficients, optimize="greedy")
1368
+ St = numpy.einsum("xj, xi -> ij", St, orbital_coefficients, optimize="greedy")
1179
1369
  return numpy.linalg.norm(St - numpy.eye(S.shape[0])) < tolerance
1180
1370
 
1181
- def basis_is_orthogonal(self, tolerance=1.e-5):
1371
+ def basis_is_orthogonal(self, tolerance=1.0e-5):
1182
1372
  S = self.overlap_integrals
1183
1373
  return numpy.linalg.norm(S - numpy.eye(S.shape[0])) < tolerance
1184
1374
 
@@ -1187,9 +1377,9 @@ class IntegralManager:
1187
1377
 
1188
1378
  def __str__(self):
1189
1379
  result = "\nIntegralManager:\n"
1190
- result+= "ActiveSpace:\n"
1191
- result+= str(self.active_space)
1192
- result+= "Orbitals:\n"
1380
+ result += "ActiveSpace:\n"
1381
+ result += str(self.active_space)
1382
+ result += "Orbitals:\n"
1193
1383
  for x in self.orbitals:
1194
1384
  result += str(x) + "\n"
1195
1385
  return result
@@ -1202,9 +1392,10 @@ class IntegralManager:
1202
1392
  print("{:15} : {}".format("active orbitals", [o.idx_total for o in self.active_orbitals]), *args, **kwargs)
1203
1393
  print("{:15} : {}".format("reference", [x.idx_total for x in self.reference_orbitals]), *args, **kwargs)
1204
1394
 
1205
- if not print_coefficients: return
1395
+ if not print_coefficients:
1396
+ return
1206
1397
 
1207
1398
  print("Current Orbitals", *args, **kwargs)
1208
- for i,x in enumerate(self.orbitals):
1399
+ for i, x in enumerate(self.orbitals):
1209
1400
  print(x, *args, **kwargs)
1210
- print("coefficients: ", self.orbital_coefficients[:,i], *args, **kwargs)
1401
+ print("coefficients: ", self.orbital_coefficients[:, i], *args, **kwargs)