#pragma once #include //todo clean up includes. lots of duplicate cstdint, cassert. #include #include #include #include namespace tc { using Mult = std::uint16_t; constexpr Mult FREE = 0; /** * @brief Complete representation of a quotient group. Describes the action of each generator on each coset. */ struct Cosets; /** * @brief Manage the presentation of a Coxeter group and enforce constraints * on the multiplicities of its relations. *
    *
  • * m_ij = 1 iff i != j *
  • *
  • * m_ij = m_ji *
  • *
  • * If m_ij == inf (tc::FREE) then no relation is imposed. *
  • *
* @see * Coxeter Group (Wikipedia) */ struct Group; /** * @brief Support generating values given a Cosets and transformation callback. * @tparam Gen_ */ template struct Path; struct Cosets { static constexpr size_t UNSET = std::numeric_limits::max(); private: size_t _rank; size_t _order; bool _complete; std::vector _data; public: Cosets(Cosets const &) = default; Cosets(Cosets &&) noexcept = default; ~Cosets() = default; void set(size_t coset, size_t gen, size_t target); [[nodiscard]] size_t get(size_t coset, size_t gen) const; [[nodiscard]] bool isset(size_t coset, size_t gen) const; [[nodiscard]] size_t rank() const; [[nodiscard]] size_t order() const; [[nodiscard]] bool complete() const; [[nodiscard]] size_t size() const; friend Group; // only constructible via Group<>::solve private: explicit Cosets(size_t rank); void add_row(); void set(size_t idx, size_t target); [[nodiscard]] size_t get(size_t idx) const; [[nodiscard]] bool isset(size_t idx) const; }; struct Group { using Rel = std::tuple; private: size_t _rank; std::vector _mults; public: Group(Group const &) = default; Group(Group &&) noexcept = default; ~Group() = default; explicit Group(size_t rank); void set(size_t, size_t, Mult); [[nodiscard]] Mult get(size_t, size_t) const; [[nodiscard]] size_t rank() const; [[nodiscard]] Group sub(std::vector const &idxs) const; [[nodiscard]] Cosets solve(std::vector const &idxs = {}, size_t bound = SIZE_MAX) const; }; template<> struct Path<> { using Action = std::tuple; // coset, gen private: std::vector _data; public: // todo be smarter about move semantics explicit Path(Cosets const &cosets) : _data() { _data.resize(cosets.order()); std::vector complete(cosets.order(), false); complete[0] = true; for (size_t cos = 0; cos < cosets.order(); ++cos) { for (size_t gen = 0; gen < cosets.rank(); ++gen) { size_t tgt = cosets.get(cos, gen); if (!complete[tgt]) { _data[tgt] = {cos, gen}; complete[tgt] = true; } } } } template void walk(Elem const &start, BinaryOp op, It out) { // todo how to work for std::back_insert_iterator? // todo how to work for non-default-constructible values? out[0] = start; for (int tgt = 1; tgt < _data.size(); ++tgt) { auto [cos, gen] = _data[tgt]; out[tgt] = op(out[cos], gen); } } template void walk(Elem const &start, BinaryOp op, It out, Gens const &gens) { out[0] = start; for (int tgt = 1; tgt < _data.size(); ++tgt) { auto [cos, gen] = _data[tgt]; out[tgt] = op(out[cos], gens[gen]); } } [[nodiscard]] size_t order() const { return _data.size(); } }; template struct Path : public Path<> { using Gen = Gen_; private: std::vector _index; public: template Path(Cosets const &cosets, T &&gens) : Path<>(cosets), _index(std::forward(gens).begin(), std::forward(gens).end()) {} template void walk(Elem const &start, BinaryOp op, It out) { Path<>::walk(start, op, out, _index.begin()); } }; }