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.
- tequila/__init__.py +29 -14
- tequila/apps/__init__.py +14 -5
- tequila/apps/_unary_state_prep_impl.py +145 -112
- tequila/apps/adapt/__init__.py +9 -1
- tequila/apps/adapt/adapt.py +154 -113
- tequila/apps/krylov/__init__.py +1 -1
- tequila/apps/krylov/krylov.py +23 -21
- tequila/apps/robustness/helpers.py +10 -6
- tequila/apps/robustness/interval.py +238 -156
- tequila/apps/unary_state_prep.py +29 -23
- tequila/autograd_imports.py +8 -5
- tequila/circuit/__init__.py +2 -1
- tequila/circuit/_gates_impl.py +135 -67
- tequila/circuit/circuit.py +163 -79
- tequila/circuit/compiler.py +114 -105
- tequila/circuit/gates.py +288 -120
- tequila/circuit/gradient.py +35 -23
- tequila/circuit/noise.py +83 -74
- tequila/circuit/postselection.py +120 -0
- tequila/circuit/pyzx.py +10 -6
- tequila/circuit/qasm.py +201 -83
- tequila/circuit/qpic.py +63 -61
- tequila/grouping/binary_rep.py +148 -146
- tequila/grouping/binary_utils.py +84 -75
- tequila/grouping/compile_groups.py +334 -230
- tequila/grouping/ev_utils.py +77 -41
- tequila/grouping/fermionic_functions.py +383 -308
- tequila/grouping/fermionic_methods.py +170 -123
- tequila/grouping/overlapping_methods.py +69 -52
- tequila/hamiltonian/paulis.py +12 -13
- tequila/hamiltonian/paulistring.py +1 -1
- tequila/hamiltonian/qubit_hamiltonian.py +45 -35
- tequila/ml/__init__.py +1 -0
- tequila/ml/interface_torch.py +19 -16
- tequila/ml/ml_api.py +11 -10
- tequila/ml/utils_ml.py +12 -11
- tequila/objective/__init__.py +8 -3
- tequila/objective/braket.py +55 -47
- tequila/objective/objective.py +87 -55
- tequila/objective/qtensor.py +36 -27
- tequila/optimizers/__init__.py +31 -23
- tequila/optimizers/_containers.py +11 -7
- tequila/optimizers/optimizer_base.py +111 -83
- tequila/optimizers/optimizer_gd.py +258 -231
- tequila/optimizers/optimizer_gpyopt.py +56 -42
- tequila/optimizers/optimizer_scipy.py +157 -112
- tequila/quantumchemistry/__init__.py +66 -38
- tequila/quantumchemistry/chemistry_tools.py +393 -209
- tequila/quantumchemistry/encodings.py +121 -13
- tequila/quantumchemistry/madness_interface.py +170 -96
- tequila/quantumchemistry/orbital_optimizer.py +86 -41
- tequila/quantumchemistry/psi4_interface.py +166 -97
- tequila/quantumchemistry/pyscf_interface.py +70 -23
- tequila/quantumchemistry/qc_base.py +866 -414
- tequila/simulators/__init__.py +0 -3
- tequila/simulators/simulator_api.py +247 -105
- tequila/simulators/simulator_aqt.py +102 -0
- tequila/simulators/simulator_base.py +147 -53
- tequila/simulators/simulator_cirq.py +58 -42
- tequila/simulators/simulator_cudaq.py +600 -0
- tequila/simulators/simulator_ddsim.py +390 -0
- tequila/simulators/simulator_mqp.py +30 -0
- tequila/simulators/simulator_pyquil.py +190 -171
- tequila/simulators/simulator_qibo.py +95 -87
- tequila/simulators/simulator_qiskit.py +119 -107
- tequila/simulators/simulator_qlm.py +52 -26
- tequila/simulators/simulator_qulacs.py +74 -52
- tequila/simulators/simulator_spex.py +95 -60
- tequila/simulators/simulator_symbolic.py +6 -5
- tequila/simulators/test_spex_simulator.py +8 -11
- tequila/tools/convenience.py +4 -4
- tequila/tools/qng.py +72 -64
- tequila/tools/random_generators.py +38 -34
- tequila/utils/bitstrings.py +7 -7
- tequila/utils/exceptions.py +19 -5
- tequila/utils/joined_transformation.py +8 -10
- tequila/utils/keymap.py +0 -5
- tequila/utils/misc.py +6 -4
- tequila/version.py +1 -1
- tequila/wavefunction/qubit_wavefunction.py +47 -28
- {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/METADATA +13 -16
- tequila_basic-1.9.10.dist-info/RECORD +93 -0
- {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/WHEEL +1 -1
- tequila_basic-1.9.9.dist-info/RECORD +0 -88
- {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/licenses/LICENSE +0 -0
- {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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
-
|
40
|
-
|
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(
|
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(
|
110
|
-
|
111
|
-
|
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.
|
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 =
|
197
|
-
|
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(
|
201
|
-
|
202
|
-
|
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(
|
205
|
-
|
206
|
-
|
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(
|
221
|
-
|
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(
|
244
|
-
|
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(
|
265
|
-
|
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
|
-
|
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
|
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
|
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
|
-
|
135
|
-
|
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(
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
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__(
|
191
|
-
|
192
|
-
|
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(
|
248
|
-
|
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(
|
312
|
-
|
313
|
-
|
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()[
|
344
|
+
c = float(wfn.variables()["NUCLEAR REPULSION ENERGY"])
|
329
345
|
|
330
|
-
g = NBodyTensor(elems=numpy.asarray(g), ordering=
|
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[
|
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=
|
374
|
-
|
375
|
-
def _run_psi4(
|
376
|
-
|
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(
|
429
|
-
|
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(
|
432
|
-
|
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
|
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(
|
500
|
-
|
501
|
-
|
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[
|
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(
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
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
|
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(
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
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[
|
545
|
-
if
|
546
|
-
|
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
|
-
|
552
|
-
|
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(
|
561
|
-
|
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(
|
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(
|
578
|
-
|
579
|
-
|
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(
|
609
|
-
|
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=
|
635
|
-
rdm2.reorder(to=
|
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(
|
640
|
-
|
641
|
-
|
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
|
-
|
677
|
-
|
678
|
-
|
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()
|