def test_basis_element_quadratic(self): xx = np.linspace(-1, 4, 20) b = BSpline.basis_element(t=[0, 1, 2, 3]) assert_allclose(b(xx), splev(xx, (b.t, b.c, b.k)), atol=1e-14) assert_allclose(b(xx), B_0123(xx), atol=1e-14) b = BSpline.basis_element(t=[0, 1, 1, 2]) xx = np.linspace(0, 2, 10) assert_allclose(b(xx), np.where(xx < 1, xx * xx, (2. - xx)**2), atol=1e-14)
def test_basis_element_quadratic(self): xx = np.linspace(-1, 4, 20) b = BSpline.basis_element(t=[0, 1, 2, 3]) assert_allclose(b(xx), splev(xx, (b.t, b.c, b.k)), atol=1e-14) assert_allclose(b(xx), B_0123(xx), atol=1e-14) b = BSpline.basis_element(t=[0, 1, 1, 2]) xx = np.linspace(0, 2, 10) assert_allclose(b(xx), np.where(xx < 1, xx*xx, (2.-xx)**2), atol=1e-14)
def _get_cubic_BSplines(interior_knots): """ given a set of interior knots, compute the bspline basis functions required to give a periodic spline model. data are assumed to be distributed across the unit period, and therefore the interior knots must be within the unit interval. boundary knots (ie. 0, 1) must not be provided. knots must be sorted into ascending order. cubic spline knots are assumed, meaning at least three interior knots must be provided. interior_knots : 1d array 1d array of interior knots, sorted from smallest to largest """ # Check everything is okay interior_knots = np.array(interior_knots) if not np.all(np.logical_and(interior_knots >= 0, interior_knots <= 1)): raise ValueError("Interior knots must be distributed across the unit period") if interior_knots.ndim != 1: raise ValueError("Knot array must be one-dimensional") if interior_knots.size < 3: raise ValueError("Must have at least three interior knots for cubic splines") full_knots = _get_full_knots(interior_knots) # Produce list of spline elements return [ BSpline.basis_element(full_knots[i : i + 5], extrapolate=False) for i in range(full_knots.size - 4) ]
def update(self): self.basis = [] x = np.append(self.c[0], self.c[0, 0:ORDER]) y = np.append(self.c[1], self.c[1, 0:ORDER]) self.c_periodic = np.array([x, y]) self.n_c_periodic = len(x) for i in range(self.n_c_periodic): self.basis.append( BSpline.basis_element(self.t[i:i + ORDER + 2], False)) self.bsplx = BSpline(self.t, x, ORDER, False) self.bsply = BSpline(self.t, y, ORDER, False) self.derx1 = self.bsplx.derivative(1) self.dery1 = self.bsply.derivative(1) self.derx2 = self.bsplx.derivative(2) self.dery2 = self.bsply.derivative(2) # Sample some values self.sample_nb = NB_POINTS_BSPL self.sample_t = np.linspace(self.t_min, self.t_max, self.sample_nb, endpoint=True) self.sample_values = np.zeros((self.sample_nb, 2)) for i in range(self.sample_nb): self.sample_values[i] = self.estimate(self.sample_t[i])
def test_integral(self): b = BSpline.basis_element([0, 1, 2]) # x for x < 1 else 2 - x assert_allclose(b.integrate(0, 1), 0.5) assert_allclose(b.integrate(1, 0), -0.5) # extrapolate or zeros outside of [0, 2]; default is yes assert_allclose(b.integrate(-1, 1), 0) assert_allclose(b.integrate(-1, 1, extrapolate=True), 0) assert_allclose(b.integrate(-1, 1, extrapolate=False), 0.5)
def _sum_basis_elements(x, t, c, k): n = len(t) - (k + 1) assert n >= k + 1 assert len(c) >= n s = 0. for i in range(n): b = BSpline.basis_element(t[i:i + k + 2], extrapolate=False)(x) s += c[i] * np.nan_to_num(b) # zero out out-of-bounds elements return s
def _sum_basis_elements(x, t, c, k): n = len(t) - (k+1) assert n >= k+1 assert len(c) >= n s = 0. for i in range(n): b = BSpline.basis_element(t[i:i+k+2], extrapolate=False)(x) s += c[i] * np.nan_to_num(b) # zero out out-of-bounds elements return s
def test_integral(self): b = BSpline.basis_element([0, 1, 2]) # x for x < 1 else 2 - x assert_allclose(b.integrate(0, 1), 0.5) assert_allclose(b.integrate(1, 0), -0.5) # extrapolate or zeros outside of [0, 2]; default is yes assert_allclose(b.integrate(-1, 1), 0) assert_allclose(b.integrate(-1, 1, extrapolate=True), 0) assert_allclose(b.integrate(-1, 1, extrapolate=False), 0.5)
def mySpline(n, L=100): # This function returns a normalized B-spline of degree n # L:int support length # a:int represents the dilation factor # expand:int length of the signal to expand to n = int(n) b = BSpline.basis_element(range(n + 1), 0) return b, (0, n), L
def mySpline(n, L=100, plot=1): #return normalize splines of degree n and length L n = int(n) b = BSpline.basis_element(range(n + 1), 0) x = np.linspace(0, n, L) y = np.fft.fftshift(normalize(b(x))[0]) if plot: plt.plot(range(L), y, 'g', lw=3) return b, y
def Bmatspl(x, knots=None, q=3): ''' Builds the B-matrix (design matrix) with b-splines as basis elements Input: ------ x -> values at which the b-spline functions are evaluated knots -> 1-D numpy array with the internal knots for total spline q -> degree of every b-spline in the linear combination Output: ------- splreg -> Splines (linear expansion) ''' if knots is None: # default definition of internal knots (equispaced along the data set interval) knots = np.linspace(x[0], x[-1], len(x) // 3, endpoint=True)[1:-1] nknots = len(knots) # number of internal knots of total spline nbsplines = nknots + q + 1 # number of b-splines in the basis set # add knots at external points of the interval spknots = np.insert(knots, 0, [x[0], x[0], x[0], x[0]]) spknots = np.append( spknots, [x[-1] + 1e-10, x[-1] + 1e-10, x[-1] + 1e-10, x[-1] + 1e-10]) a = np.ones( nbsplines) # coefficients of the b-splines in the linear expansion # build the B matrix. Their elements are the values of every b-spline at every data point ### B is a 2-D numpy array: [(number of points in x) x (number of bsplines)] spl = BSpline(t=spknots, c=a, k=q) B = spl.basis_element(spknots[0:q + 2], extrapolate=None)(x).reshape(-1, 1) for i in range(1, nbsplines): Bnew = spl.basis_element(spknots[i:i + q + 2], extrapolate=None)(x).reshape(-1, 1) B = np.hstack((B, Bnew)) B = np.nan_to_num(B, copy=False) return B
def __init__(self, domain, n_basis, locs_bounds, width=1.0, bounds_disc=False, order=3, add_constant=True): self.locs_bounds = locs_bounds self.bounds_disc = bounds_disc self.order = order self.width = width self.knots = BSplineUniscaleBasis.knots_generator(domain, n_basis, locs_bounds, width, bounds_disc, order) self.splines = [falgebra.NoNanWrapper(BSpline.basis_element(self.knots[i], extrapolate=False)) for i in range(len(self.knots))] self.add_constant = add_constant self.norms = [np.sqrt(integration.func_scalar_prod(sp, sp, domain)) for sp in self.splines] # self.norms = [np.sqrt(integration.func_scalar_prod(sp, sp, domain)[0]) for sp in self.splines] input_dim = 1 super().__init__(n_basis + int(self.add_constant), input_dim, domain) self.gram_mat = self.gram_matrix()
def get_bases(rmin, rmax, nbins, order=None, ncont=1000): if not order: print("No order given, defaulting to 1 (linear)") if nbins < order * 2: # does it have to be 2*order + 1? seems fine for piecewise, but for higher orders? raise ValueError("nbins must be at least twice the order") kvs = get_kvs(rmin, rmax, nbins, order) rcont = np.linspace(rmin, rmax, ncont) bases = np.empty((nbins + 1, ncont)) bases[0, :] = rcont for n in range(nbins): kv = kvs[n] b = BSpline.basis_element(kv) bases[n + 1, :] = [b(r) if kv[0] <= r <= kv[-1] else 0 for r in rcont] return bases
def spline_bases(rmin, rmax, projfn, ncomponents, ncont=2000, order=3): ''' Compute a set of spline basis functions for the given order. Parameters ---------- rmin : double Minimum r-value for basis functions rmax : double Maximum r-value for basis functions projfn : string, default=None Path to projection file if necessary ncomponents : int Number of components (basis functions) ncont : int, default=2000 Number of continuous r-values at which to write the basis function file order : int, default=3 Order of spline to use; default is cubic spline Returns ------- bases: array-like, double 2-d array of basis function values; first column is r-values ''' if ncomponents < order * 2: raise ValueError("ncomponents must be at least twice the order") kvs = _get_knot_vectors(rmin, rmax, ncomponents, order) rcont = np.linspace(rmin, rmax, ncont) bases = np.empty((ncont, ncomponents + 1)) bases[:, 0] = rcont for n in range(ncomponents): kv = kvs[n] b = BSpline.basis_element(kv) bases[:, n + 1] = [b(r) if kv[0] <= r <= kv[-1] else 0 for r in rcont] np.savetxt(projfn, bases) return bases
def phi(x, t, i, k): """ A basis function x : float or array evaluation point t : array mesh nodes i : int basis id k : int basis degree """ b = BSpline.basis_element(t[i:i + k + 2], extrapolate=False) s = np.nan_to_num(b(x)) return s
def test_integral(self): b = BSpline.basis_element([0, 1, 2]) # x for x < 1 else 2 - x assert_allclose(b.integrate(0, 1), 0.5) assert_allclose(b.integrate(1, 0), -1 * 0.5) assert_allclose(b.integrate(1, 0), -0.5) # extrapolate or zeros outside of [0, 2]; default is yes assert_allclose(b.integrate(-1, 1), 0) assert_allclose(b.integrate(-1, 1, extrapolate=True), 0) assert_allclose(b.integrate(-1, 1, extrapolate=False), 0.5) assert_allclose(b.integrate(1, -1, extrapolate=False), -1 * 0.5) # Test ``_fitpack._splint()`` t, c, k = b.tck assert_allclose(b.integrate(1, -1, extrapolate=False), _splint(t, c, k, 1, -1)[0]) # Test ``extrapolate='periodic'``. b.extrapolate = 'periodic' i = b.antiderivative() period_int = i(2) - i(0) assert_allclose(b.integrate(0, 2), period_int) assert_allclose(b.integrate(2, 0), -1 * period_int) assert_allclose(b.integrate(-9, -7), period_int) assert_allclose(b.integrate(-8, -4), 2 * period_int) assert_allclose(b.integrate(0.5, 1.5), i(1.5) - i(0.5)) assert_allclose(b.integrate(1.5, 3), i(1) - i(0) + i(2) - i(1.5)) assert_allclose(b.integrate(1.5 + 12, 3 + 12), i(1) - i(0) + i(2) - i(1.5)) assert_allclose(b.integrate(1.5, 3 + 12), i(1) - i(0) + i(2) - i(1.5) + 6 * period_int) assert_allclose(b.integrate(0, -1), i(0) - i(1)) assert_allclose(b.integrate(-9, -10), i(0) - i(1)) assert_allclose(b.integrate(0, -9), i(1) - i(2) - 4 * period_int)
def test_integral(self): b = BSpline.basis_element([0, 1, 2]) # x for x < 1 else 2 - x assert_allclose(b.integrate(0, 1), 0.5) assert_allclose(b.integrate(1, 0), -1 * 0.5) assert_allclose(b.integrate(1, 0), -0.5) # extrapolate or zeros outside of [0, 2]; default is yes assert_allclose(b.integrate(-1, 1), 0) assert_allclose(b.integrate(-1, 1, extrapolate=True), 0) assert_allclose(b.integrate(-1, 1, extrapolate=False), 0.5) assert_allclose(b.integrate(1, -1, extrapolate=False), -1 * 0.5) # Test ``_fitpack._splint()`` t, c, k = b.tck assert_allclose(b.integrate(1, -1, extrapolate=False), _splint(t, c, k, 1, -1)[0]) # Test ``extrapolate='periodic'``. b.extrapolate = 'periodic' i = b.antiderivative() period_int = i(2) - i(0) assert_allclose(b.integrate(0, 2), period_int) assert_allclose(b.integrate(2, 0), -1 * period_int) assert_allclose(b.integrate(-9, -7), period_int) assert_allclose(b.integrate(-8, -4), 2 * period_int) assert_allclose(b.integrate(0.5, 1.5), i(1.5) - i(0.5)) assert_allclose(b.integrate(1.5, 3), i(1) - i(0) + i(2) - i(1.5)) assert_allclose(b.integrate(1.5 + 12, 3 + 12), i(1) - i(0) + i(2) - i(1.5)) assert_allclose(b.integrate(1.5, 3 + 12), i(1) - i(0) + i(2) - i(1.5) + 6 * period_int) assert_allclose(b.integrate(0, -1), i(0) - i(1)) assert_allclose(b.integrate(-9, -10), i(0) - i(1)) assert_allclose(b.integrate(0, -9), i(1) - i(2) - 4 * period_int)
# Construct a cubic b-spline: from scipy.interpolate import BSpline b = BSpline.basis_element([0, 1, 2, 3, 4]) k = b.k b.t[k:-k] # array([ 0., 1., 2., 3., 4.]) k # 3 # Construct a second order b-spline on ``[0, 1, 1, 2]``, and compare # to its explicit form: t = [-1, 0, 1, 1, 2] b = BSpline.basis_element(t[1:]) def f(x): return np.where(x < 1, x * x, (2. - x)**2) import matplotlib.pyplot as plt fig, ax = plt.subplots() x = np.linspace(0, 2, 51) ax.plot(x, b(x), 'g', lw=3) ax.plot(x, f(x), 'r', lw=8, alpha=0.4) ax.grid(True) plt.show()
# # # fig = plt.figure() # # ax = fig.add_subplot(211) # plt.plot(t, x, "-og") # plt.plot(ipl_t, x_i, "r") # plt.xlim([0.0, max(t)]) # plt.title("Splined x(t)") # # ax = fig.add_subplot(212) # for i in range(n_points - degree - 1): # vec = np.zeros(11) # vec[i] = 1.0 # x_list = list(x_tup) # x_list[1] = vec.tolist() # x_i = si.splev(ipl_t, x_list) # plt.plot(ipl_t, x_i) # plt.xlim([0.0, 9.0]) # plt.title("Periodic basis splines") # # plt.show() from scipy.interpolate import BSpline import numpy from matplotlib import pyplot b = BSpline.basis_element([1, 2, 5, 6, 8, 12]) x = numpy.linspace(1, 12, 100) pyplot.plot(x, b(x)) pyplot.show()
def test_nan(self): # nan in, nan out. b = BSpline.basis_element([0, 1, 1, 2]) assert_(np.isnan(b(np.nan)))
def compute_bspline_integral_dot_product(basis_features, basis_dimension): """ Compute integrals and dot products of B-splines. Input: - basis_features: dict Contain information on the basis for each state - basis_dimension: dict Give the number of basis functions for each state Outputs: - integral: ndarray Array containing the integrals over an interval - dot_product: ndarray Matrix containing the dot products """ # Compute the dimension of the problem dimension = np.sum([basis_dimension[elt] for elt in basis_dimension]) # Get the knots t = basis_features['knots'] # FIXME: Consider small parameter to avoid vanishing of the last B-spline # at 1 eps = 1e-16 # Define integrals using antiderivatives integral = np.zeros(dimension) i0 = 0 # Loop over states for state in basis_dimension: # Get degree of the B-splines of state k_state = basis_features[state] # Add external knots depending on the degree t_state = np.r_[(0, ) * (k_state + 1), t, (1, ) * (k_state + 1)] for i in range(basis_dimension[state]): # Define i-th B-spline spl_i = BSpline.basis_element(t_state[i:i + k_state + 2]) # Integrate and deduce integral spl_i_int = spl_i.antiderivative(nu=1) integral[i0 + i] += spl_i_int(t_state[i + k_state + 1] - eps) integral[i0 + i] -= spl_i_int(t_state[i]) i0 += basis_dimension[state] # Compute dot product between the B-splines dot_product = np.zeros([dimension, dimension]) i, j = 0, 0 # Loop over states for state1 in basis_dimension: # Get degree of the B-splines of state1 k1 = basis_features[state1] # Add external knots depending on the degree t1 = np.r_[(0, ) * (k1 + 1), t, (1, ) * (k1 + 1)] for state2 in basis_dimension: # Get degree of the B-splines of state2 k2 = basis_features[state2] # Add external knots depending on the degree t2 = np.r_[(0, ) * (k2 + 1), t, (1, ) * (k2 + 1)] for m in range(basis_dimension[state1]): # Define m-th B-spline of the state1 basis spl_m = BSpline.basis_element(t1[m:m + k1 + 2]) for n in range(basis_dimension[state2]): # Define n-th B-spline of the state2 basis spl_n = BSpline.basis_element(t2[n:n + k2 + 2]) max_t = max(t1[m], t2[n]) min_t = min(t1[m + k1 + 1], t2[n + k2 + 1]) # If intersection of supports then do computations if max_t < min_t: # Numerical integration quad_int = quad(lambda x: spl_m(x) * spl_n(x), max_t, min_t) dot_product[i + m, j + n] += quad_int[0] j += basis_dimension[state2] j = 0 i += basis_dimension[state1] return integral, dot_product
def compute_bspline_dot_product_derivatives(basis_features, basis_dimension): """ Compute dot products of B-splines and their derivatives. Input: - basis_features: dict Contain information on the basis for each state - basis_dimension: dict Give the number of basis functions for each state Outputs: - dot_product_12: ndarray Array containing the dot products of Legendre polynomials with their derivatives - dot_product_22: ndarray Array containing the dot products of Legendre polynomials derivatives """ # Compute the dimension of the problem dimension = np.sum([basis_dimension[elt] for elt in basis_dimension]) # Get the knots t = basis_features['knots'] # FIXME: Consider small parameter to avoid vanishing of the last B-spline # at 1 eps = 1e-16 dot_product_12 = np.zeros([dimension, dimension]) dot_product_22 = np.zeros([dimension, dimension]) i, j = 0, 0 # Loop over states for state1 in basis_dimension: # Get degree of the B-splines of state1 k1 = basis_features[state1] # Add external knots depending on the degree t1 = np.r_[(0, ) * (k1 + 1), t, (1, ) * (k1 + 1)] for state2 in basis_dimension: # Get degree of the B-splines of state2 k2 = basis_features[state2] # Add external knots depending on the degree t2 = np.r_[(0, ) * (k2 + 1), t, (1, ) * (k2 + 1)] for m in range(basis_dimension[state1]): # Define m-th B-spline of the state1 basis spl_m = BSpline.basis_element(t1[m:m + k1 + 2]) # Reproduce the same spline for differenciation because of # differenciation problems with BSpline.basis_element() # FIXME: simplify if possible # Construct knots by first finding the internal knots and then # by adding the right numbers of external knots t1m = t1[m:m + k1 + 2] ind_min1 = np.max(np.argwhere(t1m == t1[m])) ind_max1 = np.min(np.argwhere(t1m == t1[m + k1 + 1])) t_m = np.r_[(t1m[ind_min1], ) * k1, t1m[ind_min1:ind_max1 + 1], (t1m[ind_max1], ) * k1] x_m = np.linspace(t1m[0], t1m[-1] - eps, 50) spl_m = make_lsq_spline(x_m, spl_m(x_m), t_m, k1) # Compute derivative spl_m_deriv = spl_m.derivative(nu=1) for n in range(basis_dimension[state2]): # Define n-th B-spline of the state2 basis spl_n = BSpline.basis_element(t2[n:n + k2 + 2]) # FIXME: simplify if possible # Construct knots by first finding the internal knots and # then by adding the right numbers of external knots t2n = t2[n:n + k2 + 2] ind_min2 = np.max(np.argwhere(t2n == t2[n])) ind_max2 = np.min(np.argwhere(t2n == t2[n + k2 + 1])) t_n = np.r_[(t2n[ind_min2], ) * k2, t2n[ind_min2:ind_max2 + 1], (t2n[ind_max2], ) * k2] x_n = np.linspace(t2n[0], t2n[-1] - eps, 50) spl_n = make_lsq_spline(x_n, spl_n(x_n), t_n, k2) # Compute derivative spl_n_deriv = spl_n.derivative(nu=1) max_t = max(t1[m], t2[n]) min_t = min(t1[m + k1 + 1], t2[n + k2 + 1]) # If intersection of supports then do computations if max_t < min_t: # Numerical integration quad_int_12 = quad(lambda x: spl_m(x) * spl_n_deriv(x), max_t, min_t) quad_int_22 = quad( lambda x: spl_m_deriv(x) * spl_n_deriv(x), max_t, min_t) dot_product_12[i + m, j + n] += quad_int_12[0] dot_product_22[i + m, j + n] += quad_int_22[0] j += basis_dimension[state2] j = 0 i += basis_dimension[state1] return dot_product_12, dot_product_22
def spl(x): y = BSpline.basis_element(knots, extrapolate=False)(x) y[np.isnan(y)] = 0 return y
def test_nan(self): # nan in, nan out. b = BSpline.basis_element([0, 1, 1, 2]) assert_(np.isnan(b(np.nan)))
# Construct the linear spline ``x if x < 1 else 2 - x`` on the base # interval :math:`[0, 2]`, and integrate it from scipy.interpolate import BSpline b = BSpline.basis_element([0, 1, 2]) b.integrate(0, 1) # array(0.5) # If the integration limits are outside of the base interval, the result # is controlled by the `extrapolate` parameter b.integrate(-1, 1) # array(0.0) b.integrate(-1, 1, extrapolate=False) # array(0.5) import matplotlib.pyplot as plt fig, ax = plt.subplots() ax.grid(True) ax.axvline(0, c='r', lw=5, alpha=0.5) # base interval ax.axvline(2, c='r', lw=5, alpha=0.5) xx = [-1, 1, 2] ax.plot(xx, b(xx)) plt.show()
splw = BSpline(kv, waver, k) #spline wr tplot = np.arange(0, kv.max(), 0.1) #tplot *= 1.0/tplot.max() rbspline = splr(tplot) waverbspline = splw(tplot) #plt.plot(r,waver,'bo') #plt.plot(r,waver,'k') #plt.plot(rbspline,waverbspline,'r') #axes = plt.gca() #axes.set_xlim([0,20]) #axes.set_ylim([0,0.2]) #plt.show() ## basis element k = 4 for i in range(len(kv) - k - 2): b = BSpline.basis_element(kv[i + 1:i + k + 2]) print(b) print(kv[i + 1:i + k + 2]) x = np.linspace(kv[i + 1], kv[i + k + 2], 51) print(x) plt.plot(x, b(x)) plt.show() #plt.plot(r,waver) #plt.show()
import matplotlib.pyplot as plt from scipy.interpolate import splprep, BSpline if __name__ == '__main__': # Initialize the spline c = np.array([100, 100]) R = 50 n = 10 phi = np.linspace(0, 2 * np.pi, n) x_init = c[0] + R * np.cos(phi) y_init = c[1] + R * np.sin(phi) x_init[n - 1] = x_init[0] y_init[n - 1] = y_init[0] dat = np.array([x_init, y_init]) tck, _ = splprep(dat, s=0, per=0, k=3) knots = tck[0] ctrl_pts = np.transpose(tck[1]) deg = tck[2] spl = BSpline(knots, ctrl_pts, deg) fig, ax = plt.subplots() # Compute the value of each basis function for knot_ind in np.arange(len(knots)): knots_basis = spl.t[knot_ind:knot_ind + deg + 2] b = spl.basis_element(knots_basis, extrapolate=False) x = np.linspace(knots_basis[0], knots_basis[-1], 50) ax.plot(x, b(x), lw=3) ax.plot([knots_basis[0]] * 2, [0, 1], 'k--') plt.xlabel('Noeud') plt.title('Valeur de fonction de base en fonction de u') plt.show()
def d_bump_cbs(x): dy = np.zeros_like(x) index = (-2 < x) & (x < 2) dy[index] = BSpline.basis_element([-2, -1, 0, 1, 2], extrapolate=False).derivative()(x[index]) return dy
def bump_cbs(x): y = np.zeros_like(x) index = (-2 < x) & (x < 2) y[index] = BSpline.basis_element([-2, -1, 0, 1, 2], extrapolate=False)(x[index]) return y