Skip to content

Commit ac5974f

Browse files
Merge branch 'Noise_Characterization' of https://github.com/cda-tum/mqt-yaqs into Noise_Characterization
2 parents e9a66de + 44b710b commit ac5974f

File tree

2 files changed

+166
-1
lines changed

2 files changed

+166
-1
lines changed

src/yaqs/noise_char/optimization.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,17 @@
55

66
def trapezoidal(y, x):
77

8-
integral = np.zeros(len(y))
8+
len_x = len(x)
9+
len_y = len(y)
10+
11+
integral = np.zeros(len_y)
912

1013
integral[0] = 0
1114

15+
if len_x != len_y:
16+
raise ValueError("Mismatch in the number of elements between x and y. len(x) = {len_x} and len(y) = {len_y}")
17+
18+
1219
for i in range(1,len(y)):
1320
integral[i] = integral[i-1] + 0.5*(x[i] - x[i-1])*(y[i] + y[i-1])
1421

src/yaqs/noise_char/propagation.py

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import numpy as np
22
import qutip as qt
33

4+
import scipy as sp
5+
46
from yaqs.core.data_structures.networks import MPO, MPS
57
from yaqs.core.data_structures.noise_model import NoiseModel
68
from yaqs.core.data_structures.simulation_parameters import Observable, PhysicsSimParams
@@ -9,6 +11,10 @@
911

1012
from yaqs.noise_char.optimization import trapezoidal
1113

14+
import scikit_tt.tensor_train as tt
15+
from scikit_tt.tensor_train import TT
16+
import scikit_tt.solvers.ode as ode
17+
import scikit_tt
1218

1319

1420

@@ -23,6 +29,10 @@ class SimulationParameters:
2329
gamma_deph: float = 0.1
2430
observables = ['x','y','z']
2531

32+
# For scikit_tt
33+
N:int = 100
34+
rank: int= 8
35+
2636

2737

2838
# def qutip_traj(sim_params_class: SimulationParameters):
@@ -363,3 +373,151 @@ def tjm(sim_params_class: SimulationParameters, N=1000):
363373

364374
return t, tjm_exp_vals
365375

