1
0

Make tc::Group an Eigen::Matrix (Schafli Matrix)

Makes tc::Group a direct subclass of Eigen::Matrix. Group should represent a Schlafli matrix.

Added a note that tc::solve assumes the matrix to be for a coxeter group.

In theory we could also implement the "normal" todd-coxeter and allow any Schlafli matrix as input.
This commit is contained in:
David Allemang
2021-11-01 16:58:48 -04:00
parent 6585d79ed9
commit 24d4d1873a
4 changed files with 172 additions and 213 deletions

View File

@@ -15,7 +15,7 @@ void test(const G &group) {
int order = cosets.order(); int order = cosets.order();
std::cout std::cout
<< std::setw(7) << group.name() << ", " << std::setw(7) << group.name << ", "
<< std::setw(7) << order << ", " << std::setw(7) << order << ", "
<< std::fixed << std::setprecision(6) << diff << "s" << std::fixed << std::setprecision(6) << diff << "s"
<< std::endl; << std::endl;

View File

@@ -10,81 +10,59 @@
#include <Eigen/Eigen> #include <Eigen/Eigen>
#include <iostream> #include <iostream>
namespace {
template<class T>
std::string stringify(const T &vec) {
std::stringstream ss;
ss << "[" << vec << "]";
return ss.str();
}
}
namespace tc { namespace tc {
/// A Schlafli Matrix
template<unsigned int Rank> template<unsigned int Rank>
struct Group; class Group : public Eigen::Matrix<unsigned int, Rank, Rank> {
template<unsigned int Rank, unsigned int PRank>
struct SubGroup;
template<unsigned int Rank>
class Group {
public: public:
using Matrix = Eigen::Matrix<unsigned int, Rank, Rank>; using Base = Eigen::Matrix<unsigned int, Rank, Rank>;
private: std::string name;
public:
std::string _name;
Matrix _data;
Eigen::SelfAdjointView<Matrix, Eigen::Upper> _mults;
public: using Base::Base;
Group(const Group<Rank> &g) :
_name(g._name),
_data(g._data),
_mults(_data) {
}
Group(Group &&g) noexcept:
_name(std::move(g._name)),
_data(std::move(g._data)),
_mults(_data) {
}
explicit Group(std::string name = "G") :
_name(std::move(name)),
_data(),
_mults(_data) {
_data.fill(2);
}
unsigned int rank() const {
return _data.rows();
}
std::string name() const {
return _name;
}
typename Matrix::Scalar &operator()(int a, int b) {
return _mults(a, b);
}
typename Matrix::Scalar operator()(int a, int b) const {
return _mults(a, b);
}
}; };
template<unsigned int Rank>
using Symbol = Eigen::Vector<unsigned int, Rank>;
template<unsigned int Rank>
Group<Rank> schlafli(const Symbol<Rank - 1> &mults, const std::string &name) {
Group<Rank> res;
res.name = name;
res.fill(2);
res.topRightCorner(Rank - 1, Rank - 1).diagonal() << mults;
res.bottomLeftCorner(Rank - 1, Rank - 1).diagonal() << mults;
return res;
}
template<unsigned int Rank>
Group<Rank> schlafli(const Symbol<Rank - 1> &mults) {
return schlafli<Rank>(mults, stringify(mults));
}
template<unsigned int GR, unsigned int HR> template<unsigned int GR, unsigned int HR>
Group<GR + HR> product(const Group<GR> &g, const Group<HR> &h) { Group<GR + HR> product(const Group<GR> &g, const Group<HR> &h) {
std::stringstream ss; Group<GR + HR> res;
ss << g.name << "*" << h.name; res.name = g.name + "*" + h.name;
Group<GR + HR> res(ss.str()); res.fill(2);
int off = 0; int off = 0;
for (int i = 0; i < GR; ++i) { res.block(off, off, GR, GR) << g.array() + off;
for (int j = i; j < GR; ++j) {
res(i + off, j + off) = g(i, j);
}
}
off += GR; off += GR;
for (int i = 0; i < HR; ++i) { res.block(off, off, HR, HR) << h.array() + off;
for (int j = i; j < HR; ++j) {
res(i + off, j + off) = h(i, j);
}
}
off += HR; off += HR;
return res; return res;
@@ -92,19 +70,14 @@ namespace tc {
template<unsigned int GR, unsigned int P> template<unsigned int GR, unsigned int P>
Group<GR * P> power(const Group<GR> &g) { Group<GR * P> power(const Group<GR> &g) {
std::stringstream ss; Group<GR * P> res;
ss << g.name << "^" << P; res.name = g.name + "^" + P;
Group<GR * P> res(ss.str()); res.fill(2);
for (int k = 0; k < P; ++k) { for (int k = 0; k < P; ++k) {
int off = k * GR; int off = k * GR;
res.block(off, off, GR, GR) << g.array() + off;
for (int i = 0; i < GR; ++i) {
for (int j = i; j < GR; ++j) {
res(i + off, j + off) = g(i, j);
}
}
} }
return res; return res;

View File

@@ -242,8 +242,11 @@ namespace {
} }
namespace tc { namespace tc {
/**
* Assumes that g is a coxeter group - that is, self-adjoint and the diagonal is 2.
*/
template<unsigned int Rank> template<unsigned int Rank>
tc::Cosets<Rank> solve(const Group <Rank> &g, const std::vector<int> &sub_gens = {}) { tc::Cosets<Rank> solve(const Group <Rank> &group, const std::vector<int> &sub_gens = {}) {
tc::Cosets<Rank> cosets; tc::Cosets<Rank> cosets;
cosets.add_row(); cosets.add_row();
@@ -256,7 +259,7 @@ namespace tc {
cosets.put(0, gen, 0); cosets.put(0, gen, 0);
} }
Tables<Rank> tables(g); Tables<Rank> tables(group);
tables.add_row(); tables.add_row();
tables.initialize(0, cosets); tables.initialize(0, cosets);

View File

@@ -2,167 +2,150 @@
#include "core.hpp" #include "core.hpp"
namespace tc { namespace tc::group {
/** /**
* Construct a group from a (simplified) Schlafli Symbol of the form [a, b, ..., c] * Universal Coxeter Group
* @param mults: The sequence of multiplicites between adjacent generators.
*/ */
template<unsigned int Rank> template<unsigned int Rank>
Group <Rank> schlafli(const std::array<unsigned int, Rank - 1> &mults, const std::string &name) { Group <Rank> U() {
Group<Rank> g(name); std::stringstream ss;
ss << "U(" << Rank << ")";
for (int i = 0; i < Rank - 1; i++) { Group<Rank> res;
g(i, i + 1) = mults[i]; res.name = ss.str();
res.fill(2);
return res;
}
/**
* Simplex
*/
template<unsigned int Rank>
Group <Rank> A() {
std::stringstream ss;
ss << "A(" << Rank << ")";
if (Rank == 0) {
Group<Rank> res;
res.name = ss.str();
return res;
} }
std::array<unsigned int, Rank - 1> mults;
mults.fill(3);
return schlafli<Rank>(mults, ss.str());
}
/**
* Cube, Orthoplex
*/
template<unsigned int Rank>
Group <Rank> B() {
std::stringstream ss;
ss << "B(" << Rank << ")";
tc::Symbol<Rank - 1> mults;
mults.fill(3);
mults(0) = 4;
return schlafli<Rank>(mults, ss.str());
}
/**
* Demicube, Orthoplex
*/
template<unsigned int Rank>
Group <Rank> D() {
std::stringstream ss;
ss << "D(" << Rank << ")";
tc::Symbol<Rank - 1> mults;
mults.fill(3);
mults(Rank - 2) = 2;
Group<Rank> g = schlafli<Rank>(mults, ss.str());
g(1, Rank - 1) = 3;
g(Rank - 1, 1) = 3;
return g; return g;
} }
/** /**
* Construct a group from a (simplified) Schlafli Symbol of the form [a, b, ..., c] * E groups
* @param mults: The sequence of multiplicites between adjacent generators.
*/ */
template<unsigned int Rank> template<unsigned int Rank>
Group <Rank> schlafli(const std::array<unsigned int, Rank - 1> &mults) { Group <Rank> E() {
std::stringstream ss; std::stringstream ss;
ss << "["; ss << "E(" << Rank << ")";
if (Rank) {
for (size_t i = 0; i < Rank - 2; ++i) { tc::Symbol<Rank - 1> mults;
ss << mults[i] << ","; mults.fill(3);
} mults(Rank - 2) = 2;
ss << mults[Rank - 1];
} Group<Rank> g = schlafli<Rank>(mults, ss.str());
ss << "]"; g(2, Rank - 1) = 3;
g(Rank - 1, 2) = 3;
return g;
}
/**
* 24 Cell
*/
Group<4> F4() {
return schlafli<4>({3, 4, 3}, "F4");
}
/**
* Hexagon
*/
Group<2> G2() {
return schlafli<2>(tc::Symbol<1>(6), "G2");
}
/**
* Icosahedron
*/
template<unsigned int Rank>
Group <Rank> H() {
std::stringstream ss;
ss << "H(" << Rank << ")";
tc::Symbol<Rank - 1> mults;
mults.fill(3);
mults(0) = 5;
return schlafli<Rank>(mults, ss.str()); return schlafli<Rank>(mults, ss.str());
} }
namespace group { /**
/** * Polygonal
* Simplex */
*/ Group<2> I2(unsigned int n) {
template<unsigned int Rank> std::stringstream ss;
Group <Rank> A() { ss << "I2(" << n << ")";
std::stringstream ss;
ss << "A(" << Rank << ")";
if (Rank == 0) return schlafli<2>(tc::Symbol<1>(n), ss.str());
return Group<Rank>(ss.str()); }
std::array<unsigned int, Rank - 1> mults; /**
mults.fill(3); * Toroidal. I2(n) * I2(m)
*/
Group<4> T(unsigned int n, unsigned int m) {
std::stringstream ss;
ss << "T(" << n << "," << m << ")";
return schlafli<Rank>(mults, ss.str()); return schlafli<4>({n, 2, m}, ss.str());
} }
/** /**
* Cube, Orthoplex * Toroidal. T(n, n)
*/ */
template<unsigned int Rank> Group<4> T(unsigned int n) {
Group <Rank> B() { std::stringstream ss;
std::stringstream ss; ss << "T(" << n << ")";
ss << "B(" << Rank << ")";
std::array<unsigned int, Rank - 1> mults; return schlafli<4>({n, 2, n}, ss.str());
mults.fill(3);
mults[0] = 4;
return schlafli<Rank>(mults, ss.str());
}
/**
* Demicube, Orthoplex
*/
template<unsigned int Rank>
Group <Rank> D() {
std::stringstream ss;
ss << "D(" << Rank << ")";
std::array<unsigned int, Rank - 1> mults;
mults.fill(3);
mults[Rank - 2] = 2;
Group<Rank> g = schlafli<Rank>(mults, ss.str());
g(1, Rank - 1) = 3;
return g;
}
/**
* E groups
*/
template<unsigned int Rank>
Group <Rank> E() {
std::stringstream ss;
ss << "E(" << Rank << ")";
std::array<unsigned int, Rank - 1> mults;
mults.fill(3);
mults[Rank - 2] = 2;
Group<Rank> g = schlafli<Rank>(mults, ss.str());
g(2, Rank - 1) = 3;
return g;
}
/**
* 24 Cell
*/
Group<4> F4() {
return schlafli<4>({3, 4, 3}, "F4");
}
/**
* Hexagon
*/
Group<2> G2() {
return schlafli<2>({6}, "G2");
}
/**
* Icosahedron
*/
template<unsigned int Rank>
Group <Rank> H() {
std::stringstream ss;
ss << "H(" << Rank << ")";
std::array<unsigned int, Rank - 1> mults;
mults.fill(3);
mults[0] = 5;
return schlafli<Rank>(mults, ss.str());
}
/**
* Polygonal
*/
Group<2> I2(unsigned int n) {
std::stringstream ss;
ss << "I2(" << n << ")";
return schlafli<2>({n}, ss.str());
}
/**
* Toroidal. I2(n) * I2(m)
*/
Group<4> T(unsigned int n, unsigned int m) {
std::stringstream ss;
ss << "T(" << n << "," << m << ")";
return schlafli<4>({n, 2, m}, ss.str());
}
/**
* Toroidal. T(n, n)
*/
Group<4> T(unsigned int n) {
std::stringstream ss;
ss << "T(" << n << ")";
return schlafli<4>({n, 2, n}, ss.str());
}
} }
} }