tequila-basic 1.9.9__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 +163 -79
  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 +87 -55
  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 +393 -209
  49. tequila/quantumchemistry/encodings.py +121 -13
  50. tequila/quantumchemistry/madness_interface.py +170 -96
  51. tequila/quantumchemistry/orbital_optimizer.py +86 -41
  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 +247 -105
  57. tequila/simulators/simulator_aqt.py +102 -0
  58. tequila/simulators/simulator_base.py +147 -53
  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 +119 -107
  66. tequila/simulators/simulator_qlm.py +52 -26
  67. tequila/simulators/simulator_qulacs.py +74 -52
  68. tequila/simulators/simulator_spex.py +95 -60
  69. tequila/simulators/simulator_symbolic.py +6 -5
  70. tequila/simulators/test_spex_simulator.py +8 -11
  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 +7 -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 +47 -28
  81. {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/METADATA +13 -16
  82. tequila_basic-1.9.10.dist-info/RECORD +93 -0
  83. {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/WHEEL +1 -1
  84. tequila_basic-1.9.9.dist-info/RECORD +0 -88
  85. {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/licenses/LICENSE +0 -0
  86. {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/top_level.txt +0 -0
@@ -18,26 +18,41 @@ The Interface with the PySCF module follows the original PySCF article https://
18
18
  Currently this is a beta version (not extensively used in real life), so be careful when using it and please report issues on github :-)
19
19
  """
20
20
 
21
+
21
22
  @dataclass
22
23
  class OptimizeOrbitalsResult:
23
-
24
- old_molecule: QuantumChemistryBase = None # the old tequila molecule
25
- molecule: QuantumChemistryBase = None # the new tequila molecule with transformed orbitals
26
- mcscf_object:object = None # the pyscf mcscf object
27
- mcscf_local_data:dict = None
28
- mo_coeff = None # the optimized mo coefficients
29
- energy: float = None # the optimized energy
30
- iterations:int = 0
24
+ old_molecule: QuantumChemistryBase = None # the old tequila molecule
25
+ molecule: QuantumChemistryBase = None # the new tequila molecule with transformed orbitals
26
+ mcscf_object: object = None # the pyscf mcscf object
27
+ mcscf_local_data: dict = None
28
+ mo_coeff = None # the optimized mo coefficients
29
+ energy: float = None # the optimized energy
30
+ iterations: int = 0
31
31
 
32
32
  def __call__(self, local_data, *args, **kwargs):
33
33
  # use as callback
34
34
  if "u" in local_data:
35
35
  self.rotation_matrix = copy.deepcopy(local_data["u"])
36
- self.mcscf_local_data=local_data
36
+ self.mcscf_local_data = local_data
37
37
  self.iterations += 1
38
38
 
39
- def optimize_orbitals(molecule, circuit=None, vqe_solver=None, pyscf_arguments=None, silent=False,
40
- vqe_solver_arguments=None, initial_guess=None, return_mcscf=False, use_hcb=False, molecule_factory=None, molecule_arguments=None, restrict_to_active_space=True, *args, **kwargs):
39
+
40
+ def optimize_orbitals(
41
+ molecule,
42
+ circuit=None,
43
+ vqe_solver=None,
44
+ pyscf_arguments=None,
45
+ silent=False,
46
+ vqe_solver_arguments=None,
47
+ initial_guess=None,
48
+ return_mcscf=False,
49
+ use_hcb=False,
50
+ molecule_factory=None,
51
+ molecule_arguments=None,
52
+ restrict_to_active_space=True,
53
+ *args,
54
+ **kwargs,
55
+ ):
41
56
  """
42
57
 
43
58
  Parameters
@@ -85,9 +100,9 @@ def optimize_orbitals(molecule, circuit=None, vqe_solver=None, pyscf_arguments=N
85
100
  pyscf_molecule = molecule
86
101
 
87
102
  mf = pyscf_molecule._get_hf()
88
- result=OptimizeOrbitalsResult()
103
+ result = OptimizeOrbitalsResult()
89
104
  mc = mcscf.CASSCF(mf, pyscf_molecule.n_orbitals, pyscf_molecule.n_electrons)
90
- mc.callback=result
105
+ mc.callback = result
91
106
  c = pyscf_molecule.compute_constant_part()
92
107
 
93
108
  if circuit is None and vqe_solver is None:
@@ -95,20 +110,34 @@ def optimize_orbitals(molecule, circuit=None, vqe_solver=None, pyscf_arguments=N
95
110
 
96
111
  if use_hcb:
97
112
  if vqe_solver_arguments is None:
98
- vqe_solver_arguments={}
99
- vqe_solver_arguments["restrict_to_hcb"]=True
113
+ vqe_solver_arguments = {}
114
+ vqe_solver_arguments["restrict_to_hcb"] = True
100
115
  # consistency check
101
116
  n_qubits = len(circuit.qubits)
102
117
  n_orbitals = molecule.n_orbitals
103
118
  if n_qubits > n_orbitals:
104
- warnings.warn("Potential inconsistency in orbital optimization: use_hcb is switched on but we have\n n_qubits={} in the circuit\n n_orbital={} in the molecule\n".format(n_qubits,n_orbitals), TequilaWarning)
119
+ warnings.warn(
120
+ "Potential inconsistency in orbital optimization: use_hcb is switched on but we have\n n_qubits={} in the circuit\n n_orbital={} in the molecule\n".format(
121
+ n_qubits, n_orbitals
122
+ ),
123
+ TequilaWarning,
124
+ )
105
125
 
106
126
  if molecule_arguments is None:
107
127
  molecule_arguments = {"parameters": pyscf_molecule.parameters, "transformation": molecule.transformation}
108
128
 
109
- wrapper = PySCFVQEWrapper(molecule_arguments=molecule_arguments, n_electrons=pyscf_molecule.n_electrons,
110
- const_part=c, circuit=circuit, vqe_solver_arguments=vqe_solver_arguments, silent=silent,
111
- vqe_solver=vqe_solver, molecule_factory=molecule_factory, *args, **kwargs)
129
+ wrapper = PySCFVQEWrapper(
130
+ molecule_arguments=molecule_arguments,
131
+ n_electrons=pyscf_molecule.n_electrons,
132
+ const_part=c,
133
+ circuit=circuit,
134
+ vqe_solver_arguments=vqe_solver_arguments,
135
+ silent=silent,
136
+ vqe_solver=vqe_solver,
137
+ molecule_factory=molecule_factory,
138
+ *args,
139
+ **kwargs,
140
+ )
112
141
  mc.fcisolver = wrapper
113
142
  mc.internal_rotation = True
114
143
  if pyscf_arguments is not None:
@@ -124,7 +153,7 @@ def optimize_orbitals(molecule, circuit=None, vqe_solver=None, pyscf_arguments=N
124
153
  if initial_guess is not None:
125
154
  if hasattr(initial_guess, "lower"):
126
155
  if "random" or "near_zero" in initial_guess.lower():
127
- scale = 1.e-3
156
+ scale = 1.0e-3
128
157
  if "random" in initial_guess.lower():
129
158
  scale = 1.0
130
159
  loc = 0.0
@@ -147,16 +176,17 @@ def optimize_orbitals(molecule, circuit=None, vqe_solver=None, pyscf_arguments=N
147
176
 
148
177
  mo_coeff = mc.mo_coeff
149
178
  transformed_molecule = pyscf_molecule.transform_orbitals(orbital_coefficients=mo_coeff, name="optimized")
150
- result.molecule=transformed_molecule
151
- result.old_molecule=molecule
152
- result.mo_coeff=mo_coeff
153
- result.energy=mc.e_tot
154
-
179
+ result.molecule = transformed_molecule
180
+ result.old_molecule = molecule
181
+ result.mo_coeff = mo_coeff
182
+ result.energy = mc.e_tot
183
+
155
184
  if return_mcscf:
156
185
  result.mcscf_object = mc
157
-
186
+
158
187
  return result
159
188
 
189
+
160
190
  @dataclass
161
191
  class PySCFVQEWrapper:
162
192
  """
@@ -193,17 +223,28 @@ class PySCFVQEWrapper:
193
223
  if self.history is None:
194
224
  self.history = []
195
225
  h2of = self.reorder(h2, "mulliken", "openfermion")
196
- restrict_to_hcb = self.vqe_solver_arguments is not None and "restrict_to_hcb" in self.vqe_solver_arguments and \
197
- self.vqe_solver_arguments["restrict_to_hcb"]
226
+ restrict_to_hcb = (
227
+ self.vqe_solver_arguments is not None
228
+ and "restrict_to_hcb" in self.vqe_solver_arguments
229
+ and self.vqe_solver_arguments["restrict_to_hcb"]
230
+ )
198
231
 
199
232
  if self.molecule_factory is None:
200
- molecule = QuantumChemistryBase(one_body_integrals=h1, two_body_integrals=h2of,
201
- nuclear_repulsion=self.const_part, n_electrons=self.n_electrons,
202
- **self.molecule_arguments)
233
+ molecule = QuantumChemistryBase(
234
+ one_body_integrals=h1,
235
+ two_body_integrals=h2of,
236
+ nuclear_repulsion=self.const_part,
237
+ n_electrons=self.n_electrons,
238
+ **self.molecule_arguments,
239
+ )
203
240
  else:
204
- molecule = self.molecule_factory(one_body_integrals=h1, two_body_integrals=h2of,
205
- nuclear_repulsion=self.const_part, n_electrons=self.n_electrons,
206
- **self.molecule_arguments)
241
+ molecule = self.molecule_factory(
242
+ one_body_integrals=h1,
243
+ two_body_integrals=h2of,
244
+ nuclear_repulsion=self.const_part,
245
+ n_electrons=self.n_electrons,
246
+ **self.molecule_arguments,
247
+ )
207
248
  if restrict_to_hcb:
208
249
  H = molecule.make_hardcore_boson_hamiltonian()
209
250
  else:
@@ -217,8 +258,10 @@ class PySCFVQEWrapper:
217
258
  vqe_solver_arguments = self.vqe_solver_arguments
218
259
  result = self.vqe_solver(H=H, circuit=self.circuit, molecule=molecule, **vqe_solver_arguments)
219
260
  if hasattr(self.vqe_solver, "compute_rdms"):
220
- rdm1,rdm2 = self.vqe_solver.compute_rdms(U=self.circuit, variables=result.variables, molecule=molecule, use_hcb=restrict_to_hcb)
221
- rdm2 = self.reorder(rdm2, 'dirac', 'mulliken')
261
+ rdm1, rdm2 = self.vqe_solver.compute_rdms(
262
+ U=self.circuit, variables=result.variables, molecule=molecule, use_hcb=restrict_to_hcb
263
+ )
264
+ rdm2 = self.reorder(rdm2, "dirac", "mulliken")
222
265
  elif self.circuit is None:
223
266
  raise Exception("Orbital Optimizer: Either provide a callable vqe_solver or a circuit")
224
267
  else:
@@ -240,8 +283,10 @@ class PySCFVQEWrapper:
240
283
  U = self.circuit
241
284
 
242
285
  if rdm1 is None or rdm2 is None:
243
- rdm1, rdm2 = molecule.compute_rdms(U=U, variables=result.variables, spin_free=True, get_rdm1=True, get_rdm2=True, use_hcb=restrict_to_hcb)
244
- rdm2 = self.reorder(rdm2, 'dirac', 'mulliken')
286
+ rdm1, rdm2 = molecule.compute_rdms(
287
+ U=U, variables=result.variables, spin_free=True, get_rdm1=True, get_rdm2=True, use_hcb=restrict_to_hcb
288
+ )
289
+ rdm2 = self.reorder(rdm2, "dirac", "mulliken")
245
290
  if not self.silent:
246
291
  print("{:20} : {}".format("energy", result.energy))
247
292
  if len(self.history) > 0:
@@ -261,9 +306,9 @@ class PySCFVQEWrapper:
261
306
  result = "{}\n".format(type(self).__name__)
262
307
  for k, v in self.__dict__.items():
263
308
  if k == "circuit" and v is not None:
264
- result += "{:30} : {}\n".format(k, "{} gates, {} parameters".format(len(v.gates),
265
- len(v.extract_variables())))
309
+ result += "{:30} : {}\n".format(
310
+ k, "{} gates, {} parameters".format(len(v.gates), len(v.extract_variables()))
311
+ )
266
312
  else:
267
313
  result += "{:30} : {}\n".format(k, v)
268
314
  return result
269
-
@@ -29,13 +29,13 @@ class OpenVQEEPySCFException(TequilaException):
29
29
  class Psi4Results:
30
30
  variables: dict = None # psi4 variables dictionary, storing all computed values
31
31
  filename: str = None # psi4 output file
32
- wfn: typing.Union[
33
- psi4.core.Wavefunction, psi4.core.CCWavefunction, psi4.core.CIWavefunction] = None # psi4 wavefunction
32
+ wfn: typing.Union[psi4.core.Wavefunction, psi4.core.CCWavefunction, psi4.core.CIWavefunction] = (
33
+ None # psi4 wavefunction
34
+ )
34
35
  mol: psi4.core.Molecule = None
35
36
 
36
37
 
37
38
  class QuantumChemistryPsi4(QuantumChemistryBase):
38
-
39
39
  def _make_psi4_active_space_data(self, active_orbitals, reference=None):
40
40
  """
41
41
  Small helper function
@@ -66,7 +66,6 @@ class QuantumChemistryPsi4(QuantumChemistryBase):
66
66
 
67
67
  @dataclass
68
68
  class ActiveSpaceDataPsi4(ActiveSpaceData):
69
-
70
69
  frozen_docc: list = None # frozen reference orbitals grouped by irrep (psi4 option, if None then the active space can not be represented by psi4)
71
70
  frozen_uocc: list = None # frozen virtual orbtials grouped by irrep (psi4 option, if None then the active space can not be represented by psi4)
72
71
 
@@ -79,8 +78,9 @@ class QuantumChemistryPsi4(QuantumChemistryBase):
79
78
  @property
80
79
  def psi4_representable(self):
81
80
  standard_ref = [self.reference_orbitals[0] == 0] + [
82
- self.reference_orbitals[i] == self.reference_orbitals[i + 1] - 1 for i in
83
- range(len(self.reference_orbitals) - 1)]
81
+ self.reference_orbitals[i] == self.reference_orbitals[i + 1] - 1
82
+ for i in range(len(self.reference_orbitals) - 1)
83
+ ]
84
84
  return self.frozen_docc is not None and self.frozen_uocc is not None and all(standard_ref)
85
85
 
86
86
  # transform irrep notation to absolute ints
@@ -101,7 +101,7 @@ class QuantumChemistryPsi4(QuantumChemistryBase):
101
101
  ref_idx += [x.idx_total for x in orbitals]
102
102
  ref_idx = sorted(ref_idx)
103
103
  elif reference is None:
104
- assert (self.n_electrons % 2 == 0)
104
+ assert self.n_electrons % 2 == 0
105
105
  ref_idx = standard_ref
106
106
 
107
107
  # determine if the active space can be represented by psi4
@@ -131,23 +131,28 @@ class QuantumChemistryPsi4(QuantumChemistryBase):
131
131
  frozen_uocc[i] = len(sorted_array)
132
132
  last = self.orbitals_by_irrep[irrep][-1]
133
133
  if len(sorted_array) > 0 and (
134
- sorted_array[-1] != last.idx_irrep or sorted_array[-1] != sorted_array[0] + len(
135
- sorted_array) - 1):
134
+ sorted_array[-1] != last.idx_irrep or sorted_array[-1] != sorted_array[0] + len(sorted_array) - 1
135
+ ):
136
136
  frozen_uocc = None
137
137
  break
138
138
 
139
- return ActiveSpaceDataPsi4(active_orbitals=sorted(active_idx),
140
- reference_orbitals=sorted(ref_idx),
141
- frozen_docc=frozen_docc,
142
- frozen_uocc=frozen_uocc)
143
-
144
- def __init__(self, parameters: ParametersQC,
145
- transformation: typing.Union[str, typing.Callable] = None,
146
- active_orbitals=None,
147
- reference_orbitals=None,
148
- frozen_orbitals=None,
149
- *args,
150
- **kwargs):
139
+ return ActiveSpaceDataPsi4(
140
+ active_orbitals=sorted(active_idx),
141
+ reference_orbitals=sorted(ref_idx),
142
+ frozen_docc=frozen_docc,
143
+ frozen_uocc=frozen_uocc,
144
+ )
145
+
146
+ def __init__(
147
+ self,
148
+ parameters: ParametersQC,
149
+ transformation: typing.Union[str, typing.Callable] = None,
150
+ active_orbitals=None,
151
+ reference_orbitals=None,
152
+ frozen_orbitals=None,
153
+ *args,
154
+ **kwargs,
155
+ ):
151
156
  """
152
157
 
153
158
  Parameters
@@ -187,9 +192,15 @@ class QuantumChemistryPsi4(QuantumChemistryBase):
187
192
  self.logs = {} # store full psi4 output
188
193
 
189
194
  # psi4 active space will be formed later
190
- super().__init__(parameters=parameters, transformation=transformation, active_orbitals=None,
191
- reference_orbitals=reference_orbitals,frozen_orbitals=[],
192
- *args, **kwargs)
195
+ super().__init__(
196
+ parameters=parameters,
197
+ transformation=transformation,
198
+ active_orbitals=None,
199
+ reference_orbitals=reference_orbitals,
200
+ frozen_orbitals=[],
201
+ *args,
202
+ **kwargs,
203
+ )
193
204
 
194
205
  oenergies = []
195
206
  for i in self.irreps:
@@ -214,7 +225,7 @@ class QuantumChemistryPsi4(QuantumChemistryBase):
214
225
  active_orbitals = [i for i in range(self.n_orbitals)]
215
226
 
216
227
  if frozen_orbitals is None and self.parameters.frozen_core:
217
- frozen_orbitals = [i for i in range(self.parameters.get_number_of_core_electrons()//2)]
228
+ frozen_orbitals = [i for i in range(self.parameters.get_number_of_core_electrons() // 2)]
218
229
 
219
230
  def list_to_irrep_dict(orbital_list):
220
231
  # assume we have been given a list of orbitals with their total indices instead of a dictionary with irreps
@@ -231,21 +242,22 @@ class QuantumChemistryPsi4(QuantumChemistryBase):
231
242
 
232
243
  if not hasattr(active_orbitals, "keys"):
233
244
  active_orbitals = list_to_irrep_dict(active_orbitals)
234
-
245
+
235
246
  if not hasattr(reference_orbitals, "keys"):
236
247
  reference_orbitals = list_to_irrep_dict(reference_orbitals)
237
248
 
238
249
  if not hasattr(frozen_orbitals, "keys"):
239
250
  frozen_orbitals = list_to_irrep_dict(frozen_orbitals)
240
-
251
+
241
252
  # remove frozen-orbitals from active orbitals
242
- for k,v in frozen_orbitals.items():
253
+ for k, v in frozen_orbitals.items():
243
254
  for x in v:
244
255
  if k in active_orbitals and x in active_orbitals[k]:
245
256
  active_orbitals[k].remove(x)
246
257
 
247
- self.integral_manager.active_space = self._make_psi4_active_space_data(active_orbitals=active_orbitals,
248
- reference=reference_orbitals)
258
+ self.integral_manager.active_space = self._make_psi4_active_space_data(
259
+ active_orbitals=active_orbitals, reference=reference_orbitals
260
+ )
249
261
  # need to recompute
250
262
  # (psi4 won't take over active space information otherwise)
251
263
  self.compute_energy(method="hf", recompute=True, *args, **kwargs)
@@ -308,9 +320,13 @@ class QuantumChemistryPsi4(QuantumChemistryBase):
308
320
  ref_wfn = kwargs["ref_wfn"]
309
321
  hf_energy = 0.0
310
322
  else:
311
- hf_energy = self.compute_energy(method="hf", ignore_active_space=True,
312
- options={"RHF__FAIL_ON_MAXITER": False}, point_group=self.point_group)
313
- ref_wfn = self.logs['hf'].wfn
323
+ hf_energy = self.compute_energy(
324
+ method="hf",
325
+ ignore_active_space=True,
326
+ options={"RHF__FAIL_ON_MAXITER": False},
327
+ point_group=self.point_group,
328
+ )
329
+ ref_wfn = self.logs["hf"].wfn
314
330
 
315
331
  if ref_wfn.nirrep() != 1:
316
332
  wfn = ref_wfn.c1_deep_copy(ref_wfn.basisset())
@@ -325,9 +341,9 @@ class QuantumChemistryPsi4(QuantumChemistryBase):
325
341
  S = numpy.asarray(mints.ao_overlap())
326
342
  h = numpy.asarray(wfn.H())
327
343
  g = numpy.asarray(mints.ao_eri())
328
- c = float(wfn.variables()['NUCLEAR REPULSION ENERGY'])
344
+ c = float(wfn.variables()["NUCLEAR REPULSION ENERGY"])
329
345
 
330
- g = NBodyTensor(elems=numpy.asarray(g), ordering='chem')
346
+ g = NBodyTensor(elems=numpy.asarray(g), ordering="chem")
331
347
 
332
348
  kwargs["overlap_integrals"] = S
333
349
  kwargs["two_body_integrals"] = g
@@ -364,16 +380,27 @@ class QuantumChemistryPsi4(QuantumChemistryBase):
364
380
 
365
381
  # set some psi4 specific features
366
382
  self.ref_energy = hf_energy
367
- self.ref_wfn = self.logs['hf'].wfn
383
+ self.ref_wfn = self.logs["hf"].wfn
368
384
  self.irreps = irreps
369
385
 
370
386
  return super().initialize_integral_manager(*args, **kwargs)
371
387
 
372
388
  def compute_ccsd_amplitudes(self):
373
- return self.compute_amplitudes(method='ccsd')
374
-
375
- def _run_psi4(self, options: dict, method=None, return_wfn=True, point_group=None, filename: str = None,
376
- guess_wfn=None, ref_wfn=None, ignore_active_space=False, *args, **kwargs):
389
+ return self.compute_amplitudes(method="ccsd")
390
+
391
+ def _run_psi4(
392
+ self,
393
+ options: dict,
394
+ method=None,
395
+ return_wfn=True,
396
+ point_group=None,
397
+ filename: str = None,
398
+ guess_wfn=None,
399
+ ref_wfn=None,
400
+ ignore_active_space=False,
401
+ *args,
402
+ **kwargs,
403
+ ):
377
404
  psi4.core.clean()
378
405
  psi4.core.clean_variables()
379
406
  psi4.core.clean_options()
@@ -425,11 +452,13 @@ class QuantumChemistryPsi4(QuantumChemistryBase):
425
452
  if ref_wfn is None or method.lower() == "hf":
426
453
  energy, wfn = psi4.energy(name=method.lower(), return_wfn=return_wfn, molecule=mol)
427
454
  else:
428
- energy, wfn = psi4.energy(name=method.lower(), ref_wfn=ref_wfn, return_wfn=return_wfn, molecule=mol,
429
- guess_wfn=guess_wfn)
455
+ energy, wfn = psi4.energy(
456
+ name=method.lower(), ref_wfn=ref_wfn, return_wfn=return_wfn, molecule=mol, guess_wfn=guess_wfn
457
+ )
430
458
  self.energies[method.lower()] = energy
431
- self.logs[method.lower()] = Psi4Results(filename=filename, variables=copy.deepcopy(psi4.core.variables()),
432
- wfn=wfn, mol=mol)
459
+ self.logs[method.lower()] = Psi4Results(
460
+ filename=filename, variables=copy.deepcopy(psi4.core.variables()), wfn=wfn, mol=mol
461
+ )
433
462
  return energy, wfn
434
463
 
435
464
  def _extract_active_space(self, arr):
@@ -438,8 +467,9 @@ class QuantumChemistryPsi4(QuantumChemistryBase):
438
467
  """
439
468
  if self.integral_manager.active_space is None:
440
469
  return arr
441
- elif len(self.integral_manager.active_space.active_orbitals) == self.integral_manager.one_body_integrals.shape[
442
- 0]:
470
+ elif (
471
+ len(self.integral_manager.active_space.active_orbitals) == self.integral_manager.one_body_integrals.shape[0]
472
+ ):
443
473
  return arr
444
474
 
445
475
  if isinstance(arr, ClosedShellAmplitudes):
@@ -487,82 +517,96 @@ class QuantumChemistryPsi4(QuantumChemistryBase):
487
517
  result *= args[i] in active_sets[i]
488
518
  return result
489
519
 
490
- c = numpy.fromfunction(
491
- function=numpy.vectorize(func),
492
- shape=arr_shape, dtype=numpy.int)
520
+ c = numpy.fromfunction(function=numpy.vectorize(func), shape=arr_shape, dtype=numpy.int)
493
521
 
494
522
  return numpy.extract(condition=c, arr=arr).reshape(final_shape)
495
523
 
496
- #def compute_mp2_amplitudes(self, active_orbitals=None, *args, **kwargs) -> ClosedShellAmplitudes:
524
+ # def compute_mp2_amplitudes(self, active_orbitals=None, *args, **kwargs) -> ClosedShellAmplitudes:
497
525
  # return self._extract_active_space(super().compute_mp2_amplitudes(*args, **kwargs))
498
526
 
499
- def compute_amplitudes(self, method: str,
500
- options: dict = None,
501
- filename: str = None,
502
- *args,
503
- **kwargs) -> typing.Union[
504
- Amplitudes, ClosedShellAmplitudes]:
505
-
527
+ def compute_amplitudes(
528
+ self, method: str, options: dict = None, filename: str = None, *args, **kwargs
529
+ ) -> typing.Union[Amplitudes, ClosedShellAmplitudes]:
506
530
  if options is None:
507
531
  options = {}
508
532
 
509
- options['basis'] = self.parameters.basis_set
533
+ options["basis"] = self.parameters.basis_set
510
534
 
511
535
  if method.lower() == "mp2":
512
536
  return self.compute_mp2_amplitudes()
513
537
  try:
514
538
  psi4.core.clean_options()
515
539
  psi4.core.clean_variables()
516
- energy, wfn = self._run_psi4(method=method,
517
- options=options,
518
- point_group='c1',
519
- ref_wfn=self.ref_wfn.c1_deep_copy(self.ref_wfn.basisset()),
520
- filename=filename,
521
- *args,
522
- **kwargs)
540
+ energy, wfn = self._run_psi4(
541
+ method=method,
542
+ options=options,
543
+ point_group="c1",
544
+ ref_wfn=self.ref_wfn.c1_deep_copy(self.ref_wfn.basisset()),
545
+ filename=filename,
546
+ *args,
547
+ **kwargs,
548
+ )
523
549
  all_amplitudes = wfn.get_amplitudes()
524
550
  closed_shell = isinstance(wfn.reference_wavefunction(), psi4.core.RHF)
525
551
  if closed_shell:
526
552
  return self._extract_active_space(
527
- ClosedShellAmplitudes(**{k: v.to_array() for k, v in all_amplitudes.items()}))
553
+ ClosedShellAmplitudes(**{k: v.to_array() for k, v in all_amplitudes.items()})
554
+ )
528
555
  else:
529
- assert (self.integral_manager.trivial_active_space()) # only for closed-shell currently
556
+ assert self.integral_manager.trivial_active_space() # only for closed-shell currently
530
557
  return Amplitudes(**{k: v.to_array() for k, v in all_amplitudes.items()})
531
558
  except Exception as err:
532
- raise TequilaPsi4Exception("\nFailed to compute {} amplitudes.\n" \
533
- "Make sure that you don't read in previous wavefunctions."
534
- "Active spaces might get you in trouble.".format(method))
535
-
536
- def compute_energy(self, method: str = "fci", options=None, recompute: bool = True, ignore_active_space=False,
537
- *args, **kwargs):
538
- if not recompute and method.lower() in self.energies and not "point_group" in kwargs:
559
+ raise TequilaPsi4Exception(
560
+ "\nFailed to compute {} amplitudes.\n"
561
+ "Make sure that you don't read in previous wavefunctions."
562
+ "Active spaces might get you in trouble.".format(method)
563
+ )
564
+
565
+ def compute_energy(
566
+ self, method: str = "fci", options=None, recompute: bool = True, ignore_active_space=False, *args, **kwargs
567
+ ):
568
+ if not recompute and method.lower() in self.energies and "point_group" not in kwargs:
539
569
  return self.energies[method.lower()]
540
570
 
541
571
  if options is None:
542
572
  options = {}
543
573
 
544
- options['basis'] = self.parameters.basis_set
545
- if not ignore_active_space and not self.integral_manager.active_space_is_trivial() and self.active_space.psi4_representable:
546
- options['frozen_docc'] = self.active_space.frozen_docc
574
+ options["basis"] = self.parameters.basis_set
575
+ if (
576
+ not ignore_active_space
577
+ and not self.integral_manager.active_space_is_trivial()
578
+ and self.active_space.psi4_representable
579
+ ):
580
+ options["frozen_docc"] = self.active_space.frozen_docc
547
581
  if sum(self.active_space.frozen_uocc) > 0 and method.lower() not in ["hf", "fci", "detci"]:
548
582
  print(
549
583
  "There are known issues with some psi4 methods and frozen virtual orbitals. Proceed with fingers crossed for {}.".format(
550
- method))
551
- options['frozen_uocc'] = self.active_space.frozen_uocc
552
- if not ignore_active_space and not self.active_space.psi4_representable and not self.integral_manager.active_space_is_trivial():
584
+ method
585
+ )
586
+ )
587
+ options["frozen_uocc"] = self.active_space.frozen_uocc
588
+ if (
589
+ not ignore_active_space
590
+ and not self.active_space.psi4_representable
591
+ and not self.integral_manager.active_space_is_trivial()
592
+ ):
553
593
  warnings.warn("Warning: Active space is not Psi4 representable", TequilaWarning)
554
594
  return self._run_psi4(method=method, options=options, ignore_active_space=ignore_active_space, *args, **kwargs)[
555
- 0]
595
+ 0
596
+ ]
556
597
 
557
598
  def __str__(self):
558
599
  result = super().__str__()
559
600
  result += "\nPsi4 Data\n"
560
- result += "{key:15} : {value:15} \n".format(key="Point Group (full)",
561
- value=self.psi4_mol.get_full_point_group().lower())
601
+ result += "{key:15} : {value:15} \n".format(
602
+ key="Point Group (full)", value=self.psi4_mol.get_full_point_group().lower()
603
+ )
562
604
  result += "{key:15} : {value:15} \n".format(key="Point Group (used)", value=self.point_group)
563
605
  result += "{key:15} : {value} \n".format(key="nirrep", value=self.nirrep)
564
606
  result += "{key:15} : {value} \n".format(key="irreps", value=self.irreps)
565
- result += "{key:15} : {value:15} \n".format(key="mos per irrep", value=str([len(self.orbital_energies(irrep=i)) for i in range(self.nirrep)]))
607
+ result += "{key:15} : {value:15} \n".format(
608
+ key="mos per irrep", value=str([len(self.orbital_energies(irrep=i)) for i in range(self.nirrep)])
609
+ )
566
610
 
567
611
  return result
568
612
 
@@ -574,9 +618,18 @@ class QuantumChemistryPsi4(QuantumChemistryBase):
574
618
  def rdm2(self) -> tuple:
575
619
  return super().rdm2
576
620
 
577
- def compute_rdms(self, U: QCircuit = None, variables: Variables = None, spin_free: bool = True,
578
- get_rdm1: bool = True, get_rdm2: bool = True, psi4_method: str = None,
579
- psi4_options: dict = {}, *args, **kwargs):
621
+ def compute_rdms(
622
+ self,
623
+ U: QCircuit = None,
624
+ variables: Variables = None,
625
+ spin_free: bool = True,
626
+ get_rdm1: bool = True,
627
+ get_rdm2: bool = True,
628
+ psi4_method: str = None,
629
+ psi4_options: dict = {},
630
+ *args,
631
+ **kwargs,
632
+ ):
580
633
  """
581
634
  Same functionality as qc_base.compute_rdms (look there for more information),
582
635
  plus the additional option to compute 1- and 2-RDM using psi4 by the keyword psi4_rdms
@@ -605,8 +658,9 @@ class QuantumChemistryPsi4(QuantumChemistryBase):
605
658
  -------
606
659
  """
607
660
  if not psi4_method:
608
- return super().compute_rdms(U=U, variables=variables, spin_free=spin_free,
609
- get_rdm1=get_rdm1, get_rdm2=get_rdm2, *args, **kwargs)
661
+ return super().compute_rdms(
662
+ U=U, variables=variables, spin_free=spin_free, get_rdm1=get_rdm1, get_rdm2=get_rdm2, *args, **kwargs
663
+ )
610
664
  else:
611
665
  # Get 1- and 2-particle reduced density matrix via Psi4 CISD computation
612
666
  # If "cisd" is chosen, change to "detci" (default is excitation level 2 anyhow) to obtain a CIWavefunction
@@ -631,14 +685,21 @@ class QuantumChemistryPsi4(QuantumChemistryBase):
631
685
  self._rdm1 = rdm1
632
686
  if psi4_options["detci__tpdm"]:
633
687
  rdm2 = psi4.driver.p4util.numpy_helper._to_array(wfn.get_tpdm("SUM", False), dense=True)
634
- rdm2 = NBodyTensor(elems=rdm2, ordering='chem')
635
- rdm2.reorder(to='phys') # RDMs in physics ordering (cp. to NBodyTensor in qc_base.py)
688
+ rdm2 = NBodyTensor(elems=rdm2, ordering="chem")
689
+ rdm2.reorder(to="phys") # RDMs in physics ordering (cp. to NBodyTensor in qc_base.py)
636
690
  rdm2 = 2 * rdm2.elems # Factor 2 since psi4 normalizes 2-rdm by 1/2
637
691
  self._rdm2 = rdm2
638
692
 
639
- def perturbative_f12_correction(self, rdm1: numpy.ndarray = None, rdm2: numpy.ndarray = None, gamma: float = 1.4,
640
- n_ri: int = None, cabs_type: str = "active", cabs_options: dict = None,
641
- **kwargs) -> float:
693
+ def perturbative_f12_correction(
694
+ self,
695
+ rdm1: numpy.ndarray = None,
696
+ rdm2: numpy.ndarray = None,
697
+ gamma: float = 1.4,
698
+ n_ri: int = None,
699
+ cabs_type: str = "active",
700
+ cabs_options: dict = None,
701
+ **kwargs,
702
+ ) -> float:
642
703
  """
643
704
  Computes the spin-free [2]_R12 correction, needing only the 1- and 2-RDM of a reference method
644
705
  Requires either 1-RDM, 2-RDM or information to compute them in kwargs
@@ -673,8 +734,16 @@ class QuantumChemistryPsi4(QuantumChemistryBase):
673
734
  the f12 correction for the energy
674
735
  """
675
736
  from .f12_corrections._f12_correction_psi4 import ExplicitCorrelationCorrectionPsi4
676
- correction = ExplicitCorrelationCorrectionPsi4(mol=self, rdm1=rdm1, rdm2=rdm2, gamma=gamma,
677
- n_ri=n_ri, cabs_type=cabs_type, cabs_options=cabs_options,
678
- **kwargs)
737
+
738
+ correction = ExplicitCorrelationCorrectionPsi4(
739
+ mol=self,
740
+ rdm1=rdm1,
741
+ rdm2=rdm2,
742
+ gamma=gamma,
743
+ n_ri=n_ri,
744
+ cabs_type=cabs_type,
745
+ cabs_options=cabs_options,
746
+ **kwargs,
747
+ )
679
748
 
680
749
  return correction.compute()