diff --git a/CMakeLists.txt b/CMakeLists.txt index 028273a..f8a670b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,12 +3,10 @@ project(toddcox-faster) option(TC_BUILD_EXAMPLE "Build example executables" OFF) -add_library(tc STATIC - src/groups.cpp - src/solve.cpp - src/core.cpp) +add_library(tc INTERFACE + ) -target_include_directories(tc PUBLIC include) +target_include_directories(tc INTERFACE include) if (TC_BUILD_EXAMPLE) add_subdirectory(example) diff --git a/example/bench.cpp b/example/bench.cpp index 5bbd231..d40c7a9 100644 --- a/example/bench.cpp +++ b/example/bench.cpp @@ -8,7 +8,7 @@ template void test(const G &group) { auto s = std::clock(); - auto cosets = group.solve(); + auto cosets = group.solve({0}); auto e = std::clock(); double diff = (double) (e - s) / CLOCKS_PER_SEC; diff --git a/example/path.cpp b/example/path.cpp index e2175a6..7192404 100644 --- a/example/path.cpp +++ b/example/path.cpp @@ -1,6 +1,6 @@ +#include "tc/core.hpp" #include "tc/groups.hpp" -#include #include int main() { diff --git a/include/tc/core.hpp b/include/tc/core.hpp index a608b75..ec21531 100644 --- a/include/tc/core.hpp +++ b/include/tc/core.hpp @@ -1,165 +1,7 @@ #pragma once -#include -#include -#include -#include - -namespace tc { - struct Action { - int from_idx = -1; - int gen = -1; - - Action() = default; - - Action(const Action &) = default; - - Action(int from_idx, int gen); - }; - - struct Path { - std::vector path; - - Path() = default; - - Path(const Path &) = default; - - void add_row(); - - [[nodiscard]] Action get(int to_idx) const; - - void put(int from_idx, int gen, int to_idx); - - template - void walk( - C& res, - T start, - std::vector gens, - std::function op - ) const { - size_t s = size(); - res.reserve(s); - res.push_back(start); - - for (int i = 1; i < s; ++i) { - auto &action = path[i]; - auto &from = res.get(action.from_idx); - auto &val = gens[action.gen]; - res.push_back(op(from,val)); - } - } - - template - [[nodiscard]] std::vector walk( - T start, - std::vector gens, - std::function op - ) const { - std::vector res; - res.reserve(size()); - res.push_back(start); - - for (int i = 1; i < size(); ++i) { - auto &action = path[i]; - auto &from = res[action.from_idx]; - auto &val = gens[action.gen]; - res.push_back(op(from, val)); - } - - return res; - } - - template - [[nodiscard]] std::vector walk( - T start, - std::function op - ) const { - std::vector res; - res.reserve(size()); - res.push_back(start); - - for (int i = 1; i < size(); ++i) { - auto &action = path[i]; - auto &from = res[action.from_idx]; - auto &val = action.gen; - res[i] = op(from, val); - } - - return res; - } - - [[nodiscard]] size_t size() const; - }; - - struct Cosets { - int ngens; - std::vector data; - Path path; - - Cosets(const Cosets &) = default; - - explicit Cosets(int ngens); - - void add_row(); - - void put(int coset, int gen, int target); - - void put(int idx, int target); - - [[nodiscard]] int get(int coset, int gen) const; - - [[nodiscard]] int get(int idx) const; - - [[nodiscard]] size_t size() const; - }; - - struct Rel { - std::array gens; - int mult; - - Rel() = default; - - Rel(const Rel &) = default; - - Rel(int a, int b, int m); - - [[nodiscard]] Rel shift(int off) const; - }; - - struct SubGroup; - - struct Group { - int ngens; - std::vector> _mults; - std::string name; - - Group(const Group &) = default; - - explicit Group(int ngens, const std::vector &rels = {}, std::string name = "G"); - - void set(const Rel &r); - - [[nodiscard]] int get(int a, int b) const; - - [[nodiscard]] std::vector get_rels() const; - - [[nodiscard]] SubGroup subgroup(const std::vector &gens) const; - - [[nodiscard]] Group product(const Group &other) const; - - [[nodiscard]] Group power(int p) const; - - [[nodiscard]] Cosets solve(const std::vector &sub_gens = {}) const; - }; - - struct SubGroup : public Group { - std::vector gen_map; - const Group &parent; - - SubGroup(const Group &parent, std::vector gen_map); - }; - - Group operator*(const Group &g, const Group &h); - - Group operator^(const Group &g, int p); -} +#include "tc/core/action.hpp" +#include "tc/core/path.hpp" +#include "tc/core/cosets.hpp" +#include "tc/core/rel.hpp" +#include "tc/core/group.hpp" diff --git a/include/tc/core/action.hpp b/include/tc/core/action.hpp new file mode 100644 index 0000000..920cec2 --- /dev/null +++ b/include/tc/core/action.hpp @@ -0,0 +1,14 @@ +#pragma once + +struct Action { + int from_idx = -1; + int gen = -1; + + Action() = default; + + Action(const Action &) = default; + + Action(int from_idx, int gen) + : from_idx(from_idx), gen(gen) { + } +}; diff --git a/include/tc/core/cosets.hpp b/include/tc/core/cosets.hpp new file mode 100644 index 0000000..5afbcd0 --- /dev/null +++ b/include/tc/core/cosets.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include + +#include "path.hpp" + +struct Cosets { + int ngens; + std::vector data; + Path path; + + Cosets(const Cosets &) = default; + + explicit Cosets(int ngens) + : ngens(ngens) { + } + + void add_row() { + data.resize(data.size() + ngens, -1); + path.add_row(); + } + + void put(int coset, int gen, int target) { + data[coset * ngens + gen] = target; + data[target * ngens + gen] = coset; + + if (path.get(target).from_idx == -1) { + path.put(coset, gen, target); + } + } + + void put(int idx, int target) { + // todo remove + int coset = idx / ngens; + int gen = idx % ngens; + put(coset, gen, target); + } + + [[nodiscard]] int get(int coset, int gen) const { + return data[coset * ngens + gen]; + } + + [[nodiscard]] int get(int idx) const { + return data[idx]; + } + + [[nodiscard]] size_t size() const { + return path.size(); + } +}; diff --git a/include/tc/core/group.hpp b/include/tc/core/group.hpp new file mode 100644 index 0000000..cec60ae --- /dev/null +++ b/include/tc/core/group.hpp @@ -0,0 +1,126 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "rel.hpp" +#include "cosets.hpp" + +namespace tc { + struct Group; + struct SubGroup; + + struct Group { + int ngens; + std::vector> _mults; + std::string name; + + Group(const Group &) = default; + + explicit Group( + int ngens, + const std::vector &rels = {}, + std::string name = "G" + ) : ngens(ngens), name(std::move(name)) { + _mults.resize(ngens); + + for (auto &mult: _mults) { + mult.resize(ngens, 2); + } + + for (const auto &rel: rels) { + set(rel); + } + } + + void set(const Rel &r) { + _mults[r.gens[0]][r.gens[1]] = r.mult; + _mults[r.gens[1]][r.gens[0]] = r.mult; + } + + [[nodiscard]] int get(int a, int b) const { + return _mults[a][b]; + } + + [[nodiscard]] std::vector get_rels() const { + std::vector res; + for (int i = 0; i < ngens - 1; ++i) { + for (int j = i + 1; j < ngens; ++j) { + res.emplace_back(i, j, get(i, j)); + } + } + return res; + } + + [[nodiscard]] Group product(const Group &other) const { + std::stringstream ss; + ss << name << "*" << other.name; + + Group g(ngens + other.ngens, get_rels(), ss.str()); + + for (const auto &rel: other.get_rels()) { + g.set(rel.shift(ngens)); + } + + return g; + } + + [[nodiscard]] Group power(int p) const { + std::stringstream ss; + ss << name << "^" << p; + + Group g(ngens * p, {}, ss.str()); + for (const auto &rel: get_rels()) { + for (int off = 0; off < g.ngens; off += ngens) { + g.set(rel.shift(off)); + } + } + + return g; + } + + [[nodiscard]] SubGroup subgroup( + const std::vector &gens + ) const; + + [[nodiscard]] Cosets solve( + const std::vector &sub_gens = {} + ) const; + }; + + struct SubGroup : public Group { + std::vector gen_map; + const Group &parent; + + SubGroup(const Group &parent, std::vector gen_map) : Group(gen_map.size()), parent(parent) { + + std::sort(gen_map.begin(), gen_map.end()); + this->gen_map = gen_map; + + for (size_t i = 0; i < gen_map.size(); ++i) { + for (size_t j = 0; j < gen_map.size(); ++j) { + int mult = parent.get(gen_map[i], gen_map[j]); + set(Rel(i, j, mult)); + } + } + } + }; + + SubGroup Group::subgroup(const std::vector &gens) const { + return SubGroup(*this, gens); + } + + Group operator*(const Group &g, const Group &h) { + return g.product(h); + } + + Group operator^(const Group &g, int p) { + return g.power(p); + } +} + +#include "solve.hpp" diff --git a/include/tc/core/path.hpp b/include/tc/core/path.hpp new file mode 100644 index 0000000..5063855 --- /dev/null +++ b/include/tc/core/path.hpp @@ -0,0 +1,88 @@ +#pragma once + +#include +#include + +#include "action.hpp" + +struct Path { + std::vector path; + + Path() = default; + + Path(const Path &) = default; + + void add_row() { + path.resize(path.size() + 1); + } + + [[nodiscard]] Action get(int to_idx) const { + return path[to_idx]; + } + + void put(int from_idx, int gen, int to_idx) { + path[to_idx] = Action(from_idx, gen); + } + + [[nodiscard]] size_t size() const { + return path.size(); + } + + template + void walk( + C &res, + T start, + std::vector gens, + std::function op + ) const { + size_t s = size(); + res.reserve(s); + res.push_back(start); + + for (int i = 1; i < s; ++i) { + auto &action = path[i]; + auto &from = res.get(action.from_idx); + auto &val = gens[action.gen]; + res.push_back(op(from, val)); + } + } + + template + [[nodiscard]] std::vector walk( + T start, + std::vector gens, + std::function op + ) const { + std::vector res; + res.reserve(size()); + res.push_back(start); + + for (int i = 1; i < size(); ++i) { + auto &action = path[i]; + auto &from = res[action.from_idx]; + auto &val = gens[action.gen]; + res.push_back(op(from, val)); + } + + return res; + } + + template + [[nodiscard]] std::vector walk( + T start, + std::function op + ) const { + std::vector res; + res.reserve(size()); + res.push_back(start); + + for (int i = 1; i < size(); ++i) { + auto &action = path[i]; + auto &from = res[action.from_idx]; + auto &val = action.gen; + res[i] = op(from, val); + } + + return res; + } +}; diff --git a/include/tc/core/rel.hpp b/include/tc/core/rel.hpp new file mode 100644 index 0000000..d064428 --- /dev/null +++ b/include/tc/core/rel.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include + +struct Rel { + std::array gens; + int mult; + + Rel() = default; + + Rel(const Rel &) = default; + + Rel(int a, int b, int m) + : gens({a, b}), mult(m) { + } + + [[nodiscard]] Rel shift(int off) const { + return Rel(gens[0] + off, gens[1] + off, mult); + } +}; diff --git a/src/solve.cpp b/include/tc/core/solve.hpp similarity index 98% rename from src/solve.cpp rename to include/tc/core/solve.hpp index 979e342..8ee13ec 100644 --- a/src/solve.cpp +++ b/include/tc/core/solve.hpp @@ -1,10 +1,6 @@ -#include "tc/core.hpp" +#pragma once -#include -#include -#include - -namespace tc { +namespace { struct Row { int gnr; std::shared_ptr lst; @@ -40,7 +36,9 @@ namespace tc { } return deps; } +} +namespace tc { Cosets Group::solve(const std::vector &sub_gens) const { Cosets cosets(ngens); cosets.add_row(); diff --git a/include/tc/groups.hpp b/include/tc/groups.hpp index 7a3e421..22012fe 100644 --- a/include/tc/groups.hpp +++ b/include/tc/groups.hpp @@ -2,69 +2,157 @@ #include "core.hpp" - namespace tc { /** * Construct a group from a (simplified) Schlafli Symbol of the form [a, b, ..., c] * @param mults: The sequence of multiplicites between adjacent generators. */ - Group schlafli(const std::vector &mults, const std::string &name); + Group schlafli(const std::vector &mults, const std::string &name) { + int ngens = (int) mults.size() + 1; + + Group g(ngens, {}, name); + + for (int i = 0; i < (int) mults.size(); i++) { + g.set(Rel(i, i + 1, mults[i])); + } + + return g; + } /** * Construct a group from a (simplified) Schlafli Symbol of the form [a, b, ..., c] * @param mults: The sequence of multiplicites between adjacent generators. */ - Group schlafli(const std::vector &mults); + Group schlafli(const std::vector &mults) { + std::stringstream ss; + ss << "["; + if (!mults.empty()) { + for (size_t i = 0; i < mults.size() - 1; ++i) { + ss << mults[i] << ","; + } + ss << mults.back(); + } + ss << "]"; + + return schlafli(mults, ss.str()); + } namespace group { /** * Simplex */ - Group A(int dim); + Group A(int dim) { + std::stringstream ss; + ss << "A(" << dim << ")"; + + if (dim == 0) + return Group(0, {}, ss.str()); + + const std::vector &mults = std::vector(dim - 1, 3); + + return schlafli(mults, ss.str()); + } /** * Cube, Orthoplex */ - Group B(int dim); + Group B(int dim) { + std::stringstream ss; + ss << "B(" << dim << ")"; + + std::vector mults(dim - 1, 3); + mults[0] = 4; + + return schlafli(mults, ss.str()); + } /** * Demicube, Orthoplex */ - Group D(int dim); + Group D(int dim) { + std::stringstream ss; + ss << "D(" << dim << ")"; + + std::vector mults(dim - 1, 3); + mults[dim - 2] = 2; + + Group g = schlafli(mults, ss.str()); + g.set(Rel(1, dim - 1, 3)); + + return g; + } /** * E groups */ - Group E(int dim); + Group E(int dim) { + std::stringstream ss; + ss << "E(" << dim << ")"; + + std::vector mults(dim - 1, 3); + mults[dim - 2] = 2; + + Group g = schlafli(mults, ss.str()); + g.set(Rel(2, dim - 1, 3)); + + return g; + } /** * 24 Cell */ - Group F4(); + Group F4() { + return schlafli({3, 4, 3}, "F4"); + } /** * Hexagon */ - Group G2(); + Group G2() { + return schlafli({6}, "G2"); + } /** * Icosahedron */ - Group H(int dim); + Group H(int dim) { + std::stringstream ss; + ss << "H(" << dim << ")"; + + std::vector mults(dim - 1, 3); + mults[0] = 5; + + return schlafli(mults, ss.str()); + } /** * Polygonal */ - Group I2(int n); + Group I2(int n) { + std::stringstream ss; + ss << "I2(" << n << ")"; + + return schlafli({n}, ss.str()); + } /** * Toroidal. I2(n) * I2(m) */ - Group T(int n, int m); + Group T(int n, int m) { + std::stringstream ss; + ss << "T(" << n << "," << m << ")"; + + return schlafli({n, 2, m}, ss.str()); + } /** * Toroidal. T(n, n) */ - Group T(int n); + Group T(int n) { + std::stringstream ss; + ss << "T(" << n << ")"; + + return schlafli({n, 2, n}, ss.str()); + } } } diff --git a/src/core.cpp b/src/core.cpp deleted file mode 100644 index d9800bc..0000000 --- a/src/core.cpp +++ /dev/null @@ -1,161 +0,0 @@ -#include "tc/core.hpp" - -#include -#include -#include - -namespace tc { - Action::Action(int from_idx, int gen) - : from_idx(from_idx), gen(gen) { - } - - void Path::add_row() { - path.resize(path.size() + 1); - } - - Action Path::get(int to_idx) const { - return path[to_idx]; - } - - void Path::put(int from_idx, int gen, int to_idx) { - path[to_idx] = Action(from_idx, gen); - } - - size_t Path::size() const { - return path.size(); - } - - Cosets::Cosets(int ngens) - : ngens(ngens) { - } - - void Cosets::add_row() { - data.resize(data.size() + ngens, -1); - path.add_row(); - } - - void Cosets::put(int coset, int gen, int target) { - data[coset * ngens + gen] = target; - data[target * ngens + gen] = coset; - - if (path.get(target).from_idx == -1) { - path.put(coset, gen, target); - } - } - - void Cosets::put(int idx, int target) { - int coset = idx / ngens; - int gen = idx % ngens; - data[idx] = target; - data[target * ngens + gen] = coset; - - if (path.get(target).from_idx == -1) { - path.put(coset, gen, target); - } - } - - int Cosets::get(int coset, int gen) const { - return data[coset * ngens + gen]; - } - - int Cosets::get(int idx) const { - return data[idx]; - } - - size_t Cosets::size() const { - return path.size(); - } - - Rel::Rel(int a, int b, int m) - : gens({a, b}), mult(m) { - } - - Rel Rel::shift(int off) const { - return Rel(gens[0] + off, gens[1] + off, mult); - } - - Group::Group(int ngens, const std::vector &rels, std::string name) - : ngens(ngens), name(std::move(name)) { - _mults.resize(ngens); - - for (auto &mult : _mults) { - mult.resize(ngens, 2); - } - - for (const auto &rel : rels) { - set(rel); - } - } - - void Group::set(const Rel &r) { - _mults[r.gens[0]][r.gens[1]] = r.mult; - _mults[r.gens[1]][r.gens[0]] = r.mult; - } - - int Group::get(int a, int b) const { - return _mults[a][b]; - } - - std::vector Group::get_rels() const { - std::vector res; - for (int i = 0; i < ngens - 1; ++i) { - for (int j = i + 1; j < ngens; ++j) { - res.emplace_back(i, j, get(i, j)); - } - } - return res; - } - - SubGroup Group::subgroup(const std::vector &gens) const { - return SubGroup(*this, gens); - } - - Group Group::product(const Group &other) const { - std::stringstream ss; - ss << name << "*" << other.name; - - Group g(ngens + other.ngens, get_rels(), ss.str()); - - for (const auto &rel : other.get_rels()) { - g.set(rel.shift(ngens)); - } - - return g; - } - - Group Group::power(int p) const { - std::stringstream ss; - ss << name << "^" << p; - - Group g(ngens * p, {}, ss.str()); - for (const auto &rel : get_rels()) { - for (int off = 0; off < g.ngens; off += ngens) { - g.set(rel.shift(off)); - } - } - - return g; - } - - SubGroup::SubGroup(const Group &parent, std::vector gen_map) - : Group(gen_map.size()), parent(parent) { - - std::sort(gen_map.begin(), gen_map.end()); - this->gen_map = gen_map; - - for (size_t i = 0; i < gen_map.size(); ++i) { - for (size_t j = 0; j < gen_map.size(); ++j) { - int mult = parent.get(gen_map[i], gen_map[j]); - set(Rel(i, j, mult)); - } - } - } - - Group operator*(const Group &g, const Group &h) { - return g.product(h); - } - - Group operator^(const Group &g, int p) { - return g.power(p); - } -} diff --git a/src/groups.cpp b/src/groups.cpp deleted file mode 100644 index 1cebc12..0000000 --- a/src/groups.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include "tc/groups.hpp" - -#include - -namespace tc { - Group schlafli(const std::vector &mults, const std::string &name) { - int ngens = (int) mults.size() + 1; - - Group g(ngens, {}, name); - - for (int i = 0; i < (int) mults.size(); i++) { - g.set(Rel(i, i + 1, mults[i])); - } - - return g; - } - - Group schlafli(const std::vector &mults) { - std::stringstream ss; - ss << "["; - if (!mults.empty()) { - for (size_t i = 0; i < mults.size() - 1; ++i) { - ss << mults[i] << ","; - } - ss << mults.back(); - } - ss << "]"; - - return schlafli(mults, ss.str()); - } - - namespace group { - Group A(const int dim) { - std::stringstream ss; - ss << "A(" << dim << ")"; - - if (dim == 0) - return Group(0, {}, ss.str()); - - const std::vector &mults = std::vector(dim - 1, 3); - - return schlafli(mults, ss.str()); - } - - Group B(const int dim) { - std::stringstream ss; - ss << "B(" << dim << ")"; - - std::vector mults(dim - 1, 3); - mults[0] = 4; - - return schlafli(mults, ss.str()); - } - - Group D(const int dim) { - std::stringstream ss; - ss << "D(" << dim << ")"; - - std::vector mults(dim - 1, 3); - mults[dim - 2] = 2; - - Group g = schlafli(mults, ss.str()); - g.set(Rel(1, dim - 1, 3)); - - return g; - } - - Group E(const int dim) { - std::stringstream ss; - ss << "E(" << dim << ")"; - - std::vector mults(dim - 1, 3); - mults[dim - 2] = 2; - - Group g = schlafli(mults, ss.str()); - g.set(Rel(2, dim - 1, 3)); - - return g; - } - - Group F4() { - return schlafli({3, 4, 3}, "F4"); - } - - Group G2() { - return schlafli({6}, "G2"); - } - - Group H(const int dim) { - std::stringstream ss; - ss << "H(" << dim << ")"; - - std::vector mults(dim - 1, 3); - mults[0] = 5; - - return schlafli(mults, ss.str()); - } - - Group I2(const int n) { - std::stringstream ss; - ss << "I2(" << n << ")"; - - return schlafli({n}, ss.str()); - } - - Group T(const int n, const int m) { - std::stringstream ss; - ss << "T(" << n << "," << m << ")"; - - return schlafli({n, 2, m}, ss.str()); - } - - Group T(const int n) { - std::stringstream ss; - ss << "T(" << n << ")"; - - return schlafli({n, 2, n}, ss.str()); - } - } -}