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_roughness(self): """Calculate the "R" matrix as the product of the second derivative of the basis functions with its transpose, integrated over time. Returns a k*k matrix, where k is the number of basis functions (i.e. the number of coefficients). Implements eq. 10 of Chen et al.""" k = self._get_num_coefficients() r = np.zeros((k, k)) p = self._degree d2 = [sp.bsplinebasis_deriv(self._knots, i, p, 2) for i in range(k)] t_min = self._knots[0] t_max = self._knots[-1] for i in range(k): jmin = max(0, i - self._degree) jmax = min(k, i + self._degree + 1) for j in range(jmin, jmax): discont = self._knots[min(i, j):max(i, j) + self._degree + 1] y, err = scipy.integrate.quad(lambda t: d2[i](t) * d2[j](t), t_min, t_max, points=discont) r[i, j] = y return r