|
Packit |
67cb25 |
/* bspline/bspline.c
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Copyright (C) 2006, 2007, 2008, 2009 Patrick Alken
|
|
Packit |
67cb25 |
* Copyright (C) 2008 Rhys Ulerich
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
67cb25 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
67cb25 |
* the Free Software Foundation; either version 3 of the License, or (at
|
|
Packit |
67cb25 |
* your option) any later version.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This program is distributed in the hope that it will be useful, but
|
|
Packit |
67cb25 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
67cb25 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
67cb25 |
* General Public License for more details.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
67cb25 |
* along with this program; if not, write to the Free Software
|
|
Packit |
67cb25 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include <config.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_errno.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_bspline.h>
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* This module contains routines related to calculating B-splines.
|
|
Packit |
67cb25 |
* The algorithms used are described in
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* [1] Carl de Boor, "A Practical Guide to Splines", Springer
|
|
Packit |
67cb25 |
* Verlag, 1978.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* The bspline_pppack_* internal routines contain code adapted from
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* [2] "PPPACK - Piecewise Polynomial Package",
|
|
Packit |
67cb25 |
* http://www.netlib.org/pppack/
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include "bspline.h"
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_bspline_alloc()
|
|
Packit |
67cb25 |
Allocate space for a bspline workspace. The size of the
|
|
Packit |
67cb25 |
workspace is O(5k + nbreak)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: k - spline order (cubic = 4)
|
|
Packit |
67cb25 |
nbreak - number of breakpoints
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: pointer to workspace
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_bspline_workspace *
|
|
Packit |
67cb25 |
gsl_bspline_alloc (const size_t k, const size_t nbreak)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (k == 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("k must be at least 1", GSL_EINVAL);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (nbreak < 2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("nbreak must be at least 2", GSL_EINVAL);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_bspline_workspace *w;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w = calloc (1, sizeof (gsl_bspline_workspace));
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w == 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate space for workspace",
|
|
Packit |
67cb25 |
GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->k = k;
|
|
Packit |
67cb25 |
w->km1 = k - 1;
|
|
Packit |
67cb25 |
w->nbreak = nbreak;
|
|
Packit |
67cb25 |
w->l = nbreak - 1;
|
|
Packit |
67cb25 |
w->n = w->l + k - 1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->knots = gsl_vector_alloc (w->n + k);
|
|
Packit |
67cb25 |
if (w->knots == 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_bspline_free (w);
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate space for knots vector",
|
|
Packit |
67cb25 |
GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->deltal = gsl_vector_alloc (k);
|
|
Packit |
67cb25 |
if (w->deltal == 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_bspline_free (w);
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate space for deltal vector",
|
|
Packit |
67cb25 |
GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->deltar = gsl_vector_alloc (k);
|
|
Packit |
67cb25 |
if (w->deltar == 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_bspline_free (w);
|
|
Packit |
67cb25 |
GSL_ERROR_NULL ("failed to allocate space for deltar vector",
|
|
Packit |
67cb25 |
GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->B = gsl_vector_alloc (k);
|
|
Packit |
67cb25 |
if (w->B == 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_bspline_free (w);
|
|
Packit |
67cb25 |
GSL_ERROR_NULL
|
|
Packit |
67cb25 |
("failed to allocate space for temporary spline vector",
|
|
Packit |
67cb25 |
GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->A = gsl_matrix_alloc (k, k);
|
|
Packit |
67cb25 |
if (w->A == 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_bspline_free (w);
|
|
Packit |
67cb25 |
GSL_ERROR_NULL
|
|
Packit |
67cb25 |
("failed to allocate space for derivative work matrix",
|
|
Packit |
67cb25 |
GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->dB = gsl_matrix_alloc (k, k + 1);
|
|
Packit |
67cb25 |
if (w->dB == 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_bspline_free (w);
|
|
Packit |
67cb25 |
GSL_ERROR_NULL
|
|
Packit |
67cb25 |
("failed to allocate space for temporary derivative matrix",
|
|
Packit |
67cb25 |
GSL_ENOMEM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return w;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* gsl_bspline_alloc() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_bspline_free()
|
|
Packit |
67cb25 |
Free a gsl_bspline_workspace.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: w - workspace to free
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: none
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
void
|
|
Packit |
67cb25 |
gsl_bspline_free (gsl_bspline_workspace * w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
RETURN_IF_NULL (w);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->knots)
|
|
Packit |
67cb25 |
gsl_vector_free (w->knots);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->deltal)
|
|
Packit |
67cb25 |
gsl_vector_free (w->deltal);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->deltar)
|
|
Packit |
67cb25 |
gsl_vector_free (w->deltar);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->B)
|
|
Packit |
67cb25 |
gsl_vector_free (w->B);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->A)
|
|
Packit |
67cb25 |
gsl_matrix_free(w->A);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->dB)
|
|
Packit |
67cb25 |
gsl_matrix_free(w->dB);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
free (w);
|
|
Packit |
67cb25 |
} /* gsl_bspline_free() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Return number of coefficients */
|
|
Packit |
67cb25 |
size_t
|
|
Packit |
67cb25 |
gsl_bspline_ncoeffs (gsl_bspline_workspace * w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
return w->n;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Return order */
|
|
Packit |
67cb25 |
size_t
|
|
Packit |
67cb25 |
gsl_bspline_order (gsl_bspline_workspace * w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
return w->k;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Return number of breakpoints */
|
|
Packit |
67cb25 |
size_t
|
|
Packit |
67cb25 |
gsl_bspline_nbreak (gsl_bspline_workspace * w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
return w->nbreak;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Return the location of the i-th breakpoint*/
|
|
Packit |
67cb25 |
double
|
|
Packit |
67cb25 |
gsl_bspline_breakpoint (size_t i, gsl_bspline_workspace * w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t j = i + w->k - 1;
|
|
Packit |
67cb25 |
return gsl_vector_get (w->knots, j);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_bspline_knots()
|
|
Packit |
67cb25 |
Compute the knots from the given breakpoints:
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
knots(1:k) = breakpts(1)
|
|
Packit |
67cb25 |
knots(k+1:k+l-1) = breakpts(i), i = 2 .. l
|
|
Packit |
67cb25 |
knots(n+1:n+k) = breakpts(l + 1)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
where l is the number of polynomial pieces (l = nbreak - 1) and
|
|
Packit |
67cb25 |
n = k + l - 1
|
|
Packit |
67cb25 |
(using matlab syntax for the arrays)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
The repeated knots at the beginning and end of the interval
|
|
Packit |
67cb25 |
correspond to the continuity condition there. See pg. 119
|
|
Packit |
67cb25 |
of [1].
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: breakpts - breakpoints
|
|
Packit |
67cb25 |
w - bspline workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success or error
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_bspline_knots (const gsl_vector * breakpts, gsl_bspline_workspace * w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (breakpts->size != w->nbreak)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("breakpts vector has wrong size", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t i; /* looping */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < w->k; i++)
|
|
Packit |
67cb25 |
gsl_vector_set (w->knots, i, gsl_vector_get (breakpts, 0));
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 1; i < w->l; i++)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_vector_set (w->knots, w->k - 1 + i,
|
|
Packit |
67cb25 |
gsl_vector_get (breakpts, i));
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = w->n; i < w->n + w->k; i++)
|
|
Packit |
67cb25 |
gsl_vector_set (w->knots, i, gsl_vector_get (breakpts, w->l));
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* gsl_bspline_knots() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_bspline_knots_uniform()
|
|
Packit |
67cb25 |
Construct uniformly spaced knots on the interval [a,b] using
|
|
Packit |
67cb25 |
the previously specified number of breakpoints. 'a' is the position
|
|
Packit |
67cb25 |
of the first breakpoint and 'b' is the position of the last
|
|
Packit |
67cb25 |
breakpoint.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: a - left side of interval
|
|
Packit |
67cb25 |
b - right side of interval
|
|
Packit |
67cb25 |
w - bspline workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success or error
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes: 1) w->knots is modified to contain the uniformly spaced
|
|
Packit |
67cb25 |
knots
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
2) The knots vector is set up as follows (using octave syntax):
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
knots(1:k) = a
|
|
Packit |
67cb25 |
knots(k+1:k+l-1) = a + i*delta, i = 1 .. l - 1
|
|
Packit |
67cb25 |
knots(n+1:n+k) = b
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_bspline_knots_uniform (const double a, const double b,
|
|
Packit |
67cb25 |
gsl_bspline_workspace * w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t i; /* looping */
|
|
Packit |
67cb25 |
double delta; /* interval spacing */
|
|
Packit |
67cb25 |
double x;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
delta = (b - a) / (double) w->l;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < w->k; i++)
|
|
Packit |
67cb25 |
gsl_vector_set (w->knots, i, a);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
x = a + delta;
|
|
Packit |
67cb25 |
for (i = 0; i < w->l - 1; i++)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_vector_set (w->knots, w->k + i, x);
|
|
Packit |
67cb25 |
x += delta;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = w->n; i < w->n + w->k; i++)
|
|
Packit |
67cb25 |
gsl_vector_set (w->knots, i, b);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
} /* gsl_bspline_knots_uniform() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_bspline_eval()
|
|
Packit |
67cb25 |
Evaluate the basis functions B_i(x) for all i. This is
|
|
Packit |
67cb25 |
a wrapper function for gsl_bspline_eval_nonzero() which
|
|
Packit |
67cb25 |
formats the output in a nice way.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: x - point for evaluation
|
|
Packit |
67cb25 |
B - (output) where to store B_i(x) values
|
|
Packit |
67cb25 |
the length of this vector is
|
|
Packit |
67cb25 |
n = nbreak + k - 2 = l + k - 1 = w->n
|
|
Packit |
67cb25 |
w - bspline workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success or error
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes: The w->knots vector must be initialized prior to calling
|
|
Packit |
67cb25 |
this function (see gsl_bspline_knots())
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_bspline_eval (const double x, gsl_vector * B, gsl_bspline_workspace * w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (B->size != w->n)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("vector B not of length n", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t i; /* looping */
|
|
Packit |
67cb25 |
size_t istart; /* first non-zero spline for x */
|
|
Packit |
67cb25 |
size_t iend; /* last non-zero spline for x, knot for x */
|
|
Packit |
67cb25 |
int error; /* error handling */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* find all non-zero B_i(x) values */
|
|
Packit |
67cb25 |
error = gsl_bspline_eval_nonzero (x, w->B, &istart, &iend, w);
|
|
Packit |
67cb25 |
if (error)
|
|
Packit |
67cb25 |
return error;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* store values in appropriate part of given vector */
|
|
Packit |
67cb25 |
for (i = 0; i < istart; i++)
|
|
Packit |
67cb25 |
gsl_vector_set (B, i, 0.0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = istart; i <= iend; i++)
|
|
Packit |
67cb25 |
gsl_vector_set (B, i, gsl_vector_get (w->B, i - istart));
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = iend + 1; i < w->n; i++)
|
|
Packit |
67cb25 |
gsl_vector_set (B, i, 0.0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* gsl_bspline_eval() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_bspline_eval_nonzero()
|
|
Packit |
67cb25 |
Evaluate all non-zero B-spline functions at point x.
|
|
Packit |
67cb25 |
These are the B_i(x) for i in [istart, iend].
|
|
Packit |
67cb25 |
Always B_i(x) = 0 for i < istart and for i > iend.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: x - point at which to evaluate splines
|
|
Packit |
67cb25 |
Bk - (output) where to store B-spline values (length k)
|
|
Packit |
67cb25 |
istart - (output) B-spline function index of
|
|
Packit |
67cb25 |
first non-zero basis for given x
|
|
Packit |
67cb25 |
iend - (output) B-spline function index of
|
|
Packit |
67cb25 |
last non-zero basis for given x.
|
|
Packit |
67cb25 |
This is also the knot index corresponding to x.
|
|
Packit |
67cb25 |
w - bspline workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success or error
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes: 1) the w->knots vector must be initialized before calling
|
|
Packit |
67cb25 |
this function
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
2) On output, B contains
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
[B_{istart,k}, B_{istart+1,k},
|
|
Packit |
67cb25 |
..., B_{iend-1,k}, B_{iend,k}]
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
evaluated at the given x.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_bspline_eval_nonzero (const double x, gsl_vector * Bk, size_t * istart,
|
|
Packit |
67cb25 |
size_t * iend, gsl_bspline_workspace * w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (Bk->size != w->k)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("Bk vector length does not match order k", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t i; /* spline index */
|
|
Packit |
67cb25 |
size_t j; /* looping */
|
|
Packit |
67cb25 |
int flag = 0; /* interval search flag */
|
|
Packit |
67cb25 |
int error = 0; /* error flag */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
i = bspline_find_interval (x, &flag, w);
|
|
Packit |
67cb25 |
error = bspline_process_interval_for_eval (x, &i, flag, w);
|
|
Packit |
67cb25 |
if (error)
|
|
Packit |
67cb25 |
return error;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*istart = i - w->k + 1;
|
|
Packit |
67cb25 |
*iend = i;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
bspline_pppack_bsplvb (w->knots, w->k, 1, x, *iend, &j, w->deltal,
|
|
Packit |
67cb25 |
w->deltar, Bk);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* gsl_bspline_eval_nonzero() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_bspline_deriv_eval()
|
|
Packit |
67cb25 |
Evaluate d^j/dx^j B_i(x) for all i, 0 <= j <= nderiv.
|
|
Packit |
67cb25 |
This is a wrapper function for gsl_bspline_deriv_eval_nonzero()
|
|
Packit |
67cb25 |
which formats the output in a nice way.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: x - point for evaluation
|
|
Packit |
67cb25 |
nderiv - number of derivatives to compute, inclusive.
|
|
Packit |
67cb25 |
dB - (output) where to store d^j/dx^j B_i(x)
|
|
Packit |
67cb25 |
values. the size of this matrix is
|
|
Packit |
67cb25 |
(n = nbreak + k - 2 = l + k - 1 = w->n)
|
|
Packit |
67cb25 |
by (nderiv + 1)
|
|
Packit |
67cb25 |
w - bspline derivative workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success or error
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes: 1) The w->knots vector must be initialized prior to calling
|
|
Packit |
67cb25 |
this function (see gsl_bspline_knots())
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
2) based on PPPACK's bsplvd
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_bspline_deriv_eval (const double x, const size_t nderiv,
|
|
Packit |
67cb25 |
gsl_matrix * dB, gsl_bspline_workspace * w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (dB->size1 != w->n)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("dB matrix first dimension not of length n", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (dB->size2 < nderiv + 1)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR
|
|
Packit |
67cb25 |
("dB matrix second dimension must be at least length nderiv+1",
|
|
Packit |
67cb25 |
GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t i; /* looping */
|
|
Packit |
67cb25 |
size_t j; /* looping */
|
|
Packit |
67cb25 |
size_t istart; /* first non-zero spline for x */
|
|
Packit |
67cb25 |
size_t iend; /* last non-zero spline for x, knot for x */
|
|
Packit |
67cb25 |
int error; /* error handling */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* find all non-zero d^j/dx^j B_i(x) values */
|
|
Packit |
67cb25 |
error =
|
|
Packit |
67cb25 |
gsl_bspline_deriv_eval_nonzero (x, nderiv, w->dB, &istart, &iend, w);
|
|
Packit |
67cb25 |
if (error)
|
|
Packit |
67cb25 |
return error;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* store values in appropriate part of given matrix */
|
|
Packit |
67cb25 |
for (j = 0; j <= nderiv; j++)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (i = 0; i < istart; i++)
|
|
Packit |
67cb25 |
gsl_matrix_set (dB, i, j, 0.0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = istart; i <= iend; i++)
|
|
Packit |
67cb25 |
gsl_matrix_set (dB, i, j, gsl_matrix_get (w->dB, i - istart, j));
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = iend + 1; i < w->n; i++)
|
|
Packit |
67cb25 |
gsl_matrix_set (dB, i, j, 0.0);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* gsl_bspline_deriv_eval() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_bspline_deriv_eval_nonzero()
|
|
Packit |
67cb25 |
At point x evaluate all requested, non-zero B-spline function
|
|
Packit |
67cb25 |
derivatives and store them in dB. These are the
|
|
Packit |
67cb25 |
d^j/dx^j B_i(x) with i in [istart, iend] and j in [0, nderiv].
|
|
Packit |
67cb25 |
Always d^j/dx^j B_i(x) = 0 for i < istart and for i > iend.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: x - point at which to evaluate splines
|
|
Packit |
67cb25 |
nderiv - number of derivatives to request, inclusive
|
|
Packit |
67cb25 |
dB - (output) where to store dB-spline derivatives
|
|
Packit |
67cb25 |
(size k by nderiv + 1)
|
|
Packit |
67cb25 |
istart - (output) B-spline function index of
|
|
Packit |
67cb25 |
first non-zero basis for given x
|
|
Packit |
67cb25 |
iend - (output) B-spline function index of
|
|
Packit |
67cb25 |
last non-zero basis for given x.
|
|
Packit |
67cb25 |
This is also the knot index corresponding to x.
|
|
Packit |
67cb25 |
w - bspline derivative workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success or error
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes: 1) the w->knots vector must be initialized before calling
|
|
Packit |
67cb25 |
this function
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
2) On output, dB contains
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
[[B_{istart, k}, ..., d^nderiv/dx^nderiv B_{istart ,k}],
|
|
Packit |
67cb25 |
[B_{istart+1,k}, ..., d^nderiv/dx^nderiv B_{istart+1,k}],
|
|
Packit |
67cb25 |
...
|
|
Packit |
67cb25 |
[B_{iend-1, k}, ..., d^nderiv/dx^nderiv B_{iend-1, k}],
|
|
Packit |
67cb25 |
[B_{iend, k}, ..., d^nderiv/dx^nderiv B_{iend, k}]]
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
evaluated at x. B_{istart, k} is stored in dB(0,0).
|
|
Packit |
67cb25 |
Each additional column contains an additional derivative.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
3) Note that the zero-th column of the result contains the
|
|
Packit |
67cb25 |
0th derivative, which is simply a function evaluation.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
4) based on PPPACK's bsplvd
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_bspline_deriv_eval_nonzero (const double x, const size_t nderiv,
|
|
Packit |
67cb25 |
gsl_matrix * dB, size_t * istart,
|
|
Packit |
67cb25 |
size_t * iend, gsl_bspline_workspace * w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (dB->size1 != w->k)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("dB matrix first dimension not of length k", GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (dB->size2 < nderiv + 1)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR
|
|
Packit |
67cb25 |
("dB matrix second dimension must be at least length nderiv+1",
|
|
Packit |
67cb25 |
GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t i; /* spline index */
|
|
Packit |
67cb25 |
size_t j; /* looping */
|
|
Packit |
67cb25 |
int flag = 0; /* interval search flag */
|
|
Packit |
67cb25 |
int error = 0; /* error flag */
|
|
Packit |
67cb25 |
size_t min_nderivk;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
i = bspline_find_interval (x, &flag, w);
|
|
Packit |
67cb25 |
error = bspline_process_interval_for_eval (x, &i, flag, w);
|
|
Packit |
67cb25 |
if (error)
|
|
Packit |
67cb25 |
return error;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*istart = i - w->k + 1;
|
|
Packit |
67cb25 |
*iend = i;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
bspline_pppack_bsplvd (w->knots, w->k, x, *iend,
|
|
Packit |
67cb25 |
w->deltal, w->deltar, w->A, dB, nderiv);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* An order k b-spline has at most k-1 nonzero derivatives
|
|
Packit |
67cb25 |
so we need to zero all requested higher order derivatives */
|
|
Packit |
67cb25 |
min_nderivk = GSL_MIN_INT (nderiv, w->k - 1);
|
|
Packit |
67cb25 |
for (j = min_nderivk + 1; j <= nderiv; j++)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (i = 0; i < w->k; i++)
|
|
Packit |
67cb25 |
gsl_matrix_set (dB, i, j, 0.0);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* gsl_bspline_deriv_eval_nonzero() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/****************************************
|
|
Packit |
67cb25 |
* INTERNAL ROUTINES *
|
|
Packit |
67cb25 |
****************************************/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
bspline_find_interval()
|
|
Packit |
67cb25 |
Find knot interval such that t_i <= x < t_{i + 1}
|
|
Packit |
67cb25 |
where the t_i are knot values.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: x - x value
|
|
Packit |
67cb25 |
flag - (output) error flag
|
|
Packit |
67cb25 |
w - bspline workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: i (index in w->knots corresponding to left limit of interval)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes: The error conditions are reported as follows:
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Condition Return value Flag
|
|
Packit |
67cb25 |
--------- ------------ ----
|
|
Packit |
67cb25 |
x < t_0 0 -1
|
|
Packit |
67cb25 |
t_i <= x < t_{i+1} i 0
|
|
Packit |
67cb25 |
t_i < x = t_{i+1} = t_{n+k-1} i 0
|
|
Packit |
67cb25 |
t_{n+k-1} < x l+k-1 +1
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static inline size_t
|
|
Packit |
67cb25 |
bspline_find_interval (const double x, int *flag, gsl_bspline_workspace * w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (x < gsl_vector_get (w->knots, 0))
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
*flag = -1;
|
|
Packit |
67cb25 |
return 0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* find i such that t_i <= x < t_{i+1} */
|
|
Packit |
67cb25 |
for (i = w->k - 1; i < w->k + w->l - 1; i++)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const double ti = gsl_vector_get (w->knots, i);
|
|
Packit |
67cb25 |
const double tip1 = gsl_vector_get (w->knots, i + 1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (tip1 < ti)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("knots vector is not increasing", GSL_EINVAL);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (ti <= x && x < tip1)
|
|
Packit |
67cb25 |
break;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (ti < x && x == tip1 && tip1 == gsl_vector_get (w->knots, w->k + w->l
|
|
Packit |
67cb25 |
- 1))
|
|
Packit |
67cb25 |
break;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (i == w->k + w->l - 1)
|
|
Packit |
67cb25 |
*flag = 1;
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
*flag = 0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return i;
|
|
Packit |
67cb25 |
} /* bspline_find_interval() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
bspline_process_interval_for_eval()
|
|
Packit |
67cb25 |
Consumes an x location, left knot from bspline_find_interval, flag
|
|
Packit |
67cb25 |
from bspline_find_interval, and a workspace. Checks that x lies within
|
|
Packit |
67cb25 |
the splines' knots, enforces some endpoint continuity requirements, and
|
|
Packit |
67cb25 |
avoids divide by zero errors in the underlying bspline_pppack_* functions.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
static inline int
|
|
Packit |
67cb25 |
bspline_process_interval_for_eval (const double x, size_t * i, const int flag,
|
|
Packit |
67cb25 |
gsl_bspline_workspace * w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (flag == -1)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("x outside of knot interval", GSL_EINVAL);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (flag == 1)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (x <= gsl_vector_get (w->knots, *i) + GSL_DBL_EPSILON)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
*i -= 1;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("x outside of knot interval", GSL_EINVAL);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (gsl_vector_get (w->knots, *i) == gsl_vector_get (w->knots, *i + 1))
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("knot(i) = knot(i+1) will result in division by zero",
|
|
Packit |
67cb25 |
GSL_EINVAL);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
} /* bspline_process_interval_for_eval */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/********************************************************************
|
|
Packit |
67cb25 |
* PPPACK ROUTINES
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* The routines herein deliberately avoid using the bspline workspace,
|
|
Packit |
67cb25 |
* choosing instead to pass all work areas explicitly. This allows
|
|
Packit |
67cb25 |
* others to more easily adapt these routines to low memory or
|
|
Packit |
67cb25 |
* parallel scenarios.
|
|
Packit |
67cb25 |
********************************************************************/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
bspline_pppack_bsplvb()
|
|
Packit |
67cb25 |
calculates the value of all possibly nonzero b-splines at x of order
|
|
Packit |
67cb25 |
jout = max( jhigh , (j+1)*(index-1) ) with knot sequence t.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Parameters:
|
|
Packit |
67cb25 |
t - knot sequence, of length left + jout , assumed to be
|
|
Packit |
67cb25 |
nondecreasing. assumption t(left).lt.t(left + 1).
|
|
Packit |
67cb25 |
division by zero will result if t(left) = t(left+1)
|
|
Packit |
67cb25 |
jhigh -
|
|
Packit |
67cb25 |
index - integers which determine the order jout = max(jhigh,
|
|
Packit |
67cb25 |
(j+1)*(index-1)) of the b-splines whose values at x
|
|
Packit |
67cb25 |
are to be returned. index is used to avoid
|
|
Packit |
67cb25 |
recalculations when several columns of the triangular
|
|
Packit |
67cb25 |
array of b-spline values are needed (e.g., in bsplpp
|
|
Packit |
67cb25 |
or in bsplvd ). precisely,
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if index = 1 ,
|
|
Packit |
67cb25 |
the calculation starts from scratch and the entire
|
|
Packit |
67cb25 |
triangular array of b-spline values of orders
|
|
Packit |
67cb25 |
1,2,...,jhigh is generated order by order , i.e.,
|
|
Packit |
67cb25 |
column by column .
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if index = 2 ,
|
|
Packit |
67cb25 |
only the b-spline values of order j+1, j+2, ..., jout
|
|
Packit |
67cb25 |
are generated, the assumption being that biatx, j,
|
|
Packit |
67cb25 |
deltal, deltar are, on entry, as they were on exit
|
|
Packit |
67cb25 |
at the previous call.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
in particular, if jhigh = 0, then jout = j+1, i.e.,
|
|
Packit |
67cb25 |
just the next column of b-spline values is generated.
|
|
Packit |
67cb25 |
x - the point at which the b-splines are to be evaluated.
|
|
Packit |
67cb25 |
left - an integer chosen (usually) so that
|
|
Packit |
67cb25 |
t(left) .le. x .le. t(left+1).
|
|
Packit |
67cb25 |
j - (output) a working scalar for indexing
|
|
Packit |
67cb25 |
deltal - (output) a working area which must be of length at least jout
|
|
Packit |
67cb25 |
deltar - (output) a working area which must be of length at least jout
|
|
Packit |
67cb25 |
biatx - (output) array of length jout, with biatx(i)
|
|
Packit |
67cb25 |
containing the value at x of the polynomial of order
|
|
Packit |
67cb25 |
jout which agrees with the b-spline b(left-jout+i,jout,t)
|
|
Packit |
67cb25 |
on the interval (t(left), t(left+1)) .
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Method:
|
|
Packit |
67cb25 |
the recurrence relation
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
x - t(i) t(i+j+1) - x
|
|
Packit |
67cb25 |
b(i,j+1)(x) = -----------b(i,j)(x) + ---------------b(i+1,j)(x)
|
|
Packit |
67cb25 |
t(i+j)-t(i) t(i+j+1)-t(i+1)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
is used (repeatedly) to generate the (j+1)-vector b(left-j,j+1)(x),
|
|
Packit |
67cb25 |
...,b(left,j+1)(x) from the j-vector b(left-j+1,j)(x),...,
|
|
Packit |
67cb25 |
b(left,j)(x), storing the new values in biatx over the old. the
|
|
Packit |
67cb25 |
facts that
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
b(i,1) = 1 if t(i) .le. x .lt. t(i+1)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
and that
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
b(i,j)(x) = 0 unless t(i) .le. x .lt. t(i+j)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
are used. the particular organization of the calculations follows
|
|
Packit |
67cb25 |
algorithm (8) in chapter x of [1].
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes:
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
(1) This is a direct translation of PPPACK's bsplvb routine with
|
|
Packit |
67cb25 |
j, deltal, deltar rewritten as input parameters and
|
|
Packit |
67cb25 |
utilizing zero-based indexing.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
(2) This routine contains no error checking. Please use routines
|
|
Packit |
67cb25 |
like gsl_bspline_eval().
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void
|
|
Packit |
67cb25 |
bspline_pppack_bsplvb (const gsl_vector * t,
|
|
Packit |
67cb25 |
const size_t jhigh,
|
|
Packit |
67cb25 |
const size_t index,
|
|
Packit |
67cb25 |
const double x,
|
|
Packit |
67cb25 |
const size_t left,
|
|
Packit |
67cb25 |
size_t * j,
|
|
Packit |
67cb25 |
gsl_vector * deltal,
|
|
Packit |
67cb25 |
gsl_vector * deltar, gsl_vector * biatx)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t i; /* looping */
|
|
Packit |
67cb25 |
double saved;
|
|
Packit |
67cb25 |
double term;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (index == 1)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
*j = 0;
|
|
Packit |
67cb25 |
gsl_vector_set (biatx, 0, 1.0);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for ( /* NOP */ ; *j < jhigh - 1; *j += 1)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_vector_set (deltar, *j, gsl_vector_get (t, left + *j + 1) - x);
|
|
Packit |
67cb25 |
gsl_vector_set (deltal, *j, x - gsl_vector_get (t, left - *j));
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
saved = 0.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i <= *j; i++)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
term = gsl_vector_get (biatx, i) / (gsl_vector_get (deltar, i)
|
|
Packit |
67cb25 |
+ gsl_vector_get (deltal,
|
|
Packit |
67cb25 |
*j - i));
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_set (biatx, i,
|
|
Packit |
67cb25 |
saved + gsl_vector_get (deltar, i) * term);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
saved = gsl_vector_get (deltal, *j - i) * term;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_set (biatx, *j + 1, saved);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return;
|
|
Packit |
67cb25 |
} /* gsl_bspline_pppack_bsplvb */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
bspline_pppack_bsplvd()
|
|
Packit |
67cb25 |
calculates value and derivs of all b-splines which do not vanish at x
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Parameters:
|
|
Packit |
67cb25 |
t - the knot array, of length left+k (at least)
|
|
Packit |
67cb25 |
k - the order of the b-splines to be evaluated
|
|
Packit |
67cb25 |
x - the point at which these values are sought
|
|
Packit |
67cb25 |
left - an integer indicating the left endpoint of the interval
|
|
Packit |
67cb25 |
of interest. the k b-splines whose support contains the
|
|
Packit |
67cb25 |
interval (t(left), t(left+1)) are to be considered.
|
|
Packit |
67cb25 |
it is assumed that t(left) .lt. t(left+1)
|
|
Packit |
67cb25 |
division by zero will result otherwise (in bsplvb).
|
|
Packit |
67cb25 |
also, the output is as advertised only if
|
|
Packit |
67cb25 |
t(left) .le. x .le. t(left+1) .
|
|
Packit |
67cb25 |
deltal - a working area which must be of length at least k
|
|
Packit |
67cb25 |
deltar - a working area which must be of length at least k
|
|
Packit |
67cb25 |
a - an array of order (k,k), to contain b-coeffs of the
|
|
Packit |
67cb25 |
derivatives of a certain order of the k b-splines
|
|
Packit |
67cb25 |
of interest.
|
|
Packit |
67cb25 |
dbiatx - an array of order (k,nderiv). its entry (i,m) contains
|
|
Packit |
67cb25 |
value of (m)th derivative of (left-k+i)-th b-spline
|
|
Packit |
67cb25 |
of order k for knot sequence t, i=1,...,k, m=0,...,nderiv.
|
|
Packit |
67cb25 |
nderiv - an integer indicating that values of b-splines and
|
|
Packit |
67cb25 |
their derivatives up to AND INCLUDING the nderiv-th
|
|
Packit |
67cb25 |
are asked for. (nderiv is replaced internally by the
|
|
Packit |
67cb25 |
integer mhigh in (1,k) closest to it.)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Method:
|
|
Packit |
67cb25 |
values at x of all the relevant b-splines of order k,k-1,..., k+1-nderiv
|
|
Packit |
67cb25 |
are generated via bsplvb and stored temporarily in dbiatx. then, the
|
|
Packit |
67cb25 |
b-coeffs of the required derivatives of the b-splines of interest are
|
|
Packit |
67cb25 |
generated by differencing, each from the preceeding one of lower order,
|
|
Packit |
67cb25 |
and combined with the values of b-splines of corresponding order in
|
|
Packit |
67cb25 |
dbiatx to produce the desired values .
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes:
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
(1) This is a direct translation of PPPACK's bsplvd routine with
|
|
Packit |
67cb25 |
deltal, deltar rewritten as input parameters (to later feed them
|
|
Packit |
67cb25 |
to bspline_pppack_bsplvb) and utilizing zero-based indexing.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
(2) This routine contains no error checking.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void
|
|
Packit |
67cb25 |
bspline_pppack_bsplvd (const gsl_vector * t,
|
|
Packit |
67cb25 |
const size_t k,
|
|
Packit |
67cb25 |
const double x,
|
|
Packit |
67cb25 |
const size_t left,
|
|
Packit |
67cb25 |
gsl_vector * deltal,
|
|
Packit |
67cb25 |
gsl_vector * deltar,
|
|
Packit |
67cb25 |
gsl_matrix * a,
|
|
Packit |
67cb25 |
gsl_matrix * dbiatx, const size_t nderiv)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int i, ideriv, il, j, jlow, jp1mid, kmm, ldummy, m, mhigh;
|
|
Packit |
67cb25 |
double factor, fkmm, sum;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
size_t bsplvb_j;
|
|
Packit |
67cb25 |
gsl_vector_view dbcol = gsl_matrix_column (dbiatx, 0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
mhigh = GSL_MIN_INT (nderiv, k - 1);
|
|
Packit |
67cb25 |
bspline_pppack_bsplvb (t, k - mhigh, 1, x, left, &bsplvb_j, deltal, deltar,
|
|
Packit |
67cb25 |
&dbcol.vector);
|
|
Packit |
67cb25 |
if (mhigh > 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* the first column of dbiatx always contains the b-spline
|
|
Packit |
67cb25 |
values for the current order. these are stored in column
|
|
Packit |
67cb25 |
k-current order before bsplvb is called to put values
|
|
Packit |
67cb25 |
for the next higher order on top of it. */
|
|
Packit |
67cb25 |
ideriv = mhigh;
|
|
Packit |
67cb25 |
for (m = 1; m <= mhigh; m++)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (j = ideriv, jp1mid = 0; j < (int) k; j++, jp1mid++)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_matrix_set (dbiatx, j, ideriv,
|
|
Packit |
67cb25 |
gsl_matrix_get (dbiatx, jp1mid, 0));
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
ideriv--;
|
|
Packit |
67cb25 |
bspline_pppack_bsplvb (t, k - ideriv, 2, x, left, &bsplvb_j, deltal,
|
|
Packit |
67cb25 |
deltar, &dbcol.vector);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* at this point, b(left-k+i, k+1-j)(x) is in dbiatx(i,j)
|
|
Packit |
67cb25 |
for i=j,...,k-1 and j=0,...,mhigh. in particular, the
|
|
Packit |
67cb25 |
first column of dbiatx is already in final form. to obtain
|
|
Packit |
67cb25 |
corresponding derivatives of b-splines in subsequent columns,
|
|
Packit |
67cb25 |
generate their b-repr. by differencing, then evaluate at x. */
|
|
Packit |
67cb25 |
jlow = 0;
|
|
Packit |
67cb25 |
for (i = 0; i < (int) k; i++)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (j = jlow; j < (int) k; j++)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_matrix_set (a, j, i, 0.0);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
jlow = i;
|
|
Packit |
67cb25 |
gsl_matrix_set (a, i, i, 1.0);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* at this point, a(.,j) contains the b-coeffs for the j-th of the
|
|
Packit |
67cb25 |
k b-splines of interest here. */
|
|
Packit |
67cb25 |
for (m = 1; m <= mhigh; m++)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
kmm = k - m;
|
|
Packit |
67cb25 |
fkmm = (float) kmm;
|
|
Packit |
67cb25 |
il = left;
|
|
Packit |
67cb25 |
i = k - 1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* for j=1,...,k, construct b-coeffs of (m)th derivative
|
|
Packit |
67cb25 |
of b-splines from those for preceding derivative by
|
|
Packit |
67cb25 |
differencing and store again in a(.,j) . the fact that
|
|
Packit |
67cb25 |
a(i,j) = 0 for i .lt. j is used. */
|
|
Packit |
67cb25 |
for (ldummy = 0; ldummy < kmm; ldummy++)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
factor =
|
|
Packit |
67cb25 |
fkmm / (gsl_vector_get (t, il + kmm) -
|
|
Packit |
67cb25 |
gsl_vector_get (t, il));
|
|
Packit |
67cb25 |
/* the assumption that t(left).lt.t(left+1) makes
|
|
Packit |
67cb25 |
denominator in factor nonzero. */
|
|
Packit |
67cb25 |
for (j = 0; j <= i; j++)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_matrix_set (a, i, j, factor * (gsl_matrix_get (a, i, j)
|
|
Packit |
67cb25 |
- gsl_matrix_get (a,
|
|
Packit |
67cb25 |
i - 1,
|
|
Packit |
67cb25 |
j)));
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
il--;
|
|
Packit |
67cb25 |
i--;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* for i=1,...,k, combine b-coeffs a(.,i) with b-spline values
|
|
Packit |
67cb25 |
stored in dbiatx(.,m) to get value of (m)th derivative
|
|
Packit |
67cb25 |
of i-th b-spline (of interest here) at x, and store in
|
|
Packit |
67cb25 |
dbiatx(i,m). storage of this value over the value of a
|
|
Packit |
67cb25 |
b-spline of order m there is safe since the remaining
|
|
Packit |
67cb25 |
b-spline derivatives of the same order do not use this
|
|
Packit |
67cb25 |
value due to the fact that a(j,i) = 0 for j .lt. i . */
|
|
Packit |
67cb25 |
for (i = 0; i < (int) k; i++)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
sum = 0;
|
|
Packit |
67cb25 |
jlow = GSL_MAX_INT (i, m);
|
|
Packit |
67cb25 |
for (j = jlow; j < (int) k; j++)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
sum +=
|
|
Packit |
67cb25 |
gsl_matrix_get (a, j, i) * gsl_matrix_get (dbiatx, j, m);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
gsl_matrix_set (dbiatx, i, m, sum);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
} /* bspline_pppack_bsplvd */
|