The hardware and bandwidth for this mirror is donated by METANET, the Webhosting and Full Service-Cloud Provider.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]metanet.ch.

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: > % % % —

Introduction

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.

Building a B-spline Basis

Basic Construction

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

Visualizing the Basis

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

Understanding the Extended Knot Sequence

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

Visualizing B-spline Bases

Visualizing a B-spline Basis

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

Visualizing Different Degrees

# 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

Customizing Visualization

# 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

Differentiating a B-spline Basis

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

Visualizing Derivative Bases

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))

Differentiating a B-spline Function

There are two methods to compute derivatives of a B-spline function.

Method 1: Using spline_eval() with der Parameter

The 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))

Method 2: Using Bspline_deriv() to Get Derivative Coefficients

The 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

Method 3: Step-by-step evaluation using basis derivatives

This method follows the same path as spline_eval:

1. Compute the derivative basis

2. Evaluate the basis at points using bs_direct

3. Use matrix multiplication with coefficients

# 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))

PP-form Conversion

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

Callable PP Objects

# 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)

Callable Splines

Creating Callable Splines

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)

Non-Callable Splines

# 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 )

Getting Parameters

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

Advanced: Knot Multiplicity and Regularity

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.

Creating B-splines with Multiple Knots

# 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)

Effect of Multiplicity on Regularity

# 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))

Derivatives at Knots

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

Simple Example: Coherence of Derivative Evaluation Methods (Degree 5)

# 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()

Summary

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.

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.