diff --git a/tc/bench/benchmark.cpp b/tc/bench/benchmark.cpp index 194947f..9149138 100644 --- a/tc/bench/benchmark.cpp +++ b/tc/bench/benchmark.cpp @@ -8,8 +8,6 @@ #include #include -#define NAMED(x) #x, x - void bench( const std::string &group_expr, const std::string &symbol, diff --git a/tc/include/tc/group.hpp b/tc/include/tc/group.hpp index 692759e..2c560f3 100644 --- a/tc/include/tc/group.hpp +++ b/tc/include/tc/group.hpp @@ -10,6 +10,11 @@ namespace tc { struct Group; struct SubGroup; + struct Graph { + size_t rank{}; + std::vector edges{}; + }; + /** * @brief Manage the presentation of a Coxeter group and enforce constraints * on the multiplicities of its relations. @@ -28,31 +33,38 @@ namespace tc { * Coxeter Group (Wikipedia) */ struct Group { - int ngens; - tc::pair_map _mults; + int rank; + tc::pair_map _orders; Group(const Group &) = default; - explicit Group(int ngens, const std::vector &rels = {}) - : ngens(ngens), _mults(ngens, 2) { + explicit Group(int rank, const std::vector &rels = {}) + : rank(rank), _orders(rank, 2) { - for (int i = 0; i < ngens; ++i) { + for (int i = 0; i < rank; ++i) { set(Rel{i, i, 1}); } - + for (const auto &rel: rels) { set(rel); } } + explicit Group(const Graph &graph) + : rank(graph.rank), _orders(graph.rank, 2) { + for (const auto &[i, j, order]: graph.edges) { + set({i, j, order}); + } + } + void set(const Rel &r) { auto &[i, j, m] = r; assert(i != j || m == 1); - _mults(i, j) = m; + _orders(i, j) = m; } [[nodiscard]] int get(int i, int j) const { - return _mults(i, j); + return _orders(i, j); } [[nodiscard]] SubGroup subgroup(const std::vector &gens) const; diff --git a/tc/include/tc/groups.hpp b/tc/include/tc/groups.hpp index a1b7806..e8e8137 100644 --- a/tc/include/tc/groups.hpp +++ b/tc/include/tc/groups.hpp @@ -13,7 +13,7 @@ namespace tc { Group coxeter(const std::string &symbol); - Group vcoxeter(const std::string &symbol, std::vector &values); + Group vcoxeter(const std::string &symbol, const std::vector &values); template Group coxeter(const std::string &symbol, const Args &... args) { diff --git a/tc/src/core.cpp b/tc/src/core.cpp index 64410a0..04bf1a3 100644 --- a/tc/src/core.cpp +++ b/tc/src/core.cpp @@ -40,27 +40,31 @@ namespace tc { } }; - Cosets solve(const Group &group, const std::vector &sub_gens, const Coset &bound) { - auto ngens = group.ngens; + Cosets solve( + const Group &group, + const std::vector &sub_gens, + const Coset &bound + ) { + auto rank = group.rank; // region Initialize Cosets Table - Cosets cosets(ngens); + Cosets cosets(rank); cosets.add_row(); - if (ngens == 0) { + if (rank == 0) { cosets.complete = true; return cosets; } for (Coset g: sub_gens) { - if (g < ngens) + if (g < rank) cosets.put(0, g, 0); } // endregion // region Initialize Relation Tables std::vector> rels; - for (const auto &[i, j, m]: group._mults) { + for (const auto &[i, j, m]: group._orders) { // The algorithm only works for Coxeter groups; multiplicities m_ii=1 are assumed. Relation tables // _may_ be added for them, but they are redundant and hurt performance so are skipped. if (i == j) continue; @@ -75,7 +79,7 @@ namespace tc { } Tables rel_tables(rels); - std::vector> tables_for(ngens); + std::vector> tables_for(rank); int rel_idx = 0; for (const auto &[i, j, m]: rels) { tables_for[i].push_back(rel_idx); @@ -146,8 +150,8 @@ namespace tc { cosets.put(fact_idx, target); - coset = fact_idx / ngens; - gen = fact_idx % ngens; + coset = fact_idx / rank; + gen = fact_idx % rank; // If the product stays within the coset todo for (size_t table_idx: tables_for[gen]) { @@ -170,7 +174,7 @@ namespace tc { if (trow.gnr == m) { // loop is closed, but idempotent, so the target links to itself via the other generator. // todo might be able to move this logic up into the (target == coset) block and avoid those computations. - facts.push(target * ngens + other_gen); + facts.push(target * rank + other_gen); } } else { if (trow.gnr == m - 1) { @@ -180,7 +184,7 @@ namespace tc { // loop is closed. We know the last element in the loop must link with this one. lst = lst_vals[trow.lst_idx]; // delete trow.lst_ptr; - facts.push(lst * ngens + other_gen); + facts.push(lst * rank + other_gen); } } } diff --git a/tc/src/groups.cpp b/tc/src/groups.cpp index e9ae9d5..9b98ac5 100644 --- a/tc/src/groups.cpp +++ b/tc/src/groups.cpp @@ -12,7 +12,7 @@ namespace tc { return res; } - Group vcoxeter(const std::string &symbol, std::vector &values) { + Group vcoxeter(const std::string &symbol, const std::vector &values) { fmt::dynamic_format_arg_store ds; for (const auto &value: values) { diff --git a/tc/src/lang.cpp b/tc/src/lang.cpp index cd66658..6235909 100644 --- a/tc/src/lang.cpp +++ b/tc/src/lang.cpp @@ -80,7 +80,7 @@ struct codegen { void loop() { ops.emplace_back(Op::LOOP); } - + void free() { ops.emplace_back(Op::FREE); } @@ -221,23 +221,18 @@ std::vector compile(const std::string &source) { return cg.ops; } -struct Graph { - size_t rank{}; - std::vector edges{}; -}; - -Graph eval(const std::vector &ops) { +tc::Graph eval(const std::vector &ops) { std::vector> stacks(1); - Graph g; + tc::Graph g; stacks.back().emplace(g.rank++); for (const auto &op: ops) { switch (op.code) { - case Op::FREE: + case Op::FREE: case Op::LINK: { tc::Mult order = tc::FREE; - + if (op.code == Op::LINK) { order = op.value; } @@ -287,20 +282,7 @@ Graph eval(const std::vector &ops) { namespace tc { Group coxeter(const std::string &symbol) { auto ops = compile(symbol); - -// fmt::print("#ops: {}\n", ops.size()); -// for (const auto &op: ops) { -// fmt::print(" {}\n", op); -// } - auto diagram = eval(ops); - - Group res((int) diagram.rank); - - for (const auto &[i, j, order]: diagram.edges) { - res.set({i, j, order}); - } - - return res; + return Group(diagram); } } diff --git a/tc/test/test_lang.cpp b/tc/test/test_lang.cpp index fc083a4..e9cfd1b 100644 --- a/tc/test/test_lang.cpp +++ b/tc/test/test_lang.cpp @@ -20,7 +20,7 @@ TEST(coxeter, simple) { auto g = tc::coxeter("5 3 3"); - ASSERT_EQ(g.ngens, 4); + ASSERT_EQ(g.rank, 4); EXPECT_EQ(g.get(0, 1), 5); EXPECT_EQ(g.get(1, 2), 3); @@ -37,7 +37,7 @@ TEST(coxeter, simple) { TEST(coxeter, looping) { auto g = tc::coxeter("{5 3 4}"); - ASSERT_EQ(g.ngens, 3); + ASSERT_EQ(g.rank, 3); EXPECT_EQ(g.get(0, 1), 5); EXPECT_EQ(g.get(1, 2), 3); diff --git a/tc/test/test_solve.cpp b/tc/test/test_solve.cpp index 3cc4f5f..a814771 100644 --- a/tc/test/test_solve.cpp +++ b/tc/test/test_solve.cpp @@ -46,12 +46,50 @@ testing::AssertionResult AssertSolveOrder( return res; } -using namespace tc::group; - #define EXPECT_SOLVE_ORDER(group, sub_gens, expected_order) EXPECT_PRED_FORMAT3(AssertSolveOrder, group, sub_gens, expected_order); using v = std::vector; +tc::Group A(unsigned int n) { + return tc::vcoxeter("3 * {}", {n - 1}); +} + +tc::Group B(unsigned int n) { + return tc::vcoxeter("4 3 * {}", {n - 2}); +} + +tc::Group D(unsigned int n) { + return tc::vcoxeter("3 * [1 1 {}]", {n - 3}); +} + +tc::Group E(unsigned int n) { + return tc::vcoxeter("3 * [1 2 {}]", {n - 4}); +} + +tc::Group F4() { + return tc::coxeter("3 4 3"); +} + +tc::Group G2() { + return tc::coxeter("6"); +} + +tc::Group H(unsigned int n) { + return tc::vcoxeter("5 3 * {}", {n - 2}); +} + +tc::Group I2(unsigned int n) { + return tc::vcoxeter("{}", {n}); +} + +tc::Group T(unsigned int m, unsigned int n) { + return tc::vcoxeter("{} 2 {}", {m, n}); +} + +tc::Group T(unsigned int n) { + return T(n, n); +} + // See the group orders here https://en.wikipedia.org/wiki/Coxeter_group#Properties TEST(solve, A) { @@ -95,27 +133,27 @@ TEST(solve, D) { EXPECT_SOLVE_ORDER(D(4), v({0, 1, 3}), 8); EXPECT_SOLVE_ORDER(D(5), v({}), 1920); EXPECT_SOLVE_ORDER(D(5), v({0, 1}), 320); - EXPECT_SOLVE_ORDER(D(5), v({0, 1, 3}), 160); - EXPECT_SOLVE_ORDER(D(5), v({0, 1, 3, 4}), 40); + EXPECT_SOLVE_ORDER(D(5), v({0, 1, 3}), 80); + EXPECT_SOLVE_ORDER(D(5), v({0, 1, 3, 4}), 16); EXPECT_SOLVE_ORDER(D(6), v({}), 23040); EXPECT_SOLVE_ORDER(D(6), v({0, 1}), 3840); - EXPECT_SOLVE_ORDER(D(6), v({0, 1, 3}), 1920); + EXPECT_SOLVE_ORDER(D(6), v({0, 1, 3}), 960); EXPECT_SOLVE_ORDER(D(6), v({0, 1, 3, 5}), 480); } TEST(solve, E) { EXPECT_SOLVE_ORDER(E(4), v({}), 120); EXPECT_SOLVE_ORDER(E(4), v({2}), 60); - EXPECT_SOLVE_ORDER(E(4), v({2, 1}), 20); - EXPECT_SOLVE_ORDER(E(4), v({2, 1, 3}), 5); + EXPECT_SOLVE_ORDER(E(4), v({2, 1}), 30); + EXPECT_SOLVE_ORDER(E(4), v({2, 1, 3}), 10); EXPECT_SOLVE_ORDER(E(5), v({}), 1920); EXPECT_SOLVE_ORDER(E(5), v({2}), 960); - EXPECT_SOLVE_ORDER(E(5), v({2, 1}), 320); - EXPECT_SOLVE_ORDER(E(5), v({2, 1, 3}), 80); + EXPECT_SOLVE_ORDER(E(5), v({2, 1}), 480); + EXPECT_SOLVE_ORDER(E(5), v({2, 1, 3}), 160); EXPECT_SOLVE_ORDER(E(6), v({}), 51840); EXPECT_SOLVE_ORDER(E(6), v({2}), 25920); - EXPECT_SOLVE_ORDER(E(6), v({2, 1}), 8640); - EXPECT_SOLVE_ORDER(E(6), v({2, 1, 3}), 2160); + EXPECT_SOLVE_ORDER(E(6), v({2, 1}), 12960); + EXPECT_SOLVE_ORDER(E(6), v({2, 1, 3}), 4320); } TEST(solve, F) {