7 #ifndef LINEARALGEBRA_HH
8 #define LINEARALGEBRA_HH
16 #include <boost/math/special_functions/round.hpp>
18 #include "casm/external/Eigen/Dense"
19 #include "casm/external/Eigen/Eigenvalues"
33 void get_Hermitian(Eigen::MatrixXcd &original_mat, Eigen::MatrixXcd &hermitian_mat, Eigen::MatrixXcd &antihermitian_mat);
35 void poly_fit(Eigen::VectorXcd &xvec, Eigen::VectorXcd &yvec, Eigen::VectorXcd &coeffs,
int degree);
41 double angle(
const Eigen::Ref<const Eigen::Vector3d> &a,
const Eigen::Ref<const Eigen::Vector3d> &b);
44 double signed_angle(
const Eigen::Ref<const Eigen::Vector3d> &a,
45 const Eigen::Ref<const Eigen::Vector3d> &b,
46 const Eigen::Ref<const Eigen::Vector3d> &pos_ref);
52 template<
typename Derived>
55 const Derived &vec2) {
56 return (vec0.cross(vec1)).
dot(vec2);
60 template<
typename Derived>
62 for(
Index i = 0; i < M.rows(); i++) {
63 for(
Index j = 0; j < M.cols(); j++) {
72 template<
typename Derived>
78 template<
typename Derived>
80 return M.isDiagonal(
tol);
91 template<
typename Derived>
92 Eigen::CwiseUnaryOp< decltype(std::ptr_fun(boost::math::iround<typename Derived::Scalar>)) ,
const Derived >
93 iround(
const Eigen::MatrixBase<Derived> &val) {
94 return val.unaryExpr(std::ptr_fun(boost::math::iround<typename Derived::Scalar>));
105 template<
typename Derived>
106 Eigen::CwiseUnaryOp< decltype(std::ptr_fun(boost::math::lround<typename Derived::Scalar>)) ,
const Derived >
107 lround(
const Eigen::MatrixBase<Derived> &val) {
108 return val.unaryExpr(std::ptr_fun(boost::math::lround<typename Derived::Scalar>));
121 template<
typename Derived>
122 typename Derived::Scalar
matrix_minor(
const Eigen::MatrixBase<Derived> &M,
int row,
int col) {
125 Eigen::Matrix <
typename Derived::Scalar,
126 Derived::RowsAtCompileTime - 1,
127 Derived::ColsAtCompileTime - 1 >
128 subM(M.rows() - 1, M.cols() - 1);
130 for(
int i = 0; i < M.rows(); i++) {
131 for(
int j = 0; j < M.cols(); j++) {
132 if(i == row || j == col)
134 (i < row) ? _i = i : _i = i - 1;
135 (j < col) ? _j = j : _j = j - 1;
136 subM(_i, _j) = M(i, j);
141 return subM.determinant();
152 template<
typename Derived>
153 Eigen::Matrix<
typename Derived::Scalar,
154 Derived::RowsAtCompileTime,
155 Derived::ColsAtCompileTime>
157 Eigen::Matrix<
typename Derived::Scalar,
158 Derived::RowsAtCompileTime,
159 Derived::ColsAtCompileTime>
160 Mcof(M.rows(), M.cols());
161 for(
int i = 0; i < Mcof.rows(); i++) {
162 for(
int j = 0; j < Mcof.cols(); j++) {
180 template<
typename Derived>
181 Eigen::Matrix<
typename Derived::Scalar,
182 Derived::RowsAtCompileTime,
183 Derived::ColsAtCompileTime>
188 namespace normal_form_impl {
197 template<
typename Scalar>
199 typedef Eigen::Matrix<Scalar, 3, 3> matrix_type;
200 matrix_type tmat = matrix_type::Identity();
201 Scalar tgcf =
extended_gcf(a, b, tmat(i, i), tmat(i, j));
203 return matrix_type::Identity();
205 tmat(j, i) = -b / tgcf;
206 tmat(j, j) = a / tgcf;
218 template<
typename Derived>
219 Eigen::Matrix<
typename Derived::Scalar,
220 Derived::RowsAtCompileTime,
221 Derived::ColsAtCompileTime>
222 inverse(
const Eigen::MatrixBase<Derived> &M) {
223 return adjugate(M) / M.determinant();
236 template<
typename DerivedIn,
typename DerivedOut>
238 Eigen::MatrixBase<DerivedOut> &U,
239 Eigen::MatrixBase<DerivedOut> &S,
240 Eigen::MatrixBase<DerivedOut> &V) {
242 static_assert(std::is_same<typename DerivedIn::Scalar, typename DerivedOut::Scalar>::value,
243 "ALL ARGUMENTS TO CASM::smith_normal_form() MUST BE BASED ON SAME SCALAR TYPE!");
244 using namespace normal_form_impl;
245 typedef typename DerivedOut::Scalar Scalar;
247 U = V = DerivedOut::Identity();
256 for(j = 0; j < 3; j++) {
258 for(i = j + 1; i < 3; i++) {
259 if(S(i, j) == 0)
continue;
260 tmat = _elementary_hermite_op<Scalar>(S(j, j), S(i, j), j, i);
266 for(i = j + 2; i < 3; i++) {
267 if(S(j, i) == 0)
continue;
268 tmat = _elementary_hermite_op<Scalar>(S(j, j + 1), S(j, i), j + 1, i);
269 S = S * tmat.transpose();
270 V =
inverse(tmat.transpose()) * V;
275 while(!S.isDiagonal()) {
278 for(b = 0; b < 2; b++) {
286 for(i = 0; i < 3; i++) {
295 Scalar q = S(b, b + 1) / S(b, b);
296 if(S(b, b + 1) % S(b, b) < 0)
298 tmat = DerivedOut::Identity();
300 S = S * tmat.transpose();
301 V =
inverse(tmat.transpose()) * V;
306 tmat = DerivedOut::Identity();
309 tmat(b + 1, b + 1) = 0;
311 S = S * tmat.transpose();
312 V =
inverse(tmat.transpose()) * V;
319 tmat = _elementary_hermite_op<Scalar>(S(b, b), S(b, b + 1), b, b + 1);
320 S = S * tmat.transpose();
321 V =
inverse(tmat.transpose()) * V;
322 for(j = 0; j < 2; j++) {
323 tmat = _elementary_hermite_op<Scalar>(S(j, j), S(j + 1, j), j, j + 1);
330 tmat = _elementary_hermite_op<Scalar>(S(j, j + 1), S(j, j + 2), j + 1, j + 2);
331 S = S * tmat.transpose();
332 V =
inverse(tmat.transpose()) * V;
337 for(j = 0; j < 3; j++) {
339 for(i = 0; i < 3; i++) {
347 for(i = 0; i < 3; i++) {
348 for(j = i + 1; j < 3; j++) {
349 if(S(i, i) > S(j, j)) {
350 S.row(i).swap(S.row(j));
351 S.col(i).swap(S.col(j));
352 U.col(i).swap(U.col(j));
353 V.row(i).swap(V.row(j));
358 for(i = 0; i < 3; i++) {
359 if(S(i, i) == 0)
continue;
360 for(j = i + 1; j < 3; j++) {
361 if(S(j, j) % S(i, i) == 0)
continue;
363 tmat = DerivedOut::Identity();
364 DerivedOut tmat2(tmat);
365 Scalar a(S(i, i)), b(S(j, j)), c, d, tgcf;
369 tmat(j, i) = -b / tgcf;
370 tmat(j, j) = (a * c) / tgcf;
374 tmat2(j, i) = -(b * d) / tgcf;
375 tmat2(j, j) = a / tgcf;
376 S = tmat * S * tmat2.transpose();
378 V =
inverse(tmat2.transpose()) * V;
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].
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
bool is_Hermitian(Eigen::MatrixXcd &mat)
void get_Hermitian(Eigen::MatrixXcd &original_mat, Eigen::MatrixXcd &hermitian_mat, Eigen::MatrixXcd &antihermitian_mat)
IntType extended_gcf(IntType i1, IntType i2, IntType &p1, IntType &p2)
Calculate greatest common factor of two integers, and bezout coefficients.
const std::vector< Eigen::Matrix3i > & negative_unimodular_matrices()
void poly_fit(Eigen::VectorXcd &xvec, Eigen::VectorXcd &yvec, Eigen::VectorXcd &coeffs, int degree)
Derived::Scalar triple_prod(const Derived &vec0, const Derived &vec1, const Derived &vec2)
const std::vector< Eigen::Matrix3i > & unimodular_matrices()
std::vector< Eigen::Matrix3i > _unimodular_matrices(bool positive, bool negative)
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 ...
const std::vector< Eigen::Matrix3i > & positive_unimodular_matrices()
Eigen::Matrix< typename Derived::Scalar, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime > adjugate(const Eigen::MatrixBase< Derived > &M)
Return adjugate matrix.
EigenIndex Index
For long integer indexing:
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.
Eigen::CwiseUnaryOp< decltype(std::ptr_fun(boost::math::lround< typename Derived::Scalar >)), const Derived > lround(const Eigen::MatrixBase< Derived > &val)
Round Eigen::MatrixXd to Eigen::MatrixXl.
T dot(const Tensor< T > &LHS, const Tensor< T > &RHS)
std::pair< Eigen::MatrixXi, Eigen::MatrixXi > hermite_normal_form(const Eigen::MatrixXi &M)
Return the hermite normal form, M == H*V.
bool is_integer(const Eigen::MatrixBase< Derived > &M, double tol)
Check if Eigen::Matrix is integer.
Derived::Scalar matrix_minor(const Eigen::MatrixBase< Derived > &M, int row, int col)
Return the minor of integer Matrix M element row, col.
bool is_diagonal(const Eigen::MatrixBase< Derived > &M, double tol=TOL)
Check if Eigen::Matrix is diagonal.
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.
Eigen::CwiseUnaryOp< decltype(std::ptr_fun(boost::math::iround< typename Derived::Scalar >)), const Derived > iround(const Eigen::MatrixBase< Derived > &val)
Round Eigen::MatrixXd to Eigen::MatrixXi.
Eigen::MatrixXd pretty(const Eigen::MatrixXd &M, double tol)
Round entries that are within tol of being integer to that integer value.
Eigen::Matrix< typename Derived::Scalar, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime > cofactor(const Eigen::MatrixBase< Derived > &M)
Return cofactor matrix.
bool almost_equal(const GenericCluster< CoordType > &LHS, const GenericCluster< CoordType > &RHS, double tol)
bool is_unimodular(const Eigen::MatrixBase< Derived > &M, double tol)
Check if Eigen::Matrix is unimodular.