CASM
AClustersApproachtoStatisticalMechanics
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules
CASM_math.hh
Go to the documentation of this file.
1 #ifndef CASM_MATH_HH
2 #define CASM_MATH_HH
5 //Maybe we should transition to boost math library?
6 //#include <boost/math/special_functions/binomial.hpp>
7 #include <boost/math/special_functions/factorials.hpp>
8 #include <iostream>
9 #include <cmath>
10 #include <cstddef>
11 #include <complex>
12 #include <string>
13 #include <sstream>
14 
15 namespace CASM {
16 
17  // *******************************************************************************************
18 
19  //round function -- rounds to nearest whole number; half-integers are rounded away from zero
20  int round(double val);
21 
22  // *******************************************************************************************
23 
24  template <typename T>
25  T min(const T &A, const T &B) {
26  return A < B ? A : B;
27  }
28 
29  // *******************************************************************************************
30 
31  template <typename T>
32  T max(const T &A, const T &B) {
33  return A > B ? A : B;
34  }
35 
36  // *******************************************************************************************
37 
39  template <typename T, typename std::enable_if<std::is_floating_point<T>::value, T>::type * = nullptr>
40  inline
41  bool almost_zero(const T &val, double tol = TOL) {
42  return std::abs(val) < tol;
43  }
44 
46  template <typename T, typename std::enable_if<std::is_floating_point<T>::value, T>::type * = nullptr>
47  inline
48  bool almost_zero(const std::complex<T> &val, double tol = TOL) {
49  return std::abs(val) < tol;
50  }
51 
53  template <typename T, typename std::enable_if<std::is_integral<T>::value, T>::type * = nullptr>
54  inline
55  bool almost_zero(const T &val, double tol = TOL) {
56  return val == 0;
57  }
58 
60  template <typename Derived>
61  bool almost_zero(const Eigen::MatrixBase<Derived> &val, double tol = TOL) {
62  return val.isZero(tol);
63  }
64 
65  // *******************************************************************************************
66 
68  template < typename T, typename std::enable_if < !std::is_integral<T>::value, T >::type * = nullptr >
69  bool almost_equal(const T &val1, const T &val2, double tol = TOL) {
70  return almost_zero(val1 - val2, tol);
71  }
72 
74  template <typename T, typename std::enable_if<std::is_integral<T>::value, T>::type * = nullptr>
75  bool almost_equal(const T &val1, const T &val2, double tol = TOL) {
76  return val1 == val2;
77  }
78 
79  // *******************************************************************************************
80 
88  template <typename T, typename std::enable_if<std::is_floating_point<T>::value, T>::type * = nullptr>
89  bool compare(const T &A, const T &B, double tol) {
90  if(!almost_equal(A, B, tol)) {
91  return A < B;
92  }
93  return false;
94  }
95 
96  struct FloatCompare {
97 
98  double tol;
99 
100  FloatCompare(double _tol) : tol(_tol) {}
101 
102  template<typename T>
103  bool operator()(const T &A, const T &B) const {
104  return compare(A, B, tol);
105  }
106  };
107 
108 
110  template<class InputIt1, class InputIt2>
111  bool float_lexicographical_compare(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, double tol) {
112  FloatCompare compare(tol);
113  return std::lexicographical_compare(first1, last1, first2, last2, compare);
114  }
115 
117  inline bool float_lexicographical_compare(const Eigen::VectorXd &A, const Eigen::VectorXd &B, double tol) {
118  return float_lexicographical_compare(A.data(), A.data() + A.size(), B.data(), B.data() + B.size(), tol);
119  }
120 
121  // *******************************************************************************************
122  //Return sign of number
123 
124  template <typename T, typename std::enable_if<std::is_integral<T>::value, T>::type * = nullptr>
125  int sgn(T val) {
126  return (T(0) < val) - (val < T(0));
127  }
128 
129  template <typename T, typename std::enable_if<std::is_floating_point<T>::value, T>::type * = nullptr>
130  int float_sgn(T val, double compare_tol = TOL) {
131  T zeroval(0);
132  if(compare(zeroval, val, compare_tol)) {
133  return 1;
134  }
135 
136  else if(compare(val, zeroval, compare_tol)) {
137  return -1;
138  }
139 
140  else {
141  return 0;
142  }
143  }
144  // *******************************************************************************************
145 
146  // Works for signed and unsigned types
147  template <typename IntType>
148  IntType nchoosek(IntType n, IntType k) {
149  assert(k <= n && 0 <= k);
150  if(n < 2 * k)
151  k = n - k;
152 
153  n -= k;
154 
155  IntType result(1);
156  for(IntType i = 1; i < k + 1; i++) {
157  result *= n + i;
158  result /= i;
159  }
160 
161  return result;
162  }
163 
164 
165  // *******************************************************************************************
168  int dl_string_dist(const std::string &a, const std::string &b);
169 
170  // *******************************************************************************************
171 
172  double ran0(int &idum);
173 
174  // *******************************************************************************************
175 
176  using boost::math::factorial;
177 
178  // *******************************************************************************************
180  int gcf(int i1, int i2);
181 
182  // *******************************************************************************************
184  int lcm(int i1, int i2);
185 
186  // *******************************************************************************************
187 
188  // evaluates Gaussians using the formula:
189  // f(x) = a*e^(-(x-b)^2/(c^2))
190  double gaussian(double a, double x, double b, double c);
191 
192  // calculates Gaussian moments given by the integral:
193  // m = \int_{\infty}^{\infty} dx x^pow*exp[-x^2/(2*sigma^2)]/(\sqrt(2*\pi)*sigma)
194  double gaussian_moment(int expon, double sigma);
195 
196  // calculates Gaussian moments given by the integral:
197  // m = \int_{\infty}^{\infty} dx x^pow*exp[-(x-x0)^2/(2*sigma^2)]/(\sqrt(2*\pi)*sigma)
198  double gaussian_moment(int expon, double sigma, double x0);
199 
200 
201  Eigen::VectorXd eigen_vector_from_string(const std::string &tstr, const int &size);
202 
203  // *******************************************************************************************
213  template<typename IntType>
214  IntType extended_gcf(IntType i1, IntType i2, IntType &p1, IntType &p2) {
215  IntType s1 = sgn(i1);
216  IntType s2 = sgn(i2);
217 
218  IntType a = i1, b = i2;
219  p1 = 1;
220  p2 = 0;
221  IntType tp1(0), tp2(1), quotient;
222 
223  i1 = std::abs(i1);
224  i2 = std::abs(i2);
225 
226  while(i2 != 0) {
227 
228  quotient = i1 / i2;
229  i1 = i1 % i2;
230  swap(i1, i2);
231  p1 = p1 - quotient * tp1;
232  swap(p1, tp1);
233  p2 = p2 - quotient * tp2;
234  swap(p2, tp2);
235  }
236 
237  p1 *= s1;
238  p2 *= s2;
239  return p1 * a + p2 * b;
240  }
241 
242  // *******************************************************************************************
244  int lcm(int i1, int i2);
245 
246 
247  // *******************************************************************************************
248  // finds rational number that approximates 'val' to within 'tol' --
249  // -- almost_int(double(denominator)*val, tol) == true OR almost_int(val/double(numerator), tol) == true OR
250  // -- denominator is always positive
251  // -- sign(numerator)=sign(val)
252  // -- if(almost_zero(val,tol)) --> numerator = 0, denominator = 1
253  // *******************************************************************************************
254 
255  void nearest_rational_number(double val, long &numerator, long &denominator, double tol = TOL);
256 
257  // *******************************************************************************************
258  /*
259  * Finds best irrational number approximation of double 'val' and
260  * returns tex-formated string that contains irrational approximation
261  * Searches numbers of the form (x/y)^(1/z), where x and y range from 1 to 'lim'
262  * z ranges from 1 to 'max_pow'
263  */
264  // *******************************************************************************************
265 
266  std::string irrational_to_tex_string(double val, int lim, int max_pow = 2);
267 
268  // *******************************************************************************************
269  //John G 010413
270  int mod(int a, int b);
271 
272  // *******************************************************************************************
273 
274  double cuberoot(double number);
275 
276  // *******************************************************************************************
277 
278  void poly_fit(Eigen::VectorXcd &xvec, Eigen::VectorXcd &yvec, Eigen::VectorXcd &coeffs, int degree); //Ivy
279 
280  // //////////////////////////////////////////
281  // //////////////////////////////////////////
282  // Array Function declarations:
283 
284  // *******************************************************************************************
285 
286  // returns 'i' if 'input' is equivalent to 'unique[i]', w.r.t. permutation of the equivalent elements of 'input'.
287  // equivalent elements are specified by 'ind_equiv'
288  // if 'input' specifies a new combination of integers, unique.size() is returned
289  Index which_unique_combination(const Array<Index> &input, const Array<Index>::X2 &unique, const Array<Index>::X2 &ind_equiv);
290 
291  // *******************************************************************************************
292 
293  Index which_unique_combination(const Array<Index> &input, const Array<Index>::X2 &unique);
294 
295  // *******************************************************************************************
297  int lcm(const Array<int> &series);
298 
299  // *******************************************************************************************
300 
301  ReturnArray< Array<int> > get_prime_factors(int target);
302 
303  // *******************************************************************************************
304 
305  template <typename IntType>
306  IntType multinomial_coeff(const Array<IntType> &exponents) {
307  IntType tcoeff(1), tsum(0);
308  for(Index i = 0; i < exponents.size(); i++) {
309  tsum += exponents[i];
310  tcoeff *= nchoosek(tsum, exponents[i]);
311  }
312  return tcoeff;
313  }
314 
315  // *******************************************************************************************
316  // get multinomial coefficient for only a subset of the coeffs
317  template <typename IntType>
318  IntType multinomial_coeff(const Array<IntType> &exponents, const Array<Index> &sublist) {
319  IntType tcoeff(1), tsum(0);
320  for(Index i = 0; i < sublist.size(); i++) {
321  tsum += exponents[sublist[i]];
322  tcoeff *= nchoosek(tsum, exponents[sublist[i]]);
323  }
324  return tcoeff;
325  }
326  // ************************************************************
327  template <typename T>
328  bool almost_equal(const Array<T> &A, const Array<T> &B, double tol = TOL) {
329  if(A.size() != B.size())
330  return false;
331  for(Index i = 0; i < A.size(); i++) {
332  if(!almost_equal(A[i], B[i], tol))
333  return false;
334  }
335  return true;
336  }
337 
338  // ************************************************************
339  // cumulative sum, first element is 0 and final elment is array.sum()
340  template <typename T>
342  Array<T> result;
343  result.reserve(arr.size() + 1);
344  result.push_back(0);
345  for(Index i = 0; i < arr.size(); i++) {
346  result.push_back(result[i] + arr[i]);
347  }
348  return result;
349  }
350 
351  // ************************************************************
352 
353  template<typename Derived>
354  double length(const Eigen::MatrixBase<Derived> &value) {
355  return value.norm();
356  }
357 
358  // ************************************************************
359 
360  template<typename Derived>
361  ReturnArray<Index> partition_distinct_values(const Eigen::MatrixBase<Derived> &value, double tol = TOL) {
362  Array<Index> subspace_dims;
363  Index last_i = 0;
364  for(Index i = 1; i < value.size(); i++) {
365  if(!almost_equal(value[last_i], value[i], tol)) {
366  subspace_dims.push_back(i - last_i);
367  last_i = i;
368  }
369  }
370  subspace_dims.push_back(value.size() - last_i);
371  return subspace_dims;
372  }
373 
374  // Finds optimal assignments, based on cost_matrix, and returns total optimal cost
375  double hungarian_method(const Eigen::MatrixXd &cost_matrix, std::vector<Index> &optimal_assignments, const double _tol);
376 
377  namespace HungarianMethod_impl {
378  // *******************************************************************************************
379  /* Hungarian Algorithm Routines
380  * Step 1: reduce the rows by smallest element
381  * Step 2: star zeros
382  * Step 3: cover columns with starred zeros and check assignement
383  * if K columns covered DONE. Else goto 4.
384  * Step 4: Find uncovered zero and prime. if no starred zero in row
385  * goto 5. Otherwise, cover row, uncover column with star zero.
386  * Continue until all zeros are covered. Store smalles
387  * uncovered value goto 6.
388  * Step 5: Build alternating prime and star zeros. Goto 3.
389  * Step 6: Add value from 4 to all covered rows, and subtract it
390  * from uncovered columns. DO NOT alter stars, primes or covers.
391  * Return to 3.
392  *
393  */
394  // *******************************************************************************************
395  void hungarian_method(const Eigen::MatrixXd &cost_matrix_arg, std::vector<Index> &optimal_assignments, const double _tol);
396 
397  //void reduce_cost(Eigen::MatrixXd &cost_matrix, double _infinity);
398 
399  //void find_zeros(const Eigen::MatrixXd &cost_matrix, Eigen::MatrixXi &zero_marks, double _tol);
400 
401  //bool check_assignment(const Eigen::MatrixXi &zero_marks, Eigen::VectorXi &col_covered);
402 
403  //int prime_zeros(const Eigen::MatrixXd &cost_matrix, Eigen::VectorXi &row_covered, Eigen::VectorXi &col_covered, Eigen::MatrixXi &zero_marks, double &min, Eigen::VectorXi &first_prime_zero);
404 
405  //int alternating_path(const Eigen::MatrixXd &cost_matrix, const Eigen::VectorXi &first_prime_zero, Eigen::MatrixXi &zero_marks, Eigen::VectorXi &row_covered, Eigen::VectorXi &col_covered);
406 
407  //int update_costs(const Eigen::VectorXi &row_covered, const Eigen::VectorXi &col_covered, const double min, Eigen::MatrixXd &cost_matrix);
408  }
409 
410  //*******************************************************************************************
412  template <typename Derived>
413  Eigen::Matrix<int,
414  Derived::RowsAtCompileTime,
415  Derived::ColsAtCompileTime>
416  scale_to_int(const Eigen::MatrixBase<Derived> &val, double _tol = TOL) {
417 
418  typedef Eigen::Matrix<int, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime> int_mat_type;
419  typedef Eigen::Matrix<double, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime> dub_mat_type;
420 
421  int_mat_type ints(int_mat_type::Zero(val.rows(), val.cols()));
422 
423  dub_mat_type dubs(val);
424 
425  Index min_i(-1);
426  double min_coeff = 2; //all values are <=1;
427  for(Index i = 0; i < dubs.rows(); i++) {
428  for(Index j = 0; j < dubs.cols(); j++) {
429  if(almost_zero(dubs(i, j))) {
430  dubs(i, j) = 0.0;
431  }
432  else if(std::abs(dubs(i, j)) < std::abs(min_coeff)) {
433  min_coeff = dubs(i, j);
434  min_i = i;
435  }
436  }
437  }
438  if(valid_index(min_i))
439  dubs /= std::abs(min_coeff);
440  else
441  return ints;
442 
443 
444  //We want to multiply the miller indeces by some factor such that all indeces become integers.
445  //In order to do this we pick a tolerance to work with and round the miller indeces if they are close
446  //enough to the integer value (e.g. 2.95 becomes 3). Choosing a tolerance that is too small will
447  //result in the "primitive-slab" blowing up.
448 
449  //Begin choosing a factor and multiply all indeces by it (starting with 1). Then round the non-smallest
450  //miller indeces (smallest index requires no rounding, since it will always be a perfect
451  //integer thanks to the previous division).
452  //Next take absolute value of difference between rounded indeces and actual values (int_diff 1 & 2).
453  //If the difference for both indeces is smaller than the tolerance then you've reached the desired
454  //accuracy and the rounded indeces can be used to construct the "primitive-slab" cell. If not, increase the
455  //factor by 1 and try again, until the tolerance is met.
456  bool within_tol = false;
457 
458  dub_mat_type tdubs;
459  for(Index factor = 1; factor < 1000 && !within_tol; factor++) {
460  Index i, j;
461  tdubs = double(factor) * dubs;
462  for(i = 0; i < dubs.rows(); i++) {
463  for(j = 0; j < dubs.cols(); j++) {
464  if(!almost_zero(round(tdubs(i, j)) - tdubs(i, j), _tol))
465  break;
466  }
467  if(j < dubs.cols())
468  break;
469  }
470  if(dubs.rows() <= i)
471  within_tol = true;
472  }
473 
474  if(within_tol) {
475  for(Index i = 0; i < dubs.rows(); i++) {
476  for(Index j = 0; j < dubs.cols(); j++) {
477  ints(i, j) = round(tdubs(i, j));
478  }
479  }
480  }
481 
482  return ints;
483  }
484 
485 
486 }
487 
488 namespace Eigen {
489  template <typename Derived1, typename Derived2>
490  inline
491  bool almost_equal(const Eigen::MatrixBase<Derived1> &val1, const Eigen::MatrixBase<Derived2> &val2, double tol = CASM::TOL) {
492  return CASM::almost_zero(val1 - val2, tol);
493  }
494 
502  template <typename Derived>
503  inline
504  bool is_symmetric(const Eigen::MatrixBase<Derived> &test_mat, double test_tol = CASM::TOL) {
505  return CASM::almost_zero(test_mat - test_mat.transpose(), test_tol);
506  }
507 
515  template <typename Derived>
516  inline
517  bool is_persymmetric(const Eigen::MatrixBase<Derived> &test_mat, double test_tol = CASM::TOL) {
518  //Reverse order of columns and rows
519  auto rev_mat = test_mat.colwise().reverse().eval().rowwise().reverse().eval();
520  return CASM::almost_zero(test_mat - rev_mat.transpose(), test_tol);
521  }
522 
530  template <typename Derived>
531  inline
532  bool is_bisymmetric(const Eigen::MatrixBase<Derived> &test_mat, double test_tol = CASM::TOL) {
533  return (is_symmetric(test_mat, test_tol) && is_persymmetric(test_mat, test_tol));
534  }
535 }
536 
537 #endif
Eigen::MatrixXd MatrixXd
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
Definition: CASM_math.hh:41
ReturnArray< T > cum_sum(const Array< T > &arr)
Definition: CASM_math.hh:341
IntType multinomial_coeff(const Array< IntType > &exponents)
Definition: CASM_math.hh:306
Index size() const
Definition: Array.hh:145
Index which_unique_combination(const Array< Index > &input, const Array< Index >::X2 &unique, const Array< Index >::X2 &ind_equiv)
Eigen::VectorXd eigen_vector_from_string(const std::string &tstr, const int &size)
Definition: CASM_math.cc:119
int gcf(int i1, int i2)
Find greatest common factor.
Definition: CASM_math.cc:92
bool compare(const T &A, const T &B, double tol)
Floating point comparison with tol, return A < B.
Definition: CASM_math.hh:89
void push_back(const T &toPush)
Definition: Array.hh:513
bool float_lexicographical_compare(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, double tol)
Floating point lexicographical comparison with tol.
Definition: CASM_math.hh:111
int lcm(int i1, int i2)
Find least common multiple.
Definition: CASM_math.cc:114
IntType extended_gcf(IntType i1, IntType i2, IntType &p1, IntType &p2)
Calculate greatest common factor of two integers, and bezout coefficients.
Definition: CASM_math.hh:214
double hungarian_method(const Eigen::MatrixXd &cost_matrix, std::vector< Index > &optimal_assignments, const double _tol)
Definition: CASM_math.cc:444
bool is_bisymmetric(const Eigen::MatrixBase< Derived > &test_mat, double test_tol=CASM::TOL)
Definition: CASM_math.hh:532
Main CASM namespace.
Definition: complete.cpp:8
void poly_fit(Eigen::VectorXcd &xvec, Eigen::VectorXcd &yvec, Eigen::VectorXcd &coeffs, int degree)
Definition: CASM_math.cc:308
double gaussian(double a, double x, double b, double c)
Definition: CASM_math.cc:144
const double TOL
double cuberoot(double number)
Definition: CASM_math.cc:292
int dl_string_dist(const std::string &a, const std::string &b)
Computes the Damerescau-Levenshtein distance – the number of edits (deletions, insertions, transpositions) to go from string 'a' to string 'b'.
Definition: CASM_math.cc:42
double ran0(int &idum)
Definition: CASM_math.cc:12
void hungarian_method(const Eigen::MatrixXd &cost_matrix_arg, std::vector< Index > &optimal_assignments, const double _tol)
Definition: CASM_math.cc:734
ReturnArray< Array< int > > get_prime_factors(int target)
Definition: CASM_math.cc:413
void swap(ConfigDoF &A, ConfigDoF &B)
Definition: ConfigDoF.cc:195
double tol
Array< X1 > X2
Definition: Array.hh:64
double gaussian_moment(int expon, double sigma)
Definition: CASM_math.cc:153
EigenIndex Index
For long integer indexing:
int float_sgn(T val, double compare_tol=TOL)
Definition: CASM_math.hh:130
IntType nchoosek(IntType n, IntType k)
Definition: CASM_math.hh:148
int mod(int a, int b)
Definition: CASM_math.cc:280
Eigen::Matrix< int, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime > scale_to_int(const Eigen::MatrixBase< Derived > &val, double _tol=TOL)
Take a vector of doubles, and multiply by some factor that turns it into a vector of integers (within...
Definition: CASM_math.hh:416
Eigen::VectorXd VectorXd
bool is_persymmetric(const Eigen::MatrixBase< Derived > &test_mat, double test_tol=CASM::TOL)
Definition: CASM_math.hh:517
std::string irrational_to_tex_string(double val, int lim, int max_pow=2)
Definition: CASM_math.cc:224
T max(const T &A, const T &B)
Definition: CASM_math.hh:32
T min(const T &A, const T &B)
Definition: CASM_math.hh:25
bool is_symmetric(const Eigen::MatrixBase< Derived > &test_mat, double test_tol=CASM::TOL)
Definition: CASM_math.hh:504
void nearest_rational_number(double val, long &numerator, long &denominator, double tol=TOL)
Definition: CASM_math.cc:188
ReturnArray< Index > partition_distinct_values(const Eigen::MatrixBase< Derived > &value, double tol=TOL)
Definition: CASM_math.hh:361
void reserve(Index new_max)
Definition: Array.hh:491
bool almost_equal(const Eigen::MatrixBase< Derived1 > &val1, const Eigen::MatrixBase< Derived2 > &val2, double tol=CASM::TOL)
Definition: CASM_math.hh:491
int sgn(T val)
Definition: CASM_math.hh:125
FloatCompare(double _tol)
Definition: CASM_math.hh:100
Basic std::vector like container (deprecated)
bool almost_equal(const GenericCluster< CoordType > &LHS, const GenericCluster< CoordType > &RHS, double tol)
bool operator()(const T &A, const T &B) const
Definition: CASM_math.hh:103
int round(double val)
Definition: CASM_math.cc:6
bool valid_index(Index i)
double length(const Eigen::MatrixBase< Derived > &value)
Definition: CASM_math.hh:354