CASM  1.1.0
A Clusters Approach to Statistical Mechanics
CASM_Eigen_math.cc
Go to the documentation of this file.
2 
3 #include <iostream>
4 
6 
7 namespace CASM {
8 // Given a string and the size expected in the array. Converts it to an
9 // Eigen::VectorXd
10 Eigen::VectorXd eigen_vector_from_string(const std::string &tstr,
11  const int &size) {
12  std::stringstream tstream;
13  tstream << tstr;
14  Eigen::VectorXd tvec(size);
15  int i = 0;
16  while (!tstream.eof()) {
17  if (i == (size)) {
18  std::cerr << "WARNING in eigen_vector_from_string. You have more "
19  "elements in your array, than the value of size you passed. "
20  "Ignoring any extraneous elements"
21  << std::endl;
22  break;
23  }
24  tstream >> tvec(i);
25  i++;
26  }
27  if (i < (size - 1)) {
28  std::cerr
29  << "ERROR in eigen_vector_from_string. Fewer elements in your array "
30  "than the value of size you passed. Can't handle this. Quitting."
31  << std::endl;
32  exit(666);
33  }
34  return tvec;
35 }
36 
37 namespace HungarianMethod_impl {
38 
39 //*******************************************************************************************
47 //*******************************************************************************************
48 
49 void reduce_cost(Eigen::MatrixXd &cost_matrix, double _infinity) {
50  // cost matrix dimension
51  int dim = cost_matrix.rows();
52 
53  // Step 1. For every row subtract the minimum element from every
54  // entry in that row.
55  for (int i = 0; i < dim; i++) {
56  double row_min = cost_matrix.row(i).minCoeff();
57  if (row_min > _infinity) continue;
58  for (int j = 0; j < dim; j++) {
59  cost_matrix(i, j) -= row_min;
60  }
61  }
62 }
63 
64 //*******************************************************************************************
65 void find_zeros(const Eigen::MatrixXd &cost_matrix, Eigen::MatrixXi &zero_marks,
66  const double _tol) {
67  // cost matrix dimension
68  int dim = cost_matrix.rows();
69  int star = -1;
70  bool is_star;
71  // Step 2. Find a zero in the matrix
72  // find zeros and star
73  for (int i = 0; i < dim; i++) {
74  for (int j = 0; j < dim; j++) {
75  if (almost_zero(cost_matrix(i, j), _tol)) {
76  is_star = false;
77  for (int k = 0; k < dim; k++) {
78  if (zero_marks(i, k) == star) {
79  is_star = true;
80  }
81  }
82  for (int l = 0; l < dim; l++) {
83  if (zero_marks(l, j) == star) {
84  is_star = true;
85  }
86  }
87  if (!is_star) {
88  zero_marks(i, j) = star;
89  }
90  }
91  }
92  }
93 }
94 
95 //*******************************************************************************************
96 
97 bool check_assignment(const Eigen::MatrixXi &zero_marks,
98  Eigen::VectorXi &col_covered) {
99  // cover columns with starred zeros and check assignment. If N colmn
100  // covered we are done else return false.
101  for (int i = 0; i < zero_marks.rows(); i++) {
102  for (int j = 0; j < zero_marks.cols(); j++) {
103  if (zero_marks(i, j) == -1) {
104  col_covered(j) = 1;
105  }
106  }
107  }
108 
109  if (col_covered.sum() == zero_marks.rows()) {
110  return true;
111  } else
112  return false;
113 }
114 
115 //*******************************************************************************************
116 
117 int prime_zeros(const Eigen::MatrixXd &cost_matrix,
118  Eigen::VectorXi &row_covered, Eigen::VectorXi &col_covered,
119  Eigen::MatrixXi &zero_marks, double &min,
120  Eigen::VectorXi &first_prime_zero, const double _tol,
121  const double _infinity) {
122  int prime = 1;
123  int covered = 1;
124  int uncovered = 0;
125 
126  bool DONE = false;
127 
128  // In step 4 we are looking for a noncovered zero.
129  // If one is found it is primed. If no star is found
130  // in its row, then step 5 is called. If a star is
131  // found, the row containing the prime is covered,
132  // and the column containing the star is uncovered.
133  // This is continued until no uncovered zeros exist.
134  while (!DONE) {
135  DONE = true;
136  for (int i = 0; i < cost_matrix.rows(); i++) {
137  for (int j = 0; j < cost_matrix.cols(); j++) {
138  if (almost_zero(cost_matrix(i, j), _tol) && col_covered(j) == 0 &&
139  row_covered(i) == 0) {
140  // find an uncovered zero and prime it
141  zero_marks(i, j) = prime;
142  // Determine if there is a starred zero in the row, if so, cover row i
143  // and uncover the column of the starred zero, k.
144  bool is_star = false;
145  for (int k = 0; k < zero_marks.cols(); k++) {
146  if (zero_marks(i, k) == -1 && !is_star) {
147  row_covered(i) = covered;
148  col_covered(k) = uncovered;
149  is_star = true;
150  }
151  }
152 
153  // If no starred zero, save the last primed zero and proceed to
154  // STEP 5.
155  if (!is_star) {
156  first_prime_zero(0) = i;
157  first_prime_zero(1) = j;
158  // alternating_path(cost_matrix, zero_marks, row_covered,
159  // col_covered, first_prime_zero);
160  return 5;
161  }
162  // else {
163  // row_covered(i) = 1;
164  // col_covered(j) = 0;
165  //}
166  }
167  }
168  }
169  for (int i = 0; i < cost_matrix.rows(); i++) {
170  for (int j = 0; j < cost_matrix.cols(); j++) {
171  if (row_covered(i) == 0 && col_covered(j) == 0 &&
172  almost_zero(cost_matrix(i, j), _tol)) {
173  DONE = false;
174  }
175  }
176  }
177  }
178 
179  // loop through all uncovered elements
180  // to find the minimum value remaining.
181  // This will be used in step 6.
182  // min = numeric_limits<double>::infinity();
183  min = _infinity;
184  int return_code(-1);
185  for (int i = 0; i < cost_matrix.rows(); i++) {
186  for (int j = 0; j < cost_matrix.cols(); j++) {
187  if (row_covered(i) == 0 && col_covered(j) == 0 &&
188  cost_matrix(i, j) < min) {
189  min = cost_matrix(i, j);
190  return_code = 6;
191  }
192  }
193  }
194  // update_costs(cost_matrix, zero_marks, row_covered, col_covered, min);
195  return return_code;
196 }
197 
198 //*******************************************************************************************
199 
200 int alternating_path(const Eigen::MatrixXd &cost_matrix,
201  const Eigen::VectorXi &first_prime_zero,
202  Eigen::MatrixXi &zero_marks, Eigen::VectorXi &row_covered,
203  Eigen::VectorXi &col_covered) {
204  bool done = false;
205 
206  // Initialize vectors to hold the locations
207  // of the alternating path. The largest path
208  // is at most 2*dimension of cost matrix -1.
209  Eigen::VectorXi row_path(2 * cost_matrix.rows() - 1);
210  Eigen::VectorXi col_path(2 * cost_matrix.cols() - 1);
211  //
212  // fill the paths initially with -1's so they
213  // are not mistaken for points in path.
214  row_path.fill(-1);
215  col_path.fill(-1);
216  //
217  // Keep track of how long the path is.
218  int path_counter = 1;
219 
220  // Set the first prime zero in the path
221  // as the location specified from step 4.
222  row_path(0) = first_prime_zero(0);
223  col_path(0) = first_prime_zero(1);
224 
225  // These bools help test if there
226  // are stars found in the prime's column.
227  // Or if there are any primes found in
228  // star's column.
229  bool star_found = false;
230  bool prime_found = false;
231 
232  // Build alternating path beginning with:
233  // uncovered primed zero (Z0)
234  // ---> starred zero in same col as Z0 (Z1)
235  // ---> primed zero in same row as Z1 (Z2)
236  // ---> continue until a starred zero cannot be found
237  //
238  // The path is stored in row_path and col_path
239  while (!done) {
240  for (int i = 0; i < zero_marks.rows(); i++) {
241  if (zero_marks(i, col_path(path_counter - 1)) == -1 && !star_found) {
242  path_counter += 1;
243  row_path(path_counter - 1) = i;
244  col_path(path_counter - 1) = col_path(path_counter - 2);
245  star_found = true;
246  prime_found = false;
247  }
248  if (i == zero_marks.rows() - 1 && !star_found) {
249  done = true;
250  }
251  }
252  if (star_found && !done) {
253  for (int j = 0; j < zero_marks.cols(); j++) {
254  if (zero_marks(row_path(path_counter - 1), j) == 1 && !prime_found) {
255  path_counter += 1;
256  row_path(path_counter - 1) = row_path(path_counter - 2);
257  col_path(path_counter - 1) = j;
258  prime_found = true;
259  star_found = false;
260  }
261  }
262  }
263  }
264 
265  // Unstar each starred zero and star each primed zero
266  for (int i = 0; i < path_counter; i++)
267  // Star primed zeros. I.e. even elements in path.
268  if (i % 2 == 0 && zero_marks(row_path(i), col_path(i)) == 1) {
269  zero_marks(row_path(i), col_path(i)) = -1;
270  }
271  // Unstar all starred zeros. I.e. odd elements.
272  else if (zero_marks(row_path(i), col_path(i)) == -1) {
273  zero_marks(row_path(i), col_path(i)) = 0;
274  }
275  for (int i = 0; i < zero_marks.rows(); i++) {
276  for (int j = 0; j < zero_marks.cols(); j++) {
277  if (zero_marks(i, j) == 1) {
278  zero_marks(i, j) = 0;
279  }
280  }
281  }
282 
283  // Uncover all lines
284  row_covered.fill(0);
285  col_covered.fill(0);
286  return 3;
287  // Step 3 should be run next by the while loop in main.
288 }
289 
290 //*******************************************************************************************
291 int update_costs(const Eigen::VectorXi &row_covered,
292  const Eigen::VectorXi &col_covered, const double min,
293  Eigen::MatrixXd &cost_matrix) {
294  // Step 6. Add value from 4 to all covered rows, and subtract it from
295  // uncovered columns. DO NOT alter stars, primes or covers. Return to 3.
296 
297  for (int i = 0; i < cost_matrix.rows(); i++) {
298  for (int j = 0; j < cost_matrix.cols(); j++) {
299  if (row_covered(i) == 1) {
300  cost_matrix(i, j) += min;
301  }
302  if (col_covered(j) == 0) {
303  cost_matrix(i, j) -= min;
304  }
305  }
306  }
307  // prime_zeros(cost_matrix, row_covered, col_covered, zero_marks);
308  return 4;
309 }
310 
311 // *******************************************************************************************
312 /* Hungarian Algorithm Routines
313  * Step 1: reduce the rows by smallest element
314  * Step 2: star zeros
315  * Step 3: cover columns with starred zeros and check assignement
316  * if K columns covered DONE. Else goto 4.
317  * Step 4: Find uncovered zero and prime. if no starred zero in row
318  * goto 5. Otherwise, cover row, uncover column with star zero.
319  * Continue until all zeros are covered. Store smalles
320  * uncovered value goto 6.
321  * Step 5: Build alternating prime and star zeros. Goto 3.
322  * Step 6: Add value from 4 to all covered rows, and subtract it
323  * from uncovered columns. DO NOT alter stars, primes or covers.
324  * Return to 3.
325  *
326  */
327 // *******************************************************************************************
328 void hungarian_method(const Eigen::MatrixXd &cost_matrix_arg,
329  std::vector<Index> &optimal_assignment,
330  const double _tol) {
331  double _infinity = 1E10;
332  Eigen::MatrixXd cost_matrix = cost_matrix_arg;
333 
334  // cost matrix dimension
335  int dim = cost_matrix.rows();
336 
337  // initialize matrix to carry stars and primes.
338  Eigen::MatrixXi zero_marks = Eigen::MatrixXi::Zero(dim, dim);
339  // initialize vectors to track (un)covered rows or columns
340  Eigen::VectorXi row_covered(dim);
341  Eigen::VectorXi col_covered(dim);
342 
343  int uncovered = 0;
344 
345  // begin uncovered
346  row_covered.fill(uncovered);
347  col_covered.fill(uncovered);
348 
349  // initialized by step 4
350  double min = 0;
351 
352  // Vector to track the first_prime_zero found in step 4 and used in step 5.
353  Eigen::VectorXi first_prime_zero(2);
354 
355  // Calling munkres step 1 to
356  // reduce the rows of the cost matrix
357  // by the smallest element in each row
358  reduce_cost(cost_matrix, _infinity);
359 
360  // Calling munkres step 2 to find
361  // a zero in the reduced matrix and
362  // if there is no starred zero in
363  // its row or column, star it.
364  // Repeat for all elements.
365  //
366  find_zeros(cost_matrix, zero_marks, _tol);
367 
368  // Set DONE to false in order to control the while loop
369  // which runs the main portion of the algorithm.
370  bool DONE = false;
371 
372  // loop_counter could be used to set a maxumum number of iterations.
373  int loop_counter = 0;
374 
375  // Main control loop for hungarian algorithm.
376  // Can only exit the while loop if munkres step 3
377  // returns true which means that there exists
378  // an optimal assignment.
379  //
380  // Begin with step three.
381  int next_step = 3;
382 
383  while (!DONE) {
384  if (next_step == 3) {
385  // Step 3 returns a boolean. TRUE if the assignment has been found
386  // FALSE, if step 4 is required.
387  if (check_assignment(zero_marks, col_covered) == true) {
388  DONE = true;
389  }
390  // Set max number of iterations if desired.
391  else if (loop_counter > 15) {
392  DONE = true;
393  } else
394  next_step = 4;
395  }
396  // Step 4 returns an int, either 5 or 6 (or -1 if failure detected)
397  if (next_step == 4) {
398  next_step = prime_zeros(cost_matrix, row_covered, col_covered, zero_marks,
399  min, first_prime_zero, _tol, _infinity);
400  }
401  // Step 5 returns an int, either 3 or 4.
402  if (next_step == 5) {
403  next_step = alternating_path(cost_matrix, first_prime_zero, zero_marks,
404  row_covered, col_covered);
405  }
406  // Step 6 returns an int, always 4.
407  if (next_step == 6) {
408  next_step = update_costs(row_covered, col_covered, min, cost_matrix);
409  }
410  if (next_step == -1) {
411  optimal_assignment.clear();
412  return;
413  }
414  // Use loop counter if desired.
415  // loop_counter++;
416  }
417 
418  // Once the main control loop finishes, an
419  // optimal assignment has been found. It
420  // is denoted by the locations of the
421  // starred zeros in the zero_marks matrix.
422  // optimal_assignment vector contains the
423  // results of the assignment as follows:
424  // the index corresponds to the index of
425  // the atom in the ideal POSCAR, and the
426  // value at an index corresponds to the
427  // atom of the relaxed structure.
428  // i.e. optimal_assignemnt(1) = 0
429  // means that the atom with index '1' in
430  // the ideal POSCAR is mapped onto the atom
431  // with index '0' in the relaxed CONTCAR.
432  optimal_assignment.assign(cost_matrix.rows(), -1);
433 
434  for (int i = 0; i < zero_marks.rows(); i++) {
435  for (int j = 0; j < zero_marks.cols(); j++) {
436  if (zero_marks(i, j) == -1) {
437  if (!valid_index(optimal_assignment[i])) {
438  optimal_assignment[i] = j;
439  } else {
440  optimal_assignment.clear();
441  break;
442  }
443  }
444  }
445  if (optimal_assignment.size() == 0 || !valid_index(optimal_assignment[i])) {
446  optimal_assignment.clear();
447  break;
448  }
449  }
450  // std::cout << cost_matrix << std::endl;
451  return;
452 }
453 
454 } // namespace HungarianMethod_impl
455 
456 //*******************************************************************************************
457 
458 double hungarian_method(const Eigen::MatrixXd &cost_matrix,
459  std::vector<Index> &optimal_assignment,
460  const double _tol) {
461  // Run hungarian algorithm on original cost_matrix
462  HungarianMethod_impl::hungarian_method(cost_matrix, optimal_assignment, _tol);
463 
464  double tot_cost = 0.0;
465  // Find the costs associated with the correct assignments
466  for (int i = 0; i < optimal_assignment.size(); i++) {
467  tot_cost += cost_matrix(i, optimal_assignment[i]);
468  }
469  if (optimal_assignment.size() == 0) tot_cost = 1e20;
470  return tot_cost;
471 }
472 
473 //*******************************************************************************************
484 //*******************************************************************************************
485 // Added by Ivy 11/28/12
486 void get_Hermitian(Eigen::MatrixXcd &original_mat,
487  Eigen::MatrixXcd &hermitian_mat,
488  Eigen::MatrixXcd &antihermitian_mat) {
489  Eigen::MatrixXcd conj_trans = original_mat.conjugate().transpose();
490 
491  hermitian_mat = 0.5 * (original_mat + conj_trans);
492  antihermitian_mat = 0.5 * (original_mat - conj_trans);
493 }
494 
495 //*******************************************************************************************
501 //*******************************************************************************************
502 // Added by Ivy 11/28/12
503 bool is_Hermitian(Eigen::MatrixXcd &mat) {
504  if ((mat - mat.conjugate().transpose()).isZero(TOL)) {
505  return true;
506  }
507  return false;
508 }
509 
524 std::pair<Eigen::MatrixXi, Eigen::MatrixXi> hermite_normal_form(
525  const Eigen::MatrixXi &M) {
526  if (M.rows() != M.cols()) {
527  throw std::runtime_error(
528  std::string(
529  "Error in hermite_normal_form(const Eigen::MatrixXi &M)\n") +
530  " M must be square.");
531  }
532 
533  if (boost::math::iround(M.cast<double>().determinant()) == 0) {
534  throw std::runtime_error(
535  std::string(
536  "Error in hermite_normal_form(const Eigen::MatrixXi &M)\n") +
537  " M must be full rank.");
538  }
539 
540  Eigen::MatrixXi V = Eigen::MatrixXi::Identity(M.rows(), M.cols());
541  Eigen::MatrixXi H = M;
542 
543  int N = M.rows();
544  int i, r, c;
545 
546  // get non-zero entries along H diagonal
547  for (i = N - 1; i >= 0; i--) {
548  // swap columns if necessary to get non-zero entry at H(i,i)
549  if (H(i, i) == 0) {
550  for (c = i - 1; c >= 0; c--) {
551  if (H(i, c) != 0) {
552  H.col(c).swap(H.col(i));
553  V.row(c).swap(V.row(i));
554  break;
555  }
556  }
557  }
558 
559  // get positive entry at H(i,i)
560  if (H(i, i) < 0) {
561  H.col(i) *= -1;
562  V.row(i) *= -1;
563  }
564 
565  // do column operations to get zeros to left of H(i,i)
566  for (c = i - 1; c >= 0; c--) {
567  if (H(i, c) == 0) continue;
568 
569  while (H(i, c) != 0) {
570  while (H(i, c) < 0) {
571  H.col(c) += H.col(i);
572  V.row(i) -= V.row(c);
573  }
574 
575  while (H(i, i) <= H(i, c) && H(i, c) != 0) {
576  H.col(c) -= H.col(i);
577  V.row(i) += V.row(c);
578  }
579 
580  while (H(i, c) < H(i, i) && H(i, c) != 0) {
581  H.col(i) -= H.col(c);
582  V.row(c) += V.row(i);
583  }
584  }
585  }
586  }
587 
588  // now we have M = H*V, where H is upper triangular
589  // so use column operations to enforce 0 <= H(i,c) < H(i,i) for c > i
590 
591  // columns left to right
592  for (c = 1; c < H.cols(); c++) {
593  // rows above the diagonal to the top
594  for (r = c - 1; r >= 0; r--) {
595  while (H(r, c) < 0) {
596  H.col(c) += H.col(r);
597  V.row(r) -= V.row(c);
598  }
599  while (H(r, c) >= H(r, r)) {
600  H.col(c) -= H.col(r);
601  V.row(r) += V.row(c);
602  }
603  }
604  }
605 
606  // now we have M = H*V
607  return std::make_pair(H, V);
608 }
609 
611 double angle(const Eigen::Ref<const Eigen::Vector3d> &a,
612  const Eigen::Ref<const Eigen::Vector3d> &b) {
613  return acos(a.dot(b) / (a.norm() * b.norm()));
614 }
615 
618 double signed_angle(const Eigen::Ref<const Eigen::Vector3d> &a,
619  const Eigen::Ref<const Eigen::Vector3d> &b,
620  const Eigen::Ref<const Eigen::Vector3d> &pos_ref) {
621  if (pos_ref.dot(a.cross(b)) < 0) {
622  return -angle(a, b);
623  } else
624  return angle(a, b);
625 }
626 
629 Eigen::MatrixXd pretty(const Eigen::MatrixXd &M, double tol) {
630  Eigen::MatrixXd Mp(M);
631  for (int i = 0; i < M.rows(); i++) {
632  for (int j = 0; j < M.cols(); j++) {
633  if (std::abs(std::round(M(i, j)) - M(i, j)) < tol) {
634  Mp(i, j) = std::round(M(i, j));
635  }
636  }
637  }
638  return Mp;
639 }
640 
642  return Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d>(mat.transpose() * mat)
643  .operatorSqrt();
644 }
645 
646 std::vector<Eigen::Matrix3i> _unimodular_matrices(bool positive, bool negative,
647  int range) {
648  std::vector<Eigen::Matrix3i> uni_det_mats;
649  int totalmats = 3480;
650 
651  if (positive && negative) {
652  totalmats = totalmats * 2;
653  }
654 
655  uni_det_mats.reserve(totalmats);
656 
657  EigenCounter<Eigen::Matrix3i> transmat_count(
658  Eigen::Matrix3i::Constant(-range), Eigen::Matrix3i::Constant(range),
659  Eigen::Matrix3i::Constant(1));
660 
661  for (; transmat_count.valid(); ++transmat_count) {
662  if (positive && transmat_count.current().determinant() == 1) {
663  uni_det_mats.push_back(transmat_count.current());
664  }
665 
666  if (negative && transmat_count.current().determinant() == -1) {
667  uni_det_mats.push_back(transmat_count.current());
668  }
669  }
670 
671  return uni_det_mats;
672 }
673 
674 const std::vector<Eigen::Matrix3i> &positive_unimodular_matrices() {
675  static std::vector<Eigen::Matrix3i> static_positive(
676  _unimodular_matrices(true, false));
677  return static_positive;
678 }
679 
680 const std::vector<Eigen::Matrix3i> &negative_unimodular_matrices() {
681  static std::vector<Eigen::Matrix3i> static_negative(
682  _unimodular_matrices(false, true));
683  return static_negative;
684 }
685 
686 } // namespace CASM
bool valid() const
Definition: BaseCounter.hh:160
const Container & current() const
Definition: BaseCounter.hh:201
A Counter allows looping over many incrementing variables in one loop.
Definition: Counter.hh:109
std::vector< Eigen::Matrix3i > _unimodular_matrices(bool positive, bool negative, int range=1)
void get_Hermitian(Eigen::MatrixXcd &original_mat, Eigen::MatrixXcd &hermitian_mat, Eigen::MatrixXcd &antihermitian_mat)
Eigen::MatrixXd pretty(const Eigen::MatrixXd &M, double tol)
Round entries that are within tol of being integer to that integer value.
const std::vector< Eigen::Matrix3i > & positive_unimodular_matrices()
Eigen::Matrix3d polar_decomposition(Eigen::Matrix3d const &mat)
double angle(const Eigen::Ref< const Eigen::Vector3d > &a, const Eigen::Ref< const Eigen::Vector3d > &b)
Get angle, in radians, between two vectors on range [0,pi].
const std::vector< Eigen::Matrix3i > & negative_unimodular_matrices()
std::pair< Eigen::MatrixXi, Eigen::MatrixXi > hermite_normal_form(const Eigen::MatrixXi &M)
Return the hermite normal form, M == H*V.
Eigen::CwiseUnaryOp< decltype(Local::round_l< typename Derived::Scalar >), const Derived > round(const Eigen::MatrixBase< Derived > &val)
Round Eigen::MatrixXd.
double signed_angle(const Eigen::Ref< const Eigen::Vector3d > &a, const Eigen::Ref< const Eigen::Vector3d > &b, const Eigen::Ref< const Eigen::Vector3d > &pos_ref)
signed angle, in radians, between -pi and pi that describe separation in direction of two vectors
Eigen::CwiseUnaryOp< decltype(Local::iround_l< typename Derived::Scalar >), const Derived > iround(const Eigen::MatrixBase< Derived > &val)
Round Eigen::MatrixXd to Eigen::MatrixXi.
bool is_Hermitian(Eigen::MatrixXcd &mat)
void hungarian_method(const Eigen::MatrixXd &cost_matrix_arg, std::vector< Index > &optimal_assignment, const double _tol)
void find_zeros(const Eigen::MatrixXd &cost_matrix, Eigen::MatrixXi &zero_marks, const double _tol)
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)
int update_costs(const Eigen::VectorXi &row_covered, const Eigen::VectorXi &col_covered, const double min, Eigen::MatrixXd &cost_matrix)
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)
bool check_assignment(const Eigen::MatrixXi &zero_marks, Eigen::VectorXi &col_covered)
void reduce_cost(Eigen::MatrixXd &cost_matrix, double _infinity)
IdentitySymRepBuilder Identity()
Main CASM namespace.
Definition: APICommand.hh:8
Eigen::MatrixXd MatrixXd
Eigen::VectorXd eigen_vector_from_string(const std::string &tstr, const int &size)
Eigen::Matrix3d Matrix3d
double hungarian_method(const Eigen::MatrixXd &cost_matrix, std::vector< Index > &optimal_assignments, const double _tol)
const double TOL
Definition: definitions.hh:30
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
Definition: CASM_math.hh:104
T min(const T &A, const T &B)
Definition: CASM_math.hh:88
bool valid_index(Index i)
Definition: definitions.cc:5
Eigen::VectorXd VectorXd