def compute_z(a,A,b,B,I,w_0): # Make sure of column vectors: a, b = to_column(a), to_column(b) # Compute z: denominator = np.sqrt(np.linalg.det((mo.mldivide(A,B)+I))) z = (w_0/denominator) * np.exp(-.5*((a-b).T).dot(mo.mldivide((A+B),(a-b)))) return(z[0][0])
def filtering(self, x0, p0, Y): # 0. Initiation N_TIME_STEPS = len(Y) self.X_DIM = x0.shape[1] self.Y_DIM = Y.shape[1] x_ = p_ = x__ = p__ = None X_ = P_ = X__ = P__ = None # # FILTERING LOOP for k in range(0, N_TIME_STEPS): print(str(k) + "/" + str(N_TIME_STEPS)) # # 1. Prediction if(k == 0): x__, p__ = x0.T, p0 else: B = self.model.getB(x_, k) Q = self.model.Q x__, p__, _ = self.integrate(x_, p_, self.model.f, k) p__ = p__ + B.dot(Q).dot(B.T) p__ = symetrize_cov(p__) # # 2. Update G = self.model.getG(x__, k) R = self.model.R mu, S, C = self.integrate(x__, p__, self.model.h, k) S = S + G.dot(R).dot(G.T) S = symetrize_cov(S) # # 3. Get estimates eps = Y[k] - to_row(mu) eps = to_column(eps) # TODO: Version with K computed # K = mo.mrdivide(C, S) # K = C.dot(np.linalg.inv(S)) # x_ = x__ + K.dot(eps) # p_ = p__ - K.dot(S).dot(K.T) # p_ = symetrize_cov(p_) # TODO: Version without direct computation of K x_ = x__ + C.dot(mo.mldivide(S, eps)) p_ = p__ - C.dot(mo.mrdivide(C,S).T) p_ = symetrize_cov(p_) # # 4. Save results X__ = x__.T if k==0 else np.vstack([X__, x__.T]) P__ = np.array([p__]) if k==0 else np.vstack([P__, [p__]]) X_ = x_.T if k==0 else np.vstack([X_, x_.T]) P_ = np.array([p_]) if k==0 else np.vstack([P_, [p_]]) return(X_, X__, P_, P__)
def compute_z(a,A,b,B,I,w_0): # Make sure of column vectors: a, b = to_column(a), to_column(b) # Compute z: denominator = np.sqrt(np.linalg.det((mo.mldivide(A,B)+I))) z = (w_0/denominator) * np.exp(-.5*((a-b).T).dot(mo.mldivide((A+B),(a-b)))) return(z[0][0]) # - compute z z = [compute_z(a, A, x0, p0, I, w_0) for a in X] z = to_column(np.array(z)) K = gp.kern.K(X) K = (K.T + K)/2.0 mu = (z.T).dot( mo.mldivide(K, Y) ) W = mo.mrdivide(z.T, K).squeeze().tolist() _Sigma = None _CC = None for i in range(0,len(z)): Y_squared_i = ( to_column(Y[i]-mu) ).dot( to_row(Y[i]-mu) ) _Sigma = W[i] * Y_squared_i if i == 0 else _Sigma + W[i] * Y_squared_i XY_squared_i = ( to_column((X[i]-x0)) ).dot( to_row(Y[i]-mu) ) _CC = W[i] * XY_squared_i if i == 0 else _CC + W[i] * XY_squared_i _Sigma = _Sigma + cov_Q Sigma = (_Sigma + _Sigma.T)/2.0 CC = _CC
def integrate(self, m, P, fun, *args): ''' Input: m - column vector P - matrix Output: x - column vector Variables: X, Y - matrix of row vectors z - column vector m, x, mu - row vector ''' # Initial sample and fitted GP: m = to_row(m) X = m Y = np.apply_along_axis(fun, 1, X, *args) gp = self.gp_fit(X,Y) # Optimization constraints: N_SIGMA = 3 P_diag = np.sqrt(np.diag(P)) lower_const = (m - N_SIGMA*P_diag)[0].tolist() upper_const = (m + N_SIGMA*P_diag)[0].tolist() # Perform sampling for i in range(0, self.N_SAMPLES): # Set extra params to pass to optimizer user_data = {"gp":gp, "m":m, "P":P, "grid_search": False} if (X.shape[1] == 1): ''' GRID SEARCH: when we are in 1 dimension ''' user_data['grid_search'] = True X_grid = np.linspace(lower_const[0], upper_const[0], self.opt_par["GRID_SIZE"]) X_grid = to_column(X_grid) objective = self.optimization_objective(X_grid, user_data) max_ind = objective.index(max(objective)) x_star = np.array([X_grid[max_ind]]) else: ''' OPTIMIZATION: for higher dimensions ''' x_star, _, _ = solve(self.optimization_objective, lower_const, upper_const, user_data=user_data, algmethod = 1, maxT = self.opt_par["MAX_T"], maxf = self.opt_par["MAX_F"]) x_star = to_row(x_star) X = np.vstack((X, x_star)) Y = np.apply_along_axis(fun, 1, X, *args) gp = self.gp_fit(X, Y) # Reoptimize GP: # TODO: Remove unique rows: if (len(unique_rows(X)) != len(X)): print("Removing duplicated rows") X = unique_rows(X) Y = np.apply_along_axis(fun, 1, X, *args) gp = self.gp_fit(X, Y) # Compute integral # Fitted GP parameters w_0 = gp.rbf.variance.tolist()[0] w_d = np.power(gp.rbf.lengthscale.tolist(), 2) # Prior parameters A = np.diag(w_d) I = np.eye(self.X_DIM) # Compute weigths z = [self.compute_z(x, A, m, P, I, w_0) for x in X] z = to_column(np.array(z)) K = gp.kern.K(X); K = (K.T + K)/2.0 W = (mo.mrdivide(z.T, K).squeeze()).tolist() # Compute mean, covariance and cross-cov mu_ = (z.T).dot( mo.mldivide(K, Y) ) mu_ = to_row(mu_) # Initiale Sigma and CC Sigma_ = CC_ = None # TODO: Sigma computation as closed form # Seems to cause problems! # Sigma_ = w_0/np.sqrt(np.linalg.det( 2*mo.mldivide(A,P) + I) ) - (z.T).dot(mo.mldivide(K,z)) # Compute cov matrix and cross cov matrix for i in range(0,len(W)): # TODO: Sigma computation as sumation: # Seems to work better for multidimensional problems and doesn't # cause problems (might be slower though): YY_i = ( to_column(Y[i]-mu_) ).dot( to_row(Y[i]-mu_) ) Sigma_ = W[i] * YY_i if i == 0 else Sigma_ + W[i] * YY_i XY_i = ( to_column(X[i]-m) ).dot( to_row(Y[i]-mu_) ) CC_ = W[i] * XY_i if i == 0 else CC_ + W[i] * XY_i mu_ = to_column(mu_) Sigma_ = symetrize_cov(Sigma_) # Return results return(mu_, Sigma_, CC_)