mirror of
https://github.com/allemangD/toddcox-visualize.git
synced 2025-11-10 12:02:47 -05:00
Compare commits
5 Commits
rework-tri
...
fetchconte
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
224d984184 | ||
|
|
47de177626 | ||
|
|
928f7d7b45 | ||
|
|
501d2e0685 | ||
|
|
aa88aee643 |
@@ -1,7 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.21)
|
cmake_minimum_required(VERSION 3.21)
|
||||||
project(toddcox-visualize)
|
project(toddcox-visualize)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
|
|
||||||
@@ -14,33 +14,8 @@ include(External/imgui.cmake)
|
|||||||
include(External/json.cmake)
|
include(External/json.cmake)
|
||||||
include(External/peglib.cmake)
|
include(External/peglib.cmake)
|
||||||
|
|
||||||
#include_directories(include)
|
include(embed.cmake)
|
||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
add_subdirectory(tc)
|
add_subdirectory(tc)
|
||||||
add_subdirectory(vis)
|
#add_subdirectory(vis)
|
||||||
|
|
||||||
#add_custom_target(resources DEPENDS resources_output)
|
|
||||||
#add_custom_command(
|
|
||||||
# OUTPUT resources_output
|
|
||||||
# COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/res ${CMAKE_CURRENT_BINARY_DIR}/res
|
|
||||||
# COMMENT "Copying Resources")
|
|
||||||
#
|
|
||||||
#add_executable(vis
|
|
||||||
# src/main.cpp
|
|
||||||
# src/gl/debug.hpp
|
|
||||||
# src/gl/shader.hpp
|
|
||||||
# src/gl/buffer.hpp
|
|
||||||
# src/gl/vertexarray.hpp
|
|
||||||
# src/gl/types.hpp)
|
|
||||||
#target_link_libraries(vis glfw glad imgui eigen nlohmann_json)
|
|
||||||
#add_dependencies(vis resources)
|
|
||||||
|
|
||||||
#add_executable(serial src/serialtest.cpp)
|
|
||||||
#target_link_libraries(serial eigen nlohmann_json)
|
|
||||||
|
|
||||||
#add_executable(combotest src/combotest.cpp)
|
|
||||||
#target_link_libraries(combotest eigen tc)
|
|
||||||
|
|
||||||
#add_executable(geometrytest src/geometrytest.cpp)
|
|
||||||
#target_link_libraries(geometrytest eigen tc nlohmann_json)
|
|
||||||
|
|||||||
85
embed.cmake
Normal file
85
embed.cmake
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
find_program(EMBED_LD ${CMAKE_LINKER})
|
||||||
|
find_program(EMBED_OBJCOPY ${CMAKE_OBJCOPY})
|
||||||
|
|
||||||
|
function(_generate_embed_source EMBED_NAME)
|
||||||
|
set(options)
|
||||||
|
set(oneValueArgs SOURCE HEADER)
|
||||||
|
set(multiValueArgs FILES)
|
||||||
|
cmake_parse_arguments(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
set(VIEW_DECLARATIONS)
|
||||||
|
set(VOID_DECLARATIONS)
|
||||||
|
set(DEFINITIONS)
|
||||||
|
|
||||||
|
foreach (FILE IN LISTS PARSE_FILES)
|
||||||
|
get_filename_component(FILE_NAME "${FILE}" NAME)
|
||||||
|
|
||||||
|
string(MAKE_C_IDENTIFIER "_binary_${FILE}" SYMBOL)
|
||||||
|
string(MAKE_C_IDENTIFIER "${FILE_NAME}" IDENTIFIER)
|
||||||
|
|
||||||
|
string(APPEND VIEW_DECLARATIONS
|
||||||
|
" /// ${FILE} Text Contents\n"
|
||||||
|
" extern std::string_view const ${IDENTIFIER};\n")
|
||||||
|
|
||||||
|
string(APPEND VOID_DECLARATIONS
|
||||||
|
" /// ${FILE} Binary Contents\n"
|
||||||
|
" extern void* const ${IDENTIFIER};\n")
|
||||||
|
|
||||||
|
string(APPEND DEFINITIONS
|
||||||
|
"// ${IDENTIFIER} (${FILE})\n"
|
||||||
|
"extern \"C\" const char ${SYMBOL}_start[], ${SYMBOL}_end[];\n"
|
||||||
|
"std::string_view const ${EMBED_NAME}::${IDENTIFIER}(${SYMBOL}_start, ${SYMBOL}_end);\n"
|
||||||
|
"void* const ${EMBED_NAME}::bin::${IDENTIFIER} = (void *) ${SYMBOL}_start;\n\n")
|
||||||
|
endforeach ()
|
||||||
|
|
||||||
|
file(WRITE "${PARSE_HEADER}"
|
||||||
|
"#pragma once\n"
|
||||||
|
"#include <string>\n\n"
|
||||||
|
"namespace ${EMBED_NAME} {\n${VIEW_DECLARATIONS}}\n\n"
|
||||||
|
"namespace ${EMBED_NAME}::bin {\n${VOID_DECLARATIONS}}\n")
|
||||||
|
|
||||||
|
file(WRITE "${PARSE_SOURCE}"
|
||||||
|
"#include <${EMBED_NAME}.hpp>\n\n"
|
||||||
|
"${DEFINITIONS}")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(_embed_file OUTPUT_OBJECT FILE)
|
||||||
|
set(OBJECT "${CMAKE_CURRENT_BINARY_DIR}/${FILE}.o")
|
||||||
|
|
||||||
|
set(${OUTPUT_OBJECT} ${OBJECT} PARENT_SCOPE)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
COMMENT "Embedding ${FILE} in ${OBJECT}"
|
||||||
|
OUTPUT "${FILE}.o" DEPENDS "${FILE}"
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
COMMAND ${EMBED_LD} -r -o "${OBJECT}" -z noexecstack --format=binary "${FILE}"
|
||||||
|
COMMAND ${EMBED_OBJCOPY} --rename-section .data=.rodata,alloc,load,readonly,data,contents "${OBJECT}"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(add_embed_library EMBED_NAME)
|
||||||
|
set(FILES ${ARGN})
|
||||||
|
|
||||||
|
set(EMBED_ROOT ${CMAKE_CURRENT_BINARY_DIR}/_embed/${EMBED_NAME})
|
||||||
|
set(EMBED_SOURCE "${EMBED_ROOT}/${EMBED_NAME}.cpp")
|
||||||
|
set(EMBED_INCLUDE "${EMBED_ROOT}/include")
|
||||||
|
set(EMBED_HEADER "${EMBED_INCLUDE}/${EMBED_NAME}.hpp")
|
||||||
|
|
||||||
|
set(OBJECTS)
|
||||||
|
foreach (FILE ${ARGN})
|
||||||
|
_embed_file(OBJECT ${FILE})
|
||||||
|
list(APPEND OBJECTS ${OBJECT})
|
||||||
|
endforeach ()
|
||||||
|
|
||||||
|
message(STATUS "Generating embedding library ${EMBED_NAME}")
|
||||||
|
_generate_embed_source(
|
||||||
|
${EMBED_NAME}
|
||||||
|
SOURCE ${EMBED_SOURCE}
|
||||||
|
HEADER ${EMBED_HEADER}
|
||||||
|
FILES ${FILES})
|
||||||
|
|
||||||
|
add_library(${EMBED_NAME} STATIC ${OBJECTS} "${EMBED_SOURCE}")
|
||||||
|
target_include_directories(${EMBED_NAME} PUBLIC "${EMBED_INCLUDE}")
|
||||||
|
set_target_properties(${EMBED_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||||
|
endfunction()
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
add_library(tc
|
add_library(tc
|
||||||
include/tc/core.hpp
|
include/tc/core.hpp
|
||||||
include/tc/cosets.hpp
|
|
||||||
include/tc/group.hpp
|
|
||||||
include/tc/groups.hpp
|
include/tc/groups.hpp
|
||||||
include/tc/pair_map.hpp
|
|
||||||
include/tc/util.hpp
|
src/cosets.cpp
|
||||||
src/core.cpp
|
src/group.cpp
|
||||||
src/groups.cpp
|
src/groups.cpp
|
||||||
src/lang.cpp
|
src/lang.cpp
|
||||||
|
src/solve.cpp
|
||||||
)
|
)
|
||||||
target_link_libraries(tc peglib::peglib fmt::fmt)
|
target_link_libraries(tc peglib::peglib fmt::fmt)
|
||||||
target_include_directories(tc PUBLIC include)
|
target_include_directories(tc PUBLIC include)
|
||||||
|
|||||||
@@ -1,2 +1,5 @@
|
|||||||
add_executable(benchmark benchmark.cpp)
|
add_executable(benchmark benchmark.cpp)
|
||||||
target_link_libraries(benchmark PUBLIC tc fmt::fmt)
|
target_link_libraries(benchmark PUBLIC tc fmt::fmt)
|
||||||
|
|
||||||
|
add_executable(named named.cpp)
|
||||||
|
target_link_libraries(named PUBLIC tc fmt::fmt)
|
||||||
|
|||||||
@@ -11,20 +11,20 @@
|
|||||||
void bench(
|
void bench(
|
||||||
const std::string &group_expr,
|
const std::string &group_expr,
|
||||||
const std::string &symbol,
|
const std::string &symbol,
|
||||||
const std::vector<tc::Gen> &gens,
|
const std::vector<size_t> &gens,
|
||||||
const tc::Coset bound = tc::UNBOUNDED
|
const size_t bound = SIZE_MAX
|
||||||
) {
|
) {
|
||||||
tc::Group group = tc::coxeter(symbol);
|
tc::Group<> group = tc::coxeter(symbol);
|
||||||
|
|
||||||
std::clock_t s = std::clock();
|
std::clock_t s = std::clock();
|
||||||
tc::Cosets cosets = tc::solve(group, gens, bound);
|
tc::Cosets<> cosets = group.solve(gens, bound);
|
||||||
std::clock_t e = std::clock();
|
std::clock_t e = std::clock();
|
||||||
|
|
||||||
auto time = (double) (e - s) / CLOCKS_PER_SEC;
|
auto time = (double) (e - s) / CLOCKS_PER_SEC;
|
||||||
tc::Coset order = cosets.size();
|
size_t order = cosets.order();
|
||||||
auto cos_s = (size_t) (order / time);
|
auto cos_s = (size_t) (order / time);
|
||||||
|
|
||||||
bool complete = cosets.complete;
|
bool complete = cosets.complete();
|
||||||
|
|
||||||
std::string name = fmt::format("{}/{}", group_expr, gens);
|
std::string name = fmt::format("{}/{}", group_expr, gens);
|
||||||
std::string row = fmt::format(
|
std::string row = fmt::format(
|
||||||
@@ -80,59 +80,59 @@ int main(int argc, char *argv[]) {
|
|||||||
// Affine Groups
|
// Affine Groups
|
||||||
|
|
||||||
// ~A_n: {3 * `n+1`}
|
// ~A_n: {3 * `n+1`}
|
||||||
bench("~A_5", "{3 * 6}", {}, 1000000);
|
bench("~A_5", "{3 * 6}", {}, 10'000'000);
|
||||||
bench("~A_6", "{3 * 7}", {}, 1000000);
|
bench("~A_6", "{3 * 7}", {}, 10'000'000);
|
||||||
bench("~A_7", "{3 * 8}", {}, 1000000);
|
bench("~A_7", "{3 * 8}", {}, 10'000'000);
|
||||||
bench("~A_8", "{3 * 9}", {}, 1000000);
|
bench("~A_8", "{3 * 9}", {}, 10'000'000);
|
||||||
// ~B_n: 4 3 * `n-3` 3 * [1 1]
|
// ~B_n: 4 3 * `n-3` 3 * [1 1]
|
||||||
bench("~B_5", "4 3 * 2 3 * [1 1]", {}, 1000000);
|
bench("~B_5", "4 3 * 2 3 * [1 1]", {}, 10'000'000);
|
||||||
bench("~B_6", "4 3 * 3 3 * [1 1]", {}, 1000000);
|
bench("~B_6", "4 3 * 3 3 * [1 1]", {}, 10'000'000);
|
||||||
bench("~B_7", "4 3 * 4 3 * [1 1]", {}, 1000000);
|
bench("~B_7", "4 3 * 4 3 * [1 1]", {}, 10'000'000);
|
||||||
bench("~B_8", "4 3 * 5 3 * [1 1]", {}, 1000000);
|
bench("~B_8", "4 3 * 5 3 * [1 1]", {}, 10'000'000);
|
||||||
// ~B_n: 4 3 * `n-2` 4
|
// ~B_n: 4 3 * `n-2` 4
|
||||||
bench("~C_5", "4 3 * 3 4", {}, 1000000);
|
bench("~C_5", "4 3 * 3 4", {}, 10'000'000);
|
||||||
bench("~C_6", "4 3 * 4 4", {}, 1000000);
|
bench("~C_6", "4 3 * 4 4", {}, 10'000'000);
|
||||||
bench("~C_7", "4 3 * 5 4", {}, 1000000);
|
bench("~C_7", "4 3 * 5 4", {}, 10'000'000);
|
||||||
bench("~C_8", "4 3 * 6 4", {}, 1000000);
|
bench("~C_8", "4 3 * 6 4", {}, 10'000'000);
|
||||||
// ~D_n: 3 * [1 1] 3 * `n-4` 3 * [1 1]
|
// ~D_n: 3 * [1 1] 3 * `n-4` 3 * [1 1]
|
||||||
bench("~D_5", "3 * [1 1] 3 * 1 3 * [1 1]", {}, 1000000);
|
bench("~D_5", "3 * [1 1] 3 * 1 3 * [1 1]", {}, 10'000'000);
|
||||||
bench("~D_6", "3 * [1 1] 3 * 2 3 * [1 1]", {}, 1000000);
|
bench("~D_6", "3 * [1 1] 3 * 2 3 * [1 1]", {}, 10'000'000);
|
||||||
bench("~D_7", "3 * [1 1] 3 * 3 3 * [1 1]", {}, 1000000);
|
bench("~D_7", "3 * [1 1] 3 * 3 3 * [1 1]", {}, 10'000'000);
|
||||||
bench("~D_8", "3 * [1 1] 3 * 4 3 * [1 1]", {}, 1000000);
|
bench("~D_8", "3 * [1 1] 3 * 4 3 * [1 1]", {}, 10'000'000);
|
||||||
// grid: `p` `q` ; 2(p+q) = pq
|
// grid: `p` `q` ; 2(p+q) = pq
|
||||||
// triangle: `p` `q` `r` ; 1/p + 1/q + 1/r = 1
|
// triangle: `p` `q` `r` ; 1/p + 1/q + 1/r = 1
|
||||||
|
|
||||||
// Special Affine Groups
|
// Special Affine Groups
|
||||||
bench("~I_1", "-", {}, 1000000);
|
bench("~I_1", "-", {}, 10'000'000);
|
||||||
bench("~E_6", "3 * [2 2 2]", {}, 1000000);
|
bench("~E_6", "3 * [2 2 2]", {}, 10'000'000);
|
||||||
bench("~E_7", "3 * [1 3 3]", {}, 1000000);
|
bench("~E_7", "3 * [1 3 3]", {}, 10'000'000);
|
||||||
bench("~E_8", "3 * [1 2 5]", {}, 1000000);
|
bench("~E_8", "3 * [1 2 5]", {}, 10'000'000);
|
||||||
// bench("E_9", "3 * [1 2 5]", {}, 1000000); // ~E_8 == E_9
|
// bench("E_9", "3 * [1 2 5]", {}, 10'000'000); // ~E_8 == E_9
|
||||||
bench("~F_4", "3 4 3 3", {}, 1000000);
|
bench("~F_4", "3 4 3 3", {}, 10'000'000);
|
||||||
bench("~G_2", "6 3", {}, 1000000);
|
bench("~G_2", "6 3", {}, 10'000'000);
|
||||||
|
|
||||||
// Hyperbolic Groups
|
// Hyperbolic Groups
|
||||||
// grid: `p` `q` ; 2(p+q) < pq
|
// grid: `p` `q` ; 2(p+q) < pq
|
||||||
// triangle: `p` `q` `r` ; 1/p + 1/q + 1/r < 1
|
// triangle: `p` `q` `r` ; 1/p + 1/q + 1/r < 1
|
||||||
|
|
||||||
// Special Hyperbolic Groups
|
// Special Hyperbolic Groups
|
||||||
bench("-BH_3", "4 3 5", {}, 1000000);
|
bench("-BH_3", "4 3 5", {}, 10'000'000);
|
||||||
bench("-K_3", "5 3 5", {}, 1000000);
|
bench("-K_3", "5 3 5", {}, 10'000'000);
|
||||||
bench("-J_3", "3 5 3", {}, 1000000);
|
bench("-J_3", "3 5 3", {}, 10'000'000);
|
||||||
// bench("~H_3", "3 5 3", {}, 1000000); // -J_3 == ~H_3
|
// bench("~H_3", "3 5 3", {}, 10'000'000); // -J_3 == ~H_3
|
||||||
bench("-DH_3", "5 3 * [1 1]", {}, 1000000);
|
bench("-DH_3", "5 3 * [1 1]", {}, 10'000'000);
|
||||||
bench("^AB_3", "{3 3 3 4}", {}, 1000000);
|
bench("^AB_3", "{3 3 3 4}", {}, 10'000'000);
|
||||||
bench("^AH_3", "{3 3 3 5}", {}, 1000000);
|
bench("^AH_3", "{3 3 3 5}", {}, 10'000'000);
|
||||||
bench("^BB_3", "{3 4 3 4}", {}, 1000000);
|
bench("^BB_3", "{3 4 3 4}", {}, 10'000'000);
|
||||||
bench("^BH_3", "{3 4 3 5}", {}, 1000000);
|
bench("^BH_3", "{3 4 3 5}", {}, 10'000'000);
|
||||||
bench("^HH_3", "{3 5 3 5}", {}, 1000000);
|
bench("^HH_3", "{3 5 3 5}", {}, 10'000'000);
|
||||||
bench("-H_4", "5 3 3 3", {}, 1000000);
|
bench("-H_4", "5 3 3 3", {}, 10'000'000);
|
||||||
// bench("~H_4", "5 3 3 3", {}, 1000000); // -H_4 == ~H_4 == H_5
|
// bench("~H_4", "5 3 3 3", {}, 10'000'000); // -H_4 == ~H_4 == H_5
|
||||||
// bench("H_5", "5 3 3 3", {}, 1000000);
|
// bench("H_5", "5 3 3 3", {}, 10'000'000);
|
||||||
bench("-BH_4", "4 3 3 5", {}, 1000000);
|
bench("-BH_4", "4 3 3 5", {}, 10'000'000);
|
||||||
bench("-K_4", "5 3 3 5", {}, 1000000);
|
bench("-K_4", "5 3 3 5", {}, 10'000'000);
|
||||||
bench("-DH_4", "5 3 3 * [1 1]", {}, 1000000);
|
bench("-DH_4", "5 3 3 * [1 1]", {}, 10'000'000);
|
||||||
bench("^AF_4", "{3 3 3 3 4}", {}, 1000000);
|
bench("^AF_4", "{3 3 3 3 4}", {}, 10'000'000);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
55
tc/bench/named.cpp
Normal file
55
tc/bench/named.cpp
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#include <fmt/ranges.h>
|
||||||
|
|
||||||
|
#include <tc/core.hpp>
|
||||||
|
|
||||||
|
template<typename G>
|
||||||
|
void show(G const &g) { // todo add formatter for groups, cosets.
|
||||||
|
fmt::print(" | ");
|
||||||
|
for (const auto &v: g.gens()) {
|
||||||
|
fmt::print("{} ", v);
|
||||||
|
}
|
||||||
|
fmt::print("\n");
|
||||||
|
|
||||||
|
for (const auto &u: g.gens()) {
|
||||||
|
fmt::print("{} | ", u);
|
||||||
|
for (const auto &v: g.gens()) {
|
||||||
|
fmt::print("{} ", g.get(u, v));
|
||||||
|
}
|
||||||
|
fmt::print("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
tc::Group<char> group(4, {'r', 'g', 'b', 'y'});
|
||||||
|
|
||||||
|
group.set('r', 'g', 5);
|
||||||
|
group.set('g', 'b', 4);
|
||||||
|
group.set('b', 'y', 3);
|
||||||
|
|
||||||
|
show(group);
|
||||||
|
|
||||||
|
auto sub = group.sub({'r', 'g', 'y'});
|
||||||
|
show(sub);
|
||||||
|
|
||||||
|
auto res = sub.solve({});
|
||||||
|
fmt::print("res order: {}\n", res.order());
|
||||||
|
|
||||||
|
auto cos = sub.solve({'r', 'y'});
|
||||||
|
|
||||||
|
fmt::print("order: {}\n", cos.order());
|
||||||
|
|
||||||
|
// tc::Group<u_int8_t> group(4, {0, 1, 2, 3});
|
||||||
|
//
|
||||||
|
// group.set(0, 1, 5);
|
||||||
|
// group.set(1, 2, 4);
|
||||||
|
// group.set(2, 3, 3);
|
||||||
|
//
|
||||||
|
// show(group);
|
||||||
|
//
|
||||||
|
// auto sub = group.sub({3, 2, 0, 1});
|
||||||
|
// show(sub);
|
||||||
|
}
|
||||||
@@ -1,30 +1,227 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <vector> //todo clean up includes. lots of duplicate cstdint, cassert.
|
||||||
#include <functional>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <cassert>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "util.hpp"
|
#include <limits>
|
||||||
#include "cosets.hpp"
|
|
||||||
#include "group.hpp"
|
|
||||||
|
|
||||||
namespace tc {
|
namespace tc {
|
||||||
Cosets solve(const Group &group, const std::vector<Gen> &sub_gens, const Coset &bound = UNBOUNDED);
|
using Mult = u_int16_t;
|
||||||
|
constexpr Mult FREE = 0;
|
||||||
|
|
||||||
// todo
|
/**
|
||||||
///**
|
* @brief Mapping from "global" generator names or objects to indexes used for value lookup.
|
||||||
// * Solve the cosets generated by sg_gens within the subgroup generated by g_gens of the group context
|
* @tparam Gen_
|
||||||
// */
|
*/
|
||||||
// tc::Cosets solve(
|
template<typename Gen_=void>
|
||||||
// const tc::Group &context,
|
struct Index;
|
||||||
// const std::vector<tc::Gen> &g_gens,
|
|
||||||
// const std::vector<tc::Gen> &sg_gens
|
|
||||||
// ) {
|
|
||||||
// // todo this should also be handled with 'global' generators.
|
|
||||||
// const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens);
|
|
||||||
//
|
|
||||||
// return tc::solve(context.subgroup(g_gens), proper_sg_gens);
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Complete representation of a quotient group. Describes the action of each generator on each coset.
|
||||||
|
* @tparam Gen_
|
||||||
|
*/
|
||||||
|
template<typename Gen_=void>
|
||||||
|
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>
|
||||||
|
*/
|
||||||
|
template<typename Gen_=void>
|
||||||
|
struct Group;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Support generating values given a Cosets and transformation callback.
|
||||||
|
* @tparam Gen_
|
||||||
|
*/
|
||||||
|
template<typename Gen_=void>
|
||||||
|
struct Path; // todo not yet implemented
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Index<> {
|
||||||
|
size_t operator()(size_t const &idx) const {
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Gen_>
|
||||||
|
struct Index {
|
||||||
|
using Gen = Gen_;
|
||||||
|
|
||||||
|
std::vector<Gen> _gens{};
|
||||||
|
|
||||||
|
// explicit Index(std::vector<Gen> gens) : _gens(gens) {}
|
||||||
|
|
||||||
|
size_t operator()(Gen const &gen) const {
|
||||||
|
auto it = std::find(_gens.begin(), _gens.end(), gen);
|
||||||
|
assert(it != _gens.end());
|
||||||
|
return it - _gens.begin();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
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<typename Gen_>
|
||||||
|
struct Cosets : public Cosets<> {
|
||||||
|
using Gen = Gen_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Index<Gen> _index;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Cosets(Cosets<> g, std::vector<Gen> gens)
|
||||||
|
: Cosets<>(g), _index(gens) {}
|
||||||
|
|
||||||
|
void set(size_t coset, Gen const &gen, size_t target) {
|
||||||
|
Cosets<>::set(coset, _index(gen), target);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] size_t get(size_t coset, Gen const &gen) const {
|
||||||
|
return Cosets<>::get(coset, _index(gen));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool isset(size_t coset, Gen const &gen) const {
|
||||||
|
return Cosets<>::isset(coset, _index(gen));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::vector<Gen> gens() const {
|
||||||
|
return _index._gens;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Cosets(size_t rank, std::vector<Gen> gens)
|
||||||
|
: Cosets<>(rank), _index(gens) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Gen_>
|
||||||
|
struct Group : public Group<> {
|
||||||
|
using Gen = Gen_;
|
||||||
|
using Rel = std::tuple<Gen, Gen, Mult>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Index<Gen> _index;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Group(Group const &) = default;
|
||||||
|
|
||||||
|
Group(Group &&) noexcept = default;
|
||||||
|
|
||||||
|
Group(Group<> g, std::vector<Gen> gens)
|
||||||
|
: Group<>(g), _index(gens) {}
|
||||||
|
|
||||||
|
Group(size_t rank, std::vector<Gen> gens)
|
||||||
|
: Group<>(rank), _index(gens) {}
|
||||||
|
|
||||||
|
~Group() = default;
|
||||||
|
|
||||||
|
void set(Gen const &u, Gen const &v, Mult m) {
|
||||||
|
Group<>::set(_index(u), _index(v), m);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Mult get(Gen const &u, Gen const &v) const {
|
||||||
|
return Group<>::get(_index(u), _index(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::vector<Gen> gens() const {
|
||||||
|
return _index._gens;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Group sub(std::vector<Gen> const &gens) const {
|
||||||
|
std::vector<size_t> idxs(gens.size());
|
||||||
|
std::transform(gens.begin(), gens.end(), idxs.begin(), _index);
|
||||||
|
return Group(Group<>::sub(idxs), gens);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Cosets<Gen> solve(std::vector<Gen> const &gens, size_t bound = SIZE_MAX) const {
|
||||||
|
std::vector<size_t> idxs(gens.size());
|
||||||
|
std::transform(gens.begin(), gens.end(), idxs.begin(), _index);
|
||||||
|
|
||||||
|
return Cosets<Gen>(Group<>::solve(idxs, bound), gens);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
#include "util.hpp"
|
|
||||||
|
|
||||||
namespace tc {
|
|
||||||
struct Cosets {
|
|
||||||
Gen ngens;
|
|
||||||
std::vector<int> data;
|
|
||||||
Path path;
|
|
||||||
bool complete = false;
|
|
||||||
|
|
||||||
Cosets(const Cosets &) = default;
|
|
||||||
|
|
||||||
explicit Cosets(Gen ngens)
|
|
||||||
: ngens(ngens) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_row() {
|
|
||||||
data.resize(data.size() + ngens, UNSET);
|
|
||||||
path.add_row();
|
|
||||||
}
|
|
||||||
|
|
||||||
void put(Coset coset, Gen gen, Coset target) {
|
|
||||||
data[coset * ngens + gen] = target;
|
|
||||||
data[target * ngens + gen] = coset;
|
|
||||||
|
|
||||||
if (path.get(target).from_idx == UNSET) {
|
|
||||||
path.put(coset, gen, target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void put(size_t idx, Coset target) {
|
|
||||||
Coset coset = idx / ngens;
|
|
||||||
Gen gen = idx % ngens;
|
|
||||||
|
|
||||||
data[idx] = target;
|
|
||||||
data[target * ngens + gen] = coset;
|
|
||||||
|
|
||||||
if (path.get(target).from_idx == UNSET) {
|
|
||||||
path.put(coset, gen, target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] Coset get(Coset coset, Gen gen) const {
|
|
||||||
return data[coset * ngens + gen];
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] Coset get(size_t idx) const {
|
|
||||||
return data[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool isset(Coset coset, Gen gen) const {
|
|
||||||
return get(coset, gen) != UNSET;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool isset(size_t idx) const {
|
|
||||||
return get(idx) != UNSET;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[[nodiscard]] tc::Coset size() const {
|
|
||||||
return path.size();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include <tc/util.hpp>
|
|
||||||
#include <tc/pair_map.hpp>
|
|
||||||
|
|
||||||
namespace tc {
|
|
||||||
struct Group;
|
|
||||||
struct SubGroup;
|
|
||||||
|
|
||||||
struct Graph {
|
|
||||||
size_t rank{};
|
|
||||||
std::vector<tc::Rel> edges{};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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 {
|
|
||||||
int rank;
|
|
||||||
tc::pair_map<int> _orders;
|
|
||||||
|
|
||||||
Group(const Group &) = default;
|
|
||||||
|
|
||||||
explicit Group(int rank, const std::vector<Rel> &rels = {})
|
|
||||||
: rank(rank), _orders(rank, 2) {
|
|
||||||
|
|
||||||
for (int i = 0; i < rank; ++i) {
|
|
||||||
set(Rel{i, i, 1});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &rel: rels) {
|
|
||||||
set(rel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit Group(const Graph &graph)
|
|
||||||
: rank(graph.rank), _orders(graph.rank, 2) {
|
|
||||||
for (const auto &[i, j, order]: graph.edges) {
|
|
||||||
set({i, j, order});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void set(const Rel &r) {
|
|
||||||
auto &[i, j, m] = r;
|
|
||||||
assert(i != j || m == 1);
|
|
||||||
_orders(i, j) = m;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] int get(int i, int j) const {
|
|
||||||
return _orders(i, j);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] SubGroup subgroup(const std::vector<tc::Gen> &gens) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SubGroup : public Group {
|
|
||||||
std::vector<tc::Gen> gen_map;
|
|
||||||
const Group &parent;
|
|
||||||
|
|
||||||
SubGroup(const Group &parent, std::vector<tc::Gen> gen_map)
|
|
||||||
: Group(gen_map.size()), parent(parent), gen_map() {
|
|
||||||
|
|
||||||
std::sort(gen_map.begin(), gen_map.end());
|
|
||||||
this->gen_map = gen_map;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < gen_map.size(); ++i) {
|
|
||||||
for (size_t j = 0; j < gen_map.size(); ++j) {
|
|
||||||
int mult = parent.get(gen_map[i], gen_map[j]);
|
|
||||||
set(Rel(i, j, mult));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,22 +1,23 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <tc/group.hpp>
|
#include <tc/core.hpp>
|
||||||
|
|
||||||
namespace tc {
|
namespace tc {
|
||||||
/**
|
/**
|
||||||
* Construct a group from a (simplified) Schlafli Symbol of the form [a, b, ..., c]
|
* Construct a group from a (simplified) Schlafli Symbol of the form [a, b, ..., c]
|
||||||
* @param mults: The sequence of multiplicites between adjacent generators.
|
* @param mults: The sequence of multiplicites between adjacent generators.
|
||||||
*/
|
*/
|
||||||
Group schlafli(const std::vector<unsigned int> &mults);
|
Group<> schlafli(const std::vector<unsigned int> &mults);
|
||||||
|
|
||||||
Group coxeter(const std::string &symbol);
|
Group<> coxeter(const std::string &symbol);
|
||||||
|
|
||||||
Group vcoxeter(const std::string &symbol, const std::vector<unsigned int> &values);
|
Group<> vcoxeter(const std::string &symbol, const std::vector<unsigned int> &values);
|
||||||
|
|
||||||
template<typename ...Args>
|
template<typename ...Args>
|
||||||
Group coxeter(const std::string &symbol, const Args &... args) {
|
Group<> coxeter(const std::string &symbol, const Args &... args) {
|
||||||
std::vector<unsigned int> values = {{args...}};
|
std::vector<unsigned int> values = {{args...}};
|
||||||
return vcoxeter(symbol, values);
|
return vcoxeter(symbol, values);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,453 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <iterator>
|
|
||||||
#include <tuple>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace tc {
|
|
||||||
template<typename T>
|
|
||||||
struct pair_map {
|
|
||||||
struct iterator;
|
|
||||||
struct const_iterator;
|
|
||||||
struct view;
|
|
||||||
struct const_view;
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t _size;
|
|
||||||
std::vector<T> _data{};
|
|
||||||
|
|
||||||
static size_t idx(size_t i, size_t j);
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit pair_map(size_t size);
|
|
||||||
|
|
||||||
explicit pair_map(size_t size, const T &value);
|
|
||||||
|
|
||||||
[[nodiscard]] size_t size() const;
|
|
||||||
|
|
||||||
T &operator()(size_t i, size_t j);
|
|
||||||
|
|
||||||
T operator()(size_t i, size_t j) const;
|
|
||||||
|
|
||||||
view of(size_t f);
|
|
||||||
|
|
||||||
const_view of(size_t f) const;
|
|
||||||
|
|
||||||
const_view cof(size_t f);
|
|
||||||
|
|
||||||
iterator begin();
|
|
||||||
|
|
||||||
iterator end();
|
|
||||||
|
|
||||||
const_iterator begin() const;
|
|
||||||
|
|
||||||
const_iterator end() const;
|
|
||||||
|
|
||||||
const_iterator cbegin();
|
|
||||||
|
|
||||||
const_iterator cend();
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct pair_map<T>::iterator {
|
|
||||||
using reference = std::tuple<size_t, size_t, T &>;
|
|
||||||
|
|
||||||
private:
|
|
||||||
pair_map<T> &_map;
|
|
||||||
size_t _i, _j;
|
|
||||||
|
|
||||||
public:
|
|
||||||
iterator(pair_map<T> &map, size_t i, size_t j);
|
|
||||||
|
|
||||||
iterator operator++();
|
|
||||||
|
|
||||||
iterator operator++(int) &;
|
|
||||||
|
|
||||||
reference operator*();
|
|
||||||
|
|
||||||
bool operator!=(const iterator &other);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct pair_map<T>::const_iterator {
|
|
||||||
using value_type = std::tuple<size_t, size_t, T>;
|
|
||||||
|
|
||||||
private:
|
|
||||||
const pair_map<T> &_map;
|
|
||||||
size_t _i, _j;
|
|
||||||
|
|
||||||
public:
|
|
||||||
const_iterator(const pair_map<T> &map, size_t i, size_t j);
|
|
||||||
|
|
||||||
const_iterator operator++();
|
|
||||||
|
|
||||||
const_iterator operator++(int) &;
|
|
||||||
|
|
||||||
value_type operator*();
|
|
||||||
|
|
||||||
bool operator!=(const const_iterator &other);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct pair_map<T>::view {
|
|
||||||
struct iterator;
|
|
||||||
struct const_iterator;
|
|
||||||
|
|
||||||
private:
|
|
||||||
pair_map<T> &_map;
|
|
||||||
size_t _f;
|
|
||||||
|
|
||||||
public:
|
|
||||||
view(pair_map<T> &map, size_t f);
|
|
||||||
|
|
||||||
iterator begin();
|
|
||||||
|
|
||||||
iterator end();
|
|
||||||
|
|
||||||
const_iterator begin() const;
|
|
||||||
|
|
||||||
const_iterator end() const;
|
|
||||||
|
|
||||||
const_iterator cbegin();
|
|
||||||
|
|
||||||
const_iterator cend();
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct pair_map<T>::view::iterator {
|
|
||||||
using reference = std::tuple<size_t, size_t, T &>;
|
|
||||||
|
|
||||||
private:
|
|
||||||
pair_map<T> &_map;
|
|
||||||
size_t _f, _v;
|
|
||||||
|
|
||||||
public:
|
|
||||||
iterator(pair_map<T> &map, size_t f, size_t v);
|
|
||||||
|
|
||||||
iterator operator++();
|
|
||||||
|
|
||||||
iterator operator++(int);
|
|
||||||
|
|
||||||
reference operator*();
|
|
||||||
|
|
||||||
bool operator!=(const iterator &other);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct pair_map<T>::view::const_iterator {
|
|
||||||
using value_type = std::tuple<size_t, size_t, T>;
|
|
||||||
|
|
||||||
private:
|
|
||||||
const pair_map<T> &_map;
|
|
||||||
size_t _f, _v;
|
|
||||||
|
|
||||||
public:
|
|
||||||
const_iterator(const pair_map<T> &map, size_t f, size_t v);
|
|
||||||
|
|
||||||
const_iterator operator++();
|
|
||||||
|
|
||||||
const_iterator operator++(int);
|
|
||||||
|
|
||||||
value_type operator*();
|
|
||||||
|
|
||||||
bool operator!=(const const_iterator &other);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct pair_map<T>::const_view {
|
|
||||||
using const_iterator = typename pair_map<T>::view::const_iterator;
|
|
||||||
|
|
||||||
private:
|
|
||||||
const pair_map<T> &_map;
|
|
||||||
size_t _f;
|
|
||||||
|
|
||||||
public:
|
|
||||||
const_view(const pair_map<T> &map, size_t f);
|
|
||||||
|
|
||||||
const_iterator begin() const;
|
|
||||||
|
|
||||||
const_iterator end() const;
|
|
||||||
|
|
||||||
const_iterator cbegin();
|
|
||||||
|
|
||||||
const_iterator cend();
|
|
||||||
};
|
|
||||||
|
|
||||||
// region pair_map
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
size_t pair_map<T>::idx(size_t i, size_t j) {
|
|
||||||
if (i > j) std::swap(i, j);
|
|
||||||
return j * (j + 1) / 2 + i;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
pair_map<T>::pair_map(size_t size)
|
|
||||||
: _size(size), _data(size * (size + 1) / 2) {}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
pair_map<T>::pair_map(size_t size, const T &value)
|
|
||||||
: _size(size), _data(size * (size + 1) / 2, value) {}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
size_t pair_map<T>::size() const {
|
|
||||||
return _size;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T &pair_map<T>::operator()(size_t i, size_t j) {
|
|
||||||
return _data[idx(i, j)];
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T pair_map<T>::operator()(size_t i, size_t j) const {
|
|
||||||
return _data[idx(i, j)];
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::view pair_map<T>::of(size_t f) {
|
|
||||||
return view(*this, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::const_view pair_map<T>::of(size_t f) const {
|
|
||||||
return const_view(*this, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::const_view pair_map<T>::cof(size_t f) {
|
|
||||||
return const_view(*this, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::iterator pair_map<T>::begin() {
|
|
||||||
return iterator(*this, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::iterator pair_map<T>::end() {
|
|
||||||
return iterator(*this, 0, _size);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::const_iterator pair_map<T>::begin() const {
|
|
||||||
return const_iterator(*this, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::const_iterator pair_map<T>::end() const {
|
|
||||||
return const_iterator(*this, 0, _size);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::const_iterator pair_map<T>::cbegin() {
|
|
||||||
return const_iterator(*this, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::const_iterator pair_map<T>::cend() {
|
|
||||||
return const_iterator(*this, 0, _size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
// region pair_map::iterator
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
pair_map<T>::iterator::iterator(pair_map<T> &map, size_t i, size_t j)
|
|
||||||
:_map(map), _i(i), _j(j) {}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::iterator pair_map<T>::iterator::operator++() {
|
|
||||||
if (++_i > _j) {
|
|
||||||
_i = 0;
|
|
||||||
++_j;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::iterator pair_map<T>::iterator::operator++(int) &{
|
|
||||||
iterator it = *this;
|
|
||||||
++this;
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::iterator::reference pair_map<T>::iterator::operator*() {
|
|
||||||
return std::tie(_i, _j, _map(_i, _j));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool pair_map<T>::iterator::operator!=(const pair_map::iterator &other) {
|
|
||||||
return &_map != &other._map || _i != other._i || _j != other._j;
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
// region pair_map::const_iterator
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
pair_map<T>::const_iterator::const_iterator(const pair_map<T> &map, size_t i, size_t j)
|
|
||||||
:_map(map), _i(i), _j(j) {}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::const_iterator pair_map<T>::const_iterator::operator++() {
|
|
||||||
if (++_i > _j) {
|
|
||||||
_i = 0;
|
|
||||||
++_j;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::const_iterator pair_map<T>::const_iterator::operator++(int) &{
|
|
||||||
const_iterator it = *this;
|
|
||||||
++this;
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::const_iterator::value_type pair_map<T>::const_iterator::operator*() {
|
|
||||||
return std::tuple(_i, _j, _map(_i, _j));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool pair_map<T>::const_iterator::operator!=(const pair_map::const_iterator &other) {
|
|
||||||
return &_map != &other._map || _i != other._i || _j != other._j;
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
// region pair_map::view
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
pair_map<T>::view::view(pair_map<T> &map, size_t f)
|
|
||||||
: _map(map), _f(f) {}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::view::iterator pair_map<T>::view::begin() {
|
|
||||||
return iterator(_map, _f, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::view::iterator pair_map<T>::view::end() {
|
|
||||||
return iterator(_map, _f, _map._size);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::view::const_iterator pair_map<T>::view::begin() const {
|
|
||||||
return const_iterator(_map, _f, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::view::const_iterator pair_map<T>::view::end() const {
|
|
||||||
return const_iterator(_map, _f, _map._size);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::view::const_iterator pair_map<T>::view::cbegin() {
|
|
||||||
return const_iterator(_map, _f, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::view::const_iterator pair_map<T>::view::cend() {
|
|
||||||
return const_iterator(_map, _f, _map._size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
// region pair_map::view::iterator
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
pair_map<T>::view::iterator::iterator(pair_map<T> &map, size_t f, size_t v)
|
|
||||||
: _map(map), _f(f), _v(v) {}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::view::iterator pair_map<T>::view::iterator::operator++() {
|
|
||||||
++_v;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::view::iterator pair_map<T>::view::iterator::operator++(int) {
|
|
||||||
iterator it = *this;
|
|
||||||
++this;
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::view::iterator::reference pair_map<T>::view::iterator::operator*() {
|
|
||||||
auto [i, j] = std::minmax(_f, _v);
|
|
||||||
return std::tie(i, j, _map(i, j));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool pair_map<T>::view::iterator::operator!=(const pair_map::view::iterator &other) {
|
|
||||||
return &_map != &other._map || _f != other._f || _v != other._v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
// region pair_map::view::const_iterator
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
pair_map<T>::view::const_iterator::const_iterator(const pair_map<T> &map, size_t f, size_t v)
|
|
||||||
: _map(map), _f(f), _v(v) {}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::view::const_iterator pair_map<T>::view::const_iterator::operator++() {
|
|
||||||
++_v;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::view::const_iterator pair_map<T>::view::const_iterator::operator++(int) {
|
|
||||||
const_iterator it = *this;
|
|
||||||
++this;
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::view::const_iterator::value_type pair_map<T>::view::const_iterator::operator*() {
|
|
||||||
auto [i, j] = std::minmax(_f, _v);
|
|
||||||
return std::tuple(i, j, _map(i, j));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool pair_map<T>::view::const_iterator::operator!=(const pair_map::view::const_iterator &other) {
|
|
||||||
return &_map != &other._map || _f != other._f || _v != other._v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
// region pair_map::const_view
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
pair_map<T>::const_view::const_view(const pair_map<T> &map, size_t f)
|
|
||||||
: _map(map), _f(f) {}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::const_view::const_iterator pair_map<T>::const_view::begin() const {
|
|
||||||
return const_iterator(_map, _f, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::const_view::const_iterator pair_map<T>::const_view::end() const {
|
|
||||||
return const_iterator(_map, _f, _map._size);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::const_view::const_iterator pair_map<T>::const_view::cbegin() {
|
|
||||||
return const_iterator(_map, _f, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename pair_map<T>::const_view::const_iterator pair_map<T>::const_view::cend() {
|
|
||||||
return const_iterator(_map, _f, _map._size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion
|
|
||||||
}
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <vector>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
namespace tc {
|
|
||||||
using Gen = uint8_t;
|
|
||||||
using Mult = uint16_t;
|
|
||||||
|
|
||||||
constexpr Mult FREE = Mult(-1);
|
|
||||||
|
|
||||||
using Coset = uint32_t;
|
|
||||||
constexpr Coset UNSET = Coset(-1);
|
|
||||||
constexpr Coset UNBOUNDED = (Coset) (-1);
|
|
||||||
|
|
||||||
using Rel = std::tuple<Gen, Gen, Mult>;
|
|
||||||
|
|
||||||
struct Action {
|
|
||||||
int from_idx = -1;
|
|
||||||
int gen = -1;
|
|
||||||
|
|
||||||
Action() = default;
|
|
||||||
|
|
||||||
Action(const Action &) = default;
|
|
||||||
|
|
||||||
Action(int from_idx, int gen)
|
|
||||||
: from_idx(from_idx), gen(gen) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Path {
|
|
||||||
std::vector<Action> path;
|
|
||||||
|
|
||||||
Path() = default;
|
|
||||||
|
|
||||||
Path(const Path &) = default;
|
|
||||||
|
|
||||||
void add_row() {
|
|
||||||
path.resize(path.size() + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] Action get(int to_idx) const {
|
|
||||||
return path[to_idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
void put(int from_idx, int gen, int to_idx) {
|
|
||||||
path[to_idx] = Action(from_idx, gen);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class C, class T, class E>
|
|
||||||
void walk(
|
|
||||||
C &res,
|
|
||||||
T start,
|
|
||||||
std::vector<E> gens,
|
|
||||||
std::function<T(const T &, const E &)> op
|
|
||||||
) const {
|
|
||||||
size_t s = size();
|
|
||||||
res.reserve(s);
|
|
||||||
res.push_back(start);
|
|
||||||
|
|
||||||
for (int i = 1; i < s; ++i) {
|
|
||||||
auto &action = path[i];
|
|
||||||
auto &from = res.get(action.from_idx);
|
|
||||||
auto &val = gens[action.gen];
|
|
||||||
res.push_back(op(from, val));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T, class E>
|
|
||||||
[[nodiscard]] std::vector<T> walk(
|
|
||||||
T start,
|
|
||||||
std::vector<E> gens,
|
|
||||||
std::function<T(const T &, const E &)> op
|
|
||||||
) const {
|
|
||||||
std::vector<T> res;
|
|
||||||
res.reserve(size());
|
|
||||||
res.push_back(start);
|
|
||||||
|
|
||||||
for (int i = 1; i < size(); ++i) {
|
|
||||||
auto &action = path[i];
|
|
||||||
auto &from = res[action.from_idx];
|
|
||||||
auto &val = gens[action.gen];
|
|
||||||
res.push_back(op(from, val));
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
[[nodiscard]] std::vector<T> walk(
|
|
||||||
T start,
|
|
||||||
std::function<T(const T &, const int &)> op
|
|
||||||
) const {
|
|
||||||
std::vector<T> res;
|
|
||||||
res.reserve(size());
|
|
||||||
res.push_back(start);
|
|
||||||
|
|
||||||
for (int i = 1; i < size(); ++i) {
|
|
||||||
auto &action = path[i];
|
|
||||||
auto &from = res[action.from_idx];
|
|
||||||
auto &val = action.gen;
|
|
||||||
res[i] = op(from, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] size_t size() const {
|
|
||||||
return path.size();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
55
tc/src/cosets.cpp
Normal file
55
tc/src/cosets.cpp
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#include <tc/core.hpp>
|
||||||
|
|
||||||
|
namespace tc {
|
||||||
|
Cosets<>::Cosets(size_t rank)
|
||||||
|
: _rank(rank), _order(0), _complete(false), _data() {}
|
||||||
|
|
||||||
|
void Cosets<>::set(size_t coset, size_t gen, size_t target) {
|
||||||
|
set(coset * rank() + gen, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] size_t Cosets<>::get(size_t coset, size_t gen) const {
|
||||||
|
return get(coset * rank() + gen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool Cosets<>::isset(size_t coset, size_t gen) const {
|
||||||
|
return isset(coset * rank() + gen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] size_t Cosets<>::rank() const {
|
||||||
|
return _rank;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] size_t Cosets<>::order() const {
|
||||||
|
return _order;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool Cosets<>::complete() const {
|
||||||
|
return _complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] size_t Cosets<>::size() const {
|
||||||
|
return _data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cosets<>::add_row() {
|
||||||
|
_data.resize(_data.size() + rank(), UNSET);
|
||||||
|
_order++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cosets<>::set(size_t idx, size_t target) {
|
||||||
|
size_t coset = idx / rank();
|
||||||
|
size_t gen = idx % rank();
|
||||||
|
_data[idx] = target;
|
||||||
|
_data[target * rank() + gen] = coset;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] size_t Cosets<>::get(size_t idx) const {
|
||||||
|
return _data[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool Cosets<>::isset(size_t idx) const {
|
||||||
|
return get(idx) != UNSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
42
tc/src/group.cpp
Normal file
42
tc/src/group.cpp
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#include <tc/core.hpp>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace tc {
|
||||||
|
Group<>::Group(size_t rank) : _rank(rank), _mults(_rank * _rank, 2) {
|
||||||
|
for (int idx = 0; idx < rank; ++idx) {
|
||||||
|
set(idx, idx, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Group<>::set(size_t u, size_t v, Mult m) {
|
||||||
|
assert(u < rank());
|
||||||
|
assert(v < rank());
|
||||||
|
|
||||||
|
_mults[u * rank() + v] = m;
|
||||||
|
_mults[v * rank() + u] = m;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Mult Group<>::get(size_t u, size_t v) const {
|
||||||
|
assert(u < rank());
|
||||||
|
assert(v < rank());
|
||||||
|
|
||||||
|
return _mults[u * rank() + v];
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] size_t Group<>::rank() const {
|
||||||
|
return _rank;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Group<> Group<>::sub(std::vector<size_t> const &idxs) const {
|
||||||
|
Group<> res(idxs.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < idxs.size(); ++i) {
|
||||||
|
for (int j = i; j < idxs.size(); ++j) {
|
||||||
|
res.set(i, j, get(idxs[i], idxs[j]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,17 +2,18 @@
|
|||||||
|
|
||||||
#include <fmt/args.h>
|
#include <fmt/args.h>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
namespace tc {
|
namespace tc {
|
||||||
Group schlafli(const std::vector<unsigned int> &mults) {
|
Group<> schlafli(const std::vector<unsigned int> &mults) {
|
||||||
Group res(mults.size() + 1);
|
Group<> res(mults.size() + 1);
|
||||||
for (size_t i = 0; i < mults.size(); ++i) {
|
for (size_t i = 0; i < mults.size(); ++i) {
|
||||||
res.set(Rel{i, i + 1, mults[i]});
|
res.set(i, i + 1, mults[i]);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
Group vcoxeter(const std::string &symbol, const std::vector<unsigned int> &values) {
|
Group<> vcoxeter(const std::string &symbol, const std::vector<unsigned int> &values) {
|
||||||
fmt::dynamic_format_arg_store<fmt::format_context> ds;
|
fmt::dynamic_format_arg_store<fmt::format_context> ds;
|
||||||
|
|
||||||
for (const auto &value: values) {
|
for (const auto &value: values) {
|
||||||
|
|||||||
@@ -3,14 +3,19 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include <tc/util.hpp>
|
#include <tc/core.hpp>
|
||||||
#include <tc/group.hpp>
|
|
||||||
#include <tc/groups.hpp>
|
#include <tc/groups.hpp>
|
||||||
|
|
||||||
#include <peglib.h>
|
#include <peglib.h>
|
||||||
|
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <fmt/ranges.h>
|
#include <fmt/ranges.h>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
struct Graph {
|
||||||
|
size_t rank{};
|
||||||
|
std::vector<tc::Group<>::Rel> edges{};
|
||||||
|
};
|
||||||
|
|
||||||
struct Op {
|
struct Op {
|
||||||
enum Code {
|
enum Code {
|
||||||
@@ -191,6 +196,7 @@ peg::parser build_parser() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
|
||||||
peg::parser build_ast_parser() {
|
peg::parser build_ast_parser() {
|
||||||
peg::parser parser;
|
peg::parser parser;
|
||||||
parser.set_logger([](size_t line, size_t col, const std::string &msg, const std::string &rule) {
|
parser.set_logger([](size_t line, size_t col, const std::string &msg, const std::string &rule) {
|
||||||
@@ -203,6 +209,7 @@ peg::parser build_ast_parser() {
|
|||||||
|
|
||||||
return parser;
|
return parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::vector<Op> compile(const std::string &source) {
|
std::vector<Op> compile(const std::string &source) {
|
||||||
@@ -221,10 +228,10 @@ std::vector<Op> compile(const std::string &source) {
|
|||||||
return cg.ops;
|
return cg.ops;
|
||||||
}
|
}
|
||||||
|
|
||||||
tc::Graph eval(const std::vector<Op> &ops) {
|
Graph eval(const std::vector<Op> &ops) {
|
||||||
std::vector<std::stack<size_t>> stacks(1);
|
std::vector<std::stack<size_t>> stacks(1);
|
||||||
|
|
||||||
tc::Graph g;
|
Graph g;
|
||||||
stacks.back().emplace(g.rank++);
|
stacks.back().emplace(g.rank++);
|
||||||
|
|
||||||
for (const auto &op: ops) {
|
for (const auto &op: ops) {
|
||||||
@@ -280,9 +287,13 @@ tc::Graph eval(const std::vector<Op> &ops) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace tc {
|
namespace tc {
|
||||||
Group coxeter(const std::string &symbol) {
|
Group<> coxeter(const std::string &symbol) {
|
||||||
auto ops = compile(symbol);
|
auto ops = compile(symbol);
|
||||||
auto diagram = eval(ops);
|
auto diagram = eval(ops);
|
||||||
return Group(diagram);
|
Group<> res(diagram.rank);
|
||||||
|
for (const auto &[i, j, m]: diagram.edges) {
|
||||||
|
res.set(i, j, m);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,11 @@
|
|||||||
#include <tc/core.hpp>
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace tc {
|
#include <tc/core.hpp>
|
||||||
SubGroup Group::subgroup(const std::vector<tc::Gen> &gens) const {
|
|
||||||
return {*this, gens};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
namespace tc {
|
||||||
/**
|
/**
|
||||||
* Each coset is associated a row in each table.
|
* Each coset is associated a row in each table.
|
||||||
* Rows document the "loops" formed by
|
* Rows document the "loops" formed by
|
||||||
@@ -24,10 +20,10 @@ namespace tc {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Tables {
|
struct Tables {
|
||||||
std::vector<Rel> rels;
|
std::vector<Group<>::Rel> rels;
|
||||||
std::vector<std::vector<Row>> rows;
|
std::vector<std::vector<Row>> rows;
|
||||||
|
|
||||||
explicit Tables(std::vector<Rel> rels)
|
explicit Tables(std::vector<Group<>::Rel> rels)
|
||||||
: rels(std::move(rels)), rows() {
|
: rels(std::move(rels)), rows() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,46 +36,44 @@ namespace tc {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Cosets solve(
|
[[nodiscard]] Cosets<> Group<>::solve(std::vector<size_t> const &idxs, size_t bound) const {
|
||||||
const Group &group,
|
|
||||||
const std::vector<Gen> &sub_gens,
|
|
||||||
const Coset &bound
|
|
||||||
) {
|
|
||||||
auto rank = group.rank;
|
|
||||||
|
|
||||||
// region Initialize Cosets Table
|
// region Initialize Cosets Table
|
||||||
Cosets cosets(rank);
|
Cosets<> cosets(rank());
|
||||||
cosets.add_row();
|
cosets.add_row();
|
||||||
|
|
||||||
if (rank == 0) {
|
if (rank() == 0) {
|
||||||
cosets.complete = true;
|
cosets._complete = true;
|
||||||
return cosets;
|
return cosets;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Coset g: sub_gens) {
|
for (size_t g: idxs) {
|
||||||
if (g < rank)
|
if (g < rank())
|
||||||
cosets.put(0, g, 0);
|
cosets.set(0, g, 0);
|
||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region Initialize Relation Tables
|
// region Initialize Relation Tables
|
||||||
std::vector<std::tuple<Gen, Gen, Mult>> rels;
|
std::vector<Group<>::Rel> rels;
|
||||||
for (const auto &[i, j, m]: group._orders) {
|
for (int i = 0; i < rank(); ++i) {
|
||||||
|
for (int j = i + 1; j < rank(); ++j) {
|
||||||
// The algorithm only works for Coxeter groups; multiplicities m_ii=1 are assumed. Relation tables
|
// The algorithm only works for Coxeter groups; multiplicities m_ii=1 are assumed. Relation tables
|
||||||
// _may_ be added for them, but they are redundant and hurt performance so are skipped.
|
// _may_ be added for them, but they are redundant and hurt performance so are skipped.
|
||||||
if (i == j) continue;
|
if (i == j) continue;
|
||||||
|
|
||||||
// Coxeter groups admit infinite multiplicities, represented by contexpr tc::FREE. Relation tables
|
// Coxeter groups admit infinite multiplicities, represented by contexpr tc::FREE. Relation tables
|
||||||
// for these should be skipped.
|
// for these should be skipped.
|
||||||
|
auto m = get(i, j);
|
||||||
|
|
||||||
if (m == FREE) {
|
if (m == FREE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
rels.emplace_back(i, j, m);
|
rels.emplace_back(i, j, m);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Tables rel_tables(rels);
|
Tables rel_tables(rels);
|
||||||
std::vector<std::vector<size_t>> tables_for(rank);
|
std::vector<std::vector<size_t>> tables_for(rank());
|
||||||
int rel_idx = 0;
|
int rel_idx = 0;
|
||||||
for (const auto &[i, j, m]: rels) {
|
for (const auto &[i, j, m]: rels) {
|
||||||
tables_for[i].push_back(rel_idx);
|
tables_for[i].push_back(rel_idx);
|
||||||
@@ -87,7 +81,7 @@ namespace tc {
|
|||||||
rel_idx++;
|
rel_idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Coset> lst_vals;
|
std::vector<size_t> lst_vals;
|
||||||
rel_tables.add_row();
|
rel_tables.add_row();
|
||||||
for (int table_idx = 0; table_idx < rel_tables.size(); ++table_idx) {
|
for (int table_idx = 0; table_idx < rel_tables.size(); ++table_idx) {
|
||||||
const auto &[i, j, m] = rel_tables.rels[table_idx];
|
const auto &[i, j, m] = rel_tables.rels[table_idx];
|
||||||
@@ -108,26 +102,26 @@ namespace tc {
|
|||||||
|
|
||||||
size_t idx = 0;
|
size_t idx = 0;
|
||||||
size_t fact_idx;
|
size_t fact_idx;
|
||||||
Coset coset, gen, target, lst;
|
size_t coset, gen, target, lst;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// find next unknown product
|
// find next unknown product
|
||||||
while (idx < cosets.data.size() and cosets.isset(idx))
|
while (idx < cosets.size() and cosets.isset(idx))
|
||||||
idx++;
|
idx++;
|
||||||
|
|
||||||
if (cosets.size() >= bound) {
|
if (cosets.order() >= bound) {
|
||||||
return cosets;
|
return cosets;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there are none, then return
|
// if there are none, then return
|
||||||
if (idx == cosets.data.size()) {
|
if (idx == cosets.size()) {
|
||||||
// todo unrolled linked list interval
|
// todo unrolled linked list interval
|
||||||
// rel_tables.del_rows_to(idx / ngens);
|
// rel_tables.del_rows_to(idx / ngens);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the unknown product must be a new coset, so add it
|
// the unknown product must be a new coset, so add it
|
||||||
target = cosets.size();
|
target = cosets.order();
|
||||||
cosets.add_row();
|
cosets.add_row();
|
||||||
rel_tables.add_row();
|
rel_tables.add_row();
|
||||||
|
|
||||||
@@ -136,8 +130,6 @@ namespace tc {
|
|||||||
facts.push(idx); // new product should be recorded and propagated
|
facts.push(idx); // new product should be recorded and propagated
|
||||||
|
|
||||||
// todo unrolled linked list interval
|
// todo unrolled linked list interval
|
||||||
// coset = idx / ngens;
|
|
||||||
// gen = idx % ngens;
|
|
||||||
// rel_tables.del_rows_to(coset);
|
// rel_tables.del_rows_to(coset);
|
||||||
|
|
||||||
// find all products which also lead to target
|
// find all products which also lead to target
|
||||||
@@ -148,10 +140,10 @@ namespace tc {
|
|||||||
// skip if this product was already learned
|
// skip if this product was already learned
|
||||||
if (cosets.get(fact_idx) != -1) continue;
|
if (cosets.get(fact_idx) != -1) continue;
|
||||||
|
|
||||||
cosets.put(fact_idx, target);
|
cosets.set(fact_idx, target);
|
||||||
|
|
||||||
coset = fact_idx / rank;
|
coset = fact_idx / rank();
|
||||||
gen = fact_idx % rank;
|
gen = fact_idx % rank();
|
||||||
|
|
||||||
// If the product stays within the coset todo
|
// If the product stays within the coset todo
|
||||||
for (size_t table_idx: tables_for[gen]) {
|
for (size_t table_idx: tables_for[gen]) {
|
||||||
@@ -159,7 +151,7 @@ namespace tc {
|
|||||||
auto &trow = rel_tables.rows[target][table_idx];
|
auto &trow = rel_tables.rows[target][table_idx];
|
||||||
auto &crow = rel_tables.rows[coset][table_idx];
|
auto &crow = rel_tables.rows[coset][table_idx];
|
||||||
|
|
||||||
Coset other_gen = (i == gen) ? j : i;
|
size_t other_gen = (i == gen) ? j : i;
|
||||||
|
|
||||||
// Test if loop is closed
|
// Test if loop is closed
|
||||||
if (trow.free) {
|
if (trow.free) {
|
||||||
@@ -174,7 +166,7 @@ namespace tc {
|
|||||||
if (trow.gnr == m) {
|
if (trow.gnr == m) {
|
||||||
// loop is closed, but idempotent, so the target links to itself via the other generator.
|
// loop is closed, but idempotent, so the target links to itself via the other generator.
|
||||||
// todo might be able to move this logic up into the (target == coset) block and avoid those computations.
|
// todo might be able to move this logic up into the (target == coset) block and avoid those computations.
|
||||||
facts.push(target * rank + other_gen);
|
facts.push(target * rank() + other_gen);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (trow.gnr == m - 1) {
|
if (trow.gnr == m - 1) {
|
||||||
@@ -184,7 +176,7 @@ namespace tc {
|
|||||||
// loop is closed. We know the last element in the loop must link with this one.
|
// loop is closed. We know the last element in the loop must link with this one.
|
||||||
lst = lst_vals[trow.lst_idx];
|
lst = lst_vals[trow.lst_idx];
|
||||||
// delete trow.lst_ptr;
|
// delete trow.lst_ptr;
|
||||||
facts.push(lst * rank + other_gen);
|
facts.push(lst * rank() + other_gen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -213,7 +205,7 @@ namespace tc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cosets.complete = true;
|
cosets._complete = true;
|
||||||
return cosets;
|
return cosets;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
include(GoogleTest)
|
include(GoogleTest)
|
||||||
|
|
||||||
add_executable(test_pair_map test_pair_map.cpp)
|
|
||||||
target_link_libraries(test_pair_map tc GTest::gtest_main)
|
|
||||||
|
|
||||||
add_executable(test_solve test_solve.cpp)
|
add_executable(test_solve test_solve.cpp)
|
||||||
target_link_libraries(test_solve tc GTest::gtest_main)
|
target_link_libraries(test_solve tc GTest::gtest_main)
|
||||||
|
|
||||||
@@ -17,6 +14,5 @@ target_compile_definitions(
|
|||||||
MIN_COS_PER_SEC=$<IF:$<CONFIG:Debug>,${MIN_DEBUG_CPS},${MIN_RELEASE_CPS}>
|
MIN_COS_PER_SEC=$<IF:$<CONFIG:Debug>,${MIN_DEBUG_CPS},${MIN_RELEASE_CPS}>
|
||||||
)
|
)
|
||||||
|
|
||||||
gtest_discover_tests(test_pair_map)
|
|
||||||
gtest_discover_tests(test_solve)
|
gtest_discover_tests(test_solve)
|
||||||
gtest_discover_tests(test_lang)
|
gtest_discover_tests(test_lang)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include <tc/group.hpp>
|
#include <tc/core.hpp>
|
||||||
#include <tc/groups.hpp>
|
#include <tc/groups.hpp>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
@@ -20,24 +20,33 @@
|
|||||||
TEST(coxeter, simple) {
|
TEST(coxeter, simple) {
|
||||||
auto g = tc::coxeter("5 3 3");
|
auto g = tc::coxeter("5 3 3");
|
||||||
|
|
||||||
ASSERT_EQ(g.rank, 4);
|
ASSERT_EQ(g.rank(), 4);
|
||||||
|
|
||||||
|
EXPECT_EQ(g.get(0, 0), 1);
|
||||||
EXPECT_EQ(g.get(0, 1), 5);
|
EXPECT_EQ(g.get(0, 1), 5);
|
||||||
EXPECT_EQ(g.get(1, 2), 3);
|
|
||||||
EXPECT_EQ(g.get(3, 4), 3);
|
|
||||||
|
|
||||||
EXPECT_EQ(g.get(0, 2), 2);
|
EXPECT_EQ(g.get(0, 2), 2);
|
||||||
EXPECT_EQ(g.get(0, 3), 2);
|
EXPECT_EQ(g.get(0, 3), 2);
|
||||||
EXPECT_EQ(g.get(0, 4), 2);
|
|
||||||
|
EXPECT_EQ(g.get(1, 0), 5);
|
||||||
|
EXPECT_EQ(g.get(1, 1), 1);
|
||||||
|
EXPECT_EQ(g.get(1, 2), 3);
|
||||||
EXPECT_EQ(g.get(1, 3), 2);
|
EXPECT_EQ(g.get(1, 3), 2);
|
||||||
EXPECT_EQ(g.get(1, 4), 2);
|
|
||||||
EXPECT_EQ(g.get(2, 4), 2);
|
EXPECT_EQ(g.get(2, 0), 2);
|
||||||
|
EXPECT_EQ(g.get(2, 1), 3);
|
||||||
|
EXPECT_EQ(g.get(2, 2), 1);
|
||||||
|
EXPECT_EQ(g.get(2, 3), 3);
|
||||||
|
|
||||||
|
EXPECT_EQ(g.get(3, 0), 2);
|
||||||
|
EXPECT_EQ(g.get(3, 1), 2);
|
||||||
|
EXPECT_EQ(g.get(3, 2), 3);
|
||||||
|
EXPECT_EQ(g.get(3, 3), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(coxeter, looping) {
|
TEST(coxeter, looping) {
|
||||||
auto g = tc::coxeter("{5 3 4}");
|
auto g = tc::coxeter("{5 3 4}");
|
||||||
|
|
||||||
ASSERT_EQ(g.rank, 3);
|
ASSERT_EQ(g.rank(), 3);
|
||||||
|
|
||||||
EXPECT_EQ(g.get(0, 1), 5);
|
EXPECT_EQ(g.get(0, 1), 5);
|
||||||
EXPECT_EQ(g.get(1, 2), 3);
|
EXPECT_EQ(g.get(1, 2), 3);
|
||||||
|
|||||||
@@ -1,127 +0,0 @@
|
|||||||
#include <functional>
|
|
||||||
#include <iostream>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
#include <tc/pair_map.hpp>
|
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
|
|
||||||
/// helper for comparing against two options
|
|
||||||
template<typename T, typename U, typename V>
|
|
||||||
testing::AssertionResult AssertEqEither(
|
|
||||||
const char *val_expr,
|
|
||||||
const char *o1_expr,
|
|
||||||
const char *o2_expr,
|
|
||||||
T val, U o1, V o2
|
|
||||||
) {
|
|
||||||
if ((val == o1) || (val == o2)) {
|
|
||||||
return testing::AssertionSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
return testing::AssertionFailure()
|
|
||||||
<< val_expr << " (" << val << ") " << "does not equal " << o1_expr
|
|
||||||
<< " (" << o1 << ") " << "or " << o2_expr << " (" << o2 << ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
#define EXPECT_EQ_EITHER(val, o1, o2) EXPECT_PRED_FORMAT3(AssertEqEither, val, o1, o2)
|
|
||||||
|
|
||||||
|
|
||||||
/// Naive symmetric pair hash
|
|
||||||
size_t key(size_t i, size_t j) {
|
|
||||||
return ((i + j) << 12) ^ i ^ j;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// factory to build a simple pair_map
|
|
||||||
tc::pair_map<size_t> populate(size_t size) {
|
|
||||||
tc::pair_map<size_t> pm(6);
|
|
||||||
|
|
||||||
for (int i = 0; i < pm.size(); ++i) {
|
|
||||||
for (int j = i; j < pm.size(); ++j) {
|
|
||||||
pm(i, j) = key(i, j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pm;
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(pair_map, fill) {
|
|
||||||
tc::pair_map<size_t> pm(6, 42);
|
|
||||||
|
|
||||||
for (int i = 0; i < pm.size(); ++i) {
|
|
||||||
for (int j = i; j < pm.size(); ++j) {
|
|
||||||
EXPECT_EQ(pm(i, j), 42);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(pair_map, symmetry) {
|
|
||||||
auto pm = populate(6);
|
|
||||||
|
|
||||||
for (int i = 0; i < pm.size(); ++i) {
|
|
||||||
for (int j = i; j < pm.size(); ++j) {
|
|
||||||
EXPECT_EQ(pm(i, j), key(i, j));
|
|
||||||
EXPECT_EQ(pm(j, i), pm(i, j));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(pair_map, copy) {
|
|
||||||
auto pm = populate(6);
|
|
||||||
auto pm_ = pm;
|
|
||||||
|
|
||||||
ASSERT_EQ(pm_.size(), 6);
|
|
||||||
|
|
||||||
for (int i = 0; i < pm_.size(); ++i) {
|
|
||||||
for (int j = i; j < pm_.size(); ++j) {
|
|
||||||
EXPECT_EQ(pm_(i, j), pm(i, j));
|
|
||||||
EXPECT_EQ(pm_(i, j), key(i, j));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(pair_map, move) {
|
|
||||||
auto pm = populate(6);
|
|
||||||
auto pm_ = std::move(pm);
|
|
||||||
|
|
||||||
ASSERT_EQ(pm_.size(), 6);
|
|
||||||
|
|
||||||
for (int i = 0; i < pm_.size(); ++i) {
|
|
||||||
for (int j = i; j < pm_.size(); ++j) {
|
|
||||||
EXPECT_EQ(pm_(i, j), key(i, j));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(pair_map, iterate) {
|
|
||||||
auto pm = populate(6);
|
|
||||||
|
|
||||||
size_t count = 0;
|
|
||||||
for (const auto &[i, j, m]: pm) {
|
|
||||||
EXPECT_EQ(m, key(i, j));
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
EXPECT_EQ(count, 21);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(pair_map, iterate_ref) {
|
|
||||||
auto pm = populate(6);
|
|
||||||
|
|
||||||
for (const auto &[i, j, m]: pm) {
|
|
||||||
m = 42;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &[i, j, m]: pm) {
|
|
||||||
EXPECT_EQ(m, 42);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(pair_map, view) {
|
|
||||||
auto pm = populate(6);
|
|
||||||
|
|
||||||
size_t count = 0;
|
|
||||||
for (const auto &[i, j, m]: pm.of(4)) {
|
|
||||||
EXPECT_EQ_EITHER(4, i, j);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
EXPECT_EQ(count, pm.size());
|
|
||||||
}
|
|
||||||
@@ -11,15 +11,15 @@ testing::AssertionResult AssertSolveOrder(
|
|||||||
const char *group_expr,
|
const char *group_expr,
|
||||||
const char *sub_gens_expr,
|
const char *sub_gens_expr,
|
||||||
const char *expected_order_expr,
|
const char *expected_order_expr,
|
||||||
const tc::Group &group,
|
const tc::Group<> &group,
|
||||||
const std::vector<tc::Gen> &sub_gens,
|
const std::vector<size_t> &sub_gens,
|
||||||
tc::Coset expected_order
|
size_t expected_order
|
||||||
) {
|
) {
|
||||||
auto start = std::clock();
|
auto start = std::clock();
|
||||||
auto cosets = tc::solve(group, sub_gens);
|
auto cosets = group.solve(sub_gens);
|
||||||
auto end = std::clock();
|
auto end = std::clock();
|
||||||
|
|
||||||
tc::Coset actual_order = cosets.size();
|
size_t actual_order = cosets.order();
|
||||||
|
|
||||||
auto total_sec = (double) (end - start) / CLOCKS_PER_SEC;
|
auto total_sec = (double) (end - start) / CLOCKS_PER_SEC;
|
||||||
auto cosets_per_sec = (double) actual_order / total_sec;
|
auto cosets_per_sec = (double) actual_order / total_sec;
|
||||||
@@ -48,45 +48,45 @@ testing::AssertionResult AssertSolveOrder(
|
|||||||
|
|
||||||
#define EXPECT_SOLVE_ORDER(group, sub_gens, expected_order) EXPECT_PRED_FORMAT3(AssertSolveOrder, group, sub_gens, expected_order);
|
#define EXPECT_SOLVE_ORDER(group, sub_gens, expected_order) EXPECT_PRED_FORMAT3(AssertSolveOrder, group, sub_gens, expected_order);
|
||||||
|
|
||||||
using v = std::vector<tc::Gen>;
|
using v = std::vector<size_t>;
|
||||||
|
|
||||||
tc::Group A(unsigned int n) {
|
tc::Group<> A(unsigned int n) {
|
||||||
return tc::vcoxeter("3 * {}", {n - 1});
|
return tc::vcoxeter("3 * {}", {n - 1});
|
||||||
}
|
}
|
||||||
|
|
||||||
tc::Group B(unsigned int n) {
|
tc::Group<> B(unsigned int n) {
|
||||||
return tc::vcoxeter("4 3 * {}", {n - 2});
|
return tc::vcoxeter("4 3 * {}", {n - 2});
|
||||||
}
|
}
|
||||||
|
|
||||||
tc::Group D(unsigned int n) {
|
tc::Group<> D(unsigned int n) {
|
||||||
return tc::vcoxeter("3 * [1 1 {}]", {n - 3});
|
return tc::vcoxeter("3 * [1 1 {}]", {n - 3});
|
||||||
}
|
}
|
||||||
|
|
||||||
tc::Group E(unsigned int n) {
|
tc::Group<> E(unsigned int n) {
|
||||||
return tc::vcoxeter("3 * [1 2 {}]", {n - 4});
|
return tc::vcoxeter("3 * [1 2 {}]", {n - 4});
|
||||||
}
|
}
|
||||||
|
|
||||||
tc::Group F4() {
|
tc::Group<> F4() {
|
||||||
return tc::coxeter("3 4 3");
|
return tc::coxeter("3 4 3");
|
||||||
}
|
}
|
||||||
|
|
||||||
tc::Group G2() {
|
tc::Group<> G2() {
|
||||||
return tc::coxeter("6");
|
return tc::coxeter("6");
|
||||||
}
|
}
|
||||||
|
|
||||||
tc::Group H(unsigned int n) {
|
tc::Group<> H(unsigned int n) {
|
||||||
return tc::vcoxeter("5 3 * {}", {n - 2});
|
return tc::vcoxeter("5 3 * {}", {n - 2});
|
||||||
}
|
}
|
||||||
|
|
||||||
tc::Group I2(unsigned int n) {
|
tc::Group<> I2(unsigned int n) {
|
||||||
return tc::vcoxeter("{}", {n});
|
return tc::vcoxeter("{}", {n});
|
||||||
}
|
}
|
||||||
|
|
||||||
tc::Group T(unsigned int m, unsigned int n) {
|
tc::Group<> T(unsigned int m, unsigned int n) {
|
||||||
return tc::vcoxeter("{} 2 {}", {m, n});
|
return tc::vcoxeter("{} 2 {}", {m, n});
|
||||||
}
|
}
|
||||||
|
|
||||||
tc::Group T(unsigned int n) {
|
tc::Group<> T(unsigned int n) {
|
||||||
return T(n, n);
|
return T(n, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
add_custom_target(resources DEPENDS resources_output)
|
add_subdirectory(shaders)
|
||||||
add_custom_command(
|
|
||||||
OUTPUT resources_output
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/res ${CMAKE_CURRENT_BINARY_DIR}/res
|
|
||||||
COMMENT "Copying Resources")
|
|
||||||
|
|
||||||
add_executable(vis
|
add_executable(vis
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
@@ -15,6 +11,6 @@ target_link_libraries(vis
|
|||||||
imgui
|
imgui
|
||||||
eigen
|
eigen
|
||||||
nlohmann_json
|
nlohmann_json
|
||||||
|
shaders
|
||||||
)
|
)
|
||||||
target_include_directories(vis PUBLIC include)
|
target_include_directories(vis PUBLIC include)
|
||||||
add_dependencies(vis resources)
|
|
||||||
|
|||||||
@@ -23,6 +23,17 @@ public:
|
|||||||
// todo throw if compile failed
|
// todo throw if compile failed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
explicit Shader(const std::string_view &src) {
|
||||||
|
id = glCreateShader(mode);
|
||||||
|
|
||||||
|
const char *str = src.data();
|
||||||
|
const GLint length = (GLint) src.length();
|
||||||
|
glShaderSource(id, 1, &str, &length);
|
||||||
|
glCompileShader(id);
|
||||||
|
|
||||||
|
// todo throw if compile failed
|
||||||
|
}
|
||||||
|
|
||||||
explicit Shader(std::ifstream source)
|
explicit Shader(std::ifstream source)
|
||||||
: Shader(std::string(
|
: Shader(std::string(
|
||||||
std::istreambuf_iterator<char>(source),
|
std::istreambuf_iterator<char>(source),
|
||||||
|
|||||||
4
vis/shaders/CMakeLists.txt
Normal file
4
vis/shaders/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
add_embed_library(shaders
|
||||||
|
main-4d.vert.glsl
|
||||||
|
main.vert.glsl
|
||||||
|
main.frag.glsl)
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
#include <tc/core.hpp>
|
#include <tc/core.hpp>
|
||||||
|
|
||||||
#include <geo/mirror.hpp>
|
#include <geo/mirror.hpp>
|
||||||
#include <geo/solver.hpp>
|
|
||||||
|
|
||||||
#include "render/pointrender.hpp"
|
#include "render/pointrender.hpp"
|
||||||
|
|
||||||
@@ -138,7 +137,12 @@ int run(GLFWwindow *window, ImGuiContext *context) {
|
|||||||
|
|
||||||
auto points = cosets.path.walk<vec4, vec4>(start, mirrors, reflect<vec4>);
|
auto points = cosets.path.walk<vec4, vec4>(start, mirrors, reflect<vec4>);
|
||||||
|
|
||||||
std::vector<Prims<2>> edges = hull<2>(group, std::vector<std::vector<tc::Gen>>{{0}, {1}, {2}, {3}}, {});
|
std::vector<unsigned> edges = {
|
||||||
|
0, 1,
|
||||||
|
0, 2,
|
||||||
|
0, 3,
|
||||||
|
0, 4,
|
||||||
|
};
|
||||||
|
|
||||||
pc.upload(points);
|
pc.upload(points);
|
||||||
lc.upload(points, edges);
|
lc.upload(points, edges);
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <shaders.hpp>
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
Eigen::Vector4f bg{0.16, 0.16, 0.16, 1.00};
|
Eigen::Vector4f bg{0.16, 0.16, 0.16, 1.00};
|
||||||
Eigen::Vector4f fg{0.71, 0.53, 0.94, 1.00};
|
Eigen::Vector4f fg{0.71, 0.53, 0.94, 1.00};
|
||||||
@@ -39,8 +41,8 @@ template<typename V_=Eigen::Vector4f>
|
|||||||
struct PointRenderer {
|
struct PointRenderer {
|
||||||
using Vertex = V_;
|
using Vertex = V_;
|
||||||
|
|
||||||
VertexShader vs{std::ifstream("res/shaders/main.vert.glsl")};
|
VertexShader vs{shaders::main_vert_glsl};
|
||||||
FragmentShader fs{std::ifstream("res/shaders/main.frag.glsl")};
|
FragmentShader fs{shaders::main_frag_glsl};
|
||||||
|
|
||||||
Program pgm{vs, fs};
|
Program pgm{vs, fs};
|
||||||
|
|
||||||
@@ -61,8 +63,8 @@ template<typename V_=Eigen::Vector4f>
|
|||||||
struct LineCloud {
|
struct LineCloud {
|
||||||
using Vertex = V_;
|
using Vertex = V_;
|
||||||
|
|
||||||
Buffer<Vertex> vbo;
|
Buffer<Vertex> vbo{};
|
||||||
Buffer<Prims<2>> ibo;
|
Buffer<unsigned> ibo{};
|
||||||
VertexArray<Vertex> vao{vbo};
|
VertexArray<Vertex> vao{vbo};
|
||||||
|
|
||||||
GLuint count{};
|
GLuint count{};
|
||||||
@@ -75,7 +77,6 @@ struct LineCloud {
|
|||||||
void upload(const T &points, const U &inds) {
|
void upload(const T &points, const U &inds) {
|
||||||
vbo.upload(points);
|
vbo.upload(points);
|
||||||
|
|
||||||
Eigen::MatrixXi x;
|
|
||||||
count = ibo.upload(inds);
|
count = ibo.upload(inds);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user