예제 #1
0
    def continue_cholesky(self, x, x_old, U_old, observed=True, nugget=None):
        """

        U = C.continue_cholesky(x, x_old, U_old[, observed=True, nugget=None])

        Computes Cholesky factorization of self(z,z). 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.

            -   `U_old`: The Cholesky factorization of C(x_old, x_old).

            -   `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.
        """

        # Concatenation of the old points and new points.
        xtot = vstack((x_old, x))

        # Number of old points.
        N_old = x_old.shape[0]

        # Number of new points.
        N_new = x.shape[0]

        U_new = self.__call__(x, x, regularize=False, observed=observed)

        # not really implemented yet.
        if nugget is not None:
            for i in xrange(N_new):
                U_new[i, i] += nugget[i]

        U = asmatrix(
            zeros((N_new + N_old, N_old + N_new), dtype=float, order='F'))
        U[:N_old, :N_old] = U_old

        offdiag = self.__call__(x=x_old,
                                y=x,
                                observed=observed,
                                regularize=False)
        trisolve(U_old, offdiag, uplo='U', transa='T', inplace=True)
        U[:N_old, N_old:] = offdiag

        U_new -= offdiag.T * offdiag

        info = dpotrf_wrap(U_new)
        if info > 0:
            raise LinAlgError, "Matrix does not appear to be positive definite by row %i. Consider another Covariance subclass, such as NearlyFullRankCovariance." % info

        U[N_old:, N_old:] = U_new
        return U
예제 #2
0
    def continue_cholesky(self, x, x_old, U_old, observed=True, nugget=None):
        """

        U = C.continue_cholesky(x, x_old, U_old[, observed=True, nugget=None])

        Computes Cholesky factorization of self(z,z). 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.

            -   `U_old`: The Cholesky factorization of C(x_old, x_old).

            -   `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.
        """

        # Concatenation of the old points and new points.
        xtot = vstack((x_old,x))

        # Number of old points.
        N_old = x_old.shape[0]

        # Number of new points.
        N_new = x.shape[0]

        U_new = self.__call__(x, x, regularize=False, observed=observed)

        # not really implemented yet.
        if nugget is not None:
            for i in xrange(N_new):
                U_new[i,i] += nugget[i]

        U = asmatrix(zeros((N_new + N_old, N_old + N_new), dtype=float, order='F'))
        U[:N_old, :N_old] = U_old

        offdiag = self.__call__(x=x_old, y=x, observed=observed, regularize=False)
        trisolve(U_old,offdiag,uplo='U',transa='T', inplace=True)
        U[:N_old, N_old:] = offdiag

        U_new -= offdiag.T*offdiag

        info = dpotrf_wrap(U_new)
        if info>0:
            raise LinAlgError, "Matrix does not appear to be positive definite by row %i. Consider another Covariance subclass, such as NearlyFullRankCovariance." %info

        U[N_old:,N_old:] = U_new
        return U
예제 #3
0
 def _obs_reg(self, M, dev_new, m_old):
     # reg_mat = chol(C(obs_mesh_*, obs_mesh_*)).T.I * M.dev
     reg_mat_new = -1. * dot(
         self.Uo[:m_old, m_old:].T,
         trisolve(self.Uo[:m_old, :m_old], M.dev, uplo='U', transa='T')).T
     trisolve(self.Uo[m_old:, m_old:].T, reg_mat_new, 'L', inplace=True)
     reg_mat_new += asmatrix(
         trisolve(self.Uo[m_old:, m_old:], dev_new.T, uplo='U',
                  transa='T')).T
     return asmatrix(vstack((M.reg_mat, reg_mat_new)))
예제 #4
0
    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.'
예제 #5
0
 def _obs_eval(self, M, M_out, x, Uo_Cxo=None):
     if Uo_Cxo is None:
         Uo_Cxo = trisolve(M.Uo,
                           self(M.obs_mesh, x, observed=False),
                           uplo='U',
                           transa='T')
     M_out += dot(asarray(M.reg_mat).squeeze(), asarray(Uo_Cxo)).squeeze()
     return M_out
