qflux 0.0.1__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.
Potentially problematic release.
This version of qflux might be problematic. Click here for more details.
- qflux/GQME/__init__.py +7 -0
- qflux/GQME/dynamics_GQME.py +438 -0
- qflux/GQME/params.py +62 -0
- qflux/GQME/readwrite.py +119 -0
- qflux/GQME/tdvp.py +233 -0
- qflux/GQME/tt_tfd.py +448 -0
- qflux/__init__.py +5 -0
- qflux/closed_systems/__init__.py +17 -0
- qflux/closed_systems/classical_methods.py +427 -0
- qflux/closed_systems/custom_execute.py +22 -0
- qflux/closed_systems/hamiltonians.py +88 -0
- qflux/closed_systems/qubit_methods.py +266 -0
- qflux/closed_systems/spin_dynamics_oo.py +371 -0
- qflux/closed_systems/spin_propagators.py +300 -0
- qflux/closed_systems/utils.py +205 -0
- qflux/open_systems/__init__.py +2 -0
- qflux/open_systems/dilation_circuit.py +183 -0
- qflux/open_systems/numerical_methods.py +303 -0
- qflux/open_systems/params.py +29 -0
- qflux/open_systems/quantum_simulation.py +360 -0
- qflux/open_systems/trans_basis.py +121 -0
- qflux/open_systems/walsh_gray_optimization.py +311 -0
- qflux/typing/__init__.py +0 -0
- qflux/typing/examples.py +24 -0
- qflux/utils/__init__.py +0 -0
- qflux/utils/io.py +16 -0
- qflux/utils/logging_config.py +61 -0
- qflux/variational_methods/__init__.py +1 -0
- qflux/variational_methods/qmad/__init__.py +0 -0
- qflux/variational_methods/qmad/ansatz.py +64 -0
- qflux/variational_methods/qmad/ansatzVect.py +61 -0
- qflux/variational_methods/qmad/effh.py +75 -0
- qflux/variational_methods/qmad/solver.py +356 -0
- qflux-0.0.1.dist-info/METADATA +144 -0
- qflux-0.0.1.dist-info/RECORD +38 -0
- qflux-0.0.1.dist-info/WHEEL +5 -0
- qflux-0.0.1.dist-info/licenses/LICENSE +674 -0
- qflux-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from scipy.linalg import expm, kron
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def vectorize_comm(A):
|
|
6
|
+
# Create an identity matrix with the same dimension as A
|
|
7
|
+
iden = np.eye(A.shape[0])
|
|
8
|
+
# Compute the vectorized commutator [A, .] as the Kronecker product
|
|
9
|
+
return kron(iden, A) - kron(A.T, iden)
|
|
10
|
+
|
|
11
|
+
class VectorizedEffectiveHamiltonian_class:
|
|
12
|
+
def __init__(self, He, Ha):
|
|
13
|
+
self.He = He
|
|
14
|
+
self.Ha = Ha
|
|
15
|
+
|
|
16
|
+
def VectorizedEffectiveHamiltonian(H, gamma, lind):
|
|
17
|
+
# Create an identity matrix with the same dimension as H
|
|
18
|
+
iden = np.eye(H.shape[0])
|
|
19
|
+
# Get the dimension of H
|
|
20
|
+
d = H.shape[0]
|
|
21
|
+
# Compute the vectorized commutator for the Hamiltonian H
|
|
22
|
+
vec_H = vectorize_comm(H)
|
|
23
|
+
# Initialize the result matrix with zeros (complex type)
|
|
24
|
+
res = np.zeros((d**2, d**2), dtype=np.complex128)
|
|
25
|
+
|
|
26
|
+
# Compute the conjugate of the Lindblad operator
|
|
27
|
+
L_conj = lind.conj()
|
|
28
|
+
L_dagger_L = L_conj.T @ lind
|
|
29
|
+
# Compute the Lindblad contribution to the effective Hamiltonian
|
|
30
|
+
res -= gamma * (kron(L_conj, lind) - (kron(iden, L_dagger_L) + kron(L_dagger_L.T, iden)) / 2)
|
|
31
|
+
|
|
32
|
+
# Return an instance of the VectorizedEffectiveHamiltonian_class with vec_H and res
|
|
33
|
+
return VectorizedEffectiveHamiltonian_class(vec_H, res)
|
|
34
|
+
|
|
35
|
+
class EffectiveHamiltonian_class:
|
|
36
|
+
def __init__(self, He, Ha, Llist, LdL):
|
|
37
|
+
self.He = He # Hermitian part
|
|
38
|
+
self.Ha = Ha # Anti-Hermitian part
|
|
39
|
+
self.Llist = Llist # List of Lindblad operators
|
|
40
|
+
self.LdL = LdL # List of L†L
|
|
41
|
+
|
|
42
|
+
def EffectiveHamiltonian( mats, Llist):
|
|
43
|
+
"""
|
|
44
|
+
Create an EffectiveHamiltonian object based on provided parameters.
|
|
45
|
+
:param mats: List of matrices (Hamiltonian terms).
|
|
46
|
+
:param Llist: List of lists of Lindblad operators.
|
|
47
|
+
:return: An instance of EffectiveHamiltonian_class.
|
|
48
|
+
"""
|
|
49
|
+
# Directly use the input matrices as the Hermitian part (assuming they are Hermitian)
|
|
50
|
+
He = sum(mats) # Sum of Hamiltonian terms as Hermitian part
|
|
51
|
+
Ha = 0.0 # Initialize anti-Hermitian part
|
|
52
|
+
LdL = [] # Initialize the list for Lindblad operator products
|
|
53
|
+
|
|
54
|
+
for LL in Llist:
|
|
55
|
+
for L in LL:
|
|
56
|
+
L_dagger_L = (L.conj().T @ L)
|
|
57
|
+
|
|
58
|
+
LdL.append(L_dagger_L) # Append to LdL list
|
|
59
|
+
Ha += L_dagger_L # Sum for the anti-Hermitian part
|
|
60
|
+
|
|
61
|
+
# Return the Effective Hamiltonian object
|
|
62
|
+
return EffectiveHamiltonian_class(He, 0.5 * Ha, [L for LL in Llist for L in LL], LdL)
|
|
63
|
+
|
|
64
|
+
# Helper methods that align with the Julia logic
|
|
65
|
+
def herm(H, t):
|
|
66
|
+
return H.He(t) # Assuming He is callable with t
|
|
67
|
+
|
|
68
|
+
def antiherm(H):
|
|
69
|
+
return H.Ha
|
|
70
|
+
|
|
71
|
+
def get_LdL(H):
|
|
72
|
+
return H.LdL
|
|
73
|
+
|
|
74
|
+
def get_L(H):
|
|
75
|
+
return H.Llist
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from itertools import combinations, product
|
|
3
|
+
from scipy.linalg import expm, kron
|
|
4
|
+
from numpy.random import rand
|
|
5
|
+
random_numbers = np.random.uniform(low=10000, high=99999)
|
|
6
|
+
np.random.seed(int(random_numbers))
|
|
7
|
+
from .ansatz import *
|
|
8
|
+
from .ansatzVect import *
|
|
9
|
+
|
|
10
|
+
# Helper Functions for evolution
|
|
11
|
+
# def tag(A):
|
|
12
|
+
# return A.tag if A else None #!!!!!!!a.any or a.all??
|
|
13
|
+
def tag(A):
|
|
14
|
+
return getattr(A, 'tag', None) if A is not None else None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def aexp(A, theta):
|
|
18
|
+
return expm(-1j * theta * A.mat / 2)
|
|
19
|
+
|
|
20
|
+
def add_A(A, P):
|
|
21
|
+
A.A.append(P)
|
|
22
|
+
A.theta = np.append(A.theta, 0)
|
|
23
|
+
|
|
24
|
+
def lmul(A, ψ):
|
|
25
|
+
# print("ehrerw:",A)
|
|
26
|
+
# print("amat:",np.shape(A.mat))
|
|
27
|
+
# print("her in lmul",A.mat @ ψ)
|
|
28
|
+
return A.mat @ ψ
|
|
29
|
+
|
|
30
|
+
def update_theta(ansatz, dtheta, dt):
|
|
31
|
+
ansatz.theta = ansatz.theta + dtheta * dt
|
|
32
|
+
|
|
33
|
+
def partial_theta(A):
|
|
34
|
+
len_A = len(A.A)
|
|
35
|
+
ψ = A.ref.copy()
|
|
36
|
+
res = []
|
|
37
|
+
for i in range(len_A):
|
|
38
|
+
ψ = aexp(A.A[i], A.theta[i]) @ ψ
|
|
39
|
+
ψt = -0.5j * lmul(A.A[i], ψ)
|
|
40
|
+
for j in range(i + 1, len_A):
|
|
41
|
+
ψt = aexp(A.A[j], A.theta[j]) @ ψt
|
|
42
|
+
res.append(ψt)
|
|
43
|
+
return res
|
|
44
|
+
|
|
45
|
+
def build_m(ψ, dψ):
|
|
46
|
+
l = len(dψ)
|
|
47
|
+
res = np.zeros((l, l))
|
|
48
|
+
ψ = ψ[:, np.newaxis] if len(ψ.shape) == 1 else ψ
|
|
49
|
+
|
|
50
|
+
for μ in range(l):
|
|
51
|
+
for ν in range(l):
|
|
52
|
+
res[μ, ν] = 2 * np.real(dψ[μ].T.conj() @ dψ[ν] + ψ.T.conj() @ dψ[μ] @ ψ.T.conj() @ dψ[ν])
|
|
53
|
+
return res
|
|
54
|
+
|
|
55
|
+
def update_m(m, dψa, ψ, dψ):
|
|
56
|
+
l = m.shape[0]
|
|
57
|
+
mp = np.zeros((l + 1, l + 1))
|
|
58
|
+
dψa = dψa[:, np.newaxis]
|
|
59
|
+
ψ = ψ[:, np.newaxis]
|
|
60
|
+
mp[l, l] = 2 * np.real((dψa.T.conj() @ dψa + ψ.T.conj() @ dψa @ ψ.T.conj() @ dψa).item())
|
|
61
|
+
mp[:l, :l] = m
|
|
62
|
+
for μ in range(l):
|
|
63
|
+
temp = 2 * np.real(dψ[μ].T.conj() @ dψa + ψ.T.conj() @ dψ[μ] @ ψ.T.conj() @ dψa)
|
|
64
|
+
mp[μ, l] = temp.item()
|
|
65
|
+
mp[l, μ] = temp.item()
|
|
66
|
+
return mp
|
|
67
|
+
|
|
68
|
+
def build_v(ψ, dψ, He, Ha):
|
|
69
|
+
L = -1j * (He - 1j * Ha)
|
|
70
|
+
l = len(dψ)
|
|
71
|
+
ψ = ψ[:, np.newaxis] if len(ψ.shape) == 1 else ψ
|
|
72
|
+
res = np.zeros(l)
|
|
73
|
+
for μ in range(l):
|
|
74
|
+
res[μ] = 2 * np.real((dψ[μ].T.conj() @ L @ ψ + dψ[μ].T.conj() @ ψ @ ψ.T.conj() @ L.T.conj() @ ψ).item())
|
|
75
|
+
return res
|
|
76
|
+
|
|
77
|
+
def update_v(v, dψₐ, ψ, He, Ha):
|
|
78
|
+
L = -1j * (He - 1j * Ha)
|
|
79
|
+
l = len(v)
|
|
80
|
+
dψₐ = dψₐ[:, np.newaxis]
|
|
81
|
+
ψ = ψ[:, np.newaxis]
|
|
82
|
+
vp = np.zeros(l + 1)
|
|
83
|
+
vp[:l] = v
|
|
84
|
+
vp[l] = 2 * np.real((dψₐ.T.conj() @ L @ ψ + dψₐ.T.conj() @ ψ @ ψ.T.conj() @ L.T.conj() @ ψ).item())
|
|
85
|
+
return vp
|
|
86
|
+
|
|
87
|
+
def lin_solve(m, v, λ=1e-4):
|
|
88
|
+
A = m.T @ m
|
|
89
|
+
try:
|
|
90
|
+
xλ = np.linalg.solve(A + λ**2 * np.eye(A.shape[0]), m.T @ v)
|
|
91
|
+
except np.linalg.LinAlgError:
|
|
92
|
+
xλ = np.linalg.lstsq(A + λ**2 * np.eye(A.shape[0]), m.T @ v, rcond=None)[0]
|
|
93
|
+
return xλ, 2 * v.T @ xλ - xλ.T @ m @ xλ
|
|
94
|
+
|
|
95
|
+
def get_newest_A(A):
|
|
96
|
+
return A.A[-1] if A.A else None
|
|
97
|
+
|
|
98
|
+
def update_state(A):
|
|
99
|
+
if A.A:
|
|
100
|
+
state = A.ref.copy()
|
|
101
|
+
for i in range(len(A.A)):
|
|
102
|
+
state = aexp(A.A[i], A.theta[i]) @ state
|
|
103
|
+
A.state = state
|
|
104
|
+
else:
|
|
105
|
+
A.state = A.ref
|
|
106
|
+
|
|
107
|
+
def set_ref(A, ref):
|
|
108
|
+
A.ref = ref
|
|
109
|
+
|
|
110
|
+
def reset(A):
|
|
111
|
+
A.theta = np.array([])
|
|
112
|
+
A.A = []
|
|
113
|
+
update_state(A)
|
|
114
|
+
|
|
115
|
+
class Result:
|
|
116
|
+
def __init__(self, t, psi, energy, pop, theta, A, jump_t, jump_L, status):
|
|
117
|
+
self.t = t
|
|
118
|
+
self.psi = psi
|
|
119
|
+
self.energy = energy # Add energy attribute
|
|
120
|
+
self.pop = pop
|
|
121
|
+
self.theta = theta
|
|
122
|
+
self.A = A
|
|
123
|
+
self.jump_t = jump_t
|
|
124
|
+
self.jump_L = jump_L
|
|
125
|
+
self.status = status
|
|
126
|
+
|
|
127
|
+
def __repr__(self):
|
|
128
|
+
return f"Result(t={self.t}, psi={self.psi}, energy={self.energy}, pop={self.pop}, theta={self.theta}, A={self.A}, jump_t={self.jump_t}, jump_L={self.jump_L}, status={self.status})"
|
|
129
|
+
|
|
130
|
+
class AVQDSol:
|
|
131
|
+
def __init__(self, t, u, θ, A, jump_L, jump_t, status=0, norm=[]):
|
|
132
|
+
self.t = t
|
|
133
|
+
self.u = u
|
|
134
|
+
self.θ = θ
|
|
135
|
+
self.A = A
|
|
136
|
+
self.jump_L = jump_L
|
|
137
|
+
self.jump_t = jump_t
|
|
138
|
+
self.status = status
|
|
139
|
+
self.norm = norm
|
|
140
|
+
|
|
141
|
+
def one_step(A, He, Ha, dt):
|
|
142
|
+
|
|
143
|
+
relrcut = A.relrcut
|
|
144
|
+
psi_ = A.state
|
|
145
|
+
dpsi_ = partial_theta(A)
|
|
146
|
+
M = build_m(psi_, dpsi_)
|
|
147
|
+
V = build_v(psi_, dpsi_, He, Ha)
|
|
148
|
+
dtheta, vmv = lin_solve(M, V)
|
|
149
|
+
vmvMax = vmv
|
|
150
|
+
Mtmp = M
|
|
151
|
+
Vtmp = V
|
|
152
|
+
dthetatmp = dtheta
|
|
153
|
+
opTmp = None
|
|
154
|
+
dpsi_ₐTmp = None
|
|
155
|
+
add_flag = True
|
|
156
|
+
|
|
157
|
+
while add_flag:
|
|
158
|
+
# print("here in onestep While")
|
|
159
|
+
tagTmp = None
|
|
160
|
+
# print("Ansatz pool:",A.pool)
|
|
161
|
+
for op in A.pool:
|
|
162
|
+
# print("opertaro from pool:",(op.tag))
|
|
163
|
+
if tag(get_newest_A(A)) == tag(op):
|
|
164
|
+
# print("here in get newest_A")
|
|
165
|
+
continue
|
|
166
|
+
# print("here in op for loop")
|
|
167
|
+
dpsi_ₐ = -0.5j * lmul(op, psi_)
|
|
168
|
+
|
|
169
|
+
Mop = update_m(M, dpsi_ₐ, psi_, dpsi_)
|
|
170
|
+
# print("Mop:",Mop)
|
|
171
|
+
Vop = update_v(V, dpsi_ₐ, psi_, He, Ha)
|
|
172
|
+
dthetaop, vmvOp = lin_solve(Mop, Vop)
|
|
173
|
+
# print("berfore the if:","vmvOp:",vmvOp, "vmvMax:",vmvMax)
|
|
174
|
+
|
|
175
|
+
if vmvOp > vmvMax:
|
|
176
|
+
# print("vmvOp:",vmvOp, "vmvMax:",vmvMax)
|
|
177
|
+
|
|
178
|
+
Mtmp = Mop
|
|
179
|
+
Vtmp = Vop
|
|
180
|
+
vmvMax = vmvOp
|
|
181
|
+
dthetatmp = dthetaop
|
|
182
|
+
opTmp = op
|
|
183
|
+
tagTmp = tag(op)
|
|
184
|
+
# print("tagTmp:",tagTmp)
|
|
185
|
+
dpsi_ₐTmp = dpsi_ₐ
|
|
186
|
+
# print("vmvMax - vmv:",vmvMax-vmv)
|
|
187
|
+
add_flag = vmvMax - vmv >= relrcut
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
if tagTmp is not None and add_flag:
|
|
192
|
+
|
|
193
|
+
add_A(A, opTmp)
|
|
194
|
+
vmv = vmvMax
|
|
195
|
+
M = Mtmp
|
|
196
|
+
V = Vtmp
|
|
197
|
+
dtheta = dthetatmp
|
|
198
|
+
dpsi_.append(dpsi_ₐTmp)
|
|
199
|
+
|
|
200
|
+
update_theta(A, dtheta, dt)
|
|
201
|
+
# print("Ansatz:",A.theta)
|
|
202
|
+
update_state(A)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def solve_avq_traj(H, A, tspan, dt, save_state=True, save_everystep=True):
|
|
206
|
+
# Store initial reference state for reinitialization
|
|
207
|
+
ref_init = A.ref.copy()
|
|
208
|
+
update_state(A)
|
|
209
|
+
|
|
210
|
+
# Initialize time and recorder lists
|
|
211
|
+
t = tspan[0]
|
|
212
|
+
t_list = []
|
|
213
|
+
u_list = []
|
|
214
|
+
theta_list = []
|
|
215
|
+
A_list = []
|
|
216
|
+
jump_L_list = []
|
|
217
|
+
jump_t_list = []
|
|
218
|
+
|
|
219
|
+
# Break flag for error handling
|
|
220
|
+
break_flag = False
|
|
221
|
+
Gamma = 0 # Jump recorder
|
|
222
|
+
q = rand() # Random number for quantum jump
|
|
223
|
+
# print("expo:",np.exp(-Gamma))
|
|
224
|
+
# print("random q:", q)
|
|
225
|
+
|
|
226
|
+
if save_everystep:
|
|
227
|
+
t_list.append(t)
|
|
228
|
+
theta_list.append(A.theta.copy())
|
|
229
|
+
|
|
230
|
+
A_list.append([tag(a) for a in A.A])
|
|
231
|
+
if save_state:
|
|
232
|
+
u_list.append(A.state.copy())
|
|
233
|
+
|
|
234
|
+
# Main evolution loop
|
|
235
|
+
# This loop performs the simulation of quantum system evolution over a set time span.
|
|
236
|
+
# It integrates the system state forward in time while handling both deterministic
|
|
237
|
+
# evolution and stochastic quantum jumps.
|
|
238
|
+
|
|
239
|
+
while t + dt <= tspan[1]: # Loop over the total time span with step size dt
|
|
240
|
+
# print("timestep:", dt) # Print current time step size for monitoring
|
|
241
|
+
He = H.He # Extract Hermitian Hamiltonian component for deterministic evolution
|
|
242
|
+
Ha = H.Ha # Extract Antihermitian Hamiltonian component for jump handling
|
|
243
|
+
|
|
244
|
+
if np.exp(-Gamma) > q: # Check if no quantum jump occurs, based on jump probability threshold
|
|
245
|
+
try:
|
|
246
|
+
one_step(A, He, Ha, dt) # Perform deterministic evolution for one time step
|
|
247
|
+
except Exception: # In case of failure, exit the loop with a flag
|
|
248
|
+
break_flag = True
|
|
249
|
+
break
|
|
250
|
+
psi_ = A.state # Update the current state of the system
|
|
251
|
+
Gamma += 2 * np.real(psi_.T.conj() @ Ha @ psi_) * dt # Update accumulated Gamma for jump probability
|
|
252
|
+
|
|
253
|
+
if save_everystep: # Option to save state at every time step
|
|
254
|
+
t_list.append(t + dt) # Save current time
|
|
255
|
+
theta_list.append(A.theta.copy()) # Save current ansatz parameters
|
|
256
|
+
A_list.append([tag(a) for a in A.A]) # Save current state of ansatz components
|
|
257
|
+
|
|
258
|
+
else: # Quantum jump occurs
|
|
259
|
+
psi_ = A.state # Get current state before jump
|
|
260
|
+
|
|
261
|
+
# Compute the probabilities for different jump operators
|
|
262
|
+
weights = np.array([np.real(psi_.T.conj() @ LdL @ psi_) for LdL in H.LdL])
|
|
263
|
+
|
|
264
|
+
# Randomly choose a jump operator based on computed probabilities
|
|
265
|
+
L_index = np.random.choice([i for i in range(np.shape(H.Llist)[0])], p=weights/weights.sum())
|
|
266
|
+
L = H.Llist[L_index] # Select corresponding jump operator
|
|
267
|
+
|
|
268
|
+
# Apply the jump operator to the state and normalize it
|
|
269
|
+
psi_n = L @ psi_ / np.linalg.norm(L @ psi_)
|
|
270
|
+
|
|
271
|
+
# Record the jump event details (time and operator used)
|
|
272
|
+
jump_t_list.append(t)
|
|
273
|
+
jump_L_list.append(tag(L))
|
|
274
|
+
|
|
275
|
+
# Record the state and parameters post-jump
|
|
276
|
+
t_list.append(t + dt)
|
|
277
|
+
set_ref(A, psi_n) # Update the state with post-jump state
|
|
278
|
+
reset(A) # Reset the ansatz parameters after jump
|
|
279
|
+
|
|
280
|
+
# Save updated ansatz parameters post-jump
|
|
281
|
+
theta_list.append(A.theta.copy())
|
|
282
|
+
A_list.append([tag(a) for a in A.A])
|
|
283
|
+
|
|
284
|
+
# Reset the jump probability accumulator
|
|
285
|
+
Gamma = 0
|
|
286
|
+
q = rand() # Generate a new random number for the next jump check
|
|
287
|
+
|
|
288
|
+
# Optionally save the state at each time step
|
|
289
|
+
if save_state:
|
|
290
|
+
u_list.append(A.state.copy()) # Store the current state
|
|
291
|
+
|
|
292
|
+
# Increment the simulation time by dt
|
|
293
|
+
t += dt
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
# Final check for status if no errors occurred
|
|
297
|
+
if not break_flag:
|
|
298
|
+
if (not jump_t_list or not np.isclose(t, jump_t_list[-1])) and not save_everystep:
|
|
299
|
+
theta_list.append(A.theta.copy())
|
|
300
|
+
A_list.append([tag(a) for a in A.A])
|
|
301
|
+
|
|
302
|
+
# Reset the ansatz to the initial condition
|
|
303
|
+
# print("ansatz before reset:",A.A)
|
|
304
|
+
set_ref(A, ref_init)
|
|
305
|
+
reset(A)
|
|
306
|
+
# print("tlist:",t_list)
|
|
307
|
+
# Return solution object
|
|
308
|
+
return AVQDSol(t_list, u_list, theta_list, A_list, jump_L_list, jump_t_list, status=0 if not break_flag else 1)
|
|
309
|
+
|
|
310
|
+
# Function to evolve a single trajectory and collect results
|
|
311
|
+
def solve_avq_trajectory(H, ansatz, tf, dt):
|
|
312
|
+
# Solve for a single trajectory using solve_avq
|
|
313
|
+
res = solve_avq_traj(H, ansatz, [0, tf], dt, save_state=True, save_everystep=True)
|
|
314
|
+
|
|
315
|
+
# Post-process the results to extract energy and populations
|
|
316
|
+
tlist = res.t
|
|
317
|
+
psi_list = res.u
|
|
318
|
+
energy = []
|
|
319
|
+
pop = []
|
|
320
|
+
|
|
321
|
+
for i in range(len(tlist)):
|
|
322
|
+
psi = psi_list[i]
|
|
323
|
+
energy.append(np.real(np.conj(psi.T) @ (H.He) @ psi)) # Energy
|
|
324
|
+
pop.append([np.abs(psi[0])**2, np.abs(psi[1])**2]) # Population in ground/excited states for amplitude damping
|
|
325
|
+
|
|
326
|
+
return Result(tlist, psi_list, energy, pop, res.θ, res.A, res.jump_t, res.jump_L, res.status)
|
|
327
|
+
pass
|
|
328
|
+
|
|
329
|
+
def solve_avq_vect(H, A, tspan, dt):
|
|
330
|
+
ref_init = A.ref.copy()
|
|
331
|
+
nqbit = A.nqbit
|
|
332
|
+
update_state(A)
|
|
333
|
+
t = tspan[0]
|
|
334
|
+
t_list = [t]
|
|
335
|
+
u_list = [A.state.reshape(2**nqbit, 2**nqbit)]
|
|
336
|
+
theta_list = [A.theta.copy()]
|
|
337
|
+
A_list = [[tag(a) for a in A.A]]
|
|
338
|
+
norm_list = [1.0]
|
|
339
|
+
Gamma = 0
|
|
340
|
+
while t + dt <= tspan[1]:
|
|
341
|
+
He = H.He
|
|
342
|
+
Ha = H.Ha
|
|
343
|
+
one_step(A, He, Ha, dt)
|
|
344
|
+
psi_ = A.state
|
|
345
|
+
Gamma += 2 * np.real(psi_.T.conj() @ Ha @ psi_) * dt
|
|
346
|
+
ρ = psi_.reshape(2**nqbit, 2**nqbit)
|
|
347
|
+
ρ /= np.trace(ρ)
|
|
348
|
+
t += dt
|
|
349
|
+
t_list.append(t)
|
|
350
|
+
u_list.append(ρ)
|
|
351
|
+
theta_list.append(A.theta.copy())
|
|
352
|
+
A_list.append([tag(a) for a in A.A])
|
|
353
|
+
norm_list.append(np.exp(-Gamma))
|
|
354
|
+
set_ref(A, ref_init)
|
|
355
|
+
reset(A)
|
|
356
|
+
return AVQDSol(t_list, u_list, theta_list, A_list, [], [], norm=norm_list)
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: qflux
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: qflux is a package for running quantum dynamics calculations on quantum devices.
|
|
5
|
+
Author-email: Brandon Allen <brandon.allen@yale.edu>, Delmar Cabral <delmar.azevedocabral@yale.edu>, Alexander Soudackov <alexander.soudackov@yale.edu>, Anton Morgunov <anton@ischemist.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/batistagroup/qflux
|
|
8
|
+
Project-URL: Issues, https://github.com/batistagroup/qflux/issues
|
|
9
|
+
Project-URL: Documentation, https://qflux.batistalab.com
|
|
10
|
+
Keywords: Quantum Computing,chemistry,quantum dynamics
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: requests
|
|
15
|
+
Requires-Dist: importlib-metadata
|
|
16
|
+
Requires-Dist: qiskit>=2.0.0
|
|
17
|
+
Requires-Dist: qiskit-aer>=0.17.0
|
|
18
|
+
Requires-Dist: qiskit-algorithms>=0.3.1
|
|
19
|
+
Requires-Dist: qiskit-ibm-runtime>=0.37.0
|
|
20
|
+
Requires-Dist: tomli>=2.2.1
|
|
21
|
+
Requires-Dist: matplotlib>=3.10
|
|
22
|
+
Requires-Dist: numpy>=2.0
|
|
23
|
+
Requires-Dist: pylatexenc>=2.10
|
|
24
|
+
Requires-Dist: qutip>=5.0
|
|
25
|
+
Requires-Dist: scipy
|
|
26
|
+
Requires-Dist: tqdm
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: ipykernel>=6.29.5; extra == "dev"
|
|
29
|
+
Requires-Dist: rich>=13.9.4; extra == "dev"
|
|
30
|
+
Requires-Dist: pre-commit>=4.1.0; extra == "dev"
|
|
31
|
+
Requires-Dist: ruff>=0.9.6; extra == "dev"
|
|
32
|
+
Requires-Dist: pytest>=8.3.4; extra == "dev"
|
|
33
|
+
Requires-Dist: mypy>=1.15.0; extra == "dev"
|
|
34
|
+
Requires-Dist: mkdocs>=1.6.1; extra == "dev"
|
|
35
|
+
Requires-Dist: mkdocstrings-python>=1.15.0; extra == "dev"
|
|
36
|
+
Requires-Dist: material-plausible-plugin>=0.3.0; extra == "dev"
|
|
37
|
+
Requires-Dist: mkdocs-material>=9.6.4; extra == "dev"
|
|
38
|
+
Requires-Dist: types-tqdm>=4.67.0.20241221; extra == "dev"
|
|
39
|
+
Provides-Extra: gqme
|
|
40
|
+
Requires-Dist: mpsqd; extra == "gqme"
|
|
41
|
+
Dynamic: license-file
|
|
42
|
+
|
|
43
|
+
[](LICENCE)
|
|
44
|
+
[](https://cqdmqd.yale.edu/)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# QFlux - A Quantum Computer Dynamics Package
|
|
48
|
+
|
|
49
|
+
This repository contains various protocols for performing quantum dynamics simulations with quantum devices. Each submodule contains object implementations for these protocols as demonstrated in a publication, as well as comprehensive tutorial notebooks designed to help users understand, implement and build upon various simulation techniques for studying quantum dynamics using quantum computer frameworks. Each tutorial is provided in Python, using Jupyter Notebooks to offer detailed explanations in both markdown and code comments.
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
## Table of Contents
|
|
53
|
+
|
|
54
|
+
1. [Getting Started](#start)
|
|
55
|
+
- [Documentation](#docs)
|
|
56
|
+
- [Notebooks For Tutorial Manuscript](#notebooks)
|
|
57
|
+
- [Additional Repositories](#repos)
|
|
58
|
+
2. [Contribution Guidelines](#contribute)
|
|
59
|
+
3. [Citation](#citation)
|
|
60
|
+
4. [License](#license)
|
|
61
|
+
5. [Acknowledgements](#acknowledgement)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
## Getting Started <a name="start"></a>
|
|
65
|
+
|
|
66
|
+
Simply select a notebook and execute them locally or in google collab. Necessary dependencies will be installed using `pip`.
|
|
67
|
+
|
|
68
|
+
If using uv through the commandline, use the following syntax to create and activate a virtual environment:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
uv venv
|
|
72
|
+
source .venv/bin/activate
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The necessary packages, including development, can be installed as follows:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
uv pip install -e ".[dev]"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Documentation <a name="docs"></a>
|
|
82
|
+
|
|
83
|
+
Documentation for QFlux, illustrating its features and representative examples, is available at the following page:
|
|
84
|
+
|
|
85
|
+
https://qflux.batistalab.com/
|
|
86
|
+
|
|
87
|
+
### Notebooks For Tutorial Manuscript <a name="notebooks"></a>
|
|
88
|
+
|
|
89
|
+
[](https://colab.research.google.com/github/batistagroup/qflux/blob/master/demos/tutorial/Part_I.ipynb) | Part I - Closed Quantum Dynamics and Simulation Protocols
|
|
90
|
+
|
|
91
|
+
[](https://colab.research.google.com/github/batistagroup/qflux/blob/master/demos/tutorial/Part_I_appendixA.ipynb) | Part I - Appendix A: Variational Methods
|
|
92
|
+
|
|
93
|
+
[](https://colab.research.google.com/github/batistagroup/qflux/blob/master/demos/tutorial/Part_I_appendixB.ipynb) | Part I - Appendix B: Bosonic Simulation
|
|
94
|
+
|
|
95
|
+
[](https://colab.research.google.com/github/batistagroup/qflux/blob/master/demos/tutorial/Part_II.ipynb) | Part II - Open Quantum Dynamics
|
|
96
|
+
|
|
97
|
+
[](https://colab.research.google.com/github/batistagroup/qflux/blob/master/demos/tutorial/Part_III_B.ipynb) | Part III - Variational Quantum Trajectory Dynamics for FMO
|
|
98
|
+
|
|
99
|
+
[](https://colab.research.google.com/github/batistagroup/qflux/blob/master/demos/tutorial/Part_III_A.ipynb) | Part III - Variational Quantum Dynamics for Amplitude Damping
|
|
100
|
+
|
|
101
|
+
[](https://colab.research.google.com/github/batistagroup/qflux/blob/master/demos/tutorial/Part_IV.ipynb) | Part IV - Generalized Quantum Master Equation Dynamics
|
|
102
|
+
|
|
103
|
+
### Contribution Guidelines <a name="contribute"></a>
|
|
104
|
+
|
|
105
|
+
To contribute to the repository, clone the qflux repository and create a new branch:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
git clone git@github.com:batistagroup/qflux.git
|
|
109
|
+
git pull
|
|
110
|
+
git checkout -b part_II_docs_spinchain
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
For example to contribute to the documentation, written in markdown (.md), edit the markdown in some form and make it complete (vim spin_chain.md for example).
|
|
114
|
+
Once complete, commit changes to file:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
git add spin_chain.md
|
|
118
|
+
git commit -m 'DOCS: Added docs on the spin chain example with Lindblad'
|
|
119
|
+
git push
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Generate a new pull request through github and assign to a tentative reviewer.
|
|
123
|
+
|
|
124
|
+
### Additional Repositories <a name="repos"></a>
|
|
125
|
+
|
|
126
|
+
[](https://github.com/dcabral00/qc_spin_tutorial) | Spin Chain Tutorial Repository
|
|
127
|
+
|
|
128
|
+
[](https://github.com/saurabhshivpuje/QMAD) | QMultiAdapt Repository
|
|
129
|
+
|
|
130
|
+
[](https://github.com/XiaohanDan97/CCI_PartIII_GQME) | GQME Tutorial Repository
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
## Citation <a name="citation"></a>
|
|
134
|
+
|
|
135
|
+
Please cite the preprint of our work when using this code until the journal version becomes available.
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
## Licensing <a name="license"></a>
|
|
139
|
+
|
|
140
|
+
Each notebook or repository might have its own licensing. Please refer to the individual README files and notebooks within each directory for specific licensing information.
|
|
141
|
+
|
|
142
|
+
## Acknowledgement <a name="acknowledgement"></a>
|
|
143
|
+
|
|
144
|
+
We acknowledge the financial support of the National Science Foundation under award number 2124511, CCI Phase I: NSF Center for Quantum Dynamics on Modular Quantum Devices (CQD-MQD).
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
qflux/__init__.py,sha256=j0hovUC2F2GdGooe2jExe89bXQh4HSozB26mOmOx03o,129
|
|
2
|
+
qflux/GQME/__init__.py,sha256=zeTbgWoan3pUfp5aa7MU-ywWBTHAOp4RpLNE4IXW6bU,115
|
|
3
|
+
qflux/GQME/dynamics_GQME.py,sha256=pFK75IqyTsLhODKSHnQiRMyQn8YDgyt-eFPiFAHjwUQ,16849
|
|
4
|
+
qflux/GQME/params.py,sha256=u7mHRdbbf88ccTIvw9Hb4AunlfNBrzara0OZTL80vwk,1822
|
|
5
|
+
qflux/GQME/readwrite.py,sha256=JUUEsDL8Ep705P8iwlQ4YjAm7MswQ-eNpH1wa8_P-_I,3583
|
|
6
|
+
qflux/GQME/tdvp.py,sha256=32Z_cLJornzM4D63nmqekhwtc-OosrQcZhIeEZAqq9s,7136
|
|
7
|
+
qflux/GQME/tt_tfd.py,sha256=-RPH9aiCinLzG0VdZo43UBVKWcuoplkFmi77oOtv5zU,15204
|
|
8
|
+
qflux/closed_systems/__init__.py,sha256=CBnnqCBp0MD7jCGq1P0nzwCyR3okp4jkC8tvqWUTBCY,472
|
|
9
|
+
qflux/closed_systems/classical_methods.py,sha256=Etqjd9OkqCgPzhC2-FgQWlIiTu66V2_7LRftPDwBrb8,15882
|
|
10
|
+
qflux/closed_systems/custom_execute.py,sha256=Mk24DEvEbQlnu52MqhnSOGBpplHoAMz5__AcBKo1E_4,656
|
|
11
|
+
qflux/closed_systems/hamiltonians.py,sha256=ArdljgB7ASUq5QIKdN8CRdhf7b_2nFyb8OPacOGGvEs,3156
|
|
12
|
+
qflux/closed_systems/qubit_methods.py,sha256=NPC0pLM8Jok4bpkTBcDvDNO3YqsCpw9S6MVMxRHwcuU,10882
|
|
13
|
+
qflux/closed_systems/spin_dynamics_oo.py,sha256=cn4aRM3wYkP6CBbL-LhlUMR4dqQSQK7bpSV-twSzFbU,13925
|
|
14
|
+
qflux/closed_systems/spin_propagators.py,sha256=pMg4ttThkXw2kzBlY2yDpdomTn-7alRtpKUAxD-vSl8,11496
|
|
15
|
+
qflux/closed_systems/utils.py,sha256=mv5zGM9WAM4NCOhD5SpzGNS3iuCNZTPVfV_pbGQUlMQ,6969
|
|
16
|
+
qflux/open_systems/__init__.py,sha256=pHbE5rHa0ktH9ZCWUECbmgXQxeS_dJ4PQ5GBhtM9uJk,102
|
|
17
|
+
qflux/open_systems/dilation_circuit.py,sha256=hzzIga8vE4HAyJT1WM0eOB4jA-e32g0dv7P70BfpazA,5908
|
|
18
|
+
qflux/open_systems/numerical_methods.py,sha256=Hv9CJwRa_Kdp8dP7nHt2JJfBx_5w1qMIj_Faaqs9IzM,11981
|
|
19
|
+
qflux/open_systems/params.py,sha256=VsMGDwPqmgxnyl1G_oufopZaNx2duiOQ3g-Bpjp3yJA,676
|
|
20
|
+
qflux/open_systems/quantum_simulation.py,sha256=rwAAr23mFouc0vg2L9QetfV4X1H5_F1eiMzfBUXdvsM,14969
|
|
21
|
+
qflux/open_systems/trans_basis.py,sha256=KG0BNDdW72CUcJ_Qffu8PjrMfJMCc9qhUwUloVX14Bw,4092
|
|
22
|
+
qflux/open_systems/walsh_gray_optimization.py,sha256=5IgHjknFYhWEslOzElicJvJUYwCWNZNqn3N1z-AQzMY,7682
|
|
23
|
+
qflux/typing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
|
+
qflux/typing/examples.py,sha256=Sj66GKPZas2ALTsy5Cq14ds26xOpsOQDhifAQ9tKVFw,853
|
|
25
|
+
qflux/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
|
+
qflux/utils/io.py,sha256=-d_nRKp2ePvLjOJNlRF9x8rs_2z6C5_jLBh-BuUFa80,480
|
|
27
|
+
qflux/utils/logging_config.py,sha256=xvrzBmXYGfd8NdNViT1ebyngXs8_UqRtkeY_4gQmV1w,2264
|
|
28
|
+
qflux/variational_methods/__init__.py,sha256=rQCX9vWIrWJg54Xt-dZ7r6lXt6oh16SmD3tBDVuChIA,17
|
|
29
|
+
qflux/variational_methods/qmad/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
|
+
qflux/variational_methods/qmad/ansatz.py,sha256=cWhXnE6KgOD7Shd9sXtZXhYhfjDan3pPhu3WKTDY-4o,1887
|
|
31
|
+
qflux/variational_methods/qmad/ansatzVect.py,sha256=KrqBVqoYYXcQWUGtRxVP10NCrl5gq0v_-uqGeHAkGFo,1852
|
|
32
|
+
qflux/variational_methods/qmad/effh.py,sha256=_T7MiDFGOYB9WA0KxEnaLKs-iIn4dZEKuUep71xh-h0,2640
|
|
33
|
+
qflux/variational_methods/qmad/solver.py,sha256=eYHlAYOY_QzA322v-fQgXPc5M-F_FSjSgupHs7mCupA,11669
|
|
34
|
+
qflux-0.0.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
35
|
+
qflux-0.0.1.dist-info/METADATA,sha256=ZPDxnoYwkFclZ3cM9kAIUH17tbsom4KN7uNjp93GpkU,7055
|
|
36
|
+
qflux-0.0.1.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
|
|
37
|
+
qflux-0.0.1.dist-info/top_level.txt,sha256=GZgw1Z1DZDPg78NCF1dXCHw_f4usRh5HP5yLtgECIpo,6
|
|
38
|
+
qflux-0.0.1.dist-info/RECORD,,
|