21 void get_Hermitian(Eigen::MatrixXcd &original_mat, Eigen::MatrixXcd &hermitian_mat, Eigen::MatrixXcd &antihermitian_mat) {
23 Eigen::MatrixXcd conj_trans = original_mat.conjugate().transpose();
25 hermitian_mat = 0.5 * (original_mat + conj_trans);
26 antihermitian_mat = 0.5 * (original_mat - conj_trans);
39 if((mat - mat.conjugate().transpose()).isZero(
TOL)) {
63 if(M.rows() != M.cols()) {
64 throw std::runtime_error(
65 std::string(
"Error in hermite_normal_form(const Eigen::MatrixXi &M)\n") +
66 " M must be square.");
70 throw std::runtime_error(
71 std::string(
"Error in hermite_normal_form(const Eigen::MatrixXi &M)\n") +
72 " M must be full rank.");
75 Eigen::MatrixXi V = Eigen::MatrixXi::Identity(M.rows(), M.cols());
76 Eigen::MatrixXi H = M;
85 for(i = N - 1; i >= 0; i--) {
89 for(c = i - 1; c >= 0; c--) {
91 H.col(c).swap(H.col(i));
92 V.row(c).swap(V.row(i));
105 for(c = i - 1; c >= 0; c--) {
109 while(H(i, c) != 0) {
112 H.col(c) += H.col(i);
113 V.row(i) -= V.row(c);
116 while(H(i, i) <= H(i, c) && H(i, c) != 0) {
117 H.col(c) -= H.col(i);
118 V.row(i) += V.row(c);
121 while(H(i, c) < H(i, i) && H(i, c) != 0) {
122 H.col(i) -= H.col(c);
123 V.row(c) += V.row(i);
134 for(c = 1; c < H.cols(); c++) {
136 for(r = c - 1; r >= 0; r--) {
138 H.col(c) += H.col(r);
139 V.row(r) -= V.row(c);
141 while(H(r, c) >= H(r, r)) {
142 H.col(c) -= H.col(r);
143 V.row(r) += V.row(c);
149 return std::make_pair(H, V);
154 double angle(
const Eigen::Ref<const Eigen::Vector3d> &a,
const Eigen::Ref<const Eigen::Vector3d> &b) {
155 return acos(a.dot(b) / (a.norm() * b.norm()));
160 const Eigen::Ref<const Eigen::Vector3d> &b,
161 const Eigen::Ref<const Eigen::Vector3d> &pos_ref) {
162 if(pos_ref.dot(a.cross(b)) < 0) {
172 for(
int i = 0; i < M.rows(); i++) {
173 for(
int j = 0; j < M.cols(); j++) {
183 std::vector<Eigen::Matrix3i> uni_det_mats;
184 int totalmats = 3480;
186 if(positive && negative) {
187 totalmats = totalmats * 2;
190 uni_det_mats.reserve(totalmats);
194 for(; transmat_count.
valid(); ++transmat_count) {
195 if(positive && transmat_count.
current().determinant() == 1) {
196 uni_det_mats.push_back(transmat_count.
current());
199 if(negative && transmat_count.
current().determinant() == -1) {
200 uni_det_mats.push_back(transmat_count.
current());
209 return static_positive;
214 return static_negative;
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 Container & current() const
A Counter allows looping over many incrementing variables in one loop.
bool is_Hermitian(Eigen::MatrixXcd &mat)
void get_Hermitian(Eigen::MatrixXcd &original_mat, Eigen::MatrixXcd &hermitian_mat, Eigen::MatrixXcd &antihermitian_mat)
const std::vector< Eigen::Matrix3i > & negative_unimodular_matrices()
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()
std::pair< Eigen::MatrixXi, Eigen::MatrixXi > hermite_normal_form(const Eigen::MatrixXi &M)
Return the hermite normal form, M == H*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.