48 std::vector< std::vector<double> > m_upper;
49 std::vector< std::vector<double> > m_lower;
52 band_matrix(
int dim,
int n_u,
int n_l);
54 void resize(
int dim,
int n_u,
int n_l);
58 return m_upper.size() - 1;
62 return m_lower.size() - 1;
65 double& operator () (
int i,
int j);
66 double operator () (
int i,
int j)
const;
68 double& saved_diag(
int i);
69 double saved_diag(
int i)
const;
71 std::vector<double> r_solve(
const std::vector<double>& b)
const;
72 std::vector<double> l_solve(
const std::vector<double>& b)
const;
73 std::vector<double> lu_solve(
const std::vector<double>& b,
74 bool is_lu_decomposed =
false);
90 std::vector<double> m_x, m_y;
93 std::vector<double> m_a, m_b, m_c;
95 bd_type m_left, m_right;
96 double m_left_value, m_right_value;
97 bool m_force_linear_extrapolation;
101 spline(): m_left(second_deriv), m_right(second_deriv),
102 m_left_value(0.0), m_right_value(0.0),
103 m_force_linear_extrapolation(
false)
109 void set_boundary(bd_type left,
double left_value,
110 bd_type right,
double right_value,
111 bool force_linear_extrapolation =
false);
112 void set_points(
const std::vector<double>& x,
113 const std::vector<double>& y,
bool cubic_spline =
true);
114 double operator() (
double x)
const;
115 double deriv(
int order,
double x)
const;
116 std::vector<double> operator[] (
size_t i)
const;
129 band_matrix::band_matrix(
int dim,
int n_u,
int n_l)
131 resize(dim, n_u, n_l);
133 void band_matrix::resize(
int dim,
int n_u,
int n_l)
138 m_upper.resize(n_u + 1);
139 m_lower.resize(n_l + 1);
140 for (
size_t i = 0; i < m_upper.size(); i++)
142 m_upper[i].resize(dim);
144 for (
size_t i = 0; i < m_lower.size(); i++)
146 m_lower[i].resize(dim);
149 int band_matrix::dim()
const
151 if (m_upper.size() > 0)
153 return m_upper[0].size();
164 double& band_matrix::operator () (
int i,
int j)
167 assert( (i >= 0) && (i < dim()) && (j >= 0) && (j < dim()) );
168 assert( (-num_lower() <= k) && (k <= num_upper()) );
170 if (k >= 0)
return m_upper[k][i];
171 else return m_lower[-k][i];
173 double band_matrix::operator () (
int i,
int j)
const
176 assert( (i >= 0) && (i < dim()) && (j >= 0) && (j < dim()) );
177 assert( (-num_lower() <= k) && (k <= num_upper()) );
179 if (k >= 0)
return m_upper[k][i];
180 else return m_lower[-k][i];
183 double band_matrix::saved_diag(
int i)
const
185 assert( (i >= 0) && (i < dim()) );
186 return m_lower[0][i];
188 double& band_matrix::saved_diag(
int i)
190 assert( (i >= 0) && (i < dim()) );
191 return m_lower[0][i];
195 void band_matrix::lu_decompose()
203 for (
int i = 0; i < this->dim(); i++)
205 assert(this->
operator()(i, i) != 0.0);
206 this->saved_diag(i) = 1.0 / this->operator()(i, i);
207 j_min =
std::max(0, i - this->num_lower());
208 j_max =
std::min(this->dim() - 1, i + this->num_upper());
209 for (
int j = j_min; j <= j_max; j++)
211 this->operator()(i, j) *= this->saved_diag(i);
213 this->operator()(i, i) = 1.0;
217 for (
int k = 0; k < this->dim(); k++)
219 i_max =
std::min(this->dim() - 1, k + this->num_lower());
220 for (
int i = k + 1; i <= i_max; i++)
222 assert(this->
operator()(k, k) != 0.0);
223 x = -this->operator()(i, k) / this->operator()(k, k);
224 this->operator()(i, k) = -x;
225 j_max =
std::min(this->dim() - 1, k + this->num_upper());
226 for (
int j = k + 1; j <= j_max; j++)
229 this->operator()(i, j) = this->operator()(i, j) + x * this->operator()(k, j);
235 std::vector<double> band_matrix::l_solve(
const std::vector<double>& b)
const
237 assert( this->dim() == (
int)b.size() );
238 std::vector<double> x(this->dim());
241 for (
int i = 0; i < this->dim(); i++)
244 j_start =
std::max(0, i - this->num_lower());
245 for (
int j = j_start; j < i; j++) sum += this->
operator()(i, j) * x[j];
246 x[i] = (b[i] * this->saved_diag(i)) - sum;
251 std::vector<double> band_matrix::r_solve(
const std::vector<double>& b)
const
253 assert( this->dim() == (
int)b.size() );
254 std::vector<double> x(this->dim());
257 for (
int i = this->dim() - 1; i >= 0; i--)
260 j_stop =
std::min(this->dim() - 1, i + this->num_upper());
261 for (
int j = i + 1; j <= j_stop; j++) sum += this->
operator()(i, j) * x[j];
262 x[i] = ( b[i] - sum ) / this->
operator()(i, i);
267 std::vector<double> band_matrix::lu_solve(
const std::vector<double>& b,
268 bool is_lu_decomposed)
270 assert( this->dim() == (
int)b.size() );
271 std::vector<double> x, y;
272 if (is_lu_decomposed ==
false)
274 this->lu_decompose();
276 y = this->l_solve(b);
277 x = this->r_solve(y);
287 void spline::set_boundary(spline::bd_type left,
double left_value,
288 spline::bd_type right,
double right_value,
289 bool force_linear_extrapolation)
291 assert(m_x.size() == 0);
294 m_left_value = left_value;
295 m_right_value = right_value;
296 m_force_linear_extrapolation = force_linear_extrapolation;
300 void spline::set_points(
const std::vector<double>& x,
301 const std::vector<double>& y,
bool cubic_spline)
303 assert(x.size() == y.size());
304 assert(x.size() > 2);
309 for (
int i = 0; i < n - 1; i++)
311 assert(m_x[i] <= m_x[i + 1]);
315 size_t nPos = (size_t)-1;
318 for (
size_t i = 0; i < m_x.size()-1; i++)
320 if (m_x[i] == m_x[i+1])
322 if (nPos == (
size_t)-1)
327 else if (nPos != (
size_t)-1)
330 dAvg /= i - nPos + 1;
332 m_x.erase(m_x.begin()+nPos, m_x.begin()+i);
333 m_y.erase(m_y.begin()+nPos, m_y.begin()+i);
340 if (cubic_spline ==
true)
344 band_matrix A(n, 1, 1);
345 std::vector<double> rhs(n);
346 for (
int i = 1; i < n - 1; i++)
348 A(i, i - 1) = 1.0 / 3.0 * (x[i] - x[i - 1]);
349 A(i, i) = 2.0 / 3.0 * (x[i + 1] - x[i - 1]);
350 A(i, i + 1) = 1.0 / 3.0 * (x[i + 1] - x[i]);
351 rhs[i] = (y[i + 1] - y[i]) / (x[i + 1] - x[i]) - (y[i] - y[i - 1]) / (x[i] - x[i - 1]);
354 if (m_left == spline::second_deriv)
359 rhs[0] = m_left_value;
361 else if (m_left == spline::first_deriv)
365 A(0, 0) = 2.0 * (x[1] - x[0]);
366 A(0, 1) = 1.0 * (x[1] - x[0]);
367 rhs[0] = 3.0 * ((y[1] - y[0]) / (x[1] - x[0]) - m_left_value);
373 if (m_right == spline::second_deriv)
376 A(n - 1, n - 1) = 2.0;
377 A(n - 1, n - 2) = 0.0;
378 rhs[n - 1] = m_right_value;
380 else if (m_right == spline::first_deriv)
385 A(n - 1, n - 1) = 2.0 * (x[n - 1] - x[n - 2]);
386 A(n - 1, n - 2) = 1.0 * (x[n - 1] - x[n - 2]);
387 rhs[n - 1] = 3.0 * (m_right_value - (y[n - 1] - y[n - 2]) / (x[n - 1] - x[n - 2]));
395 m_b = A.lu_solve(rhs);
400 for (
int i = 0; i < n - 1; i++)
402 m_a[i] = 1.0 / 3.0 * (m_b[i + 1] - m_b[i]) / (x[i + 1] - x[i]);
403 m_c[i] = (y[i + 1] - y[i]) / (x[i + 1] - x[i])
404 - 1.0 / 3.0 * (2.0 * m_b[i] + m_b[i + 1]) * (x[i + 1] - x[i]);
412 for (
int i = 0; i < n - 1; i++)
416 m_c[i] = (m_y[i + 1] - m_y[i]) / (m_x[i + 1] - m_x[i]);
421 m_b0 = (m_force_linear_extrapolation ==
false) ? m_b[0] : 0.0;
426 double h = x[n - 1] - x[n - 2];
429 m_c[n - 1] = 3.0 * m_a[n - 2] * h * h + 2.0 * m_b[n - 2] * h + m_c[n - 2];
430 if (m_force_linear_extrapolation ==
true)
434 double spline::operator() (
double x)
const
436 size_t n = m_x.size();
438 std::vector<double>::const_iterator it;
439 it = std::lower_bound(m_x.begin(), m_x.end(), x);
440 int idx =
std::max(
int(it - m_x.begin()) - 1, 0);
442 double h = x - m_x[idx];
447 interpol = (m_b0 * h + m_c0) * h + m_y[0];
449 else if (x > m_x[n - 1])
452 interpol = (m_b[n - 1] * h + m_c[n - 1]) * h + m_y[n - 1];
457 interpol = ((m_a[idx] * h + m_b[idx]) * h + m_c[idx]) * h + m_y[idx];
462 double spline::deriv(
int order,
double x)
const
466 size_t n = m_x.size();
468 std::vector<double>::const_iterator it;
469 it = std::lower_bound(m_x.begin(), m_x.end(), x);
470 int idx =
std::max(
int(it - m_x.begin()) - 1, 0);
472 double h = x - m_x[idx];
480 interpol = 2.0 * m_b0 * h + m_c0;
483 interpol = 2.0 * m_b0 * h;
490 else if (x > m_x[n - 1])
496 interpol = 2.0 * m_b[n - 1] * h + m_c[n - 1];
499 interpol = 2.0 * m_b[n - 1];
512 interpol = (3.0 * m_a[idx] * h + 2.0 * m_b[idx]) * h + m_c[idx];
515 interpol = 6.0 * m_a[idx] * h + 2.0 * m_b[idx];
518 interpol = 6.0 * m_a[idx];
528 std::vector<double> spline::operator[] (
size_t i)
const
530 std::vector<double> vCoeffs;
533 vCoeffs.push_back(NAN);
534 vCoeffs.push_back(NAN);
535 vCoeffs.push_back(NAN);
536 vCoeffs.push_back(NAN);
540 vCoeffs.push_back(m_y[i]);
541 vCoeffs.push_back(m_c[i]);
542 vCoeffs.push_back(m_b[i]);
543 vCoeffs.push_back(m_a[i]);