mirror of
https://github.com/allemangD/toddcox-visualize.git
synced 2026-01-24 06:39:20 -05:00
190 lines
5.0 KiB
C++
190 lines
5.0 KiB
C++
#pragma once
|
|
|
|
#include <vector> //todo clean up includes. lots of duplicate cstdint, cassert.
|
|
#include <cstdint>
|
|
#include <cassert>
|
|
#include <tuple>
|
|
|
|
#include <limits>
|
|
|
|
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.
|
|
* <ul>
|
|
* <li>
|
|
* <code>m_ij = 1</code> iff <code>i != j</code>
|
|
* </li>
|
|
* <li>
|
|
* <code>m_ij = m_ji</code>
|
|
* </li>
|
|
* <li>
|
|
* If <code>m_ij == inf</code> (<code>tc::FREE</code>) then no relation is imposed.
|
|
* </li>
|
|
* </ul>
|
|
* @see
|
|
* <a href="https://en.wikipedia.org/wiki/Coxeter_group#Definition">Coxeter Group (Wikipedia)</a>
|
|
*/
|
|
struct Group;
|
|
|
|
/**
|
|
* @brief Support generating values given a Cosets and transformation callback.
|
|
* @tparam Gen_
|
|
*/
|
|
template<typename Gen_=void>
|
|
struct Path;
|
|
|
|
struct Cosets {
|
|
static constexpr size_t UNSET = std::numeric_limits<size_t>::max();
|
|
|
|
private:
|
|
size_t _rank;
|
|
size_t _order;
|
|
bool _complete;
|
|
std::vector<size_t> _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<size_t, size_t, Mult>;
|
|
|
|
private:
|
|
size_t _rank;
|
|
std::vector<size_t> _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<size_t> const &idxs) const;
|
|
|
|
[[nodiscard]] Cosets solve(std::vector<size_t> const &idxs = {}, size_t bound = SIZE_MAX) const;
|
|
};
|
|
|
|
template<>
|
|
struct Path<> {
|
|
using Action = std::tuple<size_t, size_t>; // coset, gen
|
|
|
|
private:
|
|
std::vector<Action> _data;
|
|
|
|
public:
|
|
// todo be smarter about move semantics
|
|
|
|
explicit Path(Cosets const &cosets) : _data() {
|
|
_data.resize(cosets.order());
|
|
|
|
std::vector<bool> 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<typename Elem, typename BinaryOp, std::random_access_iterator It>
|
|
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<typename Elem, typename BinaryOp, std::random_access_iterator It, std::random_access_iterator Gens>
|
|
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<typename Gen_>
|
|
struct Path : public Path<> {
|
|
using Gen = Gen_;
|
|
|
|
private:
|
|
std::vector<Gen> _index;
|
|
|
|
public:
|
|
template<typename T>
|
|
Path(Cosets const &cosets, T &&gens)
|
|
: Path<>(cosets), _index(std::forward<T>(gens).begin(), std::forward<T>(gens).end()) {}
|
|
|
|
template<typename Elem, typename BinaryOp, std::random_access_iterator It>
|
|
void walk(Elem const &start, BinaryOp op, It out) {
|
|
Path<>::walk(start, op, out, _index.begin());
|
|
}
|
|
};
|
|
}
|