376+
377+
378+
379+
def construct_Ank(O_list, L_list):
380+
"""Construct observable array (same for all sites)"""
381+
# define necessary tensors for compact construction
382+
L = np.asarray(L_list)
383+
L_dag = np.conjugate(L).transpose([0,2,1])
384+
L_prod = np.einsum('ijk,ikl->ijl', L_dag, L)
385+
O = np.asarray(O_list)
386+
I = np.eye(2)
387+
# define A_nk
388+
A_nk = np.einsum('ijk,ilm->ijklm', L_dag, L) - 0.5*np.einsum('ij,klm->kijlm',I,L_prod) - 0.5*np.einsum('ijk,lm->ijklm',L_prod,I)
389+
A_nk = np.einsum('ijklm,nkl->ijnm', A_nk, O)
390+
return A_nk
391+
392+
393+
def evaluate_Ank(A_nk, state):
394+
"""Compute expected values of A_nk for each site (assuming that state is right-orthonormal)"""
395+
n_jumps = A_nk.shape[0]
396+
n_obs = A_nk.shape[2]
397+
n_sites = state.order
398+
A = np.zeros([n_sites, n_jumps, n_sites, n_obs], dtype=complex)
399+
400+
A[0,:,0,:] = np.einsum('ijk, mjnl, ilk -> mn', np.conjugate(state.cores[0][:,:,0,:]), A_nk, state.cores[0][:,:,0,:])
401+
402+
for i in range(state.order-1):
403+
# apply SVD
404+
[u, s, v] = sp.linalg.svd(state.cores[i].reshape(state.ranks[i]*state.row_dims[i]*state.col_dims[i],state.ranks[i + 1]), full_matrices=False, overwrite_a=True, check_finite=False)
405+
# define updated rank and core
406+
state.ranks[i + 1] = u.shape[1]
407+
state.cores[i] = u.reshape(state.ranks[i], state.row_dims[i], state.col_dims[i], state.ranks[i + 1])
408+
# shift non-orthonormal part to next core
409+
state.cores[i + 1] = np.tensordot(np.diag(s).dot(v), state.cores[i + 1], axes=(1, 0))
410+
411+
A[i+1,:,i+1,:] = np.einsum('ijk, mjnl, ilk -> mn', np.conjugate(state.cores[i+1][:,:,0,:]), A_nk, state.cores[i+1][:,:,0,:])
412+
413+
return A.transpose([1,0,3,2]).reshape([n_sites*n_jumps, n_sites*n_obs])
414+
415+
416+
417+
418+
419+
420+
def scikit_tt_traj(sim_params_class: SimulationParameters):
421+
422+
423+
T = sim_params_class.T
424+
dt = sim_params_class.dt
425+
L = sim_params_class.L
426+
J = sim_params_class.J
427+
g = sim_params_class.g
428+
gamma_rel = sim_params_class.gamma_rel
429+
gamma_deph = sim_params_class.gamma_deph
430+
431+
rank = sim_params_class.rank
432+
N = sim_params_class.N
433+
434+
435+
t = np.arange(0, T + dt, dt)
436+
timesteps=len(t)-1
437+
438+
439+
# Parameters
440+
X = np.array([[0, 1], [1, 0]])
441+
Y = np.array([[0, -1j], [1j, 0]])
442+
Z = np.array([[1, 0], [0, -1]])
443+
I = np.eye(2)
444+
L_1 = np.array([[0, 1], [0, 0]])
445+
L_2 = np.array([[1, 0], [0, -1]])
446+
O_list = [X, Y, Z]
447+
L_list = [L_1, L_2]
448+
449+
# A_nk = construct_Ank(O_list, L_list)
450+
451+
452+
cores = [None] * L
453+
cores[0] = tt.build_core([[-g * X, - J * Z, I]])
454+
for i in range(1, L - 1):
455+
cores[i] = tt.build_core([[I, 0, 0], [Z, 0, 0], [-g * X, - J * Z, I]])
456+
cores[-1] = tt.build_core([I, Z, -g*X])
457+
hamiltonian = TT(cores)# jump operators and parameters
458+
459+
jump_operator_list = [[L_1, L_2] for _ in range(L)]
460+
jump_parameter_list = [[np.sqrt(gamma_rel), np.sqrt(gamma_deph)] for _ in range(L)]
461+
462+
463+
obs_list=[]
464+
465+
for pauli in O_list:
466+
for j in range(L):
467+
obs= tt.eye(dims=[2]*L)
468+
obs.cores[j]=np.zeros([1,2,2,1], dtype=complex)
469+
obs.cores[j][0,:,:,0]=pauli
470+
obs_list.append(obs)
471+
472+
473+
474+
n_obs= len(obs_list)
475+
n_jump= 2*L
476+
477+
478+
479+
exp_vals = np.zeros([n_obs,timesteps+1])
480+
481+
A_nk=construct_Ank(O_list, L_list)
482+
483+
484+
A_kn_numpy=np.zeros([n_jump, n_obs, timesteps+1],dtype=complex)
485+
486+
for k in range(N):
487+
initial_state = tt.unit([2] * L, [0] * L)
488+
for i in range(rank - 1):
489+
initial_state += tt.unit([2] * L, [0] * L)
490+
initial_state = initial_state.ortho()
491+
initial_state = (1 / initial_state.norm()) * initial_state
492+
493+
494+
for j in range(n_obs):
495+
exp_vals[j,0] += initial_state.transpose(conjugate=True)@obs_list[j]@initial_state
496+
497+
A_kn_numpy[:,:,0]+= evaluate_Ank(A_nk, initial_state)
498+
499+
500+
501+
for i in range(timesteps):
502+
initial_state = ode.tjm(hamiltonian, jump_operator_list, jump_parameter_list, initial_state, dt, 1)[-1]
503+
504+
for j in range(n_obs):
505+
exp_vals[j,i+1] += initial_state.transpose(conjugate=True)@obs_list[j]@initial_state
506+
507+
A_kn_numpy[:,:,i+1] += evaluate_Ank(A_nk, initial_state)
508+
509+
510+
511+
exp_vals = (1/N)*exp_vals
512+
513+
A_kn_numpy = (1/N)*A_kn_numpy
514+
515+
516+
517+
## The .real part is added as a workaround
518+
d_On_d_gk = [ [trapezoidal(A_kn_numpy[i,j].real,t) for j in range(n_obs)] for i in range(n_jump) ]
519+
520+
521+
522+
523+
return t, exp_vals, d_On_d_gk

0 commit comments

Comments
 (0)