CASM  1.1.0
A Clusters Approach to Statistical Mechanics
Symmetrizer.cc
Go to the documentation of this file.
2 
4 #include "casm/misc/CASM_math.hh"
7 
8 namespace CASM {
9 
10 namespace SymRepTools_v2 {
11 
40  MatrixRep const &rep, GroupIndices const &head_group,
41  Eigen::MatrixXcd const &irrep_subspace, double vec_compare_tol,
42  GroupIndicesOrbitVector const &cyclic_subgroups,
43  GroupIndicesOrbitVector const &all_subgroups, bool use_all_subgroups) {
44  auto const &sgroups = (use_all_subgroups ? all_subgroups : cyclic_subgroups);
45 
46  std::vector<Eigen::VectorXcd> tdirs;
48  Index dim = rep[0].rows();
49 
50  // Loop over small (i.e., cyclic) subgroups and hope that each special
51  // direction is invariant to at least one small subgroup
52  for (auto const &orbit : sgroups) {
53  // Reynolds for small subgroup *(orbit.begin()) in irrep_subspace i
54  R.setZero(dim, dim);
55 
56  for (Index element_index : *(orbit.begin())) {
57  R += rep[element_index];
58  }
59 
60  if ((R * irrep_subspace).norm() < TOL) continue;
61 
62  // Find spanning vectors of column space of R*irrep_space, which is
63  // projection of irrep_space into its invariant component
64  auto QR = (R * irrep_subspace).colPivHouseholderQr();
65  QR.setThreshold(TOL);
66  // If only one spanning vector, it is special direction
67  if (QR.rank() > 1) continue;
68  Eigen::MatrixXcd Q = QR.matrixQ();
69 
70  // Convert from irrep_subspace back to total space and push_back
71  tdirs.push_back(Q.col(0));
72  tdirs.push_back(-Q.col(0));
73  }
74 
75  // t_result may contain duplicates, or elements that are equivalent by
76  // symmetry. To discern more info, we need to exclude duplicates and find
77  // the orbit of the directions. this should also
78  // reveal the invariant subgroups.
79 
80  VectorSymCompare sym_compare{rep, vec_compare_tol};
81  std::set<SimpleOrbit<VectorSymCompare>> orbit_result;
82  for (Eigen::VectorXcd const &direction : tdirs) {
83  orbit_result.emplace(direction, head_group.begin(), head_group.end(),
84  sym_compare);
85  }
87  for (auto const &orbit : orbit_result) {
88  result.emplace_back(orbit.begin(), orbit.end());
89  }
90 
91  if (use_all_subgroups || result.size() >= irrep_subspace.cols()) {
92  return result;
93  } else {
94  return make_irrep_special_directions(rep, head_group, irrep_subspace,
95  vec_compare_tol, cyclic_subgroups,
96  all_subgroups, true);
97  }
98 }
99 
102  multivector<Eigen::VectorXcd>::X<2> const &irrep_special_directions,
103  Eigen::MatrixXcd const &irrep_subspace, double vec_compare_tol) {
104  // Four strategies, in order of desparation
105  // 1) find a spanning set of orthogonal axes within a single orbit of special
106  // directions 2) find a spanning set of orthogonal axes within the total set
107  // of special directions 3) perform qr decomposition on lowest-multiplicity
108  // orbit to find spanning set of axes 4) find column-echelon form of
109  // irrep_subspace matrix to get a sparse/pretty set of axes
110  Eigen::MatrixXcd result;
111  Index dim = irrep_subspace.cols();
112  Index min_mult = 10000;
113  bool orb_orthog = false;
114  bool tot_orthog = false;
115 
116  Eigen::MatrixXcd axes, orb_axes, tot_axes;
117  Index tot_col(0);
118  tot_axes.setZero(irrep_subspace.rows(), dim);
119 
120  for (auto const &orbit : irrep_special_directions) {
121  // Strategy 1
122  if ((orb_orthog && orbit.size() < min_mult) || !orb_orthog) {
123  orb_axes.setZero(irrep_subspace.rows(), dim);
124  Index col = 0;
125  for (auto const &el : orbit) {
126  if (almost_zero((el.adjoint() * orb_axes).eval(), vec_compare_tol)) {
127  if (col < orb_axes.cols())
128  orb_axes.col(col++) = el;
129  else {
130  std::stringstream errstr;
131  errstr
132  << "Error in irrep_symmtrizer_from_directions(). Constructing "
133  "coordinate axes from special directions of space spanned "
134  "by row vectors:\n "
135  << irrep_subspace.transpose()
136  << "\nAxes collected thus far are the row vectors:\n"
137  << orb_axes.transpose()
138  << "\nBut an additional orthogonal row vector has been found:\n"
139  << el.transpose()
140  << "\nindicating that irrep_subspace matrix is malformed.";
141  throw std::runtime_error(errstr.str());
142  }
143  }
144  }
145  if (col == dim) {
146  // std::cout << "PLAN A-- col: " << col << "; dim: " << dim << ";
147  // min_mult: " << min_mult << "; orthog: " << orb_orthog << ";\naxes:
148  // \n"
149  // << axes << "\norb_axes: \n" << orb_axes << "\n\n";
150  orb_orthog = true;
151  min_mult = orbit.size();
152  axes = orb_axes;
153  }
154  }
155 
156  // Greedy(ish) implementation of strategy 2 -- may not find a solution, even
157  // if it exists
158  if (!orb_orthog && !tot_orthog) {
159  for (auto const &el : orbit) {
160  if (almost_zero((el.adjoint() * tot_axes).eval(), vec_compare_tol)) {
161  if (tot_col < tot_axes.cols())
162  tot_axes.col(tot_col++) = el;
163  else {
164  std::stringstream errstr;
165  errstr
166  << "Error in irrep_symmtrizer_from_directions(). Constructing "
167  "coordinate axes from special directions of space spanned "
168  "by row vectors:\n "
169  << irrep_subspace.transpose()
170  << "\nAxes collected thus far are the row vectors:\n"
171  << tot_axes.transpose()
172  << "\nBut an additional orthogonal row vector has been found:\n"
173  << el.transpose()
174  << "\nindicating that irrep_subspace matrix is malformed.";
175  throw std::runtime_error(errstr.str());
176  }
177  }
178  }
179  if (tot_col == dim) {
180  // std::cout << "PLAN B-- col: " << tot_col << "; dim: " << dim << ";
181  // min_mult: " << min_mult << "; orthog: " << tot_orthog << ";\naxes:
182  // \n"
183  // << axes << "\ntot_axes: \n" << tot_axes << "\n\n";
184  tot_orthog = true;
185  axes = tot_axes;
186  }
187  }
188 
189  // Strategy 3
190  if (!orb_orthog && !tot_orthog && orbit.size() < min_mult) {
191  orb_axes.setZero(irrep_subspace.rows(), orbit.size());
192  for (Index col = 0; col < orbit.size(); ++col) {
193  orb_axes.col(col) = orbit[col];
194  }
195  // std::cout << "PLAN C-- dim: " << dim << "; min_mult: " << min_mult <<
196  // "; orthog: " << orb_orthog << ";\naxes: \n" << axes;
197  min_mult = orbit.size();
198  axes = Eigen::MatrixXcd(orb_axes.colPivHouseholderQr().matrixQ())
199  .leftCols(dim);
200  // std::cout << "\norb_axes: \n" << orb_axes << "\n\n";
201  }
202  }
203  // std::cout << "axes: \n" << axes << "\n";
204  if (axes.cols() == 0) {
205  result = irrep_subspace.colPivHouseholderQr().solve(
206  vector_space_prepare(irrep_subspace, vec_compare_tol));
207  } else {
208  // Strategy 4
209  result = irrep_subspace.colPivHouseholderQr().solve(axes);
210  }
211 
212  // std::cout << "result: \n" << result << "\n"
213  //<< "irrep_subspace*result: \n" << irrep_subspace *result << "\n";
214  return result; //.transpose();
215 }
216 
217 } // namespace SymRepTools_v2
218 
219 } // namespace CASM
Eigen::MatrixXcd make_irrep_symmetrizer_matrix(multivector< Eigen::VectorXcd >::X< 2 > const &irrep_special_directions, Eigen::MatrixXcd const &irrep_subspace, double vec_compare_tol)
Make an irreducible space symmetrizer matrix using special directions.
Definition: Symmetrizer.cc:101
std::set< Index > GroupIndices
std::vector< GroupIndicesOrbit > GroupIndicesOrbitVector
multivector< Eigen::VectorXcd >::X< 2 > make_irrep_special_directions(MatrixRep const &rep, GroupIndices const &head_group, Eigen::MatrixXcd const &irrep_subspace, double vec_compare_tol, GroupIndicesOrbitVector const &cyclic_subgroups, GroupIndicesOrbitVector const &all_subgroups, bool use_all_subgroups=false)
Find high-symmetry directions in a irreducible space.
Definition: Symmetrizer.cc:39
Eigen::MatrixXcd vector_space_prepare(Eigen::MatrixXcd const &vector_space, double tol)
Vector space preparation for comparison.
std::vector< Eigen::MatrixXd > MatrixRep
Main CASM namespace.
Definition: APICommand.hh:8
Eigen::MatrixXd MatrixXd
const double TOL
Definition: definitions.hh:30
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
Definition: CASM_math.hh:104
INDEX_TYPE Index
For long integer indexing:
Definition: definitions.hh:39
Used for constructing SimpleOrbit of high symmetry direction vectors.
Shortcut for multidimensional vector (std::vector< std::vector< ...)
Definition: multivector.hh:26
typename multivector_impl::multivector_tmp< T, N >::type X
Definition: multivector.hh:28