1
0
Files
toddcox-faster/include/tc/group.hpp
2021-11-12 23:07:42 -05:00

175 lines
4.4 KiB
C++

#pragma once
#include <string>
#include <sstream>
#include <numeric>
#include <Eigen/Eigen>
namespace tc {
template<class T>
std::string stringify(const T &vec) {
std::stringstream ss;
ss << "[" << vec.transpose() << "]";
return ss.str();
}
}
namespace tc {
using Symbol = Eigen::Vector<unsigned int, Eigen::Dynamic>;
using MatrixXui = Eigen::Matrix<unsigned int, Eigen::Dynamic, Eigen::Dynamic>;
using ArrayXui = Eigen::Array<unsigned int, Eigen::Dynamic, Eigen::Dynamic>;
/// A Coxeter Matrix
class Group : public MatrixXui {
public:
using Base = MatrixXui;
std::string name = "G";
Symbol gens;
explicit Group(size_t rank) : Base(rank, rank), gens(rank) {
for (Eigen::Index i = 0; i < rank; ++i) {
gens(i) = i;
}
}
[[nodiscard]] size_t rank() const {
return rows();
}
};
Group subgroup(const Group &group, const Symbol &gens) {
size_t rank = group.size();
size_t srank = gens.size();
Group res(srank);
res.name = group.name + ":" + stringify(gens);
res.gens = gens;
for (Eigen::Index i = 0; i < srank; ++i) {
for (Eigen::Index j = 0; j < srank; ++j) {
res(i, j) = group(gens[i], gens[j]);
}
}
return res;
}
unsigned int factorial(unsigned int n) {
unsigned int res = 1;
for (int i = 1; i <= n; ++i) {
res *= i;
}
return res;
}
unsigned int choose(unsigned int n, unsigned int k) {
return factorial(n) / factorial(k) / factorial(n - k);
}
using SubGroups = std::vector<Group>;
SubGroups subgroups(const Group &group, size_t srank) {
size_t rank = group.rank();
std::vector<bool> mask(rank, false);
std::fill_n(mask.begin(), srank, true);
SubGroups res;
res.reserve(choose(rank, srank));
Symbol row(srank);
do {
for (int j = 0, k = 0; j < rank; ++j) {
if (mask[j])
row(k++) = j;
}
res.push_back(subgroup(group, row));
} while (std::prev_permutation(mask.begin(), mask.end()));
return res;
}
/**
* Determine which of g_gens are the correct names for sg_gens within the current context
*/
Symbol recontext_gens(
size_t rank,
Symbol g_gens,
Symbol sg_gens
) {
std::sort(g_gens.begin(), g_gens.end());
std::sort(sg_gens.begin(), sg_gens.end());
int inv_gen_map[rank];
for (int i = 0; i < g_gens.size(); ++i) {
inv_gen_map[g_gens[i]] = i;
}
Symbol s_sg_gens(sg_gens.size());
for (int i = 0; i < sg_gens.size(); ++i) {
s_sg_gens[i] = inv_gen_map[sg_gens[i]];
}
std::sort(s_sg_gens.begin(), s_sg_gens.end());
return s_sg_gens;
}
/**
* Create a named coxeter matrix from a simplified schlafli symbol
*/
Group schlafli(const Symbol &mults, const std::string &name) {
size_t rank = mults.size() + 1;
Group res(rank);
res.name = name;
res.fill(2);
res.diagonal().fill(1);
res.topRightCorner(rank - 1, rank - 1).diagonal() << mults;
res.bottomLeftCorner(rank - 1, rank - 1).diagonal() << mults;
return res;
}
/**
* Create a coxeter matrix from a simplified schlafli symbol.
*/
Group schlafli(const Symbol &mults) {
return schlafli(mults, stringify(mults));
}
Group product(const Group &g, const Group &h) {
Group res(g.rank() + h.rank());
res.name = g.name + "*" + h.name;
res.fill(2);
Eigen::Index off = 0;
res.block(off, off, g.rank(), g.rank()) << g.array() + off;
off += (Eigen::Index) g.rank();
res.block(off, off, h.rank(), h.rank()) << h.array() + off;
off += (Eigen::Index) h.rank();
return res;
}
Group power(const Group &g, size_t p) {
Group res(g.rank() * p);
res.name = g.name + "^" + std::to_string(p);
res.fill(2);
for (Eigen::Index k = 0; k < p; ++k) {
auto off = (Eigen::Index) g.rank() * k;
res.block(off, off, g.rank(), g.rank()) << g.array() + off;
}
return res;
}
}