9#include "boost/format.hpp"
19static int search_array(
double z,
double const *
x,
int n,
int i);
24 for (
unsigned int i = 0; i !=
_coeffs.
size(); ++i) {
31 int const n =
x.size();
42 for (
int i = 0; i != n; ++i) {
43 ind = search_array(
x[i], &
_knots[0], nknot, ind);
47 }
else if (ind >= nknot) {
51 double const dx =
x[i] -
_knots[ind];
59 int const n =
x.size();
72 for (
int i = 0; i != n; ++i) {
73 ind = search_array(
x[i], &
_knots[0], nknot, ind);
77 }
else if (ind >= nknot) {
81 double const dx =
x[i] -
_knots[ind];
88 if (
x.size() !=
y.size()) {
90 (boost::format(
"TautSpline: x and y must have the same size; saw %d %d\n") %
95 int const ntau =
x.size();
98 (boost::format(
"TautSpline: ntau = %d, should be >= 2\n") % ntau).
str());
103 calculateTautSpline(
x,
y, gamma0);
107 calculateTautSplineEvenOdd(
x,
y, gamma0,
type ==
Even);
113 double const gamma0) {
114 const double *tau = &
x[0];
115 const double *gtau = &
y[0];
116 int const ntau =
x.size();
119 int const nknot = ntau;
124 for (
int i = 1; i < nknot; i++) {
126 if (tau[i - 1] >= tau[i]) {
128 (boost::format(
"point %d and the next, %f %f, are out of order") % (i - 1) %
136 _coeffs[1][0] = (gtau[1] - gtau[0]) / (tau[1] - tau[0]);
140 _coeffs[1][1] = (gtau[1] - gtau[0]) / (tau[1] - tau[0]);
143 double tmp = (tau[2] - tau[0]) * (tau[2] - tau[1]) * (tau[1] - tau[0]);
145 _coeffs[1][0] = ((gtau[1] - gtau[0]) * pow(tau[2] - tau[0], 2) -
146 (gtau[2] - gtau[0]) * pow(tau[1] - tau[0], 2)) /
149 -2 * ((gtau[1] - gtau[0]) * (tau[2] - tau[0]) - (gtau[2] - gtau[0]) * (tau[1] - tau[0])) /
179 for (
int i = 0; i != 6; i++) {
186 for (
int i = 0; i < ntau - 1; i++) {
187 s[0][i] = tau[i + 1] - tau[i];
190 (boost::format(
"point %d and the next, %f %f, are out of order") % i % tau[i] %
194 s[3][i + 1] = (gtau[i + 1] - gtau[i]) / s[0][i];
196 for (
int i = 1; i < ntau - 1; ++i) {
197 s[3][i] = s[3][i + 1] - s[3][i];
205 s[1][1] = s[0][0] / 3;
208 double gamma = gamma0;
211 }
else if (gamma > 3) {
217 double const onemg3 = 1 - gamma / 3;
238 for (
int i = 1; i < ntau - 2; ++i) {
243 if ((method == 2 && s[3][i] * s[3][i + 1] >= 0) || method == 3) {
244 double const temp =
fabs(s[3][i + 1]);
245 double const denom =
fabs(s[3][i]) + temp;
248 if (
fabs(
z - 0.5) <= 1.0 / 6.0) {
263 double temp = onemg3 / onemzt;
264 alpha = (temp < 1 ? temp : 1);
265 factor = zeta / (alpha * (zt2 - 1) + 1);
266 s[5][i] = zeta * factor / 6;
267 s[1][i] += s[0][i] * ((1 - alpha * onemzt) * factor / 2 - s[5][i]);
276 s[2][i] = s[0][i] / 6;
281 }
else if (z_half == 0) {
282 s[1][i] += s[0][i] / 3;
283 s[2][i] = s[0][i] / 6;
285 onemzt = gamma * (1 -
z);
287 double const temp = onemg3 / zeta;
288 alpha = (temp < 1 ? temp : 1);
289 factor = onemzt / (1 - alpha * zeta * (onemzt + 1));
290 s[5][i] = onemzt * factor / 6;
291 s[1][i] += s[0][i] / 3;
292 s[2][i] = s[5][i] * s[0][i];
304 s[1][0] = s[0][0] / 6;
308 const double factr2 = zeta * (alpha * (zt2 - 1.) + 1.) / (alpha * (zeta * zt2 - 1.) + 1.);
309 ratio = factr2 * s[0][1] / s[1][0];
310 s[1][1] = factr2 * s[0][1] + s[0][0];
311 s[2][1] = -factr2 * s[0][0];
312 }
else if (z_half == 0) {
313 ratio = s[0][1] / s[1][0];
314 s[1][1] = s[0][1] + s[0][0];
317 ratio = s[0][1] / s[1][0];
318 s[1][1] = s[0][1] + s[0][0];
319 s[2][1] = -s[0][0] * 6 * alpha * s[5][1];
329 s[1][1] += ratio * s[2][0];
330 s[2][1] += ratio * entry3;
331 s[3][1] = ratio * s[3][1];
339 s[1][i] += ratio * s[2][i - 1];
340 s[3][i] += ratio * s[3][i - 1];
346 ratio = -s[5][i] * s[0][i] / s[1][i];
347 s[1][i + 1] = s[0][i] / 3;
348 }
else if (z_half == 0) {
349 ratio = -(s[0][i] / 6) / s[1][i];
350 s[1][i + 1] = s[0][i] / 3;
352 ratio = -(s[0][i] / 6) / s[1][i];
353 s[1][i + 1] = s[0][i] * ((1 - zeta * alpha) * factor / 2 - s[5][i]);
357 s[4][ntau - 2] = 0.5;
362 double const entry_ = ratio * s[2][ntau - 3] + s[1][ntau - 2] + s[0][ntau - 2] / 3;
363 s[1][ntau - 1] = s[0][ntau - 2] / 6;
364 s[3][ntau - 1] = ratio * s[3][ntau - 3] + s[3][ntau - 2];
366 ratio = s[0][ntau - 2] * 6 * s[5][ntau - 3] * alpha / s[1][ntau - 3];
367 s[1][ntau - 2] = ratio * s[2][ntau - 3] + s[0][ntau - 2] + s[0][ntau - 3];
368 s[2][ntau - 2] = -s[0][ntau - 3];
369 }
else if (z_half == 0) {
370 ratio = s[0][ntau - 2] / s[1][ntau - 3];
371 s[1][ntau - 2] = ratio * s[2][ntau - 3] + s[0][ntau - 2] + s[0][ntau - 3];
372 s[2][ntau - 2] = -s[0][ntau - 3];
374 const double factr2 =
375 onemzt * (alpha * (onemzt * onemzt - 1) + 1) / (alpha * (onemzt * onemzt * onemzt - 1) + 1);
376 ratio = factr2 * s[0][ntau - 2] / s[1][ntau - 3];
377 s[1][ntau - 2] = ratio * s[2][ntau - 3] + factr2 * s[0][ntau - 3] + s[0][ntau - 2];
378 s[2][ntau - 2] = -factr2 * s[0][ntau - 3];
386 s[3][ntau - 2] = ratio * s[3][ntau - 3];
387 ratio = -entry_ / s[1][ntau - 2];
388 s[1][ntau - 1] += ratio * s[2][ntau - 2];
389 s[3][ntau - 1] += ratio * s[3][ntau - 2];
394 s[3][ntau - 1] /= s[1][ntau - 1];
395 for (
int i = ntau - 2; i > 0; --i) {
396 s[3][i] = (s[3][i] - s[2][i] * s[3][i + 1]) / s[1][i];
399 s[3][0] = (s[3][0] - s[2][0] * s[3][1] - entry3 * s[3][2]) / s[1][0];
408 int const nknot0 = nknot;
411 for (
int i = 0; i < ntau - 1; ++i) {
412 double const z = s[4][i];
413 if ((
z < 0.5 &&
z != 0.0) || (
z > 0.5 && (1 -
z) != 0.0)) {
417 assert(nknot == nknot0);
424 for (
int i = 0; i < ntau - 1; ++i) {
427 double const divdif = (gtau[i + 1] - gtau[i]) / s[0][i];
429 double const z_half =
z - 0.5;
438 double const c = s[3][i + 1] / 6;
439 double const d = s[3][i] * s[5][i];
442 double const del = zeta * s[0][i];
445 double temp = onemg3 / onemzt;
446 alpha = (temp < 1 ? temp : 1);
447 factor = onemzt * onemzt * alpha;
449 _coeffs[0][j] = gtau[i] + divdif * del +
450 temp * temp * (d * onemzt * (factor - 1) + c * zeta * (zt2 - 1));
451 _coeffs[1][j] = divdif + s[0][i] * (d * (1 - 3 * factor) + c * (3 * zt2 - 1));
452 _coeffs[2][j] = (d * alpha * onemzt + c * zeta) * 6;
453 _coeffs[3][j] = (c - d * alpha) * 6 / s[0][i];
454 if (del * zt2 == 0) {
458 _coeffs[3][j - 1] =
_coeffs[3][j] - d * 6 * (1 - alpha) / (del * zt2);
462 }
else if (z_half == 0) {
463 _coeffs[1][j] = divdif - s[0][i] * (s[3][i] * 2 + s[3][i + 1]) / 6;
464 _coeffs[3][j] = (s[3][i + 1] - s[3][i]) / s[0][i];
466 onemzt = gamma * (1 -
z);
473 double const temp = onemg3 / zeta;
474 alpha = (temp < 1 ? temp : 1);
475 double const c = s[3][i + 1] * s[5][i];
476 double const d = s[3][i] / 6;
477 double const del = zeta * s[0][i];
478 _knots[j + 1] = tau[i] + del;
479 _coeffs[1][j] = divdif - s[0][i] * (2 * d + c);
480 _coeffs[3][j] = (c * alpha - d) * 6 / s[0][i];
484 _coeffs[3][j - 1] + (1 - alpha) * 6 * c / (s[0][i] * (onemzt * onemzt * onemzt));
505 double const del = tau[ntau - 1] -
_knots[nknot - 2];
509 del * (
_coeffs[2][nknot - 2] / 2 + del *
_coeffs[3][nknot - 2] / 6));
515 assert(j + 1 == nknot);
521static void spcof1(
const double x[],
double avh,
const double y[],
const double dy[],
int n,
double p,
522 double q,
double a[],
double *c[3],
double u[],
const double v[]);
524static void sperr1(
const double x[],
double avh,
const double dy[],
int n,
double *r[3],
double p,
double var,
527static double spfit1(
const double x[],
double avh,
const double dy[],
int n,
double rho,
double *p,
double *q,
528 double var,
double stat[],
const double a[],
double *c[3],
double *r[3],
double *t[2],
529 double u[],
double v[]);
531static double spint1(
const double x[],
double *avh,
const double y[],
double dy[],
int n,
double a[],
532 double *c[3],
double *r[3],
double *t[2]);
538 int const n =
x.size();
539 double const ratio = 2.0;
540 double const tau = 1.618033989;
541 double avdf, avar, stat[6];
542 double p, q, delta, r1, r2, r3, r4;
543 double gf1, gf2, gf3, gf4, avh, err;
558 r[0] = &scratch[0] + 1;
559 r[1] = r[0] + (n + 2);
560 r[2] = r[1] + (n + 2);
562 t[0] = r[2] + (n + 2);
563 t[1] = t[0] + (n + 2);
564 double *u = t[1] + (n + 2);
565 double *v = u + (n + 2);
571 avdf = spint1(&
x[0], &avh, &f[0], &sdf[0], n,
y, c, r, t);
580 gf1 = spfit1(&
x[0], avh, &sdf[0], n, r1, &p, &q, avar, stat,
y, c, r, t, u, v);
585 gf2 = spfit1(&
x[0], avh, &sdf[0], n, r2, &p, &q, avar, stat,
y, c, r, t, u, v);
588 gf1 = spfit1(&
x[0], avh, &sdf[0], n, r1, &p, &q, avar, stat,
y, c, r, t, u, v);
609 gf3 = spfit1(&
x[0], avh, &sdf[0], n, r3, &p, &q, avar, stat,
y, c, r, t, u, v);
623 if (p > 0 && q > 0) {
627 delta = (r2 - r1) / tau;
630 gf3 = spfit1(&
x[0], avh, &sdf[0], n, r3, &p, &q, avar, stat,
y, c, r, t, u, v);
631 gf4 = spfit1(&
x[0], avh, &sdf[0], n, r4, &p, &q, avar, stat,
y, c, r, t, u, v);
643 gf3 = spfit1(&
x[0], avh, &sdf[0], n, r3, &p, &q, avar, stat,
y, c, r, t, u, v);
651 gf4 = spfit1(&
x[0], avh, &sdf[0], n, r4, &p, &q, avar, stat,
y, c, r, t, u, v);
654 err = (r2 - r1) / (r1 + r2);
655 }
while (err * err + 1 > 1 && err > 1e-6);
658 gf1 = spfit1(&
x[0], avh, &sdf[0], n, r1, &p, &q, avar, stat,
y, c, r, t, u, v);
664 spcof1(&
x[0], avh, &f[0], &sdf[0], n, p, q,
y, c, u, v);
666 stat[2] /= avdf * avdf;
667 stat[3] /= avdf * avdf;
668 stat[4] /= avdf * avdf;
672 if (errs !=
nullptr) {
673 sperr1(&
x[0], avh, &sdf[0], n, r, p, avar, errs);
678 if (chisq !=
nullptr) {
679 *chisq = n * stat[4];
692static double spint1(
const double x[],
double *avh,
const double f[],
double df[],
int n,
double a[],
693 double *c[3],
double *r[3],
double *t[2]) {
703 for (i = 0; i < n - 1; ++i) {
714 for (
int i = 0; i < n; ++i) {
721 for (i = 0; i < n; ++i) {
727 h = (
x[1] -
x[0]) / (*avh);
728 ff = (f[1] - f[0]) / h;
732 for (i = 1; i < n - 1; ++i) {
734 h = (
x[i + 1] -
x[i]) / (*avh);
736 ff = (f[i + 1] - f[i]) / h;
738 t[0][i] = (g + h) * 2. / 3.;
740 r[2][i] = df[i - 1] / g;
741 r[0][i] = df[i + 1] / h;
742 r[1][i] = -df[i] / g - df[i] / h;
751 for (i = 1; i < n - 1; i++) {
752 c[0][i] = r[0][i] * r[0][i] + r[1][i] * r[1][i] + r[2][i] * r[2][i];
753 c[1][i] = r[0][i] * r[1][i + 1] + r[1][i] * r[2][i + 1];
754 c[2][i] = r[0][i] * r[2][i + 2];
785static double spfit1(
const double x[],
double avh,
const double dy[],
int n,
double rho,
double *pp,
786 double *pq,
double var,
double stat[],
const double a[],
double *c[3],
double *r[3],
787 double *t[2],
double u[],
double v[]) {
796 if (
fabs(rho) < eps) {
799 }
else if (
fabs(1 / rho) < eps) {
812 r[0][-1] = r[0][0] = 0;
814 for (
int i = 1; i < n - 1; ++i) {
815 r[2][i - 2] = g * r[0][i - 2];
816 r[1][i - 1] = f * r[0][i - 1];
818 double tmp = p * c[0][i] + q * t[0][i] - f * r[1][i - 1] - g * r[2][i - 2];
825 f = p * c[1][i] + q * t[1][i] - h * r[1][i - 1];
833 for (
int i = 1; i < n - 1; i++) {
834 u[i] =
a[i] - r[1][i - 1] * u[i - 1] - r[2][i - 2] * u[i - 2];
837 for (
int i = n - 2; i > 0; i--) {
838 u[i] = r[0][i] * u[i] - r[1][i] * u[i + 1] - r[2][i] * u[i + 2];
844 for (
int i = 0; i < n - 1; i++) {
846 h = (u[i + 1] - u[i]) / ((
x[i + 1] -
x[i]) / avh);
847 v[i] = dy[i] * (h - g);
850 v[n - 1] = -h * dy[n - 1];
851 e += v[n - 1] * v[n - 1];
855 r[0][n - 1] = r[1][n - 1] = r[0][n] = 0;
856 for (i = n - 2; i > 0; i--) {
859 r[1][i] = -g * r[0][i + 1] - h * r[1][i + 1];
860 r[2][i] = -g * r[1][i + 1] - h * r[0][i + 2];
861 r[0][i] = r[0][i] - g * r[1][i] - h * r[2][i];
867 for (i = 1; i < n - 1; ++i) {
868 f += r[0][i] * c[0][i];
869 g += r[1][i] * c[1][i];
870 h += r[2][i] * c[2][i];
878 stat[2] = n * e / (f * f + 1e-20);
879 stat[3] = e * p * p / n;
880 stat[5] = e * p / ((f < 0) ? f - 1e-10 : f + 1e-10);
882 fun = stat[3] - 2 * var * stat[1] / n + var;
886 stat[4] = stat[5] - stat[3];
900static void spcof1(
const double x[],
double avh,
const double y[],
const double dy[],
int n,
double p,
901 double q,
double a[],
double *c[3],
double u[],
const double v[]) {
906 qh = q / (avh * avh);
908 for (i = 0; i < n; ++i) {
909 a[i] =
y[i] - p * dy[i] * v[i];
915 for (i = 0; i < n - 1; ++i) {
917 c[2][i] = (u[i + 1] - u[i]) / (3 * h);
918 c[0][i] = (
a[i + 1] -
a[i]) / h - (h * c[2][i] + u[i]) * h;
928static void sperr1(
const double x[],
double avh,
const double dy[],
int n,
double *r[3],
double p,
double var,
936 h = avh / (
x[1] -
x[0]);
937 (*se)[0] = 1 - p * dy[0] * dy[0] * h * h * r[0][1];
938 r[0][0] = r[1][0] = r[2][0] = 0;
942 for (i = 1; i < n - 1; ++i) {
944 h = avh / (
x[i + 1] -
x[i]);
946 f1 = f * r[0][i - 1] + g * r[1][i - 1] + h * r[2][i - 1];
947 g1 = f * r[1][i - 1] + g * r[0][i] + h * r[1][i];
948 h1 = f * r[2][i - 1] + g * r[1][i] + h * r[0][i + 1];
949 (*se)[i] = 1 - p * dy[i] * dy[i] * (f * f1 + g * g1 + h * h1);
951 (*se)[n - 1] = 1 - p * dy[n - 1] * dy[n - 1] * h * h * r[0][n - 2];
955 for (
int i = 0; i < n; ++i) {
956 double const tmp = (*se)[i] * var;
957 (*se)[i] = (tmp >= 0) ?
sqrt(tmp) * dy[i] : 0;
965 const double *tau = &_tau[0];
966 const double *gtau = &_gtau[0];
967 int const ntau = _tau.
size();
970 if (tau[0] == 0.0f) {
971 int const np = 2 * ntau - 1;
975 x[ntau - 1] = tau[0];
976 y[ntau - 1] = gtau[0];
977 for (
int i = 1; i != ntau; ++i) {
979 x[ntau - 1 + i] = tau[i];
980 y[ntau - 1 + i] = gtau[i];
981 x[ntau - 1 - i] = -tau[i];
982 y[ntau - 1 - i] = gtau[i];
984 x[ntau - 1 + i] = tau[i];
985 y[ntau - 1 + i] = gtau[i];
986 x[ntau - 1 - i] = -tau[i];
987 y[ntau - 1 - i] = -gtau[i];
991 int const np = 2 * ntau;
995 for (
int i = 0; i != ntau; ++i) {
997 x[ntau + i] = tau[i];
998 y[ntau + i] = gtau[i];
999 x[ntau - 1 - i] = -tau[i];
1000 y[ntau - 1 - i] = gtau[i];
1002 x[ntau + i] = tau[i];
1003 y[ntau + i] = gtau[i];
1004 x[ntau - 1 - i] = -tau[i];
1005 y[ntau - 1 - i] = -gtau[i];
1015 for (ii = sp._knots.size() - 1; ii >= 0; --ii) {
1016 if (sp._knots[ii] < 0.0f) {
1020 int const i0 = ii + 1;
1021 int const nknot = sp._knots.size() - i0;
1025 for (
int i = i0; i !=
static_cast<int>(sp._knots.size()); ++i) {
1026 _knots[i - i0] = sp._knots[i];
1027 for (
int j = 0; j != 4; ++j) {
1028 _coeffs[j][i - i0] = sp._coeffs[j][i];
1038static int search_array(
double z,
double const *
x,
int n,
int i) {
1042 if (i < 0 || i >= n) {
1046 unsigned int step = 1;
1055 while (
z >=
x[hi]) {
1085 while (hi - lo > 1) {
1086 mid = (lo + hi) / 2;
1103 while (lo < n - 1 &&
x[lo + 1] == xm) lo++;
1113 for (
unsigned int i = 0; i != newRoots.
size(); ++i) {
1114 if (newRoots[i] >= x0 && newRoots[i] < x1) {
1132 double const tmp =
b *
b - 4 *
a * c;
1144 if (roots[0] > roots[1]) {
1145 double const tmp2 = roots[0];
1146 roots[0] = roots[1];
1158 do_quadratic(
b, c, d, roots);
1165 double const q = (
b *
b - 3 * c) / 9;
1166 double const r = (2 *
b *
b *
b - 9 *
b * c + 27 * d) / 54;
1172 double const sq = (q >= 0) ?
sqrt(q) : -
sqrt(-q);
1173 double const sq3 = sq * sq * sq;
1174 if (::fabs(r) < sq3) {
1175 double const theta = ::acos(r / sq3);
1183 if (roots[0] > roots[1]) {
1186 if (roots[1] > roots[2]) {
1189 if (roots[0] > roots[1]) {
1194 }
else if (::fabs(r) == sq3) {
1195 double const aa = -((r < 0) ? -::pow(-r, 1.0 / 3.0) : ::pow(r, 1.0 / 3.0));
1204 if (roots[0] > roots[1]) {
1211 double tmp = ::sqrt(r * r - (q > 0 ? sq3 * sq3 : -sq3 * sq3));
1212 tmp = r + (r < 0 ? -tmp : tmp);
1213 double const aa = -((tmp < 0) ? -::pow(-tmp, 1.0 / 3.0) : ::pow(tmp, 1.0 / 3.0));
1236 double const x1 =
b;
1239 int i0 = search_array(x0, &
_knots[0], nknot, -1);
1240 int const i1 = search_array(x1, &
_knots[0], nknot, i0);
1241 assert(i1 >= i0 && i1 <= nknot - 1);
1257 for (
unsigned int j = 0; j != newRoots.
size(); ++j) {
1258 newRoots[j] +=
_knots[i0];
1260 keep_valid_roots(
roots, newRoots, x0,
_knots[i0]);
1263 }
else if (i0 >= nknot) {
1268 for (
unsigned int j = 0; j != newRoots.
size(); ++j) {
1269 newRoots[j] +=
_knots[i0];
1271 keep_valid_roots(
roots, newRoots, x0, x1);
1279 for (
int i = i0; i <= i1; i++) {
1282 for (
unsigned int j = 0; j != newRoots.
size(); ++j) {
1283 newRoots[j] +=
_knots[i];
1285 keep_valid_roots(
roots, newRoots, ((i == i0) ? x0 :
_knots[i]), ((i == i1) ? x1 :
_knots[i + 1]));
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
SmoothedSpline(std::vector< double > const &x, std::vector< double > const &y, std::vector< double > const &dy, double s, double *chisq=nullptr, std::vector< double > *errs=nullptr)
Cubic spline data smoother.
std::vector< double > _knots
std::vector< double > roots(double const value, double const x0, double const x1) const
Find the roots of Spline - val = 0 in the range [x0, x1).
void derivative(std::vector< double > const &x, std::vector< double > &dydx) const
Find the derivative of a Spline.
void _allocateSpline(int const nknot)
Allocate the storage a Spline needs.
void interpolate(std::vector< double > const &x, std::vector< double > &y) const
Interpolate a Spline.
std::vector< std::vector< double > > _coeffs
TautSpline(std::vector< double > const &x, std::vector< double > const &y, double const gamma=0, Symmetry type=Unknown)
Construct cubic spline interpolant to given data.
Reports invalid arguments.