Blame doc/bspline.rst

Packit 67cb25
.. index::
Packit 67cb25
   single: basis splines, B-splines
Packit 67cb25
   single: splines, basis
Packit 67cb25
Packit 67cb25
.. _chap_basis-splines:
Packit 67cb25
Packit 67cb25
*************
Packit 67cb25
Basis Splines
Packit 67cb25
*************
Packit 67cb25
Packit 67cb25
This chapter describes functions for the computation of smoothing
Packit 67cb25
basis splines (B-splines). A smoothing spline differs from an
Packit 67cb25
interpolating spline in that the resulting curve is not required to
Packit 67cb25
pass through each datapoint.  For information about
Packit 67cb25
interpolating splines, see :ref:`sec_interpolation`.
Packit 67cb25
Packit 67cb25
The header file :file:`gsl_bspline.h` contains the prototypes for the
Packit 67cb25
bspline functions and related declarations.
Packit 67cb25
Packit 67cb25
.. index::
Packit 67cb25
   single: basis splines, overview
Packit 67cb25
Packit 67cb25
Overview
Packit 67cb25
========
Packit 67cb25
Packit 67cb25
B-splines are commonly used as basis functions to fit smoothing
Packit 67cb25
curves to large data sets. To do this, the abscissa axis is
Packit 67cb25
broken up into some number of intervals, where the endpoints
Packit 67cb25
of each interval are called *breakpoints*. These breakpoints
Packit 67cb25
are then converted to *knots* by imposing various continuity
Packit 67cb25
and smoothness conditions at each interface. Given a nondecreasing
Packit 67cb25
knot vector
Packit 67cb25
Packit 67cb25
.. math:: t = \{t_0, t_1, \dots, t_{n+k-1}\}
Packit 67cb25
Packit 67cb25
the :math:`n` basis splines of order :math:`k` are defined by
Packit 67cb25
Packit 67cb25
.. only:: not texinfo
Packit 67cb25
Packit 67cb25
   .. math::
Packit 67cb25
Packit 67cb25
      B_{i,1}(x) &=
