This is the mail archive of the gsl-discuss@sourceware.org mailing list for the GSL project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [Help-gsl] Submitted patch to add bspline derivative capabilities


Hi Brian and Patrick,

The attached patch moves the derivative functionality into a separate
workspace.  Users allocate a gsl_bspline_workspace then a
gsl_bspline_deriv_workspace if they need the new capabilities.  All
the derivative-related functions are named like gsl_bspline_deriv_* to
help make the separation clear.  The patch includes updates to
doc/bspline.texi.

Applies cleanly to savannah and Brian's bspline-compat branch.  Brian,
I'm not sure if I missed running a specific compatibility test in your
branch or not...  If you had one in there, I missed it and haven't run
it.

- Rhys

On Fri, Dec 5, 2008 at 4:40 PM, Rhys Ulerich <rhys.ulerich@gmail.com> wrote:
> I'll break out the bspline derivative workspace and get back to you guys
> with a patch.
>
> FYI, the derivative workspace storage is O(order^2) in contrast to the
> evaluation workspace being only O(order).  Leading constant on the
> derivative storage term is small, but I could see where later joining the
> workspaces is a disadvantage for someone needing only evaluation
> capabilities.
>
> - Rhys
>
> On Fri, Dec 5, 2008 at 1:10 PM, Patrick Alken <patrick.alken@colorado.edu>
> wrote:
>>
>> Ah I hadn't considered this issue. If there are other areas of
>> GSL which have the same issues maybe we should keep a list so
>> when there is a major new release like 2.0 we could integrate
>> these "extra" workspaces? Of course one problem with that is
>> if we have a separate workspace for bspline derivatives it may
>> never be convenient to integrate it with the normal bspline
>> workspace.
>>
>> On Fri, Dec 05, 2008 at 06:56:15PM +0000, Brian Gough wrote:
>> > I noticed a problem when preparing the new release.  The extra entries
>> > in the bspline derivatives workspace break binary compatibility.
>> >
>> > This isn't necessarily a huge problem, but it seems undesirable to
>> > force an upgrade of all applications just for those two struct
>> > entries.  If we're going to break binary compatibility we may as well
>> > do it for all other functions that need it at the same time.
>> >
>> > So I'd propose using a separate workspace for the derivative functions
>> > in this release.
>> >
>> > See e.g.  branch bspline-compat at
>> > http://src.network-theory.com/gsl.git/
>> > which is basically finished, I just need to add some error checking.
>
>
Move bspline derivative data into separate workspace.

From: Rhys Ulerich <rhys.ulerich@gmail.com>

Required for binary compatibility with existing code.
---

 bspline/TODO          |    3 
 bspline/bspline.c     |  558 +++++++++++++++++++++++++++----------------------
 bspline/gsl_bspline.h |   66 ++++--
 bspline/test.c        |   20 +-
 doc/bspline.texi      |   21 ++
 5 files changed, 389 insertions(+), 279 deletions(-)

diff --git a/bspline/TODO b/bspline/TODO
index 41e9bf0..37a52c3 100644
--- a/bspline/TODO
+++ b/bspline/TODO
@@ -1,5 +1,8 @@
 Add functions:
 
+add bspline derivatve code to examples/bspline.c or produce a 
+derivative-related example.
+
 gsl_bspline_smooth to fit smoothing splines to data more efficiently
 than the standard least squares inversion (see pppack l2appr and
 smooth.spline() from GNU R)
diff --git a/bspline/bspline.c b/bspline/bspline.c
index 45bd628..f286707 100644
--- a/bspline/bspline.c
+++ b/bspline/bspline.c
@@ -36,12 +36,12 @@
  *
  */
 
+static inline size_t
+bspline_find_interval(const double x, int *flag, gsl_bspline_workspace *w);
 
