def log_likelihood(self, p): r"""Returns the log of the likelihood for the stored data given parameters ``p``. The likelihood is computed in time proportional to :math:`\mathcal{O}(N)`, where :math:`N` is the number of data samples. """ p = self.to_params(p) alphas, betas = self._alphas_betas(p) bc = self._banded_covariance(p) ys = self.ys.copy() - p['mu'] ys[1:] = ys[1:] - alphas*ys[0:-1] dts = self.ts.reshape((-1, 1)) - self.ts.reshape((1, -1)) tau = np.exp(p['lntau']) nu = self._inv_logit(p['logitnu']) sigma = np.exp(p['lnsigma']) full_cov = sigma*sigma*((1-nu)*np.exp(-np.abs(dts)/tau) + nu) llow = sl.cholesky_banded(bc, lower=True) logdet = np.sum(np.log(llow[0, :])) return -0.5*self.ts.shape[0]*np.log(2.0*np.pi) - logdet - 0.5*np.dot(ys, sl.cho_solve_banded((llow, True), ys))
def posterior_cov(self): r""" Posterior covariance of the states conditional on the data Notes ----- **Warning**: the matrix computed when accessing this property can be extremely large: it is shaped `(nobs * k_states, nobs * k_states)`. In most cases, it is better to use the `posterior_cov_inv_chol_sparse` property if possible, which holds in sparse diagonal banded storage the Cholesky factor of the inverse of the posterior covariance matrix. .. math:: Var[\alpha \mid Y^n ] This posterior covariance matrix is *not* identical to the `smoothed_state_cov` attribute produced by the Kalman smoother, because it additionally contains all cross-covariance terms. Instead, `smoothed_state_cov` contains the `(k_states, k_states)` block diagonal entries of this posterior covariance matrix. """ if self._posterior_cov is None: from scipy.linalg import cho_solve_banded inv_chol = self.posterior_cov_inv_chol_sparse self._posterior_cov = cho_solve_banded((inv_chol, True), np.eye(inv_chol.shape[1])) return self._posterior_cov
def cholesky_solve(a, bb): """Solve the equation :math:`A x = b` where `a` is a *lower* Cholesky-banded matrix. In the :class:`~pydl.pydlutils.bspline.Bspline` machinery, `a` needs to be padded. This function should only used with the output of :func:`~pydl.pydlutils.bspline.cholesky_band`, to ensure the proper padding on `a`. Otherwise the computation is delegated to :func:`scipy.linalg.cho_solve_banded`. Parameters ---------- a : :class:`numpy.ndarray` *Lower* Cholesky decomposition of :math:`A` in :math:`A x = b`. bb : :class:`numpy.ndarray` :math:`b` in :math:`A x = b`. Returns ------- :class:`numpy.ndarray` The solution, padded to be the same shape as `bb`. """ bw = a.shape[0] n = bb.shape[0] - bw x = np.zeros(bb.shape, dtype=bb.dtype) x[0:n] = cho_solve_banded((a[:, 0:n], True), bb[0:n]) return x
def _step(self): self.x = cho_solve_banded( (self.c, False), self.y + sum(self.ρ[i] * self.D[i].T @ (self.α[i] + self.u[i]) for i in range(self.r)), check_finite=False, ) for i in range(self.r): Dx = self.D[i] @ self.x for j in range(self.x.shape[1]): self.α[i][:, j] = ptv.tv1_1d(Dx[:, j] - self.u[i][:, j], self.λ[i] / self.ρ[i]) self.u[i] += self.α[i] - Dx
def test_lower_real(self): # Symmetric positive definite banded matrix `a` a = array([[4.0, 1.0, 0.0, 0.0], [1.0, 4.0, 0.5, 0.0], [0.0, 0.5, 4.0, 0.2], [0.0, 0.0, 0.2, 4.0]]) # Banded storage form of `a`. ab = array([[4.0, 4.0, 4.0, 4.0], [1.0, 0.5, 0.2, -1.0]]) c = cholesky_banded(ab, lower=True) lfac = zeros_like(a) lfac[list(range(4)), list(range(4))] = c[0] lfac[(1, 2, 3), (0, 1, 2)] = c[1, :3] assert_array_almost_equal(a, dot(lfac, lfac.T)) b = array([0.0, 0.5, 4.2, 4.2]) x = cho_solve_banded((c, True), b) assert_array_almost_equal(x, [0.0, 0.0, 1.0, 1.0])
def test_lower_complex(self): # Hermitian positive definite banded matrix `a` a = array([[4.0, 1.0, 0.0, 0.0], [1.0, 4.0, 0.5, 0.0], [0.0, 0.5, 4.0, -0.2j], [0.0, 0.0, 0.2j, 4.0]]) # Banded storage form of `a`. ab = array([[4.0, 4.0, 4.0, 4.0], [1.0, 0.5, 0.2j, -1.0]]) c = cholesky_banded(ab, lower=True) lfac = zeros_like(a) lfac[list(range(4)), list(range(4))] = c[0] lfac[(1, 2, 3), (0, 1, 2)] = c[1, :3] assert_array_almost_equal(a, dot(lfac, lfac.conj().T)) b = array([0.0, 0.5j, 3.8j, 3.8]) x = cho_solve_banded((c, True), b) assert_array_almost_equal(x, [0.0, 0.0, 1.0j, 1.0])
def Binvprod(self, x): """Computes the product B^(-1) * x via the Cholesky factor. Using the band Cholesky factorization of B, the matrix-vector product y is computed using scipy.linalg.cho_solve_banded to solve B * y = x. Argument: x: Vector to multiply. Returns: Matrix-vector product B^(-1) * x. """ return la.cho_solve_banded((self.sqrtBdata, True), x)
def test_upper_real(self): # Symmetric positive definite banded matrix `a` a = array([[4.0, 1.0, 0.0, 0.0], [1.0, 4.0, 0.5, 0.0], [0.0, 0.5, 4.0, 0.2], [0.0, 0.0, 0.2, 4.0]]) # Banded storage form of `a`. ab = array([[-1.0, 1.0, 0.5, 0.2], [4.0, 4.0, 4.0, 4.0]]) c = cholesky_banded(ab, lower=False) ufac = zeros_like(a) ufac[list(range(4)), list(range(4))] = c[-1] ufac[(0, 1, 2), (1, 2, 3)] = c[0, 1:] assert_array_almost_equal(a, dot(ufac.T, ufac)) b = array([0.0, 0.5, 4.2, 4.2]) x = cho_solve_banded((c, False), b) assert_array_almost_equal(x, [0.0, 0.0, 1.0, 1.0])
def test_upper_complex(self): # Hermitian positive definite banded matrix `a` a = array([[4.0, 1.0, 0.0, 0.0], [1.0, 4.0, 0.5, 0.0], [0.0, 0.5, 4.0, -0.2j], [0.0, 0.0, 0.2j, 4.0]]) # Banded storage form of `a`. ab = array([[-1.0, 1.0, 0.5, -0.2j], [4.0, 4.0, 4.0, 4.0]]) c = cholesky_banded(ab, lower=False) ufac = zeros_like(a) ufac[range(4), range(4)] = c[-1] ufac[(0, 1, 2), (1, 2, 3)] = c[0, 1:] assert_array_almost_equal(a, dot(ufac.conj().T, ufac)) b = array([0.0, 0.5, 4.0 - 0.2j, 0.2j + 4.0]) x = cho_solve_banded((c, False), b) assert_array_almost_equal(x, [0.0, 0.0, 1.0, 1.0])
def Qinvprod(self, x, i): """Product of the inverse of Q[i] with a vector x. The model error covariance matrix Q[i] is assumed to be a band matrix accessible from sqrtQdata[i], which is stored in lower form. Arguments: x: The vector to multiply. i: Index indicating which model error covariance to use. Returns: Product of the inverse of Q[i] with x. """ return la.cho_solve_banded((self.sqrtQdata[i], True), x)
def test_upper_complex(self): # Hermitian positive definite banded matrix `a` a = array([[4.0, 1.0, 0.0, 0.0], [1.0, 4.0, 0.5, 0.0], [0.0, 0.5, 4.0, -0.2j], [0.0, 0.0, 0.2j, 4.0]]) # Banded storage form of `a`. ab = array([[-1.0, 1.0, 0.5, -0.2j], [4.0, 4.0, 4.0, 4.0]]) c = cholesky_banded(ab, lower=False) ufac = zeros_like(a) ufac[range(4),range(4)] = c[-1] ufac[(0,1,2),(1,2,3)] = c[0,1:] assert_array_almost_equal(a, dot(ufac.conj().T, ufac)) b = array([0.0, 0.5, 4.0-0.2j, 0.2j + 4.0]) x = cho_solve_banded((c, False), b) assert_array_almost_equal(x, [0.0, 0.0, 1.0, 1.0])
def test_posterior_cov(self): # Test the values from the Cython results inv_chol = np.array(self._sim_cfa.posterior_cov_inv_chol, copy=True) actual = cho_solve_banded((inv_chol, True), np.eye(inv_chol.shape[1])) for t in range(self.mod.nobs): tm = t * self.mod.k_states t1m = tm + self.mod.k_states assert_allclose(actual[tm:t1m, tm:t1m], self.res.smoothed_state_cov[..., t], atol=self.cov_atol) # Test the values from the CFASimulationSmoother wrapper results actual = self.sim_cfa.posterior_cov for t in range(self.mod.nobs): tm = t * self.mod.k_states t1m = tm + self.mod.k_states assert_allclose(actual[tm:t1m, tm:t1m], self.res.smoothed_state_cov[..., t], atol=self.cov_atol)
def drawFrame(i): #print '' print 'i:',i gridT = np.reshape(T[0], (Nx, Ny)) #print 'gridT:', shape(gridT) #print gridT #print 'x:',shape(x) #print 'y:',shape(y) z = im.zoom(gridT, szmul, order=3) extent = (xi, xf, yf, yi) ax.imshow(z, extent=extent, cmap=paleta, interpolation="nearest", vmin=0.0, vmax=vmax) c1 = ax.contour(x,y,z, levels=np.arange(0.0, vmax, vmax/50.0), colors='k', vmin=0.0, vmax=vmax) c2 = ax.contourf(x,y,z, levels=np.arange(0.0, vmax, vmax/50.0), cmap=paleta, vmin=0.0, vmax=vmax) # calculando os valores para o próximo frame da animação vecB = calcNextTimeResultVec(i) #print vecB #vecR = la.solve(matA, vecB) #print 'choFacA:', choFacA vecR = la.cho_solve_banded((choA, False), vecB) #vecR = la.cho_solve(choFacA, vecB) vecR = list(vecR.flat) #print 'vecR:', vecR T[0] = vecR
def test_cho_solve_banded(self): x = array([[0, -1, -1], [2, 2, 2]]) xcho = cholesky_banded(x) assert_no_overwrite(lambda b: cho_solve_banded((xcho, False), b), [(3,)])
def make_lsq_spline(x, y, t, k=3, w=None, axis=0, check_finite=True): r"""Compute the (coefficients of) an LSQ B-spline. The result is a linear combination .. math:: S(x) = \sum_j c_j B_j(x; t) of the B-spline basis elements, :math:`B_j(x; t)`, which minimizes .. math:: \sum_{j} \left( w_j \times (S(x_j) - y_j) \right)^2 Parameters ---------- x : array_like, shape (m,) Abscissas. y : array_like, shape (m, ...) Ordinates. t : array_like, shape (n + k + 1,). Knots. Knots and data points must satisfy Schoenberg-Whitney conditions. k : int, optional B-spline degree. Default is cubic, k=3. w : array_like, shape (n,), optional Weights for spline fitting. Must be positive. If ``None``, then weights are all equal. Default is ``None``. axis : int, optional Interpolation axis. Default is zero. check_finite : bool, optional Whether to check that the input arrays contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default is True. Returns ------- b : a BSpline object of the degree `k` with knots `t`. Notes ----- The number of data points must be larger than the spline degree `k`. Knots `t` must satisfy the Schoenberg-Whitney conditions, i.e., there must be a subset of data points ``x[j]`` such that ``t[j] < x[j] < t[j+k+1]``, for ``j=0, 1,...,n-k-2``. Examples -------- Generate some noisy data: >>> x = np.linspace(-3, 3, 50) >>> y = np.exp(-x**2) + 0.1 * np.random.randn(50) Now fit a smoothing cubic spline with a pre-defined internal knots. Here we make the knot vector (k+1)-regular by adding boundary knots: >>> from scipy.interpolate import make_lsq_spline, BSpline >>> t = [-1, 0, 1] >>> k = 3 >>> t = np.r_[(x[0],)*(k+1), ... t, ... (x[-1],)*(k+1)] >>> spl = make_lsq_spline(x, y, t, k) For comparison, we also construct an interpolating spline for the same set of data: >>> from scipy.interpolate import make_interp_spline >>> spl_i = make_interp_spline(x, y) Plot both: >>> import matplotlib.pyplot as plt >>> xs = np.linspace(-3, 3, 100) >>> plt.plot(x, y, 'ro', ms=5) >>> plt.plot(xs, spl(xs), 'g-', lw=3, label='LSQ spline') >>> plt.plot(xs, spl_i(xs), 'b-', lw=3, alpha=0.7, label='interp spline') >>> plt.legend(loc='best') >>> plt.show() **NaN handling**: If the input arrays contain ``nan`` values, the result is not useful since the underlying spline fitting routines cannot deal with ``nan``. A workaround is to use zero weights for not-a-number data points: >>> y[8] = np.nan >>> w = np.isnan(y) >>> y[w] = 0. >>> tck = make_lsq_spline(x, y, t, w=~w) Notice the need to replace a ``nan`` by a numerical value (precise value does not matter as long as the corresponding weight is zero.) See Also -------- BSpline : base class representing the B-spline objects make_interp_spline : a similar factory function for interpolating splines LSQUnivariateSpline : a FITPACK-based spline fitting routine splrep : a FITPACK-based fitting routine """ x = _as_float_array(x, check_finite) y = _as_float_array(y, check_finite) t = _as_float_array(t, check_finite) if w is not None: w = _as_float_array(w, check_finite) else: w = np.ones_like(x) k = operator.index(k) if not -y.ndim <= axis < y.ndim: raise ValueError("axis {} is out of bounds".format(axis)) if axis < 0: axis += y.ndim y = np.rollaxis(y, axis) # now internally interp axis is zero if x.ndim != 1 or np.any(x[1:] - x[:-1] <= 0): raise ValueError("Expect x to be a 1-D sorted array_like.") if x.shape[0] < k+1: raise ValueError("Need more x points.") if k < 0: raise ValueError("Expect non-negative k.") if t.ndim != 1 or np.any(t[1:] - t[:-1] < 0): raise ValueError("Expect t to be a 1-D sorted array_like.") if x.size != y.shape[0]: raise ValueError('x & y are incompatible.') if k > 0 and np.any((x < t[k]) | (x > t[-k])): raise ValueError('Out of bounds w/ x = %s.' % x) if x.size != w.size: raise ValueError('Incompatible weights.') # number of coefficients n = t.size - k - 1 # construct A.T @ A and rhs with A the collocation matrix, and # rhs = A.T @ y for solving the LSQ problem ``A.T @ A @ c = A.T @ y`` lower = True extradim = prod(y.shape[1:]) ab = np.zeros((k+1, n), dtype=np.float_, order='F') rhs = np.zeros((n, extradim), dtype=y.dtype, order='F') _bspl._norm_eq_lsq(x, t, k, y.reshape(-1, extradim), w, ab, rhs) rhs = rhs.reshape((n,) + y.shape[1:]) # have observation matrix & rhs, can solve the LSQ problem cho_decomp = cholesky_banded(ab, overwrite_ab=True, lower=lower, check_finite=check_finite) c = cho_solve_banded((cho_decomp, lower), rhs, overwrite_b=True, check_finite=check_finite) c = np.ascontiguousarray(c) return BSpline.construct_fast(t, c, k, axis=axis)
def l2appr(n_dim, K, vec_timestamps, vec_obs, numObs, knots, weight): # CONSTRUCTS THE (WEIGHTED DISCRETE) L2-APPROXIMATION BY SPLINES OF ORDER # K WITH KNOT SEQUENCE T(1), .., T(N+K) TO GIVEN DATA POINTS # (TAU(I),GTAU(I)), I=1,...,NTAU. THE B-SPLINE COEFFICIENTS # B C O E F OF THE APPROXIMATING SPLINE ARE DETERMINED FROM THE # NORMAL EQUATIONS USING CHOLESKY'S METHOD. # n_dim : dimension of the B-spline space # K : order # numObs : number of data points # number of knots = n_dim + K bcoeff = np.asarray([0.0 for i in range(n_dim)]) biatx = np.asarray([0.0 for i in range(K)]) Q = np.zeros((K, n_dim)) left_py = K - 1 leftmk_py = -1 # left - K # Note that left cors. to the index of the knot just left of x, by Dr. Watson's notes indices. # The knots t run from t_1 to t_{n_dim+K}. # The python vector t will, however, go from 0 to n_dim+K-1. # t_1 is stored at location t[0]. # t_2 is stored at location t[1]. # t_K is stored at location t[K-1] # t[i] is stored at location t[i-1]. # If we identify an index 'left' st. t[left] < x < t[left+1], then # x is actually in between t_{left} and t_{left+1} for ll in range(0, numObs): # print 'll =', ll, 'x_ll =', vec_timestamps[ll], # print 'knots[left_py]', knots[left_py], 'vec_timestamps[ll] >= knots[left_py]', vec_timestamps[ll] >= knots[left_py] # corner case if (left_py == n_dim - 1) or (vec_timestamps[ll] < knots[left_py + 1]): # we want: vec_timestamps(ll) \in (knots(left_fort) , knots(left_fort+1)) # i.e., vec_timestamps(ll) \in (knots(left_py - 1) , knots(left_py)) # call bsplvb directly left_fort = left_py + 1 biatx[0:K + 1] = bsplvb(knots, K, 1, vec_timestamps[ll], left_fort) else: # Locate left st. vec_timestamps(ll) \in (knots(left_fort) , knots(left_fort+1)) # i.e., vec_timestamps(ll) \in (knots(left_py - 1) , knots(left_py)) while (vec_timestamps[ll] >= knots[left_py + 1]): left_py += 1 leftmk_py += 1 # now call bsplvb left_fort = left_py + 1 biatx[0:K + 1] = bsplvb(knots, K, 1, vec_timestamps[ll], left_fort) # BIATX(MM-1) (originally, BIATX(MM) in Fortran) # CONTAINS THE VALUE OF B(LEFT-K+MM), MM = 1,2,...,K, AT TAU(LL). # HENCE, WITH DW := BIATX(MM-1)*WEIGHT(LL), (originally, BIATX(MM)*WEIGHT(LL) in Fortran) # THE NUMBER DW*GTAU(LL) # IS A SUMMAND IN THE INNER PRODUCT # (B(LEFT-K+MM),G) WHICH GOES INTO BCOEF(LEFT-K+MM-1) (originally, BCOEF(LEFT-K+MM) in Fortran) # AND THE NUMBER BIATX(JJ)*DW IS A SUMMAND IN THE INNER PRODUCT # (B(LEFT-K+JJ),B(LEFT-K+MM)), INTO Q(JJ-MM+1,LEFT-K+MM) # SINCE (LEFT-K+JJ) - (LEFT-K+MM) + 1 = JJ - MM + 1 . # Solving: min || Ax - b || # So, we solve: A^tA x = A^t b # # Entries of A^t A: # # --- # \ # [AtA]_{ij} = B_i(x_l) * B_j(x_j) * w(l) # / # --- # i,j= # # AtA is a symmetric banded matrix due to local support of B-splines. # No point storing (or even calculating) all entries. # Only nonzero entries are calculated. # # Entries of A^t b: # for mm in range(1, K + 1): dw = biatx[mm - 1] * weight[ll] j = (leftmk_py + 1) + mm # The rhs < A^t, b > bcoeff[j - 1] = dw * vec_obs[ll] + bcoeff[j - 1] i = 1 for jj in range(mm, K + 1): Q[i - 1, j - 1] = biatx[jj - 1] * dw + Q[ i - 1, j - 1] # j is fixed for currnt x_ll and current mm. # only i and jj are incrementing. # Q[*, j-1] is getting filled. # Then mm increments. j will also increment. # Q[*, j_old+1] will get filled. # # Then next x_ll comes in. # Suppose x_ll is in the same knot interval. # mm will still run from 1 to K. # j, by formula, will again take same values as previous loop. # So same columns of Q will get updated. # i will also take same values as previous ll-loop. # So, same rows of Q will update. # Essentially, for fixed [left, left+1), same entries # of Q will update. # # Suppose x_ll is in a different interval. # i.e., left is different, say, left_new = left_old+1 # Then, j takes 1 higher values than prevoius ll-loops. # Meaning, a new (1 up) set of columns is filled. # mm and K are always same. So each row is filled again, # just in a different column. # That's the story of 'matrix filling' here. # Figure out the actual working of bandedness etc. -- TODO. i += 1 # Get the CHOLESKY FACTORIZATION FOR banded matrix Q, THEN USE # IT TO SOLVE THE NORMAL EQUATIONS # C*X = BCOEF # FOR X , AND STORE X IN BCOEF # print 'In l2appr' # print 'n_dim =', n_dim # with open("ltr_python_output.csv", "a") as fh: # fh.write('writing Q:' + '\n') # for i in range(K): # fh.write(' '.join([str(Q[i, col]) for col in range(n_dim)] ) + '\n ') # fh.close() cb = la.cholesky_banded(Q, overwrite_ab=False, lower=True, check_finite=True) bcoeff = la.cho_solve_banded((cb, True), bcoeff, overwrite_b=True, check_finite=True) return bcoeff
def make_lsq_spline(x, y, t, k=3, w=None, axis=0, check_finite=True): r"""Compute the (coefficients of) an LSQ B-spline. The result is a linear combination .. math:: S(x) = \sum_j c_j B_j(x; t) of the B-spline basis elements, :math:`B_j(x; t)`, which minimizes .. math:: \sum_{j} \left( w_j \times (S(x_j) - y_j) \right)^2 Parameters ---------- x : array_like, shape (m,) Abscissas. y : array_like, shape (m, ...) Ordinates. t : array_like, shape (n + k + 1,). Knots. Knots and data points must satisfy Schoenberg-Whitney conditions. k : int, optional B-spline degree. Default is cubic, k=3. w : array_like, shape (n,), optional Weights for spline fitting. Must be positive. If ``None``, then weights are all equal. Default is ``None``. axis : int, optional Interpolation axis. Default is zero. check_finite : bool, optional Whether to check that the input arrays contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default is True. Returns ------- b : a BSpline object of the degree `k` with knots `t`. Notes ----- The number of data points must be larger than the spline degree `k`. Knots `t` must satisfy the Schoenberg-Whitney conditions, i.e., there must be a subset of data points ``x[j]`` such that ``t[j] < x[j] < t[j+k+1]``, for ``j=0, 1,...,n-k-2``. Examples -------- Generate some noisy data: >>> x = np.linspace(-3, 3, 50) >>> y = np.exp(-x**2) + 0.1 * np.random.randn(50) Now fit a smoothing cubic spline with a pre-defined internal knots. Here we make the knot vector (k+1)-regular by adding boundary knots: >>> from scipy.interpolate import make_lsq_spline, BSpline >>> t = [-1, 0, 1] >>> k = 3 >>> t = np.r_[(x[0],)*(k+1), ... t, ... (x[-1],)*(k+1)] >>> spl = make_lsq_spline(x, y, t, k) For comparison, we also construct an interpolating spline for the same set of data: >>> from scipy.interpolate import make_interp_spline >>> spl_i = make_interp_spline(x, y) Plot both: >>> import matplotlib.pyplot as plt >>> xs = np.linspace(-3, 3, 100) >>> plt.plot(x, y, 'ro', ms=5) >>> plt.plot(xs, spl(xs), 'g-', lw=3, label='LSQ spline') >>> plt.plot(xs, spl_i(xs), 'b-', lw=3, alpha=0.7, label='interp spline') >>> plt.legend(loc='best') >>> plt.show() **NaN handling**: If the input arrays contain ``nan`` values, the result is not useful since the underlying spline fitting routines cannot deal with ``nan``. A workaround is to use zero weights for not-a-number data points: >>> y[8] = np.nan >>> w = np.isnan(y) >>> y[w] = 0. >>> tck = make_lsq_spline(x, y, t, w=~w) Notice the need to replace a ``nan`` by a numerical value (precise value does not matter as long as the corresponding weight is zero.) See Also -------- BSpline : base class representing the B-spline objects make_interp_spline : a similar factory function for interpolating splines LSQUnivariateSpline : a FITPACK-based spline fitting routine splrep : a FITPACK-based fitting routine """ x = _as_float_array(x, check_finite) y = _as_float_array(y, check_finite) t = _as_float_array(t, check_finite) if w is not None: w = _as_float_array(w, check_finite) else: w = np.ones_like(x) k = operator.index(k) axis = normalize_axis_index(axis, y.ndim) y = np.rollaxis(y, axis) # now internally interp axis is zero if x.ndim != 1 or np.any(x[1:] - x[:-1] <= 0): raise ValueError("Expect x to be a 1-D sorted array_like.") if x.shape[0] < k + 1: raise ValueError("Need more x points.") if k < 0: raise ValueError("Expect non-negative k.") if t.ndim != 1 or np.any(t[1:] - t[:-1] < 0): raise ValueError("Expect t to be a 1-D sorted array_like.") if x.size != y.shape[0]: raise ValueError('x & y are incompatible.') if k > 0 and np.any((x < t[k]) | (x > t[-k])): raise ValueError('Out of bounds w/ x = %s.' % x) if x.size != w.size: raise ValueError('Incompatible weights.') # number of coefficients n = t.size - k - 1 # construct A.T @ A and rhs with A the collocation matrix, and # rhs = A.T @ y for solving the LSQ problem ``A.T @ A @ c = A.T @ y`` lower = True extradim = prod(y.shape[1:]) ab = np.zeros((k + 1, n), dtype=np.float_, order='F') rhs = np.zeros((n, extradim), dtype=y.dtype, order='F') _bspl._norm_eq_lsq(x, t, k, y.reshape(-1, extradim), w, ab, rhs) rhs = rhs.reshape((n, ) + y.shape[1:]) # have observation matrix & rhs, can solve the LSQ problem cho_decomp = cholesky_banded(ab, overwrite_ab=True, lower=lower, check_finite=check_finite) c = cho_solve_banded((cho_decomp, lower), rhs, overwrite_b=True, check_finite=check_finite) c = np.ascontiguousarray(c) return BSpline.construct_fast(t, c, k, axis=axis)
def linear_map(self, x): if not self.banded: return cho_solve(self._cholesky, x) else: return cho_solve_banded(self._cholesky, x)