예제 #6
0
    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
예제 #7
0
 def _unobs_reg(self, M):
     # reg_mat = chol(C(obs_mesh_*, obs_mesh_*)).T.I * M.dev
     return asmatrix(trisolve(self.Uo, M.dev.T, uplo='U', transa='T')).T
예제 #8
0
    def __call__(self,
                 x,
                 y=None,
                 observed=True,
                 regularize=True,
                 return_Uo_Cxo=False):

        if y is x:
            symm = True
        else:
            symm = False

        # Remember shape of x, and then 'regularize' it.
        orig_shape = shape(x)
        if len(orig_shape) > 1:
            orig_shape = orig_shape[:-1]

        if regularize:
            x = regularize_array(x)

        ndimx = x.shape[-1]
        lenx = x.shape[0]

        if return_Uo_Cxo:
            Uo_Cxo = None

        # Safety
        if self.ndim is not None:
            if not self.ndim == ndimx:
                raise ValueError, "The number of spatial dimensions of x, "+\
                                    ndimx.__str__()+\
                                    ", does not match the number of spatial dimensions of the Covariance instance's base mesh, "+\
                                    self.ndim.__str__()+"."

        # If there are observation points, prepare self(obs_mesh, x)
        # and chol(self(obs_mesh, obs_mesh)).T.I * self(obs_mesh, x)

        # ==========================================================
        # = If only one argument is provided, return the diagonal. =
        # ==========================================================
        if y is None:
            # Special fast-path for functions that have an 'amp' parameter
            if hasattr(self.eval_fun, 'diag_call'):
                V = self.eval_fun.diag_call(x, **self.params)
            # Otherwise, evaluate the diagonal in a loop.
            else:
                V = empty(lenx, dtype=float)
                for i in xrange(lenx):
                    this_x = x[i].reshape((1, -1))
                    V[i] = self.eval_fun(this_x, this_x, **self.params)
            if self.observed and observed:
                sqpart = empty(lenx, dtype=float)
                Cxo = self.eval_fun(self.obs_mesh, x, **self.params)
                Uo_Cxo = trisolve(self.Uo, Cxo, uplo='U', transa='T')
                square_and_sum(Uo_Cxo, sqpart)
                V -= sqpart

            if return_Uo_Cxo:
                return V.reshape(orig_shape), Uo_Cxo
            else:
                return V.reshape(orig_shape)

        else:

            # ====================================================
            # = # If x and y are the same array, save some work: =
            # ====================================================
            if symm:
                C = self.eval_fun(x, x, symm=True, **self.params)
                # Update return value using observations.
                if self.observed and observed:
                    Cxo = self.eval_fun(self.obs_mesh, x, **self.params)
                    Uo_Cxo = trisolve(self.Uo, Cxo, uplo='U', transa='T')
                    C -= Uo_Cxo.T * Uo_Cxo

                if return_Uo_Cxo:
                    return C, Uo_Cxo
                else:
                    return C

            # ======================================
            # = # If x and y are different arrays: =
            # ======================================
            else:

                if regularize:
                    y = regularize_array(y)

                ndimy = y.shape[-1]
                leny = y.shape[0]

                if not ndimx == ndimy:
                    raise ValueError, 'The last dimension of x and y (the number of spatial dimensions) must be the same.'

                C = self.eval_fun(x, y, **self.params)

                # Update return value using observations.
                if self.observed and observed:

                    # If there are observation points, prepare self(obs_mesh, y)
                    # and chol(self(obs_mesh, obs_mesh)).T.I * self(obs_mesh, y)
                    Cyo = self.eval_fun(self.obs_mesh, y, **self.params)
                    Uo_Cyo = trisolve(self.Uo, Cyo, uplo='U', transa='T')
                    C -= Uo_Cxo.T * Uo_Cyo

                return C
