45#ifndef LASS_GUARDIAN_OF_INCLUSION_NUM_SPLINE_CUBIC_INL
46#define LASS_GUARDIAN_OF_INCLUSION_NUM_SPLINE_CUBIC_INL
65template <
typename S,
typename D,
typename T>
66SplineCubic<S, D, T>::SplineCubic()
90template <
typename S,
typename D,
typename T>
91template <
typename PairInputIterator>
92SplineCubic<S, D, T>::SplineCubic(PairInputIterator iFirst, PairInputIterator iLast)
94 while (iFirst != iLast)
97 node.x = iFirst->first;
98 node.d = iFirst->second;
99 nodes_.push_back(node);
124template <
typename S,
typename D,
typename T>
125template <
typename ScalarInputIterator,
typename DataInputIterator>
126SplineCubic<S, D, T>::SplineCubic(ScalarInputIterator iFirstControl,
127 ScalarInputIterator iLastControl,
128 DataInputIterator iFirstData)
130 while (iFirstControl != iLastControl)
133 node.x = *iFirstControl++;
134 node.d = *iFirstData++;
135 nodes_.push_back(node);
152template <
typename S,
typename D,
typename T>
153const typename SplineCubic<S, D, T>::TData
154SplineCubic<S, D, T>::operator ()(TScalar iX)
const
156 LASS_ASSERT(!isEmpty());
158 const TNodeConstIterator n = findNode(iX);
159 const TScalar s = iX - n->x;
161 TDataTraits::multiplyAccumulate(result, n->c, s);
162 TDataTraits::multiplyAccumulate(result, n->b,
num::sqr(s));
163 TDataTraits::multiplyAccumulate(result, n->a,
num::cubic(s));
179template <
typename S,
typename D,
typename T>
180const typename SplineCubic<S, D, T>::TData
181SplineCubic<S, D, T>::derivative(TScalar iX)
const
183 LASS_ASSERT(!isEmpty());
185 const TNodeConstIterator n = findNode(iX);
186 const TScalar s = iX - n->x;
188 TDataTraits::multiplyAccumulate(result, n->b, 2 * s);
189 TDataTraits::multiplyAccumulate(result, n->a, 3 *
num::sqr(s));
205template <
typename S,
typename D,
typename T>
206const typename SplineCubic<S, D, T>::TData
207SplineCubic<S, D, T>::derivative2(TScalar iX)
const
209 LASS_ASSERT(!isEmpty());
211 const TNodeConstIterator n = findNode(iX);
212 const TScalar s = iX - n->x;
214 TDataTraits::multiplyAccumulate(result, n->a, 6 * s);
231template <
typename S,
typename D,
typename T>
232const typename SplineCubic<S, D, T>::TData
233SplineCubic<S, D, T>::integral(TScalar iBegin, TScalar iEnd)
const
235 LASS_ASSERT(!isEmpty());
237 TNodeConstIterator first = findNode(iBegin);
238 TNodeConstIterator last = findNode(iEnd);
241 const TScalar s1 = iBegin - first->x;
242 const TScalar s2 = iEnd - first->x;
243 TData result(first->d);
244 TDataTraits::scale(result, s2 - s1);
245 TDataTraits::multiplyAccumulate(result, first->c, (
num::sqr(s2) -
num::sqr(s1)) / 2);
252 TScalar multiplier = 1;
255 std::swap(iBegin, iEnd);
256 std::swap(first, last);
260 TNodeConstIterator
next = stde::next(first);
262 const TScalar s1 = iBegin - first->x;
263 const TScalar s2 =
next->x - first->x;
264 TData result(first->d);
265 TDataTraits::scale(result, s2 - s1);
266 TDataTraits::multiplyAccumulate(result, first->c, (
num::sqr(s2) -
num::sqr(s1)) / 2);
271 while (first != last)
273 const TScalar s =
next->x - first->x;
274 TDataTraits::multiplyAccumulate(result, first->d, s);
275 TDataTraits::multiplyAccumulate(result, first->c,
num::sqr(s) / 2);
276 TDataTraits::multiplyAccumulate(result, first->b,
num::cubic(s) / 3);
277 TDataTraits::multiplyAccumulate(result, first->a,
num::sqr(
num::sqr(s)) / 4);
281 const TScalar s = iEnd - first->x;
282 TDataTraits::multiplyAccumulate(result, first->d, s);
283 TDataTraits::multiplyAccumulate(result, first->c,
num::sqr(s) / 2);
284 TDataTraits::multiplyAccumulate(result, first->b,
num::cubic(s) / 3);
285 TDataTraits::multiplyAccumulate(result, first->a,
num::sqr(
num::sqr(s)) / 4);
287 TDataTraits::scale(result, multiplier);
299template <
typename S,
typename D,
typename T>
300bool SplineCubic<S, D, T>::isEmpty()
const
302 return nodes_.empty();
311template <
typename S,
typename D,
typename T>
312const typename SplineCubic<S, D, T>::TControlRange
313SplineCubic<S, D, T>::controlRange()
const
315 return TControlRange(nodes_.front().x, nodes_.back().x);
322template <
typename S,
typename D,
typename T>
323void SplineCubic<S, D, T>::init()
325 typedef std::vector<TScalar> TVector;
329 const size_t n = nodes_.size();
332 LASS_THROW(
"A cubic spline needs at least two nodes! This one only has '"
333 <<
static_cast<unsigned>(n) <<
"'.");
340 dataDimension_ = TDataTraits::dimension(nodes_[0].d);
342 for (
size_t i = 1; i < n; ++i)
344 h.push_back(nodes_[i].x - nodes_[i - 1].x);
348 LASS_THROW(
"Nodes in cubic spline must have absolutely increasing control components.");
350 if (TDataTraits::dimension(nodes_[i].d) != dataDimension_)
352 LASS_THROW(
"All data elements in cubic spline must have same dimension.");
359 TDataTraits::zero(nodes_[0].a, dataDimension_);
360 TDataTraits::zero(nodes_[0].b, dataDimension_);
361 nodes_[0].c = nodes_[1].d;
362 TDataTraits::multiplyAccumulate(nodes_[0].c, nodes_[0].d, -1);
363 TDataTraits::scale(nodes_[0].c,
num::inv(h[0]));
364 nodes_[1].a = nodes_[0].a;
365 nodes_[1].b = nodes_[0].b;
366 nodes_[1].c = nodes_[0].c;
372 for (
size_t i = 0; i < n; ++i)
374 TDataTraits::zero(nodes_[i].b, dataDimension_);
381 const size_t numUnknowns = n - 2;
384 TVector ma(numUnknowns);
385 TVector mb(numUnknowns);
386 TVector mc(numUnknowns);
387 TVector temp(numUnknowns);
388 TVector unknowns(numUnknowns);
390 mb[0] = 2 * (h[0] + h[1]);
392 for (
size_t i = 1; i < numUnknowns - 1; ++i)
395 mb[i] = 2 * (h[i] + h[i + 1]);
398 ma[numUnknowns - 1] = h[numUnknowns - 1];
399 mb[numUnknowns - 1] = 2 * (h[numUnknowns - 1] + h[numUnknowns]);
401 for (
size_t k = 0; k < dataDimension_; ++k)
403 for (
size_t i = 0; i < numUnknowns; ++i)
406 const TScalar d0 = TDataTraits::get(nodes_[i].d, k);
407 const TScalar d1 = TDataTraits::get(nodes_[i + 1].d, k);
408 const TScalar d2 = TDataTraits::get(nodes_[i + 2].d, k);
409 unknowns[i] = 3 * (d0 / h[i] - d1 * (h[i] + h[i + 1]) / (h[i] * h[i + 1]) + d2 / h[i + 1]);
411 if (!num::impl::solveTridiagonal<TScalar>(\
412 ma.begin(), mb.begin(), mc.begin(), unknowns.begin(), temp.begin(), numCast<std::ptrdiff_t>(numUnknowns)))
414 LASS_THROW(
"serious logic error, could not solve equation, contact [Bramz]");
416 for (
size_t i = 0; i < numUnknowns; ++i)
418 TDataTraits::set(nodes_[i + 1].b, k, unknowns[i]);
424 for (
size_t i = 0; i < n - 1; ++i)
426 Node& node = nodes_[i];
427 const Node& nextNode = nodes_[i + 1];
431 TDataTraits::multiplyAccumulate(node.a, node.b, -1);
432 TDataTraits::scale(node.a,
num::inv(3 * h[i]));
436 TDataTraits::multiplyAccumulate(node.c, node.d, -1);
437 TDataTraits::scale(node.c,
num::inv(h[i]));
438 TDataTraits::multiplyAccumulate(node.c, nextNode.b, -h[i] / 3);
439 TDataTraits::multiplyAccumulate(node.c, node.b, -2 * h[i] / 3);
442 Node& node = nodes_[n - 1];
443 const Node& prevNode = nodes_[n - 2];
445 TDataTraits::multiplyAccumulate(node.c, prevNode.b, 2 * h[n - 2]);
446 TDataTraits::multiplyAccumulate(node.c, prevNode.a, 3 *
num::sqr(h[n - 2]));
462template <
typename S,
typename D,
typename T>
463const typename SplineCubic<S, D, T>::TNodeConstIterator
464SplineCubic<S, D, T>::findNode(TScalar iX)
const
466 const typename TNodes::size_type size = nodes_.size();
467 LASS_ASSERT(nodes_.size() >= 2);
471 if (iX < nodes_[1].x)
473 return nodes_.begin();
475 if (iX >= nodes_[size - 2].x)
477 return stde::prev(nodes_.end(), 2);
482 TNodeConstIterator first = nodes_.begin();
483 TNodeConstIterator last = nodes_.end();
484 while (stde::next(first) != last)
486 TNodeConstIterator middle = stde::next(first, std::distance(first, last) / 2);
487 LASS_ASSERT(middle != first && middle != last);
497 LASS_ASSERT(first != last);
500 LASS_ASSERT(first->x <= iX && last->x > iX);
T sqr(const T &x)
return x * x
T inv(const T &x)
return x ^ -1
T cubic(const T &x)
return x * x * x
const lass::python::impl::IterNextSlot next("__next__", Py_tp_iternext)
__next__ method (iterator next)
numeric types and traits.
Library for Assembled Shared Sources.