11import numpy as np
22import qutip as qt
33
4+ import scipy as sp
5+
46from yaqs .core .data_structures .networks import MPO , MPS
57from yaqs .core .data_structures .noise_model import NoiseModel
68from yaqs .core .data_structures .simulation_parameters import Observable , PhysicsSimParams
911
1012from 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