######################################################################## # # walrus: Computational Methods for Finitely Generated Monoids and Groups # # WARNING # ######################################################################## # # TODO (documentation) # - Examples # - notes on the implementation (design decisions etc) # # TODO (technical) # - MakeIsReducedDiagram an operation # - Sort out families of elements etc # - what to do about the __ID hack? # - What to do about float vs rational? # - provide a way to label generators # - Introduce an InfoLevel and log things with info levels, remove Print # statements # - Put relators of different presentations into different families # - Check whether some sub-functions could be cleaned out from functions # and would become more generally useful # - Better indexing of locations on relator/places # - Better datastructure for storing one step reachables # (basically a hashmap from orb I think) plus wrapper functions # - PlaceQuadruples should be an object or a record # - Add proper error messages for "This shouldn't happen" with a pointer # towards the github issue tracker # - Make a reasonably standard format (and exporter/importer) to exchange # pregroup presentations so we can move them between GAP/other # implementations for cross-checking
# # TODO (mathematical/functional) # - Write tests # - Interleaving # - Preparing the presentation (User choosing Pregroup/removing generators, relators) # - check LocationBlobGraph + distances # - Make the distance computation in LBG more efficient? # - Check OneStepReachables # - Check RSymTest # ######################################################################## # # Some notes on the implementation # # - Stored curvature is always "negative curvature", so in most cases a # positive value. # - Curvature values are stored as rationals at first, later converted to # floats. This might not be the best way to do this (we might want to # always use rationals or always use floats) #
# Alternative to LocationBlobGraph, only has pairs, coloured Green for location pair # and red for intermult pair # a bit hacky though
InstallMethod(VertexGraph, "for a pregroup presentation",
[IsPregroupPresentation and IsPregroupPresentationRep], function(pres)
local mat, v, vd, vg, e, loc, loc2, pg, p, ploc, ploc2, imp, i, backmap, len, li, labels;
pg := Pregroup(pres);
li := LocationIndex(pres);
# Green vertices [[a, b], 0] correspond to locations
v := List(Keys(li), l -> [l, 0]); # Red vertices correspond to intermult pairs
Append(v, List(IntermultPairs(pg), p -> [p, 1]));
e := function(a,b) if (a[2] = 0) and (b[2] = 0) then# both vertices are green if PregroupInverse(a[1][2]) = b[1][1] then# There are locations R(i,a,b) and R'(j,b^-1,c)
ploc := li[a[1]];
ploc2 := li[b[1]]; for loc in ploc do for loc2 in ploc2 do if CheckReducedDiagram(loc, loc2) then
return 1; fi;
od;
od;
return infinity; fi; elif (a[2] = 0) and (b[2] = 1) then# a is green, b is red if PregroupInverse(a[1][2]) = b[1][1] then# There is location R(i,a,b)
return 1; fi; elif (a[2] = 1) and (b[2] = 0) then# a is red, b is green if PregroupInverse(a[1][2]) = b[1][1] then#
return 0; fi; fi;
return infinity; end;
backmap := HashMap(); for i in [1..Length(v)] do
backmap[ [__ID(v[i][1][1]), __ID(v[i][1][2]), v[i][2] ] ] := i;
od;
mat := List(DigraphVertices(vg), i -> List(DigraphVertices(vg), j -> e(v[i], v[j]) ) );
vg!.mat := mat;
vg!.backmap := backmap;
return vg; end);
InstallMethod(VertexGraphDistances, "for a pregroup presentation",
[IsPregroupPresentation and IsPregroupPresentationRep], function(pres)
local vg, wt, f, vertices, n, mat, i, j, k, a, b, t, out;
vg := VertexGraph(pres);
vertices := DigraphVertices(vg);
mat := vg!.mat;
# SC_FLOYD_WARSHALL(mat);
for k in vertices do for i in vertices do for j in vertices do
t := mat[i, k] + mat[k, j]; if t < mat[i,j] then
mat[i,j] := t; fi;
od;
od;
od; # Can there be more than one such entry?
return mat; end);
InstallMethod(VertexTriples, "for a pregroup presentation",
[IsPregroupPresentation and IsPregroupPresentationRep], function(pres)
local v, v1, v2, v1l, v2l, vl, vg, lv, vgd, dist, vtl;
vl := DigraphVertexLabel(vg, v); # Only green vertices if (vl[2] = 0) then for v1 in InNeighboursOfVertex(vg, v) do
v1l := DigraphVertexLabel(vg, v1); for v2 in OutNeighboursOfVertex(vg, v) do
v2l := DigraphVertexLabel(vg, v2);
dist := vgd[v2][v1]; if (v1l[2] = 0) and (v2l[2] = 0) then if dist = 1then
vtl[ [v, v1, v2 ] ] := 1/6; elif dist = 2then
vtl[ [ v, v1, v2 ] ] := 1/4; elif dist = 3then
vtl[ [ v, v1, v2 ] ] := 3/10; elif dist > 3then
vtl[ [ v, v1, v2 ] ] := 1/3; else
Error("this shouldn't happen"); fi; elif (v1l[2] = 0) and (v2l[2] = 1) then if dist = 0then
vtl[ [ v, v1, v2 ] ] := 0; elif dist = 1then
vtl[ [ v, v1, v2 ] ] := 1/6; elif dist > 1then
vtl[ [ v, v1, v2 ] ] := 1/4; else
Error("this shouldn't happen"); fi; elif (v1l[2] = 1) and (v2l[2] = 0) then if dist = 1then
vtl[ [ v, v1, v2 ] ] := 0; elif dist = 2then
vtl[ [ v, v1, v2 ] ] := 1/6; elif dist > 2then
vtl[ [ v, v1, v2 ] ] := 1/4; else
Error("this shouldn't happen"); fi; elif (v1l[2] = 1) and (v2l[2] = 1) then
vtl[ [ v, v1, v2 ] ] := 0; # what if dist=infinity (i.e. no path) else
Error("this should not happen"); fi;
od;
od; fi;
od;
return vtl; end);
InstallGlobalFunction(WalrusVertex, function(pres, v1, v, v2)
local vt, t;
t := VertexTriples(pres)[ [v, v1, v2] ]; if t <> fail then
return t; else
return 1/3; fi; end);
#XXX Computes triples (a,b,c) that are infixes # of strings found here with appropriate numbers
InstallMethod(ShortRedBlobIndex, "for a pregroup presentation",
[IsPregroupPresentation], function(pres)
local pg, n, imm, index, nrl, cand, word, nonrletts, len, c;
pg := Pregroup(pres);
n := Size(pg);
imm := IntermultMapIDs(pg);
# TODO: This would be better done by a tree structure
index := HashMap();
cand := [[2..n]];
nonrletts := [];
word := [];
len := 1;
# minimum length 3 while (len > 0) and (len < 7) do if Length(cand[len]) > 0then
c := Remove(cand[len], 1);
word[len] := pg[c];
nonrletts[len] := not IsRLetter(pres, pg[c]); # Possible not go further if we have too many R-letters? if IsIntermultPair(word[len], word[1]) and
ReduceUPregroupWord(word{ [1..len] }) = [] then
nrl := SizeBlist(nonrletts{[1..len]}); if len = 3then # if len = 3 then no proper subword can be equal to 1 # because we only look at intermult pairs, and pairs # of inverses are explicitly not intermult pairs if nrl = 0then
EnterAllSubwords(index, word{[1..len]}, 1/6); elif nrl = 1then
EnterAllSubwords(index, word{[1..len]}, 1/4); else # Print("? nrl", nrl, "\n"); fi; elif len = 4then if nrl = 0then
EnterAllSubwords(index, word{[1..len]}, 1/4); elif nrl = 1then
EnterAllSubwords(index, word{[1..len]}, 1/3); else # Print("? nrl", nrl, "\n"); fi; elif len = 5then if (nrl = 0) then
EnterAllSubwords(index, word{[1..len]}, 3/10); fi; elif (len = 6)
and (ReduceUPregroupWord(word{[2,3,4]}) <> [])
and (ReduceUPregroupWord(word{[3,4,5]}) <> []) then if nrl = 0then
EnterAllSubwords(index, word{[1..len]}, 1/3); else # Print("? nrl", nrl, "\n"); fi; fi; # We have entered, so backtrack
len := len - 1; else if (len = 6) then
len := len - 1; else
len := len + 1;
cand[len] := ShallowCopy(imm[c]); fi; fi; else
len := len - 1; fi;
od;
return index; end);
# This should become an operation
InstallMethod(Blob, "for a pregroup presentation, an element, an element, and an element"
, [ IsPregroupPresentation
, IsElementOfPregroup
, IsElementOfPregroup
, IsElementOfPregroup ], function(pres, a, b, c)
local it, v, n;
n := Size(Pregroup(pres));
it := ShortRedBlobIndex(pres);
v := it[ [__ID(a), __ID(b), __ID(c)] ];
if v <> fail then
return v; fi;
return 5/14; end);
# TODO: Use a map
InstallGlobalFunction(VertexFor, function(vg, trip)
return vg!.backmap[ [ __ID(trip[1]), __ID(trip[2]), trip[3] ] ]; end);
# Compute a list of # - places reachable from loc1 on Relator(loc1), and # - the corresponding location on Relator(loc2) # by a consolidated edge between Relator(loc1) and Relator(loc2)
InstallGlobalFunction(ConsolidatedEdgePlaces, function(loc1, loc2)
local res, length, r1_loc, r2_loc, r1_length;
if OutLetter(r1_loc) <> PregroupInverse(InLetter(r2_loc)) then
Error("This shouldn't happen"); # return []; fi;
repeat
r1_loc := NextLocation(r1_loc);
r2_loc := PrevLocation(r2_loc);
length := length + 1;
Append(res, List(Places(r1_loc), x -> [x, r2_loc, length]));
until (OutLetter(r1_loc) <> PregroupInverse(InLetter(r2_loc)))
or (length = r1_length);
# Meh. if (length = r1_length) or
(length = Length(Relator(loc2))) then
return []; else
return res; fi; end);
# Helper function to add or update # a "place quadruple"
AddOrUpdatePQ := function(L, pq)
local pp;
pp := PositionProperty(L, x -> x[1] = pq[1] and x[2] = pq[2]); if pp = fail then
Add(L, Immutable(pq)); else if L[pp][4] < pq[4] then
L[pp] := Immutable(pq); fi; fi; end;
# The RSym tester # The epsilon is chosen by the user
InstallMethod(RSymTestOp, "for a pregroup presentation, and a rational",
[IsPregroupPresentation, IsRat], function(pres, eps)
local i, j, rel, R, pplaces,
places, Ps, P, Q, Pq,
osrp, # a one-step reachable place
osrpp,
L,
zeta,
xi, psip, pp; # Make sure epsilon is a float # FIXME: To experiment and find out about rounding errors # we try running this thing with rationals
eps := Rat(eps); # FIXME: CAREFUL, if the zeta value is wrong, the RSymTester # does not work correctly
zeta := Minimum(Int(6 * (1 + eps) + 1) - 1,
LengthLongestRelator(pres));
Info(InfoWalrus, 10
, "RSymTest start");
Info(InfoWalrus, 10
, "zeta: ", zeta);
# Precompute some things so it doesn't show up in weird places # in the profiling data # Some of this we might want to compute on demand?
VertexGraphDistances(pres);
pplaces := Places(pres); if not IsEmpty(pplaces) then
OneStepReachablePlaces(pplaces[1]); fi;
for rel in Relators(pres) do
Info(InfoWalrus, 20
, "relator: ", ViewString(rel), "\n");
places := Places(rel); for Ps in places do
Info(InfoWalrus, 20
, " start place: "
, ViewString(Ps)
, "\n" );
L := [ [__ID(Ps), 0, 0, 0] ]; # This list is called L in the paper # This is the list of possible decompositions # The meaning of the components of the quadruples q is # - q[1] is a place # - q[2] is the distance of q[1] from Ps # - q[3] is the number of steps that q[1] is from Ps # - q[4] is a curvature value for i in [1..zeta] do
Info(InfoWalrus, 30
, STRINGIFY("L = ", ViewString(L)), ", i = ", i); for Pq in L do# Pq is for "PlaceQuadruple", which is # a silly name
Info(InfoWalrus, 30,
STRINGIFY("Considering: ", Pq)); if Pq[3] = i - 1then# Reachable in i - 1 steps
osrpp := OneStepReachablePlaces(pplaces[Pq[1]]); for osrp in Keys(osrpp) do
Info(InfoWalrus, 30,
STRINGIFY("OneStepReachable: ", osrp)); if Pq[2] + osrp[2] <= Length(rel) then
psip := Pq[4]
+ osrp[2] * (1 + eps) / Length(rel) # storing positive values -> subtract here
- osrpp[osrp];
Info(InfoWalrus, 30
, STRINGIFY("psi' = "
, Pq[4], " + "
, osrp[2] * (1+eps) / Length(rel), " - "
, osrpp[osrp], " = "
, psip, "\n")
); if psip < 0then elif (Pq[4] > 0) and
(osrp[1] = __ID(Ps)) and
(Pq[2] + osrp[2] = Length(rel)) then # Add the place that caused the failure
Add( L, Immutable( [ osrp[1], Pq[2] + osrp[2], i, psip ] ) );
return [fail, L, Pq]; else
AddOrUpdatePQ(L, [osrp[1], Pq[2] + osrp[2], i, psip]); fi; fi;
od; fi;
od;
od;
od;
od;
return true; end);
InstallGlobalFunction(RSymTest, function(args...)
local pg, pgp, rgreen, inv;
if Length(args) >= 2then if IsPregroupPresentation(args[1]) then
return RSymTestOp(args[1], args[2]); fi; if IsFreeGroup(args[1]) then
pgp := PregroupPresentationFromFp(args[1], args[2], args[3]);
return RSymTestOp(pgp, args[4]); fi; else # TODO: Usage message fi; end);
InstallMethod(IsHyperbolic, "for a free group, a list, a list, and a rational number",
[IsFreeGroup, IsObject, IsObject, IsRat],
{freeg, rrel, grel, eps} -> RSymTest(freeg, rrel, grel, eps));
InstallMethod(IsHyperbolic, "for a pregroup presentation, and a rational number",
[IsPregroupPresentation, IsRat],
{pres, eps} -> RSymTest(pres,eps));
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.25 Sekunden
(vorverarbeitet am 2026-10-12)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.