/* R : A Computer Language for Statistical Data Analysis * Copyright (C) 2010 The R Foundation * Copyright (C) 2016 The R Core Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, a copy is available at * https://www.R-project.org/Licenses/ */ #include "modreg.h" #include /* To be "exported" (as part of R's C API): */ /** * Modify the slopes m_k := s'(x_k) using Fritsch & Carlson (1980)'s algorithm * * @param m numeric vector of length n, the preliminary desired slopes s'(x_i), i = 1:n * @param S the divided differences (y_{i+1} - y_i) / (x_{i+1} - x_i); i = 1:(n-1) * @param n == length(m) == 1 + length(S) * @return m*: the modified m[]'s: Note that m[] is modified in place * @author Martin Maechler, Date: 19 Apr 2010 */ void monoFC_mod(double *m, double S[], int n) { if(n < 2) error(_("n must be at least two")); for(int k = 0; k < n - 1; k++) { /* modify both (m[k] & m[k+1]) if needed : */ double Sk = S[k]; int k1 = k + 1; if(Sk == 0.) { /* or |S| < eps ?? FIXME ?? */ m[k] = m[k1] = 0.; } else { double alpha = m[k ] / Sk, beta = m[k1] / Sk, a2b3, ab23; if((a2b3 = 2*alpha + beta - 3) > 0 && (ab23 = alpha + 2*beta - 3) > 0 && alpha * (a2b3 + ab23) < a2b3*a2b3) { /* we are outside the monotonocity region ==> fix slopes */ double tauS = 3*Sk / sqrt(alpha*alpha + beta*beta); m[k ] = tauS * alpha; m[k1] = tauS * beta; } } } /* end for */ } SEXP monoFC_m(SEXP m, SEXP Sx) { SEXP val; int n = LENGTH(m); if (isInteger(m)) val = PROTECT(coerceVector(m, REALSXP)); else { if (!isReal(m)) error(_("Argument m must be numeric")); val = PROTECT(duplicate(m)); } if(n < 2) error(_("length(m) must be at least two")); if(!isReal(Sx) || LENGTH(Sx) != n-1) error(_("Argument Sx must be numeric vector one shorter than m[]")); /* Fix up the slopes m[] := val[]: */ monoFC_mod(REAL(val), REAL(Sx), n); UNPROTECT(1); return(val); }