KJB
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
l_algorithm.h
Go to the documentation of this file.
1 /* $Id: l_algorithm.h 18301 2014-11-26 19:17:13Z ksimek $ */
2 /* {{{=========================================================================== *
3  |
4  | Copyright (c) 1994-2011 by Kobus Barnard (author)
5  |
6  | Personal and educational use of this code is granted, provided that this
7  | header is kept intact, and that the authorship is not misrepresented, that
8  | its use is acknowledged in publications, and relevant papers are cited.
9  |
10  | For other use contact the author (kobus AT cs DOT arizona DOT edu).
11  |
12  | Please note that the code in this file has not necessarily been adequately
13  | tested. Naturally, there is no guarantee of performance, support, or fitness
14  | for any particular task. Nonetheless, I am interested in hearing about
15  | problems that you encounter.
16  |
17  | Author: Kyle Simek
18  * =========================================================================== }}}*/
19 
20 // vim: tabstop=4 shiftwidth=4 foldmethod=marker
21 
22 #ifndef KJB_L_CPP_ALGORITHM_H
23 #define KJB_L_CPP_ALGORITHM_H
24 
29 #include <l_cpp/l_functors.h>
30 #include <l_cpp/l_std_parallel.h>
31 #include <l_cpp/l_exception.h>
32 
33 #include <map>
34 #include <iterator>
35 #include <algorithm>
36 #include <assert.h>
37 #include <cfloat>
38 #include <algorithm>
39 #include <vector>
40 #include <utility>
41 
42 //#include <boost/lambda/lambda.hpp>
43 #include <l_cpp/l_functors.h>
44 //#include <boost/bind.hpp>
45 //#include <boost/function.hpp>
46 #include <boost/concept_check.hpp>
47 //#include <boost/iterator/transform_iterator.hpp>
48 //#include <boost/iterator/indirect_iterator.hpp>
49 
50 namespace kjb
51 {
52 
68 template <class Iterator, class Real>
69 typename std::iterator_traits<Iterator>::value_type lerp(Iterator begin, Iterator end, Real x)
70 {
71  typedef typename std::iterator_traits<Iterator>::value_type value_type;
72  x = std::max(Real(0.0), x);
73  x = std::min(x, Real(1.0));
74 
75  int max_index = std::distance(begin, end) - 1;
76  int integer = x * max_index;
77  Real rational = x * max_index - integer;
78 
79  assert(integer >= 0);
80  assert(integer <= (int) max_index);
81  assert(rational >= 0.0);
82  assert(rational < 1.0);
83 
84  if(integer == (int) max_index)
85  {
86  assert(rational < FLT_EPSILON);
87  Iterator it = begin;
88  std::advance(it, integer);
89  return *it;
90  }
91 
92  Iterator lower = begin;
93  std::advance(lower, integer);
94 
95  Iterator upper = lower;
96  ++upper;
97 
98  value_type interp = (1.0 - rational) * (*lower) + rational * (*upper);
99 
100  return interp;
101 }
102 
120 template <class IIterator, class OIterator, class QueryType>
121 typename std::iterator_traits<OIterator>::value_type
122 lerp(IIterator ibegin, IIterator iend, OIterator obegin, const QueryType& query_point)
123 {
124  size_t n = std::distance(ibegin, iend);
125  OIterator oend = obegin + n;
126 
127  typedef typename std::iterator_traits<IIterator>::value_type InputType ;
128  typedef typename std::iterator_traits<OIterator>::value_type OutputType;
129 
130  BOOST_CONCEPT_ASSERT((boost::Convertible<QueryType, InputType>));
131 
132  if(n == 0)
133  KJB_THROW_2(Illegal_argument, "Function is empty.");
134 
135  IIterator iit = ibegin;
136  std::advance(iit, n-1);
137 
138  const InputType& lower_bound = *ibegin;
139  const InputType& upper_bound = *iit;
140  // out of range
141  if(!(lower_bound <= query_point && query_point <= upper_bound))
143 
144  iit = std::upper_bound(ibegin, iend, query_point);
145  const InputType& iupper = *iit;
146  const InputType& ilower = *(--iit);
147 
148  size_t dist = std::distance(ibegin, iit);
149  // get output lower/upper values
150  OIterator oit = obegin;
151  std::advance(oit, dist);
152  const OutputType& olower = *oit;
153 
154  if(query_point == ilower)
155  return olower;
156 
157  const OutputType& oupper = *(++oit);
158 
159  const InputType offset = query_point - ilower;
160  const InputType range_size = iupper - ilower;
161  return olower + offset * (oupper - olower) / range_size;
162 }
163 
176 template <class IIterator, class OIterator, class I2Iterator, class O2Iterator>
178  IIterator ibegin,
179  IIterator iend,
180  OIterator obegin,
181  I2Iterator i2begin,
182  I2Iterator i2end,
183  O2Iterator o2begin)
184 {
185  size_t n = std::distance(ibegin, iend);
186  OIterator oend = obegin + n;
187 
188  size_t n2 = std::distance(i2begin, i2end);
189  O2Iterator o2end = o2begin + n2;
190 
191  typedef typename std::iterator_traits<IIterator>::value_type InputType;
192  typedef typename std::iterator_traits<OIterator>::value_type OutputType;
193  typedef typename std::iterator_traits<I2Iterator>::value_type Input2Type;
194  typedef typename std::iterator_traits<O2Iterator>::value_type Output2Type;
195 
196  BOOST_CONCEPT_ASSERT((boost::Convertible<InputType, Input2Type>));
197 // BOOST_CONCEPT_ASSERT((boost::Convertible<OutputType, Output2Type>));
198 
199  if(n == 0)
200  KJB_THROW_2(Illegal_argument, "Function is empty.");
201  if(n2 == 0)
202  return;
203 
204  IIterator iit = ibegin;
205  std::advance(iit, n-1);
206 
207  IIterator i2it = i2begin;
208  std::advance(i2it, n2-1);
209 
210  {
211  const InputType& lower_bound = *ibegin;
212  const InputType& upper_bound = *iit;
213 
214  // get range of query inputs
215  const Input2Type& query_lower_bound = *i2begin;
216  const Input2Type& query_upper_bound = *i2it;
217 
218  // out of range
219  if(!(lower_bound <= query_lower_bound && query_upper_bound <= upper_bound))
221 
222  }
223 
224  iit = ibegin;
225  OIterator oit = obegin;
226 
227  i2it = i2begin;
228  O2Iterator o2it = o2begin;
229 
230  // handle one or more query points equal to the lower bound.
231  while(*i2it == *iit)
232  {
233  *o2it++ = *oit;
234  *i2it++;
235  }
236 
237  InputType* prev_input;
238  OutputType* prev_output;
239  Input2Type range_size;
240 
241  // fact: *i2it > *iit
242 
243  for(; i2it != i2end; ++i2it)
244  {
245  const Input2Type& query = *i2it;
246 
247  // make sure iit is the upper bound of the range we're inside
248  // will always be true for the first iteration:
249  if(query > *iit)
250  {
251  while(query > *iit)
252  {
253  prev_input = &*iit;
254  prev_output = &*oit;
255  ++iit;
256  ++oit;
257  }
258  range_size = *iit - *prev_input;
259  }
260 
261  // special case: exact hit
262  if(query == *iit)
263  {
264  *o2it++ = *oit;
265  continue;
266  }
267 
268  // we are now between the lower and upper bound
269  // 1. find out how far above minimum
270  Input2Type distance = query - static_cast<Input2Type>(*prev_input);
271 
272  // 2. convert to percent
273  distance /= range_size;
274 
275  // 3. lerp it
276  *o2it++ = *prev_output + distance * (*oit - *prev_output);
277  }
278 }
279 
293 template <class Key_type, class Value_type, class Query_type>
294 Value_type lerp(const std::map<Key_type, Value_type>& piecewise_function, const Query_type& query_point)
295 {
296  typedef std::map<Key_type, Value_type> Data_set;
297  typedef typename Data_set::const_iterator Iterator;
298  const Data_set& data_set = piecewise_function;
299 
300  BOOST_CONCEPT_ASSERT((boost::Convertible<Query_type, Key_type>));
301 
302  if(data_set.empty())
303  KJB_THROW_2(Illegal_argument, "Function is empty.");
304 
305  // out of range
306  if(!(data_set.begin()->first <= query_point && query_point <= data_set.rbegin()->first))
308 
309  Iterator upper = data_set.upper_bound(query_point);
310  Iterator lower = upper;
311  advance(upper, -1);
312 
313  if(query_point == lower->first)
314  return lower->second;
315 
316  const Key_type offset = query_point - lower->first;
317  const Key_type range_size = upper->first - lower->first;
318  return lower->second + offset * (upper->second - lower->second) / range_size;
319 }
320 
328 template <class ForwardIterator>
329 void linspace(double min, double max, size_t n, ForwardIterator begin, bool endpoint = true)
330 {
331 #if 0 /* This version accumulates precision error the longer the list */
332  double incr;
333  if(endpoint)
334  incr = (max - min) / (n - 1);
335  else
336  incr = (max - min) / n;
337 
338  ForwardIterator end = begin;
339  std::advance(end, n);
340  std::generate(begin, end, Increase_by<double>(min, incr));
341 #else /* This version is a port of matlab's linspace, incurs no drift */
342  double last = (endpoint ? n-1 : n);
343 
344  ForwardIterator it = begin;
345  for(size_t i = 0; i < n-1; ++i)
346  *it++ = min + i / last * (max - min);
347  *it++ = max;
348 #endif
349 }
350 
354 template <class ForwardIterator>
355 void logspace(double min, double max, size_t n, ForwardIterator begin)
356 {
357  linspace(min, max, n, begin);
358 
359  ForwardIterator end = begin;
360  std::advance(end, n);
361  std::transform(begin, end, begin, std::bind1st(std::ptr_fun(static_cast<double(*)(double, double)>(pow)), 10));
362 }
363 
383 template <class InType, class OutIterator, class UnaryOperator>
384 void linspace(
385  const InType& lower,
386  const InType& upper,
387  size_t N,
388  const OutIterator& out_begin,
389  const UnaryOperator& f)
390 {
391  const InType* range[2];
392  range[0] = &lower;
393  range[1] = &upper;
394 
395  // create real-valued inputs
396  std::vector<double> x(N);
397  linspace(0.0, 1.0, N, x.begin());
398 //
399 // // create a transform function converts real-valued inputs to
400 // // InType-valued inputs.
401 // boost::function1<InType, double> lerp = boost::bind(
402 // static_cast< InType (*)(boost::indirect_iterator<InType const**> , boost::indirect_iterator<InType const**>, double)> (&::kjb::lerp),
403 // boost::indirect_iterator<InType const **>(range),
404 // boost::indirect_iterator<InType const **>(range+2),
405 // _1);
406 //
407 // // evaluate function at each point
408 // transform(
409 // boost::make_transform_iterator(x.begin(), lerp),
410 // boost::make_transform_iterator(x.end(), lerp),
411 // out_begin,
412 // f);
413 //
414 // OutIterator out_it = out_begin;
415 // for(size_t i = 0; i < x.size(); ++i)
416 // {
417 // *out_it++ = f(::kjb::lerp(lower, upper, x[i]));
418 // }
419 
420  OutIterator it = out_begin;
421  InType diff = upper - lower;
422 #pragma omp parallel for
423  for(size_t i = 0; i < x.size(); ++i)
424  *it++ = f(lower + x[i] * diff);
425 }
426 
427 
445 template <class InType, class OutIterator>
446 void linspace(InType min, InType max, size_t n, OutIterator begin)
447 {
449  min,
450  max,
451  n,
452  begin,
453  Identity<InType>()); // identity function
454 }
455 } // namespace kjb
456 
457 
458 namespace kjb_parallel
459 {
466 template <class InType, class OutIterator, class UnaryOperator>
467 void linspace(
468  const InType& lower,
469  const InType& upper,
470  size_t N,
471  const OutIterator& out_begin,
472  const UnaryOperator& f)
473 {
474  const InType* range[2];
475  range[0] = &lower;
476  range[1] = &upper;
477 
478  // create real-valued inputs
479  std::vector<double> x(N);
480  ::kjb::linspace(0.0, 1.0, N, x.begin());
481 //
482 // // create a transform function converts real-valued inputs to
483 // // InType-valued inputs.
484 // boost::function1<InType, double> lerp = boost::bind(
485 // static_cast< InType (*)(boost::indirect_iterator<InType const**> , boost::indirect_iterator<InType const**>, double)> (&::kjb::lerp),
486 // boost::indirect_iterator<InType const **>(range),
487 // boost::indirect_iterator<InType const **>(range+2),
488 // _1);
489 //
490 // // evaluate function at each point
491 // transform(
492 // boost::make_transform_iterator(x.begin(), lerp),
493 // boost::make_transform_iterator(x.end(), lerp),
494 // out_begin,
495 // f);
496 //
497 //#pragma omp parallel for
498 // for(size_t i = 0; i < x.size(); ++i)
499 // {
500 // out_begin[i] = f(lerp(lower, upper, x[i]));
501 // }
502 
503  OutIterator it = out_begin;
504  InType diff = upper - lower;
505 #pragma omp parallel for
506  for(size_t i = 0; i < x.size(); ++i)
507  *it++ = f(lower + x[i] * diff);
508 }
509 
510 } // namespace kjb_parallel
511 
512 #endif
Identity function.
Definition: l_functors.h:144
Int_matrix::Value_type max(const Int_matrix &mat)
Return the maximum value in this matrix.
Definition: l_int_matrix.h:1397
void ordered_lerp(IIterator ibegin, IIterator iend, OIterator obegin, I2Iterator i2begin, I2Iterator i2end, O2Iterator o2begin)
Definition: l_algorithm.h:177
Object thrown when an index argument exceeds the size of a container.
Definition: l_exception.h:399
Generator that increases (using +=) itself by the given value everytime it is called.
Definition: l_functors.h:65
#define KJB_THROW(ex)
Definition: l_exception.h:46
std::iterator_traits< Iterator >::value_type lerp(Iterator begin, Iterator end, Real x)
Definition: l_algorithm.h:69
double dist(const pt a, const pt b)
compute approx. Great Circle distance between two UTM points
Definition: layer.cpp:45
x
Definition: APPgetLargeConnectedEdges.m:100
void linspace(double min, double max, size_t n, ForwardIterator begin, bool endpoint=true)
Definition: l_algorithm.h:329
void linspace(const InType &lower, const InType &upper, size_t N, const OutIterator &out_begin, const UnaryOperator &f)
Definition: l_algorithm.h:467
#define KJB_THROW_2(ex, msg)
Definition: l_exception.h:48
Int_matrix::Value_type min(const Int_matrix &mat)
Return the minimum value in this matrix.
Definition: l_int_matrix.h:1385
void logspace(double min, double max, size_t n, ForwardIterator begin)
Definition: l_algorithm.h:355
Object thrown when an argument to a function is not acceptable.
Definition: l_exception.h:377
get the indices of edges in each direction for i
Definition: APPgetLargeConnectedEdges.m:48
Support for error handling exception classes in libKJB.