예제 #9
0
    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), without
        actually evaluating the matrix first. 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)

        # 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]
        if rank_limit == 0:
            m_new_max = N_new
        else:
            m_new_max = min(N_new, max(0, rank_limit - m_old))

        # get-row function
        def rowfun(i, xpiv, rowvec):
            """
            A function that can be used to overwrite an input array with superdiagonal rows.
            """
            rowvec[i:] = self.__call__(x=xpiv[i - 1, :].reshape(1, -1),
                                       y=xpiv[i:, :],
                                       regularize=False,
                                       observed=observed)

        # diagonal
        diag = self.__call__(x, y=None, regularize=False, observed=observed)

        # not really implemented yet.
        if nugget is not None:
            diag += nugget.ravel()

        # Arrange U for input to ichol. See documentation.
        U = asmatrix(
            zeros((m_new_max + m_old, N_old + N_new), dtype=float, order='F'))
        U[:m_old, :m_old] = U_old[:, :m_old]
        U[:m_old, N_new + m_old:] = U_old[:, m_old:]

        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)
        U[:m_old, m_old:N_new + m_old] = offdiag

        # Initialize pivot vector:
        # [old_posdef_pivots  new_pivots  old_singular_pivots]
        #   - old_posdef_pivots are the indices of the rows that made it into the Cholesky factor so far.
        #   - old_singular_pivots are the indices of the rows that haven't made it into the Cholesky factor so far.
        #   - new_pivots are the indices of the rows that are going to be incorporated now.
        piv = zeros(N_new + N_old, dtype=int)
        piv[:m_old] = piv_old[:m_old]
        piv[N_new + m_old:] = piv_old[m_old:]
        piv[m_old:N_new + m_old] = arange(N_new) + N_old

        # ============================================
        # = Call to Fortran function ichol_continue. =
        # ============================================

        # Early return if rank is all used up.
        if m_new_max > 0:

            # ============================================
            # = Call to Fortran function ichol_continue. =
            # ============================================
            if not assume_full_rank:
                m, piv = ichol_continue(U,
                                        diag=diag,
                                        reltol=self.relative_precision,
                                        rowfun=rowfun,
                                        piv=piv,
                                        x=xtot[piv, :],
                                        mold=m_old)
            else:
                m = m_old + N_new
                C_eval = self.__call__(x, x, observed=True, regularize=False)
                U2 = cholesky(C_eval).T
                U[m_old:, m_old:N_new + m_old] = U2

                if m_old < N_old:
                    offdiag2 = self.__call__(x=x,
                                             y=x_old[piv_old[m_old:]],
                                             observed=observed,
                                             regularize=False)
                    trisolve(U2, offdiag2, uplo='U', transa='T', inplace=True)
                    U[m_old:, N_new + m_old:] = offdiag2

        else:
            m = 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.
            U = U[:m, :]
            if assume_full_rank:
                return {'pivots': piv, 'U': U, 'C_eval': C_eval, 'U_new': U2}
            else:
                return {'pivots': piv, 'U': U}

        else:
            # Useful for the user. U.T * U = C(x,x).
            return U[:m, argsort(piv)]
예제 #10
0
 def _obs_reg(self, M, dev_new, m_old):
     # reg_mat = chol(self.basis_o.T * self.coef_cov * self.basis_o + diag(obs_V)).T.I * self.basis_o.T * self.coef_cov *
     # chol(self(obs_mesh_*, obs_mesh_*)).T.I * M.dev
     M.reg_mat += self.Uo_cov.T * asmatrix(trisolve(self.Uo, dev_new, uplo='U', transa='T')).T
     return M.reg_mat
예제 #11
0
 def _unobs_reg(self, M):
     # reg_mat = chol(self.basis_o.T * self.coef_cov * self.basis_o + diag(obs_V)).T.I * self.basis_o.T * self.coef_cov *
     # chol(self(obs_mesh_*, obs_mesh_*)).T.I * M.dev
     return self.Uo_cov.T * asmatrix(trisolve(self.Uo, M.dev, uplo='U', transa='T')).T
