12 namespace SymRepTools_v2 {
14 namespace IrrepDecompositionImpl {
18 Eigen::MatrixXcd
prettyc(
const Eigen::MatrixXcd &M) {
20 Eigen::MatrixXcd Mp(M);
21 for (
int i = 0; i < M.rows(); i++) {
22 for (
int j = 0; j < M.cols(); j++) {
23 if (std::abs(
std::round(M(i, j).real()) - M(i, j).real()) < tol) {
26 if (std::abs(
std::round(M(i, j).imag()) - M(i, j).imag()) < tol) {
39 for (
int i = 0; i < M.rows(); i++) {
40 for (
int j = 0; j < M.cols(); j++) {
41 if (std::abs(
std::round(M(i, j)) - M(i, j)) < tol) {
58 return Eigen::MatrixXd::Zero(rows, cols);
66 return Eigen::MatrixXcd::Zero(rows, cols);
78 phase = std::complex<double>(1., 0.);
108 phase = std::complex<double>(0., 1.);
123 Eigen::MatrixXcd
const &kernel) {
124 Index dim = rep[0].rows();
131 auto const &phase = params.
phase;
132 Eigen::MatrixXcd M_init = phase * col_i * col_j.adjoint() +
133 std::conj(phase) * col_j * col_i.adjoint();
137 for (
Index element_index : head_group) {
138 M += rep[element_index] * M_init * rep[element_index].transpose();
144 Eigen::HouseholderQR<Eigen::MatrixXcd> qr;
145 qr.compute(subspace);
146 return Eigen::MatrixXcd(qr.householderQ())
147 .rightCols(subspace.rows() - subspace.cols());
150 Eigen::HouseholderQR<Eigen::MatrixXd> qr;
151 qr.compute(subspace);
153 .rightCols(subspace.rows() - subspace.cols());
158 Index end = begin + 1;
159 while (end < eigenvalues.size() &&
182 bool allow_complex) {
183 Index dim = KV_matrix.rows();
186 Eigen::MatrixXcd X = (KV_matrix).block(0, begin, dim, end - begin);
187 Eigen::MatrixXcd subspace_init;
191 subspace_init = Eigen::MatrixXcd::Zero(dim, 2 * X.cols());
192 subspace_init.leftCols(X.cols()) =
193 sqrt(2.0) * X.real().cast<std::complex<double>>();
194 subspace_init.rightCols(X.cols()) =
195 sqrt(2.0) * X.imag().cast<std::complex<double>>();
202 Eigen::HouseholderQR<Eigen::MatrixXcd> qr;
203 Eigen::ColPivHouseholderQR<Eigen::MatrixXcd> colqr;
204 colqr.setThreshold(
TOL);
206 qr.compute(subspace_init);
207 colqr.compute(subspace_init);
208 Eigen::MatrixXcd Q = qr.householderQ();
209 Eigen::MatrixXcd irrep_subspace = Q.leftCols(colqr.rank());
210 return irrep_subspace;
215 Eigen::VectorXcd characters(rep.size());
217 Index element_index = 0;
218 for (Eigen::MatrixXcd
const &matrix : rep) {
219 characters(element_index) = matrix.trace();
229 Index element_index = 0;
231 characters(element_index) = matrix.trace();
242 Index element_index = 0;
243 for (Eigen::MatrixXcd
const &matrix : rep) {
246 if (!
almost_zero(matrix.block(begin, 0, end - begin, begin), tol)) {
251 if (end != matrix.cols()) {
253 matrix.block(begin, end, end - begin, matrix.cols() - end),
260 if (!
almost_zero(matrix.block(0, begin, begin, end - begin), tol)) {
265 if (end != matrix.rows()) {
267 matrix.block(end, begin, matrix.rows() - end, end - begin),
281 Eigen::VectorXcd characters(rep.size());
283 Index element_index = 0;
284 for (Eigen::MatrixXcd
const &matrix : rep) {
285 characters(element_index) =
286 matrix.block(begin, begin, end - begin, end - begin).trace();
293 double squared_norm = 0.0;
294 for (
Index i = 0; i < characters.size(); ++i) {
295 squared_norm +=
std::norm(characters(i));
301 double squared_norm = 0.0;
302 for (
Index i = 0; i < characters.size(); ++i) {
303 squared_norm += characters(i) * characters(i);
309 return (matrix.array().conjugate() * matrix.array()).sum();
318 Eigen::MatrixXcd
const &space_B) {
323 Eigen::MatrixXcd
extend(Eigen::MatrixXcd
const &space_A,
324 Eigen::MatrixXcd
const &space_B) {
325 Eigen::MatrixXcd result(space_A.rows(), space_A.cols() + space_B.cols());
326 result.leftCols(space_A.cols()) = space_A;
327 result.rightCols(space_B.cols()) = space_B;
334 Eigen::MatrixXd result(space_A.rows(), space_A.cols() + space_B.cols());
335 result.leftCols(space_A.cols()) = space_A;
336 result.rightCols(space_B.cols()) = space_B;
343 total_dim += irrep.irrep_dim;
357 std::vector<Eigen::MatrixXcd>
const &transformed_rep,
358 Index _head_group_size,
double _tol,
bool allow_complex,
Index _begin,
360 : head_group_size(_head_group_size),
364 irrep_dim(end - begin) {
377 std::complex<double> complex_one{1., 0.};
379 std::complex<double> complex_size{double(
characters.size()), 0.};
400 if (this_is_identity != other_is_identity) {
401 return this_is_identity;
413 bool other_is_gerade = other.
is_gerade();
414 if (this_is_gerade != other_is_gerade) {
415 return this_is_gerade;
446 throw std::runtime_error(
"Error comparing PossibleIrrep, tied");
457 Eigen::MatrixXcd
const &commuter, Eigen::MatrixXcd
const &kernel,
459 bool allow_complex) {
466 double dim = kernel.rows();
467 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXcd> esolve;
468 double scale = dim * sqrt(dim);
469 esolve.compute(scale * kernel.adjoint() * commuter * kernel);
471 Eigen::MatrixXcd KV_matrix = kernel * esolve.eigenvectors();
478 std::vector<Eigen::MatrixXcd> transformed_rep;
479 transformed_rep.reserve(head_group.size());
480 for (
auto const &element_index : head_group) {
481 transformed_rep.push_back(KV_matrix.adjoint() * rep[element_index] *
493 std::vector<PossibleIrrep> possible_irreps;
497 possible_irreps.emplace_back(eigenvalues, KV_matrix, transformed_rep,
498 head_group.size(), is_irrep_tol, allow_complex,
501 }
while (begin != eigenvalues.size());
503 return possible_irreps;
508 std::vector<IrrepInfo> irrep_info;
510 irrep_info.emplace_back(irrep.subspace.adjoint(), irrep.characters);
512 if (irrep.subspace.cols() == 2 * (irrep.end - irrep.begin))
513 irrep_info.back().pseudo_irrep =
true;
515 irrep_info.back().pseudo_irrep =
false;
520 Index irrep_index = 0;
521 for (
Index i = 0; i < irrep_info.size() - 1; ++i) {
522 irrep_info[i].index = irrep_index;
523 if (
almost_equal(irrep_info[i + 1].characters, irrep_info[i].characters,
549 subspace.adjoint().template cast<std::complex<double>>();
552 for (
const auto &direction_orbit : subspace_irrep.
directions) {
553 std::vector<Eigen::VectorXd> new_orbit;
554 new_orbit.reserve(direction_orbit.size());
555 for (
const auto &directions : direction_orbit) {
556 new_orbit.push_back(subspace * directions);
558 result.
directions.push_back(std::move(new_orbit));
568 double characters_squared_norm = 0;
569 for (
Index element_index : head_group) {
570 double character = rep[element_index].trace();
571 characters_squared_norm += character * character;
573 return almost_equal(characters_squared_norm,
double(head_group.size()),
TOL);
665 bool allow_complex) {
667 return std::vector<IrrepInfo>();
669 int dim = rep[0].rows();
678 Eigen::MatrixXcd kernel =
complex_I(dim, dim);
679 Eigen::MatrixXcd adapted_subspace{dim, 0};
685 std::set<PossibleIrrep> irreps;
690 commuter_params.
reset(kernel);
692 double is_irrep_tol =
TOL;
696 if (!commuter_params.
valid()) {
704 Eigen::MatrixXcd commuter =
722 commuter, kernel, rep, head_group, is_irrep_tol, allow_complex);
727 bool any_new_irreps =
false;
728 for (
auto const &possible_irrep : possible_irreps) {
729 if (possible_irrep.is_irrep &&
731 irreps.insert(possible_irrep);
732 adapted_subspace =
extend(adapted_subspace, possible_irrep.subspace);
733 any_new_irreps =
true;
739 if (any_new_irreps && adapted_subspace.cols() != dim) {
741 commuter_params.
reset(kernel);
742 if (kernel.cols() + adapted_subspace.cols() != adapted_subspace.rows()) {
743 throw std::runtime_error(
744 "Unknown error finding irreps: dimension mismatch");
749 }
while (adapted_subspace.cols() != dim);
766 std::vector<IrrepInfo>
const &subspace_irreps,
768 std::vector<IrrepInfo> fullspace_irreps;
769 fullspace_irreps.reserve(subspace_irreps.size());
770 for (
auto const &irrep : subspace_irreps) {
773 return fullspace_irreps;
780 if (!subspace.isIdentity()) {
782 subspace.cols() * head_group.size());
784 for (
Index element_index : head_group) {
785 symspace.block(0, l, subspace.rows(), subspace.cols()) =
786 rep[element_index] * subspace;
787 l += subspace.cols();
789 Eigen::ColPivHouseholderQR<Eigen::MatrixXd> colqr(symspace);
790 colqr.setThreshold(
TOL);
805 subspace.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV)
809 for (
Index i = 0; i < fullspace_rep.size(); ++i) {
810 subspace_rep.push_back(trans_mat * fullspace_rep[i] * rightmat);
819 std::vector<IrrepInfo>
const &irreps,
822 std::vector<IrrepInfo> symmetrized_irreps;
823 double vec_compare_tol =
TOL;
824 bool use_all_subgroups =
false;
825 for (
const auto &irrep : irreps) {
826 Eigen::MatrixXcd irrep_subspace = irrep.trans_mat.adjoint();
830 vec_compare_tol, cyclic_subgroups,
831 all_subgroups, use_all_subgroups);
834 irrep_special_directions, irrep_subspace, vec_compare_tol);
838 (irrep_subspace * symmetrizer_matrix).adjoint();
839 symmetrized_irrep.directions =
to_real(irrep_special_directions);
840 symmetrized_irreps.push_back(symmetrized_irrep);
842 return symmetrized_irreps;
Eigen::CwiseUnaryOp< decltype(Local::round_l< typename Derived::Scalar >), const Derived > round(const Eigen::MatrixBase< Derived > &val)
Round Eigen::MatrixXd.
T norm(const Tensor< T > &ttens)
IdentitySymRepBuilder Identity()
bool almost_equal(ClusterInvariants const &A, ClusterInvariants const &B, double tol)
Check if ClusterInvariants are equal.
Container::value_type sum(const Container &container, typename Container::value_type init_val=0)
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
INDEX_TYPE Index
For long integer indexing:
typename multivector_impl::multivector_tmp< T, N >::type X