-static inline size_t bspline_find_interval(const double x, int *flag,
-    gsl_bspline_workspace *w);
-
-static inline int bspline_process_interval_for_eval(
-  const double x, size_t *i, int flag, gsl_bspline_workspace *w);
+static inline int
+bspline_process_interval_for_eval(const double x, size_t *i, int flag,
+                                  gsl_bspline_workspace *w);
 
 static void
 bspline_pppack_bsplvb(const gsl_vector *t,
@@ -68,7 +68,7 @@ bspline_pppack_bsplvd(const gsl_vector *t,
 /*
 gsl_bspline_alloc()
   Allocate space for a bspline workspace. The size of the
-workspace is O(5k + nbreak + 2k^2)
+workspace is O(5k + nbreak)
 
 Inputs: k      - spline order (cubic = 4)
         nbreak - number of breakpoints
@@ -91,8 +91,7 @@ gsl_bspline_alloc(const size_t k, const size_t nbreak)
     {
       gsl_bspline_workspace *w;
 
-      w = (gsl_bspline_workspace *)
-          calloc(1, sizeof(gsl_bspline_workspace));
+      w = (gsl_bspline_workspace *) calloc(1, sizeof(gsl_bspline_workspace));
       if (w == 0)
         {
           GSL_ERROR_NULL("failed to allocate space for workspace", GSL_ENOMEM);
@@ -108,7 +107,8 @@ gsl_bspline_alloc(const size_t k, const size_t nbreak)
       if (w->knots == 0)
         {
           gsl_bspline_free(w);
-          GSL_ERROR_NULL("failed to allocate space for knots vector", GSL_ENOMEM);
+          GSL_ERROR_NULL("failed to allocate space for knots vector",
+                         GSL_ENOMEM);
         }
 
       w->deltal = gsl_vector_alloc(k);
@@ -116,58 +116,120 @@ gsl_bspline_alloc(const size_t k, const size_t nbreak)
       if (!w->deltal || !w->deltar)
         {
           gsl_bspline_free(w);
-          GSL_ERROR_NULL("failed to allocate space for delta vectors", GSL_ENOMEM);
+          GSL_ERROR_NULL("failed to allocate space for delta vectors",
+                         GSL_ENOMEM);
         }
 
       w->A = gsl_matrix_alloc(k, k);
       if (w->A == 0)
         {
           gsl_bspline_free(w);
-          GSL_ERROR_NULL("failed to allocate space for derivative work matrix", GSL_ENOMEM);
+          GSL_ERROR_NULL("failed to allocate space for derivative work matrix",
+                         GSL_ENOMEM);
         }
 
       w->B = gsl_vector_alloc(k);
       if (w->B == 0)
         {
           gsl_bspline_free(w);
-          GSL_ERROR_NULL("failed to allocate space for temporary spline vector", GSL_ENOMEM);
+          GSL_ERROR_NULL(
+            "failed to allocate space for temporary spline vector",
+            GSL_ENOMEM);
         }
 
       w->dB = gsl_matrix_alloc(k, k + 1);
       if (w->dB == 0)
         {
           gsl_bspline_free(w);
-          GSL_ERROR_NULL("failed to allocate space for temporary derivative matrix", GSL_ENOMEM);
+          GSL_ERROR_NULL(
+            "failed to allocate space for temporary derivative matrix",
+            GSL_ENOMEM);
         }
 
-
       return (w);
     }
 } /* gsl_bspline_alloc() */
 
+/*
+gsl_bspline_deriv_alloc()
+  Allocate space for a bspline derivative workspace. The size of the
+workspace is O(2k^2)
+
+Inputs: bspline - gsl_bspline_workspace of the associated bspline
+
+Return: pointer to workspace
+*/
+
+gsl_bspline_deriv_workspace *
+gsl_bspline_deriv_alloc(gsl_bspline_workspace * bspline)
+{
+  if (bspline == 0)
+    {
+      GSL_ERROR_NULL("bspline must not be null", GSL_EINVAL);
+    }
+  else if (bspline->k == 0)
+    {
+      /* Not strictly necessary, but a sanity check on the bspline */
+      GSL_ERROR_NULL("k must be at least 1", GSL_EINVAL);
+    }
+  else
+    {
+      gsl_bspline_deriv_workspace *w;
+
+      w = (gsl_bspline_deriv_workspace *) calloc(1,
+          sizeof(gsl_bspline_deriv_workspace));
+      if (w == 0)
+        {
+          GSL_ERROR_NULL("failed to allocate space for workspace", GSL_ENOMEM);
+        }
+
+      w->A = gsl_matrix_alloc(bspline->k, bspline->k);
+      if (w->A == 0)
+        {
+          gsl_bspline_deriv_free(w);
+          GSL_ERROR_NULL("failed to allocate space for derivative work matrix",
+                         GSL_ENOMEM);
+        }
+
+      w->dB = gsl_matrix_alloc(bspline->k, bspline->k + 1);
+      if (w->dB == 0)
+        {
+          gsl_bspline_deriv_free(w);
+          GSL_ERROR_NULL(
+            "failed to allocate space for temporary derivative matrix",
+            GSL_ENOMEM);
+        }
+
+      w->bspline = bspline;
+
+      return (w);
+    }
+} /* gsl_bspline_deriv_alloc() */
+
 /* Return number of coefficients */
 size_t
-gsl_bspline_ncoeffs (gsl_bspline_workspace * w)
+gsl_bspline_ncoeffs(gsl_bspline_workspace * w)
 {
   return w->n;
 }
 
 /* Return order */
 size_t
-gsl_bspline_order (gsl_bspline_workspace * w)
+gsl_bspline_order(gsl_bspline_workspace * w)
 {
   return w->k;
 }
 
 /* Return number of breakpoints */
 size_t
-gsl_bspline_nbreak (gsl_bspline_workspace * w)
+gsl_bspline_nbreak(gsl_bspline_workspace * w)
 {
   return w->nbreak;
 }
 
+/* Return the location of the i-th breakpoint*/
 double
-gsl_bspline_breakpoint (size_t i, gsl_bspline_workspace * w)
+gsl_bspline_breakpoint(size_t i, gsl_bspline_workspace * w)
 {
   size_t j = i + w->k - 1;
   return gsl_vector_get(w->knots, j);
@@ -175,7 +237,8 @@ gsl_bspline_breakpoint (size_t i, gsl_bspline_workspace * w)
 
 /*
 gsl_bspline_free()
-  Free a bspline workspace
+  Free a gsl_bspline_workspace.
+Any associated gsl_bspline_deriv_workspace should be freed beforehand.
 
 Inputs: w - workspace to free
 
@@ -194,28 +257,46 @@ gsl_bspline_free(gsl_bspline_workspace *w)
   if (w->deltar)
     gsl_vector_free(w->deltar);
 
-  if (w->A)
-    gsl_matrix_free(w->A);
-
   if (w->B)
     gsl_vector_free(w->B);
 
+  free(w);
+} /* gsl_bspline_free() */
+
+/*
+gsl_bspline_deriv_free()
+  Free a gsl_bspline_deriv_workspace.
+The associated gsl_bspline_workspace should be freed afterwards.
+
+Inputs: w - workspace to free
+
+Return: none
+*/
+
+void
+gsl_bspline_deriv_free(gsl_bspline_deriv_workspace *w)
+{
+  w->bspline = 0;
+
+  if (w->A)
+    gsl_matrix_free(w->A);
+
   if (w->dB)
     gsl_matrix_free(w->dB);
 
   free(w);
-} /* gsl_bspline_free() */
+} /* gsl_bspline_deriv_free() */
 
 /*
 gsl_bspline_knots()
   Compute the knots from the given breakpoints:
 
-knots(1:k) = breakpts(1)
-knots(k+1:k+l-1) = breakpts(i), i = 2 .. l
-knots(n+1:n+k) = breakpts(l + 1)
+   knots(1:k) = breakpts(1)
+   knots(k+1:k+l-1) = breakpts(i), i = 2 .. l
+   knots(n+1:n+k) = breakpts(l + 1)
 
 where l is the number of polynomial pieces (l = nbreak - 1) and
-n = k + l - 1
+   n = k + l - 1
 (using matlab syntax for the arrays)
 
 The repeated knots at the beginning and end of the interval
@@ -244,8 +325,7 @@ gsl_bspline_knots(const gsl_vector *breakpts, gsl_bspline_workspace *w)
 
       for (i = 1; i < w->l; ++i)
         {
-          gsl_vector_set(w->knots, w->k - 1 + i,
-                         gsl_vector_get(breakpts, i));
+          gsl_vector_set(w->knots, w->k - 1 + i, gsl_vector_get(breakpts, i));
         }
 
       for (i = w->n; i < w->n + w->k; ++i)
@@ -323,8 +403,7 @@ Notes: The w->knots vector must be initialized prior to calling
 */
 
 int
-gsl_bspline_eval(const double x, gsl_vector *B,
-                 gsl_bspline_workspace *w)
+gsl_bspline_eval(const double x, gsl_vector *B, gsl_bspline_workspace *w)
 {
   if (B->size != w->n)
     {
@@ -358,7 +437,6 @@ gsl_bspline_eval(const double x, gsl_vector *B,
     }
 } /* gsl_bspline_eval() */
 
-
 /*
 gsl_bspline_eval_nonzero()
   Evaluate all non-zero B-spline functions at point x.
@@ -368,7 +446,7 @@ Always B_i(x) = 0 for i < istart and for i > iend.
 Inputs: x      - point at which to evaluate splines
         Bk     - (output) where to store B-spline values (length k)
         istart - (output) B-spline function index of
-                    first non-zero basis for given x
+                 first non-zero basis for given x
         iend   - (output) B-spline function index of
                  last non-zero basis for given x.
                  This is also the knot index corresponding to x.
@@ -381,18 +459,15 @@ Notes: 1) the w->knots vector must be initialized before calling
 
        2) On output, B contains
 
-              [B_{istart,k}, B_{istart+1,k},
-               ..., B_{iend-1,k}, B_{iend,k}]
+             [B_{istart,k}, B_{istart+1,k},
+             ..., B_{iend-1,k}, B_{iend,k}]
 
           evaluated at the given x.
 */
 
 int
-gsl_bspline_eval_nonzero(const double x,
-                         gsl_vector *Bk,
-                         size_t *istart,
-                         size_t *iend,
-                         gsl_bspline_workspace *w)
+gsl_bspline_eval_nonzero(const double x, gsl_vector *Bk, size_t *istart,
+                         size_t *iend, gsl_bspline_workspace *w)
 {
   if (Bk->size != w->k)
     {
@@ -400,9 +475,9 @@ gsl_bspline_eval_nonzero(const double x,
     }
   else
     {
-      size_t i;  /* spline index */
-      size_t j;  /* looping */
-      int flag  = 0; /* interval search flag */
+      size_t i;      /* spline index */
+      size_t j;      /* looping */
+      int flag = 0;  /* interval search flag */
       int error = 0; /* error flag */
 
       i = bspline_find_interval(x, &flag, w);
@@ -415,27 +490,26 @@ gsl_bspline_eval_nonzero(const double x,
       *istart = i - w->k + 1;
       *iend = i;
 
-      bspline_pppack_bsplvb(w->knots, w->k, 1, x, *iend,
-                            &j, w->deltal, w->deltar, Bk);
+      bspline_pppack_bsplvb(w->knots, w->k, 1, x, *iend, &j, w->deltal,
+                            w->deltar, Bk);
 
       return GSL_SUCCESS;
     }
 } /* gsl_bspline_eval_nonzero() */
 
 /*
-gsl_bspline_eval_deriv()
+gsl_bspline_deriv_eval()
   Evaluate d^j/dx^j B_i(x) for all i, 0 <= j <= nderiv.
-This is a wrapper function for gsl_bspline_eval_deriv_nonzero()
+This is a wrapper function for gsl_bspline_deriv_eval_nonzero()
 which formats the output in a nice way.
 
 Inputs: x      - point for evaluation
-        nderiv - number of derivatives to compute,
-                 inclusive.
+        nderiv - number of derivatives to compute, inclusive.
         dB     - (output) where to store d^j/dx^j B_i(x)
                  values. the size of this matrix is
                  (n = nbreak + k - 2 = l + k - 1 = w->n)
                  by (nderiv + 1)
-        w      - bspline workspace
+        w      - bspline derivative workspace
 
 Return: success or error
 
@@ -446,30 +520,29 @@ Notes: 1) The w->knots vector must be initialized prior to calling
 */
 
 int
-gsl_bspline_eval_deriv(const double x,
-                       const size_t nderiv,
-                       gsl_matrix *dB,
-                       gsl_bspline_workspace *w)
+gsl_bspline_deriv_eval(const double x, const size_t nderiv, gsl_matrix *dB,
+                       gsl_bspline_deriv_workspace *w)
 {
-  if (dB->size1 != w->n)
+  if (dB->size1 != w->bspline->n)
     {
       GSL_ERROR("dB matrix first dimension not of length n", GSL_EBADLEN);
     }
-  else if (dB->size2 < nderiv+1)
+  else if (dB->size2 < nderiv + 1)
     {
-      GSL_ERROR("dB matrix second dimension must be at least length nderiv+1", GSL_EBADLEN);
+      GSL_ERROR("dB matrix second dimension must be at least length nderiv+1",
+                GSL_EBADLEN);
     }
   else
     {
-      size_t i;         /* looping */
-      size_t j;         /* looping */
-      size_t istart;    /* first non-zero spline for x */
-      size_t iend;      /* last non-zero spline for x, knot for x*/
-      int error;        /* error handling */
+      size_t i;      /* looping */
+      size_t j;      /* looping */
+      size_t istart; /* first non-zero spline for x */
+      size_t iend;   /* last non-zero spline for x, knot for x*/
+      int error;     /* error handling */
 
       /* find all non-zero d^j/dx^j B_i(x) values */
-      error = gsl_bspline_eval_deriv_nonzero(
-                x, nderiv, w->dB, &istart, &iend, w);
+      error = gsl_bspline_deriv_eval_nonzero(x, nderiv, w->dB, &istart, &iend,
+                                             w);
       if (error)
         {
           return error;
@@ -484,16 +557,16 @@ gsl_bspline_eval_deriv(const double x,
           for (i = istart; i <= iend; ++i)
             gsl_matrix_set(dB, i, j, gsl_matrix_get(w->dB, i - istart, j));
 
-          for (i = iend + 1; i < w->n; ++i)
+          for (i = iend + 1; i < w->bspline->n; ++i)
             gsl_matrix_set(dB, i, j, 0.0);
         }
 
       return GSL_SUCCESS;
     }
-} /* gsl_bspline_eval_deriv() */
+} /* gsl_bspline_deriv_eval() */
 
 /*
-gsl_bspline_eval_deriv_nonzero()
+gsl_bspline_deriv_eval_nonzero()
   At point x evaluate all requested, non-zero B-spline function
 derivatives and store them in dB.  These are the
 d^j/dx^j B_i(x) with i in [istart, iend] and j in [0, nderiv].
@@ -508,7 +581,7 @@ Inputs: x      - point at which to evaluate splines
         iend   - (output) B-spline function index of
                  last non-zero basis for given x.
                  This is also the knot index corresponding to x.
-        w      - bspline workspace
+        w      - bspline derivative workspace
 
 Return: success or error
 
@@ -517,14 +590,14 @@ Notes: 1) the w->knots vector must be initialized before calling
 
        2) On output, dB contains
 
-       [[B_{istart,  k}, ..., d^nderiv/dx^nderiv B_{istart  ,k}],
-        [B_{istart+1,k}, ..., d^nderiv/dx^nderiv B_{istart+1,k}],
-        ...
-        [B_{iend-1,  k}, ..., d^nderiv/dx^nderiv B_{iend-1,  k}],
-        [B_{iend,    k}, ..., d^nderiv/dx^nderiv B_{iend,    k}]]
+            [[B_{istart,  k}, ..., d^nderiv/dx^nderiv B_{istart  ,k}],
+             [B_{istart+1,k}, ..., d^nderiv/dx^nderiv B_{istart+1,k}],
+             ...
+             [B_{iend-1,  k}, ..., d^nderiv/dx^nderiv B_{iend-1,  k}],
+             [B_{iend,    k}, ..., d^nderiv/dx^nderiv B_{iend,    k}]]
 
-        evaluated at x.  B_{istart, k} is stored in dB(0,0).
-        Each additional column contains an additional derivative.
+          evaluated at x.  B_{istart, k} is stored in dB(0,0).
+          Each additional column contains an additional derivative.
 
        3) Note that the zero-th column of the result contains the
           0th derivative, which is simply a function evaluation.
@@ -533,48 +606,46 @@ Notes: 1) the w->knots vector must be initialized before calling
 */
 
 int
-gsl_bspline_eval_deriv_nonzero(const double x,
-                               const size_t nderiv,
-                               gsl_matrix *dB,
-                               size_t *istart,
-                               size_t *iend,
-                               gsl_bspline_workspace *w)
+gsl_bspline_deriv_eval_nonzero(const double x, const size_t nderiv,
+                               gsl_matrix *dB, size_t *istart, size_t *iend,
+                               gsl_bspline_deriv_workspace *w)
 {
-  if (dB->size1 != w->k)
+  if (dB->size1 != w->bspline->k)
     {
       GSL_ERROR("dB matrix first dimension not of length k", GSL_EBADLEN);
     }
-  else if (dB->size2 < nderiv+1)
+  else if (dB->size2 < nderiv + 1)
     {
-      GSL_ERROR("dB matrix second dimension must be at least length nderiv+1", GSL_EBADLEN);
+      GSL_ERROR("dB matrix second dimension must be at least length nderiv+1",
+                GSL_EBADLEN);
     }
   else
     {
       size_t i;      /* spline index */
       size_t j;      /* looping */
-      int flag  = 0; /* interval search flag */
+      int flag = 0;  /* interval search flag */
       int error = 0; /* error flag */
       size_t min_nderivk;
 
-      i = bspline_find_interval(x, &flag, w);
-      error = bspline_process_interval_for_eval(x, &i, flag, w);
+      i = bspline_find_interval(x, &flag, w->bspline);
+      error = bspline_process_interval_for_eval(x, &i, flag, w->bspline);
       if (error)
         {
           return error;
         }
 
-      *istart = i - w->k + 1;
+      *istart = i - w->bspline->k + 1;
       *iend = i;
 
-      bspline_pppack_bsplvd(w->knots, w->k, x, *iend,
-                            w->deltal, w->deltar, w->A, dB, nderiv);
+      bspline_pppack_bsplvd(w->bspline->knots, w->bspline->k, x, *iend,
+                            w->bspline->deltal, w->bspline->deltar, w->A, dB, nderiv);
 
       /* An order k b-spline has at most k-1 nonzero derivatives
-         so we need to zero all requested higher order derivatives */
-      min_nderivk = GSL_MIN_INT(nderiv, w->k - 1);
+       so we need to zero all requested higher order derivatives */
+      min_nderivk = GSL_MIN_INT(nderiv, w->bspline->k - 1);
       for (j = min_nderivk + 1; j <= nderiv; ++j)
         {
-          for (i = 0; i < w->k; ++i)
+          for (i = 0; i < w->bspline->k; ++i)
             {
               gsl_matrix_set(dB, i, j, 0.0);
             }
@@ -582,8 +653,7 @@ gsl_bspline_eval_deriv_nonzero(const double x,
 
       return GSL_SUCCESS;
     }
-} /* gsl_bspline_eval_deriv_nonzero() */
-
+} /* gsl_bspline_deriv_eval_nonzero() */
 
 /****************************************
  *          INTERNAL ROUTINES           *
@@ -591,10 +661,7 @@ gsl_bspline_eval_deriv_nonzero(const double x,
 
 /*
 bspline_find_interval()
-  Find knot interval such that
-
-  t_i <= x < t_{i + 1}
-
+  Find knot interval such that t_i <= x < t_{i + 1}
 where the t_i are knot values.
 
 Inputs: x    - x value
@@ -605,17 +672,16 @@ Return: i (index in w->knots corresponding to left limit of interval)
 
 Notes: The error conditions are reported as follows:
 
-Condition                        Return value        Flag
----------                        ------------        ----
-x < t_0                               0               -1
-t_i <= x < t_{i+1}                    i                0
-t_i < x = t_{i+1} = t_{n+k-1}         i                0
-t_{n+k-1} < x                       l+k-1             +1
+       Condition                        Return value        Flag
+       ---------                        ------------        ----
+       x < t_0                               0               -1
+       t_i <= x < t_{i+1}                    i                0
+       t_i < x = t_{i+1} = t_{n+k-1}         i                0
+       t_{n+k-1} < x                       l+k-1             +1
 */
 
 static inline size_t
-bspline_find_interval(const double x, int *flag,
-                      gsl_bspline_workspace *w)
+bspline_find_interval(const double x, int *flag, gsl_bspline_workspace *w)
 {
   size_t i;
 
@@ -639,8 +705,8 @@ bspline_find_interval(const double x, int *flag,
       if (ti <= x && x < tip1)
         break;
 
-      if (ti < x && x == tip1 &&
-          tip1 == gsl_vector_get(w->knots, w->k + w->l - 1))
+      if (ti < x && x == tip1 && tip1 == gsl_vector_get(w->knots, w->k + w->l
+          - 1))
         break;
     }
 
@@ -652,17 +718,16 @@ bspline_find_interval(const double x, int *flag,
   return i;
 } /* bspline_find_interval() */
 
-
 /*
 bspline_process_interval_for_eval()
-    Consumes an x location, left knot from bspline_find_interval, flag
+  Consumes an x location, left knot from bspline_find_interval, flag
 from bspline_find_interval, and a workspace.  Checks that x lies within
 the splines' knots, enforces some endpoint continuity requirements, and
 avoids divide by zero errors in the underlying bspline_pppack_* functions.
- */
-static inline int bspline_process_interval_for_eval(
-  const double x, size_t *i, const int flag, gsl_bspline_workspace
-  *w)
+*/
+static inline int
+bspline_process_interval_for_eval(const double x, size_t *i, const int flag,
+                                  gsl_bspline_workspace *w)
 {
   if (flag == -1)
     {
@@ -689,7 +754,6 @@ static inline int bspline_process_interval_for_eval(
   return GSL_SUCCESS;
 } /* bspline_process_interval_for_eval */
 
-
 /********************************************************************
  * PPPACK ROUTINES
  *
@@ -705,66 +769,71 @@ bspline_pppack_bsplvb()
 jout = max( jhigh , (j+1)*(index-1) ) with knot sequence t.
 
 Parameters:
-        t      - knot sequence, of length left + jout , assumed to be
-                 nondecreasing.  assumption t(left).lt.t(left + 1).
-                 division by zero  will result if t(left) = t(left+1)
-        jhigh  -
-        index  - integers which determine the order jout = max(jhigh,
-                 (j+1)*(index-1))  of the b-splines whose values at x
-                 are to be returned.  index  is used to avoid
-                 recalculations when several columns of the triangular
-                 array of b-spline values are needed (e.g., in  bsplpp
-                 or in  bsplvd ).
-                 precisely, if  index = 1 ,
-                   the calculation starts from scratch and the entire
-                   triangular array of b-spline values of orders
-                   1,2,...,jhigh  is generated order by order , i.e.,
-                   column by column .
-                 if  index = 2 ,
-                   only the b-spline values of order j+1, j+2, ..., jout
-                   are generated, the assumption being that biatx, j,
-                   deltal, deltar are, on entry, as they were on exit
-                   at the previous call.
-                   in particular, if jhigh = 0, then jout = j+1, i.e.,
-                   just the next column of b-spline values is generated.
-        x      - the point at which the b-splines are to be evaluated.
-        left   - an integer chosen (usually) so that
-                 t(left) .le. x .le. t(left+1).
-        j      - (output) a working scalar for indexing
-        deltal - (output) a working area which must be of length at
-                 least jout
-        deltar - (output) a working area which must be of length at
-                 least jout
-        biatx  - (output) array of length jout, with  biatx(i)
-                 containing the value at  x  of the polynomial of order
-                 jout which agrees with the b-spline b(left-jout+i,jout,t)
-                 on the interval (t(left), t(left+1)) .
+   t      - knot sequence, of length left + jout , assumed to be
+            nondecreasing.  assumption t(left).lt.t(left + 1).
+            division by zero  will result if t(left) = t(left+1)
+   jhigh  -
+   index  - integers which determine the order jout = max(jhigh,
+            (j+1)*(index-1))  of the b-splines whose values at x
+            are to be returned.  index  is used to avoid
+            recalculations when several columns of the triangular
+            array of b-spline values are needed (e.g., in  bsplpp
+            or in  bsplvd ).  precisely,
+
+            if  index = 1 ,
+               the calculation starts from scratch and the entire
+               triangular array of b-spline values of orders
+               1,2,...,jhigh  is generated order by order , i.e.,
+               column by column .
+
+            if  index = 2 ,
+               only the b-spline values of order j+1, j+2, ..., jout
+               are generated, the assumption being that biatx, j,
+               deltal, deltar are, on entry, as they were on exit
+               at the previous call.
+
+            in particular, if jhigh = 0, then jout = j+1, i.e.,
+            just the next column of b-spline values is generated.
+   x      - the point at which the b-splines are to be evaluated.
+   left   - an integer chosen (usually) so that
+            t(left) .le. x .le. t(left+1).
+   j      - (output) a working scalar for indexing
+   deltal - (output) a working area which must be of length at least jout
+   deltar - (output) a working area which must be of length at least jout
+   biatx  - (output) array of length jout, with  biatx(i)
+            containing the value at  x  of the polynomial of order
+            jout which agrees with the b-spline b(left-jout+i,jout,t)
+            on the interval (t(left), t(left+1)) .
 
 Method:
-      the recurrence relation
-
-                        x - t(i)              t(i+j+1) - x
-        b(i,j+1)(x) = -----------b(i,j)(x) + ---------------b(i+1,j)(x)
-                      t(i+j)-t(i)            t(i+j+1)-t(i+1)
-
-      is used (repeatedly) to generate the (j+1)-vector  b(left-j,j+1)(x),
-      ...,b(left,j+1)(x)  from the j-vector  b(left-j+1,j)(x),...,
-      b(left,j)(x), storing the new values in  biatx  over the old. the
-      facts that
-                b(i,1) = 1  if  t(i) .le. x .lt. t(i+1)
-      and that
-                b(i,j)(x) = 0  unless  t(i) .le. x .lt. t(i+j)
-      are used. the particular organization of the calculations follows
-      algorithm (8) in chapter x of [1].
+   the recurrence relation
+
+                      x - t(i)              t(i+j+1) - x
+      b(i,j+1)(x) = -----------b(i,j)(x) + ---------------b(i+1,j)(x)
+                    t(i+j)-t(i)            t(i+j+1)-t(i+1)
+
+   is used (repeatedly) to generate the (j+1)-vector  b(left-j,j+1)(x),
+   ...,b(left,j+1)(x)  from the j-vector  b(left-j+1,j)(x),...,
+   b(left,j)(x), storing the new values in  biatx  over the old. the
+   facts that
+
+      b(i,1) = 1  if  t(i) .le. x .lt. t(i+1)
+
+   and that
+
+      b(i,j)(x) = 0  unless  t(i) .le. x .lt. t(i+j)
+
+   are used. the particular organization of the calculations follows
+   algorithm (8) in chapter x of [1].
 
 Notes:
 
-    (1) This is a direct translation of PPPACK's bsplvb routine with
-        j, deltal, deltar rewritten as input parameters and
-        utilizing zero-based indexing.
+   (1) This is a direct translation of PPPACK's bsplvb routine with
+       j, deltal, deltar rewritten as input parameters and
+       utilizing zero-based indexing.
 
-    (2) This routine contains no error checking.  Please use routines
-        like gsl_bspline_eval().
+   (2) This routine contains no error checking.  Please use routines
+       like gsl_bspline_eval().
 */
 
 static void
@@ -778,7 +847,7 @@ bspline_pppack_bsplvb(const gsl_vector *t,
                       gsl_vector *deltar,
                       gsl_vector *biatx)
 {
-  size_t i;   /* looping */
+  size_t i; /* looping */
   double saved;
   double term;
 
@@ -797,12 +866,10 @@ bspline_pppack_bsplvb(const gsl_vector *t,
 
       for (i = 0; i <= *j; ++i)
         {
-          term = gsl_vector_get(biatx, i) /
-                 (gsl_vector_get(deltar, i) +
-                  gsl_vector_get(deltal, *j - i));
+          term = gsl_vector_get(biatx, i) / (gsl_vector_get(deltar, i)
+                                             + gsl_vector_get(deltal, *j - i));
 
-          gsl_vector_set(biatx, i,
-                         saved + gsl_vector_get(deltar, i) * term);
+          gsl_vector_set(biatx, i, saved + gsl_vector_get(deltar, i) * term);
 
           saved = gsl_vector_get(deltal, *j - i) * term;
         }
@@ -815,48 +882,47 @@ bspline_pppack_bsplvb(const gsl_vector *t,
 
 /*
 bspline_pppack_bsplvd()
-calculates value and derivs of all b-splines which do not vanish at x
+  calculates value and derivs of all b-splines which do not vanish at x
 
 Parameters:
-        t      - the knot array, of length left+k (at least)
-        k      - the order of the b-splines to be evaluated
-        x      - the point at which these values are sought
-        left   - an integer indicating the left endpoint of the interval
-                 of interest. the k b-splines whose support contains the
-                 interval (t(left), t(left+1)) are to be considered.
-                 it is assumed that t(left) .lt. t(left+1)
-                 division by zero will result otherwise (in  bsplvb).
-                 also, the output is as advertised only if
-                 t(left) .le. x .le. t(left+1) .
-        deltal - a working area which must be of length at least k
-        deltar - a working area which must be of length at least k
-        a      - an array of order (k,k), to contain b-coeffs of the
-                 derivatives of a certain order of the k b-splines
-                 of interest.
-        dbiatx - an array of order (k,nderiv). its entry (i,m) contains
-                 value of (m)th derivative of (left-k+i)-th b-spline
-                 of order k for knot sequence  t, i=1,...,k,
-                 m=0,...,nderiv.
-        nderiv - an integer indicating that values of b-splines and
-                 their derivatives up to AND INCLUDING the nderiv-th
-                 are asked for. (nderiv is replaced internally by the
-                 integer mhigh in (1,k) closest to it.)
+   t      - the knot array, of length left+k (at least)
+   k      - the order of the b-splines to be evaluated
+   x      - the point at which these values are sought
+   left   - an integer indicating the left endpoint of the interval
+            of interest. the k b-splines whose support contains the
+            interval (t(left), t(left+1)) are to be considered.
+            it is assumed that t(left) .lt. t(left+1)
+            division by zero will result otherwise (in  bsplvb).
+            also, the output is as advertised only if
+            t(left) .le. x .le. t(left+1) .
+   deltal - a working area which must be of length at least k
+   deltar - a working area which must be of length at least k
+   a      - an array of order (k,k), to contain b-coeffs of the
+            derivatives of a certain order of the k b-splines
+            of interest.
+   dbiatx - an array of order (k,nderiv). its entry (i,m) contains
+            value of (m)th derivative of (left-k+i)-th b-spline
+            of order k for knot sequence  t, i=1,...,k, m=0,...,nderiv.
+   nderiv - an integer indicating that values of b-splines and
+            their derivatives up to AND INCLUDING the nderiv-th
+            are asked for. (nderiv is replaced internally by the
+            integer mhigh in (1,k) closest to it.)
 
 Method:
-  values at x of all the relevant b-splines of order k,k-1,..., k+1-nderiv
-  are generated via bsplvb and stored temporarily in dbiatx.  then, the
-  b-coeffs of the required derivatives of the b-splines of interest are
-  generated by differencing, each from the preceeding one of lower order,
-  and combined with the values of b-splines of corresponding order in
-  dbiatx  to produce the desired values .
+   values at x of all the relevant b-splines of order k,k-1,..., k+1-nderiv
+   are generated via bsplvb and stored temporarily in dbiatx.  then, the
+   b-coeffs of the required derivatives of the b-splines of interest are
+   generated by differencing, each from the preceeding one of lower order,
+   and combined with the values of b-splines of corresponding order in
+   dbiatx  to produce the desired values .
 
 Notes:
 
-    (1) This is a direct translation of PPPACK's bsplvd routine with
-        deltal, deltar rewritten as input parameters (to later feed them
-        to bspline_pppack_bsplvb) and utilizing zero-based indexing.
+   (1) This is a direct translation of PPPACK's bsplvd routine with
+       deltal, deltar rewritten as input parameters (to later feed them
+       to bspline_pppack_bsplvb) and utilizing zero-based indexing.
 
-    (2) This routine contains no error checking.
+   (2) This routine contains no error checking.
 */
 
 static void
@@ -877,36 +943,36 @@ bspline_pppack_bsplvd(const gsl_vector *t,
   gsl_vector_view dbcol = gsl_matrix_column(dbiatx, 0);
 
   mhigh = GSL_MIN_INT(nderiv, k - 1);
-  bspline_pppack_bsplvb(t, k-mhigh, 1, x, left,
-                        &bsplvb_j, deltal, deltar, &dbcol.vector);
+  bspline_pppack_bsplvb(t, k - mhigh, 1, x, left, &bsplvb_j, deltal, deltar,
+                        &dbcol.vector);
   if (mhigh > 0)
     {
       /* the first column of dbiatx always contains the b-spline
-         values for the current order. these are stored in column
-         k-current order before bsplvb is called to put values
-         for the next higher order on top of it.  */
+       values for the current order. these are stored in column
+       k-current order before bsplvb is called to put values
+       for the next higher order on top of it.  */
       ideriv = mhigh;
       for (m = 1; m <= mhigh; ++m)
         {
-          for (j = ideriv, jp1mid = 0; j < (int)k; ++j, ++jp1mid)
+          for (j = ideriv, jp1mid = 0; j < (int) k; ++j, ++jp1mid)
             {
-              gsl_matrix_set(dbiatx, j, ideriv,
-                             gsl_matrix_get(dbiatx, jp1mid, 0));
+              gsl_matrix_set(dbiatx, j, ideriv, gsl_matrix_get(dbiatx, jp1mid,
+                             0));
             }
           --ideriv;
-          bspline_pppack_bsplvb(t, k-ideriv, 2, x, left,
-                                &bsplvb_j, deltal, deltar, &dbcol.vector);
+          bspline_pppack_bsplvb(t, k - ideriv, 2, x, left, &bsplvb_j, deltal,
+                                deltar, &dbcol.vector);
         }
 
       /* at this point,  b(left-k+i, k+1-j)(x) is in  dbiatx(i,j)
-         for i=j,...,k-1 and j=0,...,mhigh. in particular, the
-         first column of dbiatx is already in final form. to obtain
-         corresponding derivatives of b-splines in subsequent columns,
-         generate their b-repr. by differencing, then evaluate at x. */
+       for i=j,...,k-1 and j=0,...,mhigh. in particular, the
+       first column of dbiatx is already in final form. to obtain
+       corresponding derivatives of b-splines in subsequent columns,
+       generate their b-repr. by differencing, then evaluate at x. */
       jlow = 0;
-      for (i = 0; i < (int)k; ++i)
+      for (i = 0; i < (int) k; ++i)
         {
-          for (j = jlow; j < (int)k; ++j)
+          for (j = jlow; j < (int) k; ++j)
             {
               gsl_matrix_set(a, j, i, 0.0);
             }
@@ -915,7 +981,7 @@ bspline_pppack_bsplvd(const gsl_vector *t,
         }
 
       /* at this point, a(.,j) contains the b-coeffs for the j-th of the
-         k b-splines of interest here. */
+       k b-splines of interest here. */
       for (m = 1; m <= mhigh; ++m)
         {
           kmm = k - m;
@@ -924,40 +990,38 @@ bspline_pppack_bsplvd(const gsl_vector *t,
           i = k - 1;
 
           /* for j=1,...,k, construct b-coeffs of (m)th  derivative
-             of b-splines from those for preceding derivative by
-             differencing and store again in  a(.,j) . the fact that
-             a(i,j) = 0  for i .lt. j  is used. */
+           of b-splines from those for preceding derivative by
+           differencing and store again in  a(.,j) . the fact that
+           a(i,j) = 0  for i .lt. j  is used. */
           for (ldummy = 0; ldummy < kmm; ++ldummy)
             {
-              factor = fkmm/(
-                         gsl_vector_get(t, il + kmm) - gsl_vector_get(t, il)
-                       );
+              factor = fkmm / (gsl_vector_get(t, il + kmm) - gsl_vector_get(t,
+                               il));
               /* the assumption that t(left).lt.t(left+1) makes
-                 denominator in factor nonzero. */
-              for (j = 0; j <=i; ++j)
+               denominator in factor nonzero. */
+              for (j = 0; j <= i; ++j)
                 {
-                  gsl_matrix_set(a, i, j, factor*(
-                                   gsl_matrix_get(a, i, j) - gsl_matrix_get(a, i-1, j)));
+                  gsl_matrix_set(a, i, j, factor * (gsl_matrix_get(a, i, j)
+                                                    - gsl_matrix_get(a, i - 1, j)));
                 }
               --il;
               --i;
             }
 
           /* for i=1,...,k, combine b-coeffs a(.,i) with b-spline values
-             stored in dbiatx(.,m) to get value of (m)th  derivative
-             of i-th b-spline (of interest here) at x, and store in
-             dbiatx(i,m). storage of this value over the value of a
-             b-spline of order m there is safe since the remaining
-             b-spline derivatives of the same order do not use this
-             value due to the fact that a(j,i) = 0 for j .lt. i . */
-          for (i = 0; i < (int)k; ++i)
+           stored in dbiatx(.,m) to get value of (m)th  derivative
+           of i-th b-spline (of interest here) at x, and store in
+           dbiatx(i,m). storage of this value over the value of a
+           b-spline of order m there is safe since the remaining
+           b-spline derivatives of the same order do not use this
+           value due to the fact that a(j,i) = 0 for j .lt. i . */
+          for (i = 0; i < (int) k; ++i)
             {
               sum = 0;
               jlow = GSL_MAX_INT(i, m);
-              for (j = jlow; j < (int)k; ++j)
+              for (j = jlow; j < (int) k; ++j)
                 {
-                  sum += gsl_matrix_get(a, j, i)
-                         * gsl_matrix_get(dbiatx, j, m);
+                  sum += gsl_matrix_get(a, j, i) * gsl_matrix_get(dbiatx, j, m);
                 }
               gsl_matrix_set(dbiatx, i, m, sum);
             }
diff --git a/bspline/gsl_bspline.h b/bspline/gsl_bspline.h
index 8a2ffc5..f7f8175 100644
--- a/bspline/gsl_bspline.h
+++ b/bspline/gsl_bspline.h
@@ -39,41 +39,53 @@
 __BEGIN_DECLS
 
 typedef struct
-  {
-    size_t k;      /* spline order */
-    size_t km1;    /* k - 1 (polynomial order) */
-    size_t l;      /* number of polynomial pieces on interval */
+{
+    size_t k; /* spline order */
+    size_t km1; /* k - 1 (polynomial order) */
+    size_t l; /* number of polynomial pieces on interval */
     size_t nbreak; /* number of breakpoints (l + 1) */
-    size_t n;      /* number of bspline basis functions (l + k - 1) */
+    size_t n; /* number of bspline basis functions (l + k - 1) */
 
-    gsl_vector *knots;  /* knots vector */
+    gsl_vector *knots; /* knots vector */
     gsl_vector *deltal; /* left delta */
     gsl_vector *deltar; /* right delta */
-    gsl_matrix *A;      /* work matrix */
-    gsl_vector *B;      /* temporary spline results */
-    gsl_matrix *dB;     /* temporary derivative results */
-  } gsl_bspline_workspace;
+    gsl_matrix *A; /* work matrix */
+    gsl_vector *B; /* temporary spline results */
+    gsl_matrix *dB; /* temporary derivative results */
+} gsl_bspline_workspace;
+
+typedef struct
+{
+    gsl_bspline_workspace *bspline; /* associated bspline */
+    gsl_matrix *A; /* work matrix */
+    gsl_matrix *dB; /* temporary derivative results */
+} gsl_bspline_deriv_workspace;
 
 gsl_bspline_workspace *
 gsl_bspline_alloc(const size_t k, const size_t nbreak);
 
-void gsl_bspline_free(gsl_bspline_workspace *w);
+void
+gsl_bspline_free(gsl_bspline_workspace *w);
 
-size_t gsl_bspline_ncoeffs (gsl_bspline_workspace * w);
-size_t gsl_bspline_order (gsl_bspline_workspace * w);
-size_t gsl_bspline_nbreak (gsl_bspline_workspace * w);
-double gsl_bspline_breakpoint (size_t i, gsl_bspline_workspace * w);
+size_t
+gsl_bspline_ncoeffs(gsl_bspline_workspace * w);
+size_t
+gsl_bspline_order(gsl_bspline_workspace * w);
+size_t
+gsl_bspline_nbreak(gsl_bspline_workspace * w);
+double
+gsl_bspline_breakpoint(size_t i, gsl_bspline_workspace * w);
 
 int
 gsl_bspline_knots(const gsl_vector *breakpts, gsl_bspline_workspace *w);
 
-int gsl_bspline_knots_uniform(const double a, const double b,
-                              gsl_bspline_workspace *w);
+int
+gsl_bspline_knots_uniform(const double a,
+                          const double b,
+                          gsl_bspline_workspace *w);
 
 int
-gsl_bspline_eval(const double x,
-                 gsl_vector *B,
-                 gsl_bspline_workspace *w);
+gsl_bspline_eval(const double x, gsl_vector *B, gsl_bspline_workspace *w);
 
 int
 gsl_bspline_eval_nonzero(const double x,
@@ -82,19 +94,25 @@ gsl_bspline_eval_nonzero(const double x,
                          size_t *iend,
                          gsl_bspline_workspace *w);
 
+gsl_bspline_deriv_workspace *
+gsl_bspline_deriv_alloc(gsl_bspline_workspace * bspline);
+
+void
+gsl_bspline_deriv_free(gsl_bspline_deriv_workspace *w);
+
 int
-gsl_bspline_eval_deriv(const double x,
+gsl_bspline_deriv_eval(const double x,
                        const size_t nderiv,
                        gsl_matrix *dB,
-                       gsl_bspline_workspace *w);
+                       gsl_bspline_deriv_workspace *w);
 
 int
-gsl_bspline_eval_deriv_nonzero(const double x,
+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);
+                               gsl_bspline_deriv_workspace *w);
 
 __END_DECLS
 
diff --git a/bspline/test.c b/bspline/test.c
index 393fbf3..5b511d3 100644
--- a/bspline/test.c
+++ b/bspline/test.c
@@ -26,7 +26,7 @@
 #include <gsl/gsl_nan.h>
 
 void
-test_bspline(gsl_bspline_workspace * bw)
+test_bspline(gsl_bspline_workspace * bw, gsl_bspline_deriv_workspace * dbw)
 {
   gsl_vector *B;
   gsl_matrix *dB;
@@ -68,7 +68,7 @@ test_bspline(gsl_bspline_workspace * bw)
     {
       double xi = a + (b - a) * (i / (n - 1.0));
       gsl_bspline_eval(xi, B, bw);
-      gsl_bspline_eval_deriv(xi, 0, dB, bw);
+      gsl_bspline_deriv_eval(xi, 0, dB, dbw);
 
       for (j = 0; j < ncoeffs; j++)
         {
@@ -100,8 +100,10 @@ main(int argc, char **argv)
         {
           double a = -1.23 * order, b = 45.6 * order;
           gsl_bspline_workspace *bw = gsl_bspline_alloc(order, breakpoints);
+          gsl_bspline_deriv_workspace *dbw = gsl_bspline_deriv_alloc(bw);
           gsl_bspline_knots_uniform(a, b, bw);
-          test_bspline(bw);
+          test_bspline(bw, dbw);
+          gsl_bspline_deriv_free(dbw);
           gsl_bspline_free(bw);
         }
     }
@@ -113,6 +115,7 @@ main(int argc, char **argv)
         {
           double a = -1.23 * order, b = 45.6 * order;
           gsl_bspline_workspace *bw = gsl_bspline_alloc(order, breakpoints);
+          gsl_bspline_deriv_workspace *dbw = gsl_bspline_deriv_alloc(bw);
           gsl_vector *k = gsl_vector_alloc(breakpoints);
           for (i = 0; i < breakpoints; i++)
             {
@@ -122,8 +125,9 @@ main(int argc, char **argv)
               gsl_vector_set(k, i, x);
             };
           gsl_bspline_knots(k, bw);
-          test_bspline(bw);
+          test_bspline(bw, dbw);
           gsl_vector_free(k);
+          gsl_bspline_deriv_free(dbw);
           gsl_bspline_free(bw);
         }
     }
@@ -143,6 +147,7 @@ main(int argc, char **argv)
     };
 
     gsl_bspline_workspace *bw = gsl_bspline_alloc(2, 3);
+    gsl_bspline_deriv_workspace *dbw = gsl_bspline_deriv_alloc(bw);
     gsl_matrix *dB = gsl_matrix_alloc(gsl_bspline_ncoeffs(bw),
                                       gsl_bspline_order(bw) + 1);
 
@@ -158,7 +163,7 @@ main(int argc, char **argv)
         /* Initialize dB with poison to ensure we overwrite it */
         gsl_matrix_set_all(dB, GSL_NAN);
 
-        gsl_bspline_eval_deriv(xloc[i], gsl_bspline_order(bw), dB, bw);
+        gsl_bspline_deriv_eval(xloc[i], gsl_bspline_order(bw), dB, dbw);
         for (j = 0; j < gsl_bspline_ncoeffs(bw) ; ++j)
           {
             /* check basis function 1st deriv */
@@ -178,6 +183,7 @@ main(int argc, char **argv)
       }
 
     gsl_matrix_free(dB);
+    gsl_bspline_deriv_free(dbw);
     gsl_bspline_free(bw);
     gsl_vector_free(breakpts);
   }
@@ -213,6 +219,7 @@ main(int argc, char **argv)
     };
 
     gsl_bspline_workspace *bw = gsl_bspline_alloc(3, 5);
+    gsl_bspline_deriv_workspace *dbw = gsl_bspline_deriv_alloc(bw);
 
     gsl_matrix *dB = gsl_matrix_alloc(gsl_bspline_ncoeffs(bw),
                                       gsl_bspline_order(bw) + 1);
@@ -229,7 +236,7 @@ main(int argc, char **argv)
       {
         /* Initialize dB with poison to ensure we overwrite it */
         gsl_matrix_set_all(dB, GSL_NAN);
-        gsl_bspline_eval_deriv(xloc[i], gsl_bspline_order(bw), dB, bw);
+        gsl_bspline_deriv_eval(xloc[i], gsl_bspline_order(bw), dB, dbw);
 
         /* check basis function evaluation */
         for (j = 0; j < gsl_bspline_ncoeffs(bw); ++j)
@@ -255,6 +262,7 @@ main(int argc, char **argv)
       }
 
     gsl_matrix_free(dB);
+    gsl_bspline_deriv_free(dbw);
     gsl_bspline_free(bw);
     gsl_vector_free(breakpts);
   }
diff --git a/doc/bspline.texi b/doc/bspline.texi
index 36b3dce..b2cdb1b 100644
--- a/doc/bspline.texi
+++ b/doc/bspline.texi
@@ -78,6 +78,8 @@ be readily obtained from a least-squares fit.
 @section Initializing the B-splines solver
 @cindex basis splines, initializing
 
+Using B-splines requires a gsl_bspline_workspace:
+
 @deftypefun {gsl_bspline_workspace *} gsl_bspline_alloc (const size_t @var{k}, const size_t @var{nbreak})
 This function allocates a workspace for computing B-splines of order
 @var{k}. The number of breakpoints is given by @var{nbreak}. This
@@ -88,6 +90,21 @@ are specified by @math{k = 4}. The size of the workspace is
 
 @deftypefun void gsl_bspline_free (gsl_bspline_workspace * @var{w})
 This function frees the memory associated with the workspace @var{w}.
+Any associated gsl_bspline_deriv_workspace should be freed beforehand.
+@end deftypefun
+
+Evaluation of B-spline basis function derivatives additionally requires
+a gsl_bspline_deriv_workspace:
+
+@deftypefun {gsl_bspline_deriv_workspace *} gsl_bspline_deriv_alloc (gsl_bspline_workspace * bspline)
+This function allocates a workspace for computing the B-spline basis
+function derivatives for @var{bspline}.  The size of the workspace is
+@math{O(2k^2)}.
+@end deftypefun
+
+@deftypefun void gsl_bspline_deriv_free (gsl_bspline_deriv_workspace * @var{w})
+This function frees the memory associated with the workspace @var{w}.
+The associated gsl_bspline_workspace should be freed afterwards.
 @end deftypefun
 
 @node Constructing the knots vector
@@ -140,7 +157,7 @@ This function returns the number of B-spline coefficients given by
 @section Evaluation of B-spline derivatives
 @cindex basis splines, derivatives
 
-@deftypefun int gsl_bspline_eval_deriv (const double @var{x}, const size_t @var{nderiv}, gsl_matrix * @var{dB}, gsl_bspline_workspace * @var{w})
+@deftypefun int gsl_bspline_deriv_eval (const double @var{x}, const size_t @var{nderiv}, gsl_matrix * @var{dB}, gsl_bspline_workspace * @var{w})
 This function evaluates all B-spline basis function derivatives of orders
 @math{0} through @math{nderiv} (inclusive) at the position @var{x}
 and stores them in @var{dB}.  The @math{(i,j)}th element of @var{dB}
@@ -153,7 +170,7 @@ at once than to compute them individually, due to the nature of the
 defining recurrence relation.
 @end deftypefun
 
-@deftypefun int gsl_bspline_eval_deriv_nonzero (const double @var{x}, const size_t @var{nderiv}, gsl_matrix * @var{dB}, size_t * @var{istart}, size_t * @var{iend}, gsl_bspline_workspace * @var{w})
+@deftypefun int gsl_bspline_deriv_eval_nonzero (const double @var{x}, const size_t @var{nderiv}, gsl_matrix * @var{dB}, size_t * @var{istart}, size_t * @var{iend}, gsl_bspline_workspace * @var{w})
 This function evaluates all potentially nonzero B-spline basis function
 derivatives of orders @math{0} through @math{nderiv} (inclusive) at
 the position @var{x} and stores them in @var{dB}.  The @math{(i,j)}th

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]