title: “B-spline Basis Manipulation”
author: “Alexandre Abbes” date: “2026-08-20” output: rmarkdown::html_vignette: toc: true toc_depth: 3 fig_width: 7 fig_height: 5 vignette: > % % % —
This vignette covers the B-spline basis manipulation tools provided
by the BsplineQuantReg package. B-splines are a powerful
tool for nonparametric regression and function approximation. The
package provides a comprehensive set of functions for building,
manipulating, and evaluating B-spline bases. The calculations are
standard and follow authors such as Deboor or Schumaker.
The primary function for building a B-spline basis is
Bspline_base(), which takes an extended knot sequence and
returns the basis functions in piecewise polynomial form.
# Extended knot sequence for cubic B-splines on [0,5]
# with internal knots at 1, 2, 3, 4
sn <- c(0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5)
# Build the basis
basis <- Bspline_base(sn, degree = 3)
# Inspect the basis structure
str(basis[1:4])
## List of 4
## $ base : num [1:8, 1:11, 1:4] 0 0 0 0 0 0 0 0 0 0 ...
## $ base0 : num [1:8, 1:11, 1:4] 0 0 0 0 0 0 0 0 0 0 ...
## $ ext_knot: num [1:12] 0 0 0 0 1 2 3 4 5 5 ...
## $ knot : num [1:6] 0 1 2 3 4 5
The view_basis() function provides a quick visualization
of all basis functions.
# Visualize the basis
view_basis(basis)
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
For a B-spline of degree d with kn
intervals, the extended knot sequence has length
kn + 1 + 2*d:
# d = 3, kn = 5 (intervals: [0,1], [1,2], [2,3], [3,4], [4,5])
# Length: 5 + 1 + 6 = 12
sn_example <- c(0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5)
# The first and last d knots are repeated to enforce boundary conditions
basis_example <- Bspline_base(sn_example, degree = 3)
cat("Number of basis functions:", basis_example$n_splines, "\n")
## Number of basis functions: 8
cat("Effective knots:", basis_example$knot, "\n")
## Effective knots: 0 1 2 3 4 5
The view_basis() function provides a quick visualization
of all basis functions.
# Visualize the basis
view_basis(basis)
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
# piecewise constant (degree 0)
sn_cnst <- c(0, 1, 2, 3, 4, 5)
basis_cnst <- Bspline_base(sn_cnst, degree = 0)
view_basis(basis_cnst)
## [1] 1
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## [1] 2
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## [1] 3
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## [1] 4
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## [1] 5
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
# Linear (degree 1)
sn_lin <- c(0, 0, 1, 2, 3, 4, 5, 5)
basis_lin <- Bspline_base(sn_lin, degree = 1)
view_basis(basis_lin)
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
# Quadratic (degree 2)
sn_quad <- c(0, 0, 0, 1, 2, 3, 4, 5, 5, 5)
basis_quad <- Bspline_base(sn_quad, degree = 2)
view_basis(basis_quad)
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
# View with custom evaluation points
x_fine <- seq(-0.5, 5.5, length.out = 300)
view_basis(basis, x_values = x_fine)
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
The Bspline_base_deriv() function computes the basis of
derivatives of a B-spline basis.
# Compute first derivative basis
basis_der1 <- Bspline_base_deriv(basis, der = 1)
# Compute second derivative basis
basis_der2 <- Bspline_base_deriv(basis, der = 2)
# Compute third derivative basis
basis_der3 <- Bspline_base_deriv(basis, der = 3)
# Check degrees
cat("Original degree:", basis$degree, "\n")
## Original degree: 3
cat("1st derivative degree:", basis_der1$degree, "\n")
## 1st derivative degree: 2
cat("2nd derivative degree:", basis_der2$degree, "\n")
## 2nd derivative degree: 1
cat("3rd derivative degree:", basis_der3$degree, "\n")
## 3rd derivative degree: 0
par(mfrow = c(2, 2))
view_basis(basis, main = "Original Basis (deg 3)")
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
view_basis(basis_der1, main = "1st Derivative Basis (deg 2)")
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
view_basis(basis_der2, main = "2nd Derivative Basis (deg 1)")
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
view_basis(basis_der3, main = "3rd Derivative Basis (deg 0)")
## [1] 1
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## [1] 2
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## [1] 3
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## [1] 4
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## [1] 5
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## [1] 6
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## [1] 7
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## [1] 8
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
par(mfrow = c(1, 1))
There are two methods to compute derivatives of a B-spline function.
spline_eval() with der
ParameterThe simplest method is to use spline_eval() with the
der argument. This function calculates the derivative of
the Bspline basis, then the values of the differentiated basis, and
finaly evaluates the function.
# Create a random B-spline function
bs_function<-basis
bs_function$coeff <- rnorm(basis$n_splines)
# Evaluate the function and its derivatives
x_plot <- seq(0, 5, length.out = 200)
y <- spline_eval(bs_function, x_plot, der = 0)
y1 <- spline_eval(bs_function, x_plot, der = 1)
y2 <- spline_eval(bs_function, x_plot, der = 2)
y3 <- spline_eval(bs_function, x_plot, der = 3)
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
# Plot
par(mfrow = c(2, 2))
plot(x_plot, y, type = "l", main = "Function", xlab = "x", ylab = "f(x)")
plot(x_plot, y1, type = "l", main = "1st Derivative", xlab = "x", ylab = "f'(x)")
plot(x_plot, y2, type = "l", main = "2nd Derivative", xlab = "x", ylab = "f''(x)")
plot(x_plot, y3, type = "l", main = "3rd Derivative", xlab = "x", ylab = "f'''(x)")
par(mfrow = c(1, 1))
Bspline_deriv() to Get Derivative
CoefficientsThe second method computes the coefficients of the der-th derivative B-spline directly on a Bspline basis that is supposed with new degree=degree-der .
# Compute derivative coefficients
der1_func <- Bspline_deriv(bs_function, der = 1)
der2_func <- Bspline_deriv(bs_function, der = 2)
# Evaluate using the derivative B-spline
y1_coeff <- spline_eval(der1_func, x_plot)
y2_coeff <- spline_eval(der2_func, x_plot)
# Both methods should give the same result
max(abs(y1 - y1_coeff))
## [1] 3.154657e-10
max(abs(y2 - y2_coeff))
## [1] 6.405885e-10
This method follows the same path as spline_eval:
# Create a B-spline function
sn <- c(0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5)
basis <- Bspline_base(sn, degree = 3)
basis$coeff <- c(1, -2, 3, -1, 2, 1, 0, 0.5)
# Step 1: Compute the derivative basis (derivative order = 1)
basis_der1 <- Bspline_base_deriv(basis, der = 1)
# Step 2: Evaluate the derivative basis at points using bs_direct
x_plot <- seq(0, 5, length.out = 100)
Bvalues_der1 <- bs_direct(basis_der1, x_plot)
# Step 3: Compute the derivative values using matrix multiplication
# Bvalues_der1 is (n_splines x n_points), coefficients is (n_splines x 1)
# Result is (1 x n_points) or vector of length n_points
y_der1 <- t(Bvalues_der1) %*% basis$coeff
# Step 4: Compare with spline_eval (direct method)
y_der1_direct <- spline_eval(basis, x_plot, der = 1)
# The results are identical
cat("Maximum difference:", max(abs(y_der1 - y_der1_direct)), "\n")
## Maximum difference: 0
# Plot to verify
plot(x_plot, y_der1, type = "l", col = "blue", lwd = 2,
main = "First Derivative: Step-by-Step Method",
xlab = "x", ylab = "f'(x)")
lines(x_plot, y_der1_direct, col = "red", lty = 2, lwd = 2)
legend("topright", legend = c("Matrix multiplication", "spline_eval"),
col = c("blue", "red"), lty = c(1, 2), lwd = 2)
# For higher derivatives, repeat the process
basis_der2 <- Bspline_base_deriv(basis, der = 2)
Bvalues_der2 <- bs_direct(basis_der2, x_plot)
y_der2 <- t(Bvalues_der2) %*% basis$coeff
basis_der3 <- Bspline_base_deriv(basis, der = 3)
Bvalues_der3 <- bs_direct(basis_der3, x_plot)
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
y_der3 <- t(Bvalues_der3) %*% basis$coeff
# Plot all derivatives
par(mfrow = c(2, 2))
plot(x_plot, spline_eval(basis, x_plot), type = "l", col = "blue", lwd = 2,
main = "Function", xlab = "x", ylab = "f(x)")
grid()
plot(x_plot, y_der1, type = "l", col = "darkgreen", lwd = 2,
main = "1st Derivative", xlab = "x", ylab = "f'(x)")
grid()
abline(h = 0, col = "gray", lty = 3)
plot(x_plot, y_der2, type = "l", col = "purple", lwd = 2,
main = "2nd Derivative", xlab = "x", ylab = "f''(x)")
grid()
abline(h = 0, col = "gray", lty = 3)
plot(x_plot, y_der3, type = "l", col = "orange", lwd = 2,
main = "3rd Derivative", xlab = "x", ylab = "f'''(x)")
grid()
abline(h = 0, col = "gray", lty = 3)
par(mfrow = c(1, 1))
B-splines can be converted to piecewise polynomial (PP) form using
Bsplinetopp().
# Convert to PP form
pp <- Bsplinetopp(bs_function,Bsbasis=basis, callable = FALSE)
# PP form contains polynomial coefficients for each interval
print(pp)
## Piecewise Polynomial (PP) (non-callable)
## ================================
## $degree: 3
## $knot: 0 1 2 3 4 5
## coefficients dimension: 5 x 4
##
## $coeff:
## Intervals 1 : -3.2416, 5.9572, -0.6732, -1.419
## Intervals 2 : 1.4643, -3.7676, 1.5164, 0.6234
## Intervals 3 : 0.3579, 0.6253, -1.626, -0.1636
## Intervals 4 : -0.9783, 1.6991, 0.6984, -0.8063
## Intervals 5 : -1.4114, -1.2357, 1.1619, 0.613
## Usage: pp_eval(pp, x_values)
#or omit the basis (slower, re-calculate the basis)
pp <- Bsplinetopp(bs_function, callable = FALSE)
# PP form contains polynomial coefficients for each interval
print(pp)
## Piecewise Polynomial (PP) (non-callable)
## ================================
## $degree: 3
## $knot: 0 1 2 3 4 5
## coefficients dimension: 5 x 4
##
## $coeff:
## Intervals 1 : -3.2416, 5.9572, -0.6732, -1.419
## Intervals 2 : 1.4643, -3.7676, 1.5164, 0.6234
## Intervals 3 : 0.3579, 0.6253, -1.626, -0.1636
## Intervals 4 : -0.9783, 1.6991, 0.6984, -0.8063
## Intervals 5 : -1.4114, -1.2357, 1.1619, 0.613
## Usage: pp_eval(pp, x_values)
# Evaluate the PP form
y_pp <- evalpp(pp, x_plot)
# Recalculatethe
y <- spline_eval(bs_function,x_plot)
# Should match the original B-spline
max(abs(y - y_pp))
## [1] 1.110223e-15
# Create a callable PP object
pp_call <- Bsplinetopp(bs_function, callable = TRUE)
class(pp_call) # "callable_pp" "function"
## [1] "callable_pp" "function"
# Evaluate directly
y_call <- pp_call(x_plot)
# Access parameters
params <- get_parameters(pp_call)
print(params$degree)
## [1] 3
print(params$knot)
## [1] 0 1 2 3 4 5
# Print method
print(pp_call)
## Callable Piecewise Polynomial (PP) Object
## ==========================================
## Degree: 3
## Intervals: 5
## Knots: 6
## coefficients dimension: 5 x 4
##
## $coeff:
## Intervals 1 : -3.2416, 5.9572, -0.6732, -1.419
## Intervals 2 : 1.4643, -3.7676, 1.5164, 0.6234
## Intervals 3 : 0.3579, 0.6253, -1.626, -0.1636
## Intervals 4 : -0.9783, 1.6991, 0.6984, -0.8063
## Intervals 5 : -1.4114, -1.2357, 1.1619, 0.613
## Usage: pp(x_values) or evalpp(pp, x_values)
The make_spline() function transforms a B-spline object
into a callable function.
# Create a callable spline
spline_func <- make_spline(bs_function, callable = TRUE)
class(spline_func) # "callable_spline" "function"
## [1] "callable_spline" "function"
# Evaluate directly
y_callable <- spline_func(x_plot)
# Access parameters
get_parameters(spline_func)$degree
## [1] 3
get_parameters(spline_func)$knot
## [1] 0 1 2 3 4 5
get_parameters(spline_func)$coeff
## [1] -1.4190437 -1.6434424 1.8792401 -0.3720345 -1.3727258 1.0248489 0.9756790
## [8] -0.8721564
# Print method
print(spline_func)
## callable_spline Object
## ======================
## Degree: 3
## Knots ( 6 ): 0 1 2 3 4 5
## Coefficients ( 8 ): -1.419044 -1.643442 1.87924 -0.3720345 -1.372726 1.024849 0.975679 -0.8721564
## for result, type get_parameter(spline)
# Create a non-callable spline
spline_list <- make_spline(bs_function, callable = FALSE)
class(spline_list) # "non_callable_spline" "list"
## [1] "non_callable_spline" "list"
# Access components
spline_list$degree
## [1] 3
spline_list$knot
## [1] 0 1 2 3 4 5
spline_list$coeff
## [1] -1.4190437 -1.6434424 1.8792401 -0.3720345 -1.3727258 1.0248489 0.9756790
## [8] -0.8721564
# Print method
print(spline_list)
## Non callable Spline List
## ========================
## $degree: 3
## $knot : [ 0, 1, 2, 3, 4, 5 ] ( 6 knots )
## $coeff (rounded 10^(-7)) :[ -1.4190437, -1.6434424, 1.8792401, -0.3720345, -1.3727258, 1.0248489, 0.975679, -0.8721564 ] ( dim Basis is 8 )
The get_parameters() function extracts parameters from
callable objects.
params <- get_parameters(spline_func)
print(params$degree)
## [1] 3
print(params$knot)
## [1] 0 1 2 3 4 5
print(head(params$coeff, 5))
## [1] -1.4190437 -1.6434424 1.8792401 -0.3720345 -1.3727258
Knot multiplicity controls the smoothness of B-splines at knot
points. The regularity at a knot is determined by the multiplicity
m and the degree d: the spline is
C^(d - m - 1) at that knot.
# Create a basis with a double knot at 3: accept discontinuity of the 2cnd derivative at 3
sn_mult <- c(0, 0, 0, 0, 1, 2, 3, 3, 4, 5, 5, 5, 5)
basis_mult <- Bspline_base(sn_mult, degree = 3)
# Visualize
view_basis(basis_mult)
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
abline(v = 3, col = "orange", lty = 2, lwd = 2)
# Single knot (m=1): C^2 continuity
# Double knot (m=2): C^1 continuity
# Triple knot (m=3): C^0 continuity
# Quadruple knot (m=4): Discontinuity
sn1 <- c(0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5) # m=1 at 3
sn2 <- c(0, 0, 0, 0, 1, 2, 3, 3, 4, 5, 5, 5, 5) # m=2 at 3
sn3 <- c(0, 0, 0, 0, 1, 2, 3, 3, 3, 4, 5, 5, 5, 5) # m=3 at 3
sn4 <- c(0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 4, 5, 5, 5, 5) # m=3 at 3
# Compare the bases
basis1 <- Bspline_base(sn1, degree = 3)
basis2 <- Bspline_base(sn2, degree = 3)
basis3 <- Bspline_base(sn3, degree = 3)
basis4 <- Bspline_base(sn4, degree = 3)
# Visualize the differences
par(mfrow = c(2, 1))
view_basis(basis1, main = "m=1 (only C² at x=3)")
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
view_basis(basis2, main = "m=2 (only C¹ at x=3)")
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
par(mfrow = c(2, 1))
view_basis(basis3, main = "m=3 (only C⁰ at x=3)")
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
view_basis(basis4, main = "m=4 (discontinuous at x=3)")
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
## Some x values smaler than first knot, extrapolating
## Some x values greater than last knot, extrapolating
par(mfrow = c(1, 1))
The Spline_der_knot() function computes derivative
values at knot points efficiently.
# Compute derivatives at knots
der_knots <- Spline_der_knot(basis, der = 1)
print(head(der_knots))
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
## [1,] 0 0.00 0.00 0.0 0.0 0 0 0
## [2,] 0 0.00 0.00 0.0 0.0 0 0 0
## [3,] 0 0.00 0.00 0.0 0.0 0 0 0
## [4,] -3 3.00 0.00 0.0 0.0 0 0 0
## [5,] 0 -0.75 0.25 0.5 0.0 0 0 0
## [6,] 0 0.00 -0.50 0.0 0.5 0 0 0
# Create a degree 5 B-spline
sn5 <- c(0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 5)
basis5 <- Bspline_base(sn5, degree = 5)
basis5$coeff <- c(1, -2, 3, -1, 2, 1, 0, -1, 2,5)
# Evaluation points
x <- seq(0, 5, length.out = 100)
# --- Method 1: spline_eval with der parameter ---
y1 <- spline_eval(basis5, x, der = 1)
# --- Method 2: Bspline_deriv + spline_eval ---
der_basis <- Bspline_deriv(basis5, der = 1)
y2 <- spline_eval(der_basis, x)
# --- Method 3: Step-by-step (basis derivative + bs_direct + matrix mult) ---
der_basis2 <- Bspline_base_deriv(basis5, der = 1)
Bvals <- bs_direct(der_basis2, x)
y3 <- t(Bvals) %*% basis5$coeff
# All three methods give identical results
cat("Max differences:\n")
## Max differences:
cat(" Method 1 vs Method 2:", max(abs(y1 - y2)), "\n")
## Method 1 vs Method 2: 8.999983e-10
cat(" Method 1 vs Method 3:", max(abs(y1 - y3)), "\n")
## Method 1 vs Method 3: 0
cat(" Method 2 vs Method 3:", max(abs(y2 - y3)), "\n")
## Method 2 vs Method 3: 8.999983e-10
# Plot to verify visually
plot(x, y1, type = "l", col = "blue", lwd = 2,
main = "First Derivative - All Methods Coincide (deg 5)",
xlab = "x", ylab = "f'(x)")
lines(x, y2, col = "red", lty = 2, lwd = 2)
lines(x, y3, col = "green", lty = 3, lwd = 2)
legend("topright",
legend = c("spline_eval(der=1)", "Bspline_deriv", "Step-by-step"),
col = c("blue", "red", "green"), lty = c(1, 2, 3), lwd = 2)
grid()
| Feature | Function | Description |
|---|---|---|
| Build basis | Bspline_base() |
Create B-spline basis |
| View basis | view_basis() |
Visualize basis functions |
| Differentiate basis | Bspline_base_deriv() |
Compute derivative basis |
| Differentiate function | spline_eval(der=...) |
Evaluate derivatives |
| Derivative coefficients | Bspline_deriv() |
Get derivative B-spline |
| PP conversion | Bsplinetopp() |
Convert to PP form |
| Callable spline | make_spline() |
Create callable function |
| Extract params | get_parameters() |
Get parameters from callable |
| Derivatives at knots | Spline_der_knot() |
Efficient knot derivatives |
All Bsplines functions are implemented in pure R and support B-splines of any degree (greater than 0), with full derivative and PP-form capabilities. Limitation to degree 4 is only for regression with contsraints over intervals.