예제 #12
0
    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), without
        actually evaluating the matrix first. 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)

        # 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]
        if rank_limit == 0:
            m_new_max = N_new
        else:
            m_new_max = min(N_new,max(0,rank_limit-m_old))


        # get-row function
        def rowfun(i,xpiv,rowvec):
            """
            A function that can be used to overwrite an input array with superdiagonal rows.
            """
            rowvec[i:] = self.__call__(x=xpiv[i-1,:].reshape(1,-1), y=xpiv[i:,:], regularize=False, observed = observed)


        # diagonal
        diag = self.__call__(x, y=None, regularize=False, observed = observed)


        # not really implemented yet.
        if nugget is not None:
            diag += nugget.ravel()


        # Arrange U for input to ichol. See documentation.
        U = asmatrix(zeros((m_new_max + m_old, N_old + N_new), dtype=float, order='F'))
        U[:m_old, :m_old] = U_old[:,:m_old]
        U[:m_old,N_new+m_old:] = U_old[:,m_old:]

        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)
        U[:m_old, m_old:N_new+m_old] = offdiag


        # Initialize pivot vector:
        # [old_posdef_pivots  new_pivots  old_singular_pivots]
        #   - old_posdef_pivots are the indices of the rows that made it into the Cholesky factor so far.
        #   - old_singular_pivots are the indices of the rows that haven't made it into the Cholesky factor so far.
        #   - new_pivots are the indices of the rows that are going to be incorporated now.
        piv = zeros(N_new + N_old, dtype=int)
        piv[:m_old] = piv_old[:m_old]
        piv[N_new + m_old:] = piv_old[m_old:]
        piv[m_old:N_new + m_old] = arange(N_new)+N_old


        # ============================================
        # = Call to Fortran function ichol_continue. =
        # ============================================


        # Early return if rank is all used up.
        if m_new_max > 0:

            # ============================================
            # = Call to Fortran function ichol_continue. =
            # ============================================
            if not assume_full_rank:
                m, piv = ichol_continue(U, diag = diag, reltol = self.relative_precision, rowfun = rowfun, piv=piv, x=xtot[piv,:], mold=m_old)
            else:
                m = m_old + N_new
                C_eval = self.__call__(x,x,observed=True,regularize=False)
                U2 = cholesky(C_eval).T
                U[m_old:,m_old:N_new+m_old] = U2

                if m_old < N_old:
                    offdiag2 = self.__call__(x=x, y=x_old[piv_old[m_old:]], observed=observed, regularize=False)
                    trisolve(U2,offdiag2,uplo='U',transa='T',inplace=True)
                    U[m_old:,N_new+m_old:] = offdiag2

        else:
            m = 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.
            U = U[:m,:]
            if assume_full_rank:
                return {'pivots': piv, 'U': U, 'C_eval':C_eval, 'U_new': U2}
            else:
                return {'pivots': piv, 'U': U}

        else:
            # Useful for the user. U.T * U = C(x,x).
            return U[:m,argsort(piv)]
예제 #13
0
파일: Covariance.py 프로젝트: huard/pymc
 def _obs_eval(self, M, M_out, x):
     Cxo = self(M.obs_mesh, x, observed = False)
     Cxo_Uo_inv = trisolve(M.Uo, Cxo, uplo='U', transa='T')
     M_out += dot(asarray(M.reg_mat).T,asarray(Cxo_Uo_inv)).squeeze()
     return M_out
예제 #14
0
    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)]
예제 #15
0
 def _obs_eval(self, M, M_out, x, Uo_Cxo=None):
     if Uo_Cxo is None:
         Uo_Cxo = trisolve(M.Uo, self(M.obs_mesh, x, observed = False), uplo='U', transa='T')
     M_out += dot(asarray(M.reg_mat).squeeze(),asarray(Uo_Cxo)).squeeze()
     return M_out
예제 #16
0
 def _obs_reg(self, M, dev_new, m_old):
     # reg_mat = chol(C(obs_mesh_*, obs_mesh_*)).T.I * M.dev
     reg_mat_new = -1.*dot(self.Uo[:m_old,m_old:].T , trisolve(self.Uo[:m_old,:m_old], M.dev, uplo='U', transa='T')).T
     trisolve(self.Uo[m_old:,m_old:].T, reg_mat_new, 'L', inplace=True)
     reg_mat_new += asmatrix(trisolve(self.Uo[m_old:,m_old:], dev_new.T, uplo='U', transa='T')).T
     return asmatrix(vstack((M.reg_mat,reg_mat_new)))
