Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
NVIDIA
GitHub Repository: NVIDIA/cuda-q-academic
Path: blob/main/chemistry-simulations/aux_files/krylov/qchem/uccsd_vqe.py
583 views
1
import cudaq
2
from aux_files.krylov.qchem.uccsd import get_uccsd_op, uccsd_circuit
3
from aux_files.krylov.qchem.uccsd import uccsd_circuit_double, uccsd_circuit_single
4
5
import numpy as np
6
from scipy.optimize import minimize
7
8
cudaq.set_target("nvidia", option='fp64')
9
10
11
def uccsd_circuit_vqe(spin_mult,
12
only_singles,
13
only_doubles,
14
qubits_num,
15
electron_count,
16
optimize,
17
theta,
18
hamiltonian,
19
method='BFGS',
20
vqe_tol=1e-3,
21
verbose=False):
22
"""
23
Generate the UCCSD circuit for VQE.
24
25
Parameters:
26
- spin_`mult`: Spin multiplicity of the system.
27
- only_singles: If True, only single excitations are included.
28
- only_doubles: If True, only double excitations are included.
29
- qubits_`num`: Number of qubits in the system.
30
- electron_count: Number of electrons in the system.
31
- theta: Initial parameters for the circuit.
32
- hamiltonian: Hamiltonian of the system.
33
"""
34
35
# Get the UCCSD pool
36
if not only_singles and not only_doubles:
37
word_single, word_double, coef_single, coef_double = get_uccsd_op(
38
electron_count,
39
qubits_num,
40
spin_mult=0,
41
only_singles=False,
42
only_doubles=False)
43
if verbose:
44
print(f"word_single: {word_single}")
45
print(f"word_double: {word_double}")
46
print(f"coef_single: {coef_single}")
47
print(f"coef_double: {coef_double}")
48
49
elif only_singles and not only_doubles:
50
word_single, coef_single = get_uccsd_op(electron_count,
51
qubits_num,
52
spin_mult=0,
53
only_singles=True,
54
only_doubles=False)
55
56
if verbose:
57
print(f"word_single: {word_single}")
58
print(f"coef_single: {coef_single}")
59
60
elif only_doubles and not only_singles:
61
word_double, coef_double = get_uccsd_op(electron_count,
62
qubits_num,
63
spin_mult=0,
64
only_singles=False,
65
only_doubles=True)
66
67
if verbose:
68
print(f"word_double: {word_double}")
69
print(f"coef_double: {coef_double}")
70
else:
71
raise ValueError("Invalid option for only_singles and only_doubles")
72
73
# Get the UCCSD circuit (singles and doubles excitation are included)
74
@cudaq.kernel
75
def uccsd_kernel(qubits_num: int, electron_count: int, theta: list[float],
76
word_single: list[cudaq.pauli_word],
77
word_double: list[cudaq.pauli_word],
78
coef_single: list[float], coef_double: list[float]):
79
"""
80
UCCSD kernel
81
"""
82
# `Prepare the statefrom qchem.uccsd import get_uccsd_op, uccsd_circuit, uccsd_parameter_size`
83
84
qubits = cudaq.qvector(qubits_num)
85
86
# Initialize the qubits
87
for i in range(electron_count):
88
x(qubits[i])
89
90
# Apply the UCCSD circuit
91
uccsd_circuit(qubits, theta, word_single, coef_single, word_double,
92
coef_double)
93
94
# Get the UCCSD circuit (only doubles excitations are included)
95
@cudaq.kernel
96
def uccsd_double_kernel(qubits_num: int, electron_count: int,
97
theta: list[float],
98
word_double: list[cudaq.pauli_word],
99
coef_double: list[float]):
100
"""
101
UCCSD kernel
102
"""
103
# Prepare the state
104
qubits = cudaq.qvector(qubits_num)
105
106
# Initialize the qubits
107
for i in range(electron_count):
108
x(qubits[i])
109
110
# Apply the UCCSD circuit
111
uccsd_circuit_double(qubits, theta, word_double, coef_double)
112
113
# Get the UCCSD circuit (only singles excitations are included)
114
@cudaq.kernel
115
def uccsd_single_kernel(qubits_num: int, electron_count: int,
116
theta: list[float],
117
word_single: list[cudaq.pauli_word],
118
coef_single: list[float]):
119
"""
120
UCCSD kernel
121
"""
122
# Prepare the state
123
qubits = cudaq.qvector(qubits_num)
124
125
# Initialize the qubits
126
for i in range(electron_count):
127
x(qubits[i])
128
129
# Apply the UCCSD circuit
130
uccsd_circuit_single(qubits, theta, word_single, coef_single)
131
132
def cost(theta):
133
134
theta = theta.tolist()
135
136
if not only_singles and not only_doubles:
137
energy = cudaq.observe(uccsd_kernel, hamiltonian, qubits_num,
138
electron_count, theta, word_single,
139
word_double, coef_single,
140
coef_double).expectation()
141
142
143
elif only_singles and not only_doubles:
144
energy = cudaq.observe(uccsd_single_kernel, hamiltonian, qubits_num,
145
electron_count, theta, word_single,
146
coef_single).expectation()
147
148
elif only_doubles and not only_singles:
149
energy = cudaq.observe(uccsd_double_kernel, hamiltonian, qubits_num,
150
electron_count, theta, word_double,
151
coef_double).expectation()
152
153
else:
154
raise ValueError("Invalid option for only_singles and only_doubles")
155
156
return energy
157
158
if optimize:
159
if method == 'L-BFGS-B':
160
result_vqe = minimize(cost,
161
theta,
162
method='L-BFGS-B',
163
jac='3-point',
164
tol=vqe_tol)
165
print('Optimizer exited successfully: ',
166
result_vqe.success,
167
flush=True)
168
elif method == 'BFGS':
169
result_vqe = minimize(cost,
170
theta,
171
method='BFGS',
172
jac='3-point',
173
options={'gtol': 1e-5})
174
print('Optimizer exited successfully: ',
175
result_vqe.success,
176
flush=True)
177
elif method == 'COBYLA':
178
result_vqe = minimize(cost,
179
theta,
180
method='COBYLA',
181
options={
182
'rhobeg': 1.0,
183
'maxiter': 20000,
184
'disp': False,
185
'tol': vqe_tol
186
})
187
else:
188
raise ValueError(
189
"Invalid optimization method. Use 'L-BFGS-B', 'BFGS', or 'COBYLA'."
190
)
191
192
total_energy = result_vqe.fun
193
194
if verbose:
195
print(f"Total energy: {total_energy:.10f} Hartree")
196
# Print the optimized parameters: first n are singles, then doubles.
197
if verbose:
198
print(f"optimized parameters: {result_vqe.x}")
199
200
return (result_vqe.fun, result_vqe.x, result_vqe.success, np.array(cudaq.get_state(uccsd_kernel, qubits_num,
201
electron_count,result_vqe.x, word_single,
202
word_double, coef_single,
203
coef_double)))
204
205
else:
206
total_energy = cudaq.observe(uccsd_kernel, hamiltonian, qubits_num,
207
electron_count, theta, word_single,
208
word_double, coef_single,
209
coef_double).expectation()
210
if verbose:
211
print(f"Total energy: {total_energy:.10f} Hartree")
212
213
print(np.array(cudaq.get_state(uccsd_kernel, qubits_num,
214
electron_count,theta, word_single,
215
word_double, coef_single,
216
coef_double)))
217
218
print(cudaq.get_state(uccsd_kernel, qubits_num,
219
electron_count,theta, word_single,
220
word_double, coef_single,
221
coef_double))
222
223
return (total_energy, theta, True, np.array(cudaq.get_state(uccsd_kernel, qubits_num,
224
electron_count,theta, word_single,
225
word_double, coef_single,
226
coef_double)) )
227