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 + -
显示快捷键?