diff --git a/.idea/cosets.iml b/.idea/cosets.iml
deleted file mode 100644
index f08604b..0000000
--- a/.idea/cosets.iml
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 9bb8048..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index 44442b6..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 94a25f7..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/cosets/CMakeLists.txt b/cosets/CMakeLists.txt
index dfa29e2..c8cf75b 100644
--- a/cosets/CMakeLists.txt
+++ b/cosets/CMakeLists.txt
@@ -15,3 +15,5 @@ add_custom_command(
${CMAKE_CURRENT_SOURCE_DIR}/src/shaders
${CMAKE_CURRENT_BINARY_DIR}/shaders
)
+
+add_executable(coxeter src/tc.cpp)
diff --git a/cosets/src/main.cpp b/cosets/src/main.cpp
index 8531459..de0e007 100644
--- a/cosets/src/main.cpp
+++ b/cosets/src/main.cpp
@@ -29,16 +29,16 @@ public:
program = build_program("main", vs, fs);
- float verts_data[4 * VERTS_N]{
- +.5f, +.5f, 0.f, 0.f,
- +.5f, -.5f, 0.f, 0.f,
- -.5f, -.5f, 0.f, -.1f,
- -.5f, +.5f, 0.f, -.1f,
+ glm::vec4 verts_data[VERTS_N]{
+ {+0.5, +0.5, +0.5, +0.0},
+ {+0.5, -0.5, +0.5, +0.0},
+ {-0.5, -0.5, +0.5, +0.0},
+ {-0.5, +0.5, +0.5, +0.0},
- +.5f, +.5f, 0.f, .1f,
- +.5f, -.5f, 0.f, .1f,
- -.5f, -.5f, 0.2f, .0f,
- -.5f, +.5f, 0.2f, .0f,
+ {+0.5, +0.5, +0.5, -0.5},
+ {+0.5, -0.5, +0.5, -0.5},
+ {-0.5, -0.5, +0.5, +0.5},
+ {-0.5, +0.5, +0.5, +0.5},
};
glGenBuffers(1, &verts);
diff --git a/cosets/src/tc.cpp b/cosets/src/tc.cpp
new file mode 100644
index 0000000..12ca511
--- /dev/null
+++ b/cosets/src/tc.cpp
@@ -0,0 +1,222 @@
+#include
+#include
+#include
+#include
+#include
+
+
+struct Table {
+ int N;
+ std::vector> fwd;
+ std::vector> rev;
+
+ explicit Table(int N) {
+ add_row();
+ this->N = N;
+ }
+
+ void add_row() {
+ fwd.emplace_back(N, -1);
+ rev.emplace_back(N, -1);
+ }
+
+ int add_coset() {
+ for (int from = 0; from < (int) size(); ++from) {
+ for (int gen = 0; gen < N; ++gen) {
+ if (get(from, gen) < 0) {
+ int to = (int) size();
+ add_row();
+ set(from, gen, to);
+ return to;
+ }
+ }
+ }
+ return 0;
+ }
+
+ [[nodiscard]] unsigned size() const {
+ return fwd.size();
+ }
+
+ void set(int from, int gen, int to) {
+ fwd[from][gen] = to;
+ rev[to][gen] = from;
+ }
+
+ [[nodiscard]] int get(int from, int gen) const {
+ return fwd[from][gen];
+ }
+
+ [[nodiscard]] int rget(int gen, int to) const {
+ return rev[to][gen];
+ }
+
+ std::vector> words() {
+ std::vector *> vecs(size());
+ vecs[0] = new std::vector();
+
+ while (std::find(vecs.begin(), vecs.end(), nullptr) != vecs.end()) {
+ for (int from = 0; from < (int) vecs.size(); ++from) {
+ std::vector *word = vecs[from];
+ if (word == nullptr) {
+ continue;
+ }
+
+ for (int gen = 0; gen < (int) N; ++gen) {
+ int to = get(from, gen);
+ if (vecs[to] != nullptr) {
+ continue;
+ }
+
+ vecs[to] = new std::vector(*word);
+ vecs[to]->push_back(gen);
+ }
+ }
+ }
+
+ std::vector> res(size());
+ for (int i = 0; i < (int) size(); ++i) {
+ res[i] = *vecs[i];
+ }
+
+ return res;
+ }
+};
+
+struct Row {
+ std::vector::const_iterator l;
+ std::vector::const_iterator r;
+
+ int from;
+ int to;
+
+ Row(const std::vector &vec, int cos) {
+ this->l = vec.begin();
+ this->r = vec.end() - 1;
+ this->from = cos;
+ this->to = cos;
+ }
+
+ bool learn(Table *table) {
+ if (r - l == 0) {
+ return false;
+ }
+
+ while (r - l > 0) {
+ int next = table->get(from, *l);
+ if (next < 0) break;
+ l++;
+ from = next;
+ }
+
+ while (r - l > 0) {
+ int next = table->rget(*r, to);
+ if (next < 0) break;
+ r--;
+ to = next;
+ }
+
+ if (r - l == 0) {
+ table->set(from, *l, to);
+ return true;
+ }
+
+ return false;
+ }
+};
+
+std::ostream &operator<<(std::ostream &out, const Row &row) {
+ out << "[ " << row.from << " | ";
+ auto it = row.l;
+ while (row.r - it > 0) {
+ out << *it << " ";
+ it++;
+ }
+ out << "| " << row.to << " ]";
+ return out;
+}
+
+Table *solve(int gens, const std::vector &subgens, const std::vector> &rels) {
+ auto *table = new Table(gens);
+
+ for (int gen : subgens)
+ table->set(0, gen, 0);
+
+ std::vector rows;
+ rows.reserve(rels.size());
+ for (const auto &rel : rels)
+ rows.emplace_back(rel, 0);
+
+ while (!rows.empty()) {
+ while (true) {
+ bool learned = false;
+ for (int i = (int) rows.size() - 1; i >= 0; i--) {
+ if (rows[i].learn(table)) {
+ learned = true;
+ rows.erase(rows.begin() + i);
+ }
+ }
+ if (!learned)
+ break;
+ }
+
+ int i = (int) table->size();
+ if (table->add_coset() > 0) {
+ for (const auto &rel : rels)
+ rows.emplace_back(rel, i);
+ } else {
+ break;
+ }
+ }
+
+ return table;
+}
+
+std::ostream &operator<<(std::ostream &out, const Table &table) {
+ int k = ceil(log10(table.size()));
+
+ out << "[";
+ for (unsigned j = 0; j < table.size(); ++j) {
+ auto arr = table.fwd[j];
+ out << " " << std::setw(k) << j << " [";
+ for (int i = 0; i < table.N; ++i) {
+ out << arr[i];
+
+ if (i < table.N - 1)
+ out << " ";
+ }
+
+ out << "]";
+ if (j < table.fwd.size() - 1)
+ out << "\n ";
+ }
+ out << "]\n";
+
+ return out;
+}
+
+int main(int argc, char *argv[]) {
+ std::vector> ids{
+ {0, 0},
+ {1, 1},
+ {2, 2},
+ {0, 1, 0, 1, 0, 1, 0, 1},
+ {1, 2, 1, 2, 1, 2},
+ {0, 2, 0, 2}
+ };
+
+ Table *table = solve(3, {0, 1}, ids);
+
+ std::cout << table->size() << std::endl;
+ std::cout << *table << std::endl;
+
+ for (const auto &v : table->words()) {
+ std::cout << "[ ";
+ for (auto e : v) {
+ std::cout << e << " ";
+ }
+ std::cout << "]\n";
+ }
+
+ return 0;
+}