Skip to content

Commit

Permalink
Possibly working
Browse files Browse the repository at this point in the history
  • Loading branch information
james-d-mitchell committed Nov 21, 2023
1 parent ded81ac commit 18c91c5
Show file tree
Hide file tree
Showing 4 changed files with 239 additions and 20 deletions.
2 changes: 1 addition & 1 deletion src/fpsemi-examples.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1165,7 +1165,7 @@ namespace libsemigroups {
Presentation<word_type> full_transformation_monoid(size_t n, author val) {
if (n < 4) {
LIBSEMIGROUPS_EXCEPTION(
"the 1st argument (size_t) must be at least 4, found {}", n);
"the 1st argument (degree) must be at least 4, found {}", n);
} else if (val != author::Aizenstat && val != author::Iwahori) {
LIBSEMIGROUPS_EXCEPTION(
"expected 2nd argument to be author::Aizenstat or "
Expand Down
60 changes: 48 additions & 12 deletions src/sims1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ namespace libsemigroups {
size_t m = std::distance(s->presentation().rules.cbegin(),
s->cbegin_long_rules());
p.rules.erase(p.rules.begin() + m, p.rules.end());
// TODO could be slightly less space allocated here
_2_sided_include.assign(2 * n * p.alphabet().size(), word_type());
_2_sided_words.assign(n, word_type());
_felsch_graph.init(std::move(p));
// n == 0 only when the iterator is cend
_felsch_graph.number_of_active_nodes(n == 0 ? 0 : 1);
Expand All @@ -147,7 +150,9 @@ namespace libsemigroups {
_felsch_graph(that._felsch_graph),
_mtx(),
_pending(that._pending),
_sims1(that._sims1) {}
_sims1(that._sims1),
_2_sided_include(that._2_sided_include),
_2_sided_words(that._2_sided_words) {}

// Intentionally don't copy the mutex, it doesn't compile, wouldn't make
// sense if the mutex was used here.
Expand All @@ -160,7 +165,9 @@ namespace libsemigroups {
_felsch_graph(std::move(that._felsch_graph)),
_mtx(),
_pending(std::move(that._pending)),
_sims1(that._sims1) {}
_sims1(that._sims1),
_2_sided_include(std::move(that._2_sided_include)),
_2_sided_words(std::move(that._2_sided_words)) {}

// Intentionally don't copy the mutex, it doesn't compile, wouldn't make
// sense if the mutex was used here.
Expand All @@ -175,6 +182,10 @@ namespace libsemigroups {
// keep our own _mtx
_pending = that._pending;
_sims1 = that._sims1;

_2_sided_include = that._2_sided_include;
_2_sided_words = that._2_sided_words;

return *this;
}

Expand All @@ -188,8 +199,10 @@ namespace libsemigroups {
_min_target_node = std::move(that._min_target_node);

// protected
_felsch_graph = std::move(that._felsch_graph);
_pending = std::move(that._pending);
_felsch_graph = std::move(that._felsch_graph);
_pending = std::move(that._pending);
_2_sided_include = std::move(that._2_sided_include);
_2_sided_words = std::move(that._2_sided_words);
// keep our own _mtx
_sims1 = that._sims1;
return *this;
Expand Down Expand Up @@ -218,9 +231,6 @@ namespace libsemigroups {
if (_min_target_node == 0) {
_pending.emplace_back(0, 0, 0, 0, 1, false);
}
// TODO maybe use less space in _2_sided_include
_2_sided_include.assign((n * (n - 1)), word_type());
_2_sided_words.assign(n, word_type());
}
}

Expand Down Expand Up @@ -253,9 +263,33 @@ namespace libsemigroups {

// Don't call number_of_edges because this calls the function in
// WordGraph
size_type start = _felsch_graph.definitions().size();
size_type const prev_num_non_tree_edges
= 2 * ((start - _felsch_graph.number_of_active_nodes()) + 2);
size_type start = _felsch_graph.definitions().size();

size_type prev_num_non_tree_edges;
if (current.target_is_new_node) {
// number of tree edges is number_of_active_nodes - 2
// because the active nodes include the target which is a new node
prev_num_non_tree_edges = 2
* ((_felsch_graph.definitions().size()
- _felsch_graph.number_of_active_nodes())
+ 2);
LIBSEMIGROUPS_ASSERT(_felsch_graph.definitions().size()
- (prev_num_non_tree_edges / 2)
== _felsch_graph.number_of_active_nodes() - 2);
} else {
// number of tree edges is number_of_active_nodes - 1 because the
// target is not a new node
prev_num_non_tree_edges = 2
* ((_felsch_graph.definitions().size()
- _felsch_graph.number_of_active_nodes())
+ 1);
LIBSEMIGROUPS_ASSERT(_felsch_graph.definitions().size()
- (prev_num_non_tree_edges / 2)
== _felsch_graph.number_of_active_nodes() - 1);
}

LIBSEMIGROUPS_ASSERT(prev_num_non_tree_edges / 2
<= _felsch_graph.definitions().size());

_felsch_graph.set_target_no_checks(
current.source, current.generator, current.target);
Expand All @@ -280,7 +314,7 @@ namespace libsemigroups {
while (start < _felsch_graph.definitions().size()) {
for (size_t i = start, j = 0; i < _felsch_graph.definitions().size();
++i) {
auto e = _felsch_graph.definitions()[i];
auto e = _felsch_graph.definitions()[i]; // TODO reference
if (current.target_is_new_node && e.first == current.source
&& e.second == current.generator) {
continue;
Expand All @@ -304,13 +338,15 @@ namespace libsemigroups {
first = _2_sided_include.cbegin();
last = _2_sided_include.cbegin() + num_non_tree_edges;
start = _felsch_graph.definitions().size();
prev_num_non_tree_edges = num_non_tree_edges;

if (!felsch_graph::make_compatible<RegisterDefs>(
_felsch_graph,
0,
_felsch_graph.number_of_active_nodes(),
first,
last)) {
last)
|| !_felsch_graph.process_definitions(start)) {
return false;
}
}
Expand Down
77 changes: 77 additions & 0 deletions tests/gap.g
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
AsWordGraph := function(C)
local lookup, S, A, out, next, pos, class, a;

lookup := EquivalenceRelationCanonicalLookup(C);
S := Source(C);
A := GeneratorsOfSemigroup(S);

out := [];

for class in EquivalenceClasses(C) do
next := [];
for a in A do
pos := PositionCanonical(S, Representative(class) * a);
Add(next, lookup[pos]);
od;
Add(out, next);
od;

return Digraph(out);
end;

StandardizeWordGraph := function(D)
local s, t, N, n, result, x, r;

# TODO arg checks
if IsNullDigraph(D) then
return D;
fi;
s := 0;
t := 0;
N := OutNeighbours(D);
n := Length(N[1]);
result := DigraphMutableCopy(D);

while s <= t do
for x in [1 .. n] do
r := N[s + 1][x];
if r > t then
t := t + 1;
if r > t then
OnDigraphs(result, (t + 1, r));
N := OutNeighbours(result);
fi;
fi;
od;
s := s + 1;
od;
return result;
end;

ToWordGraphs := function(Cs)
local Ds;
Ds := List(Cs, AsWordGraph);
Ds := List(Ds, x -> List(x, y -> y{[2 .. Length(y)]}));
return Ds - 1;
end;

AllMultiplicationTables:= function(S)
local result;
result := ShallowCopy(Orbit(SymmetricGroup(Size(S)),
MultiplicationTable(S),
OnMultiplicationTable));
if not IsSelfDualSemigroup(S) then
Append(result,
Orbit(SymmetricGroup(Size(S)),
TransposedMat(MultiplicationTable(S)),
OnMultiplicationTable));
fi;
return result;
end;



ExpectedNumber := function(num_gens, max_size)


end;
120 changes: 113 additions & 7 deletions tests/test-sims1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2835,21 +2835,27 @@ namespace libsemigroups {
REQUIRE(s.number_of_threads(4).number_of_congruences(std::pow(2, 6)) == 0);
}

LIBSEMIGROUPS_TEST_CASE("Sims1", "092", "2-sided example", "[quick][sims1]") {
LIBSEMIGROUPS_TEST_CASE("Sims1",
"092",
"2-sided full transformation monoid 2",
"[quick][sims1]") {
Presentation<word_type> p;
p.alphabet(2);
p.contains_empty_word(true);
presentation::add_rule(p, 00_w, {});
presentation::add_rule(p, 01_w, 1_w);
presentation::add_rule(p, 11_w, 1_w);
Sims1 s(congruence_kind::twosided, p);
// REQUIRE(s.number_of_congruences(4) == 4); // Verified with GAP
REQUIRE(s.number_of_congruences(4) == 4); // Verified with GAP
auto it = s.cbegin(4);
REQUIRE(*(it++) == to_word_graph<node_type>(4, {{0, 0}}));
REQUIRE(*(it++) == to_word_graph<node_type>(4, {{0, 1}, {1, 1}}));
REQUIRE(*(it++) == to_word_graph<node_type>(4, {{1, 2}, {0, 2}, {2, 2}}));
REQUIRE(*(it++) == to_word_graph<node_type>(4, {{0, 0}})); // ok
REQUIRE(*(it++) == to_word_graph<node_type>(4, {{0, 1}, {1, 1}})); // ok
REQUIRE(*(it++)
== to_word_graph<node_type>(4, {{1, 2}, {0, 2}, {2, 2}})); // ok

REQUIRE(*(it++)
== to_word_graph<node_type>(4, {{1, 2}, {0, 2}, {3, 2}, {2, 2}}));
== to_word_graph<node_type>(
4, {{1, 2}, {0, 2}, {3, 2}, {2, 2}})); // ok
}

LIBSEMIGROUPS_TEST_CASE("Sims1", "093", "2-sided example", "[quick][sims1]") {
Expand All @@ -2867,8 +2873,9 @@ namespace libsemigroups {
presentation::add_rule(p, {0, 1, 0, 1}, {0});
Sims1 s(congruence_kind::twosided, p);

// REQUIRE(s.number_of_congruences(4) == 6); // Verified with GAP
REQUIRE(s.number_of_congruences(4) == 6); // Verified with GAP
auto it = s.cbegin(5);
// Verified in 000
REQUIRE(*(it++) == to_word_graph<node_type>(5, {{0, 0}}));
REQUIRE(*(it++) == to_word_graph<node_type>(5, {{1, 0}, {1, 1}}));
REQUIRE(*(it++) == to_word_graph<node_type>(5, {{1, 1}, {1, 1}}));
Expand All @@ -2877,6 +2884,105 @@ namespace libsemigroups {
REQUIRE(*(it++)
== to_word_graph<node_type>(5, {{1, 2}, {1, 1}, {3, 2}, {3, 3}}));
}

LIBSEMIGROUPS_TEST_CASE("Sims1",
"095",
"2-sided full transf. monoid 3",
"[quick][sims1]") {
Presentation<std::string> p;
p.alphabet("abc");
p.contains_empty_word(true);
presentation::add_rule(p, "b^2"_p, ""_p);
presentation::add_rule(p, "bc"_p, "ac"_p);
presentation::add_rule(p, "c^2"_p, "c"_p);
presentation::add_rule(p, "a^3"_p, ""_p);
presentation::add_rule(p, "a^2b"_p, "ba"_p);
presentation::add_rule(p, "aba"_p, "b"_p);
presentation::add_rule(p, "baa"_p, "ab"_p);
presentation::add_rule(p, "bab"_p, "aa"_p);
presentation::add_rule(p, "bac"_p, "c"_p);
presentation::add_rule(p, "cac"_p, "cb"_p);
presentation::add_rule(p, "aca^2c"_p, "ca^2c"_p);
presentation::add_rule(p, "ca^2cb"_p, "ca^2ca"_p);
presentation::add_rule(p, "ca^2cab"_p, "ca^2c"_p);
Sims1 s(congruence_kind::twosided, p);
REQUIRE(s.number_of_congruences(27) == 7); // Verified with GAP

auto it = s.cbegin(27);

REQUIRE(*(it++) == to_word_graph<node_type>(27, {{0, 0, 0}})); // ok
REQUIRE(*(it++)
== to_word_graph<node_type>(27, {{0, 0, 1}, {1, 1, 1}})); // ok
REQUIRE(*(it++)
== to_word_graph<node_type>(
27, {{0, 1, 2}, {1, 0, 2}, {2, 2, 2}})); // ok
REQUIRE(*(it++)
== to_word_graph<node_type>(27,
{{1, 2, 3},
{4, 5, 3},
{6, 0, 3},
{3, 3, 3},
{0, 6, 3},
{2, 1, 3},
{5, 4, 3}})); // ok
REQUIRE(*(it++)
== to_word_graph<node_type>(27,
{{1, 2, 3},
{4, 5, 6},
{7, 0, 6},
{8, 3, 3},
{0, 7, 9},
{2, 1, 9},
{10, 6, 6},
{5, 4, 3},
{11, 11, 3},
{12, 9, 9},
{13, 13, 6},
{3, 8, 14},
{15, 15, 9},
{6, 10, 14},
{14, 14, 14},
{9, 12, 14}})); // ok
REQUIRE(*(it++)
== to_word_graph<node_type>(
27, {{1, 2, 3}, {4, 5, 6}, {7, 0, 6}, {8, 9, 3},
{0, 7, 10}, {2, 1, 10}, {11, 12, 6}, {5, 4, 3},
{13, 14, 9}, {15, 3, 9}, {16, 17, 10}, {18, 19, 12},
{20, 6, 12}, {3, 15, 21}, {9, 8, 21}, {14, 13, 3},
{22, 23, 17}, {24, 10, 17}, {6, 20, 21}, {12, 11, 21},
{19, 18, 6}, {21, 21, 21}, {10, 24, 21}, {17, 16, 21},
{23, 22, 10}})); // ok
REQUIRE(*(it++)
== to_word_graph<node_type>(
27, {{1, 2, 3}, {4, 5, 6}, {7, 0, 6}, {8, 9, 3},
{0, 7, 10}, {2, 1, 10}, {11, 12, 6}, {5, 4, 3},
{13, 14, 9}, {15, 3, 9}, {16, 17, 10}, {18, 19, 12},
{20, 6, 12}, {3, 15, 21}, {9, 8, 21}, {14, 13, 3},
{22, 23, 17}, {24, 10, 17}, {6, 20, 21}, {12, 11, 21},
{19, 18, 6}, {25, 25, 21}, {10, 24, 21}, {17, 16, 21},
{23, 22, 10}, {26, 21, 25}, {21, 26, 21}})); // ok
}

LIBSEMIGROUPS_TEST_CASE("Sims1",
"096",
"2-sided free monoid",
"[quick][sims1]") {
Presentation<std::string> p;
p.alphabet("ab");
p.contains_empty_word(true);
Sims1 s(congruence_kind::twosided, p);
REQUIRE(s.number_of_congruences(1) == 1);
REQUIRE(s.number_of_congruences(2) == 7);
REQUIRE(s.number_of_congruences(3) == 27);
REQUIRE(s.number_of_congruences(4) == 94);
REQUIRE(s.number_of_congruences(5) == 275);
REQUIRE(s.number_of_congruences(6) == 833);
REQUIRE(s.number_of_congruences(7) == 2'307);
REQUIRE(s.number_of_congruences(8) == 6'488);
REQUIRE(s.number_of_congruences(9) == 18'207);
REQUIRE(s.number_of_congruences(10) == 52'960);
}

} // namespace libsemigroups

// [[[0, 0, 0]], #1#
Expand Down

0 comments on commit 18c91c5

Please sign in to comment.