CASM
AClustersApproachtoStatisticalMechanics
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules
LinearAlgebra.cc
Go to the documentation of this file.
3 
4 #include "casm/external/boost.hh"
5 
6 namespace CASM {
7 
8  //*******************************************************************************************
19  //*******************************************************************************************
20  //Added by Ivy 11/28/12
21  void get_Hermitian(Eigen::MatrixXcd &original_mat, Eigen::MatrixXcd &hermitian_mat, Eigen::MatrixXcd &antihermitian_mat) {
22 
23  Eigen::MatrixXcd conj_trans = original_mat.conjugate().transpose();
24 
25  hermitian_mat = 0.5 * (original_mat + conj_trans);
26  antihermitian_mat = 0.5 * (original_mat - conj_trans);
27  }
28 
29  //*******************************************************************************************
35  //*******************************************************************************************
36  //Added by Ivy 11/28/12
37  bool is_Hermitian(Eigen::MatrixXcd &mat) {
38 
39  if((mat - mat.conjugate().transpose()).isZero(TOL)) {
40  return true;
41  }
42  return false;
43  }
44 
45 
46 
61  std::pair<Eigen::MatrixXi, Eigen::MatrixXi> hermite_normal_form(const Eigen::MatrixXi &M) {
62 
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.");
67  }
68 
69  if(boost::math::iround(M.cast<double>().determinant()) == 0) {
70  throw std::runtime_error(
71  std::string("Error in hermite_normal_form(const Eigen::MatrixXi &M)\n") +
72  " M must be full rank.");
73  }
74 
75  Eigen::MatrixXi V = Eigen::MatrixXi::Identity(M.rows(), M.cols());
76  Eigen::MatrixXi H = M;
77 
78 
79 
80  int N = M.rows();
81  int i, r, c;
82 
83 
84  // get non-zero entries along H diagonal
85  for(i = N - 1; i >= 0; i--) {
86 
87  // swap columns if necessary to get non-zero entry at H(i,i)
88  if(H(i, i) == 0) {
89  for(c = i - 1; c >= 0; c--) {
90  if(H(i, c) != 0) {
91  H.col(c).swap(H.col(i));
92  V.row(c).swap(V.row(i));
93  break;
94  }
95  }
96  }
97 
98  // get positive entry at H(i,i)
99  if(H(i, i) < 0) {
100  H.col(i) *= -1;
101  V.row(i) *= -1;
102  }
103 
104  // do column operations to get zeros to left of H(i,i)
105  for(c = i - 1; c >= 0; c--) {
106  if(H(i, c) == 0)
107  continue;
108 
109  while(H(i, c) != 0) {
110 
111  while(H(i, c) < 0) {
112  H.col(c) += H.col(i);
113  V.row(i) -= V.row(c);
114  }
115 
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);
119  }
120 
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);
124  }
125 
126  }
127  }
128  }
129 
130  // now we have M = H*V, where H is upper triangular
131  // so use column operations to enforce 0 <= H(i,c) < H(i,i) for c > i
132 
133  // columns left to right
134  for(c = 1; c < H.cols(); c++) {
135  // rows above the diagonal to the top
136  for(r = c - 1; r >= 0; r--) {
137  while(H(r, c) < 0) {
138  H.col(c) += H.col(r);
139  V.row(r) -= V.row(c);
140  }
141  while(H(r, c) >= H(r, r)) {
142  H.col(c) -= H.col(r);
143  V.row(r) += V.row(c);
144  }
145  }
146  }
147 
148  // now we have M = H*V
149  return std::make_pair(H, V);
150  }
151 
152 
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()));
156  }
157 
159  double signed_angle(const Eigen::Ref<const Eigen::Vector3d> &a,
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) {
163  return -angle(a, b);
164  }
165  else
166  return angle(a, b);
167  }
168 
171  Eigen::MatrixXd Mp(M);
172  for(int i = 0; i < M.rows(); i++) {
173  for(int j = 0; j < M.cols(); j++) {
174  if(std::abs(std::round(M(i, j)) - M(i, j)) < tol) {
175  Mp(i, j) = std::round(M(i, j));
176  }
177  }
178  }
179  return Mp;
180  }
181 
182  std::vector<Eigen::Matrix3i> _unimodular_matrices(bool positive, bool negative) {
183  std::vector<Eigen::Matrix3i> uni_det_mats;
184  int totalmats = 3480;
185 
186  if(positive && negative) {
187  totalmats = totalmats * 2;
188  }
189 
190  uni_det_mats.reserve(totalmats);
191 
192  EigenCounter<Eigen::Matrix3i> transmat_count(Eigen::Matrix3i::Constant(-1), Eigen::Matrix3i::Constant(1), Eigen::Matrix3i::Constant(1));
193 
194  for(; transmat_count.valid(); ++transmat_count) {
195  if(positive && transmat_count.current().determinant() == 1) {
196  uni_det_mats.push_back(transmat_count.current());
197  }
198 
199  if(negative && transmat_count.current().determinant() == -1) {
200  uni_det_mats.push_back(transmat_count.current());
201  }
202  }
203 
204  return uni_det_mats;
205  }
206 
207  const std::vector<Eigen::Matrix3i> &positive_unimodular_matrices() {
208  static std::vector<Eigen::Matrix3i> static_positive(_unimodular_matrices(true, false));
209  return static_positive;
210  }
211 
212  const std::vector<Eigen::Matrix3i> &negative_unimodular_matrices() {
213  static std::vector<Eigen::Matrix3i> static_negative(_unimodular_matrices(true, false));
214  return static_negative;
215  }
216 
217  const std::vector<Eigen::Matrix3i> &unimodular_matrices() {
218  static std::vector<Eigen::Matrix3i> static_all(_unimodular_matrices(true, false));
219  return static_all;
220  }
221 }
222 
Eigen::MatrixXd MatrixXd
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].
A Counter allows looping over many incrementing variables in one loop.
Definition: Counter.hh:71
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()
Main CASM namespace.
Definition: complete.cpp:8
const double TOL
const std::vector< Eigen::Matrix3i > & unimodular_matrices()
double tol
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.
int round(double val)
Definition: CASM_math.cc:6