library of assembled shared sources

http://lass.cocamware.com

spline_linear.inl

Go to the documentation of this file.
00001 /** @file
00002  *  @author Bram de Greve (bramz@users.sourceforge.net)
00003  *  @author Tom De Muer (tomdemuer@users.sourceforge.net)
00004  *
00005  *  *** BEGIN LICENSE INFORMATION ***
00006  *  
00007  *  The contents of this file are subject to the Common Public Attribution License 
00008  *  Version 1.0 (the "License"); you may not use this file except in compliance with 
00009  *  the License. You may obtain a copy of the License at 
00010  *  http://lass.sourceforge.net/cpal-license. The License is based on the 
00011  *  Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover 
00012  *  use of software over a computer network and provide for limited attribution for 
00013  *  the Original Developer. In addition, Exhibit A has been modified to be consistent 
00014  *  with Exhibit B.
00015  *  
00016  *  Software distributed under the License is distributed on an "AS IS" basis, WITHOUT 
00017  *  WARRANTY OF ANY KIND, either express or implied. See the License for the specific 
00018  *  language governing rights and limitations under the License.
00019  *  
00020  *  The Original Code is LASS - Library of Assembled Shared Sources.
00021  *  
00022  *  The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
00023  *  The Original Developer is the Initial Developer.
00024  *  
00025  *  All portions of the code written by the Initial Developer are:
00026  *  Copyright (C) 2004-2007 the Initial Developer.
00027  *  All Rights Reserved.
00028  *  
00029  *  Contributor(s):
00030  *
00031  *  Alternatively, the contents of this file may be used under the terms of the 
00032  *  GNU General Public License Version 2 or later (the GPL), in which case the 
00033  *  provisions of GPL are applicable instead of those above.  If you wish to allow use
00034  *  of your version of this file only under the terms of the GPL and not to allow 
00035  *  others to use your version of this file under the CPAL, indicate your decision by 
00036  *  deleting the provisions above and replace them with the notice and other 
00037  *  provisions required by the GPL License. If you do not delete the provisions above,
00038  *  a recipient may use your version of this file under either the CPAL or the GPL.
00039  *  
00040  *  *** END LICENSE INFORMATION ***
00041  */
00042 
00043 
00044 
00045 #ifndef LASS_GUARDIAN_OF_INCLUSION_NUM_SPLINE_LINEAR_INL
00046 #define LASS_GUARDIAN_OF_INCLUSION_NUM_SPLINE_LINEAR_INL
00047 
00048 #include "num_common.h"
00049 #include "spline_linear.h"
00050 #include "../stde/extended_iterator.h"
00051 
00052 namespace lass
00053 {
00054 namespace num
00055 {
00056 
00057 // --- public --------------------------------------------------------------------------------------
00058 
00059 template <typename S, typename D, typename T>
00060 SplineLinear<S, D, T>::SplineLinear()
00061 {
00062 }
00063 
00064 
00065 
00066 /** construct a spline from a range of control/data pairs.
00067  *
00068  *  Each node consists of a control value and a data value.  This contstructor accepts a single 
00069  *  range [iFirst, iLast) of control/data pairs.  The iterator type should have two fields
00070  *  @c first and @c second that contain respectively the control and data values.  This is
00071  *  choosen so that a std::pair can be used as a representatin of the control/data pair.
00072  *
00073  *  @pre
00074  *  @arg [iFirst, iLast) is a valid range.
00075  *  @arg @c PairInputIterator has a member @c first containing the control value
00076  *  @arg @c PairInputIterator has a member @c second containing the data value
00077  *
00078  *  @par complexity: 
00079  *      O(D * log(N)) with 
00080  *      @arg D = a figure that indicates the complexity of operations on data values.
00081  *               Is most probably linear with the dimension of the data value
00082  *      @arg N = number of nodes
00083  */
00084 template <typename S, typename D, typename T>
00085 template <typename PairInputIterator>
00086 SplineLinear<S, D, T>::SplineLinear(PairInputIterator iFirst, 
00087                                     PairInputIterator iLast)
00088 {
00089     while (iFirst != iLast)
00090     {
00091         Node node;
00092         node.x = iFirst->first;
00093         node.y = iFirst->second;
00094         nodes_.push_back(node);
00095         ++iFirst;
00096     }
00097     init();
00098 }
00099 
00100 
00101 
00102 /** construct a spline from seperate ranges.
00103  *
00104  *  Each node consists of a control value and a data value.  This contstructor accepts seperate
00105  *  ranges for control and data values.  The control values are given by the range 
00106  *  [iFirstControl , iLastControl).  Of the range of the data values, only the iterator
00107  *  iFirstData to the the first element is given.
00108  *
00109  *  @pre
00110  *  @arg [iFirstControl, iLastControl) is a valid range.
00111  *  @arg [iFirstData, iFirstData + (iLastControl - iFirstControl)) is a valid range.
00112  *
00113  *  @par complexity: 
00114  *      O(D * log(N)) with 
00115  *      @arg D = a figure that indicates the complexity of operations on data values.
00116  *               Is most probably linear with the dimension of the data value
00117  *      @arg N = number of nodes
00118  */
00119 template <typename S, typename D, typename T>
00120 template <typename ScalarInputIterator, typename DataInputIterator>
00121 SplineLinear<S, D, T>::SplineLinear(ScalarInputIterator iFirstControl, 
00122                                     ScalarInputIterator iLastControl,
00123                                     DataInputIterator iFirstData)
00124 {
00125     while (iFirstControl != iLastControl)
00126     {
00127         Node node;
00128         node.x = *iFirstControl++;
00129         node.y = *iFirstData++;
00130         nodes_.push_back(node);
00131     }
00132     init();
00133 }
00134 
00135 
00136 
00137 /** Get the linear interpolated data value that corresponds with constrol value @a iX.
00138  *
00139  *  @pre this->isEmpty() == false
00140  *
00141  *  @par complexity: 
00142  *      O(D * log(N)) with 
00143  *      @arg D = a figure that indicates the complexity of operations on data values.
00144  *               Is most probably linear with the dimension of the data value
00145  *      @arg N = number of nodes
00146  */
00147 template <typename S, typename D, typename T>
00148 const typename SplineLinear<S, D, T>::TData
00149 SplineLinear<S, D, T>::operator ()(TScalar iX) const
00150 {
00151     LASS_ASSERT(!isEmpty());
00152 
00153     const typename TNodes::const_iterator n = findNode(iX);
00154     const TScalar dx = iX - n->x;
00155 
00156     TData result(n->y);
00157     TDataTraits::multiplyAccumulate(result, n->dy, dx);
00158     return result;
00159 }
00160 
00161 
00162 
00163 /** Get the first derivative of data value that corresponds with constrol value @a iX.
00164  *
00165  *  As long as @a iX is exact on a node, it equals to lim_{dx->0} (*this(iX + dx) - *this(iX)) / dx.
00166  *  With linear splines, in theory the first derivative does not exist on the nodes.  This
00167  *  function however will return the first derivative on the right of the node. *  
00168  *
00169  *  @pre this->isEmpty() == false
00170  *
00171  *  @par complexity: 
00172  *      O(D * log(N)) with 
00173  *      @arg D = a figure that indicates the complexity of operations on data values.
00174  *               Is most probably linear with the dimension of the data value
00175  *      @arg N = number of nodes
00176  */
00177 template <typename S, typename D, typename T>
00178 const typename SplineLinear<S, D, T>::TData
00179 SplineLinear<S, D, T>::derivative(TScalar iX) const
00180 {
00181     LASS_ASSERT(!isEmpty());
00182 
00183     return findNode(iX)->dy;
00184 }
00185 
00186 
00187 
00188 /** Get the second derivative of data value that corresponds with constrol value @a iX.
00189  *
00190  *  For a linear spline, the second derivative is always zero, except on the nodes where it
00191  *  does not exist.  This function however will always return zero, even on the nodes.
00192  *
00193  *  @pre this->isEmpty() == false
00194  *
00195  *  @par complexity: 
00196  *      O(D * log(N)) with 
00197  *      @arg D = a figure that indicates the complexity of operations on data values.
00198  *               Is most probably linear with the dimension of the data value
00199  *      @arg N = number of nodes
00200  */
00201 template <typename S, typename D, typename T>
00202 const typename SplineLinear<S, D, T>::TData
00203 SplineLinear<S, D, T>::derivative2(TScalar /*iX*/) const
00204 {
00205     LASS_ASSERT(!isEmpty());
00206 
00207     TData result;
00208     TDataTraits::zero(result, dataDimension_);
00209     return result;
00210 }
00211 
00212 
00213 
00214 /** Get the integrated data value between control points @a iA and @a iB.
00215  *
00216  *  @pre this->isEmpty() == false
00217  *
00218  *  @par complexity: 
00219  *      O(D * M * log(N)) with 
00220  *      @arg D = a figure that indicates the complexity of operations on data values.
00221  *               Is most probably linear with the dimension of the data value
00222  *      @arg M = number of nodes between @a iA and @a iB.
00223  *      @arg N = total number of nodes in spline
00224  */
00225 template <typename S, typename D, typename T>
00226 const typename SplineLinear<S, D, T>::TData
00227 SplineLinear<S, D, T>::integral(TScalar iBegin, TScalar iEnd) const
00228 {
00229     LASS_ASSERT(!isEmpty());
00230 
00231     TNodeConstIterator first = findNode(iBegin);
00232     TNodeConstIterator last = findNode(iEnd);
00233     if (first == last)
00234     {
00235         TData result(first->y);
00236         TDataTraits::scale(result, iEnd - iBegin);
00237         TDataTraits::multiplyAccumulate(result, first->dy, 
00238             (num::sqr(iEnd - first->x) - num::sqr(iBegin - first->x)) / 2);
00239         return result;
00240     }
00241     else
00242     {
00243         TScalar multiplier = 1;
00244         if (iEnd < iBegin)
00245         {
00246             std::swap(iBegin, iEnd);
00247             std::swap(first, last);
00248             multiplier = -1;
00249         }
00250 
00251         TNodeConstIterator next = stde::next(first);
00252 
00253         TData result(first->y);
00254         TDataTraits::scale(result, next->x - iBegin);
00255         TDataTraits::multiplyAccumulate(result, first->dy, 
00256             (num::sqr(next->x - first->x) - num::sqr(iBegin - first->x)) / 2);
00257         first = next++;
00258 
00259         while (first != last)
00260         {
00261             const TScalar dx = next->x - first->x;
00262             TDataTraits::multiplyAccumulate(result, first->y, dx);
00263             TDataTraits::multiplyAccumulate(result, first->dy, num::sqr(dx) / 2);
00264             first = next++;
00265         }
00266 
00267         const TScalar dx = iEnd - first->x;
00268         TDataTraits::multiplyAccumulate(result, first->y, dx);
00269         TDataTraits::multiplyAccumulate(result, first->dy, num::sqr(dx) / 2);
00270 
00271         TDataTraits::scale(result, multiplier);
00272         return result;
00273     }
00274 }
00275 
00276 
00277 
00278 /** return true if the spline contains any nodes at all.
00279  *  @par complexity: 
00280  *      O(1)
00281  */
00282 template <typename S, typename D, typename T>
00283 const bool SplineLinear<S, D, T>::isEmpty() const
00284 {
00285     return nodes_.empty();
00286 }
00287 
00288 
00289 
00290 /** return the range of control values for which the spline can interpolate.
00291  *  @par complexity: 
00292  *      O(1)
00293  */
00294 template <typename S, typename D, typename T>
00295 const typename SplineLinear<S, D, T>::TControlRange
00296 SplineLinear<S, D, T>::controlRange() const
00297 {
00298     typedef typename SplineLinear<S, D, T>::TControlRange TRange;
00299     return TRange(nodes_.front().x, nodes_.back().x);
00300 }
00301 
00302 
00303 
00304 // --- private -------------------------------------------------------------------------------------
00305 
00306 template <typename S, typename D, typename T>
00307 void SplineLinear<S, D, T>::init()
00308 {
00309     // are there any nodes at all?  we need at least two!
00310     //
00311     const typename TNodes::size_type size = nodes_.size();
00312     if (size < 2)
00313     {
00314         LASS_THROW("A linear interpolator needs at least two nodes!  This one only has '"
00315             << static_cast<unsigned>(nodes_.size()) << "'.");
00316     }
00317 
00318     typename TNodes::iterator prev = nodes_.begin();
00319     dataDimension_ = TDataTraits::dimension(prev->y);
00320     const typename TNodes::iterator end = nodes_.end();
00321     for (typename TNodes::iterator i = stde::next(nodes_.begin()); i != end; prev = i++)
00322     {
00323         // check for increasing control components
00324         //
00325         if (prev->x >= i->x)
00326         {
00327             LASS_THROW("Nodes in linear interpolator must have absolutely increasing control "
00328                 "values.");
00329         }
00330 
00331         // check dimension of data
00332         //
00333         if (TDataTraits::dimension(i->y) != dataDimension_)
00334         {
00335             LASS_THROW("All data in linear interpolator must be of same dimension.");
00336         }
00337 
00338         // calculate derivative of previous node
00339         //
00340         prev->dy = i->y;
00341         TDataTraits::multiplyAccumulate(prev->dy, prev->y, -1);
00342         TDataTraits::scale(prev->dy, num::inv(i->x - prev->x));
00343     }
00344 
00345     // extend last node with same derivative as last edge.
00346     stde::prev(end)->dy = stde::prev(end, 2)->dy;
00347 }
00348 
00349 
00350 
00351 /** binary search to find node that belongs to iX
00352  *
00353  *  @return
00354  *  @arg the index @a i if @a iX is in the interval [@c nodes_[i].x, @c nodes_[i+1].x)
00355  *  @arg 0 if @a iX is smaller than @c nodes_[0].x</tt>
00356  *  @arg @c nodes_.size()-2 if @a iX is greater than @c nodes_[nodes_.size()-1].x
00357  *
00358  *  complexity: O(ln N)
00359  */
00360 template <typename S, typename D, typename T>
00361 const typename SplineLinear<S, D, T>::TNodeConstIterator
00362 SplineLinear<S, D, T>::findNode(TScalar iX) const
00363 {
00364     LASS_ASSERT(nodes_.size() >= 2);
00365 
00366     // early outs
00367     //
00368     if (iX < nodes_.front().x)
00369     {
00370         return nodes_.begin();
00371     }
00372     if (iX >= nodes_.back().x)
00373     {
00374         return stde::prev(nodes_.end());
00375     }
00376 
00377     // binary search
00378     //
00379     TNodeConstIterator first = nodes_.begin();
00380     TNodeConstIterator last = nodes_.end();
00381     while (stde::next(first) != last)
00382     {
00383         TNodeConstIterator middle = stde::next(first, std::distance(first, last) / 2);
00384         LASS_ASSERT(middle != first && middle != last);
00385 
00386         if (middle->x <= iX)
00387         {
00388             first = middle;
00389         }
00390         else
00391         {
00392             last = middle;
00393         }
00394         LASS_ASSERT(first != last);
00395     }
00396 
00397     LASS_ASSERT(first->x <= iX && last->x > iX);
00398     return first;
00399 }
00400 
00401 
00402 
00403 }
00404 
00405 }
00406 
00407 #endif
00408 
00409 // EOF

Generated on Mon Nov 10 14:21:39 2008 for Library of Assembled Shared Sources by doxygen 1.5.7.1
SourceForge.net Logo