Packit 67cb25
        \left\{
Packit 67cb25
          \begin{array}{cc}
Packit 67cb25
            1, & t_i \le x < t_{i+1} \\
Packit 67cb25
            0, & else
Packit 67cb25
          \end{array}
Packit 67cb25
        \right. \\
Packit 67cb25
      B_{i,k}(x) &= {(x - t_i) \over (t_{i+k-1} - t_i)} B_{i,k-1}(x) +
Packit 67cb25
                    {(t_{i+k} - x) \over (t_{i+k} - t_{i+1})} B_{i+1,k-1}(x)
Packit 67cb25
Packit 67cb25
.. only:: texinfo
Packit 67cb25
Packit 67cb25
   ::
Packit 67cb25
Packit 67cb25
      B_(i,1)(x) = (1, t_i <= x < t_(i+1)
Packit 67cb25
                   (0, else
Packit 67cb25
      B_(i,k)(x) = [(x - t_i)/(t_(i+k-1) - t_i)] B_(i,k-1)(x)
Packit 67cb25
                    + [(t_(i+k) - x)/(t_(i+k) - t_(i+1))] B_(i+1,k-1)(x)
Packit 67cb25
Packit 67cb25
for :math:`i = 0, \ldots, n-1`. The common case of cubic B-splines
Packit 67cb25
is given by :math:`k = 4`. The above recurrence relation can be
Packit 67cb25
evaluated in a numerically stable way by the de Boor algorithm.
Packit 67cb25
Packit 67cb25
If we define appropriate knots on an interval :math:`[a,b]` then
Packit 67cb25
the B-spline basis functions form a complete set on that interval.
Packit 67cb25
Therefore we can expand a smoothing function as
Packit 67cb25
Packit 67cb25
.. math:: f(x) = \sum_{i=0}^{n-1} c_i B_{i,k}(x)
Packit 67cb25
Packit 67cb25
given enough :math:`(x_j, f(x_j))` data pairs. The coefficients
Packit 67cb25
:math:`c_i` can be readily obtained from a least-squares fit.
Packit 67cb25
Packit 67cb25
.. index::
Packit 67cb25
   single: basis splines, initializing
Packit 67cb25
Packit 67cb25
Initializing the B-splines solver
Packit 67cb25
=================================
Packit 67cb25
Packit 67cb25
.. type:: gsl_bspline_workspace
Packit 67cb25
Packit 67cb25
   The computation of B-spline functions requires a preallocated
Packit 67cb25
   workspace.
Packit 67cb25
Packit 67cb25
.. function:: gsl_bspline_workspace * gsl_bspline_alloc (const size_t k, const size_t nbreak)
Packit 67cb25
Packit 67cb25
   This function allocates a workspace for computing B-splines of order
Packit 67cb25
   :data:`k`. The number of breakpoints is given by :data:`nbreak`. This
Packit 67cb25
   leads to :math:`n = nbreak + k - 2` basis functions. Cubic B-splines
Packit 67cb25
   are specified by :math:`k = 4`. The size of the workspace is
Packit 67cb25
   :math:`O(2k^2 + 5k + nbreak)`.
Packit 67cb25
Packit 67cb25
.. function:: void gsl_bspline_free (gsl_bspline_workspace * w)
Packit 67cb25
Packit 67cb25
   This function frees the memory associated with the workspace :data:`w`.
Packit 67cb25
Packit 67cb25
.. index::
Packit 67cb25
   single: knots, basis splines
Packit 67cb25
Packit 67cb25
Constructing the knots vector
Packit 67cb25
=============================
Packit 67cb25
Packit 67cb25
.. function:: int gsl_bspline_knots (const gsl_vector * breakpts, gsl_bspline_workspace * w)
Packit 67cb25
Packit 67cb25
   This function computes the knots associated with the given breakpoints
Packit 67cb25
   and stores them internally in :code:`w->knots`.
Packit 67cb25
Packit 67cb25
.. function:: int gsl_bspline_knots_uniform (const double a, const double b, gsl_bspline_workspace * w)
Packit 67cb25
Packit 67cb25
   This function assumes uniformly spaced breakpoints on :math:`[a,b]`
Packit 67cb25
   and constructs the corresponding knot vector using the previously
Packit 67cb25
   specified :data:`nbreak` parameter. The knots are stored in
Packit 67cb25
   :code:`w->knots`.
Packit 67cb25
Packit 67cb25
.. index::
Packit 67cb25
   single: basis splines, evaluation
Packit 67cb25
Packit 67cb25
Evaluation of B-splines
Packit 67cb25
=======================
Packit 67cb25
Packit 67cb25
.. function:: int gsl_bspline_eval (const double x, gsl_vector * B, gsl_bspline_workspace * w)
Packit 67cb25
Packit 67cb25
   This function evaluates all B-spline basis functions at the position
Packit 67cb25
   :data:`x` and stores them in the vector :data:`B`, so that the :math:`i`-th element
Packit 67cb25
   is :math:`B_i(x)`. The vector :data:`B` must be of length
Packit 67cb25
   :math:`n = nbreak + k - 2`.  This value may also be obtained by calling
Packit 67cb25
   :func:`gsl_bspline_ncoeffs`.
Packit 67cb25
   Computing all the basis functions at once is more efficient than
Packit 67cb25
   computing them individually, due to the nature of the defining
Packit 67cb25
   recurrence relation.
Packit 67cb25
Packit 67cb25
.. function:: int gsl_bspline_eval_nonzero (const double x, gsl_vector * Bk, size_t * istart, size_t * iend, gsl_bspline_workspace * w)
Packit 67cb25
Packit 67cb25
   This function evaluates all potentially nonzero B-spline basis
Packit 67cb25
   functions at the position :data:`x` and stores them in the vector :data:`Bk`, so
Packit 67cb25
   that the :math:`i`-th element is :math:`B_{(istart+i)}(x)`.
Packit 67cb25
   The last element of :data:`Bk` is :math:`B_{iend}(x)`.
Packit 67cb25
   The vector :data:`Bk` must be
Packit 67cb25
   of length :math:`k`.  By returning only the nonzero basis functions,
Packit 67cb25
   this function
Packit 67cb25
   allows quantities involving linear combinations of the :math:`B_i(x)`
Packit 67cb25
   to be computed without unnecessary terms
Packit 67cb25
   (such linear combinations occur, for example,
Packit 67cb25
   when evaluating an interpolated function).
Packit 67cb25
Packit 67cb25
.. function:: size_t gsl_bspline_ncoeffs (gsl_bspline_workspace * w)
Packit 67cb25
Packit 67cb25
   This function returns the number of B-spline coefficients given by
Packit 67cb25
   :math:`n = nbreak + k - 2`.
Packit 67cb25
Packit 67cb25
.. index::
Packit 67cb25
   single: basis splines, derivatives
Packit 67cb25
Packit 67cb25
Evaluation of B-spline derivatives
Packit 67cb25
==================================
Packit 67cb25
Packit 67cb25
.. function:: int gsl_bspline_deriv_eval (const double x, const size_t nderiv, gsl_matrix * dB, gsl_bspline_workspace * w)
Packit 67cb25
Packit 67cb25
   This function evaluates all B-spline basis function derivatives of orders
Packit 67cb25
   :math:`0` through :data:`nderiv` (inclusive) at the position :data:`x`
Packit 67cb25
   and stores them in the matrix :data:`dB`.  The :math:`(i,j)`-th element of :data:`dB`
Packit 67cb25
   is :math:`d^jB_i(x)/dx^j`.  The matrix :data:`dB` must be
Packit 67cb25
   of size :math:`n = nbreak + k - 2` by :math:`nderiv + 1`.
Packit 67cb25
   The value :math:`n` may also be obtained
Packit 67cb25
   by calling :func:`gsl_bspline_ncoeffs`.  Note that function evaluations
Packit 67cb25
   are included as the zeroth order derivatives in :data:`dB`.
Packit 67cb25
   Computing all the basis function derivatives at once is more efficient
Packit 67cb25
   than computing them individually, due to the nature of the defining
Packit 67cb25
   recurrence relation.
Packit 67cb25
Packit 67cb25
.. function:: int gsl_bspline_deriv_eval_nonzero (const double x, const size_t nderiv, gsl_matrix * dB, size_t * istart, size_t * iend, gsl_bspline_workspace * w)
Packit 67cb25
Packit 67cb25
   This function evaluates all potentially nonzero B-spline basis function
Packit 67cb25
   derivatives of orders :math:`0` through :data:`nderiv` (inclusive) at
Packit 67cb25
   the position :data:`x` and stores them in the matrix :data:`dB`.  The
Packit 67cb25
   :math:`(i,j)`-th element of :data:`dB` is :math:`d^jB_{(istart+i)}(x)/dx^j`.
Packit 67cb25
   The last row of :data:`dB` contains :math:`d^jB_{iend}(x)/dx^j`.
Packit 67cb25
   The matrix :data:`dB` must be
Packit 67cb25
   of size :math:`k` by at least :math:`nderiv + 1`.  Note that function
Packit 67cb25
   evaluations are included as the zeroth order derivatives in :data:`dB`.
Packit 67cb25
   By returning only the nonzero basis functions, this function allows
Packit 67cb25
   quantities involving linear combinations of the :math:`B_i(x)` and
Packit 67cb25
   their derivatives to be computed without unnecessary terms.
Packit 67cb25
Packit 67cb25
.. index::
Packit 67cb25
   single: basis splines, Greville abscissae
Packit 67cb25
   single: basis splines, Marsden-Schoenberg points
Packit 67cb25
Packit 67cb25
Working with the Greville abscissae
Packit 67cb25
===================================
Packit 67cb25
Packit 67cb25
The Greville abscissae are defined to be the mean location of :math:`k-1`
Packit 67cb25
consecutive knots in the knot vector for each basis spline function of order
Packit 67cb25
:math:`k`.  With the first and last knots in the :type:`gsl_bspline_workspace`
Packit 67cb25
knot vector excluded, there are :func:`gsl_bspline_ncoeffs` Greville abscissae
Packit 67cb25
for any given B-spline basis.  These values are often used in B-spline
Packit 67cb25
collocation applications and may also be called Marsden-Schoenberg points.
Packit 67cb25
Packit 67cb25
.. function:: double gsl_bspline_greville_abscissa (size_t i, gsl_bspline_workspace * w)
Packit 67cb25
Packit 67cb25
   Returns the location of the :math:`i`-th Greville abscissa for the given
Packit 67cb25
   B-spline basis.  For the ill-defined case when :math:`k = 1`, the implementation
Packit 67cb25
   chooses to return breakpoint interval midpoints.
Packit 67cb25
Packit 67cb25
.. See https://savannah.gnu.org/bugs/index.php?34361
Packit 67cb25
.. @deftypefun int gsl_bspline_knots_greville (const gsl_vector * abscissae, gsl_bspline_workspace * w, double * abserr);
Packit 67cb25
.. Given target Greville abscissae values in :data:`abscissae` and a workspace
Packit 67cb25
.. :data:`w` where @code{abscissae->size == gsl_bspline_ncoeffs(w)}, this functions
Packit 67cb25
.. computes and stores the knots required for the workspace to best approximate
Packit 67cb25
.. the target abscissae.  The approximation is optimal in that the first and last
Packit 67cb25
.. values in :data:`abscissae` are preserved exactly while the 2-norm of the error
Packit 67cb25
.. in any other abscissae is minimized.  If not-@code{NULL}, the sum of the
Packit 67cb25
.. absolute approximation errors over each abscissa is returned in :data:`abserr`.
Packit 67cb25
..
Packit 67cb25
.. The workspace order must satisfy :math:`k > 1` and :data:`abscissae` should be
Packit 67cb25
.. monotonically increasing.  Beware that when @code{w->nbreak} is small relative
Packit 67cb25
.. to @code{w->k} the best approximation may still be of poor quality for
Packit 67cb25
.. non-uniformly spaced :data:`abscissae`.  This function has memory and runtime
Packit 67cb25
.. overhead that scales like a QR-based linear least squares solution on a
Packit 67cb25
.. @code{(abscissae->size - 2)} by @code{(w->nbreak - 2)} problem.
Packit 67cb25
.. @end deftypefun
Packit 67cb25
Packit 67cb25
.. index::
Packit 67cb25
   single: basis splines, examples
Packit 67cb25
Packit 67cb25
Examples
Packit 67cb25
========
Packit 67cb25
Packit 67cb25
The following program computes a linear least squares fit to data using
Packit 67cb25
cubic B-spline basis functions with uniform breakpoints. The data is
Packit 67cb25
generated from the curve :math:`y(x) = \cos{(x)} \exp{(-x/10)}` on
Packit 67cb25
the interval :math:`[0, 15]` with Gaussian noise added.
Packit 67cb25
Packit 67cb25
.. include:: examples/bspline.c
Packit 67cb25
   :code:
Packit 67cb25
Packit 67cb25
The output is shown below::
Packit 67cb25
Packit 67cb25
  $ ./a.out > bspline.txt
Packit 67cb25
  chisq/dof = 1.118217e+00, Rsq = 0.989771
Packit 67cb25
Packit 67cb25
The data and fitted model are shown in :numref:`fig_bspline`.
Packit 67cb25
Packit 67cb25
.. _fig_bspline:
Packit 67cb25
Packit 67cb25
.. figure:: /images/bspline.png
Packit 67cb25
   :scale: 60%
Packit 67cb25
Packit 67cb25
   Data (black) and fitted model (red)
Packit 67cb25
Packit 67cb25
References and Further Reading
Packit 67cb25
==============================
Packit 67cb25
Packit 67cb25
Further information on the algorithms described in this section can be
Packit 67cb25
found in the following book,
Packit 67cb25
Packit 67cb25
* C. de Boor, *A Practical Guide to Splines* (1978), Springer-Verlag,
Packit 67cb25
  ISBN 0-387-90356-9.
Packit 67cb25
Packit 67cb25
Further information of Greville abscissae and B-spline collocation
Packit 67cb25
can be found in the following paper,
Packit 67cb25
Packit 67cb25
* Richard W. Johnson, Higher order B-spline collocation at the Greville
Packit 67cb25
  abscissae.  *Applied Numerical Mathematics*. vol.: 52, 2005, 63--75.
Packit 67cb25
Packit 67cb25
A large collection of B-spline routines is available in the
Packit 67cb25
PPPACK library available at http://www.netlib.org/pppack,
Packit 67cb25
which is also part of SLATEC.