12 std::stringstream tstream;
16 while (!tstream.eof()) {
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"
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."
37 namespace HungarianMethod_impl {
51 int dim = cost_matrix.rows();
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;
68 int dim = cost_matrix.rows();
73 for (
int i = 0; i < dim; i++) {
74 for (
int j = 0; j < dim; j++) {
77 for (
int k = 0; k < dim; k++) {
78 if (zero_marks(i, k) == star) {
82 for (
int l = 0; l < dim; l++) {
83 if (zero_marks(l, j) == star) {
88 zero_marks(i, j) = star;
98 Eigen::VectorXi &col_covered) {
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) {
109 if (col_covered.sum() == zero_marks.rows()) {
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) {
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) {
141 zero_marks(i, j) = prime;
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;
156 first_prime_zero(0) = i;
157 first_prime_zero(1) = j;
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 &&
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);
201 const Eigen::VectorXi &first_prime_zero,
202 Eigen::MatrixXi &zero_marks, Eigen::VectorXi &row_covered,
203 Eigen::VectorXi &col_covered) {
209 Eigen::VectorXi row_path(2 * cost_matrix.rows() - 1);
210 Eigen::VectorXi col_path(2 * cost_matrix.cols() - 1);
218 int path_counter = 1;
222 row_path(0) = first_prime_zero(0);
223 col_path(0) = first_prime_zero(1);
229 bool star_found =
false;
230 bool prime_found =
false;
240 for (
int i = 0; i < zero_marks.rows(); i++) {
241 if (zero_marks(i, col_path(path_counter - 1)) == -1 && !star_found) {
243 row_path(path_counter - 1) = i;
244 col_path(path_counter - 1) = col_path(path_counter - 2);
248 if (i == zero_marks.rows() - 1 && !star_found) {
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) {
256 row_path(path_counter - 1) = row_path(path_counter - 2);
257 col_path(path_counter - 1) = j;
266 for (
int i = 0; i < path_counter; i++)
268 if (i % 2 == 0 && zero_marks(row_path(i), col_path(i)) == 1) {
269 zero_marks(row_path(i), col_path(i)) = -1;
272 else if (zero_marks(row_path(i), col_path(i)) == -1) {
273 zero_marks(row_path(i), col_path(i)) = 0;
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;
292 const Eigen::VectorXi &col_covered,
const double min,
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;
302 if (col_covered(j) == 0) {
303 cost_matrix(i, j) -=
min;
329 std::vector<Index> &optimal_assignment,
331 double _infinity = 1E10;
335 int dim = cost_matrix.rows();
338 Eigen::MatrixXi zero_marks = Eigen::MatrixXi::Zero(dim, dim);
340 Eigen::VectorXi row_covered(dim);
341 Eigen::VectorXi col_covered(dim);
346 row_covered.fill(uncovered);
347 col_covered.fill(uncovered);
353 Eigen::VectorXi first_prime_zero(2);
373 int loop_counter = 0;
384 if (next_step == 3) {
391 else if (loop_counter > 15) {
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);
402 if (next_step == 5) {
404 row_covered, col_covered);
407 if (next_step == 6) {
410 if (next_step == -1) {
411 optimal_assignment.clear();
432 optimal_assignment.assign(cost_matrix.rows(), -1);
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) {
438 optimal_assignment[i] = j;
440 optimal_assignment.clear();
445 if (optimal_assignment.size() == 0 || !
valid_index(optimal_assignment[i])) {
446 optimal_assignment.clear();
459 std::vector<Index> &optimal_assignment,
464 double tot_cost = 0.0;
466 for (
int i = 0; i < optimal_assignment.size(); i++) {
467 tot_cost += cost_matrix(i, optimal_assignment[i]);
469 if (optimal_assignment.size() == 0) tot_cost = 1e20;
487 Eigen::MatrixXcd &hermitian_mat,
488 Eigen::MatrixXcd &antihermitian_mat) {
489 Eigen::MatrixXcd conj_trans = original_mat.conjugate().transpose();
491 hermitian_mat = 0.5 * (original_mat + conj_trans);
492 antihermitian_mat = 0.5 * (original_mat - conj_trans);
504 if ((mat - mat.conjugate().transpose()).isZero(
TOL)) {
525 const Eigen::MatrixXi &M) {
526 if (M.rows() != M.cols()) {
527 throw std::runtime_error(
529 "Error in hermite_normal_form(const Eigen::MatrixXi &M)\n") +
530 " M must be square.");
534 throw std::runtime_error(
536 "Error in hermite_normal_form(const Eigen::MatrixXi &M)\n") +
537 " M must be full rank.");
541 Eigen::MatrixXi H = M;
547 for (i = N - 1; i >= 0; i--) {
550 for (c = i - 1; c >= 0; c--) {
552 H.col(c).swap(H.col(i));
553 V.row(c).swap(V.row(i));
566 for (c = i - 1; c >= 0; c--) {
567 if (H(i, c) == 0)
continue;
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);
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);
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);
592 for (c = 1; c < H.cols(); c++) {
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);
599 while (H(r, c) >= H(r, r)) {
600 H.col(c) -= H.col(r);
601 V.row(r) += V.row(c);
607 return std::make_pair(H, V);
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()));
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) {
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) {
642 return Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d>(mat.transpose() * mat)
648 std::vector<Eigen::Matrix3i> uni_det_mats;
649 int totalmats = 3480;
651 if (positive && negative) {
652 totalmats = totalmats * 2;
655 uni_det_mats.reserve(totalmats);
658 Eigen::Matrix3i::Constant(-range), Eigen::Matrix3i::Constant(range),
659 Eigen::Matrix3i::Constant(1));
661 for (; transmat_count.
valid(); ++transmat_count) {
662 if (positive && transmat_count.
current().determinant() == 1) {
663 uni_det_mats.push_back(transmat_count.
current());
666 if (negative && transmat_count.
current().determinant() == -1) {
667 uni_det_mats.push_back(transmat_count.
current());
675 static std::vector<Eigen::Matrix3i> static_positive(
677 return static_positive;
681 static std::vector<Eigen::Matrix3i> static_negative(
683 return static_negative;
const Container & current() const
A Counter allows looping over many incrementing variables in one loop.
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()
Eigen::VectorXd eigen_vector_from_string(const std::string &tstr, const int &size)
double hungarian_method(const Eigen::MatrixXd &cost_matrix, std::vector< Index > &optimal_assignments, const double _tol)
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
T min(const T &A, const T &B)
bool valid_index(Index i)