def test_calc_phi(self): """Performs some rudimentary tests, asserting that phi is sane.""" phi = self.sm._get_phi() self.assertLessEqual(phi.max(), 1) self.assertGreaterEqual(phi.min(), 0) self.assertEqual(np.count_nonzero(phi), (len(self.sm.dataset) - 2) * \ (self.sm._degree + 1) + 2) bf = sp.bsplinebasis(self.sm.knots, 0, self.sm._degree) self.assertEqual(phi[0, 0], 1) self.assertEqual(phi[-1, 0], 0) self.assertEqual(phi[self.sm._degree + 2, 0], 0) basis = sp.bsplinebasis(self.sm.knots, 6, self.sm._degree) values = [] for t_idx in [5, 6, 7, 8, 9]: knotrange = self.sm.knots[-1] - self.sm.knots[0] t = float(t_idx) / (len(self.sm.dataset) - 1) * knotrange self.assertEqual(phi[t_idx, 6], basis(t)) self.assertTrue(np.any(phi[5:10, 6] > 0))
def test_calc_phi(self): """Performs some rudimentary tests, asserting that phi is sane.""" phi = self.sm._get_phi() self.assertLessEqual(phi.max(), 1) self.assertGreaterEqual(phi.min(), 0) self.assertEqual(np.count_nonzero(phi), (len(self.sm.dataset) - 2) * \ (self.sm._degree + 1) + 2) bf = sp.bsplinebasis(self.sm.knots, 0, self.sm._degree) self.assertEqual(phi[0, 0], 1) self.assertEqual(phi[-1, 0], 0) self.assertEqual(phi[self.sm._degree+2, 0], 0) basis = sp.bsplinebasis(self.sm.knots, 6, self.sm._degree) values = [] for t_idx in [5, 6, 7, 8, 9]: knotrange = self.sm.knots[-1] - self.sm.knots[0] t = float(t_idx) / (len(self.sm.dataset) - 1) * knotrange self.assertEqual(phi[t_idx, 6], basis(t)) self.assertTrue(np.any(phi[5:10, 6] > 0))
def _get_roughness(self): """Calculate the "R" matrix analytically if the B-spline degree is 3, taking advantage of integration by parts and the fact that the 3rd derivative of a 3rd-degree B-spline is a constant. Further description in roughness.tex.""" p = self._degree if p != 3: return BSplineBasicSmoother._get_roughness(self) k = self._get_num_coefficients() r = np.zeros((k, k)) bases = [sp.bsplinebasis(self._knots, i, p) for i in range(k)] d1 = [sp.bsplinebasis_deriv(self._knots, i, p, 1) for i in range(k)] d2 = [sp.bsplinebasis_deriv(self._knots, i, p, 2) for i in range(k)] t = self._knots t_min = t[0] t_max = t[-1] for i in range(k): if t[i+1] > t[i]: c_0 = 6./((t[i+3] - t[i]) * (t[i+2] - t[i]) * (t[i+1] - t[i])) else: c_0 = 0 div = ((t[i+3] - t[i])*(t[i+2] - t[i])) l1 = 1. / div if div > 0 else 0 div = ((t[i+3] - t[i])*(t[i+3] - t[i+1])) l2 = 1. / div if div > 0 else 0 div = ((t[i+4] - t[i+1])*(t[i+3] - t[i+1])) l3 = 1. / div if div > 0 else 0 c_1 = - 6./(t[i+2] - t[i+1]) * (l1 + l2 + l3) if t[i+2] > t[i+1] else 0 div = ((t[i+3] - t[i])*(t[i+3] - t[i+1])) l1 = 1. / div if div > 0 else 0 div = ((t[i+4] - t[i+1])*(t[i+3] - t[i+1])) l2 = 1. / div if div > 0 else 0 div = ((t[i+4] - t[i+1])*(t[i+4] - t[i+2])) l3 = 1. / div if div > 0 else 0 c_2 = 6./(t[i+3] - t[i+2]) * (l1 + l2 + l3) if t[i+3] > t[i+2] else 0 if t[i+4] > t[i+3]: c_3 = - 6./((t[i+4] - t[i+1]) * (t[i+4] - t[i+2]) * (t[i+4] - t[i+3])) else: c_3 = 0 jmin = max(0, i - self._degree) jmax = min(k, i + self._degree + 1) for j in range(jmin, jmax): phi = bases[j] r[i, j] = d2[i](t_max) * d1[j](t_max) - d2[i](t_min) * d1[j](t_min) \ - c_0 * (phi(t[i+1]) - phi(t[i])) \ - c_1 * (phi(t[i+2]) - phi(t[i+1])) \ - c_2 * (phi(t[i+3]) - phi(t[i+2])) \ - c_3 * (phi(t[i+4]) - phi(t[i+3])) return r
def _get_phi(self): """Calculate the n*k matrix where element i,j is the value at time i of the j'th b-spline basis function. Implements eq. 5 of Chen et al.""" k = self._get_num_coefficients() n = len(self._dataset) phi = np.zeros((n, k)) bases = [sp.bsplinebasis(self._knots, i, self._degree) \ for i in range(k)] t_range = self._knots[-1] - self._knots[0] for i in range(n): for j in range(k): t = float(i) / (n - 1) * t_range phi[i, j] = bases[j](t) return phi