mirror of
https://github.com/allemangD/toddcox-visualize.git
synced 2025-11-10 03:52:48 -05:00
modified coxeter notation parsing
This commit is contained in:
@@ -12,6 +12,7 @@ include(External/glfw.cmake)
|
|||||||
include(External/gtest.cmake)
|
include(External/gtest.cmake)
|
||||||
include(External/imgui.cmake)
|
include(External/imgui.cmake)
|
||||||
include(External/json.cmake)
|
include(External/json.cmake)
|
||||||
|
include(External/peglib.cmake)
|
||||||
|
|
||||||
include_directories(include)
|
include_directories(include)
|
||||||
|
|
||||||
|
|||||||
16
External/peglib.cmake
vendored
Normal file
16
External/peglib.cmake
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
FetchContent_Declare(
|
||||||
|
peglib
|
||||||
|
GIT_REPOSITORY https://github.com/yhirose/cpp-peglib
|
||||||
|
GIT_TAG v1.8.2
|
||||||
|
GIT_PROGRESS TRUE
|
||||||
|
)
|
||||||
|
set(PEGLIB_BUILD_TESTS OFF CACHE INTERNAL "")
|
||||||
|
FetchContent_GetProperties(peglib)
|
||||||
|
if(NOT ${peglib}_POPULATED)
|
||||||
|
FetchContent_Populate(peglib)
|
||||||
|
find_package(Threads)
|
||||||
|
add_library(peglib INTERFACE ${peglib_SOURCE_DIR}/peglib.h)
|
||||||
|
target_include_directories(peglib INTERFACE ${peglib_SOURCE_DIR})
|
||||||
|
target_link_libraries(peglib INTERFACE Threads::Threads)
|
||||||
|
add_library(peglib::peglib ALIAS peglib)
|
||||||
|
endif()
|
||||||
@@ -1,14 +1,25 @@
|
|||||||
add_library(tc
|
add_library(tc
|
||||||
include/tc/pair_map.hpp
|
|
||||||
include/tc/core.hpp
|
include/tc/core.hpp
|
||||||
include/tc/cosets.hpp
|
include/tc/cosets.hpp
|
||||||
include/tc/group.hpp
|
include/tc/group.hpp
|
||||||
include/tc/groups.hpp
|
include/tc/groups.hpp
|
||||||
|
include/tc/lang.hpp
|
||||||
|
include/tc/pair_map.hpp
|
||||||
include/tc/util.hpp
|
include/tc/util.hpp
|
||||||
src/core.cpp
|
src/core.cpp
|
||||||
src/groups.cpp)
|
src/groups.cpp
|
||||||
|
src/lang.cpp
|
||||||
|
)
|
||||||
|
target_link_libraries(tc PUBLIC peglib::peglib fmt::fmt)
|
||||||
target_include_directories(tc PUBLIC include)
|
target_include_directories(tc PUBLIC include)
|
||||||
|
|
||||||
|
add_library(tc::tc ALIAS tc)
|
||||||
|
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
add_subdirectory(bench)
|
add_subdirectory(bench)
|
||||||
|
|
||||||
|
add_executable(langtest src/langtest.cpp)
|
||||||
|
target_link_libraries(langtest PUBLIC tc::tc)
|
||||||
|
|
||||||
|
add_executable(pegtest src/pegtest.cpp)
|
||||||
|
target_link_libraries(pegtest PUBLIC peglib::peglib fmt::fmt)
|
||||||
|
|||||||
@@ -8,14 +8,14 @@
|
|||||||
#include <tc/core.hpp>
|
#include <tc/core.hpp>
|
||||||
#include <tc/groups.hpp>
|
#include <tc/groups.hpp>
|
||||||
|
|
||||||
#define NAMED(x) #x, x
|
|
||||||
|
|
||||||
void bench(
|
void bench(
|
||||||
std::string group_expr,
|
const std::string &group_expr,
|
||||||
const tc::Group &group,
|
const std::string &symbol,
|
||||||
const std::vector<tc::Gen> &gens,
|
const std::vector<tc::Gen> &gens,
|
||||||
const tc::Coset bound = tc::UNBOUNDED
|
const tc::Coset bound = tc::UNBOUNDED
|
||||||
) {
|
) {
|
||||||
|
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 = tc::solve(group, gens, bound);
|
||||||
std::clock_t e = std::clock();
|
std::clock_t e = std::clock();
|
||||||
@@ -43,29 +43,27 @@ tc::Group sch(T ...arg) {
|
|||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
std::vector<std::string> args(argv + 1, argv + argc);
|
std::vector<std::string> args(argv + 1, argv + argc);
|
||||||
|
|
||||||
using namespace tc::group;
|
|
||||||
|
|
||||||
fmt::print("{:>24},{:>10},{:>6},{:>9},{:>10}\n", "NAME", "ORDER", "COMPL", "TIME", "COS/S");
|
fmt::print("{:>24},{:>10},{:>6},{:>9},{:>10}\n", "NAME", "ORDER", "COMPL", "TIME", "COS/S");
|
||||||
|
|
||||||
bench(NAMED(H(2)), {});
|
bench("H2", "5", {});
|
||||||
bench(NAMED(H(3)), {});
|
bench("H3", "5 3", {});
|
||||||
bench(NAMED(H(4)), {});
|
bench("H4", "5 3 3", {});
|
||||||
|
|
||||||
bench(NAMED(T(100)), {});
|
bench("T100", "100 2 100", {});
|
||||||
bench(NAMED(T(500)), {});
|
bench("T500", "500 2 500", {});
|
||||||
bench(NAMED(T(1000)), {});
|
bench("T1000", "1000 2 1000", {});
|
||||||
|
|
||||||
bench(NAMED(E(6)), {});
|
bench("E6", "3 * [2 2 1]", {});
|
||||||
bench(NAMED(E(7)), {});
|
bench("E7", "3 * [3 2 1]", {});
|
||||||
|
// bench("E8", "3 * [4 2 1]", {}); // too big
|
||||||
|
|
||||||
bench(NAMED(B(6)), {});
|
bench("B6", "4 3 * 4", {});
|
||||||
bench(NAMED(B(7)), {});
|
bench("B7", "4 3 * 5", {});
|
||||||
bench(NAMED(B(8)), {});
|
bench("B8", "4 3 * 6", {});
|
||||||
|
|
||||||
auto g = tc::group::A(4);
|
bench("~A3", "{3 * 4}", {}, 5000000);
|
||||||
g.set(tc::Rel{0, 3, 3});
|
bench("~A4", "{3 * 5}", {}, 5000000);
|
||||||
bench("~A(3)", g, {}, 4385964);
|
bench("~I1", "{- * 5}", {}, 5000000);
|
||||||
bench("~I(1)", sch(tc::FREE), {}, 4385964);
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,5 @@
|
|||||||
#include "group.hpp"
|
#include "group.hpp"
|
||||||
|
|
||||||
namespace tc {
|
namespace tc {
|
||||||
constexpr Coset UNBOUNDED = (Coset) (-1);
|
|
||||||
|
|
||||||
Cosets solve(const Group &group, const std::vector<Gen> &sub_gens, const Coset &bound = UNBOUNDED);
|
Cosets solve(const Group &group, const std::vector<Gen> &sub_gens, const Coset &bound = UNBOUNDED);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,17 +2,9 @@
|
|||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
#include "cosets.hpp"
|
#include "util.hpp"
|
||||||
|
|
||||||
namespace tc {
|
namespace tc {
|
||||||
using Coset = uint32_t;
|
|
||||||
using Gen = uint8_t;
|
|
||||||
using Mult = uint16_t;
|
|
||||||
constexpr Mult FREE = Mult(-1);
|
|
||||||
constexpr Coset UNSET = Coset(-1);
|
|
||||||
|
|
||||||
using Rel = std::tuple<Gen, Gen, Mult>;
|
|
||||||
|
|
||||||
struct Cosets {
|
struct Cosets {
|
||||||
Gen ngens;
|
Gen ngens;
|
||||||
std::vector<int> data;
|
std::vector<int> data;
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <tc/util.hpp>
|
||||||
#include <tc/pair_map.hpp>
|
#include <tc/pair_map.hpp>
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
namespace tc {
|
namespace tc {
|
||||||
struct Group;
|
struct Group;
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core.hpp"
|
#include <vector>
|
||||||
|
|
||||||
|
#include <tc/group.hpp>
|
||||||
|
|
||||||
namespace tc {
|
namespace tc {
|
||||||
/**
|
/**
|
||||||
@@ -10,55 +11,13 @@ namespace tc {
|
|||||||
*/
|
*/
|
||||||
Group schlafli(const std::vector<int> &mults);
|
Group schlafli(const std::vector<int> &mults);
|
||||||
|
|
||||||
namespace group {
|
Group coxeter(const std::string &symbol);
|
||||||
/**
|
|
||||||
* Simplex
|
|
||||||
*/
|
|
||||||
Group A(int dim);
|
|
||||||
|
|
||||||
/**
|
Group vcoxeter(const std::string &symbol, std::vector<int> &values);
|
||||||
* Cube, Orthoplex
|
|
||||||
*/
|
|
||||||
Group B(int dim);
|
|
||||||
|
|
||||||
/**
|
template<typename ...Args>
|
||||||
* Demicube, Orthoplex
|
Group coxeter(const std::string &symbol, const Args &... args) {
|
||||||
*/
|
std::vector<int> values = {{args...}};
|
||||||
Group D(int dim);
|
return vcoxeter(symbol, values);
|
||||||
|
|
||||||
/**
|
|
||||||
* E groups
|
|
||||||
*/
|
|
||||||
Group E(int dim);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 24 Cell
|
|
||||||
*/
|
|
||||||
Group F4();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hexagon
|
|
||||||
*/
|
|
||||||
Group G2();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Icosahedron
|
|
||||||
*/
|
|
||||||
Group H(int dim);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Polygonal
|
|
||||||
*/
|
|
||||||
Group I2(int n);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toroidal. I2(n) * I2(m)
|
|
||||||
*/
|
|
||||||
Group T(int n, int m);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toroidal. T(n, n)
|
|
||||||
*/
|
|
||||||
Group T(int n);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,17 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
namespace tc {
|
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 {
|
struct Action {
|
||||||
int from_idx = -1;
|
int from_idx = -1;
|
||||||
int gen = -1;
|
int gen = -1;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <cassert>
|
#include <tc/groups.hpp>
|
||||||
|
|
||||||
#include "tc/groups.hpp"
|
#include <fmt/args.h>
|
||||||
|
#include <fmt/core.h>
|
||||||
|
|
||||||
namespace tc {
|
namespace tc {
|
||||||
Group schlafli(const std::vector<int> &mults) {
|
Group schlafli(const std::vector<int> &mults) {
|
||||||
@@ -11,74 +12,13 @@ namespace tc {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace group {
|
Group v_coxeter(const std::string &symbol, std::vector<int> &values) {
|
||||||
Group A(const int dim) {
|
fmt::dynamic_format_arg_store<fmt::format_context> ds;
|
||||||
assert(dim >= 1);
|
|
||||||
|
for (const auto &value: values) {
|
||||||
return schlafli(std::vector<int>(dim - 1, 3));
|
ds.push_back(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Group B(const int dim) {
|
return coxeter(fmt::vformat(symbol, ds));
|
||||||
assert(dim >= 2);
|
|
||||||
|
|
||||||
std::vector<int> mults(dim - 1, 3);
|
|
||||||
mults[0] = 4;
|
|
||||||
|
|
||||||
return schlafli(mults);
|
|
||||||
}
|
|
||||||
|
|
||||||
Group D(const int dim) {
|
|
||||||
assert(dim >= 4);
|
|
||||||
|
|
||||||
std::vector<int> mults(dim - 1, 3);
|
|
||||||
mults[dim - 2] = 2;
|
|
||||||
|
|
||||||
Group g = schlafli(mults);
|
|
||||||
g.set(Rel{1, dim - 1, 3});
|
|
||||||
|
|
||||||
return g;
|
|
||||||
}
|
|
||||||
|
|
||||||
Group E(const int dim) {
|
|
||||||
assert(dim >= 6);
|
|
||||||
|
|
||||||
std::vector<int> mults(dim - 1, 3);
|
|
||||||
mults[dim - 2] = 2;
|
|
||||||
|
|
||||||
Group g = schlafli(mults);
|
|
||||||
g.set(Rel{2, dim - 1, 3});
|
|
||||||
|
|
||||||
return g;
|
|
||||||
}
|
|
||||||
|
|
||||||
Group F4() {
|
|
||||||
return schlafli({3, 4, 3});
|
|
||||||
}
|
|
||||||
|
|
||||||
Group G2() {
|
|
||||||
return schlafli({6});
|
|
||||||
}
|
|
||||||
|
|
||||||
Group H(const int dim) {
|
|
||||||
assert(dim >= 2);
|
|
||||||
assert(dim <= 4);
|
|
||||||
|
|
||||||
std::vector<int> mults(dim - 1, 3);
|
|
||||||
mults[0] = 5;
|
|
||||||
|
|
||||||
return schlafli(mults);
|
|
||||||
}
|
|
||||||
|
|
||||||
Group I2(const int n) {
|
|
||||||
return schlafli({n});
|
|
||||||
}
|
|
||||||
|
|
||||||
Group T(const int n, const int m) {
|
|
||||||
return schlafli({n, 2, m});
|
|
||||||
}
|
|
||||||
|
|
||||||
Group T(const int n) {
|
|
||||||
return T(n, n);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
#include <tc/pair_map.hpp>
|
|
||||||
289
tc/src/lang.cpp
Normal file
289
tc/src/lang.cpp
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
#include <vector>
|
||||||
|
#include <stack>
|
||||||
|
#include <string>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include <tc/group.hpp>
|
||||||
|
#include <tc/groups.hpp>
|
||||||
|
|
||||||
|
#include <peglib.h>
|
||||||
|
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#include <fmt/ranges.h>
|
||||||
|
|
||||||
|
struct Op {
|
||||||
|
enum Code {
|
||||||
|
LINK,
|
||||||
|
PUSH,
|
||||||
|
POP,
|
||||||
|
LOOP,
|
||||||
|
};
|
||||||
|
|
||||||
|
Code code: 4;
|
||||||
|
unsigned int value: 12;
|
||||||
|
|
||||||
|
explicit Op(Code code, unsigned int value = 0)
|
||||||
|
: code(code), value(value) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct fmt::formatter<Op> {
|
||||||
|
template<typename ParseContext>
|
||||||
|
constexpr auto parse(ParseContext &ctx) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename FormatContext>
|
||||||
|
auto format(const Op &op, FormatContext &ctx) {
|
||||||
|
switch (op.code) {
|
||||||
|
case Op::LINK:
|
||||||
|
return fmt::format_to(ctx.out(), "link({})",
|
||||||
|
(unsigned int) op.value);
|
||||||
|
case Op::PUSH:
|
||||||
|
return fmt::format_to(ctx.out(), "push()");
|
||||||
|
case Op::POP:
|
||||||
|
return fmt::format_to(ctx.out(), "pop()");
|
||||||
|
case Op::LOOP:
|
||||||
|
return fmt::format_to(ctx.out(), "loop()");
|
||||||
|
default:
|
||||||
|
return fmt::format_to(ctx.out(), "[{}]({})",
|
||||||
|
(unsigned int) op.code,
|
||||||
|
(unsigned int) op.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Factor {
|
||||||
|
unsigned int mode;
|
||||||
|
std::vector<unsigned int> orders;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct codegen {
|
||||||
|
std::vector<Op> ops;
|
||||||
|
|
||||||
|
void link(unsigned int order) {
|
||||||
|
ops.emplace_back(Op::LINK, order);
|
||||||
|
}
|
||||||
|
|
||||||
|
void push() {
|
||||||
|
ops.emplace_back(Op::PUSH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop() {
|
||||||
|
ops.emplace_back(Op::POP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
ops.emplace_back(Op::LOOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename It>
|
||||||
|
void insert(It begin, It end) {
|
||||||
|
std::copy(begin, end, std::back_inserter(ops));
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(const codegen &o) {
|
||||||
|
insert(o.ops.begin(), o.ops.end());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::string GRAMMAR = R"(
|
||||||
|
root <- term+
|
||||||
|
term <- product / op
|
||||||
|
op <- block / link
|
||||||
|
block <- '(' root ')' / '{' root '}' / '[' root ']'
|
||||||
|
link <- int
|
||||||
|
product <- op '*' factor
|
||||||
|
factor <- int / '{' int+ '}' / '[' int+ ']'
|
||||||
|
int <- < [0-9]+ >
|
||||||
|
|
||||||
|
%whitespace <- [ \t\n\r]*
|
||||||
|
)";
|
||||||
|
|
||||||
|
peg::parser build_parser() {
|
||||||
|
peg::parser parser;
|
||||||
|
parser.set_logger([](size_t line, size_t col, const std::string &msg, const std::string &rule) {
|
||||||
|
fmt::print(stderr, "{}:{} [{}] {}\n", line, col, rule, msg);
|
||||||
|
});
|
||||||
|
auto ok = parser.load_grammar(GRAMMAR);
|
||||||
|
assert(ok);
|
||||||
|
|
||||||
|
parser["int"] = [](const peg::SemanticValues &vs) -> std::any {
|
||||||
|
return vs.token_to_number<unsigned int>();
|
||||||
|
};
|
||||||
|
|
||||||
|
parser["link"] = [](const peg::SemanticValues &vs) -> std::any {
|
||||||
|
codegen cg;
|
||||||
|
|
||||||
|
auto order = std::any_cast<unsigned int>(vs[0]);
|
||||||
|
cg.link(order);
|
||||||
|
|
||||||
|
return cg;
|
||||||
|
};
|
||||||
|
|
||||||
|
parser["root"] = [](const peg::SemanticValues &vs) -> std::any {
|
||||||
|
codegen cg;
|
||||||
|
|
||||||
|
for (const auto &sub: vs) {
|
||||||
|
cg.insert(std::any_cast<codegen>(sub));
|
||||||
|
}
|
||||||
|
|
||||||
|
return cg;
|
||||||
|
};
|
||||||
|
|
||||||
|
parser["block"] = [](const peg::SemanticValues &vs) -> std::any {
|
||||||
|
if (vs.choice() == 0) return vs[0];
|
||||||
|
|
||||||
|
codegen cg;
|
||||||
|
|
||||||
|
cg.push();
|
||||||
|
cg.insert(std::any_cast<codegen>(vs[0]));
|
||||||
|
if (vs.choice() == 1) cg.loop();
|
||||||
|
cg.pop();
|
||||||
|
|
||||||
|
return cg;
|
||||||
|
};
|
||||||
|
|
||||||
|
parser["factor"] = [](const peg::SemanticValues &vs) -> std::any {
|
||||||
|
return Factor{
|
||||||
|
(unsigned int) vs.choice(),
|
||||||
|
vs.transform<unsigned int>(),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
parser["product"] = [](const peg::SemanticValues &vs) -> std::any {
|
||||||
|
auto sub = std::any_cast<codegen>(vs[0]);
|
||||||
|
auto fac = std::any_cast<Factor>(vs[1]);
|
||||||
|
|
||||||
|
codegen cg;
|
||||||
|
|
||||||
|
for (const auto &order: fac.orders) {
|
||||||
|
if (fac.mode == 0) {
|
||||||
|
for (unsigned int i = 0; i < order; ++i) {
|
||||||
|
cg.insert(sub);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cg.push();
|
||||||
|
for (unsigned int i = 0; i < order; ++i) {
|
||||||
|
cg.insert(sub);
|
||||||
|
}
|
||||||
|
if (fac.mode == 1) cg.loop();
|
||||||
|
cg.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cg;
|
||||||
|
};
|
||||||
|
|
||||||
|
return parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
peg::parser build_ast_parser() {
|
||||||
|
peg::parser parser;
|
||||||
|
parser.set_logger([](size_t line, size_t col, const std::string &msg, const std::string &rule) {
|
||||||
|
fmt::print(stderr, "{}:{} [{}] {}\n", line, col, rule, msg);
|
||||||
|
});
|
||||||
|
auto ok = parser.load_grammar(GRAMMAR);
|
||||||
|
assert(ok);
|
||||||
|
|
||||||
|
parser.enable_ast();
|
||||||
|
|
||||||
|
return parser;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::vector<Op> compile(const std::string &source) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
static peg::parser ast_parser = build_ast_parser();
|
||||||
|
std::shared_ptr<peg::Ast> ast;
|
||||||
|
bool ast_ok = ast_parser.parse(source, ast);
|
||||||
|
assert(ast_ok);
|
||||||
|
std::cout << peg::ast_to_s(ast) << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static peg::parser parser = build_parser();
|
||||||
|
codegen cg;
|
||||||
|
bool ok = parser.parse(source, cg);
|
||||||
|
assert(ok);
|
||||||
|
return cg.ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Graph {
|
||||||
|
size_t rank{};
|
||||||
|
std::vector<std::tuple<size_t, size_t, unsigned int>> edges{};
|
||||||
|
};
|
||||||
|
|
||||||
|
Graph eval(const std::vector<Op> &ops) {
|
||||||
|
std::vector<std::stack<size_t>> stacks(1);
|
||||||
|
|
||||||
|
Graph g;
|
||||||
|
stacks.back().emplace(g.rank++);
|
||||||
|
|
||||||
|
for (const auto &op: ops) {
|
||||||
|
switch (op.code) {
|
||||||
|
case Op::LINK: {
|
||||||
|
auto order = op.value;
|
||||||
|
|
||||||
|
auto top = stacks.back().top();
|
||||||
|
auto curr = g.rank++;
|
||||||
|
|
||||||
|
stacks.back().emplace(curr);
|
||||||
|
g.edges.emplace_back(top, curr, order);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op::PUSH: {
|
||||||
|
stacks.emplace_back();
|
||||||
|
|
||||||
|
auto ptop = stacks[stacks.size() - 2].top();
|
||||||
|
stacks.back().emplace(ptop);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op::POP: {
|
||||||
|
stacks.pop_back();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op::LOOP: {
|
||||||
|
g.rank--;
|
||||||
|
|
||||||
|
auto ptop = stacks[stacks.size() - 2].top();
|
||||||
|
auto &[top, _, order] = g.edges.back();
|
||||||
|
|
||||||
|
stacks.back().pop();
|
||||||
|
g.edges.pop_back();
|
||||||
|
|
||||||
|
g.edges.emplace_back(top, ptop, order);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Invalid opcode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace tc {
|
||||||
|
Group coxeter(const std::string &symbol) {
|
||||||
|
auto ops = compile(symbol);
|
||||||
|
|
||||||
|
// fmt::print("#ops: {}\n", ops.size());
|
||||||
|
// for (const auto &op: ops) {
|
||||||
|
// fmt::print(" {}\n", op);
|
||||||
|
// }
|
||||||
|
|
||||||
|
auto diagram = eval(ops);
|
||||||
|
|
||||||
|
Group res((int) diagram.rank);
|
||||||
|
|
||||||
|
for (const auto &[i, j, order]: diagram.edges) {
|
||||||
|
res.set({i, j, order});
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
39
tc/src/langtest.cpp
Normal file
39
tc/src/langtest.cpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <tc/group.hpp>
|
||||||
|
#include <tc/groups.hpp>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::vector<std::string> symbols = {
|
||||||
|
"5 3 3",
|
||||||
|
"5 (3 3)",
|
||||||
|
"[5 3 3]",
|
||||||
|
"[4 3 [3 5] 3]",
|
||||||
|
"{3 4 5 6 7 8 9}",
|
||||||
|
"3 {3 3 [4] 3} 5",
|
||||||
|
"5 * 3",
|
||||||
|
"5 * [3]",
|
||||||
|
"5 * {2 3}",
|
||||||
|
"5 * [3 2]",
|
||||||
|
"(5 2) * [3 2]",
|
||||||
|
"4 [3 * [2 3]] 5",
|
||||||
|
"{3 * 3} [4] [5]",
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto &symbol: symbols) {
|
||||||
|
auto group = tc::coxeter(symbol);
|
||||||
|
|
||||||
|
std::cout << "'" << symbol << "'" << std::endl;
|
||||||
|
|
||||||
|
for (int i = 0; i < group.ngens; ++i) {
|
||||||
|
for (int j = 0; j < group.ngens; ++j) {
|
||||||
|
std::cout << group.get(i, j) << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "===========================" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
280
tc/src/pegtest.cpp
Normal file
280
tc/src/pegtest.cpp
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
#include <vector>
|
||||||
|
#include <stack>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#include <fmt/ranges.h>
|
||||||
|
|
||||||
|
#include <peglib.h>
|
||||||
|
|
||||||
|
struct Op {
|
||||||
|
enum Code {
|
||||||
|
LINK,
|
||||||
|
PUSH,
|
||||||
|
POP,
|
||||||
|
LOOP,
|
||||||
|
};
|
||||||
|
|
||||||
|
Code code: 4;
|
||||||
|
unsigned int value: 12;
|
||||||
|
|
||||||
|
explicit Op(Code code, unsigned int value = 0)
|
||||||
|
: code(code), value(value) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct fmt::formatter<Op> {
|
||||||
|
template<typename ParseContext>
|
||||||
|
constexpr auto parse(ParseContext &ctx) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename FormatContext>
|
||||||
|
auto format(const Op &op, FormatContext &ctx) {
|
||||||
|
switch (op.code) {
|
||||||
|
case Op::LINK:
|
||||||
|
return fmt::format_to(ctx.out(), "link({})",
|
||||||
|
(unsigned int) op.value);
|
||||||
|
case Op::PUSH:
|
||||||
|
return fmt::format_to(ctx.out(), "push()");
|
||||||
|
case Op::POP:
|
||||||
|
return fmt::format_to(ctx.out(), "pop()");
|
||||||
|
case Op::LOOP:
|
||||||
|
return fmt::format_to(ctx.out(), "loop()");
|
||||||
|
default:
|
||||||
|
return fmt::format_to(ctx.out(), "[{}]({})",
|
||||||
|
(unsigned int) op.code,
|
||||||
|
(unsigned int) op.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Factor {
|
||||||
|
unsigned int mode;
|
||||||
|
std::vector<unsigned int> orders;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct codegen {
|
||||||
|
std::vector<Op> ops;
|
||||||
|
|
||||||
|
void link(unsigned int order) {
|
||||||
|
ops.emplace_back(Op::LINK, order);
|
||||||
|
}
|
||||||
|
|
||||||
|
void push() {
|
||||||
|
ops.emplace_back(Op::PUSH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop() {
|
||||||
|
ops.emplace_back(Op::POP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
ops.emplace_back(Op::LOOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename It>
|
||||||
|
void insert(It begin, It end) {
|
||||||
|
std::copy(begin, end, std::back_inserter(ops));
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(const codegen &o) {
|
||||||
|
insert(o.ops.begin(), o.ops.end());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
peg::parser build_parser() {
|
||||||
|
const auto grammar = R"(
|
||||||
|
root <- term+
|
||||||
|
term <- product / op
|
||||||
|
op <- block / link
|
||||||
|
block <- '(' root ')' / '{' root '}' / '[' root ']'
|
||||||
|
link <- int
|
||||||
|
product <- op '*' factor
|
||||||
|
factor <- int / '{' int+ '}' / '[' int+ ']'
|
||||||
|
int <- < [0-9]+ >
|
||||||
|
|
||||||
|
%whitespace <- [ \t\n\r]*
|
||||||
|
)";
|
||||||
|
|
||||||
|
peg::parser parser;
|
||||||
|
parser.set_logger([](size_t line, size_t col, const std::string &msg, const std::string &rule) {
|
||||||
|
fmt::print(stderr, "{}:{} [{}] {}\n", line, col, rule, msg);
|
||||||
|
});
|
||||||
|
auto ok = parser.load_grammar(grammar);
|
||||||
|
assert(ok);
|
||||||
|
|
||||||
|
parser["int"] = [](const peg::SemanticValues &vs) -> std::any {
|
||||||
|
return vs.token_to_number<unsigned int>();
|
||||||
|
};
|
||||||
|
|
||||||
|
parser["link"] = [](const peg::SemanticValues &vs) -> std::any {
|
||||||
|
codegen cg;
|
||||||
|
|
||||||
|
auto order = std::any_cast<unsigned int>(vs[0]);
|
||||||
|
cg.link(order);
|
||||||
|
|
||||||
|
return cg;
|
||||||
|
};
|
||||||
|
|
||||||
|
parser["root"] = [](const peg::SemanticValues &vs) -> std::any {
|
||||||
|
codegen cg;
|
||||||
|
|
||||||
|
for (const auto &sub: vs) {
|
||||||
|
cg.insert(std::any_cast<codegen>(sub));
|
||||||
|
}
|
||||||
|
|
||||||
|
return cg;
|
||||||
|
};
|
||||||
|
|
||||||
|
parser["block"] = [](const peg::SemanticValues &vs) -> std::any {
|
||||||
|
if (vs.choice() == 0) return vs[0];
|
||||||
|
|
||||||
|
codegen cg;
|
||||||
|
|
||||||
|
cg.push();
|
||||||
|
cg.insert(std::any_cast<codegen>(vs[0]));
|
||||||
|
if (vs.choice() == 1) cg.loop();
|
||||||
|
cg.pop();
|
||||||
|
|
||||||
|
return cg;
|
||||||
|
};
|
||||||
|
|
||||||
|
parser["factor"] = [](const peg::SemanticValues &vs) -> std::any {
|
||||||
|
return Factor{
|
||||||
|
(unsigned int) vs.choice(),
|
||||||
|
vs.transform<unsigned int>(),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
parser["product"] = [](const peg::SemanticValues &vs) -> std::any {
|
||||||
|
auto sub = std::any_cast<codegen>(vs[0]);
|
||||||
|
auto fac = std::any_cast<Factor>(vs[1]);
|
||||||
|
|
||||||
|
codegen cg;
|
||||||
|
|
||||||
|
for (const auto &order: fac.orders) {
|
||||||
|
if (fac.mode == 0) {
|
||||||
|
for (unsigned int i = 0; i < order; ++i) {
|
||||||
|
cg.insert(sub);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cg.push();
|
||||||
|
for (unsigned int i = 0; i < order; ++i) {
|
||||||
|
cg.insert(sub);
|
||||||
|
}
|
||||||
|
if (fac.mode == 1) cg.loop();
|
||||||
|
cg.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cg;
|
||||||
|
};
|
||||||
|
|
||||||
|
return parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Op> compile(const std::string &source) {
|
||||||
|
static peg::parser parser = build_parser();
|
||||||
|
|
||||||
|
std::any val;
|
||||||
|
codegen cg;
|
||||||
|
|
||||||
|
bool success = parser.parse(source, cg);
|
||||||
|
assert(success);
|
||||||
|
|
||||||
|
return cg.ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Graph {
|
||||||
|
size_t rank{};
|
||||||
|
std::vector<std::tuple<size_t, size_t, unsigned int>> edges{};
|
||||||
|
};
|
||||||
|
|
||||||
|
Graph eval(const std::vector<Op> &ops) {
|
||||||
|
std::vector<std::stack<size_t>> stacks(1);
|
||||||
|
|
||||||
|
Graph g;
|
||||||
|
stacks.back().emplace(g.rank++);
|
||||||
|
|
||||||
|
for (const auto &op: ops) {
|
||||||
|
switch (op.code) {
|
||||||
|
case Op::LINK: {
|
||||||
|
auto order = op.value;
|
||||||
|
|
||||||
|
auto top = stacks.back().top();
|
||||||
|
auto curr = g.rank++;
|
||||||
|
|
||||||
|
stacks.back().emplace(curr);
|
||||||
|
g.edges.emplace_back(top, curr, order);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op::PUSH: {
|
||||||
|
stacks.emplace_back();
|
||||||
|
|
||||||
|
auto ptop = stacks[stacks.size() - 2].top();
|
||||||
|
stacks.back().emplace(ptop);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op::POP: {
|
||||||
|
stacks.pop_back();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op::LOOP: {
|
||||||
|
g.rank--;
|
||||||
|
|
||||||
|
auto ptop = stacks[stacks.size() - 2].top();
|
||||||
|
auto &[top, _, order] = g.edges.back();
|
||||||
|
|
||||||
|
stacks.back().pop();
|
||||||
|
g.edges.pop_back();
|
||||||
|
|
||||||
|
g.edges.emplace_back(top, ptop, order);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Invalid opcode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::vector<std::string> sources = {
|
||||||
|
"5 3 3",
|
||||||
|
"5 (3 3)",
|
||||||
|
"[5 3 3]",
|
||||||
|
"[4 3 [3 5] 3]",
|
||||||
|
"{3 4 3 5}",
|
||||||
|
"3 {3 3 [4] 3} 5",
|
||||||
|
"5 * 3",
|
||||||
|
"5 * [3]",
|
||||||
|
"5 * {2 3}",
|
||||||
|
"5 * [3 2]",
|
||||||
|
"(5 2) * [3 2]",
|
||||||
|
"4 [3 * [2 3]] 5",
|
||||||
|
"{3 * 3} [4] [5]",
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto &source: sources) {
|
||||||
|
fmt::print("source: '{}'\n", source);
|
||||||
|
|
||||||
|
auto ops = compile(source);
|
||||||
|
for (const auto &op: ops) {
|
||||||
|
fmt::print("- {}\n", op);
|
||||||
|
}
|
||||||
|
auto g = eval(ops);
|
||||||
|
fmt::print("rank: {}\n", g.rank);
|
||||||
|
for (const auto &edge: g.edges) {
|
||||||
|
fmt::print("- {}\n", edge);
|
||||||
|
}
|
||||||
|
fmt::print("=======================================\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user