예제 #17
0
 def _unobs_reg(self, M):
     # reg_mat = chol(C(obs_mesh_*, obs_mesh_*)).T.I * M.dev
     return asmatrix(trisolve(self.Uo, M.dev.T, uplo='U',transa='T')).T
예제 #18
0
    def __call__(self, x, y=None, observed=True, regularize=True, return_Uo_Cxo=False):

        if y is x:
            symm=True
        else:
            symm=False

        # Remember shape of x, and then 'regularize' it.
        orig_shape = shape(x)
        if len(orig_shape)>1:
            orig_shape = orig_shape[:-1]

        if regularize:
            x=regularize_array(x)

        ndimx = x.shape[-1]
        lenx = x.shape[0]

        if return_Uo_Cxo:
            Uo_Cxo = None

        # Safety
        if self.ndim is not None:
            if not self.ndim == ndimx:
                raise ValueError, "The number of spatial dimensions of x, "+\
                                    ndimx.__str__()+\
                                    ", does not match the number of spatial dimensions of the Covariance instance's base mesh, "+\
                                    self.ndim.__str__()+"."


        # If there are observation points, prepare self(obs_mesh, x)
        # and chol(self(obs_mesh, obs_mesh)).T.I * self(obs_mesh, x)



        # ==========================================================
        # = If only one argument is provided, return the diagonal. =
        # ==========================================================
        if y is None:
            # Special fast-path for functions that have an 'amp' parameter
            if hasattr(self.eval_fun, 'diag_call'):
                V = self.eval_fun.diag_call(x, **self.params)
            # Otherwise, evaluate the diagonal in a loop.
            else:
                V=empty(lenx,dtype=float)
                for i in xrange(lenx):
                    this_x = x[i].reshape((1,-1))
                    V[i] = self.eval_fun(this_x, this_x, **self.params)
            if self.observed and observed:
                sqpart = empty(lenx,dtype=float)
                Cxo = self.eval_fun(self.obs_mesh, x, **self.params)
                Uo_Cxo = trisolve(self.Uo, Cxo, uplo='U', transa='T')
                square_and_sum(Uo_Cxo, sqpart)
                V -= sqpart

            if return_Uo_Cxo:    
                return V.reshape(orig_shape), Uo_Cxo
            else:
                return V.reshape(orig_shape)

        else:

            # ====================================================
            # = # If x and y are the same array, save some work: =
            # ====================================================
            if symm:
                C=self.eval_fun(x,x,symm=True,**self.params)
                # Update return value using observations.
                if self.observed and observed:
                    Cxo = self.eval_fun(self.obs_mesh, x, **self.params)
                    Uo_Cxo = trisolve(self.Uo, Cxo, uplo='U', transa='T')
                    C -= Uo_Cxo.T * Uo_Cxo

                if return_Uo_Cxo:
                    return C, Uo_Cxo
                else:
                    return C


            # ======================================
            # = # If x and y are different arrays: =
            # ======================================
            else:

                if regularize:
                    y=regularize_array(y)

                ndimy = y.shape[-1]
                leny = y.shape[0]

                if not ndimx==ndimy:
                    raise ValueError, 'The last dimension of x and y (the number of spatial dimensions) must be the same.'

                C = self.eval_fun(x,y,**self.params)

                # Update return value using observations.
                if self.observed and observed:

                    # If there are observation points, prepare self(obs_mesh, y)
                    # and chol(self(obs_mesh, obs_mesh)).T.I * self(obs_mesh, y)
                    Cyo = self.eval_fun(self.obs_mesh, y, **self.params)
                    Uo_Cyo = trisolve(self.Uo, Cyo,uplo='U', transa='T')
                    C -= Uo_Cxo.T * Uo_Cyo

                return C
예제 #19
0
    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.'
