63 enum bd_type { first_deriv = 1, second_deriv = 2, not_a_knot = 3 };
66 std::vector<double> m_x, m_y;
70 std::vector<double> m_b, m_c, m_d;
73 bd_type m_left, m_right;
74 double m_left_value, m_right_value;
75 bool m_made_monotonic;
76 void set_coeffs_from_b();
77 size_t find_closest(
double x)
const;
85 m_right(second_deriv),
88 m_made_monotonic(
false) {
91 spline(
const std::vector<double>& X,
92 const std::vector<double>& Y,
93 spline_type type = cspline,
94 bool make_monotonic =
false,
95 bd_type left = second_deriv,
96 double left_value = 0.0,
97 bd_type right = second_deriv,
98 double right_value = 0.0)
102 m_left_value(left_value),
103 m_right_value(right_value),
104 m_made_monotonic(
false)
106 this->set_points(X, Y, m_type);
107 if (make_monotonic) {
108 this->make_monotonic();
113 void set_boundary(bd_type left,
double left_value, bd_type right,
double right_value);
116 void set_points(
const std::vector<double>& x,
const std::vector<double>& y, spline_type type = cspline);
125 bool make_monotonic();
128 double operator()(
double x)
const;
129 double deriv(
int order,
double x)
const;
132 std::vector<double> solve(
double y,
bool ignore_extrapolation =
true)
const;
135 std::vector<double> get_x()
const {
return m_x; }
136 std::vector<double> get_y()
const {
return m_y; }
137 double get_x_min()
const {
138 assert(!m_x.empty());
141 double get_x_max()
const {
142 assert(!m_x.empty());
148 std::string info()
const;
157 std::vector<std::vector<double> > m_upper;
158 std::vector<std::vector<double> > m_lower;
162 band_matrix(
int dim,
int n_u,
int n_l);
165 void resize(
int dim,
int n_u,
int n_l);
167 int num_upper()
const {
return (
int)m_upper.size() - 1; }
168 int num_lower()
const {
return (
int)m_lower.size() - 1; }
170 double& operator()(
int i,
int j);
171 double operator()(
int i,
int j)
const;
173 double& saved_diag(
int i);
174 double saved_diag(
int i)
const;
176 std::vector<double> r_solve(
const std::vector<double>& b)
const;
177 std::vector<double> l_solve(
const std::vector<double>& b)
const;
178 std::vector<double> lu_solve(
const std::vector<double>& b,
bool is_lu_decomposed =
false);
183std::vector<double> solve_cubic(
double a,
double b,
double c,
double d,
int newton_iter = 0);
194void spline::set_boundary(spline::bd_type left,
double left_value, spline::bd_type right,
double right_value) {
195 assert(m_x.size() == 0);
198 m_left_value = left_value;
199 m_right_value = right_value;
202void spline::set_coeffs_from_b() {
203 assert(m_x.size() == m_y.size());
204 assert(m_x.size() == m_b.size());
205 assert(m_x.size() > 2);
206 size_t n = m_b.size();
207 if (m_c.size() != n) m_c.resize(n);
208 if (m_d.size() != n) m_d.resize(n);
210 for (
size_t i = 0; i < n - 1; i++) {
211 const double h = m_x[i + 1] - m_x[i];
213 m_c[i] = (3.0 * (m_y[i + 1] - m_y[i]) / h - (2.0 * m_b[i] + m_b[i + 1])) / h;
215 m_d[i] = ((m_b[i + 1] - m_b[i]) / (3.0 * h) - 2.0 / 3.0 * m_c[i]) / h;
219 m_c0 = (m_left == first_deriv) ? 0.0 : m_c[0];
222void spline::set_points(
const std::vector<double>& x,
const std::vector<double>& y, spline_type type) {
223 assert(x.size() == y.size());
224 assert(x.size() >= 3);
226 if (m_left == not_a_knot || m_right == not_a_knot) assert(x.size() >= 4);
228 m_made_monotonic =
false;
231 int n = (int)x.size();
233 for (
int i = 0; i < n - 1; i++) {
234 assert(m_x[i] < m_x[i + 1]);
237 if (type == linear) {
242 for (
int i = 0; i < n - 1; i++) {
245 m_b[i] = (m_y[i + 1] - m_y[i]) / (m_x[i + 1] - m_x[i]);
248 m_b[n - 1] = m_b[n - 2];
251 }
else if (type == cspline) {
257 int n_upper = (m_left == spline::not_a_knot) ? 2 : 1;
258 int n_lower = (m_right == spline::not_a_knot) ? 2 : 1;
259 internal::band_matrix A(n, n_upper, n_lower);
260 std::vector<double> rhs(n);
261 for (
int i = 1; i < n - 1; i++) {
262 A(i, i - 1) = 1.0 / 3.0 * (x[i] - x[i - 1]);
263 A(i, i) = 2.0 / 3.0 * (x[i + 1] - x[i - 1]);
264 A(i, i + 1) = 1.0 / 3.0 * (x[i + 1] - x[i]);
265 rhs[i] = (y[i + 1] - y[i]) / (x[i + 1] - x[i]) - (y[i] - y[i - 1]) / (x[i] - x[i - 1]);
268 if (m_left == spline::second_deriv) {
272 rhs[0] = m_left_value;
273 }
else if (m_left == spline::first_deriv) {
276 A(0, 0) = 2.0 * (x[1] - x[0]);
277 A(0, 1) = 1.0 * (x[1] - x[0]);
278 rhs[0] = 3.0 * ((y[1] - y[0]) / (x[1] - x[0]) - m_left_value);
279 }
else if (m_left == spline::not_a_knot) {
282 A(0, 0) = -(x[2] - x[1]);
283 A(0, 1) = x[2] - x[0];
284 A(0, 2) = -(x[1] - x[0]);
289 if (m_right == spline::second_deriv) {
291 A(n - 1, n - 1) = 2.0;
292 A(n - 1, n - 2) = 0.0;
293 rhs[n - 1] = m_right_value;
294 }
else if (m_right == spline::first_deriv) {
298 A(n - 1, n - 1) = 2.0 * (x[n - 1] - x[n - 2]);
299 A(n - 1, n - 2) = 1.0 * (x[n - 1] - x[n - 2]);
300 rhs[n - 1] = 3.0 * (m_right_value - (y[n - 1] - y[n - 2]) / (x[n - 1] - x[n - 2]));
301 }
else if (m_right == spline::not_a_knot) {
304 A(n - 1, n - 3) = -(x[n - 1] - x[n - 2]);
305 A(n - 1, n - 2) = x[n - 1] - x[n - 3];
306 A(n - 1, n - 1) = -(x[n - 2] - x[n - 3]);
313 m_c = A.lu_solve(rhs);
318 for (
int i = 0; i < n - 1; i++) {
319 m_d[i] = 1.0 / 3.0 * (m_c[i + 1] - m_c[i]) / (x[i + 1] - x[i]);
320 m_b[i] = (y[i + 1] - y[i]) / (x[i + 1] - x[i]) - 1.0 / 3.0 * (2.0 * m_c[i] + m_c[i + 1]) * (x[i + 1] - x[i]);
324 double h = x[n - 1] - x[n - 2];
327 m_b[n - 1] = 3.0 * m_d[n - 2] * h * h + 2.0 * m_c[n - 2] * h + m_b[n - 2];
328 if (m_right == first_deriv) m_c[n - 1] = 0.0;
330 }
else if (type == cspline_hermite) {
338 for (
int i = 1; i < n - 1; i++) {
339 const double h = m_x[i + 1] - m_x[i];
340 const double hl = m_x[i] - m_x[i - 1];
341 m_b[i] = -h / (hl * (hl + h)) * m_y[i - 1] + (h - hl) / (hl * h) * m_y[i] + hl / (h * (hl + h)) * m_y[i + 1];
344 if (m_left == first_deriv) {
345 m_b[0] = m_left_value;
346 }
else if (m_left == second_deriv) {
347 const double h = m_x[1] - m_x[0];
348 m_b[0] = 0.5 * (-m_b[1] - 0.5 * m_left_value * h + 3.0 * (m_y[1] - m_y[0]) / h);
349 }
else if (m_left == not_a_knot) {
351 const double h0 = m_x[1] - m_x[0];
352 const double h1 = m_x[2] - m_x[1];
353 m_b[0] = -m_b[1] + 2.0 * (m_y[1] - m_y[0]) / h0 + h0 * h0 / (h1 * h1) * (m_b[1] + m_b[2] - 2.0 * (m_y[2] - m_y[1]) / h1);
357 if (m_right == first_deriv) {
358 m_b[n - 1] = m_right_value;
360 }
else if (m_right == second_deriv) {
361 const double h = m_x[n - 1] - m_x[n - 2];
362 m_b[n - 1] = 0.5 * (-m_b[n - 2] + 0.5 * m_right_value * h + 3.0 * (m_y[n - 1] - m_y[n - 2]) / h);
363 m_c[n - 1] = 0.5 * m_right_value;
364 }
else if (m_right == not_a_knot) {
366 const double h0 = m_x[n - 2] - m_x[n - 3];
367 const double h1 = m_x[n - 1] - m_x[n - 2];
368 m_b[n - 1] = -m_b[n - 2] + 2.0 * (m_y[n - 1] - m_y[n - 2]) / h1 +
369 h1 * h1 / (h0 * h0) * (m_b[n - 3] + m_b[n - 2] - 2.0 * (m_y[n - 2] - m_y[n - 3]) / h0);
371 m_c[n - 1] = (m_b[n - 2] + 2.0 * m_b[n - 1]) / h1 - 3.0 * (m_y[n - 1] - m_y[n - 2]) / (h1 * h1);
385 m_c0 = (m_left == first_deriv) ? 0.0 : m_c[0];
388bool spline::make_monotonic() {
389 assert(m_x.size() == m_y.size());
390 assert(m_x.size() == m_b.size());
391 assert(m_x.size() > 2);
392 bool modified =
false;
393 const int n = (int)m_x.size();
396 for (
int i = 0; i < n; i++) {
397 int im1 = std::max(i - 1, 0);
398 int ip1 = std::min(i + 1, n - 1);
399 if (((m_y[im1] <= m_y[i]) && (m_y[i] <= m_y[ip1]) && m_b[i] < 0.0) ||
400 ((m_y[im1] >= m_y[i]) && (m_y[i] >= m_y[ip1]) && m_b[i] > 0.0)) {
408 for (
int i = 0; i < n - 1; i++) {
409 double h = m_x[i + 1] - m_x[i];
410 double avg = (m_y[i + 1] - m_y[i]) / h;
411 if (avg == 0.0 && (m_b[i] != 0.0 || m_b[i + 1] != 0.0)) {
415 }
else if ((m_b[i] >= 0.0 && m_b[i + 1] >= 0.0 && avg > 0.0) || (m_b[i] <= 0.0 && m_b[i + 1] <= 0.0 && avg < 0.0)) {
417 double r = sqrt(m_b[i] * m_b[i] + m_b[i + 1] * m_b[i + 1]) / std::fabs(avg);
423 m_b[i + 1] *= (3.0 / r);
428 if (modified ==
true) {
430 m_made_monotonic =
true;
437size_t spline::find_closest(
double x)
const {
438 std::vector<double>::const_iterator it;
439 it = std::upper_bound(m_x.begin(), m_x.end(), x);
440 size_t idx = std::max(
int(it - m_x.begin()) - 1, 0);
444double spline::operator()(
double x)
const {
450 size_t n = m_x.size();
451 size_t idx = find_closest(x);
453 double h = x - m_x[idx];
457 interpol = (m_c0 * h + m_b[0]) * h + m_y[0];
458 }
else if (x > m_x[n - 1]) {
460 interpol = (m_c[n - 1] * h + m_b[n - 1]) * h + m_y[n - 1];
463 interpol = ((m_d[idx] * h + m_c[idx]) * h + m_b[idx]) * h + m_y[idx];
468double spline::deriv(
int order,
double x)
const {
470 size_t n = m_x.size();
471 size_t idx = find_closest(x);
473 double h = x - m_x[idx];
479 interpol = 2.0 * m_c0 * h + m_b[0];
482 interpol = 2.0 * m_c0;
488 }
else if (x > m_x[n - 1]) {
492 interpol = 2.0 * m_c[n - 1] * h + m_b[n - 1];
495 interpol = 2.0 * m_c[n - 1];
505 interpol = (3.0 * m_d[idx] * h + 2.0 * m_c[idx]) * h + m_b[idx];
508 interpol = 6.0 * m_d[idx] * h + 2.0 * m_c[idx];
511 interpol = 6.0 * m_d[idx];
521std::vector<double> spline::solve(
double y,
bool ignore_extrapolation)
const {
522 std::vector<double> x;
523 std::vector<double> root;
524 const size_t n = m_x.size();
527 if (ignore_extrapolation ==
false) {
528 root = internal::solve_cubic(m_y[0] - y, m_b[0], m_c0, 0.0, 1);
529 for (
size_t j = 0; j < root.size(); j++) {
531 x.push_back(m_x[0] + root[j]);
538 for (
size_t i = 0; i < n - 1; i++) {
539 root = internal::solve_cubic(m_y[i] - y, m_b[i], m_c[i], m_d[i], 1);
540 for (
size_t j = 0; j < root.size(); j++) {
541 double h = (i > 0) ? (m_x[i] - m_x[i - 1]) : 0.0;
542 double eps = internal::get_eps() * 512.0 * std::min(h, 1.0);
543 if ((-eps <= root[j]) && (root[j] < m_x[i + 1] - m_x[i])) {
544 double new_root = m_x[i] + root[j];
545 if (x.size() > 0 && x.back() + eps > new_root) {
548 x.push_back(new_root);
555 if (ignore_extrapolation ==
false) {
556 root = internal::solve_cubic(m_y[n - 1] - y, m_b[n - 1], m_c[n - 1], 0.0, 1);
557 for (
size_t j = 0; j < root.size(); j++) {
558 if (0.0 <= root[j]) {
559 x.push_back(m_x[n - 1] + root[j]);
568std::string spline::info()
const {
569 std::stringstream ss;
570 ss <<
"type " << m_type <<
", left boundary deriv " << m_left <<
" = ";
571 ss << m_left_value <<
", right boundary deriv " << m_right <<
" = ";
572 ss << m_right_value << std::endl;
573 if (m_made_monotonic) {
574 ss <<
"(spline has been adjusted for piece-wise monotonicity)";
585band_matrix::band_matrix(
int dim,
int n_u,
int n_l) { resize(dim, n_u, n_l); }
586void band_matrix::resize(
int dim,
int n_u,
int n_l) {
590 m_upper.resize(n_u + 1);
591 m_lower.resize(n_l + 1);
592 for (
size_t i = 0; i < m_upper.size(); i++) {
593 m_upper[i].resize(dim);
595 for (
size_t i = 0; i < m_lower.size(); i++) {
596 m_lower[i].resize(dim);
599int band_matrix::dim()
const {
600 if (m_upper.size() > 0) {
601 return m_upper[0].size();
609double& band_matrix::operator()(
int i,
int j) {
611 assert((i >= 0) && (i < dim()) && (j >= 0) && (j < dim()));
612 assert((-num_lower() <= k) && (k <= num_upper()));
615 return m_upper[k][i];
617 return m_lower[-k][i];
619double band_matrix::operator()(
int i,
int j)
const {
621 assert((i >= 0) && (i < dim()) && (j >= 0) && (j < dim()));
622 assert((-num_lower() <= k) && (k <= num_upper()));
625 return m_upper[k][i];
627 return m_lower[-k][i];
630double band_matrix::saved_diag(
int i)
const {
631 assert((i >= 0) && (i < dim()));
632 return m_lower[0][i];
634double& band_matrix::saved_diag(
int i) {
635 assert((i >= 0) && (i < dim()));
636 return m_lower[0][i];
640void band_matrix::lu_decompose() {
647 for (
int i = 0; i < this->dim(); i++) {
648 assert(this->
operator()(i, i) != 0.0);
649 this->saved_diag(i) = 1.0 / this->operator()(i, i);
650 j_min = std::max(0, i - this->num_lower());
651 j_max = std::min(this->dim() - 1, i + this->num_upper());
652 for (
int j = j_min; j <= j_max; j++) {
653 this->operator()(i, j) *= this->saved_diag(i);
655 this->operator()(i, i) = 1.0;
659 for (
int k = 0; k < this->dim(); k++) {
660 i_max = std::min(this->dim() - 1, k + this->num_lower());
661 for (
int i = k + 1; i <= i_max; i++) {
662 assert(this->
operator()(k, k) != 0.0);
663 x = -this->operator()(i, k) / this->operator()(k, k);
664 this->operator()(i, k) = -x;
665 j_max = std::min(this->dim() - 1, k + this->num_upper());
666 for (
int j = k + 1; j <= j_max; j++) {
668 this->operator()(i, j) = this->operator()(i, j) + x * this->operator()(k, j);
674std::vector<double> band_matrix::l_solve(
const std::vector<double>& b)
const {
675 assert(this->dim() == (
int)b.size());
676 std::vector<double> x(this->dim());
679 for (
int i = 0; i < this->dim(); i++) {
681 j_start = std::max(0, i - this->num_lower());
682 for (
int j = j_start; j < i; j++) sum += this->
operator()(i, j) * x[j];
683 x[i] = (b[i] * this->saved_diag(i)) - sum;
688std::vector<double> band_matrix::r_solve(
const std::vector<double>& b)
const {
689 assert(this->dim() == (
int)b.size());
690 std::vector<double> x(this->dim());
693 for (
int i = this->dim() - 1; i >= 0; i--) {
695 j_stop = std::min(this->dim() - 1, i + this->num_upper());
696 for (
int j = i + 1; j <= j_stop; j++) sum += this->
operator()(i, j) * x[j];
697 x[i] = (b[i] - sum) / this->
operator()(i, i);
702std::vector<double> band_matrix::lu_solve(
const std::vector<double>& b,
bool is_lu_decomposed) {
703 assert(this->dim() == (
int)b.size());
704 std::vector<double> x, y;
705 if (is_lu_decomposed ==
false) {
706 this->lu_decompose();
708 y = this->l_solve(b);
709 x = this->r_solve(y);
716 return 2.2204460492503131e-16;
720std::vector<double> solve_linear(
double a,
double b) {
721 std::vector<double> x;
740std::vector<double> solve_quadratic(
double a,
double b,
double c,
int newton_iter = 0) {
742 return solve_linear(a, b);
745 double p = 0.5 * b / c;
747 double discr = p * p - q;
748 const double eps = 0.5 * internal::get_eps();
749 double discr_err = (6.0 * (p * p) + 3.0 * fabs(q) + fabs(discr)) * eps;
751 std::vector<double> x;
752 if (fabs(discr) <= discr_err) {
756 }
else if (discr < 0) {
761 x[0] = -p - sqrt(discr);
762 x[1] = -p + sqrt(discr);
766 for (
size_t i = 0; i < x.size(); i++) {
767 for (
int k = 0; k < newton_iter; k++) {
768 double f = (c * x[i] + b) * x[i] + a;
769 double f1 = 2.0 * c * x[i] + b;
771 if (fabs(f1) > 1e-8) {
787std::vector<double> solve_cubic(
double a,
double b,
double c,
double d,
int newton_iter) {
789 return solve_quadratic(a, b, c, newton_iter);
801 std::vector<double> z;
802 double p = -(1.0 / 3.0) * b + (1.0 / 9.0) * (c * c);
803 double r = 2.0 * (c * c) - 9.0 * b;
804 double q = -0.5 * a - (1.0 / 54.0) * (c * r);
805 double discr = p * p * p - q * q;
813 const double eps = internal::get_eps();
814 double p_err = eps * ((3.0 / 3.0) * fabs(b) + (4.0 / 9.0) * (c * c) + fabs(p));
815 double r_err = eps * (6.0 * (c * c) + 18.0 * fabs(b) + fabs(r));
816 double q_err = 0.5 * fabs(a) * eps + (1.0 / 54.0) * fabs(c) * (r_err + fabs(r) * 3.0 * eps) + fabs(q) * eps;
817 double discr_err = (p * p) * (3.0 * p_err + fabs(p) * 2.0 * eps) + fabs(q) * (2.0 * q_err + fabs(q) * eps) + fabs(discr) * eps;
820 if (fabs(discr) <= discr_err) {
822 if (fabs(p) <= p_err) {
831 }
else if (discr > 0) {
834 double ac = (1.0 / 3.0) * acos(q / (p * sqrt(p)));
835 double sq = 2.0 * sqrt(p);
837 z[1] = sq * cos(ac - 2.0 * M_PI / 3.0);
838 z[2] = sq * cos(ac - 4.0 * M_PI / 3.0);
839 }
else if (discr < 0.0) {
842 double sgnq = (q >= 0 ? 1 : -1);
843 double basis = fabs(q) + sqrt(-discr);
844 double C = sgnq * pow(basis, 1.0 / 3.0);
847 for (
size_t i = 0; i < z.size(); i++) {
849 z[i] -= (1.0 / 3.0) * c;
851 for (
int k = 0; k < newton_iter; k++) {
852 double f = ((z[i] + c) * z[i] + b) * z[i] + a;
853 double f1 = (3.0 * z[i] + 2.0 * c) * z[i] + b;
855 if (fabs(f1) > 1e-8) {
863 assert(z.size() > 0);
864 double xmin = fabs(z[0]);
866 for (
size_t i = 1; i < z.size(); i++) {
867 if (xmin > fabs(z[i])) {
874 std::sort(z.begin(), z.end());