CASM
AClustersApproachtoStatisticalMechanics
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules
SymGroupRep.cc
Go to the documentation of this file.
2 
3 #include <numeric>
4 #include "casm/external/Eigen/CASM_AddOns"
5 #include "casm/misc/CASM_math.hh"
6 
10 
11 
12 namespace CASM {
13 
15  Array<SymOpRepresentation * > (RHS.size(), NULL) {
16  (*this) = RHS;
17  }
18 
19  //*******************************************************************************************
20 
22  clear();
23  }
24 
25  //*******************************************************************************************
26 
29  clear();
30  if(RHS.size() > 0 && has_valid_master() && master_group().size() != RHS.size()) {
31  throw std::runtime_error("Invalid assignment of SymGroupRep. Sizes are incompatible.\n");
32  }
33  resize(RHS.size(), NULL);
34  for(Index i = 0; i < RHS.size(); i++) {
35  if(RHS[i])
36  set_rep(i, *RHS[i]);
37  }
38  return *this;
39  }
40 
41  //*******************************************************************************************
42 
43  void SymGroupRep::set_master_group(const MasterSymGroup &master, const SymGroupRepID &_rep_ID) {
44  m_master_group = &master;
45  if(_rep_ID.empty() || &(master.representation(_rep_ID)) != this) {
46  throw std::runtime_error(std::string("SymGroupRep::set_master_group() attempted to assign SymGroupRepID that does not match the current SymGroupRep!\n"));
47  }
48  m_rep_ID = _rep_ID;
49  if(size() == 0)
51  else if(size() == master.size()) {
52  for(Index i = 0; i < size(); i++) {
53  if(at(i))
54  at(i)->set_identifiers(master, m_rep_ID, i);
55  }
56  }
57  else {
58  throw std::runtime_error(std::string("SymGroupRep::set_master_group() passed new master whose size is incompatible with the size\n") +
59  "of the current representation.\n");
60  }
61  }
62 
63  //*******************************************************************************************
64 
65  void SymGroupRep::set_rep(const SymOp &base_op, const SymOpRepresentation &new_rep) const {
66  if(!has_valid_master()) {
67  std::cerr << "CRITICAL ERROR: In SymGroupRep::set_rep(), you are trying to assign the representation of a SymOp whose factor_group is not specified!\n"
68  << " Exiting...\n";
69  assert(0);
70  exit(1);
71  }
72  if(valid_index(base_op.index()))
73  return set_rep(base_op.index(), new_rep);
74 
75  //else:
76  return set_rep(master_group().find_periodic(base_op), new_rep);
77 
78  }
79 
80  //*******************************************************************************************
81 
82  void SymGroupRep::set_rep(const SymOpRepresentation &base_op, const SymOpRepresentation &new_rep) const {
83  if(!has_valid_master()) {
84  std::cerr << "CRITICAL ERROR: In SymGroupRep::set_rep(), you are trying to assign the representation of a SymOpRepresentation whose factor_group is not specified!\n"
85  << " Exiting...\n";
86  assert(0);
87  exit(1);
88  }
89  if(valid_index(base_op.index()))
90  set_rep(base_op.index(), new_rep);
91  else {
92  std::cerr << "CRITICAL ERROR: In SymGroupRep::set_rep(), you are trying to assign the representation of a SymOpRepresentation whose index is not specified!\n"
93  << " Exiting...\n";
94  assert(0);
95  exit(1);
96  }
97 
98  }
99 
100  //*******************************************************************************************
101 
102  void SymGroupRep::set_rep(Index op_index, const SymOpRepresentation &new_rep) const {
103 
104  assert(valid_index(op_index) && op_index < size() && "In SymGroupRep::set_rep(), reference representation is improperly initialized.");
105  if(at(op_index)) {
106  std::cerr << "CRITICAL ERROR: In SymGroupRep::set_rep(), representation already exists for operation " << op_index << ".\n"
107  << " Exiting...\n";
108  assert(0);
109  exit(1);
110  }
111 
112  SymOpRepresentation *tcopy = new_rep.copy();
113  if(has_valid_master())
114  tcopy->set_identifiers(master_group(), m_rep_ID, op_index);
115 
116  // avoid doing this elsewhere in CASM
117  const_cast<SymOpRepresentation *&>(at(op_index)) = tcopy;
118 
119  }
120 
121  //*******************************************************************************************
122 
124  return master_group().add_representation(*this);
125  }
126  //*******************************************************************************************
127 
129  for(Index i = 0; i < size(); i++)
130  delete at(i);
132  }
133 
134  //John G 050513
135 
136  //*******************************************************************************************
137 
138  void SymGroupRep::print_permutation(std::ostream &stream) const {
139  for(Index i = 0; i < this->size(); i++) {
140  if(at(i)->get_permutation())
141  stream << *(at(i)->get_permutation()) << '\n';
142  else
143  stream << "nullptr\n";
144  }
145  return;
146  }
147 
148  //\John G
149 
150  //*******************************************************************************************
151 
152  void SymGroupRep::print_MatrixXd(std::ostream &stream) const {
153  for(Index i = 0; i < size(); i++) {
154  stream << "SymRep Matrix " << i + 1 << " of " << size() << ":\n";
155  if(at(i)->get_MatrixXd())
156  stream << *(at(i)->get_MatrixXd()) << '\n';
157  else
158  stream << "nullptr\n";
159  stream << "\n";
160  }
161  std::cout << "\n";
162  return;
163  }
164 
165  //*******************************************************************************************
166 
167  void SymGroupRep::print_MatrixXd(std::ostream &stream, const SymGroup &head_group) const {
168  for(Index i = 0; i < head_group.size(); i++) {
169  stream << "SymRep Matrix " << i + 1 << " of " << head_group.size() << ":\n";
170  if(at(head_group[i].index())->get_MatrixXd())
171  stream << *(at(head_group[i].index())->get_MatrixXd()) << '\n';
172  else
173  stream << "nullptr\n";
174  stream << "\n";
175  }
176  return;
177  }
178 
179  //*******************************************************************************************
181  if(!size() || !get_MatrixXd(0))
182  return Eigen::MatrixXd();
183 
184  Eigen::MatrixXd block_shape(get_MatrixXd(0)->cwiseProduct(*get_MatrixXd(0)));
185 
186  for(Index i = 1; i < size(); i++) {
187  block_shape += get_MatrixXd(i)->cwiseProduct(*get_MatrixXd(i));
188 
189  }
190  return block_shape;
191  }
192  //*******************************************************************************************
194  if(!size() || !head_group.size() || !get_MatrixXd(head_group[0].index()))
195  return Eigen::MatrixXd();
196 
197  Eigen::MatrixXd block_shape(get_MatrixXd(head_group[0].index())->cwiseProduct(*get_MatrixXd(head_group[0].index())));
198 
199  for(Index i = 1; i < head_group.size(); i++) {
200  block_shape += get_MatrixXd(head_group[i].index())->cwiseProduct(*get_MatrixXd(head_group[i].index()));
201  }
202 
203  return block_shape;
204  }
205 
206  //*******************************************************************************************
209 
210  if(bmat.cols() == 0)
211  return 0;
212 
213  Index Nb = 1;
214 
215  //count zeros on first superdiagonal
216  for(EigenIndex i = 0; i + 1 < bmat.rows(); i++) {
217  if(almost_zero(bmat(i, i + 1)))
218  Nb++;
219  }
220 
221  return Nb;
222 
223  }
224  //*******************************************************************************************
225 
226  Index SymGroupRep::num_blocks(const SymGroup &head_group) const {
227  Eigen::MatrixXd bmat(block_shape_matrix(head_group));
228 
229  if(bmat.cols() == 0)
230  return 0;
231 
232  Index Nb = 1;
233 
234  //count zeros on first superdiagonal
235  for(EigenIndex i = 0; i + 1 < bmat.rows(); i++) {
236  if(almost_zero(bmat(i, i + 1)))
237  Nb++;
238  }
239 
240  return Nb;
241  }
242 
243  //*******************************************************************************************
245  if(has_valid_master()) {
246  throw std::runtime_error("SymGroupRep::push_back_copy() only callable on SymGroupRep that has no master\n");
247  }
249 
250  }
251  //*******************************************************************************************
252 
254  return at(i)->get_MatrixXd();
255  }
256 
257  //*******************************************************************************************
258 
260  return at(op.index())->get_MatrixXd();
261  }
262 
263  //*******************************************************************************************
264 
266  return at(i)->get_permutation();
267  }
268 
269  //*******************************************************************************************
270 
272  return at(op.index())->get_permutation();
273  }
274 
275 
276  //*******************************************************************************************
277  // Calculates new SymGroupRep that is the results of performing coordinate transformation specified by trans_mat
278  // The ROWS of trans_mat are the new basis vectors in terms of the old such that
279  // new_symrep_matrix = trans_mat * old_symrep_matrix * trans_mat.transpose();
281  SymGroupRep new_rep(master_group());
282  if(!size())
283  return new_rep;
284  if(at(0) && !(at(0)->get_MatrixXd())) {
285  std::cerr << "CRITICAL ERROR: Trying to perform matrix transformation on a non-matrix SymRep. Exiting...\n";
286  assert(0);
287  exit(1);
288  }
289  Eigen::MatrixXd rightmat;
290  rightmat = Eigen::JacobiSVD<Eigen::MatrixXd>(trans_mat.transpose()).solve(Eigen::MatrixXd::Identity(trans_mat.rows(), trans_mat.rows()));
291 
292  for(Index i = 0; i < size(); i++) {
293  if(!at(i))
294  continue;
295 
296  new_rep.set_rep(i, SymMatrixXd(trans_mat * (*(at(i)->get_MatrixXd())) * rightmat));
297  }
298  return new_rep;
299  }
300 
301  //*******************************************************************************************
302 
303  //assumes that representation is real-valued and irreducible
305 
306  // High symmetry subspace matrices (columns span subspaces)
308  ssubs = calc_special_subspaces(head_group);
309  /*for(Index i = 0; i < ssubs.size(); i++) {
310  std::cout << "In SymGroupRep::coord_symmetrized_copy -- subspace orbit " << i << " of " << ssubs.size() << " (dimensionality " << ssubs[i][0].cols() << "):\n";
311  for(Index j = 0; j < ssubs[i].size(); j++) {
312  std::cout << ssubs[i][j].transpose() << "\n";
313  }
314  std::cout << "\n";
315  }
316  */
317 
318  //std::cout << "\n\nSymGroupRep before reorientation is:\n";
319  //print_MatrixXd(std::cout, head_group);
320  //std::cout << '\n';
321 
322  Array<bool> sub_valid(ssubs.size(), true);
323  Array<Index> sub_ranks(ssubs.size());
324 
325 
326  Index dim(get_MatrixXd(head_group[0].index())->rows());
327  Eigen::MatrixXd trans_mat(Eigen::MatrixXd::Zero(dim, dim)), tmat;
328  Eigen::FullPivHouseholderQR<Eigen::MatrixXd> QR;
329  QR.setThreshold(TOL);
330 
331  // calculate the rank of each subspace orbit
332  for(Index i = 0; i < ssubs.size(); i++) {
333  //Fill tmat by concatenating columns of subspace matrices
334  tmat.resize(dim, ssubs[i][0].cols()*ssubs[i].size());
335  for(Index j = 0; j < ssubs[i].size(); j++) {
336  tmat.block(0, j * ssubs[i][j].cols(), dim, ssubs[i][j].cols()) = ssubs[i][j];
337  }
338  sub_ranks[i] = QR.compute(tmat).rank();
339  }
340 
341  Index i_best, n_cols(0);
342  while(n_cols < dim) {
343 
344  // find the best subspace orbit to add
345  i_best = -1;
346  for(Index i = 0; i < ssubs.size(); i++) {
347  // The subspace orbit must be valid (as we add subspaces, we invalidate them)
348  if(!sub_valid[i])
349  continue;
350 
351  if(!valid_index(i_best)) {
352  i_best = i;
353  continue;
354  }
355 
356  //compare cols() also
357  if(ssubs[i][0].cols() < ssubs[i_best][0].cols() // prefer 1D subspaces (high symmetry directions are better than high-symmetry planes)
358  || (ssubs[i][0].cols() == ssubs[i_best][0].cols() && sub_ranks[i] < sub_ranks[i_best]) // prefer low-rank orbits (likely irreps)
359  // prefer lower multiplicity (higher symmetry)
360  || (ssubs[i][0].cols() == ssubs[i_best][0].cols() && sub_ranks[i] == sub_ranks[i_best] && ssubs[i].size() < ssubs[i_best].size())) {
361  i_best = i;
362  }
363  }
364 
365  // make big matrix that combines trans_mat with best subspace
366  // we fill it in this particular way so that the resulting basis is most likely to transform as an irreducible representation
367  tmat.resize(dim, n_cols + ssubs[i_best].size()*ssubs[i_best][0].cols());
368  tmat.leftCols(n_cols) = trans_mat.leftCols(n_cols);
369  for(EigenIndex k = 0; k < ssubs[i_best][0].cols(); k++) {
370  for(Index j = 0; j < ssubs[i_best].size(); j++) {
371  tmat.col(n_cols + k * ssubs[i_best].size() + j) = ssubs[i_best][j].col(k);
372  }
373  }
374 
375  // number of basis vectors is now QR.rank()
376  n_cols = QR.compute(tmat).rank();
377  trans_mat.leftCols(n_cols) = Eigen::MatrixXd(tmat.householderQr().householderQ()).leftCols(n_cols);
378  sub_valid[i_best] = false; // take i_best out of consideration
379 
380  if(n_cols == dim)
381  break;
382 
383  // invalidate any subspaces that are redundant
384  for(Index i = 0; i < ssubs.size(); i++) {
385  if(!sub_valid[i])
386  continue;
387  tmat.resize(dim, n_cols + ssubs[i].size()*ssubs[i][0].cols());
388  tmat.leftCols(n_cols) = trans_mat.leftCols(n_cols);
389  for(Index j = 0; j < ssubs[i].size(); j++) {
390  tmat.block(0, n_cols + j * ssubs[i][j].cols(), dim, ssubs[i][j].cols()) = ssubs[i][j];
391  }
392 
393  if(QR.compute(tmat).rank() < n_cols + sub_ranks[i]) {
394  sub_valid[i] = false;
395  }
396  }
397 
398  }
399  //std::cout << "TRANSFORMATION MATRIX IS:\n" << trans_mat << "\n\n";
400 
401  return trans_mat.transpose();
402 
403  }
404 
405  //*******************************************************************************************
416  Array<SymGroupRepID> irrep_IDs = get_irrep_IDs(head_group);
417 
418  multivector<Eigen::VectorXd>::X<3> sdirs(irrep_IDs.size());
419  Array<Array<Eigen::VectorXd> > irrep_dirs;
420  Index irow(0);
421  Eigen::MatrixXd trans_mat = get_irrep_trans_mat(head_group);
422  for(Index i = 0; i < irrep_IDs.size(); i++) {
423  RemoteHandle irrep(head_group, irrep_IDs[i]);
424  Eigen::MatrixXd subtrans_mat = trans_mat.block(irow, 0, irrep.dim(), trans_mat.cols()).transpose();
425  if(i == 0 || irrep_IDs[i] != irrep_IDs[i - 1]) {
426  irrep_dirs = irrep->_calc_special_irrep_directions(head_group);
427  }
428  for(Index s = 0; s < irrep_dirs.size(); s++) {
429  //std::cout << "Irrep dir " << i << ", " << s << ": \n";
430  sdirs[i].push_back(std::vector<Eigen::VectorXd>());
431  for(Index d = 0; d < irrep_dirs[s].size(); d++) {
432  //std::cout << irrep_dirs[s][d].transpose() << std::endl;
433  sdirs[i].back().push_back(subtrans_mat * irrep_dirs[s][d]);
434  }
435  }
436  irow += irrep.dim();
437  }
438  return sdirs;
439  }
440 
441  //*******************************************************************************************
442  std::vector<Eigen::MatrixXd> SymGroupRep::irreducible_wedges(const SymGroup &head_group, std::vector<Index> &multiplicities)const {
443  Index dim = get_MatrixXd(head_group[0])->cols();
444 
446  std::vector<Eigen::MatrixXd> wedges(sdirs.size());
447  double best_proj, tproj;
448  multiplicities.clear();
449 
450  for(Index s = 0; s < sdirs.size(); s++) {
451  wedges[s] = Eigen::MatrixXd::Zero(dim, sdirs[s].size());
452  wedges[s].col(0) = sdirs[s][0][0];
453  multiplicities.push_back(sdirs[s][0].size());
454  for(Index i = 1; i < sdirs[s].size(); i++) {
455  Index j_best = 0;
456  best_proj = (wedges[s].transpose() * sdirs[s][i][0]).sum();
457  for(Index j = 1; j < sdirs[s][i].size(); j++) {
458  tproj = (wedges[s].transpose() * sdirs[s][i][j]).sum();
459  if(tproj > best_proj) {
460  best_proj = tproj;
461  j_best = j;
462  }
463  }
464  multiplicities.push_back(sdirs[s][i].size());
465  wedges[s].col(i) = sdirs[s][i][j_best];
466  }
467  }
468  return wedges;
469  }
470  //*******************************************************************************************
472  if(!size() || !(get_MatrixXd(head_group[0]))) {
473  std::cerr << "CRITICAL ERROR: In SymGroupRep::_calc_special_irrep_directions() called on imcompatible SymGroupRep.\n Exiting...\n";
474  exit(1);
475  }
476 
477  Index i, j;
478 
479  Array<Array<Eigen::VectorXd> > sdirs; // Array of orbits of special directions
480 
481  Eigen::VectorXd tdir;
482 
483  const Array<Array<Array<Index> > > &isubs(head_group.subgroups());
484  Eigen::ColPivHouseholderQR<Eigen::MatrixXd> QR(*(get_MatrixXd(head_group[0])));
485 
486  Index dim = get_MatrixXd(head_group[0])->cols();
487 
488  QR.setThreshold(10 * TOL);
489 
490  // i loops over subgroup "orbits". There are 0 to 'dim' special directions associated with each orbit.
491  Eigen::MatrixXd Reynolds(*(at(0)->get_MatrixXd()));
492  for(i = 0; i < isubs.size(); i++) {
493  if(isubs[i].size() == 0 || isubs[i][0].size() == 0) {
494  std::cerr << "CRITICAL ERROR: In SymGroupRep::_calc_special_irrep_directions(), attempting to use a zero-size subgroup.\n Exiting...\n";
495  exit(1);
496  }
497  Index s = 0;
498  Reynolds.setZero();
499  // j loops over elements of "prototype" subgroup to get the Reynold's operator for the vector
500  // space on which the representation is defined
501  for(j = 0; j < isubs[i][s].size(); j++) {
502  Reynolds += *get_MatrixXd(head_group[isubs[i][s][j]]);
503  }
504 
505  Reynolds /= double(isubs[i][s].size());
506 
507  //Need this because Eigen computes nonzero rank for matrix filled with small numbers close to zero.
508  //QR.setThreshold() doesn't help
509  if(almost_zero(Reynolds))
510  continue;
511 
512  // Column space of Reynold's matrix is invariant under the subgroup
513  QR.compute(Reynolds);
514 
515  // We're only interested in 1-D invariant spaces
516  if(QR.rank() != 1)
517  continue;
518 
519  //QR.matrixQ().col(0) is a special direction
520 
521  Eigen::MatrixXd matrixQ(QR.householderQ());
522 
523  //std::cout << "QR matrixR:\n" << Eigen::MatrixXd(QR.matrixQR().template triangularView<Eigen::Upper>()) << "\n";
524  //std::cout << "QR matrixQ:\n" << matrixQ << "\n";
525 
526  // See if QR.matrixQ().col(0) has been found
527  for(j = 0; j < sdirs.size(); j++) {
528  if(sdirs[j].almost_contains(matrixQ.col(0))) {
529  break;
530  }
531  }
532  if(j == sdirs.size()) {
533 
534  //Get equivalents
536  for(j = 0; j < head_group.size(); j++) {
537  tdir = (*get_MatrixXd(head_group[j])) * matrixQ.col(0);
538  if(!sdirs.back().almost_contains(tdir))
539  sdirs.back().push_back(tdir);
540  }
541  }
542 
543  for(j = 0; j < sdirs.size(); j++) {
544  if(sdirs[j].almost_contains(-matrixQ.col(0))) {
545  break;
546  }
547  }
548  if(j == sdirs.size() && dim > 1) {
549 
550  //Get equivalents
552  for(j = 0; j < head_group.size(); j++) {
553  tdir = -(*get_MatrixXd(head_group[j])) * matrixQ.col(0);
554  if(!sdirs.back().almost_contains(tdir))
555  sdirs.back().push_back(tdir);
556  }
557  }
558  }
559  return sdirs;
560  }
561 
562  //*******************************************************************************************
563 
564  // Similar to algorithm for finding special directions, except we also find special planes,
565  // n-planes, etc. The matrices that are returned have column vectors that span the special
566  // subspaces. The subspaces are arranged in orbits of subspaces that are equivalent by symmetry
567 
569  if(!size() || !at(0)->get_MatrixXd()) {
570  std::cerr << "CRITICAL ERROR: In SymGroupRep::calc_special_subspaces() called on imcompatible SymGroupRep.\n Exiting...\n";
571  exit(1);
572  }
573 
574  Index i, j, k;
575 
576  Array<Array<Eigen::MatrixXd> > ssubs; // Array of orbits of special directions
577 
578  Eigen::MatrixXd tsub, ttrans;
579 
580  // Operation indices of subgroups
581  const Array<Array<Array<Index> > > &sg_op_inds(head_group.subgroups());
582 
583  Eigen::FullPivHouseholderQR<Eigen::MatrixXd> QR(*(at(0)->get_MatrixXd()));
584 
585  QR.setThreshold(TOL);
586 
587  Eigen::MatrixXd Reynolds(*(at(0)->get_MatrixXd()));
588 
589  // 'i' loops over subgroup "orbits". There are 0 to 'dim' special directions associated with each orbit.
590  for(i = 0; i < sg_op_inds.size(); i++) {
591  if(sg_op_inds[i].size() == 0 || sg_op_inds[i][0].size() == 0) {
592  std::cerr << "CRITICAL ERROR: In SymGroupRep::calc_special_subspaces(), attempting to use a zero-size subgroup.\n Exiting...\n";
593  exit(1);
594  }
595 
596  Reynolds.setZero();
597  // j loops over elements of "prototype" subgroup to get the Reynold's operator for the vector
598  // space on which the representation is defined
599  for(j = 0; j < sg_op_inds[i][0].size(); j++) {
600  Reynolds += *(at(head_group[sg_op_inds[i][0][j]].index())->get_MatrixXd());
601  }
602 
603  Reynolds /= double(sg_op_inds[i][0].size());
604 
605  // Column space of Reynold's matrix is invariant under the subgroup
606  QR.compute(Reynolds);
607 
608  // If there are no special subspaces, the Reynold's operator has zero
609  if(QR.rank() < 1)
610  continue;
611 
612  // The first (QR.rank()) columns of QR.matrixQ() span a special subspace --
613  // this can be accessed as QR.matrixQ().leftCols(QR.rank())
614  tsub = QR.matrixQ().leftCols(QR.rank());
615 
616  // See if tsub has been found. Because we only keep orthonormal spanning vectors, this check is significantly simplified
617  // -- the matrix (tsub.transpose()*ssubs[j][k]) must have a determinant of +/-1 if the two matrices span the same column space
618  for(j = 0; j < ssubs.size(); j++) {
619 
620  if(ssubs[j][0].cols() != tsub.cols())
621  continue;
622 
623  for(k = 0; k < ssubs[j].size(); k++) {
624  double tdet = (tsub.transpose() * ssubs[j][k]).determinant();
625  if(almost_equal(std::abs(tdet), 1.0))
626  break;
627  }
628  if(k < ssubs[j].size())
629  break;
630  }
631  if(j < ssubs.size())
632  continue;
633 
634  //tsub is new -- get equivalents
636  for(j = 0; j < head_group.size(); j++) {
637  ttrans = (*(at(head_group[j].index())->get_MatrixXd())) * tsub;
638  for(k = 0; k < ssubs.back().size(); k++) {
639  double tdet = (ttrans.transpose() * ssubs.back()[k]).determinant();
640  if(almost_equal(std::abs(tdet), 1.0))
641  break;
642  }
643  if(k == ssubs.back().size())
644  ssubs.back().push_back(ttrans);
645  }
646 
647  // Unlike directions, the negative orientation of a subspace matrix is not considered
648  // distinct. This is because we are only concerned about coordinate axes.
649 
650  }
651 
652  // Order subspaces by dimension, small to large; within blocks of equal dimension, order from
653  // lowest multiplicity to highest
654  for(i = 0; i < ssubs.size(); i++) {
655  for(j = i + 1; j < ssubs.size(); j++) {
656  if(ssubs[i][0].cols() > ssubs[j][0].cols())
657  ssubs.swap_elem(i, j);
658  if(ssubs[i][0].cols() == ssubs[j][0].cols() && ssubs[i].size() > ssubs[j].size())
659  ssubs.swap_elem(i, j);
660  }
661  }
662 
663  return ssubs;
664  }
665 
666  //*******************************************************************************************
667  //assumes that representation is real-valued, and combines complex-valued irreps with their complex conjugate
668  ReturnArray<Index> SymGroupRep::num_each_real_irrep(const SymGroup &head_group, bool verbose) const {
669  const Array<bool > &complex_irrep(head_group.get_complex_irrep_list());
670  Array<Index> tarray(num_each_irrep(head_group, verbose));
671 
672  if(tarray.size() != complex_irrep.size()) {
673  std::cerr << "CRITICAL ERROR: Dimension mismatch in SymGroupRep::num_each_real_irrep. Exiting..\n";
674  assert(0);
675  exit(1);
676  }
677 
678  // Go through and remove double counting of complex irreps
679  for(Index i = 0; i < tarray.size(); i++) {
680  if(tarray[i] && complex_irrep[i]) {
681  if(i + 1 == tarray.size() || tarray[i] != tarray[i + 1]) {
682  std::cerr << "CRITICAL ERROR: Invalid irrep decomposition found in SymGroupRep::num_each_real_irrep. Exiting..\n";
683  assert(0);
684  exit(1);
685  }
686  tarray[i + 1] = 0;
687  i++;
688  }
689  }
690  return tarray;
691  }
692 
693  //*******************************************************************************************
694  //assumes that representation is real-valued
696  if(!has_valid_master()) {
697  std::cerr << "In SymGroupRep::num_each_irrep() attempting to find irrep decomposition of a SymGroupRep that has no valid master_group.\n";
698  assert(0);
699  exit(1);
700  }
701  return num_each_irrep(master_group());
702  }
703 
704  //*******************************************************************************************
705 
706  ReturnArray<Index> SymGroupRep::num_each_irrep(const SymGroup &head_group, bool verbose) const {
707  const Array<Array<Index> > &conj_class(head_group.get_conjugacy_classes());
708  const Array<Array<std::complex<double> > > &char_table(head_group.character_table());
709 
710  Array<Index> tdec(conj_class.size(), 0);
711  Array<double> repchar(conj_class.size(), 0);
712 
713  if(verbose) {
714  std::cout << "Decomposing representation:\n ";
715  for(Index i = 0; i < head_group.size(); i++) {
716  std::cout << *(get_MatrixXd(head_group[i])) << "\n\n";
717  }
718  }
719 
720  //std::cout << "Character table is\n";
721  for(Index i = 0; i < conj_class.size(); i++) {
722  Index rep_index(head_group[conj_class[i][0]].index());
723  repchar[i] = at(rep_index)->character();
724  //std::cout << char_table[i] << "\n\n";
725  }
726 
727  if(verbose)
728  std::cout << " Irrep decomposition: ";
729  for(Index i = 0; i < char_table.size(); i++) { // Loop over irreducible representations
730  double temp(0);
731  for(Index j = 0; j < char_table[i].size(); j++) { // Loop over conjugacy classes
732  temp += double(conj_class[j].size()) * repchar[j] * (char_table[i][j]).real();
733  }
734  tdec[i] = round(temp / double(head_group.size()));
735  if(verbose)
736  std::cout << " " << tdec[i];
737  }
738  if(verbose)
739  std::cout << '\n';
740 
741 
742  return tdec;
743  }
744 
745  //*******************************************************************************************
746 
748  Array<Index> irrep_decomp(num_each_real_irrep(head_group));
749  Array<SymGroupRepID> irrep_IDs;
750  for(Index i = 0; i < irrep_decomp.size(); i++) {
751  if(irrep_decomp[i] == 0)
752  continue;
753 
754  if(head_group.get_irrep_ID(i).empty())
755  calc_new_irreps(head_group);
756 
757  if(head_group.get_irrep_ID(i).empty()) {
758  std::cerr << "CRITICAL ERROR: In SymGroupRep::get_irrep_IDs(), cannot resolve irrep " << i << " which has multiplicity " << irrep_decomp[i] << ". Exiting...\n";
759  assert(0);
760  exit(1);
761  }
762 
763  irrep_IDs.append(Array<SymGroupRepID>(irrep_decomp[i], head_group.get_irrep_ID(i)));
764  }
765 
766  return irrep_IDs;
767 
768  }
769 
770  //*******************************************************************************************
771 
772  void SymGroupRep::calc_new_irreps(int max_iter) const {
773  if(!has_valid_master()) {
774  std::cerr << "In SymGroupRep::calc_new_irreps() attempting to calculate new irreps of a SymGroupRep that has no valid master_group.\n";
775  assert(0);
776  exit(1);
777  }
778  calc_new_irreps(master_group(), max_iter);
779  return;
780  }
781 
782  //*******************************************************************************************
783  //
784  // assumes that representation is real-valued. This means that complex-valued
785  // irreps in the character table get combined into single 2-D irreps
786 
787  void SymGroupRep::calc_new_irreps(const SymGroup &head_group, int max_iter) const {
788 
789  if(!size() || !at(0)->get_MatrixXd()) {
790  std::cerr << "WARNING: In SymGroupRep::calc_new_irreps, size of representation is " << size() << " and MatrixXd address is " << at(0)->get_MatrixXd() << std::endl
791  << " No valid irreps will be returned.\n";
792  return;
793  }
794  if(!head_group.size()) {
795  assert(0 && "In SymGroupRep::calc_new_irreps(), passed an empty SymGroup!");
796  return;
797  }
798 
799  MasterSymGroup const *master_ptr(NULL);
800  if(has_valid_master())
801  master_ptr = &master_group();
802  else if(head_group[0].has_valid_master())
803  master_ptr = &head_group[0].master_group();
804  else {
805  std::cerr << "CRITICAL ERROR: In SymGroupRep::calc_new_irreps(), there is no MasterSymGroup available!\n"
806  << " Exiting...\n";
807  }
808  int dim((at(0)->get_MatrixXd())->rows());
809 
810  Array<Index> i_decomp(num_each_real_irrep(head_group));
811  int Nirrep(i_decomp.sum());
812  if(Nirrep == 0) {
813  std::cerr << "In SymGroupRep::calc_new_irreps(), there are no valid irreps, so no valid irreps will be returned.\n";
814  return;
815  }
816  if(Nirrep == 1) {
817  //std::cout << "There is only 1 irrep, so I'm returning a symmetrized copy of *this\n";
818  head_group.set_irrep_ID(i_decomp.find(1), master_ptr->add_representation(coord_transformed_copy(_symmetrized_irrep_trans_mat(head_group))));
819  return;
820  }
821 
822  //std::cout << "This representation contains " << Nirrep << " irreps... About to build commuters!\n";
823  Array<Eigen::MatrixXd> commuters;
824 
825  // Build 'commuters', which span space of matrices that commute with SymOpReps
826  for(int i = 0; i < dim; i++) {
827  for(int j = i; j < dim; j++) {
828  Eigen::MatrixXd tmat(Eigen::MatrixXd::Zero(dim, dim)), tcommute(Eigen::MatrixXd::Zero(dim, dim));
829 
830  //We only build symmetric commuters, which assures we only select out real-valued representations
831  tmat(i, j) = 1;
832  tmat(j, i) = 1;
833  //apply reynolds operator
834  for(Index ns = 0; ns < head_group.size(); ns++) {
835  tcommute += (*(get_MatrixXd(head_group[ns]))) * tmat * (*(get_MatrixXd(head_group[ns]))).transpose();
836  }
837  //Do Gram-Shmidt while building 'commuters'
838  for(Index nc = 0; nc < commuters.size(); nc++) {
839  double tproj((commuters[nc].array()*tcommute.array()).sum()); //Frobenius product
840  tcommute -= tproj * commuters[nc];
841  }
842  double tnorm(tcommute.norm());
843  if(tnorm > TOL) {
844  commuters.push_back(tcommute / tnorm);
845  //std::cout << commuters.back() << "\n\n";
846  }
847  }
848  }
849  for(Index nc = 0; nc < commuters.size(); nc++) {
850  commuters[nc] *= (dim * sqrt(dim)); //magnify the range of eigenvalues
851  }
852  //Finished building commuters
853 
854  Eigen::JacobiSVD<Eigen::MatrixXd> svd;
855  double min_diff(-1);
856  int Nstep(0), Nfound(0), max_found = 0;
857  Eigen::MatrixXd tmat(dim, dim), trans_mat(dim, dim);
858  int rseed(5284163); //use constant seed for reproducibility
859  Eigen::VectorXd mags(commuters.size());
860  while((max_found < Nirrep || min_diff < 0.05 || Nstep < 10) && Nstep < max_iter) {
861  Nstep++;
862  Nfound = 1;
863  double tmindiff(1e+8), tdiff(0);
864 
865  tmat.setZero();
866  for(EigenIndex i = 0; i < mags.size(); i++)
867  mags[i] = ran0(rseed);
868  mags.normalize();
869 
870  for(Index nc = 0; nc < commuters.size(); nc++) {
871  tmat += mags[nc] * commuters[nc];
872  }
873  svd.compute(tmat, Eigen::ComputeFullU);
874 
875  for(EigenIndex ne = 1; ne < svd.singularValues().size(); ne++) {
876  tdiff = std::abs(svd.singularValues()[ne - 1] - svd.singularValues()[ne]);
877  if(tdiff > TOL) {
878  Nfound++;
879  tmindiff = std::min(tdiff, tmindiff);
880  }
881  }
882 
883  if(Nfound > max_found || (Nfound == max_found && tmindiff > min_diff)) {
884  max_found = Nfound;
885  //trans_mat defined to go from old basis to new basis
886  trans_mat = svd.matrixU().transpose();
887  min_diff = tmindiff;
888  }
889  }
890  //std::cout << "After " << Nstep << " iterations, found suitable decomposition \n ***U:" << svd.matrixU() << "\n\n ***S" << svd.singularValues() << "\n\n";
891  //std::cout << "trans_mat is:\n" << trans_mat << "\n\n";
892  if(Nstep >= max_iter) {
893  std::cerr << "CRITICAL ERROR: In SymGroupRep::calc_new_irreps, reached maximum iterations (" << max_iter << ") without finding all irreps.\n"
894  << " I found " << max_found << " of " << Nirrep << " distinguishable within " << min_diff << " (0.1 required). Exiting...\n";
895  assert(0);
896  exit(1);
897 
898  }
899 
900  // Almost there. We have a transformation matrix that block-diagonalizes the symmetry matrices. Now we apply it.
901 
902  //get the block_shape_matrix of the transformed representation
903  //std::cout << "Transformed representation will be: \n";
904  Eigen::MatrixXd block_shape(Eigen::MatrixXd::Zero(dim, dim));
905  for(Index i = 0; i < head_group.size(); i++) {
906  //std::cout << "Operation " << i << " of " << head_group.size() << ":\n";
907  tmat = trans_mat * (*(at(head_group[i].index())->get_MatrixXd())) * trans_mat.transpose();
908  //std::cout << tmat << "\n";
909  block_shape.array() += tmat.array() * tmat.array();
910  }
911  //std::cout << "Block shape matrix of transformed representation is: \n" << block_shape << '\n';
912  //now loop over the 1st off-diagonal of the block-shape matrix and look for breaks
913  int i1(0);
914  int nblocks = 0;
915  for(int i2 = 1; i2 < dim; i2++) {
916  if(block_shape(i2 - 1, i2) > 0.5)
917  continue;
918  nblocks++;
919  //std::cout << "Found block number " << nblocks << " of " << Nirrep << '\n';
920  //Found end of block
921  tmat.resize(i2 - i1, dim);
922  tmat = trans_mat.block(i1, 0, i2 - i1, dim);
923  SymGroupRep new_irrep(coord_transformed_copy(tmat));
924 
925  Array<Index> tdecomp(new_irrep.num_each_real_irrep(head_group));
926  if(tdecomp.sum() != 1) {
927  std::cerr << "CRITICAL ERROR: In SymGroupRep::calc_new_irreps(), representation identified as irreducible did not pass final tests. Exiting...\n";
928  assert(0);
929  exit(1);
930  }
931  Index i_irrep = tdecomp.find(1);
932  if(!head_group.get_irrep_ID(i_irrep).empty()) {
933  i1 = i2;
934  continue;
935  }
936 
937  SymGroupRepID irrep_ID = master_ptr->add_representation(new_irrep.coord_transformed_copy(new_irrep._symmetrized_irrep_trans_mat(head_group)));
938 
939  head_group.set_irrep_ID(i_irrep, irrep_ID);
940  //std::cout << "Setting the rep_ID of irrep " << i_irrep << " to " << irrep_ID;
941  //std::cout << " and validating -- " << head_group.get_irrep_ID(i_irrep) << '\n';
942 
943  i1 = i2;
944 
945  }
946 
947  // Process the final block
948  nblocks++;
949  //std::cout << "Found block number " << nblocks << " of " << Nirrep << '\n';
950 
951  tmat.resize(dim - i1, dim);
952  tmat = trans_mat.block(i1, 0, dim - i1, dim);
953  SymGroupRep new_irrep(coord_transformed_copy(tmat));
954 
955  //std::cout << "\nIts representation looks like this:\n";
956  //new_irrep->print_MatrixXd(std::cout, head_group);
957  //std::cout << '\n';
958  Array<Index> tdecomp(new_irrep.num_each_real_irrep(head_group));
959  if(tdecomp.sum() != 1) {
960  std::cerr << "CRITICAL ERROR: In SymGroupRep::calc_new_irreps(), representation identified as irreducible did not pass final tests. Exiting...\n";
961  assert(0);
962  exit(1);
963  }
964  Index i_irrep = tdecomp.find(1);
965  if(!head_group.get_irrep_ID(i_irrep).empty()) {
966  return;
967  }
968 
969  SymGroupRepID irrep_ID = master_ptr->add_representation(new_irrep.coord_transformed_copy(new_irrep._symmetrized_irrep_trans_mat(head_group)));
970 
971  //std::cout << "Setting the rep_ID of irrep " << i_irrep << " to " << irrep_ID;
972  head_group.set_irrep_ID(i_irrep, irrep_ID);
973  //std::cout << " and validating -- " << head_group.get_irrep_ID(i_irrep) << '\n';
974 
975  return;
976 
977  }
978 
979  //*******************************************************************************************
980 
981  bool SymGroupRep::is_irrep() const {
982  double tvalue = 0;
983 
984  for(Index i = 0; i < size(); i++) {
985  tvalue += (at(i)->character()) * (at(i)->character());
986  }
987 
988  if(Index(round(tvalue)) == master_group().size()) {
989  return true;
990  }
991  else {
992  return false;
993  }
994  }
995 
996  //*******************************************************************************************
997 
998  bool SymGroupRep::is_irrep(const SymGroup &head_group) const {
999  double tvalue = 0;
1000 
1001  for(Index i = 0; i < head_group.size(); i++) {
1002  tvalue += (at(head_group[i].index())->character()) * (at(head_group[i].index())->character());
1003  }
1004 
1005  if(Index(round(tvalue)) == head_group.size()) {
1006  return true;
1007  }
1008  else {
1009  return false;
1010  }
1011  }
1012 
1013  //*******************************************************************************************
1014 
1015  // Finds the transformation matrix that block-diagonalizes this representation into irrep blocks
1016  // The ROWS of trans_mat are the new basis vectors in terms of the old such that
1017  // new_symrep_matrix = trans_mat * old_symrep_matrix * trans_mat.transpose();
1019  std::vector< std::vector<Index> > subspaces;
1020  return get_irrep_trans_mat(head_group, subspaces);
1021  }
1022 
1023  //*******************************************************************************************
1024 
1025  // Finds the transformation matrix that block-diagonalizes this representation into irrep blocks
1026  // The ROWS of trans_mat are the new basis vectors in terms of the old such that
1027  // new_symrep_matrix = trans_mat * old_symrep_matrix * trans_mat.transpose();
1028  // Also populate 'subspaces' with lists of columns that form irreps
1029  Eigen::MatrixXd SymGroupRep::get_irrep_trans_mat(const SymGroup &head_group, std::vector< std::vector<Index> > &subspaces) const {
1030  //std::cout << "INSIDE GET_IRREP_TRANS_MAT\n";
1031  const Array<bool > &complex_irrep(head_group.get_complex_irrep_list());
1032  //const Array<Array<std::complex<double> > > &char_table(master_group().character_table());
1033  const Array<Array<std::complex<double> > > &char_table(head_group.character_table());
1034 
1035  Array<Index> irrep_decomp(num_each_real_irrep(head_group));
1036 
1037  //get_irrep_IDs() harvests any new irreps that appear in this representation
1038  Array<SymGroupRepID> irrep_IDs(get_irrep_IDs(head_group));
1039 
1040  int rep_dim = get_MatrixXd(head_group[0])->rows();
1041 
1042  // We will fill the columns of trans_mat and then return its transpose at the end
1043  Eigen::MatrixXd tproj(Eigen::MatrixXd::Zero(rep_dim, rep_dim)),
1044  tmat(Eigen::MatrixXd::Zero(rep_dim, rep_dim)),
1045  trans_mat(Eigen::MatrixXd::Zero(rep_dim, rep_dim));
1046 
1047  // set a relatively high threshold for determining matrix rank, since we know values should be close to 1
1048  Eigen::FullPivLU<Eigen::MatrixXd> LU;
1049  LU.setThreshold(0.001);
1050  Eigen::FullPivHouseholderQR<Eigen::MatrixXd> QR;
1051  QR.setThreshold(0.001);
1052 
1053  int col_count = 0;
1054  for(Index i = 0; i < irrep_decomp.size(); i++) {
1055  if(irrep_decomp[i] == 0)
1056  continue;
1057 
1058  int c_mult(1);
1059  if(complex_irrep[i])
1060  c_mult = 2;
1061 
1062  const SymGroupRep &t_irrep(head_group.get_irrep(i));
1063 
1064  int irrep_dim = c_mult * round(char_table[i][0].real());
1065 
1066  // make sure t_irrep is valid and has the correct dimension.
1067  assert(irrep_dim == (t_irrep.get_MatrixXd(head_group[0])->rows()));
1068 
1069  //get the (0,0) projection operator -> projects out vectors that transform as the first basis vector of irrep 'i'
1070  tproj.setZero();
1071  //std::cout << "PROJECTING OUT THE FOLLOWING IRREP\n";
1072  for(Index j = 0; j < head_group.size(); j++) {
1073  //std::cout << "OP " << j << ":\n";
1074 
1075  tproj += (*(t_irrep.get_MatrixXd(head_group[j])))(0, 0) * (*get_MatrixXd(head_group[j]));
1076  }
1077  tproj *= double(irrep_dim) / double(head_group.size());
1078 
1079  // tproj is now the (0,0) projection operator for t_irrep. That means its rows span
1080  // a subspace spanned by (0,0) basis functions of t_irrep, and we can do Gram Shmidt to find a minimal set
1081 
1082  //std::cout << "Irrep decomp is " << irrep_decomp << "\n";
1083  //std::cout << "For irrep " << i << " tproj is:\n" << tproj << "\n\n";
1084 
1085  // We want to get a set of spanning vectors that are sparse and orthonormal
1086  // first we do LU (i.e., Gaussian elimination) to clean things up a bit
1087  LU.compute(tproj);
1088  tmat = LU.matrixLU().triangularView<Eigen::Upper>();
1089 
1090  //std::cout << "Gaussian elimination yields:\n" << tmat << "\n\n";
1091 
1092  //find reduced-row-echelon form -- why is this not an Eigen routine?
1093  double tval;
1094  for(int j = LU.rank() - 1; j > 0; j--) {
1095  tval = tmat(j, j); // <- in case aliasing is an issue
1096  tmat.row(j) /= tval;
1097  for(int k = 0; k < j; k++) {
1098  tval = tmat(k, j);
1099  tmat.row(k) -= tval * tmat.row(j);
1100  }
1101  }
1102  // rearrange columns so that they match initial definition
1103  tmat = tmat * LU.permutationQ().inverse();
1104 
1105  //std::cout << "And finally:\n" << tmat << "\n\n";
1106 
1107  // rows of tmat span the space, but they aren't orthonormal
1108  // do QR (aka Gram-Shmidt), and first QR.rank() columns of QR will span the space
1109  QR.compute(tmat.transpose());
1110  if(QR.rank() != irrep_decomp[i]) {
1111  std::cerr << "CRITICAL ERROR: In SymGroupRep::get_irrep_trans_mat(), did not find correct number of basis vectors to account for\n"
1112  << " multiplicity of irrep #" << i << ". There should be " << irrep_decomp[i] << " but I found " << QR.rank() << "\n"
1113  << " Exiting...\n";
1114  exit(1);
1115  }
1116 
1117  //std::cout << "QR yields:\n " << QR.matrixQ() << "\n\n";
1118  for(EigenIndex n = 0; n < QR.rank(); n++) {
1119  subspaces.push_back(std::vector<Index>(irrep_dim));
1120  std::iota(subspaces.back().begin(), subspaces.back().end(), col_count + n * irrep_dim);
1121  trans_mat.col(col_count + n * irrep_dim) = QR.matrixQ().col(n);
1122  }
1123  //std::cout << "Initial trans_mat is:\n" << trans_mat << "\n\n";
1124 
1125  // NOW, let's make the (0,j) projection matrices to project out the other basis functions
1126  for(int j = 1; j < irrep_dim; j++) {
1127 
1128  tproj.setZero();
1129  for(Index k = 0; k < head_group.size(); k++) {
1130  //tproj += (*(t_irrep->get_MatrixXd(head_group[k])))(0,j) * (*get_MatrixXd(head_group[k])); // <-- this is wrong, not totally sure why
1131  tproj += (*(t_irrep.get_MatrixXd(head_group[k])))(j, 0) * (*get_MatrixXd(head_group[k]));
1132  }
1133  tproj *= double(irrep_dim) / double(head_group.size());
1134 
1135  //std::cout << "(0, " << j << ") projection operator is:\n" << tproj << "\n\n";
1136  //apply (0,j) projection operator to trans_mat. It will project the 0'th basis vectors to the j'th
1137  tmat = tproj * QR.matrixQ();
1138 
1139  //store the result in trans_mat
1140  for(EigenIndex n = 0; n < QR.rank(); n++) {
1141  trans_mat.col(col_count + n * irrep_dim + j) = tmat.col(n);
1142  }
1143  //std::cout << "NOW trans_mat is:\n" << trans_mat << "\n\n";
1144  }
1145 
1146  //update col_count:
1147  col_count += irrep_decomp[i] * irrep_dim;
1148  }
1149 
1150  return trans_mat.transpose();
1151  }
1152  //*******************************************************************************************
1153 
1154  // Finds the transformation matrix that block-diagonalizes this representation into irrep blocks
1155  // The ROWS of trans_mat are the new basis vectors in terms of the old such that
1156  // new_symrep_matrix = trans_mat * old_symrep_matrix * trans_mat.transpose();
1158 
1159  if(!size() || !head_group.size() || !get_MatrixXd(head_group[0].index())) {
1160  std::cerr << "WARNING: In SymGroupRep::calc_new_irreps, size of representation is " << size() << " and MatrixXd address is " << get_MatrixXd(head_group[0].index()) << std::endl
1161  << " No valid irreps will be returned.\n";
1162  return Eigen::MatrixXd();
1163  }
1164 
1165  int dim(get_MatrixXd(head_group[0].index())->rows());
1166  Array<Eigen::MatrixXcd> commuters;
1167  std::cout.precision(8);
1168  std::cout.flags(std::ios::showpoint | std::ios::fixed | std::ios::right);
1169  // Identity always commutes, and by putting it first we prevent some accidental degeneracies
1170  commuters.push_back(Eigen::MatrixXcd::Identity(dim, dim) / sqrt(double(dim)));
1171  typedef std::complex<double> cplx;
1172  Array<cplx> phase;
1173  phase.push_back(cplx(1.0, 0.0)); // 1+0i
1174  phase.push_back(cplx(0.0, 1.0)); // 0+1i
1175 
1176  Eigen::SelfAdjointEigenSolver<Eigen::MatrixXcd> esolve;
1177  Eigen::HouseholderQR<Eigen::MatrixXd> qr;
1178  Eigen::ColPivHouseholderQR<Eigen::MatrixXd> colqr;
1179  colqr.setThreshold(0.001);
1180  int Nfound(0);
1181  Eigen::MatrixXcd tmat(Eigen::MatrixXcd::Zero(dim, dim)), tcommute(Eigen::MatrixXcd::Zero(dim, dim));
1182  Eigen::MatrixXd trans_mat(Eigen::MatrixXd::Zero(dim, dim)), kernel(Eigen::MatrixXd::Random(dim, dim).householderQr().householderQ());
1183 
1184 
1185 
1186  //std::cout << "Commuter are:\n";
1187  // Build 'commuters', which span space of real matrices that commute with SymOpReps
1188  // 'kernel' is the kernel of trans_mat, and as the loop progresses, 'kernel' shrinks and the rank for trans_mat increases
1189  Array<Index> irrep_dims;
1190  std::cout << "~~~~~~~Dimension is " << dim << "\n";
1191  for(Index kci = 0; kci < kernel.cols(); kci++) {
1192  bool found_new_irreps(false);
1193  for(Index kcj = kci; kcj < kernel.cols(); kcj++) {
1194  for(Index nph = 0; nph < 2; nph++) {
1195  if(kci == kcj && nph > 0) continue;
1196  tcommute.setZero();
1197 
1198  // form commuters by taking outer product of i'th column of the kernel with the j'th column
1199  // commuters are constructed to be self-adjoint, which assures eigenvalues are real
1200  tmat = phase[nph] * kernel.col(kci) * kernel.col(kcj).transpose() // outer product
1201  + std::conj(phase[nph]) * kernel.col(kcj) * kernel.col(kci).transpose(); // adjoint of outer product
1202 
1203  //apply reynolds operator
1204  for(Index ns = 0; ns < head_group.size(); ns++) {
1205  tcommute += (*(get_MatrixXd(head_group[ns].index()))) * tmat * (*(get_MatrixXd(head_group[ns].index()))).transpose();
1206  //tcommute += phase[nph]*(get_MatrixXd(ns)->col(i)) * (get_MatrixXd(ns)->row(j))+std::conj(phase[nph])*(get_MatrixXd(ns)->col(j)) * (get_MatrixXd(ns)->row(i));
1207  }
1208 
1209  //Do Gram-Shmidt while building 'commuters'
1210  for(Index nc = 0; nc < commuters.size(); nc++) {
1211  double tproj((commuters[nc].array().conjugate()*tcommute.array()).sum().real()); //Frobenius product
1212  tcommute -= tproj * commuters[nc];
1213  }
1214  double tnorm(tcommute.norm());
1215  if(tnorm > TOL) {
1216  commuters.push_back(tcommute / tnorm);
1217  //std::cout << commuters.back() << "\n\n";
1218  }
1219  else continue; // Attempt to construct the next commuter...
1220 
1221  //Finished building commuter now we can try to harvest irreps from it
1222 
1223  // construct trans_mat from the non-degenerate irreps obtained from the commuter
1224 
1225  Index nc = commuters.size() - 1;
1226 
1227  // magnify the range of eigenvalues to be (I think) independent of matrix dimension by multiplying by dim^{3/2}
1228  esolve.compute(double(dim)*sqrt(double(dim))*kernel.transpose()*commuters[nc]*kernel);
1229  //std::cout << "KERNEL IS:\n" << kernel << "\n\n";
1230  //std::cout << esolve.eigenvalues().size() << " EIGENVALUES of commuter " << nc << " are \n" << esolve.eigenvalues().transpose() << "\n";
1231  Array<Index> subspace_dims = partition_distinct_values(esolve.eigenvalues());
1232  //std::cout << "Eigenvectors are:\n" << esolve.eigenvectors().real() << "\n\n" << esolve.eigenvectors().imag() << "\n\n";
1233  //std::cout << "QR Eigenvectors are:\n"
1234  //<< Eigen::MatrixXcd(esolve.eigenvectors().householderQr().householderQ()).real() << "\n\n"
1235  //<< Eigen::MatrixXcd(esolve.eigenvectors().householderQr().householderQ()).imag() << "\n\n";
1236 
1237  tmat = kernel * (esolve.eigenvectors().householderQr().householderQ());
1238  //std::cout << "Considering vectors:\n" << tmat.real() << "\n\n" << tmat.imag() << "\n\n";
1239  //std::cout << "orthonormality check 1:\n" << (tmat.adjoint()*tmat).real() << "\n\n" << (tmat.adjoint()*tmat).imag() << "\n\n";
1240  //std::cout << "orthonormality check 2:\n" << (tmat * tmat.adjoint()).real() << "\n\n" << (tmat * tmat.adjoint()).imag() << "\n\n";
1241 
1242  // make transformed copy of the representation
1243  Array<Eigen::MatrixXcd> trans_rep(head_group.size());
1244  Eigen::MatrixXd block_shape(Eigen::MatrixXd::Zero(kernel.cols(), kernel.cols()));
1245  //std::cout << "Transformed representation is:\n";
1246  for(Index i = 0; i < head_group.size(); i++) {
1247  trans_rep[head_group[i].index()] = tmat.adjoint() * (*get_MatrixXd(head_group[i].index())) * tmat;
1248  block_shape += (trans_rep[head_group[i].index()].cwiseProduct(trans_rep[head_group[i].index()].conjugate())).real();
1249  //std::cout << trans_rep[i] << "\n\n";
1250  }
1251 
1252  Index last_i = 0;
1253  for(Index ns = 0; ns < subspace_dims.size(); ns++) {
1254  double tnorm(0);
1255  Array<std::complex<double> > char_array;
1256 
1257  for(Index ng = 0; ng < trans_rep.size(); ng++) {
1258  cplx tchar(0, 0);
1259  for(Index i = last_i; i < last_i + subspace_dims[ns]; i++)
1260  tchar += trans_rep[ng](i, i);
1261  char_array.push_back(tchar);
1262  tnorm += std::norm(tchar);
1263  }
1264 
1265  if(almost_equal(tnorm, double(head_group.size()))) { // this representation is irreducible
1266  std::cout << "THE REPRESENTATION IS IRREDUCIBLE!!\n";
1267  std::cout << "It's characters are: " << char_array << "\n\n";
1268  Eigen::MatrixXd ttrans_mat(dim, 2 * subspace_dims[ns]);
1269  //std::cout << "Vectors in this subspace are:\n" << tmat.block(0, last_i, dim, subspace_dims[ns]) << "\n\n";
1270  ttrans_mat.leftCols(subspace_dims[ns]) = sqrt(2.0) * tmat.block(0, last_i, dim, subspace_dims[ns]).real();
1271  ttrans_mat.rightCols(subspace_dims[ns]) = sqrt(2.0) * tmat.block(0, last_i, dim, subspace_dims[ns]).imag();
1272  //std::cout << "Separated into components:\n" << ttrans_mat << "\n\n";
1273  //Only append to trans_mat if the new columns extend the space (i.e., are orthogonal)
1274 
1275  if(almost_zero((ttrans_mat.transpose()*trans_mat).norm(), 0.001)) {
1276  qr.compute(ttrans_mat);
1277  //it seems stupid to use two different decompositions that do almost the same thing, but
1278  // HouseholderQR is not rank-revealing, and colPivHouseholder mixes up the columns of the Q matrix.
1279  colqr.compute(ttrans_mat);
1280  Index rnk = colqr.rank();
1281  irrep_dims.push_back(subspace_dims[ns]);
1282  if(rnk == 2 * subspace_dims[ns])
1283  irrep_dims.push_back(subspace_dims[ns]);
1284  ttrans_mat = Eigen::MatrixXd(qr.householderQ()).leftCols(rnk);
1285  SymGroupRep t_rep(coord_transformed_copy(ttrans_mat.transpose()));
1286  //std::cout << "***Adding columns!\n" << Eigen::MatrixXd(qr.householderQ()).leftCols(rnk) << "\n\n";
1287  //trans_mat.block(0, Nfound, dim, rnk) = Eigen::MatrixXd(qr.householderQ()).leftCols(rnk);
1288  trans_mat.block(0, Nfound, dim, rnk) = ttrans_mat * (t_rep._symmetrized_irrep_trans_mat(head_group)).transpose();
1289  Nfound += rnk;
1290  found_new_irreps = true;
1291  }
1292  }
1293  last_i += subspace_dims[ns];
1294  }
1295  if(found_new_irreps) {
1296  qr.compute(trans_mat);
1297  kernel = Eigen::MatrixXd(qr.householderQ()).rightCols(dim - Nfound);
1298  break;
1299  }
1300  }
1301  if(found_new_irreps) {
1302  kci = 0;
1303  break;
1304  }
1305  }
1306  }
1307 
1308  // make transformed copy of the representation
1309  Eigen::MatrixXd block_shape(Eigen::MatrixXd::Zero(dim, dim));
1310  //std::cout << "Transformed representation is:\n";
1311  for(Index i = 0; i < head_group.size(); i++) {
1312  block_shape += (trans_mat.transpose() * (*get_MatrixXd(head_group[i].index())) * trans_mat).cwiseAbs2();
1313  }
1314  std::cout << "BLOCK MATRIX IS:\n"
1315  << block_shape << "\n\n";
1316  std::cout << "IRREP DIMENSIONS ARE: " << irrep_dims << "\n\n";
1317  return trans_mat.transpose();
1318 
1319  }
1320 
1321  //*******************************************************************************************
1322 
1324 
1325  const Array<Array<Index> > &conj_class(master_group().get_conjugacy_classes());
1326  const Array<Array<std::complex<double> > > &char_table(master_group().character_table());
1327 
1328  Eigen::MatrixXd tmat((*(at(0)->get_MatrixXd())).rows(), (*(at(0)->get_MatrixXd())).cols());
1329  tmat.setZero();
1330  Array<Eigen::MatrixXd> tarray(conj_class.size());
1331 
1332  for(Index i = 0; i < conj_class.size(); i++) {
1333  double dimension = char_table[i][0].real();
1334  for(Index j = 0; j < master_group().size(); j++) {
1335  double character = char_table[i][master_group().class_of_op(j)].real();
1336  Eigen::MatrixXd rep_mat = *(at(j)->get_MatrixXd());
1337  tmat += (character * rep_mat);
1338  }
1339  tarray[i] = ((dimension) / (master_group().size())) * tmat;
1340  }
1341 
1342  return tarray;
1343  }
1344 
1345  //*******************************************************************************************
1346 
1348  json.put_obj();
1349 
1350  // Member not included in json:
1351  //
1352  // Pointer to the m_master_group that generated this SymGroupRep
1353  // MasterSymGroup const *m_master_group;
1354 
1355  // class SymGroupRep : public Array<SymOpRepresentation *>
1356  json["symop_representations"].put_array();
1357  for(Index i = 0; i < size(); i++) {
1358  at(i)->to_json(json["symop_representations"]);
1359  }
1360 
1361  // int m_rep_ID;
1362  json["m_rep_ID"] = m_rep_ID;
1363 
1364  return json;
1365  }
1366 
1367  //*******************************************************************************************
1368 
1369  SymGroupRep subset_permutation_rep(const SymGroupRep &permute_rep, const Array<Index>::X2 &subsets) {
1370  SymGroupRep new_rep(SymGroupRep::NO_HOME, permute_rep.size());
1371  if(permute_rep.has_valid_master())
1372  new_rep = SymGroupRep(permute_rep.master_group());
1373 
1374  Array<Index> perm_sub;
1375  if(subsets.size())
1376  perm_sub.resize(subsets[0].size());
1377 
1378  Array<Index> tperm(subsets.size());
1379  for(Index np = 0; np < permute_rep.size(); ++np) {
1380  Permutation const *perm_ptr(permute_rep.get_permutation(np));
1381  if(perm_ptr == NULL) {
1382  // This check may not make sense. Some representations may not have all operations. If it's causing problems, comment it out
1383  std::cerr << "CRITICAL ERROR: In subset_permutation_rep(SymGroupRep,Array<Index>::X2), permute_rep is missing at least one permutation!\n"
1384  << " Exiting...\n";
1385  assert(0);
1386  exit(1);
1387  }
1388  Permutation iperm = perm_ptr->inverse();
1389  for(Index ns = 0; ns < subsets.size(); ++ns) {
1390  for(Index ne = 0; ne < subsets[ns].size(); ++ne) {
1391  perm_sub[ne] = iperm[subsets[ns][ne]];
1392  }
1393  Index ns2;
1394  for(ns2 = 0; ns2 < subsets.size(); ++ns2) {
1395  if(perm_sub.all_in(subsets[ns2])) {
1396  tperm[ns] = ns2;
1397  break;
1398  }
1399  }
1400  if(ns2 >= subsets.size()) {
1401  std::cerr << "CRITICAL ERROR: In subset_permutation_rep(SymGroupRep,Array<Index>::X2), subsets are not closed under permute_rep permutations!\n"
1402  << " Exiting...\n";
1403  assert(0);
1404  exit(1);
1405  }
1406  }
1407  new_rep.set_rep(np, SymPermutation(tperm));
1408  }
1409  return new_rep;
1410  }
1411 
1412  //*******************************************************************************************
1413 
1415  SymGroupRep new_rep(SymGroupRep::NO_HOME, permute_rep.size());
1416  if(permute_rep.has_valid_master())
1417  new_rep = SymGroupRep(permute_rep.master_group());
1418 
1419  Array<Index> rep_dims(sum_reps.size(), 0);
1420  if(permute_rep.get_permutation(0) == NULL) {
1421  std::cerr << "CRITICAL ERROR: In permuted_direct_sum_rep(SymGroupRep,Array<SymGroupRep const*>), permute_rep does not contain permutations!\n"
1422  << " Exiting...\n";
1423  assert(0);
1424  exit(1);
1425  }
1426 
1427  for(Index i = 0; i < sum_reps.size(); i++) {
1428  if(sum_reps[i] == NULL) {
1429  continue;
1430  }
1431  if((permute_rep.has_valid_master() != sum_reps[i]->has_valid_master())
1432  || (permute_rep.has_valid_master() && &(permute_rep.master_group()) != &(sum_reps[i]->master_group()))
1433  || sum_reps[i]->get_MatrixXd(0) == NULL) {
1434  std::cerr << "CRITICAL ERROR: In permuted_direct_sum_rep(SymGroupRep,Array<SymGroupRep const*>), found incompatible SymGroupReps!\n"
1435  << " Exiting...\n";
1436  assert(0);
1437  exit(1);
1438  }
1439  rep_dims[i] = (*sum_reps[i])[0]->get_MatrixXd()->cols();
1440  }
1441  //std::cout << "SUM_REPS is " << sum_reps << "\n";
1442  //std::cout << "REP_DIMS is " << rep_dims << "\n";
1443  Array<Index> sum_inds(cum_sum(rep_dims));
1444  Eigen::MatrixXd sum_mat(rep_dims.sum(), rep_dims.sum());
1445  Eigen::MatrixXd const *rep_mat_ptr(NULL);
1446  Permutation const *perm_ptr;
1447  for(Index g = 0; g < permute_rep.size(); g++) {
1448  sum_mat.setZero();
1449  perm_ptr = permute_rep.get_permutation(g);
1450  for(Index r = 0; r < perm_ptr->size(); r++) {
1451  if(rep_dims[r] == 0) continue;
1452  Index new_r = (*perm_ptr)[r];
1453  rep_mat_ptr = sum_reps[new_r]->get_MatrixXd(g);
1454  sum_mat.block(sum_inds[r], sum_inds[new_r], rep_dims[new_r], rep_dims[new_r]) = *rep_mat_ptr;
1455  }
1456  new_rep.set_rep(g, SymMatrixXd(sum_mat));
1457  }
1458  return new_rep;
1459  }
1460 
1461  //*******************************************************************************************
1462  SymGroupRep kron_rep(const SymGroupRep &LHS, const SymGroupRep &RHS) {
1463  if((LHS.has_valid_master() != RHS.has_valid_master()) || (LHS.has_valid_master() && &LHS.master_group() != &RHS.master_group())) {
1464  std::cerr << "CRITICAL ERROR: In kron_rep(SymGroupRep,SymGroupRep), taking product of two incompatible SymGroupReps!\n"
1465  << " Exiting...\n";
1466  exit(1);
1467  }
1468  SymGroupRep new_rep(SymGroupRep::NO_HOME, LHS.size());
1469  if(LHS.has_valid_master())
1470  new_rep = SymGroupRep(LHS.master_group());
1471 
1472  Eigen::MatrixXd tmat;
1473  for(Index i = 0; i < LHS.size(); i++) {
1474  //std::cout << "rep1 matrix:\n";
1475  //std::cout << *(rep1->get_MatrixXd(i)) << '\n';
1476  //std::cout << "rep2 matrix:\n";
1477  //std::cout << *(rep2->get_MatrixXd(i)) << '\n';
1478  assert(LHS.get_MatrixXd(i) && RHS.get_MatrixXd(i));
1479  kroneckerProduct(*(LHS.get_MatrixXd(i)), *(RHS.get_MatrixXd(i)), tmat);
1480  //std::cout << "Total matrix:\n" << tmat << '\n';
1481  new_rep.set_rep(i, SymMatrixXd(tmat));
1482  }
1483  return new_rep;
1484  }
1485 
1486 
1487  //*******************************************************************************************
1488 
1489  // If 'm_home_group' is not nullptr, should be initialized accordingly
1491  // Member not included in json:
1492  //
1493  // Pointer to the m_master_group that generated this SymGroupRep
1494  // MasterSymGroup const *m_master_group;
1495 
1496  // class SymGroupRep : public Array<SymOpRepresentation *>
1497 
1498  for(Index i = 0; i < size(); i++) {
1499  delete at(i);
1500  }
1501  clear();
1502  //std::cout << "Resizing SymGroupRep to " << json["symop_representations"].size() << std::endl;
1503  resize(json["symop_representations"].size());
1504  //std::cout << "Reading in the symmetry operations" << std::endl;
1505  for(int i = 0; i < json["symop_representations"].size(); i++) {
1507  CASM::from_json(at(i), json["symop_representations"][i]);
1508  }
1509 
1510  //std::cout << "Reading in m_rep_id" << std::endl;
1511  // int m_rep_ID;
1512  CASM::from_json(m_rep_ID, json["m_rep_ID"]);
1513 
1514  //std::cout << "Done reading in the permute_group" << std::endl;
1515  }
1516 
1517  //*******************************************************************************************
1518 
1520  return rep.to_json(json);
1521  }
1522 
1523 
1524  // If 'm_master_group' is not NULL, should be initialized accordingly
1525  void from_json(SymGroupRep &rep, const jsonParser &json) {
1526  rep.from_json(json);
1527  }
1528 
1529 
1530 }
1531 
Eigen::MatrixXd MatrixXd
size_type size() const
Returns array size if *this is a JSON array, object size if *this is a JSON object, 1 otherwise.
Definition: jsonParser.cc:430
jsonParser & to_json(jsonParser &json) const
virtual SymOpRepresentation * copy() const =0
Make copy of Derived object through Base-class interface.
ReturnArray< Eigen::MatrixXd > get_projection_operators() const
std::vector< Eigen::MatrixXd > irreducible_wedges(const SymGroup &head_group, std::vector< Index > &multiplicities) const
Definition: SymGroupRep.cc:442
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
Definition: CASM_math.hh:41
ReturnArray< T > cum_sum(const Array< T > &arr)
Definition: CASM_math.hh:341
virtual Eigen::MatrixXd const * get_MatrixXd() const
void from_json(ClexDescription &desc, const jsonParser &json)
Index size() const
Definition: Array.hh:145
const MasterSymGroup & master_group() const
Definition: SymGroup.hh:56
bool almost_contains(const SymOpRepresentation *&test_elem, double tol_val=TOL) const
Definition: Array.hh:284
Type-safe ID object for communicating and accessing Symmetry representation info. ...
bool empty() const
Returns true if SymGroupRepID has not been initialized with valid group_index or rep_index.
void push_back(const T &toPush)
Definition: Array.hh:513
jsonParser & to_json(const ClexDescription &desc, jsonParser &json)
ReturnArray< Index > num_each_irrep() const
Definition: SymGroupRep.cc:695
SymGroupRep subset_permutation_rep(const SymGroupRep &permute_rep, const Array< Index >::X2 &subsets)
ReturnArray< Array< Eigen::VectorXd > > _calc_special_irrep_directions(const SymGroup &subgroup) const
Definition: SymGroupRep.cc:471
Index index() const
Index of this operation within the master_group.
Eigen::MatrixXd block_shape_matrix() const
Definition: SymGroupRep.cc:180
Main CASM namespace.
Definition: complete.cpp:8
void from_json(const jsonParser &json)
ReturnArray< SymGroupRepID > get_irrep_IDs(const SymGroup &subgroup) const
Definition: SymGroupRep.cc:747
const double TOL
bool is_irrep() const
Definition: SymGroupRep.cc:981
double ran0(int &idum)
Definition: CASM_math.cc:12
void set_identifiers(const MasterSymGroup &new_group, SymGroupRepID new_rep_ID)
Change m_master_group and determine op_index.
Eigen::MatrixXd get_irrep_trans_mat(const SymGroup &head_group) const
void print_MatrixXd(std::ostream &stream) const
Definition: SymGroupRep.cc:152
SymGroupRep kron_rep(const SymGroupRep &LHS, const SymGroupRep &RHS)
SymPermutation describes how a symmetry operation permutes a list of 'things' For example...
virtual double character() const
Calculates character of the representation (if well-defined)
SymGroup is a collection of symmetry operations that satisfy the group property The symmetry operatio...
Definition: SymGroup.hh:33
void calc_new_irreps(int max_iter=1000) const
Definition: SymGroupRep.cc:772
void clear()
Definition: Array.hh:216
MasterSymGroup const * m_master_group
Pointer to the home_group that generated this SymGroupRep.
Definition: SymGroupRep.hh:164
Eigen::MatrixXd::Index EigenIndex
For integer indexing:
bool has_valid_master() const
Definition: SymGroupRep.hh:71
SymOp is the Coordinate representation of a symmetry operation it keeps fraction (FRAC) and Cartesian...
Definition: SymOp.hh:28
SymGroupRep const & get_irrep(Index i) const
Get symrep for a particular irrep.
Definition: SymGroup.cc:3121
ReturnArray< Array< Eigen::MatrixXd > > calc_special_subspaces(const SymGroup &subgroup) const
Definition: SymGroupRep.cc:568
typename multivector_impl::multivector_tmp< T, N >::type X
Definition: multivector.hh:28
Eigen::MatrixXd const * get_MatrixXd(Index i) const
Definition: SymGroupRep.cc:253
virtual Permutation const * get_permutation() const
virtual jsonParser & to_json(jsonParser &json) const =0
T norm(const Tensor< T > &ttens)
Definition: Tensor.hh:968
EigenIndex Index
For long integer indexing:
Permutation inverse() const
Construct permutation that undoes the permutation performed by 'this'.
Definition: Permutation.cc:84
void print_permutation(std::ostream &stream) const
Definition: SymGroupRep.cc:138
Index num_blocks() const
Definition: SymGroupRep.cc:207
void set_irrep_ID(Index i, SymGroupRepID ID) const
set symrep ID of a particular irrep
Definition: SymGroup.cc:3079
const Array< std::complex< double > >::X2 & character_table() const
Definition: SymGroup.cc:3212
const Array< Index >::X3 & subgroups() const
Definition: SymGroup.cc:3243
Eigen::VectorXd VectorXd
SymOpRepresentation * sum() const
Index dim() const
Matrix dimension of representation.
Definition: SymGroupRep.hh:229
T min(const T &A, const T &B)
Definition: CASM_math.hh:25
const Array< Index >::X2 & get_conjugacy_classes() const
Definition: SymGroup.cc:3197
SymOpRepresentation *& at(Index ind)
Definition: Array.hh:157
SymOpRepresentation is the base class for anything describes a symmetry operation.
SymGroupRepID add_copy_to_master() const
Adds copy of this representation its home_group.
Definition: SymGroupRep.cc:123
void swap_elem(Index i, Index j)
Definition: Array.hh:231
SymGroupRep & operator=(const SymGroupRep &RHS)
Definition: SymGroupRep.cc:27
Index size() const
Definition: Permutation.hh:53
Index find(const T &test_elem) const
Definition: Array.hh:707
SymGroupRepID get_irrep_ID(Index i) const
Get symrep ID of a particular irrep.
Definition: SymGroup.cc:3088
void push_back_copy(const SymOpRepresentation &_pushed)
Definition: SymGroupRep.cc:244
Array & append(const Array &new_tail)
Definition: Array.hh:897
Generalized symmetry matrix representation for arbitrary dimension Can be used to describe applicatio...
Definition: SymMatrixXd.hh:22
bool all_in(const Array &superset) const
Definition: Array.hh:664
ReturnArray< Index > num_each_real_irrep(const SymGroup &subgroup, bool verbose=false) const
Definition: SymGroupRep.cc:668
const MasterSymGroup & master_group() const
Definition: SymGroupRep.hh:66
Permutation const * get_permutation(Index i) const
Definition: SymGroupRep.cc:265
jsonParser & put_obj()
Puts new empty JSON object.
Definition: jsonParser.hh:276
ReturnArray< Index > partition_distinct_values(const Eigen::MatrixBase< Derived > &value, double tol=TOL)
Definition: CASM_math.hh:361
SymGroupRep permuted_direct_sum_rep(const SymGroupRep &permute_rep, const Array< SymGroupRep const * > &sum_reps)
SymGroupRep coord_transformed_copy(const Eigen::MatrixXd &trans_mat) const
Definition: SymGroupRep.cc:280
Eigen::MatrixXd _symmetrized_irrep_trans_mat(const SymGroup &subgroup) const
Definition: SymGroupRep.cc:304
SymGroupRep is an alternative representation of a SymGroup for something other than real space...
Definition: SymGroupRep.hh:30
Index class_of_op(Index i) const
Get conjugacy class index of operation at(i)
Definition: SymGroup.cc:3071
multivector< Eigen::VectorXd >::X< 3 > calc_special_total_directions(const SymGroup &subgroup) const
Definition: SymGroupRep.cc:415
Eigen::MatrixXd get_irrep_trans_mat_blind(const SymGroup &head_group) const
const Array< bool > & get_complex_irrep_list() const
Definition: SymGroup.cc:3204
SymGroupRepID m_rep_ID
rep_ID is unique identifier of a specific SymGroupRep instantiation
Definition: SymGroupRep.hh:161
void set_master_group(const MasterSymGroup &master, const SymGroupRepID &_rep_ID)
Definition: SymGroupRep.cc:43
T & back()
Definition: Array.hh:177
SymGroupRepID add_representation(const SymGroupRep &new_rep) const
Add a new representation by passing a reference. SymGroup will store a copy.
Definition: SymGroup.cc:361
Basic std::vector like container (deprecated)
jsonParser & put_array()
Puts new empty JSON array.
Definition: jsonParser.hh:285
bool almost_equal(const GenericCluster< CoordType > &LHS, const GenericCluster< CoordType > &RHS, double tol)
int round(double val)
Definition: CASM_math.cc:6
bool valid_index(Index i)
SymGroupRep const & representation(SymGroupRepID i) const
Const access of alternate Representations of a SymGroup.
Definition: SymGroup.cc:375
void set_rep(const SymOpRepresentation &base_rep, const SymOpRepresentation &new_rep) const
Definition: SymGroupRep.cc:82