From 31fa8e86a9d27679ac46f070868da4c64de6ad23 Mon Sep 17 00:00:00 2001 From: allem Date: Tue, 28 Jan 2020 23:18:16 -0500 Subject: [PATCH] generics don't crash, but don't work either --- vis/include/geometry.hpp | 558 ++++++++++++++++++++++++++++----------- vis/src/main.cpp | 19 +- 2 files changed, 409 insertions(+), 168 deletions(-) diff --git a/vis/include/geometry.hpp b/vis/include/geometry.hpp index 385124c..913980b 100644 --- a/vis/include/geometry.hpp +++ b/vis/include/geometry.hpp @@ -26,190 +26,428 @@ size_t num_gens_from_key(size_t key) { return count; } -struct Mesh { -// int dim; - std::vector vals; +template +struct Primitive { + std::array inds; - Mesh() : vals() {} + Primitive() = default; - explicit Mesh(std::vector &vals) : vals(vals) {} + Primitive(const Primitive &) = default; - explicit Mesh(const std::vector &parts) { - size_t count = 0; - for (const auto &part : parts) { - count += part.size(); + Primitive(const Primitive &sub, unsigned root) { + std::copy(sub.inds.begin(), sub.inds.end(), inds.begin()); + inds[N - 1] = root; + } + + ~Primitive() = default; + + inline void flip() { + if (N > 1) std::swap(inds[0], inds[1]); + } + + void apply(const tc::Cosets &table, int gen) { + for (auto &ind : inds) { + ind = table.get(ind, gen); } - vals.reserve(count); + flip(); + } +}; - for (const auto &part : parts) { - vals.insert(vals.end(), part.vals.begin(), part.vals.end()); +std::vector gens(const tc::Group &context) { + std::vector g_gens(context.ngens); + std::iota(g_gens.begin(), g_gens.end(), 0); + return g_gens; +} + +std::vector recontext_gens( + const tc::Group &context, + std::vector g_gens, + std::vector sg_gens) { + + std::sort(g_gens.begin(), g_gens.end()); + + int inv_gen_map[context.ngens]; + for (size_t i = 0; i < g_gens.size(); i++) { + inv_gen_map[g_gens[i]] = i; + } + + std::vector s_sg_gens; + s_sg_gens.reserve(sg_gens.size()); + for (const auto gen : sg_gens) { + s_sg_gens.push_back(inv_gen_map[gen]); + } + std::sort(s_sg_gens.begin(), s_sg_gens.end()); + + return s_sg_gens; + +// std::sort(g_gens.begin(), g_gens.end()); +// +// std::vector inv_g_map(g_gens.size()); +// for (int i = 0; i < g_gens.size(); ++i) { +// inv_g_map[g_gens[i]] = i; +// } +// +// std::transform(sg_gens.begin(), sg_gens.end(), sg_gens.begin(), +// [inv_g_map](const auto &gen) { +// return inv_g_map[gen]; +// } +// ); +// +// std::sort(sg_gens.begin(), sg_gens.end()); +// return sg_gens; +} + +int get_parity( + const tc::Group &context, + const std::vector &g_gens, + const std::vector &sg_gens +) { + if (g_gens.size() != sg_gens.size() + 1) return 0; + + const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens); + + int i = 0; + for (; i < sg_gens.size(); ++i) { + if (proper_sg_gens[i] != i) { + break; } } + return i & 1; +} + +tc::Cosets solve( + const tc::Group &context, + const std::vector &g_gens, + const std::vector &sg_gens +) { + const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens); + return context.subgroup(g_gens).solve(proper_sg_gens); +} + +tc::Cosets solve_sg( + const tc::Group &context, + const std::vector &sg_gens +) { + return solve(context, gens(context), sg_gens); +} + +tc::Cosets solve_g( + const tc::Group &context, + const std::vector &g_gens +) { + std::vector sg_gens; + return solve(context, g_gens, sg_gens); +} + +tc::Cosets solve( + const tc::Group &context +) { + std::vector sg_gens; + return solve_sg(context, sg_gens); +} + +template +struct Mesh { + std::vector> prims; + + Mesh() : prims() {} + + Mesh(const Mesh &) = default; + + explicit Mesh(std::vector> &prims) : prims(prims) {} + [[nodiscard]] size_t size() const { - return vals.size(); + return prims.size(); + } + + void apply(const tc::Cosets &table, int gen) { + for (auto &prim : prims) { + prim.apply(table, gen); + } } void flip() { -// if (dim == 0) -// return; -// for (int i = 0; i < vals.size(); i += dim + 1) { -// std::swap(vals[i], vals[i + 1]); -// } - } -}; - -struct GeomGen { - std::vector>> coset_memo; - std::vector> triangulate_memo; - tc::Group &context; - - explicit GeomGen(tc::Group &g) : context(g) { - size_t num_sg = std::pow(2, g.ngens); - coset_memo.resize(num_sg); - triangulate_memo.resize(num_sg); - for (size_t i = 0; i < num_sg; i++) { - auto num_sg_sg = std::pow(2, num_gens_from_key(i)); - coset_memo[i].resize(num_sg_sg, std::nullopt); + for (auto &prim : prims) { + prim.flip(); } } - std::vector group_gens() { - std::vector gens(context.ngens); - for (int i = 0; i < context.ngens; i++) { - gens[i] = i; - } - return gens; - } + Mesh recontext( + const tc::Group &context, + const std::vector &g_gens, + const std::vector &sg_gens + ) { + const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens); + // todo memo recontext + const auto table = solve_g(context, g_gens); + const auto path = solve_g(context, sg_gens).path; - std::vector prepare_gens(std::vector &g_gens, std::vector &sg_gens) { - std::sort(g_gens.begin(), g_gens.end()); + auto map = path.template walk(0, proper_sg_gens, [table](int coset, int gen) { + return table.get(coset, gen); + }); - int inv_gen_map[context.ngens]; - for (size_t i = 0; i < g_gens.size(); i++) { - inv_gen_map[g_gens[i]] = i; - } - - std::vector s_sg_gens; - s_sg_gens.reserve(sg_gens.size()); - for (const auto gen : sg_gens) { - s_sg_gens.push_back(inv_gen_map[gen]); - } - std::sort(s_sg_gens.begin(), s_sg_gens.end()); - - return s_sg_gens; - } - - int get_parity(std::vector &g_gens, std::vector &sg_gens) { - if (g_gens.size() != sg_gens.size() + 1) - return 0; - auto s_sg_gens = prepare_gens(g_gens, sg_gens); - const int loop_max = g_gens.size() - 1; - for (int i = 0; i < loop_max; i++) { - if (s_sg_gens[i] != i) - return i % 2; - } - return loop_max % 2; - } - - tc::Cosets _solve(std::vector &g_gens, std::vector &sg_gens) { - auto s_sg_gens = prepare_gens(g_gens, sg_gens); - - size_t group_key = get_key_from_gens(g_gens); - size_t subgroup_key = get_key_from_gens(s_sg_gens); - - if (!coset_memo[group_key][subgroup_key]) { - tc::SubGroup g = context.subgroup(g_gens); - coset_memo[group_key][subgroup_key] = g.solve(s_sg_gens); - } - return *coset_memo[group_key][subgroup_key]; - } - - tc::Cosets solve(std::vector g_gens, std::vector sg_gens) { - return _solve(g_gens, sg_gens); - } - - tc::Cosets solve_sg(std::vector &sg_gens) { - auto g_gens = group_gens(); - return _solve(g_gens, sg_gens); - } - - tc::Cosets solve_g(std::vector &g_gens) { - std::vector sg_gens; - return _solve(g_gens, sg_gens); - } - - tc::Cosets solve() { - std::vector sg_gens; - return solve_sg(sg_gens); - } - - Mesh recontext(std::vector &g_gens, std::vector &sg_gens, const Mesh &items) { - auto s_sg_gens = prepare_gens(g_gens, sg_gens); - auto table = solve_g(g_gens); - auto path = solve_g(sg_gens).path; - - auto coset_map = [table](int coset, int gen) { return table.get(coset, gen); }; - - auto map = path.walk(0, s_sg_gens, coset_map); - - Mesh ret; - ret.vals.reserve(items.size()); - for (const auto val : items.vals) { - ret.vals.push_back(map[val]); - } - if (get_parity(g_gens, sg_gens) == 1) - ret.flip(); - return ret; - } - - Mesh tile(std::vector &g_gens, std::vector &sg_gens, const Mesh &items) { - Mesh base = recontext(g_gens, sg_gens, items); - auto s_sg_gens = prepare_gens(g_gens, sg_gens); - auto table = solve_g(g_gens); - auto path = _solve(g_gens, sg_gens).path; - - auto simplex_map = [table](Mesh from, int gen) -> Mesh { - for (auto &coset : from.vals) { - coset = table.get(coset, gen); + Mesh res = *this; + for (Primitive &prim : res.prims) { + for (auto &ind : prim.inds) { + ind = map[ind]; } - from.flip(); + } + + if (get_parity(context, g_gens, sg_gens) == 1) + res.flip(); + + return res; + } + + Mesh tile( + const tc::Group &context, + const std::vector &g_gens, + const std::vector &sg_gens + ) { + Mesh base = recontext(context, g_gens, sg_gens); + const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens); + + // todo memo tile + const auto table = solve_g(context, g_gens); + const auto path = solve(context, g_gens, sg_gens).path; + + const auto all = path.template walk, int>(base, g_gens, [table](Mesh from, int gen) { + from.apply(table, gen); return from; - }; + }); - auto r = path.walk(base, group_gens(), simplex_map); - - return Mesh(r); + return merge(all); } - Mesh triangulate(std::vector &g_gens); - - Mesh _triangulate(std::vector &g_gens) { - Mesh S; - if (g_gens.empty()) { - S.vals.push_back(0); - return S; - } - for (std::vector sg_gens : Combos(g_gens, g_gens.size() - 1)) { - auto sub_simps = triangulate(sg_gens); - int start = sub_simps.size(); - sub_simps = tile(g_gens, sg_gens, sub_simps); - for (int l = start; l < sub_simps.size(); l += g_gens.size()) { - for (int m = l; m < l + g_gens.size(); m++) { - S.vals.push_back(sub_simps.vals[m]); - } - S.vals.push_back(0); + Mesh fan(int root) { + std::vector> res(prims.size()); + std::transform(prims.begin(), prims.end(), res.begin(), + [root](const Primitive &prim) { + return Primitive(prim, root); } - } - return S; + ); + return Mesh(res); } - }; -Mesh GeomGen::triangulate(std::vector &g_gens) { - int key = get_key_from_gens(g_gens); - if (!triangulate_memo[key]) { - triangulate_memo[key] = _triangulate(g_gens); +template +Mesh merge(const std::vector> &meshes) { + size_t size = 0; + for (const auto &mesh : meshes) { + size += mesh.size(); } - return *triangulate_memo[key]; -} \ No newline at end of file + + std::vector> prims; + prims.reserve(size); + for (const auto &mesh : meshes) { + prims.insert(prims.end(), mesh.prims.begin(), mesh.prims.end()); + } + + return Mesh(prims); +} + +template +Mesh triangulate( + const tc::Group &context, + const std::vector &g_gens +) { + if (g_gens.size() + 1 != N) + throw std::logic_error("g_gens size must be one less than N"); + + const auto &combos = Combos(g_gens, g_gens.size() - 1); + + std::vector> meshes; + for (const auto &sg_gens : combos) { + Mesh base = triangulate(context, sg_gens); + Mesh raised = base.tile(context, g_gens, sg_gens); + raised.prims.erase(raised.prims.begin(), raised.prims.begin() + base.size()); + Mesh fan = raised.fan(0); + meshes.push_back(fan); + } + + return merge(meshes); +} + +template<> +Mesh<1> triangulate<1>( + const tc::Group &context, + const std::vector &g_gens +) { + if (not g_gens.empty()) + throw std::logic_error("g_gens must be empty for a trivial Mesh"); + + Mesh<1> res; + res.prims.emplace_back(); + return res; +} + +//template +//struct GeomGen { +// std::vector>> coset_memo; +// std::vector>> triangulate_memo; +// tc::Group &context; +// +// explicit GeomGen(tc::Group &g) : context(g) { +// size_t num_sg = std::pow(2, g.ngens); +// coset_memo.resize(num_sg); +// triangulate_memo.resize(num_sg); +// for (size_t i = 0; i < num_sg; i++) { +// auto num_sg_sg = std::pow(2, num_gens_from_key(i)); +// coset_memo[i].resize(num_sg_sg, std::nullopt); +// } +// } +// +// std::vector group_gens() { +// std::vector gens(context.ngens); +// for (int i = 0; i < context.ngens; i++) { +// gens[i] = i; +// } +// return gens; +// } +// +// std::vector prepare_gens(std::vector &g_gens, std::vector &sg_gens) { +// std::sort(g_gens.begin(), g_gens.end()); +// +// int inv_gen_map[context.ngens]; +// for (size_t i = 0; i < g_gens.size(); i++) { +// inv_gen_map[g_gens[i]] = i; +// } +// +// std::vector s_sg_gens; +// s_sg_gens.reserve(sg_gens.size()); +// for (const auto gen : sg_gens) { +// s_sg_gens.push_back(inv_gen_map[gen]); +// } +// std::sort(s_sg_gens.begin(), s_sg_gens.end()); +// +// return s_sg_gens; +// } +// +// int get_parity(std::vector &g_gens, std::vector &sg_gens) { +// if (g_gens.size() != sg_gens.size() + 1) +// return 0; +// auto s_sg_gens = prepare_gens(g_gens, sg_gens); +// const int loop_max = g_gens.size() - 1; +// for (int i = 0; i < loop_max; i++) { +// if (s_sg_gens[i] != i) +// return i % 2; +// } +// return loop_max % 2; +// } +// +// tc::Cosets _solve(std::vector &g_gens, std::vector &sg_gens) { +// auto s_sg_gens = prepare_gens(g_gens, sg_gens); +// +// size_t group_key = get_key_from_gens(g_gens); +// size_t subgroup_key = get_key_from_gens(s_sg_gens); +// +// if (!coset_memo[group_key][subgroup_key]) { +// tc::SubGroup g = context.subgroup(g_gens); +// coset_memo[group_key][subgroup_key] = g.solve(s_sg_gens); +// } +// return *coset_memo[group_key][subgroup_key]; +// } +// +// tc::Cosets solve(std::vector g_gens, std::vector sg_gens) { +// return _solve(g_gens, sg_gens); +// } +// +// tc::Cosets solve_sg(std::vector &sg_gens) { +// auto g_gens = group_gens(); +// return _solve(g_gens, sg_gens); +// } +// +// tc::Cosets solve_g(std::vector &g_gens) { +// std::vector sg_gens; +// return _solve(g_gens, sg_gens); +// } +// +// tc::Cosets solve() { +// std::vector sg_gens; +// return solve_sg(sg_gens); +// } +// +// Mesh recontext(std::vector &g_gens, std::vector &sg_gens, const Mesh &items) { +// auto s_sg_gens = prepare_gens(g_gens, sg_gens); +// auto table = solve_g(g_gens); +// auto path = solve_g(sg_gens).path; +// +// auto coset_map = [table](int coset, int gen) { return table.get(coset, gen); }; +// +// auto map = path.template walk(0, s_sg_gens, coset_map); +// +// Mesh ret; +// ret.vals.reserve(items.size()); +// for (const auto val : items.vals) { +// ret.vals.push_back(map[val]); +// } +// if (get_parity(g_gens, sg_gens) == 1) +// ret.flip(); +// return ret; +// } +// +// Mesh tile(std::vector &g_gens, std::vector &sg_gens, const Mesh &items) { +// Mesh base = recontext(g_gens, sg_gens, items); +// auto s_sg_gens = prepare_gens(g_gens, sg_gens); +// auto table = solve_g(g_gens); +// auto path = _solve(g_gens, sg_gens).path; +// +// auto simplex_map = [table](Mesh from, int gen) -> Mesh { +// for (auto &prim : from.prims) { +// prim.apply(table, gen); +// } +// from.flip(); +// return from; +// }; +// +// auto r = path.template walk, int>(base, group_gens(), simplex_map); +// +// return merge(r); +// } +// +// Mesh triangulate(std::vector &g_gens); +// +// Mesh<1> _triangulate(std::vector &g_gens) { +// Mesh<1> m; +// m.prims.emplace_back(); +// return m; +// } +// +// Mesh _triangulate(std::vector &g_gens) { +// +// Mesh S; +// if (g_gens.empty()) { +// S.prims.push_back(Primitive()); +// return S; +// } +// +// GeomGen gg(context); +// for (std::vector sg_gens : Combos(g_gens, g_gens.size() - 1)) { +// Mesh sub_simps = gg.triangulate(sg_gens); +// int start = sub_simps.size(); +// Mesh raised = tile(g_gens, sg_gens, sub_simps); +// +// for (const Primitive &prim : raised.prims) { +// S.prims.push_back(Primitive(prim, 0)); +// } +// +//// for (int l = start; l < raised.size(); l += g_gens.size()) { +//// for (int m = l; m < l + g_gens.size(); m++) { +//// S.vals.push_back(raised.vals[m]); +//// } +//// S.vals.push_back(0); +//// } +// } +// return S; +// } +//}; +// +//template +//Mesh GeomGen::triangulate(std::vector &g_gens) { +// int key = get_key_from_gens(g_gens); +// if (!triangulate_memo[key]) { +// triangulate_memo[key] = _triangulate(g_gens); +// } +// return *triangulate_memo[key]; +//} \ No newline at end of file diff --git a/vis/src/main.cpp b/vis/src/main.cpp index 52a7c60..8566e6b 100644 --- a/vis/src/main.cpp +++ b/vis/src/main.cpp @@ -97,8 +97,10 @@ int main(int argc, char *argv[]) { //region points auto group = tc::group::H(4); - GeomGen gg(group); - auto res = gg.solve(); +// GeomGen<4> gg4(group); +// GeomGen<3> gg3(group); +// auto res = gg4.solve(); + auto res = group.solve(); auto mirrors = mirror(group); auto corners = plane_intersections(mirrors); @@ -107,7 +109,7 @@ int main(int argc, char *argv[]) { // auto start = barycentric(corners, {0.05f, 0.1f, 0.2f, 1.00f}); auto points = res.path.walk(start, mirrors, reflect); - auto g_gens = gg.group_gens(); + auto g_gens = gens(group); std::vector vaos; std::vector ibos; @@ -120,17 +122,18 @@ int main(int argc, char *argv[]) { // }; auto chosen = combos; - for (auto sg_gens : chosen) { - auto s = gg.tile(g_gens, sg_gens, gg.triangulate(sg_gens)); - const std::vector data = s.vals; + for (const auto& sg_gens : chosen) { + const Mesh<4> &base = triangulate<4>(group, sg_gens); + const auto &s = base; +// s = tile(context, g_gens, sg_gens, base); GLuint vao = utilCreateVertexArray(); GLuint ibo = utilCreateBuffer(); - unsigned count = data.size(); + unsigned count = s.size(); glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, ibo); - glBufferData(GL_ARRAY_BUFFER, sizeof(int) * count, &data[0], GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, sizeof(Primitive<4>) * count, &s.prims[0], GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribIPointer(0, 4, GL_INT, 0, nullptr); glBindBuffer(GL_ARRAY_BUFFER, 0);