예제 #20
0
 def _unobs_reg(self, M):
     # reg_mat = chol(self.basis_o.T * self.coef_cov * self.basis_o + diag(obs_V)).T.I * self.basis_o.T * self.coef_cov *
     # chol(self(obs_mesh_*, obs_mesh_*)).T.I * M.dev
     return self.Uo_cov.T * asmatrix(
         trisolve(self.Uo, M.dev, uplo='U', transa='T')).T
예제 #21
0
 def _obs_reg(self, M, dev_new, m_old):
     # reg_mat = chol(self.basis_o.T * self.coef_cov * self.basis_o + diag(obs_V)).T.I * self.basis_o.T * self.coef_cov *
     # chol(self(obs_mesh_*, obs_mesh_*)).T.I * M.dev
     M.reg_mat = M.reg_mat + self.Uo_cov.T * asmatrix(
         trisolve(self.Uo, dev_new, uplo='U', transa='T')).T
     return M.reg_mat
예제 #22
0
    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)]
예제 #23
0
파일: Covariance.py 프로젝트: huard/pymc
    def __call__(self, x, y=None, observed=True, regularize=True):

        if y is x:
            symm=True
        else:
            symm=False

        # Remember shape of x, and then 'regularize' it.
        orig_shape = shape(x)
        if len(orig_shape)>1:
            orig_shape = orig_shape[:-1]

        if regularize:
            x=regularize_array(x)

        ndimx = x.shape[-1]
        lenx = x.shape[0]


        # Safety
        if self.ndim is not None:
            if not self.ndim == ndimx:
                raise ValueError, "The number of spatial dimensions of x, "+\
                                    ndimx.__str__()+\
                                    ", does not match the number of spatial dimensions of the Covariance instance's base mesh, "+\
                                    self.ndim.__str__()+"."


        # If there are observation points, prepare self(obs_mesh, x)
        # and chol(self(obs_mesh, obs_mesh)).T.I * self(obs_mesh, x)
        if self.observed and observed:
            Cxo = self.eval_fun(self.obs_mesh, x, **self.params)
            Uo_Cxo = trisolve(self.Uo, Cxo, uplo='U', transa='T')


        # ==========================================================
        # = If only one argument is provided, return the diagonal. =
        # ==========================================================
        # See documentation.
        if y is None:

            # V = diag_call(x=x, cov_fun = self.diag_cov_fun)
            # =============================================================================
            # = Come up with a better solution, the diagonal is not necessarily constant. =
            # =============================================================================
            V=empty(lenx,dtype=float)
            # V.fill(self.params['amp']**2)
            for i in xrange(lenx):
                this_x = x[i].reshape((1,-1))
                V[i] = self.eval_fun(this_x, this_x,**self.params)
            if self.observed and observed:
                for i in range(lenx):
                    this_Uo_Cxo = Uo_Cxo[:,i]
                    V[i] -= this_Uo_Cxo.T*this_Uo_Cxo

            return V.reshape(orig_shape)

        else:

            # ====================================================
            # = # If x and y are the same array, save some work: =
            # ====================================================
            if symm:
                C=self.eval_fun(x,x,symm=True,**self.params)
                # Update return value using observations.
                if self.observed and observed:
                    C -= Uo_Cxo.T * Uo_Cxo
                return C


            # ======================================
            # = # If x and y are different arrays: =
            # ======================================
            else:

                if regularize:
                    y=regularize_array(y)

                ndimy = y.shape[-1]
                leny = y.shape[0]

                if not ndimx==ndimy:
                    raise ValueError, 'The last dimension of x and y (the number of spatial dimensions) must be the same.'

                C = self.eval_fun(x,y,**self.params)

                # Update return value using observations.
                if self.observed and observed:

                    # If there are observation points, prepare self(obs_mesh, y)
                    # and chol(self(obs_mesh, obs_mesh)).T.I * self(obs_mesh, y)
                    Cyo = self.eval_fun(self.obs_mesh, y, **self.params)
                    Uo_Cyo = trisolve(self.Uo, Cyo,uplo='U', transa='T')
                    C -= Uo_Cxo.T * Uo_Cyo

                return C