@@ -628,9 +628,12 @@ class GaussianModel:
628628 """
629629
630630 def __init__ (self , DHT , M , j , p = None , scale = None , guess = None ,
631- Nfields = None , noise_likelihood = 0 ):
631+ Nfields = None , noise_likelihood = 0 ,
632+ Wvalues = None , V = None ):
632633
633634 self ._DHT = DHT
635+ self ._Wvalues = Wvalues
636+ self ._V = V
634637
635638 # Correct shape of design matrix etc.
636639 if len (M .shape ) == 2 :
@@ -687,7 +690,19 @@ def __init__(self, DHT, M, j, p=None, scale=None, guess=None,
687690
688691 self ._Sinv [sn :en , sn :en ] += Sj [n ]
689692 else :
690- self ._Sinv = None
693+ #self._Sinv = None
694+ q_array = self ._DHT .q
695+
696+ def true_squared_exponential_kernel (q , p , l ):
697+
698+ q1 , q2 = np .meshgrid (q , q )
699+ p1 , p2 = np .meshgrid (p , p )
700+ SE_Kernel = np .sqrt (p1 * p2 ) * np .exp (- 0.5 * (q1 - q2 )** 2 / l ** 2 )
701+ return SE_Kernel
702+
703+ Ykm = self ._DHT .coefficients (direction = "backward" )
704+ # We continue after set M matrix because is needed to calculate
705+ # best parameters for S matrix.
691706
692707 # Compute the design matrix
693708 self ._M = np .zeros ([Nr * Nfields , Nr * Nfields ], dtype = 'f8' )
@@ -707,7 +722,89 @@ def __init__(self, DHT, M, j, p=None, scale=None, guess=None,
707722
708723 self ._like_noise = noise_likelihood
709724
725+ # M is already defined, so we find best parameters for S matrix and use it.
726+ m , c , l = self .minimizeS ()
727+ pI = np .exp (m * np .log (q_array ) + c )
728+ S_fspace = true_squared_exponential_kernel (q_array , pI , l )
729+ S_real = np .dot (np .transpose (Ykm ), np .dot (S_fspace , Ykm ))
730+ S_real_inv = np .linalg .inv (S_real )
731+ self ._Sinv = S_real_inv
732+
710733 self ._fit ()
734+
735+ def minimizeS (self ):
736+ from scipy .optimize import minimize
737+ from scipy .special import gamma
738+ V = self ._V
739+
740+ def calculate_S (m , c , l ):
741+ q_array = self ._DHT .q
742+ p_array = c * (q_array ** m )
743+ def true_squared_exponential_kernel (q , p , l ):
744+ q1 , q2 = np .meshgrid (q , q )
745+ p1 , p2 = np .meshgrid (p , p )
746+ SE_Kernel = np .sqrt (p1 * p2 ) * np .exp (- 0.5 * (q1 - q2 )** 2 / l ** 2 )
747+ return SE_Kernel
748+
749+ Ykm = self ._DHT .coefficients (direction = "backward" )
750+ S_fspace = true_squared_exponential_kernel (q_array , p_array , l )
751+ S_real = np .dot (np .transpose (Ykm ), np .dot (S_fspace , Ykm ))
752+ return S_real
753+
754+ def calculate_D (S ):
755+ S_real_inv = np .linalg .inv (S )
756+ Dinv = self ._M + S_real_inv
757+ D = np .linalg .inv (Dinv )
758+ return [Dinv , D ]
759+
760+ def calculate_mu (Dinv ):
761+ try :
762+ Dchol = scipy .linalg .cho_factor (Dinv )
763+ mu = scipy .linalg .cho_solve (Dchol , self ._j )
764+
765+ except np .linalg .LinAlgError :
766+ U , s , V = scipy .linalg .svd (Dinv , full_matrices = False )
767+ s1 = np .where (s > 0 , 1. / s , 0 )
768+ mu = np .dot (V .T , np .multiply (np .dot (U .T , self ._j ), s1 ))
769+ return mu
770+
771+ def likelihood (param , data ):
772+ m , c , l = param
773+ Wvalues = self ._Wvalues
774+ N = np .diag (1 / Wvalues )
775+
776+ alpha = 1.3
777+ l0 = 1e7
778+
779+ # Create an Inverse Gamma distribution function
780+ def inv_gamma_function (l , alpha , beta ):
781+ return ((gamma (alpha )* beta )** (- 1 ))* ((beta / l )** (alpha + 1 ))* np .exp (- beta / l )
782+
783+ S = calculate_S (m ,c , l )
784+ [Dinv , D ] = calculate_D (S )
785+ mu = calculate_mu (Dinv )
786+ logdetS = np .linalg .slogdet (S )[1 ]
787+ logdetD = np .linalg .slogdet (D )[1 ]
788+ logdetN = np .linalg .slogdet (N )[1 ]
789+ factor = np .log (2 * np .pi )
790+
791+ log_likelihood = 2 * np .log (np .abs ((1 / m )* (1 / c ))) \
792+ + 2 * np .log (inv_gamma_function (l , alpha , l0 )) \
793+ - 0.5 * (factor + logdetN ) \
794+ - 0.5 * (factor + logdetS ) \
795+ + 0.5 * (factor + logdetD ) \
796+ + 0.5 * np .dot (np .transpose (self ._j ), mu ) \
797+ - 0.5 * np .dot (np .transpose (data ), np .dot (np .diag (Wvalues ), data ))
798+ return - log_likelihood
799+
800+ result = minimize (likelihood , x0 = np .array ([- 5 , 60 , 5e4 ]), args = (V ,),
801+ bounds = [(- 6 , 6 ), (1 , 70 ), (1e3 , 1e6 )],
802+ method = "Powell" , tol = 1e-6 ,
803+ )
804+ m , c , l = result .x
805+ print ("Result: " , "m: " , m , "c: " , c , "l: " , "{:e}" .format (l ))
806+ return [m , c , l ]
807+
711808
712809 def _fit (self ):
713810 """Compute the mean and variance"""
0 commit comments