From 01043e9bce34971c817c0c1e190bd2e9e493fdec Mon Sep 17 00:00:00 2001 From: David Allemang Date: Sat, 24 Oct 2020 23:06:52 -0400 Subject: [PATCH] Replace ComboIterator with std::set> via combinations.hpp Since the number of generators never exceeds 6, the maximum number of combinations is (6, 3) = 20, so the space optimizations of using an iterator is mute. Doing this way also allows to use set_difference and set_union to deal with collections of subgroups. This is not easily possible otherwise. --- vis/include/combinations.hpp | 44 +++++++++++++++ vis/include/combo_iterator.hpp | 98 ---------------------------------- vis/include/geometry.hpp | 1 - vis/include/rendering.hpp | 15 +++--- vis/include/solver.hpp | 5 +- 5 files changed, 55 insertions(+), 108 deletions(-) create mode 100644 vis/include/combinations.hpp delete mode 100644 vis/include/combo_iterator.hpp diff --git a/vis/include/combinations.hpp b/vis/include/combinations.hpp new file mode 100644 index 0000000..f522b2c --- /dev/null +++ b/vis/include/combinations.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include + +template +V select(const V &options, const std::vector &mask, size_t count) { + V result; + result.reserve(count); + + for (int i = 0; i < mask.size(); ++i) { + if (mask[i]) result.push_back(options[i]); + } + + return result; +} + +template +std::set combinations(const V &options, size_t count) { + std::set result; + + std::vector mask(options.size(), false); + std::fill(mask.begin(), mask.begin() + count, true); + + do { + result.insert(select(options, mask, count)); + } while (std::next_permutation(mask.begin(), mask.end(), std::greater<>())); + + return result; +} + +template +std::set difference(const std::set &a, const std::set &b) { + std::set result; + + std::set_difference( + a.begin(), a.end(), + b.begin(), b.end(), + std::inserter(result, result.end()) + ); + + return result; +} diff --git a/vis/include/combo_iterator.hpp b/vis/include/combo_iterator.hpp deleted file mode 100644 index 1669b2b..0000000 --- a/vis/include/combo_iterator.hpp +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -size_t choose(size_t n, size_t k) { - if (k == 0) return 1; - return n * choose(n - 1, k - 1) / k; -} - -template -class ComboIterator { -private: - const std::vector &options; - - std::vector bits; - std::vector curr; - int at; - - void set_curr() { - for (int i = 0, j = 0; i < bits.size(); ++i) { - if (bits[i]) curr[j++] = options[i]; - } - } - -public: - ComboIterator(const std::vector &options, int k, int at = 0) - : options(options), bits(options.size()), curr(k), at(at) { - std::fill(bits.begin(), bits.begin() + k, true); - set_curr(); - } - - [[nodiscard]] bool operator==(const ComboIterator &o) const { - return at == o.at; - } - - [[nodiscard]] bool operator!=(const ComboIterator &o) const { - return at != o.at; - } - - auto operator*() const { - return curr; - } - - const auto &operator->() const { - return &this; - } - - auto operator++(int) { - std::prev_permutation(bits.begin(), bits.end()); - set_curr(); - ++at; - return *this; - } - - auto operator++() &{ - auto res = *this; - (*this)++; - return res; - } - - auto operator--(int) { - std::next_permutation(bits.begin(), bits.end()); - set_curr(); - --at; - return *this; - } - - auto operator--() &{ - auto res = *this; - (*this)--; - return res; - } -}; - -template -class Combos { -private: - const std::vector options; - int k; - int size; - -public: - Combos(const std::vector &options, int k) - : options(options), k(k), size(choose(options.size(), k)) { - } - - ComboIterator begin() const { - return ComboIterator(options, k); - } - - ComboIterator end() const { - return ComboIterator(options, k, size); - } -}; diff --git a/vis/include/geometry.hpp b/vis/include/geometry.hpp index b164722..2244dcd 100644 --- a/vis/include/geometry.hpp +++ b/vis/include/geometry.hpp @@ -5,7 +5,6 @@ #include #include #include -#include "combo_iterator.hpp" template using Prims = Eigen::Matrix; diff --git a/vis/include/rendering.hpp b/vis/include/rendering.hpp index 0be3cc2..e64c15c 100644 --- a/vis/include/rendering.hpp +++ b/vis/include/rendering.hpp @@ -5,7 +5,8 @@ #include #include -#include "mirror.hpp" +#include +#include struct Matrices { mat4 proj = mat4::Identity(); @@ -46,13 +47,13 @@ public: cgl::VertexArray vao; explicit Slice(const tc::Group &g) : group(g) { - auto gens = generators(group); - auto combos = Combos(gens, 3); - std::vector> exclude = {{0, 1, 2}}; + auto ctx = generators(group); + auto all_ctxs = combinations(ctx, N - 1); + auto selected_ctxs = difference(all_ctxs, { + {0, 2, 4}, + }); - auto all_sg_gens = combos; - - auto mesh = Mesh::hull(g, generators(g), all_sg_gens); + auto mesh = Mesh::hull(group, ctx, selected_ctxs); ibo.put(mesh); vao.ipointer(0, ibo, 4, GL_UNSIGNED_INT); diff --git a/vis/include/solver.hpp b/vis/include/solver.hpp index 6eedc24..3c6e7c6 100644 --- a/vis/include/solver.hpp +++ b/vis/include/solver.hpp @@ -9,7 +9,7 @@ #include #include -#include "combo_iterator.hpp" +#include /** * Produce a list of all generators for the group context. The range [0..group.ngens). @@ -184,7 +184,8 @@ Mesh Mesh::fill(const tc::Group &g, std::vector ctx) { if (ctx.size() + 1 != N) throw std::logic_error("ctx size must be one less than N"); - const auto &combos = Combos(ctx, (int)ctx.size() - 1); +// const auto &combos = Combos(ctx, (int)ctx.size() - 1); + const auto &combos = combinations(ctx, (int) ctx.size() - 1); std::vector> meshes;