mirror of
https://github.com/allemangD/toddcox-visualize.git
synced 2025-11-10 03:52:48 -05:00
use coxeter notation parser for benchmark and tests
This commit is contained in:
@@ -8,8 +8,6 @@
|
|||||||
#include <tc/core.hpp>
|
#include <tc/core.hpp>
|
||||||
#include <tc/groups.hpp>
|
#include <tc/groups.hpp>
|
||||||
|
|
||||||
#define NAMED(x) #x, x
|
|
||||||
|
|
||||||
void bench(
|
void bench(
|
||||||
const std::string &group_expr,
|
const std::string &group_expr,
|
||||||
const std::string &symbol,
|
const std::string &symbol,
|
||||||
|
|||||||
@@ -10,6 +10,11 @@ namespace tc {
|
|||||||
struct Group;
|
struct Group;
|
||||||
struct SubGroup;
|
struct SubGroup;
|
||||||
|
|
||||||
|
struct Graph {
|
||||||
|
size_t rank{};
|
||||||
|
std::vector<tc::Rel> edges{};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Manage the presentation of a Coxeter group and enforce constraints
|
* @brief Manage the presentation of a Coxeter group and enforce constraints
|
||||||
* on the multiplicities of its relations.
|
* on the multiplicities of its relations.
|
||||||
@@ -28,31 +33,38 @@ namespace tc {
|
|||||||
* <a href="https://en.wikipedia.org/wiki/Coxeter_group#Definition">Coxeter Group (Wikipedia)</a>
|
* <a href="https://en.wikipedia.org/wiki/Coxeter_group#Definition">Coxeter Group (Wikipedia)</a>
|
||||||
*/
|
*/
|
||||||
struct Group {
|
struct Group {
|
||||||
int ngens;
|
int rank;
|
||||||
tc::pair_map<int> _mults;
|
tc::pair_map<int> _orders;
|
||||||
|
|
||||||
Group(const Group &) = default;
|
Group(const Group &) = default;
|
||||||
|
|
||||||
explicit Group(int ngens, const std::vector<Rel> &rels = {})
|
explicit Group(int rank, const std::vector<Rel> &rels = {})
|
||||||
: ngens(ngens), _mults(ngens, 2) {
|
: rank(rank), _orders(rank, 2) {
|
||||||
|
|
||||||
for (int i = 0; i < ngens; ++i) {
|
for (int i = 0; i < rank; ++i) {
|
||||||
set(Rel{i, i, 1});
|
set(Rel{i, i, 1});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &rel: rels) {
|
for (const auto &rel: rels) {
|
||||||
set(rel);
|
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) {
|
void set(const Rel &r) {
|
||||||
auto &[i, j, m] = r;
|
auto &[i, j, m] = r;
|
||||||
assert(i != j || m == 1);
|
assert(i != j || m == 1);
|
||||||
_mults(i, j) = m;
|
_orders(i, j) = m;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] int get(int i, int j) const {
|
[[nodiscard]] int get(int i, int j) const {
|
||||||
return _mults(i, j);
|
return _orders(i, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] SubGroup subgroup(const std::vector<int> &gens) const;
|
[[nodiscard]] SubGroup subgroup(const std::vector<int> &gens) const;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace tc {
|
|||||||
|
|
||||||
Group coxeter(const std::string &symbol);
|
Group coxeter(const std::string &symbol);
|
||||||
|
|
||||||
Group vcoxeter(const std::string &symbol, std::vector<unsigned int> &values);
|
Group vcoxeter(const std::string &symbol, const std::vector<unsigned int> &values);
|
||||||
|
|
||||||
template<typename ...Args>
|
template<typename ...Args>
|
||||||
Group coxeter(const std::string &symbol, const Args &... args) {
|
Group coxeter(const std::string &symbol, const Args &... args) {
|
||||||
|
|||||||
@@ -40,27 +40,31 @@ namespace tc {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Cosets solve(const Group &group, const std::vector<Gen> &sub_gens, const Coset &bound) {
|
Cosets solve(
|
||||||
auto ngens = group.ngens;
|
const Group &group,
|
||||||
|
const std::vector<Gen> &sub_gens,
|
||||||
|
const Coset &bound
|
||||||
|
) {
|
||||||
|
auto rank = group.rank;
|
||||||
|
|
||||||
// region Initialize Cosets Table
|
// region Initialize Cosets Table
|
||||||
Cosets cosets(ngens);
|
Cosets cosets(rank);
|
||||||
cosets.add_row();
|
cosets.add_row();
|
||||||
|
|
||||||
if (ngens == 0) {
|
if (rank == 0) {
|
||||||
cosets.complete = true;
|
cosets.complete = true;
|
||||||
return cosets;
|
return cosets;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Coset g: sub_gens) {
|
for (Coset g: sub_gens) {
|
||||||
if (g < ngens)
|
if (g < rank)
|
||||||
cosets.put(0, g, 0);
|
cosets.put(0, g, 0);
|
||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region Initialize Relation Tables
|
// region Initialize Relation Tables
|
||||||
std::vector<std::tuple<Gen, Gen, Mult>> rels;
|
std::vector<std::tuple<Gen, Gen, Mult>> 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
|
// 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.
|
// _may_ be added for them, but they are redundant and hurt performance so are skipped.
|
||||||
if (i == j) continue;
|
if (i == j) continue;
|
||||||
@@ -75,7 +79,7 @@ namespace tc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Tables rel_tables(rels);
|
Tables rel_tables(rels);
|
||||||
std::vector<std::vector<size_t>> tables_for(ngens);
|
std::vector<std::vector<size_t>> tables_for(rank);
|
||||||
int rel_idx = 0;
|
int rel_idx = 0;
|
||||||
for (const auto &[i, j, m]: rels) {
|
for (const auto &[i, j, m]: rels) {
|
||||||
tables_for[i].push_back(rel_idx);
|
tables_for[i].push_back(rel_idx);
|
||||||
@@ -146,8 +150,8 @@ namespace tc {
|
|||||||
|
|
||||||
cosets.put(fact_idx, target);
|
cosets.put(fact_idx, target);
|
||||||
|
|
||||||
coset = fact_idx / ngens;
|
coset = fact_idx / rank;
|
||||||
gen = fact_idx % ngens;
|
gen = fact_idx % rank;
|
||||||
|
|
||||||
// If the product stays within the coset todo
|
// If the product stays within the coset todo
|
||||||
for (size_t table_idx: tables_for[gen]) {
|
for (size_t table_idx: tables_for[gen]) {
|
||||||
@@ -170,7 +174,7 @@ namespace tc {
|
|||||||
if (trow.gnr == m) {
|
if (trow.gnr == m) {
|
||||||
// loop is closed, but idempotent, so the target links to itself via the other generator.
|
// 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.
|
// 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 {
|
} else {
|
||||||
if (trow.gnr == m - 1) {
|
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.
|
// loop is closed. We know the last element in the loop must link with this one.
|
||||||
lst = lst_vals[trow.lst_idx];
|
lst = lst_vals[trow.lst_idx];
|
||||||
// delete trow.lst_ptr;
|
// delete trow.lst_ptr;
|
||||||
facts.push(lst * ngens + other_gen);
|
facts.push(lst * rank + other_gen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace tc {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
Group vcoxeter(const std::string &symbol, std::vector<unsigned int> &values) {
|
Group vcoxeter(const std::string &symbol, const std::vector<unsigned int> &values) {
|
||||||
fmt::dynamic_format_arg_store<fmt::format_context> ds;
|
fmt::dynamic_format_arg_store<fmt::format_context> ds;
|
||||||
|
|
||||||
for (const auto &value: values) {
|
for (const auto &value: values) {
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ struct codegen {
|
|||||||
void loop() {
|
void loop() {
|
||||||
ops.emplace_back(Op::LOOP);
|
ops.emplace_back(Op::LOOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void free() {
|
void free() {
|
||||||
ops.emplace_back(Op::FREE);
|
ops.emplace_back(Op::FREE);
|
||||||
}
|
}
|
||||||
@@ -221,23 +221,18 @@ std::vector<Op> compile(const std::string &source) {
|
|||||||
return cg.ops;
|
return cg.ops;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Graph {
|
tc::Graph eval(const std::vector<Op> &ops) {
|
||||||
size_t rank{};
|
|
||||||
std::vector<tc::Rel> edges{};
|
|
||||||
};
|
|
||||||
|
|
||||||
Graph eval(const std::vector<Op> &ops) {
|
|
||||||
std::vector<std::stack<size_t>> stacks(1);
|
std::vector<std::stack<size_t>> stacks(1);
|
||||||
|
|
||||||
Graph g;
|
tc::Graph g;
|
||||||
stacks.back().emplace(g.rank++);
|
stacks.back().emplace(g.rank++);
|
||||||
|
|
||||||
for (const auto &op: ops) {
|
for (const auto &op: ops) {
|
||||||
switch (op.code) {
|
switch (op.code) {
|
||||||
case Op::FREE:
|
case Op::FREE:
|
||||||
case Op::LINK: {
|
case Op::LINK: {
|
||||||
tc::Mult order = tc::FREE;
|
tc::Mult order = tc::FREE;
|
||||||
|
|
||||||
if (op.code == Op::LINK) {
|
if (op.code == Op::LINK) {
|
||||||
order = op.value;
|
order = op.value;
|
||||||
}
|
}
|
||||||
@@ -287,20 +282,7 @@ Graph eval(const std::vector<Op> &ops) {
|
|||||||
namespace tc {
|
namespace tc {
|
||||||
Group coxeter(const std::string &symbol) {
|
Group coxeter(const std::string &symbol) {
|
||||||
auto ops = compile(symbol);
|
auto ops = compile(symbol);
|
||||||
|
|
||||||
// fmt::print("#ops: {}\n", ops.size());
|
|
||||||
// for (const auto &op: ops) {
|
|
||||||
// fmt::print(" {}\n", op);
|
|
||||||
// }
|
|
||||||
|
|
||||||
auto diagram = eval(ops);
|
auto diagram = eval(ops);
|
||||||
|
return Group(diagram);
|
||||||
Group res((int) diagram.rank);
|
|
||||||
|
|
||||||
for (const auto &[i, j, order]: diagram.edges) {
|
|
||||||
res.set({i, j, order});
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
TEST(coxeter, simple) {
|
TEST(coxeter, simple) {
|
||||||
auto g = tc::coxeter("5 3 3");
|
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(0, 1), 5);
|
||||||
EXPECT_EQ(g.get(1, 2), 3);
|
EXPECT_EQ(g.get(1, 2), 3);
|
||||||
@@ -37,7 +37,7 @@ TEST(coxeter, simple) {
|
|||||||
TEST(coxeter, looping) {
|
TEST(coxeter, looping) {
|
||||||
auto g = tc::coxeter("{5 3 4}");
|
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(0, 1), 5);
|
||||||
EXPECT_EQ(g.get(1, 2), 3);
|
EXPECT_EQ(g.get(1, 2), 3);
|
||||||
|
|||||||
@@ -46,12 +46,50 @@ testing::AssertionResult AssertSolveOrder(
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace tc::group;
|
|
||||||
|
|
||||||
#define EXPECT_SOLVE_ORDER(group, sub_gens, expected_order) EXPECT_PRED_FORMAT3(AssertSolveOrder, group, sub_gens, expected_order);
|
#define EXPECT_SOLVE_ORDER(group, sub_gens, expected_order) EXPECT_PRED_FORMAT3(AssertSolveOrder, group, sub_gens, expected_order);
|
||||||
|
|
||||||
using v = std::vector<tc::Gen>;
|
using v = std::vector<tc::Gen>;
|
||||||
|
|
||||||
|
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
|
// See the group orders here https://en.wikipedia.org/wiki/Coxeter_group#Properties
|
||||||
|
|
||||||
TEST(solve, A) {
|
TEST(solve, A) {
|
||||||
@@ -95,27 +133,27 @@ TEST(solve, D) {
|
|||||||
EXPECT_SOLVE_ORDER(D(4), v({0, 1, 3}), 8);
|
EXPECT_SOLVE_ORDER(D(4), v({0, 1, 3}), 8);
|
||||||
EXPECT_SOLVE_ORDER(D(5), v({}), 1920);
|
EXPECT_SOLVE_ORDER(D(5), v({}), 1920);
|
||||||
EXPECT_SOLVE_ORDER(D(5), v({0, 1}), 320);
|
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}), 80);
|
||||||
EXPECT_SOLVE_ORDER(D(5), v({0, 1, 3, 4}), 40);
|
EXPECT_SOLVE_ORDER(D(5), v({0, 1, 3, 4}), 16);
|
||||||
EXPECT_SOLVE_ORDER(D(6), v({}), 23040);
|
EXPECT_SOLVE_ORDER(D(6), v({}), 23040);
|
||||||
EXPECT_SOLVE_ORDER(D(6), v({0, 1}), 3840);
|
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);
|
EXPECT_SOLVE_ORDER(D(6), v({0, 1, 3, 5}), 480);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(solve, E) {
|
TEST(solve, E) {
|
||||||
EXPECT_SOLVE_ORDER(E(4), v({}), 120);
|
EXPECT_SOLVE_ORDER(E(4), v({}), 120);
|
||||||
EXPECT_SOLVE_ORDER(E(4), v({2}), 60);
|
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}), 30);
|
||||||
EXPECT_SOLVE_ORDER(E(4), v({2, 1, 3}), 5);
|
EXPECT_SOLVE_ORDER(E(4), v({2, 1, 3}), 10);
|
||||||
EXPECT_SOLVE_ORDER(E(5), v({}), 1920);
|
EXPECT_SOLVE_ORDER(E(5), v({}), 1920);
|
||||||
EXPECT_SOLVE_ORDER(E(5), v({2}), 960);
|
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}), 480);
|
||||||
EXPECT_SOLVE_ORDER(E(5), v({2, 1, 3}), 80);
|
EXPECT_SOLVE_ORDER(E(5), v({2, 1, 3}), 160);
|
||||||
EXPECT_SOLVE_ORDER(E(6), v({}), 51840);
|
EXPECT_SOLVE_ORDER(E(6), v({}), 51840);
|
||||||
EXPECT_SOLVE_ORDER(E(6), v({2}), 25920);
|
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}), 12960);
|
||||||
EXPECT_SOLVE_ORDER(E(6), v({2, 1, 3}), 2160);
|
EXPECT_SOLVE_ORDER(E(6), v({2, 1, 3}), 4320);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(solve, F) {
|
TEST(solve, F) {
|
||||||
|
|||||||
Reference in New Issue
Block a user