bspline.c

来自「math library from gnu」· C语言 代码 · 共 1,008 行 · 第 1/2 页

C
1,008
字号
      /* find all non-zero d^j/dx^j B_i(x) values */      error =	gsl_bspline_deriv_eval_nonzero (x, nderiv, dw->dB, &istart, &iend, w,					dw);      if (error)	{	  return error;	}      /* store values in appropriate part of given matrix */      for (j = 0; j <= nderiv; j++)	{	  for (i = 0; i < istart; i++)	    gsl_matrix_set (dB, i, j, 0.0);	  for (i = istart; i <= iend; i++)	    gsl_matrix_set (dB, i, j, gsl_matrix_get (dw->dB, i - istart, j));	  for (i = iend + 1; i < w->n; i++)	    gsl_matrix_set (dB, i, j, 0.0);	}      return GSL_SUCCESS;    }}				/* gsl_bspline_deriv_eval() *//*gsl_bspline_deriv_eval_nonzero()  At point x evaluate all requested, non-zero B-spline functionderivatives and store them in dB.  These are thed^j/dx^j B_i(x) with i in [istart, iend] and j in [0, nderiv].Always d^j/dx^j B_i(x) = 0 for i < istart and for i > iend.Inputs: x      - point at which to evaluate splines        nderiv - number of derivatives to request, inclusive        dB     - (output) where to store dB-spline derivatives                 (size k by nderiv + 1)        istart - (output) B-spline function index of                 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.        w      - bspline derivative workspaceReturn: success or errorNotes: 1) the w->knots vector must be initialized before calling          this function       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}]]          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.       4) based on PPPACK's bsplvd*/intgsl_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 * dw){  if (dB->size1 != w->k)    {      GSL_ERROR ("dB matrix first dimension not of length k", GSL_EBADLEN);    }  else if (dB->size2 < nderiv + 1)    {      GSL_ERROR	("dB matrix second dimension must be at least length nderiv+1",	 GSL_EBADLEN);    }  else if (dw->k < w->k)     {      GSL_ERROR ("derivative workspace is too small", GSL_EBADLEN);    }  else    {      size_t i;			/* spline index */      size_t j;			/* looping */      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);      if (error)	{	  return error;	}      *istart = i - w->k + 1;      *iend = i;      bspline_pppack_bsplvd (w->knots, w->k, x, *iend,			     w->deltal, w->deltar, dw->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);      for (j = min_nderivk + 1; j <= nderiv; j++)	{	  for (i = 0; i < w->k; i++)	    {	      gsl_matrix_set (dB, i, j, 0.0);	    }	}      return GSL_SUCCESS;    }}				/* gsl_bspline_deriv_eval_nonzero() *//**************************************** *          INTERNAL ROUTINES           * ****************************************//*bspline_find_interval()  Find knot interval such that t_i <= x < t_{i + 1}where the t_i are knot values.Inputs: x    - x value        flag - (output) error flag        w    - bspline workspaceReturn: 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*/static inline size_tbspline_find_interval (const double x, int *flag, gsl_bspline_workspace * w){  size_t i;  if (x < gsl_vector_get (w->knots, 0))    {      *flag = -1;      return 0;    }  /* find i such that t_i <= x < t_{i+1} */  for (i = w->k - 1; i < w->k + w->l - 1; i++)    {      const double ti = gsl_vector_get (w->knots, i);      const double tip1 = gsl_vector_get (w->knots, i + 1);      if (tip1 < ti)	{	  GSL_ERROR ("knots vector is not increasing", GSL_EINVAL);	}      if (ti <= x && x < tip1)	break;      if (ti < x && x == tip1 && tip1 == gsl_vector_get (w->knots, w->k + w->l							 - 1))	break;    }  if (i == w->k + w->l - 1)    *flag = 1;  else    *flag = 0;  return i;}				/* bspline_find_interval() *//*bspline_process_interval_for_eval()  Consumes an x location, left knot from bspline_find_interval, flagfrom bspline_find_interval, and a workspace.  Checks that x lies withinthe splines' knots, enforces some endpoint continuity requirements, andavoids divide by zero errors in the underlying bspline_pppack_* functions.*/static inline intbspline_process_interval_for_eval (const double x, size_t * i, const int flag,				   gsl_bspline_workspace * w){  if (flag == -1)    {      GSL_ERROR ("x outside of knot interval", GSL_EINVAL);    }  else if (flag == 1)    {      if (x <= gsl_vector_get (w->knots, *i) + GSL_DBL_EPSILON)	{	  *i -= 1;	}      else	{	  GSL_ERROR ("x outside of knot interval", GSL_EINVAL);	}    }  if (gsl_vector_get (w->knots, *i) == gsl_vector_get (w->knots, *i + 1))    {      GSL_ERROR ("knot(i) = knot(i+1) will result in division by zero",		 GSL_EINVAL);    }  return GSL_SUCCESS;}				/* bspline_process_interval_for_eval *//******************************************************************** * PPPACK ROUTINES * * The routines herein deliberately avoid using the bspline workspace, * choosing instead to pass all work areas explicitly.  This allows * others to more easily adapt these routines to low memory or * parallel scenarios. ********************************************************************//*bspline_pppack_bsplvb()  calculates the value of all possibly nonzero b-splines at x of orderjout = 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)) .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].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.   (2) This routine contains no error checking.  Please use routines       like gsl_bspline_eval().*/static voidbspline_pppack_bsplvb (const gsl_vector * t,		       const size_t jhigh,		       const size_t index,		       const double x,		       const size_t left,		       size_t * j,		       gsl_vector * deltal,		       gsl_vector * deltar, gsl_vector * biatx){  size_t i;			/* looping */  double saved;  double term;  if (index == 1)    {      *j = 0;      gsl_vector_set (biatx, 0, 1.0);    }  for ( /* NOP */ ; *j < jhigh - 1; *j += 1)    {      gsl_vector_set (deltar, *j, gsl_vector_get (t, left + *j + 1) - x);      gsl_vector_set (deltal, *j, x - gsl_vector_get (t, left - *j));      saved = 0.0;      for (i = 0; i <= *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);	  saved = gsl_vector_get (deltal, *j - i) * term;	}      gsl_vector_set (biatx, *j + 1, saved);    }  return;}				/* gsl_bspline_pppack_bsplvb *//*bspline_pppack_bsplvd()  calculates value and derivs of all b-splines which do not vanish at xParameters:   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 .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.   (2) This routine contains no error checking.*/static voidbspline_pppack_bsplvd (const gsl_vector * t,		       const size_t k,		       const double x,		       const size_t left,		       gsl_vector * deltal,		       gsl_vector * deltar,		       gsl_matrix * a,		       gsl_matrix * dbiatx, const size_t nderiv){  int i, ideriv, il, j, jlow, jp1mid, kmm, ldummy, m, mhigh;  double factor, fkmm, sum;  size_t bsplvb_j;  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);  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.  */      ideriv = mhigh;      for (m = 1; m <= mhigh; m++)	{	  for (j = ideriv, jp1mid = 0; j < (int) k; j++, jp1mid++)	    {	      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);	}      /* 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. */      jlow = 0;      for (i = 0; i < (int) k; i++)	{	  for (j = jlow; j < (int) k; j++)	    {	      gsl_matrix_set (a, j, i, 0.0);	    }	  jlow = i;	  gsl_matrix_set (a, i, i, 1.0);	}      /* at this point, a(.,j) contains the b-coeffs for the j-th of the         k b-splines of interest here. */      for (m = 1; m <= mhigh; m++)	{	  kmm = k - m;	  fkmm = (float) kmm;	  il = left;	  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. */	  for (ldummy = 0; ldummy < kmm; ldummy++)	    {	      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++)		{		  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++)	    {	      sum = 0;	      jlow = GSL_MAX_INT (i, m);	      for (j = jlow; j < (int) k; j++)		{		  sum +=		    gsl_matrix_get (a, j, i) * gsl_matrix_get (dbiatx, j, m);		}	      gsl_matrix_set (dbiatx, i, m, sum);	    }	}    }  return;}				/* bspline_pppack_bsplvd */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?