1
0
Files
toddcox-faster/include/tc/complex.hpp
2021-11-12 23:13:13 -05:00

171 lines
4.9 KiB
C++

#pragma once
#include <tc/group.hpp>
#include <tc/solver.hpp>
#include <cmath>
#include <optional>
#include <numeric>
#include <iostream>
#include <utility>
namespace tc {
std::vector<Symbol> combinations(const Symbol &symbol, size_t srank) {
size_t rank = symbol.size();
std::vector<bool> mask(rank, false);
std::fill_n(mask.begin(), srank, true);
std::vector<Symbol> combos;
combos.reserve(choose(rank, srank));
Symbol row(srank);
do {
for (int j = 0, k = 0; j < rank; ++j) {
if (mask[j]) {
row(k++) = symbol(j);
}
}
combos.emplace_back(row);
} while (std::prev_permutation(mask.begin(), mask.end()));
return combos;
}
// todo remove
ArrayXui fan(const ArrayXui &prims, int root) {
ArrayXui res(prims.rows() + 1, prims.cols());
res.topRows(prims.rows()) << prims;
res.bottomRows(1).fill(root);
return res;
}
// todo visitor
void apply(const tc::Cosets &table, unsigned int gen, ArrayXui &prims) {
for (Eigen::Index i = 0; i < prims.size(); ++i) {
prims(i) = table.get(prims(i), gen);
}
}
/**
* Convert the indexes of this mesh to those of a different context, using g_gens to build the parent context and sg_gens to build this context.
*/
void recontext(
ArrayXui &prims,
const tc::Group &context,
const Symbol &g_gens,
const Symbol &sg_gens
) {
const auto proper_sg_gens = recontext_gens(context.rank(), g_gens, sg_gens);
const auto table = solve(context, g_gens, Symbol(0));
const auto path = solve(context, sg_gens, Symbol(0)).path();
auto map = path.walk(0U, proper_sg_gens, [&table](auto coset, auto gen) {
return table.get(coset, gen);
});
// todo visitor
for (Eigen::Index i = 0; i < prims.size(); ++i) {
prims(i) = map[prims(i)];
}
}
// todo remove
ArrayXui merge(const std::vector<ArrayXui> &meshes) {
Eigen::Index cols = 0;
for (const auto &mesh: meshes) {
cols += mesh.cols();
}
ArrayXui res(meshes[0].rows(), cols);
Eigen::Index offset = 0;
for (const auto &mesh: meshes) {
res.middleCols(offset, mesh.cols()) << mesh;
offset += mesh.cols();
}
return res;
}
std::vector<ArrayXui> each_tile(
ArrayXui base,
const tc::Group &context,
const Symbol &g_gens,
const Symbol &sg_gens
) {
recontext(base, context, g_gens, sg_gens);
const auto table = solve(context, g_gens, Symbol(0));
const auto path = solve(context, g_gens, sg_gens).path();
auto _gens = context.gens;
auto res = path.walk(base, _gens, [&table](auto from, auto &gen) {
apply(table, gen, from);
return from;
});
return res;
}
/**
* Produce a mesh of primitives that fill out the volume of the subgroup generated by generators g_gens within the group context
*/
ArrayXui triangulate(
const tc::Group &context,
const Symbol &g_gens
) {
if (g_gens.size() == 0) {
return ArrayXui::Zero(1, 1);
}
const auto &combos = combinations(g_gens, g_gens.size() - 1);
std::vector<ArrayXui> meshes;
// todo inline logic
// erase, merge, and fan can be inlined
// for 1..#tiles
// cols += cols
// parts.append(cols)
// result(rows, cols)
// for 1..#parts
// result.middlecols << part
// result.bottomrow.fill(0)
// todo subgroup/coset metadata
// would be good to also output which coset of which subgroup each primitive is a part of.
// this could be used in shaders etc to make rendering things easier
for (const auto &sg_gens: combos) {
auto base = triangulate(context, sg_gens);
auto tiles = each_tile(base, context, g_gens, sg_gens);
tiles.erase(tiles.begin(), tiles.begin() + 1);
auto raised = merge(tiles);
auto fanned = fan(raised, 0);
meshes.push_back(fanned);
}
const ArrayXui &result = merge(meshes);
return result;
}
template<class T>
auto hull(const tc::Group &group, T all_sg_gens) {
std::vector<ArrayXui> parts;
auto g_gens = group.gens;
// todo inline logic
// should be able to inline in a similar way as is possible in triangulate
for (const Symbol &sg_gens: all_sg_gens) {
const auto &base = triangulate(group, sg_gens);
const auto &tiles = each_tile(base, group, g_gens, sg_gens);
for (const auto &tile: tiles) {
parts.push_back(tile);
}
}
return parts;
}
}