Medusa  1.1
Coordinate Free Mehless Method implementation
numutils.hpp
Go to the documentation of this file.
1 #ifndef MEDUSA_BITS_UTILS_NUMUTILS_HPP_
2 #define MEDUSA_BITS_UTILS_NUMUTILS_HPP_
3 
11 #include <medusa/Config.hpp>
15 #include <cmath>
16 
17 namespace mm {
18 
26 template<typename T>
27 int iceil(T x) { return static_cast<int>(std::ceil(x)); }
28 
35 template<typename T>
36 int ifloor(T x) { return static_cast<int>(std::floor(x)); }
37 
39 template <unsigned int exponent>
40 inline double ipow(double base) {
41  return ipow<exponent - 1>(base) * base;
42 }
43 
45 template <>
46 inline double ipow<0>(double) { return 1; }
47 
55 template <typename T>
56 inline T ipow(T b, int e) {
57  T r = 1.0;
58  while (e > 0) {
59  r *= b;
60  --e;
61  }
62  return r;
63 }
64 
71 template <typename T>
72 inline T ipowneg(T b, int e) {
73  if (e < 0) return 1.0 / ipow(b, -e);
74  else return ipow(b, e);
75 }
76 
78 template <typename T>
79 inline constexpr int signum(T x, std::false_type) {
80  return T(0) < x;
81 }
83 template <typename T>
84 inline constexpr int signum(T x, std::true_type) {
85  return (T(0) < x) - (x < T(0));
86 }
93 template <typename T>
94 inline constexpr int signum(T x) {
95  return signum(x, std::is_signed<T>());
96 }
97 
119 template <int dim>
120 bool incrementCounter(Vec<int, dim>& counter, const Vec<int, dim>& limit) {
121  for (int i = dim - 1; i >= 0; --i) {
122  if (counter[i] >= limit[i] - 1) {
123  counter[i] = 0;
124  } else {
125  counter[i]++;
126  return true;
127  }
128  }
129  return false;
130 }
131 
142 template <int dim>
143 bool incrementCounter(Vec<int, dim>& counter, const Vec<int, dim>& low, const Vec<int, dim>& high) {
144  for (int i = dim - 1; i >= 0; --i) {
145  if (counter[i] >= high[i] - 1) {
146  counter[i] = low[i];
147  } else {
148  counter[i]++;
149  return true;
150  }
151  }
152  return false;
153 }
154 
181 template <int dim>
183  const Vec<int, dim>& high, const Vec<int, dim>& size) {
184  for (int i = dim - 1; i >= 0; --i) {
185  if (counter[i] == high[i] - 1 || (high[i] == 0 && counter[i] == size[i] - 1)) {
186  counter[i] = low[i];
187  } else {
188  counter[i]++;
189  if (counter[i] >= size[i]) counter[i] = 0;
190  return true;
191  }
192  }
193  return false;
194 }
195 
209 template <class scalar_t, int dim>
211  const Vec<int, dim>& counts,
212  const Vec<bool, dim> include_boundary = true) {
214  for (int i = 0; i < dim; ++i) {
215  if (include_boundary[i]) assert(counts[i] >= 2);
216  else assert(counts[i] >= 0);
217  if (counts[i] == 0) return ret;
218  }
219  Vec<scalar_t, dim> step;
220  for (int i = 0; i < dim; ++i) {
221  if (include_boundary[i]) step[i] = (end[i] - beg[i]) / (counts[i] - 1);
222  else step[i] = (end[i] - beg[i]) / (counts[i] + 1);
223  }
224  Vec<int, dim> counter = 0;
225  do {
226  Vec<scalar_t, dim> tmp;
227  for (int i = 0; i < dim; ++i) {
228  if (include_boundary[i]) tmp[i] = beg[i] + counter[i] * step[i];
229  else tmp[i] = beg[i] + (counter[i] + 1) * step[i];
230  }
231  ret.push_back(tmp);
232  } while (incrementCounter(counter, counts));
233  return ret;
234 }
235 
237 template <class scalar_t, int dim>
239  const Vec<int, dim>& counts, bool include_boundary) {
240  return linspace(beg, end, counts, Vec<bool, dim>(include_boundary));
241 }
242 
244 template <typename scalar_t>
245 Range<scalar_t> linspace(scalar_t beg, scalar_t end, int count, bool include_boundary = true) {
246  Range<scalar_t> ret;
247  if (include_boundary) {
248  assert_msg(count >= 2, "Count must be >= 2, got %d.", count);
249  scalar_t step = (end - beg) / (count - 1);
250  for (int i = 0; i < count; ++i) {
251  ret.push_back(beg + step * i);
252  }
253  } else {
254  assert_msg(count >= 0, "Count must be >= 0, got %d.", count);
255  scalar_t step = (end - beg) / (count + 1);
256  for (int i = 1; i <= count; ++i) {
257  ret.push_back(beg + step * i);
258  }
259  }
260  return ret;
261 }
262 
278 template<typename function_t, typename input_t, typename output_t, bool verbose = false>
279 input_t bisection(const function_t& f, input_t lo, input_t hi, output_t target = 0.0,
280  input_t tolerance = 1e-4, int max_iter = 40) {
281  input_t a = lo, d = hi - lo;
282  output_t fa = f(lo) - target;
283  output_t fb = f(hi) - target;
284 
285  assert_msg(signum(fa) != signum(fb),
286  "Function values have the same sign, f(a) = %s, f(b) = %s.", fa, fb);
287 
288  while (d > tolerance) {
289  d /= static_cast<input_t>(2.);
290  output_t fc = f(a+d) - target;
291 
292  if (verbose) std::cout << "f(" << a+d << ")=" << fc + target << "\n";
293  if (signum(fa) == signum(fc)) {
294  a += d;
295  fa = fc;
296  }
297  --max_iter;
298  if (max_iter < 0) {
299  std::cerr << "\nBisection ended without finding the solution after max_num"
300  " iterations." << std::endl;
301  break;
302  }
303  }
304  return a+d;
305 }
306 
307 } // namespace mm
308 
309 #endif // MEDUSA_BITS_UTILS_NUMUTILS_HPP_
mm
Root namespace for the whole library.
Definition: Gaussian.hpp:14
scalar_t
Scalar scalar_t
Type of the elements, alias of Scalar.
Definition: MatrixBaseAddons.hpp:16
mm::incrementCyclicCounter
bool incrementCyclicCounter(Vec< int, dim > &counter, const Vec< int, dim > &low, const Vec< int, dim > &high, const Vec< int, dim > &size)
Increments a multi-dimensional counter with given upper and lower limits and global upper size,...
Definition: numutils.hpp:182
mm::Vec
Eigen::Matrix< scalar_t, dim, 1, Eigen::ColMajor|Eigen::AutoAlign, dim, 1 > Vec
Fixed size vector type, representing a mathematical 1d/2d/3d vector.
Definition: Vec_fwd.hpp:31
mm::ipowneg
T ipowneg(T b, int e)
Compute possibly negative integer power b^e.
Definition: numutils.hpp:72
dim
@ dim
Number of elements of this matrix.
Definition: MatrixBaseAddons.hpp:14
mm::ipow
double ipow(double base)
Compile time integer power, returns base raised to power exponent.
Definition: numutils.hpp:40
mm::bisection
input_t bisection(const function_t &f, input_t lo, input_t hi, output_t target=0.0, input_t tolerance=1e-4, int max_iter=40)
Solves f(x) = target using bisection.
Definition: numutils.hpp:279
assert_msg
#define assert_msg(cond,...)
Assert with better error reporting.
Definition: assert.hpp:75
mm::ifloor
int ifloor(T x)
Floors a floating point to an integer.
Definition: numutils.hpp:36
Config.hpp
mm::iceil
int iceil(T x)
Ceils a floating point to an integer.
Definition: numutils.hpp:27
mm::linspace
Range< Vec< scalar_t, dim > > linspace(const Vec< scalar_t, dim > &beg, const Vec< scalar_t, dim > &end, const Vec< int, dim > &counts, const Vec< bool, dim > include_boundary=true)
Multidimensional clone of Matlab's linspace function.
Definition: numutils.hpp:210
assert.hpp
mm::ipow< 0 >
double ipow< 0 >(double)
Compile time integer power (base case 0)
Definition: numutils.hpp:46
mm::incrementCounter
bool incrementCounter(Vec< int, dim > &counter, const Vec< int, dim > &limit)
Increments a multi-dimensional counter with given limits.
Definition: numutils.hpp:120
Vec.hpp
mm::signum
constexpr int signum(T x, std::false_type)
Signum overload for unsigned types.
Definition: numutils.hpp:79
mm::Range
An extension of std::vector<T> to support additional useful operations.
Definition: Range_fwd.hpp:30
Range.hpp