CASM
AClustersApproachtoStatisticalMechanics
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules
CASM_math.cc
Go to the documentation of this file.
1 #include "casm/misc/CASM_math.hh"
2 
3 namespace CASM {
4  //*******************************************************************************************
5 
6  int round(double val) {
7  return int(val < 0 ? floor(val + 0.5) : ceil(val - 0.5));
8  };
9 
10  //*******************************************************************************************
11 
12  double ran0(int &idum) {
13  int IA = 16807;
14  int IM = 2147483647;
15  int IQ = 127773;
16  int IR = 2836;
17  int MASK = 123459876;
18  double AM = 1.0 / IM;
19 
20  //minimal random number generator of Park and Miller
21  //returns uniform random deviate between 0.0 and 1.0
22  //set or rest idum to any integer value (except the
23  //unlikely value MASK) to initialize the sequence: idum must
24  //not be altered between calls for successive deviates
25  //in a sequence
26 
27  int k;
28  idum = idum ^ MASK; //XOR the two integers
29  k = idum / IQ;
30  idum = IA * (idum - k * IQ) - IR * k;
31  if(idum < 0) {
32  idum = idum + IM;
33  }
34  double ran = AM * idum;
35  idum = idum ^ MASK;
36  return ran;
37 
38  }
39 
40  //*******************************************************************************************
41 
42  int dl_string_dist(const std::string &a, const std::string &b) {
43  // "infinite" distance is just the max possible distance
44  int max_val = a.size() + b.size();
45 
46  // make and initialize the character array indices
47  std::map<char, int> DA;
48 
49  // make the distance matrix H
50  Eigen::MatrixXi H(a.size() + 2, b.size() + 2);
51 
52  // initialize the left and top edges of H
53  H(0, 0) = max_val;
54  for(int i = 0; i <= a.size(); ++i) {
55  DA[a[i]] = 0;
56  H(i + 1, 0) = max_val;
57  H(i + 1, 1) = i;
58  }
59  for(int j = 0; j <= b.size(); ++j) {
60  DA[b[j]] = 0;
61  H(0, j + 1) = max_val;
62  H(1, j + 1) = j;
63  }
64 
65  // fill in the distance matrix H
66  // look at each character in a
67  for(int i = 1; i <= a.size(); ++i) {
68  int DB = 0;
69  // look at each character in b
70  for(int j = 1; j <= b.size(); ++j) {
71  int i1 = DA[b[j - 1]];
72  int j1 = DB;
73  int cost;
74  if(a[i - 1] == b[j - 1]) {
75  cost = 0;
76  DB = j;
77  }
78  else
79  cost = 1;
80  H(i + 1, j + 1) = min(min(H(i, j) + cost, // substitution
81  H(i + 1, j) + 1), // insertion
82  min(H(i, j + 1) + 1, // deletion
83  H(i1, j1) + (i - i1 - 1) + 1 + (j - j1 - 1)));
84  }
85  DA[a[i - 1]] = i;
86  }
87  return H(a.size() + 1, b.size() + 1);
88  }
89 
90  //*******************************************************************************************
92  int gcf(int i1, int i2) {
93  i1 = std::abs(i1);
94  i2 = std::abs(i2);
95  while(i1 != i2 && i1 != 1 && i2 != 1) {
96  if(i1 < i2) {
97  i2 -= i1;
98  }
99  else {
100  i1 -= i2;
101  }
102  }
103  if(i1 == 1) {
104  return i1;
105  }
106  else {
107  return i2;
108  }
109 
110  }
111 
112  //*******************************************************************************************
114  int lcm(int i1, int i2) {
115  return std::abs(i1 * (i2 / gcf(i1, i2)));
116  }
117 
118  //Given a string and the size expected in the array. Converts it to an Eigen::VectorXd
119  Eigen::VectorXd eigen_vector_from_string(const std::string &tstr, const int &size) {
120  std::stringstream tstream;
121  tstream << tstr;
122  Eigen::VectorXd tvec(size);
123  int i = 0;
124  while(!tstream.eof()) {
125  if(i == (size)) {
126  std::cerr << "WARNING in eigen_vector_from_string. You have more elements in your array, than the value of size you passed. Ignoring any extraneous elements" << std::endl;
127  break;
128  }
129  tstream >> tvec(i);
130  i++;
131  }
132  if(i < (size - 1)) {
133  std::cerr << "ERROR in eigen_vector_from_string. Fewer elements in your array than the value of size you passed. Can't handle this. Quitting." << std::endl;
134  exit(666);
135  }
136  return tvec;
137  }
138 
139  //*******************************************************************************************
140  // This evaluates Gaussians using the formula:
141  // f(x) = a*e^(-(x-b)^2/(c^2))
142  //*******************************************************************************************
143 
144  double gaussian(double a, double x, double b, double c) {
145  return a * exp(-((x - b) * (x - b)) / (c * c));
146  }
147 
148  //*******************************************************************************************
149  // This calculates Gaussian moments given by the integral:
150  // m = \int_{\infty}^{\infty} dx x^pow*exp[-x^2/(2*sigma^2)]/(\sqrt(2*\pi)*sigma)
151  //*******************************************************************************************
152 
153  double gaussian_moment(int expon, double sigma) {
154 
155  if(expon % 2) return 0.0;
156 
157  double m = pow(sigma, expon);
158 
159  expon -= 1;
160  while(expon - 2 > 0) {
161  m *= double(expon);
162  expon -= 2;
163  }
164  return m;
165  }
166 
167  //*******************************************************************************************
168  // This calculates Gaussian moments given by the integral:
169  // m = \int_{\infty}^{\infty} dx x^pow*exp[-(x-x0)^2/(2*sigma^2)]/(\sqrt(2*\pi)*sigma)
170  //*******************************************************************************************
171 
172  double gaussian_moment(int expon, double sigma, double x0) {
173  double m = 0;
174  for(int i = 0; i <= expon; i++) {
175  m += nchoosek(expon, i) * gaussian_moment(i, sigma) * pow(x0, expon - i);
176  }
177 
178  return m;
179  }
180 
181 
182  //*******************************************************************************************
183  // finds rational number that approximates 'val' to within 'tol' --
184  // -- almost_int(double(denominator)*val, tol) == true OR almost_int(val/double(numerator), tol) == true OR
185  // -- denominator is always positive
186  // -- sign(numerator)=sign(val)
187  // -- if(almost_zero(val,tol)) --> numerator = 0, denominator = 1
188  void nearest_rational_number(double val, long &numerator, long &denominator, double tol) {
189  if(almost_zero(val, tol)) {
190  numerator = 0;
191  denominator = 1;
192  return;
193  }
194  long sgn(val < 0 ? -1 : 1);
195  val = std::abs(val);
196  double tdenom, tnum;
197  long lim(max(long(100), long(1 / (10 * tol))));
198  for(long i = 1; i < lim + 1; i++) {
199  tdenom = double(i) / val;
200  tnum = val / double(i);
201  if(tdenom > 1 && almost_zero(tdenom - round(tdenom), tol)) {
202  numerator = sgn * i;
203  denominator = round(tdenom);
204  return;
205  }
206  else if(tnum > 1 && almost_zero(tnum - round(tnum), tol)) {
207  denominator = i;
208  numerator = sgn * round(tnum);
209  return;
210  }
211  }
212 
213 
214  }
215 
216  //*******************************************************************************************
217  /* Finds best irrational number approximation of double 'val' and
218  * returns tex-formated string that contains irrational approximation
219  * searches numbers of the form (x/y)^(1/z), where x and y range from 1 to 'lim'
220  * z ranges from 1 to 'max_pow'
221  */
222  //*******************************************************************************************
223 
224  std::string irrational_to_tex_string(double val, int lim, int max_pow) {
225  std::stringstream tstr;
226  if(almost_zero(round(val) - val)) {
227  tstr << round(val);
228  return tstr.str();
229  }
230  if(val < 0) {
231  tstr << '-';
232  val = std::abs(val);
233  }
234  double tval(val), tdenom, tnum;
235  int idenom, inum;
236  for(int ipow = 1; ipow < max_pow + 1; ipow++) {
237  for(int i = 1; i < lim + 1; i++) {
238  tdenom = double(i) / tval;
239  tnum = tval / double(i);
240  if(tdenom > 1 && almost_zero(std::abs(tdenom - round(tdenom)))) {
241  inum = i;
242  idenom = round(tdenom);
243  }
244  else if(tnum > 1 && almost_zero(std::abs(tnum - round(tnum)))) {
245  idenom = i;
246  inum = round(tnum);
247  }
248  else {
249  continue;
250  }
251 
252  if(ipow == 1) {
253  tstr << inum << '/' << idenom;
254  return tstr.str();
255  }
256  if(ipow == 2) {
257  tstr << "\\sqrt{" << inum;
258  if(idenom != 1)
259  tstr << '/' << idenom;
260  tstr << '}';
261  return tstr.str();
262  }
263  else {
264  tstr << '(' << inum;
265  if(idenom != 1)
266  tstr << '/' << idenom;
267  tstr << ")^{1/" << ipow << "}";
268  return tstr.str();
269  }
270  }
271  tval *= val;
272  }
273  tstr << val;
274  return tstr.str();
275  }
276 
277 
278  //*******************************************************************************************
279  //John G 010413
280  int mod(int a, int b) {
281  if(b < 0)
282  return mod(-a, -b);
283 
284  int ret = a % b;
285  if(ret < 0)
286  ret += b;
287  return ret;
288  }
289 
290  //*******************************************************************************************
291 
292  double cuberoot(double number) {
293  if(number < 0) {
294  return -pow(-number, 1.0 / 3);
295  }
296 
297  else {
298  return pow(number, 1.0 / 3);
299  }
300  }
301 
302  //*******************************************************************************************
306  //*******************************************************************************************
307 
308  void poly_fit(Eigen::VectorXcd &xvec, Eigen::VectorXcd &yvec, Eigen::VectorXcd &coeffs, int degree) {
309 
310  // Check that the dimensions are correct
311  if(xvec.rows() != yvec.rows()) {
312  std::cout << "******************************************\n"
313  << "ERROR in poly_fit: Dimensions of xvec and \n"
314  << "yvec do not match up! Cannot perform a \n"
315  << "polynomial fit.\n"
316  << "******************************************\n";
317  exit(1);
318  }
319 
320  Eigen::MatrixXcd polymat = Eigen::MatrixXcd::Ones(xvec.rows(), degree + 1);
321 
322  // Construct polymatrix
323  for(int d = degree; d > 0; d--) {
324 
325  polymat.col(degree - d) = xvec;
326 
327  for(int m = 0; m < d - 1; m++) {
328  polymat.col(degree - d) = polymat.col(degree - d).cwiseProduct(xvec);
329  }
330  }
331 
332  // SVD least squares fit
333  Eigen::JacobiSVD<Eigen::MatrixXcd> svd_solver(polymat, Eigen::ComputeThinU | Eigen::ComputeThinV);
334  coeffs = svd_solver.solve(yvec);
335 
336  return;
337 
338  }
339 
340 
341  //************************************************************
342 
343  // returns 'i' if 'input' is equivalent to 'unique[i]', w.r.t. permutation of the equivalent elements of 'input'.
344  // equivalent elements are specified by 'ind_equiv'
345  // if 'input' specifies a new combination of integers, unique.size() is returned
346  Index which_unique_combination(const Array<Index> &input, const Array<Array<Index> > &unique, const Array<Array<Index> > &ind_equiv) {
347  Index tval, tcount;
348  Index i, j, k, l;
349  for(i = 0; i < unique.size(); i++) {
350  //Is input equivalent to unique[i] w.r.t. ind_equiv?
351  //Loop over groups of equivalent indices
352  if(unique[i].size() != input.size()) continue;
353  for(j = 0; j < ind_equiv.size(); j++) {
354 
355  //Loop over indices that are equivalent
356  for(k = 0; k < ind_equiv[j].size(); k++) {
357  tval = input[ind_equiv[j][k]];
358  tcount = 0;
359  for(l = 0; l < ind_equiv[j].size(); l++)
360  tcount += int(unique[i][ind_equiv[j][l]] == tval) - int(input[ind_equiv[j][l]] == tval);
361 
362  if(tcount != 0)
363  break;
364  }
365  if(k != ind_equiv[j].size())
366  break;
367  }
368  if(j == ind_equiv.size())
369  return i;
370  }
371  return i;
372  }
373 
374  //****************************************
375 
377  Index tval, tcount;
378  Index i, j, l;
379  for(i = 0; i < unique.size(); i++) {
380  //Is input equivalent to unique[i] w.r.t. ind_equiv?
381  //Loop over groups of equivalent indices
382  if(unique[i].size() != input.size()) continue;
383  for(j = 0; j < input.size(); j++) {
384  tval = input[j];
385  tcount = 0;
386  for(l = 0; l < input.size(); l++)
387  tcount += int(unique[i][l] == tval) - int(input[l] == tval);
388 
389  if(tcount != 0)
390  break;
391  }
392 
393  if(j == input.size())
394  return i;
395  }
396  return i;
397 
398  }
399 
400  //************************************************************
402  int lcm(const Array<int> &series) {
403  if(!series.size()) return 0;
404  int lcm_val(series[0]);
405  for(Index i = 1; i < series.size(); i++)
406  lcm_val = lcm(lcm_val, series[i]);
407 
408  return lcm_val;
409  }
410 
411  //************************************************************
412 
414  Array<Array<int> > factors_array;
415  Array<int> factor_list;
416 
417  if(target <= 1) {
418  std::cerr << "WARNING in CASM_Global_Definitions::get_prime_factors" << std::endl;
419  std::cerr << "You're asking for prime factors of " << target << ". Returning empty array." << std::endl << std::endl;
420  return factors_array;
421  }
422  int factor = 2;
423 
424  while(target != 1) {
425  while(target % factor == 0) {
426  factor_list.push_back(factor);
427  target = target / factor;
428  }
429 
430  factor++;
431 
432  if(factor_list.size() > 0) {
433  factors_array.push_back(factor_list);
434  }
435  factor_list.clear();
436  }
437 
438  return factors_array;
439  }
440 
441 
442  //*******************************************************************************************
443 
444  double hungarian_method(const Eigen::MatrixXd &cost_matrix, std::vector<Index> &optimal_assignment, const double _tol) {
445  // Run hungarian algorithm on original cost_matrix
446  HungarianMethod_impl::hungarian_method(cost_matrix, optimal_assignment, _tol);
447 
448  double tot_cost = 0.0;
449  // Find the costs associated with the correct assignments
450  for(int i = 0; i < optimal_assignment.size(); i++) {
451  tot_cost += cost_matrix(i, optimal_assignment[i]);
452  }
453  if(optimal_assignment.size() == 0)
454  tot_cost = 1e20;
455  return tot_cost;
456  }
457 
458  namespace HungarianMethod_impl {
459  //*******************************************************************************************
467  //*******************************************************************************************
468 
469  void reduce_cost(Eigen::MatrixXd &cost_matrix, double _infinity) {
470 
471  // cost matrix dimension
472  int dim = cost_matrix.rows();
473 
474  // Step 1. For every row subtract the minimum element from every
475  // entry in that row.
476  for(int i = 0; i < dim; i++) {
477  double row_min = cost_matrix.row(i).minCoeff();
478  if(row_min > _infinity)
479  continue;
480  for(int j = 0; j < dim; j++) {
481  cost_matrix(i, j) -= row_min;
482  }
483  }
484  }
485 
486  //*******************************************************************************************
487  void find_zeros(const Eigen::MatrixXd &cost_matrix, Eigen::MatrixXi &zero_marks, const double _tol) {
488  // cost matrix dimension
489  int dim = cost_matrix.rows();
490  int star = -1;
491  bool is_star;
492  // Step 2. Find a zero in the matrix
493  // find zeros and star
494  for(int i = 0; i < dim; i++) {
495  for(int j = 0; j < dim; j++) {
496  if(almost_zero(cost_matrix(i, j), _tol)) {
497  is_star = false;
498  for(int k = 0; k < dim; k++) {
499  if(zero_marks(i, k) == star) {
500  is_star = true;
501  }
502  }
503  for(int l = 0; l < dim; l++) {
504  if(zero_marks(l, j) == star) {
505  is_star = true;
506  }
507  }
508  if(!is_star) {
509  zero_marks(i, j) = star;
510  }
511  }
512  }
513  }
514  }
515 
516  //*******************************************************************************************
517 
518  bool check_assignment(const Eigen::MatrixXi &zero_marks, Eigen::VectorXi &col_covered) {
519 
520 
521  // cover columns with starred zeros and check assignment. If N colmn
522  // covered we are done else return false.
523  for(int i = 0; i < zero_marks.rows(); i++) {
524  for(int j = 0; j < zero_marks.cols(); j++) {
525  if(zero_marks(i, j) == -1) {
526  col_covered(j) = 1;
527  }
528  }
529  }
530 
531  if(col_covered.sum() == zero_marks.rows()) {
532  return true;
533  }
534  else return false;
535  }
536 
537  //*******************************************************************************************
538 
539  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, const double _tol, const double _infinity) {
540 
541  int prime = 1;
542  int covered = 1;
543  int uncovered = 0;
544 
545  bool DONE = false;
546 
547 
548  // In step 4 we are looking for a noncovered zero.
549  // If one is found it is primed. If no star is found
550  // in its row, then step 5 is called. If a star is
551  // found, the row containing the prime is covered,
552  // and the column containing the star is uncovered.
553  // This is continued until no uncovered zeros exist.
554  while(!DONE) {
555  DONE = true;
556  for(int i = 0; i < cost_matrix.rows(); i++) {
557  for(int j = 0; j < cost_matrix.cols(); j++) {
558  if(almost_zero(cost_matrix(i, j), _tol) && col_covered(j) == 0 && row_covered(i) == 0) {
559  //find an uncovered zero and prime it
560  zero_marks(i, j) = prime;
561  // Determine if there is a starred zero in the row, if so, cover row i
562  // and uncover the column of the starred zero, k.
563  bool is_star = false;
564  for(int k = 0; k < zero_marks.cols(); k++) {
565  if(zero_marks(i, k) == -1 && !is_star) {
566  row_covered(i) = covered;
567  col_covered(k) = uncovered;
568  is_star = true;
569  }
570  }
571 
572  // If no starred zero, save the last primed zero and proceed to STEP 5.
573  if(!is_star) {
574  first_prime_zero(0) = i;
575  first_prime_zero(1) = j;
576  //alternating_path(cost_matrix, zero_marks, row_covered, col_covered, first_prime_zero);
577  return 5;
578  }
579  //else {
580  // row_covered(i) = 1;
581  // col_covered(j) = 0;
582  //}
583 
584 
585  }
586  }
587  }
588  for(int i = 0; i < cost_matrix.rows(); i++) {
589  for(int j = 0; j < cost_matrix.cols(); j++) {
590  if(row_covered(i) == 0 && col_covered(j) == 0 && almost_zero(cost_matrix(i, j), _tol)) {
591  DONE = false;
592  }
593  }
594  }
595  }
596 
597  // loop through all uncovered elements
598  // to find the minimum value remaining.
599  // This will be used in step 6.
600  //min = numeric_limits<double>::infinity();
601  min = _infinity;
602  int return_code(-1);
603  for(int i = 0; i < cost_matrix.rows(); i++) {
604  for(int j = 0; j < cost_matrix.cols(); j++) {
605  if(row_covered(i) == 0 && col_covered(j) == 0 && cost_matrix(i, j) < min) {
606  min = cost_matrix(i, j);
607  return_code = 6;
608  }
609  }
610  }
611  //update_costs(cost_matrix, zero_marks, row_covered, col_covered, min);
612  return return_code;
613  }
614 
615  //*******************************************************************************************
616 
617  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) {
618 
619 
620  bool done = false;
621 
622  // Initialize vectors to hold the locations
623  // of the alternating path. The largest path
624  // is at most 2*dimension of cost matrix -1.
625  Eigen::VectorXi row_path(2 * cost_matrix.rows() - 1);
626  Eigen::VectorXi col_path(2 * cost_matrix.cols() - 1);
627  //
628  //fill the paths initially with -1's so they
629  //are not mistaken for points in path.
630  row_path.fill(-1);
631  col_path.fill(-1);
632  //
633  // Keep track of how long the path is.
634  int path_counter = 1;
635 
636  // Set the first prime zero in the path
637  // as the location specified from step 4.
638  row_path(0) = first_prime_zero(0);
639  col_path(0) = first_prime_zero(1);
640 
641  // These bools help test if there
642  // are stars found in the prime's column.
643  // Or if there are any primes found in
644  // star's column.
645  bool star_found = false;
646  bool prime_found = false;
647 
648  // Build alternating path beginning with:
649  // uncovered primed zero (Z0)
650  // ---> starred zero in same col as Z0 (Z1)
651  // ---> primed zero in same row as Z1 (Z2)
652  // ---> continue until a starred zero cannot be found
653  //
654  // The path is stored in row_path and col_path
655  while(!done) {
656 
657  for(int i = 0; i < zero_marks.rows(); i++) {
658  if(zero_marks(i, col_path(path_counter - 1)) == -1 && !star_found) {
659  path_counter += 1;
660  row_path(path_counter - 1) = i;
661  col_path(path_counter - 1) = col_path(path_counter - 2);
662  star_found = true;
663  prime_found = false;
664  }
665  if(i == zero_marks.rows() - 1 && !star_found) {
666  done = true;
667  }
668 
669  }
670  if(star_found && !done) {
671  for(int j = 0; j < zero_marks.cols(); j++) {
672  if(zero_marks(row_path(path_counter - 1), j) == 1 && !prime_found) {
673  path_counter += 1;
674  row_path(path_counter - 1) = row_path(path_counter - 2);
675  col_path(path_counter - 1) = j;
676  prime_found = true;
677  star_found = false;
678  }
679  }
680  }
681  }
682 
683 
684 
685 
686  // Unstar each starred zero and star each primed zero
687  for(int i = 0; i < path_counter; i ++)
688  // Star primed zeros. I.e. even elements in path.
689  if(i % 2 == 0 && zero_marks(row_path(i), col_path(i)) == 1) {
690  zero_marks(row_path(i), col_path(i)) = -1;
691  }
692  // Unstar all starred zeros. I.e. odd elements.
693  else if(zero_marks(row_path(i), col_path(i)) == -1) {
694  zero_marks(row_path(i), col_path(i)) = 0;
695  }
696  for(int i = 0; i < zero_marks.rows(); i++) {
697  for(int j = 0; j < zero_marks.cols(); j ++) {
698  if(zero_marks(i, j) == 1) {
699  zero_marks(i, j) = 0;
700  }
701  }
702  }
703 
704  // Uncover all lines
705  row_covered.fill(0);
706  col_covered.fill(0);
707  return 3;
708  // Step 3 should be run next by the while loop in main.
709  }
710 
711  //*******************************************************************************************
712  int update_costs(const Eigen::VectorXi &row_covered, const Eigen::VectorXi &col_covered, const double min, Eigen::MatrixXd &cost_matrix) {
713 
714  // Step 6. Add value from 4 to all covered rows, and subtract it from uncovered columns.
715  // DO NOT alter stars, primes or covers.
716  // Return to 3.
717 
718  for(int i = 0; i < cost_matrix.rows(); i++) {
719  for(int j = 0; j < cost_matrix.cols(); j++) {
720  if(row_covered(i) == 1) {
721  cost_matrix(i, j) += min;
722  }
723  if(col_covered(j) == 0) {
724  cost_matrix(i, j) -= min;
725  }
726  }
727  }
728  //prime_zeros(cost_matrix, row_covered, col_covered, zero_marks);
729  return 4;
730  }
731 
732  //*******************************************************************************************
733 
734  void hungarian_method(const Eigen::MatrixXd &cost_matrix_arg, std::vector<Index> &optimal_assignment, const double _tol) {
735  double _infinity = 1E10;
736  Eigen::MatrixXd cost_matrix = cost_matrix_arg;
737 
738  // cost matrix dimension
739  int dim = cost_matrix.rows();
740 
741 
742  // initialize matrix to carry stars and primes.
743  Eigen::MatrixXi zero_marks = Eigen::MatrixXi::Zero(dim, dim);
744  // initialize vectors to track (un)covered rows or columns
745  Eigen::VectorXi row_covered(dim);
746  Eigen::VectorXi col_covered(dim);
747 
748 
749  int uncovered = 0;
750 
751  // begin uncovered
752  row_covered.fill(uncovered);
753  col_covered.fill(uncovered);
754 
755  //initialized by step 4
756  double min;
757 
758  // Vector to track the first_prime_zero found in step 4 and used in step 5.
759  Eigen::VectorXi first_prime_zero(2);
760 
761 
762  // Calling munkres step 1 to
763  // reduce the rows of the cost matrix
764  // by the smallest element in each row
765  reduce_cost(cost_matrix, _infinity);
766 
767  // Calling munkres step 2 to find
768  // a zero in the reduced matrix and
769  // if there is no starred zero in
770  // its row or column, star it.
771  // Repeat for all elements.
772  //
773  find_zeros(cost_matrix, zero_marks, _tol);
774 
775 
776  // Set DONE to false in order to control the while loop
777  // which runs the main portion of the algorithm.
778  bool DONE = false;
779 
780  // loop_counter could be used to set a maxumum number of iterations.
781  int loop_counter = 0;
782 
783 
784  // Main control loop for hungarian algorithm.
785  // Can only exit the while loop if munkres step 3
786  // returns true which means that there exists
787  // an optimal assignment.
788  //
789  // Begin with step three.
790  int next_step = 3;
791 
792  while(!DONE) {
793  if(next_step == 3) {
794  // Step 3 returns a boolean. TRUE if the assignment has been found
795  // FALSE, if step 4 is required.
796  if(check_assignment(zero_marks, col_covered) == true) {
797  DONE = true;
798  }
799  // Set max number of iterations if desired.
800  else if(loop_counter > 15) {
801  DONE = true;
802  }
803  else next_step = 4;
804  }
805  // Step 4 returns an int, either 5 or 6 (or -1 if failure detected)
806  if(next_step == 4) {
807  next_step = prime_zeros(cost_matrix, row_covered, col_covered, zero_marks, min, first_prime_zero, _tol, _infinity);
808  }
809  // Step 5 returns an int, either 3 or 4.
810  if(next_step == 5) {
811  next_step = alternating_path(cost_matrix, first_prime_zero, zero_marks, row_covered, col_covered);
812  }
813  // Step 6 returns an int, always 4.
814  if(next_step == 6) {
815  next_step = update_costs(row_covered, col_covered, min, cost_matrix);
816  }
817  if(next_step == -1) {
818  optimal_assignment.clear();
819  return;
820  }
821  // Use loop counter if desired.
822  // loop_counter++;
823  }
824 
825  // Once the main control loop finishes, an
826  // optimal assignment has been found. It
827  // is denoted by the locations of the
828  // starred zeros in the zero_marks matrix.
829  // optimal_assignment vector contains the
830  // results of the assignment as follows:
831  // the index corresponds to the index of
832  // the atom in the ideal POSCAR, and the
833  // value at an index corresponds to the
834  // atom of the relaxed structure.
835  // i.e. optimal_assignemnt(1) = 0
836  // means that the atom with index '1' in
837  // the ideal POSCAR is mapped onto the atom
838  // with index '0' in the relaxed CONTCAR.
839  optimal_assignment.assign(cost_matrix.rows(), -1);
840 
841  for(int i = 0; i < zero_marks.rows(); i++) {
842  for(int j = 0; j < zero_marks.cols(); j++) {
843  if(zero_marks(i, j) == -1) {
844  if(!valid_index(optimal_assignment[i])) {
845  optimal_assignment[i] = j;
846  }
847  else {
848  optimal_assignment.clear();
849  break;
850  }
851  }
852  }
853  if(optimal_assignment.size() == 0 || !valid_index(optimal_assignment[i])) {
854  optimal_assignment.clear();
855  break;
856  }
857 
858  }
859  //std::cout << cost_matrix << std::endl;
860  return;
861  }
862 
863  }
864 }
865 
Eigen::MatrixXd MatrixXd
int update_costs(const Eigen::VectorXi &row_covered, const Eigen::VectorXi &col_covered, const double min, Eigen::MatrixXd &cost_matrix)
Definition: CASM_math.cc:712
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
Definition: CASM_math.hh:41
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
void push_back(const T &toPush)
Definition: Array.hh:513
int lcm(int i1, int i2)
Find least common multiple.
Definition: CASM_math.cc:114
double hungarian_method(const Eigen::MatrixXd &cost_matrix, std::vector< Index > &optimal_assignments, const double _tol)
Definition: CASM_math.cc:444
void find_zeros(const Eigen::MatrixXd &cost_matrix, Eigen::MatrixXi &zero_marks, const double _tol)
Definition: CASM_math.cc:487
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
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
double tol
double gaussian_moment(int expon, double sigma)
Definition: CASM_math.cc:153
void clear()
Definition: Array.hh:216
EigenIndex Index
For long integer indexing:
IntType nchoosek(IntType n, IntType k)
Definition: CASM_math.hh:148
int mod(int a, int b)
Definition: CASM_math.cc:280
Eigen::VectorXd VectorXd
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)
Definition: CASM_math.cc:617
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
void nearest_rational_number(double val, long &numerator, long &denominator, double tol=TOL)
Definition: CASM_math.cc:188
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, const double _tol, const double _infinity)
Definition: CASM_math.cc:539
bool check_assignment(const Eigen::MatrixXi &zero_marks, Eigen::VectorXi &col_covered)
Definition: CASM_math.cc:518
int sgn(T val)
Definition: CASM_math.hh:125
void reduce_cost(Eigen::MatrixXd &cost_matrix, double _infinity)
Definition: CASM_math.cc:469
int round(double val)
Definition: CASM_math.cc:6
bool valid_index(Index i)