def observe(self, obs_mesh, obs_V): __doc__ = Covariance.observe.__doc__ ndim = obs_mesh.shape[1] nobs = obs_mesh.shape[0] if self.ndim is not None: if not ndim==self.ndim: raise ValueError, "Dimension of observation mesh is not equal to dimension of base mesh." else: self.ndim = ndim # bases_o is the basis evaluated on the observation mesh. basis_o = asmatrix(self.eval_basis(obs_mesh, regularize=False)) # chol(basis_o.T * coef_cov * basis_o) chol_inner = self.coef_U * basis_o # chol(basis_o.T * coef_cov * basis_o + diag(obs_V)). Really should do this as low-rank update of covariance # of V. U, piv, m = ichol_basis(basis=chol_inner, nug=obs_V, reltol=self.relative_precision) U = asmatrix(U) piv_new = piv[:m] self.obs_piv = piv_new obs_mesh_new = obs_mesh[piv_new,:] self.Uo = U[:m,:m] # chol(basis_o.T * coef_cov * basis_o + diag(obs_V)) ^ -T * basis_o.T self.Uo_cov = trisolve(self.Uo, basis_o[:,piv[:m]].T, uplo='U', transa='T') # chol(basis_o.T * coef_cov * basis_o + diag(obs_V)).T.I * basis_o.T * coef_cov self.Uo_cov = self.Uo_cov * self.coef_cov # coef_cov -= coef_cov * basis_o * (basis_o.T * coef_cov * basis_o + diag(obs_V)).I * basis_o.T * coef_cov self.coef_cov -= self.Uo_cov.T * self.Uo_cov # coef_U = chol(coef_cov) U, m, piv = ichol_full(c=self.coef_cov, reltol=self.relative_precision) U = asmatrix(U) self.coef_U = U[:m,argsort(piv)] self.m = m return piv_new, obs_mesh_new, None
def __init__(self, basis, coef_cov, relative_precision = 1.0E-15, **params): self.observed = False self.obs_mesh = None self.obs_V = None self.Uo = None self.obs_piv = None self.obs_len = None self.full_piv = None self.full_obs_mesh = None self.basiscov=True self.basis = ravel(basis) self.shape = self.get_shape_from_basis(basis) self.n = prod(self.shape) self.ndim = len(self.shape) self.relative_precision = relative_precision self.params = params if coef_cov.shape == self.shape: self.coef_cov = asmatrix(diag(coef_cov.ravel())) elif coef_cov.shape == self.shape*2: self.coef_cov = asmatrix(coef_cov.reshape((self.n, self.n))) else: raise ValueError, "Covariance tensor's shape must be basis.shape or basis.shape*2 (using tuple multiplication)." # Cholesky factor the covariance matrix of the coefficients. U, m, piv = ichol_full(c=self.coef_cov, reltol=relative_precision) self.coef_U = asmatrix(U[:m,argsort(piv)]) # Rank of the coefficient covariance. self.unobs_m = m self.m = m # Record the unobserved Cholesky factor of the coefficient covariance. self.unobs_coef_U = self.coef_U.copy() self.observed = False
def __init__(self, basis, coef_cov, relative_precision=1.0E-15, **params): self.observed = False self.obs_mesh = None self.obs_V = None self.Uo = None self.obs_piv = None self.obs_len = None self.full_piv = None self.full_obs_mesh = None self.basiscov = True self.basis = ravel(basis) self.shape = self.get_shape_from_basis(basis) self.n = prod(self.shape) self.ndim = len(self.shape) self.relative_precision = relative_precision self.params = params if coef_cov.shape == self.shape: self.coef_cov = asmatrix(diag(coef_cov.ravel())) elif coef_cov.shape == self.shape * 2: self.coef_cov = asmatrix(coef_cov.reshape((self.n, self.n))) else: raise ValueError, "Covariance tensor's shape must be basis.shape or basis.shape*2 (using tuple multiplication)." # Cholesky factor the covariance matrix of the coefficients. U, m, piv = ichol_full(c=self.coef_cov, reltol=relative_precision) self.coef_U = asmatrix(U[:m, argsort(piv)]) # Rank of the coefficient covariance. self.unobs_m = m self.m = m # Record the unobserved Cholesky factor of the coefficient covariance. self.unobs_coef_U = self.coef_U.copy() self.observed = False
def cholesky(self, x, apply_pivot = True, observed=True, nugget=None, regularize=True): """ U = C.cholesky(x[, observed=True, nugget=None]) {'pivots': piv, 'U': U} = \ C.cholesky(x, apply_pivot = False[, observed=True, nugget=None]) Computes incomplete Cholesky factorization of self(x,x). :Arguments: - `x`: The input array on which to evaluate the covariance. - `apply_pivot`: A flag. If it's set to 'True', it returns a matrix U (not necessarily triangular) such that U.T*U=C(x,x). If it's set to 'False', the return value is a dictionary. Item 'pivots' is a vector of pivots, and item 'U' is an upper-triangular matrix (not necessarily square) such that U[:,argsort(piv)].T * U[:,argsort(piv)] = C(x,x). - `observed`: If 'True', any observations are taken into account when computing the Cholesky factor. If not, the unobserved version of self is used. - `nugget`: The 'nugget' parameter, which will essentially be added to the diagonal of C(x,x) before Cholesky factorizing. """ if regularize: x=regularize_array(x) # Number of points in x. N_new = x.shape[0] # Special fast version for single points. if N_new==1: U=asmatrix(sqrt(self.__call__(x, regularize = False, observed = observed))) # print U if not apply_pivot: return {'pivots': array([0]), 'U': U} else: return U C = self.__call__(x, x, regularize=False, observed=observed) if nugget is not None: for i in xrange(N_new): C[i,i] += nugget[i] # ======================================= # = Call to Fortran function ichol_full = # ======================================= U, m, piv = ichol_full(c=C, reltol=self.relative_precision) U = asmatrix(U) # Arrange output matrix and return. if m<0: raise ValueError, "Matrix does not appear to be positive semidefinite" if not apply_pivot: # Useful for self.observe and Realization.__call__. U is upper triangular. U = U[:m,:] return {'pivots': piv, 'U': U} else: # Useful for users. U.T*U = C(x,x) return U[:m,argsort(piv)]
def continue_cholesky(self, x, x_old, chol_dict_old, apply_pivot = True, observed=True, nugget=None, regularize=True, assume_full_rank=False): """ U = C.continue_cholesky(x, x_old, chol_dict_old[, observed=True, nugget=None]) {'pivots': piv, 'U': U} = \ C.cholesky(x, x_old, chol_dict_old, apply_pivot = False[, observed=True, nugget=None]) Computes incomplete Cholesky factorization of self(z,z). Here z is the concatenation of x and x_old. Assumes the Cholesky factorization of self(x_old, x_old) has already been computed. :Arguments: - `x`: The input array on which to evaluate the Cholesky factorization. - `x_old`: The input array on which the Cholesky factorization has been computed. - `chol_dict_old`: A dictionary with kbasis_ys ['pivots', 'U']. Would be the output of either this method or C.cholesky(). - `apply_pivot`: A flag. If it's set to 'True', it returns a matrix U (not necessarily triangular) such that U.T*U=C(x,x). If it's set to 'False', the return value is a dictionary. Item 'pivots' is a vector of pivots, and item 'U' is an upper-triangular matrix (not necessarily square) such that U[:,argsort(piv)].T * U[:,argsort(piv)] = C(x,x). - `observed`: If 'True', any observations are taken into account when computing the Cholesky factor. If not, the unobserved version of self is used. - `nugget`: The 'nugget' parameter, which will essentially be added to the diagonal of C(x,x) before Cholesky factorizing. """ if regularize: x=regularize_array(x) # Concatenation of the old points and new points. xtot = vstack((x_old,x)) # Extract information from chol_dict_old. U_old = chol_dict_old['U'] m_old = U_old.shape[0] piv_old = chol_dict_old['pivots'] # Number of old points. N_old = x_old.shape[0] # Number of new points. N_new = x.shape[0] # Compute off-diagonal part of Cholesky factor offdiag = self.__call__(x=x_old[piv_old[:m_old],:], y=x, observed=observed, regularize=False) trisolve(U_old[:,:m_old],offdiag,uplo='U',transa='T', inplace=True) # Compute new diagonal part of Cholesky factor C_new = self.__call__(x=x, y=x, observed=observed, regularize=False) if nugget is not None: for i in xrange(N_new): C_new[i,i] += nugget[i] C_new -= offdiag.T*offdiag if not assume_full_rank: U_new, m_new, piv_new = ichol_full(c=C_new, reltol=self.relative_precision) else: U_new = cholesky(C_new).T m_new = U_new.shape[0] piv_new = arange(m_new) U_new = asmatrix(U_new[:m_new,:]) U = asmatrix(zeros((m_new + m_old, N_old + N_new), dtype=float, order='F')) # Top portion of U U[:m_old, :m_old] = U_old[:,:m_old] U[:m_old,N_new+m_old:] = U_old[:,m_old:] offdiag=offdiag[:,piv_new] U[:m_old, m_old:N_new+m_old] = offdiag # Lower portion of U U[m_old:,m_old:m_old+N_new] = U_new if m_old < N_old and m_new > 0: offdiag_lower = self.__call__( x=x[piv_new[:m_new],:], y=x_old[piv_old[m_old:],:], observed=observed, regularize=False) offdiag_lower -= offdiag[:,:m_new].T*U[:m_old,m_old+N_new:] trisolve(U_new[:,:m_new],offdiag_lower,uplo='U',transa='T', inplace=True) U[m_old:,m_old+N_new:] = offdiag_lower # Rank and pivots m=m_old+m_new piv=hstack((piv_old[:m_old],piv_new+N_old,piv_old[m_old:])) # Arrange output matrix and return. if m<0: raise ValueError, 'Matrix does not appear positive semidefinite.' if not apply_pivot: # Useful for self.observe. U is upper triangular. return {'pivots': piv, 'U': U} else: # Useful for the user. U.T * U = C(x,x). return U[:,argsort(piv)]
def cholesky(self, x, apply_pivot = True, observed=True, nugget=None, regularize=True, rank_limit=0): """ U = C.cholesky(x[, observed=True, nugget=None, rank_limit=0]) {'pivots': piv, 'U': U} = \ C.cholesky(x, apply_pivot = False[, observed=True, nugget=None]) Computes incomplete Cholesky factorization of self(x,x). :Arguments: - `x`: The input array on which to evaluate the covariance. - `apply_pivot`: A flag. If it's set to 'True', it returns a matrix U (not necessarily triangular) such that U.T*U=C(x,x). If it's set to 'False', the return value is a dictionary. Item 'pivots' is a vector of pivots, and item 'U' is an upper-triangular matrix (not necessarily square) such that U[:,argsort(piv)].T * U[:,argsort(piv)] = C(x,x). - `observed`: If 'True', any observations are taken into account when computing the Cholesky factor. If not, the unobserved version of self is used. - `nugget`: The 'nugget' parameter, which will essentially be added to the diagonal of C(x,x) before Cholesky factorizing. - `rank_limit`: If rank_limit > 0, the factor will have at most rank_limit rows. """ if rank_limit > 0: raise ValueError, 'NearlyFullRankCovariance does not accept a rank_limit argument. Use Covariance instead.' if regularize: x=regularize_array(x) # Number of points in x. N_new = x.shape[0] # Special fast version for single points. if N_new==1: V = self.__call__(x, regularize = False, observed = observed) if nugget is not None: V += nugget U=asmatrix(sqrt(V)) # print U if not apply_pivot: return {'pivots': array([0]), 'U': U} else: return U C = self.__call__(x, x, regularize=False, observed=observed) if nugget is not None: for i in xrange(N_new): C[i,i] += nugget[i] # ======================================= # = Call to Fortran function ichol_full = # ======================================= U, m, piv = ichol_full(c=C, reltol=self.relative_precision) U = asmatrix(U) # Arrange output matrix and return. if m<0: raise ValueError, "Matrix does not appear to be positive semidefinite" if not apply_pivot: # Useful for self.observe and Realization.__call__. U is upper triangular. U = U[:m,:] return {'pivots': piv, 'U': U} else: # Useful for users. U.T*U = C(x,x) return U[:m,argsort(piv)]
def continue_cholesky(self, x, x_old, chol_dict_old, apply_pivot = True, observed=True, nugget=None, regularize=True, assume_full_rank=False, rank_limit=0): """ U = C.continue_cholesky(x, x_old, chol_dict_old[, observed=True, nugget=None, rank_limit=0]) Returns {'pivots': piv, 'U': U} Computes incomplete Cholesky factorization of self(z,z). Here z is the concatenation of x and x_old. Assumes the Cholesky factorization of self(x_old, x_old) has already been computed. :Arguments: - `x`: The input array on which to evaluate the Cholesky factorization. - `x_old`: The input array on which the Cholesky factorization has been computed. - `chol_dict_old`: A dictionary with kbasis_ys ['pivots', 'U']. Would be the output of either this method or C.cholesky(). - `apply_pivot`: A flag. If it's set to 'True', it returns a matrix U (not necessarily triangular) such that U.T*U=C(x,x). If it's set to 'False', the return value is a dictionary. Item 'pivots' is a vector of pivots, and item 'U' is an upper-triangular matrix (not necessarily square) such that U[:,argsort(piv)].T * U[:,argsort(piv)] = C(x,x). - `observed`: If 'True', any observations are taken into account when computing the Cholesky factor. If not, the unobserved version of self is used. - `nugget`: The 'nugget' parameter, which will essentially be added to the diagonal of C(x,x) before Cholesky factorizing. - `rank_limit`: If rank_limit > 0, the factor will have at most rank_limit rows. """ if regularize: x=regularize_array(x) if rank_limit > 0: raise ValueError, 'NearlyFullRankCovariance does not accept a rank_limit argument. Use Covariance instead.' if rank_limit > 0: raise ValueError, 'NearlyFullRankCovariance does not accept a rank_limit argument. Use Covariance instead.' # Concatenation of the old points and new points. xtot = vstack((x_old,x)) # Extract information from chol_dict_old. U_old = chol_dict_old['U'] m_old = U_old.shape[0] piv_old = chol_dict_old['pivots'] # Number of old points. N_old = x_old.shape[0] # Number of new points. N_new = x.shape[0] # Compute off-diagonal part of Cholesky factor offdiag = self.__call__(x=x_old[piv_old[:m_old],:], y=x, observed=observed, regularize=False) trisolve(U_old[:,:m_old],offdiag,uplo='U',transa='T', inplace=True) # Compute new diagonal part of Cholesky factor C_new = self.__call__(x=x, y=x, observed=observed, regularize=False) if nugget is not None: for i in xrange(N_new): C_new[i,i] += nugget[i] C_new -= offdiag.T*offdiag if not assume_full_rank: U_new, m_new, piv_new = ichol_full(c=C_new, reltol=self.relative_precision) else: U_new = cholesky(C_new).T m_new = U_new.shape[0] piv_new = arange(m_new) U_new = asmatrix(U_new[:m_new,:]) U = asmatrix(zeros((m_new + m_old, N_old + N_new), dtype=float, order='F')) # Top portion of U U[:m_old, :m_old] = U_old[:,:m_old] U[:m_old,N_new+m_old:] = U_old[:,m_old:] offdiag=offdiag[:,piv_new] U[:m_old, m_old:N_new+m_old] = offdiag # Lower portion of U U[m_old:,m_old:m_old+N_new] = U_new if m_old < N_old and m_new > 0: offdiag_lower = self.__call__( x=x[piv_new[:m_new],:], y=x_old[piv_old[m_old:],:], observed=observed, regularize=False) offdiag_lower -= offdiag[:,:m_new].T*U[:m_old,m_old+N_new:] trisolve(U_new[:,:m_new],offdiag_lower,uplo='U',transa='T', inplace=True) U[m_old:,m_old+N_new:] = offdiag_lower # Rank and pivots m=m_old+m_new piv=hstack((piv_old[:m_old],piv_new+N_old,piv_old[m_old:])) # Arrange output matrix and return. if m<0: raise ValueError, 'Matrix does not appear positive semidefinite.' if not apply_pivot: # Useful for self.observe. U is upper triangular. if assume_full_rank: return {'pivots':piv,'U':U,'C_eval':C_new,'U_new':U_new} else: return {'pivots': piv, 'U': U} else: # Useful for the user. U.T * U = C(x,x). return U[:,argsort(piv)]
def observe(self, obs_mesh, obs_V, output_type='o'): __doc__ = Covariance.observe.__doc__ ndim = obs_mesh.shape[1] nobs = obs_mesh.shape[0] if self.ndim is not None: if not ndim == self.ndim: raise ValueError, "Dimension of observation mesh is not equal to dimension of base mesh." else: self.ndim = ndim # bases_o is the basis evaluated on the observation mesh. basis_o = asmatrix(self.eval_basis(obs_mesh, regularize=False)) # chol(basis_o.T * coef_cov * basis_o) chol_inner = self.coef_U * basis_o if output_type == 's': C_eval = dot(chol_inner.T, chol_inner).copy('F') U_eval = linalg.cholesky(C_eval).T.copy('F') U = U_eval m = U_eval.shape[0] piv = arange(m) else: # chol(basis_o.T * coef_cov * basis_o + diag(obs_V)). Really should do this as low-rank update of covariance # of V. U, piv, m = ichol_basis(basis=chol_inner, nug=obs_V, reltol=self.relative_precision) U = asmatrix(U) piv_new = piv[:m] self.obs_piv = piv_new obs_mesh_new = obs_mesh[piv_new, :] self.Uo = U[:m, :m] # chol(basis_o.T * coef_cov * basis_o + diag(obs_V)) ^ -T * basis_o.T self.Uo_cov = trisolve(self.Uo, basis_o[:, piv[:m]].T, uplo='U', transa='T') # chol(basis_o.T * coef_cov * basis_o + diag(obs_V)).T.I * basis_o.T * coef_cov self.Uo_cov = self.Uo_cov * self.coef_cov # coef_cov = coef_cov - coef_cov * basis_o * (basis_o.T * coef_cov * basis_o + diag(obs_V)).I * basis_o.T * coef_cov self.coef_cov = self.coef_cov - self.Uo_cov.T * self.Uo_cov # coef_U = chol(coef_cov) U, m, piv = ichol_full(c=self.coef_cov, reltol=self.relative_precision) U = asmatrix(U) self.coef_U = U[:m, argsort(piv)] self.m = m if output_type == 'o': return piv_new, obs_mesh_new if output_type == 's': return U_eval, C_eval, basis_o raise ValueError, 'Output type not recognized.'