CASM  1.1.0
A Clusters Approach to Statistical Mechanics
CASM_Eigen_math.hh
Go to the documentation of this file.
1 #ifndef CASM_Eigen_math
2 #define CASM_Eigen_math
3 
4 #include <boost/math/special_functions/round.hpp>
5 #include <cassert>
6 #include <cmath>
7 #include <complex>
8 #include <type_traits>
9 #include <vector>
10 
11 #include "./KroneckerTensorProduct.h"
12 #include "casm/external/Eigen/Eigenvalues"
14 #include "casm/global/eigen.hh"
15 #include "casm/misc/CASM_math.hh"
16 
17 namespace Local {
18 template <typename T>
19 inline static bool _compare(T const &a, T const &b, double tol) {
20  return (a + tol) < b;
21 }
22 
23 template <>
24 inline bool _compare(std::complex<double> const &a,
25  std::complex<double> const &b, double tol) {
26  if (!CASM::almost_equal(real(a), real(b), tol)) {
27  return real(a) < real(b);
28  } else if (!CASM::almost_equal(imag(a), imag(b), tol)) {
29  return imag(a) < imag(b);
30  }
31  return false;
32 }
33 
34 // Lambda functions to replace std::ptr_fun, which is deprecated
35 template <typename T>
36 auto round_l = [](T val) { return boost::math::round<T>(val); };
37 template <typename T>
38 auto iround_l = [](T val) { return boost::math::iround<T>(val); };
39 template <typename T>
40 auto lround_l = [](T val) { return boost::math::lround<T>(val); };
41 } // namespace Local
42 namespace CASM {
43 
46  const Eigen::Ref<const Eigen::MatrixXd> &A,
47  const Eigen::Ref<const Eigen::MatrixXd> &B, double tol) {
48  return float_lexicographical_compare(A.data(), A.data() + A.size(), B.data(),
49  B.data() + B.size(), tol);
50 }
51 
53 template <typename Derived>
54 bool colmajor_lex_compare(const Eigen::MatrixBase<Derived> &A,
55  const Eigen::MatrixBase<Derived> &B, double tol) {
56  if (A.cols() == B.cols()) {
57  if (A.rows() == B.rows()) {
58  for (Index j = 0; j < A.cols(); ++j) {
59  for (Index i = 0; i < A.rows(); ++i) {
60  if (!almost_equal(A(i, j), B(i, j), tol))
61  return Local::_compare(A(i, j), B(i, j), tol);
62  }
63  }
64  return false;
65  } else if (A.rows() < B.rows())
66  return true;
67  else
68  return false;
69  } else if (A.cols() < B.cols())
70  return true;
71  else
72  return false;
73 }
74 
77 template <typename Derived>
78 typename Derived::PlainObject reduced_column_echelon(
79  Eigen::MatrixBase<Derived> const &M, double _tol) {
80  typename Derived::PlainObject R(M);
81  Index col = 0;
82  for (Index row = 0; row < R.rows(); ++row) {
83  Index i = 0;
84  for (i = col; i < R.cols(); ++i) {
85  if (!almost_zero(R(row, i), _tol)) {
86  if (i != col) R.col(i).swap(R.col(col));
87  break;
88  }
89  }
90  if (i == R.cols()) continue;
91  R.col(col) /= R(row, col);
92  for (i = 0; i < R.cols(); ++i) {
93  if (i != col) R.col(i) -= R(row, i) * R.col(col);
94  }
95  ++col;
96  }
97  return R.leftCols(col);
98 }
99 
100 Eigen::VectorXd eigen_vector_from_string(const std::string &tstr,
101  const int &size);
102 
103 // *******************************************************************************************
104 
105 // Finds optimal assignments, based on cost_matrix, and returns total optimal
106 // cost
107 double hungarian_method(const Eigen::MatrixXd &cost_matrix,
108  std::vector<Index> &optimal_assignments,
109  const double _tol);
110 
113 template <typename Derived>
114 typename Derived::Scalar *end_ptr(Eigen::PlainObjectBase<Derived> &container) {
115  return container.data() + container.size();
116 }
117 
120 template <typename Derived>
121 typename Derived::Scalar const *end_ptr(
122  Eigen::PlainObjectBase<Derived> const &container) {
123  return container.data() + container.size();
124 }
125 
134 void get_Hermitian(Eigen::MatrixXcd &original_mat,
135  Eigen::MatrixXcd &hermitian_mat,
136  Eigen::MatrixXcd &antihermitian_mat); // Ivy
137 bool is_Hermitian(Eigen::MatrixXcd &mat); // Ivy
138 
140 std::pair<Eigen::MatrixXi, Eigen::MatrixXi> hermite_normal_form(
141  const Eigen::MatrixXi &M);
142 
144 double angle(const Eigen::Ref<const Eigen::Vector3d> &a,
145  const Eigen::Ref<const Eigen::Vector3d> &b);
146 
149 double signed_angle(const Eigen::Ref<const Eigen::Vector3d> &a,
150  const Eigen::Ref<const Eigen::Vector3d> &b,
151  const Eigen::Ref<const Eigen::Vector3d> &pos_ref);
152 
155 Eigen::MatrixXd pretty(const Eigen::MatrixXd &M, double tol);
156 
157 template <typename Derived>
158 typename Derived::Scalar triple_product(const Derived &vec0,
159  const Derived &vec1,
160  const Derived &vec2) {
161  return (vec0.cross(vec1)).dot(vec2);
162 }
163 
165 template <typename Derived>
166 bool is_integer(const Eigen::MatrixBase<Derived> &M, double tol) {
167  for (Index i = 0; i < M.rows(); i++) {
168  for (Index j = 0; j < M.cols(); j++) {
169  if (!almost_zero(boost::math::lround(M(i, j)) - M(i, j), tol))
170  return false;
171  }
172  }
173  return true;
174 }
175 
177 template <typename Derived>
178 bool is_unimodular(const Eigen::MatrixBase<Derived> &M, double tol) {
179  return is_integer(M, tol) &&
180  almost_equal(std::abs(M.determinant()),
181  static_cast<typename Derived::Scalar>(1), tol);
182 }
183 
185 template <typename Derived>
186 bool is_diagonal(const Eigen::MatrixBase<Derived> &M, double tol = TOL) {
187  return M.isDiagonal(tol);
188 }
189 
199 template <typename Derived>
200 Eigen::CwiseUnaryOp<decltype(Local::round_l<typename Derived::Scalar>),
201  const Derived>
202 round(const Eigen::MatrixBase<Derived> &val) {
203  return val.unaryExpr(Local::round_l<typename Derived::Scalar>);
204 }
205 
215 template <typename Derived>
216 Eigen::CwiseUnaryOp<decltype(Local::iround_l<typename Derived::Scalar>),
217  const Derived>
218 iround(const Eigen::MatrixBase<Derived> &val) {
219  return val.unaryExpr(Local::iround_l<typename Derived::Scalar>);
220 }
221 
231 template <typename Derived>
232 Eigen::CwiseUnaryOp<decltype(Local::lround_l<typename Derived::Scalar>),
233  const Derived>
234 lround(const Eigen::MatrixBase<Derived> &val) {
235  return val.unaryExpr(Local::lround_l<typename Derived::Scalar>);
236 }
237 
249 template <typename Derived>
250 typename Derived::Scalar matrix_minor(const Eigen::MatrixBase<Derived> &M,
251  int row, int col) {
252  // create the submatrix of M which doesn't include any elements from M in
253  // 'row' or 'col'
254  Eigen::Matrix<typename Derived::Scalar, Derived::RowsAtCompileTime - 1,
255  Derived::ColsAtCompileTime - 1>
256  subM(M.rows() - 1, M.cols() - 1);
257  int i, j;
258  for (i = 0; i < row; ++i) {
259  for (j = 0; j < col; ++j) {
260  subM(i, j) = M(i, j);
261  }
262  for (++j; j < M.cols(); ++j) {
263  subM(i, j - 1) = M(i, j);
264  }
265  }
266 
267  for (++i; i < M.rows(); ++i) {
268  for (j = 0; j < col; ++j) {
269  subM(i - 1, j) = M(i, j);
270  }
271  for (++j; j < M.cols(); ++j) {
272  subM(i - 1, j - 1) = M(i, j);
273  }
274  }
275 
276  // return determinant of subM
277  return subM.determinant();
278 }
279 
289 template <typename Derived>
290 Eigen::Matrix<typename Derived::Scalar, Derived::RowsAtCompileTime,
291  Derived::ColsAtCompileTime>
292 cofactor(const Eigen::MatrixBase<Derived> &M) {
293  Eigen::Matrix<typename Derived::Scalar, Derived::RowsAtCompileTime,
294  Derived::ColsAtCompileTime>
295  Mcof(M.rows(), M.cols());
296  for (int i = 0; i < Mcof.rows(); i++) {
297  for (int j = 0; j < Mcof.cols(); j++) {
298  Mcof(i, j) = ((((i + j) % 2) == 0) ? matrix_minor(M, i, j)
299  : -matrix_minor(M, i, j));
300  }
301  }
302  return Mcof;
303 }
304 
315 // Note: If Eigen ever implements integer factorizations, we should probably
316 // change how this works
317 template <typename Derived>
318 Eigen::Matrix<typename Derived::Scalar, Derived::RowsAtCompileTime,
319  Derived::ColsAtCompileTime>
320 adjugate(const Eigen::MatrixBase<Derived> &M) {
321  return cofactor(M).transpose();
322 }
323 
324 namespace normal_form_impl {
334 template <typename Scalar>
335 Eigen::Matrix<Scalar, 3, 3> _elementary_hermite_op(Scalar a, Scalar b, Scalar i,
336  Scalar j) {
337  typedef Eigen::Matrix<Scalar, 3, 3> matrix_type;
338  matrix_type tmat = matrix_type::Identity();
339  Scalar tgcf = extended_gcf(a, b, tmat(i, i), tmat(i, j));
340  if (tgcf == 0) {
341  return matrix_type::Identity();
342  }
343  tmat(j, i) = -b / tgcf;
344  tmat(j, j) = a / tgcf;
345  return tmat;
346 }
347 
348 } // namespace normal_form_impl
349 
356 template <typename Derived>
357 Eigen::Matrix<typename Derived::Scalar, Derived::RowsAtCompileTime,
358  Derived::ColsAtCompileTime>
359 inverse(const Eigen::MatrixBase<Derived> &M) {
360  return adjugate(M) / M.determinant();
361 }
362 
375 template <typename DerivedIn, typename DerivedOut>
376 void smith_normal_form(const Eigen::MatrixBase<DerivedIn> &M,
377  Eigen::MatrixBase<DerivedOut> &U,
378  Eigen::MatrixBase<DerivedOut> &S,
379  Eigen::MatrixBase<DerivedOut> &V) {
380  static_assert(std::is_same<typename DerivedIn::Scalar,
381  typename DerivedOut::Scalar>::value,
382  "ALL ARGUMENTS TO CASM::smith_normal_form() MUST BE BASED ON "
383  "SAME SCALAR TYPE!");
384  using namespace normal_form_impl;
385  typedef typename DerivedOut::Scalar Scalar;
386 
387  U = V = DerivedOut::Identity();
388  S = M;
389  // std::cout << "S is:\n" << S << "\n\n";
390 
391  DerivedOut tmat = U;
392 
393  int i, j;
394 
395  // Bidiagonalize S with elementary Hermite transforms.
396  for (j = 0; j < 3; j++) {
397  // take j as column index and zero elements of j below the diagonal
398  for (i = j + 1; i < 3; i++) {
399  if (S(i, j) == 0) continue;
400  tmat = _elementary_hermite_op<Scalar>(S(j, j), S(i, j), j, i);
401  S = tmat * S;
402  U = U * inverse(tmat);
403  }
404 
405  // take j as row index and zero elements of j after superdiagonal
406  for (i = j + 2; i < 3; i++) {
407  if (S(j, i) == 0) continue;
408  tmat = _elementary_hermite_op<Scalar>(S(j, j + 1), S(j, i), j + 1, i);
409  S = S * tmat.transpose();
410  V = inverse(tmat.transpose()) * V;
411  }
412  }
413 
414  // std::cout << "About to hunt zeros, SNF decomposition is currently:\n" << U
415  // << "\n\n" << S << "\n\n" << V << "\n\n";
416  while (!S.isDiagonal()) {
417  // find off-diagonal element
418  int b = 0;
419  for (b = 0; b < 2; b++) {
420  if (S(b, b + 1)) break;
421  }
422 
423  // To guarantee reduction in S(b,b), first make S(b,b) positive
424  // and make S(b,b+1) nonnegative and less than S(b,b).
425  if (S(b, b) < 0) {
426  for (i = 0; i < 3; i++) {
427  S(b, i) = -S(b, i);
428  U(i, b) = -U(i, b);
429  }
430  }
431 
432  // std::cout << "S before q:\n" << S << '\n';
433 
434  if (S(b, b)) {
435  Scalar q = S(b, b + 1) / S(b, b);
436  if (S(b, b + 1) % S(b, b) < 0) q -= 1;
437  tmat = DerivedOut::Identity();
438  tmat(b + 1, b) = -q;
439  S = S * tmat.transpose();
440  V = inverse(tmat.transpose()) * V;
441  // std::cout << "tmat for q:\n" << tmat << '\n';
442  // std::cout << "S after q:\n" << S << '\n';
443  } else {
444  tmat = DerivedOut::Identity();
445  tmat(b, b) = 0;
446  tmat(b, b + 1) = 1;
447  tmat(b + 1, b + 1) = 0;
448  tmat(b + 1, b) = 1;
449  S = S * tmat.transpose();
450  V = inverse(tmat.transpose()) * V;
451  }
452 
453  if (!S(b, b + 1)) continue;
454 
455  tmat = _elementary_hermite_op<Scalar>(S(b, b), S(b, b + 1), b, b + 1);
456  S = S * tmat.transpose();
457  V = inverse(tmat.transpose()) * V;
458  for (j = 0; j < 2; j++) {
459  tmat = _elementary_hermite_op<Scalar>(S(j, j), S(j + 1, j), j, j + 1);
460  S = tmat * S;
461  U = U * inverse(tmat);
462 
463  if (j + 2 >= 3) continue;
464 
465  tmat = _elementary_hermite_op<Scalar>(S(j, j + 1), S(j, j + 2), j + 1,
466  j + 2);
467  S = S * tmat.transpose();
468  V = inverse(tmat.transpose()) * V;
469  }
470  }
471 
472  // Now it's diagonal -- make it non-negative
473  for (j = 0; j < 3; j++) {
474  if (S(j, j) < 0) {
475  for (i = 0; i < 3; i++) {
476  S(j, i) = -S(j, i);
477  U(i, j) = -U(i, j);
478  }
479  }
480  }
481 
482  // sort diagonal elements
483  for (i = 0; i < 3; i++) {
484  for (j = i + 1; j < 3; j++) {
485  if (S(i, i) > S(j, j)) {
486  S.row(i).swap(S.row(j));
487  S.col(i).swap(S.col(j));
488  U.col(i).swap(U.col(j));
489  V.row(i).swap(V.row(j));
490  }
491  }
492  }
493  // enforce divisibility condition:
494  for (i = 0; i < 3; i++) {
495  if (S(i, i) == 0) continue;
496  for (j = i + 1; j < 3; j++) {
497  if (S(j, j) % S(i, i) == 0) continue;
498  // Replace S(i,i), S(j,j) by their gcd and lcm respectively.
499  tmat = DerivedOut::Identity();
500  DerivedOut tmat2(tmat);
501  Scalar a(S(i, i)), b(S(j, j)), c, d, tgcf;
502  tgcf = extended_gcf(a, b, c, d);
503  tmat(i, i) = 1;
504  tmat(i, j) = d;
505  tmat(j, i) = -b / tgcf;
506  tmat(j, j) = (a * c) / tgcf;
507 
508  tmat2(i, i) = c;
509  tmat2(i, j) = 1;
510  tmat2(j, i) = -(b * d) / tgcf;
511  tmat2(j, j) = a / tgcf;
512  S = tmat * S * tmat2.transpose();
513  U = U * inverse(tmat);
514  V = inverse(tmat2.transpose()) * V;
515  }
516  }
517  return;
518 }
519 
521 
522 std::vector<Eigen::Matrix3i> _unimodular_matrices(bool positive, bool negative,
523  int range = 1);
524 const std::vector<Eigen::Matrix3i> &positive_unimodular_matrices();
525 const std::vector<Eigen::Matrix3i> &negative_unimodular_matrices();
526 
527 template <int range = 1>
528 const std::vector<Eigen::Matrix3i> &unimodular_matrices() {
529  static std::vector<Eigen::Matrix3i> static_all(
530  _unimodular_matrices(true, true, range));
531  return static_all;
532 }
533 
536 } // namespace CASM
537 
538 namespace Eigen {
548 /* namespace Local { */
549 /* template<typename T> */
550 /* struct _Floor { */
551 /* T operator()(T val)const { */
552 /* return floor(val); */
553 /* } */
554 /* }; */
555 /* } */
556 /* template<typename Derived> */
557 /* CwiseUnaryOp<Local::_Floor<typename Derived::Scalar>, const Derived > */
558 /* floor(const MatrixBase<Derived> &val) { */
559 /* return val.unaryExpr(Local::_Floor<typename Derived::Scalar>()); */
560 /* } */
561 
563 template <typename Derived>
564 bool almost_zero(const MatrixBase<Derived> &val, double tol = CASM::TOL) {
565  return val.isZero(tol);
566 }
567 
568 template <typename Derived>
569 double length(const Eigen::MatrixBase<Derived> &value) {
570  return value.norm();
571 }
572 
573 //*******************************************************************************************
576 template <typename Derived>
577 Eigen::Matrix<int, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime>
578 scale_to_int(const Eigen::MatrixBase<Derived> &val, double _tol = CASM::TOL) {
579  using CASM::almost_zero;
580  using CASM::Index;
581 
582  typedef Eigen::Matrix<int, Derived::RowsAtCompileTime,
583  Derived::ColsAtCompileTime>
584  int_mat_type;
585  typedef Eigen::Matrix<double, Derived::RowsAtCompileTime,
586  Derived::ColsAtCompileTime>
587  dub_mat_type;
588 
589  int_mat_type ints(int_mat_type::Zero(val.rows(), val.cols()));
590 
591  dub_mat_type dubs(val);
592 
593  Index min_i(-1);
594  double min_coeff = 2; // all values are <=1;
595  for (Index i = 0; i < dubs.rows(); i++) {
596  for (Index j = 0; j < dubs.cols(); j++) {
597  if (almost_zero(dubs(i, j))) {
598  dubs(i, j) = 0.0;
599  } else if (std::abs(dubs(i, j)) < std::abs(min_coeff)) {
600  min_coeff = dubs(i, j);
601  min_i = i;
602  }
603  }
604  }
605  if (CASM::valid_index(min_i))
606  dubs /= std::abs(min_coeff);
607  else
608  return ints;
609 
610  // We want to multiply the miller indeces by some factor such that all indeces
611  // become integers. In order to do this we pick a tolerance to work with and
612  // round the miller indeces if they are close enough to the integer value
613  // (e.g. 2.95 becomes 3). Choosing a tolerance that is too small will result
614  // in the "primitive-slab" blowing up.
615 
616  // Begin choosing a factor and multiply all indeces by it (starting with 1).
617  // Then round the non-smallest miller indeces (smallest index requires no
618  // rounding, since it will always be a perfect integer thanks to the previous
619  // division). Next take absolute value of difference between rounded indeces
620  // and actual values (int_diff 1 & 2). If the difference for both indeces is
621  // smaller than the tolerance then you've reached the desired accuracy and the
622  // rounded indeces can be used to construct the "primitive-slab" cell. If not,
623  // increase the factor by 1 and try again, until the tolerance is met.
624  bool within_tol = false;
625 
626  dub_mat_type tdubs;
627  Index i, j;
628  for (Index factor = 1; factor < 1000 && !within_tol; factor++) {
629  tdubs = double(factor) * dubs;
630  for (i = 0; i < dubs.rows(); i++) {
631  for (j = 0; j < dubs.cols(); j++) {
632  if (!CASM::almost_zero(boost::math::round(tdubs(i, j)) - tdubs(i, j),
633  _tol))
634  break;
635  }
636  if (j < dubs.cols()) break;
637  }
638  if (dubs.rows() <= i) within_tol = true;
639  }
640 
641  if (within_tol) {
642  for (i = 0; i < dubs.rows(); i++) {
643  for (j = 0; j < dubs.cols(); j++) {
644  ints(i, j) = boost::math::round(tdubs(i, j));
645  }
646  }
647  }
648 
649  return ints;
650 }
651 
652 template <typename Derived1, typename Derived2>
653 inline bool almost_equal(const Eigen::MatrixBase<Derived1> &val1,
654  const Eigen::MatrixBase<Derived2> &val2,
655  double tol = CASM::TOL) {
656  return almost_zero(val1 - val2, tol);
657 }
658 
666 template <typename Derived>
667 inline bool is_symmetric(const Eigen::MatrixBase<Derived> &test_mat,
668  double test_tol = CASM::TOL) {
669  return almost_zero(test_mat - test_mat.transpose(), test_tol);
670 }
671 
679 template <typename Derived>
680 inline bool is_persymmetric(const Eigen::MatrixBase<Derived> &test_mat,
681  double test_tol = CASM::TOL) {
682  // Reverse order of columns and rows
683  auto rev_mat = test_mat.colwise().reverse().eval().rowwise().reverse().eval();
684  return almost_zero(test_mat - rev_mat.transpose(), test_tol);
685 }
686 
694 template <typename Derived>
695 inline bool is_bisymmetric(const Eigen::MatrixBase<Derived> &test_mat,
696  double test_tol = CASM::TOL) {
697  return (is_symmetric(test_mat, test_tol) &&
698  is_persymmetric(test_mat, test_tol));
699 }
700 
701 template <typename Derived>
702 std::vector<CASM::Index> partition_distinct_values(
703  const Eigen::MatrixBase<Derived> &value, double tol = CASM::TOL) {
704  std::vector<CASM::Index> subspace_dims;
705  CASM::Index last_i = 0;
706  for (CASM::Index i = 1; i < value.size(); i++) {
707  if (!CASM::almost_equal(value[last_i], value[i], tol)) {
708  subspace_dims.push_back(i - last_i);
709  last_i = i;
710  }
711  }
712  subspace_dims.push_back(value.size() - last_i);
713  return subspace_dims;
714 }
715 
716 template <typename Derived, typename Index = typename Derived::Index>
717 Index print_matrix_width(std::ostream &s, const Derived &m, Index width) {
718  for (Index j = 0; j < m.cols(); ++j) {
719  for (Index i = 0; i < m.rows(); ++i) {
720  std::stringstream sstr;
721  sstr.copyfmt(s);
722  sstr << m.coeff(i, j);
723  width = std::max<Index>(width, Index(sstr.str().length()));
724  }
725  }
726  return width;
727 }
728 
729 } // namespace Eigen
730 
731 #endif
std::set< std::string > & s
std::vector< Eigen::Matrix3i > _unimodular_matrices(bool positive, bool negative, int range=1)
bool is_diagonal(const Eigen::MatrixBase< Derived > &M, double tol=TOL)
Check if Eigen::Matrix is diagonal.
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)
bool is_unimodular(const Eigen::MatrixBase< Derived > &M, double tol)
Check if Eigen::Matrix is unimodular.
void smith_normal_form(const Eigen::MatrixBase< DerivedIn > &M, Eigen::MatrixBase< DerivedOut > &U, Eigen::MatrixBase< DerivedOut > &S, Eigen::MatrixBase< DerivedOut > &V)
Return the smith normal form, M == U*S*V.
Derived::Scalar triple_product(const Derived &vec0, const Derived &vec1, const Derived &vec2)
Derived::Scalar matrix_minor(const Eigen::MatrixBase< Derived > &M, int row, int col)
Return the minor of integer Matrix M element row, col.
Eigen::CwiseUnaryOp< decltype(Local::lround_l< typename Derived::Scalar >), const Derived > lround(const Eigen::MatrixBase< Derived > &val)
Round Eigen::MatrixXd to Eigen::MatrixXl.
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.
Eigen::Matrix< typename Derived::Scalar, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime > inverse(const Eigen::MatrixBase< Derived > &M)
Return the integer inverse matrix of an invertible integer matrix.
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)
const std::vector< Eigen::Matrix3i > & unimodular_matrices()
Eigen::Matrix< typename Derived::Scalar, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime > cofactor(const Eigen::MatrixBase< Derived > &M)
Return cofactor matrix.
Eigen::Matrix< typename Derived::Scalar, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime > adjugate(const Eigen::MatrixBase< Derived > &M)
Return adjugate matrix.
bool is_integer(const Eigen::MatrixBase< Derived > &M, double tol)
Check if Eigen::Matrix is integer.
IdentitySymRepBuilder Identity()
Eigen::Matrix< Scalar, 3, 3 > _elementary_hermite_op(Scalar a, Scalar b, Scalar i, Scalar j)
Return an elementary hermite transformation.
Main CASM namespace.
Definition: APICommand.hh:8
bool almost_equal(ClusterInvariants const &A, ClusterInvariants const &B, double tol)
Check if ClusterInvariants are equal.
Eigen::MatrixXd MatrixXd
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:277
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 colmajor_lex_compare(const Eigen::MatrixBase< Derived > &A, const Eigen::MatrixBase< Derived > &B, double tol)
Floating point lexicographical comparison with tol.
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
Definition: CASM_math.hh:104
bool float_lexicographical_compare(const Eigen::Ref< const Eigen::MatrixXd > &A, const Eigen::Ref< const Eigen::MatrixXd > &B, double tol)
Floating point lexicographical comparison with tol.
ReturnArray< Index > partition_distinct_values(const Eigen::MatrixBase< Derived > &value, double tol=TOL)
bool valid_index(Index i)
Definition: definitions.cc:5
T * end_ptr(std::vector< T > &container)
Return pointer one past end of vector. Equivalent to convainer.data()+container.size()
Definition: algorithm.hh:142
INDEX_TYPE Index
For long integer indexing:
Definition: definitions.hh:39
Eigen::VectorXd VectorXd
Derived::PlainObject reduced_column_echelon(Eigen::MatrixBase< Derived > const &M, double _tol)
bool is_persymmetric(const Eigen::MatrixBase< Derived > &test_mat, double test_tol=CASM::TOL)
bool is_symmetric(const Eigen::MatrixBase< Derived > &test_mat, double test_tol=CASM::TOL)
double length(const Eigen::MatrixBase< Derived > &value)
Eigen::Matrix< int, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime > scale_to_int(const Eigen::MatrixBase< Derived > &val, double _tol=CASM::TOL)
Index print_matrix_width(std::ostream &s, const Derived &m, Index width)
bool is_bisymmetric(const Eigen::MatrixBase< Derived > &test_mat, double test_tol=CASM::TOL)
auto lround_l
static bool _compare(T const &a, T const &b, double tol)
auto iround_l
auto round_l