Skip to content

Commit 0eafd3d

Browse files
Replace Dot -> Graphviz
1 parent 3cb60b5 commit 0eafd3d

11 files changed

Lines changed: 1520 additions & 1183 deletions

File tree

PackageInfo.g

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ Dependencies := rec(
379379
NeededOtherPackages := [["datastructures", ">=0.2.5"],
380380
["digraphs", ">=1.6.2"],
381381
["genss", ">=1.6.5"],
382+
["graphviz", ">=0.0.0"],
382383
["images", ">=1.3.1"],
383384
["IO", ">=4.5.1"],
384385
["orb", ">=4.8.2"]],

doc/display.xml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -265,13 +265,15 @@ gap> FileString("t3.dot", DotString(S));
265265
gap> S := DualSymmetricInverseMonoid(4);
266266
<inverse block bijection monoid of degree 4 with 3 generators>
267267
gap> DotSemilatticeOfIdempotents(S);
268-
"//dot\ngraph graphname {\n node [shape=point]\nranksep=2;\nsubgraph \
269-
cluster_1{\n15 \n}\nsubgraph cluster_2{\n5 11 14 12 13 8 \n}\nsubgraph\
270-
cluster_3{\n2 10 6 3 4 9 7 \n}\nsubgraph cluster_4{\n1 \n}\n2 -- 1\n3\
271-
-- 1\n4 -- 1\n5 -- 2\n5 -- 3\n5 -- 4\n6 -- 1\n7 -- 1\n8 -- 2\n8 -- 6\
272-
\n8 -- 7\n9 -- 1\n10 -- 1\n11 -- 2\n11 -- 9\n11 -- 10\n12 -- 3\n12 -- \
273-
6\n12 -- 9\n13 -- 3\n13 -- 7\n13 -- 10\n14 -- 4\n14 -- 6\n14 -- 10\n15\
274-
-- 5\n15 -- 8\n15 -- 11\n15 -- 12\n15 -- 13\n15 -- 14\n }"]]></Example>
268+
"//dot\ngraph semilattice {\n\tnode[shape=point] ranksep=2 \nsubgraph \
269+
cluster_1 {\n\t15\n}\nsubgraph cluster_2 {\n\t5\n\t11\n\t14\n\t12\n\t1\
270+
3\n\t8\n}\nsubgraph cluster_3 {\n\t2\n\t10\n\t6\n\t3\n\t4\n\t9\n\t7\n}\
271+
\nsubgraph cluster_4 {\n\t1\n}\n\t2 -- 1\n\t3 -- 1\n\t4 -- 1\n\t5 -- 2\
272+
\n\t5 -- 3\n\t5 -- 4\n\t6 -- 1\n\t7 -- 1\n\t8 -- 2\n\t8 -- 6\n\t8 -- 7\
273+
\n\t9 -- 1\n\t10 -- 1\n\t11 -- 2\n\t11 -- 9\n\t11 -- 10\n\t12 -- 3\n\t\
274+
12 -- 6\n\t12 -- 9\n\t13 -- 3\n\t13 -- 7\n\t13 -- 10\n\t14 -- 4\n\t14 \
275+
-- 6\n\t14 -- 10\n\t15 -- 5\n\t15 -- 8\n\t15 -- 11\n\t15 -- 12\n\t15 -\
276+
- 13\n\t15 -- 14\n}\n"]]></Example>
275277
</Description>
276278
</ManSection>
277279
<#/GAPDoc>

etc/code-coverage-test-gap.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#!/usr/bin/env python3
2+
"""
3+
"""
4+
5+
import argparse, tempfile, subprocess, re, sys, os, webbrowser
6+
from os.path import exists, isdir, isfile
7+
8+
_ERR_PREFIX = "\033[31mcode-coverage-test-gap.py: error: "
9+
_INFO_PREFIX = "\033[40;38;5;82m"
10+
11+
_PARSER = argparse.ArgumentParser(
12+
prog="code-coverage-test-gap.py", usage="%(prog)s [options]"
13+
)
14+
_PARSER.add_argument(
15+
"tstfiles",
16+
nargs="+",
17+
type=str,
18+
help="the test files you want to check code coverage for"
19+
+ "(must be at least one)",
20+
)
21+
_PARSER.add_argument(
22+
"--gap-root",
23+
nargs="?",
24+
type=str,
25+
help="the gap root directory (default: ~/gap)",
26+
default="~/gap/",
27+
)
28+
_PARSER.add_argument(
29+
"--open",
30+
nargs="?",
31+
type=str,
32+
help=("open the html page for this file " + "(default: None)"),
33+
default=None,
34+
)
35+
36+
_ARGS = _PARSER.parse_args()
37+
if not _ARGS.gap_root[-1] == "/":
38+
_ARGS.gap_root += "/"
39+
40+
if exists("gap") and isdir("gap"):
41+
_PROFILE_DIR = "/gap/"
42+
elif exists("lib") and isdir("lib"):
43+
_PROFILE_DIR = "/lib/"
44+
else:
45+
sys.exit(_ERR_PREFIX + "no directory gap or lib to profile!\033[0m")
46+
47+
_ARGS.gap_root = os.path.expanduser(_ARGS.gap_root)
48+
if not (exists(_ARGS.gap_root) and isdir(_ARGS.gap_root)):
49+
sys.exit(_ERR_PREFIX + "can't find GAP root directory!\033[0m")
50+
51+
for f in _ARGS.tstfiles:
52+
if not (exists(f) and isfile(f)):
53+
sys.exit(_ERR_PREFIX + f + " does not exist!\033[0m")
54+
55+
_DIR = tempfile.mkdtemp()
56+
print(f"{_INFO_PREFIX}Using temporary directory: {_DIR}\033[0m")
57+
58+
_COMMANDS = 'echo "'
59+
for f in _ARGS.tstfiles:
60+
_COMMANDS += f'Test(\\"{f}\\");;\n'
61+
_COMMANDS += (
62+
'''UncoverageLineByLine();;
63+
LoadPackage(\\"profiling\\", false);;
64+
filesdir := \\"'''
65+
+ os.getcwd()
66+
+ _PROFILE_DIR
67+
+ """\\";;\n"""
68+
)
69+
_COMMANDS += 'outdir := \\"' + _DIR + '\\";;\n'
70+
_COMMANDS += 'x := ReadLineByLineProfile(\\"' + _DIR + '/profile.gz\\");;\n'
71+
_COMMANDS += 'OutputAnnotatedCodeCoverageFiles(x, filesdir, outdir);"'
72+
73+
pro1 = subprocess.Popen(_COMMANDS, stdout=subprocess.PIPE, shell=True)
74+
_RUN_GAP = _ARGS.gap_root + "gap -A -m 1g -T --cover " + _DIR + "/profile.gz"
75+
76+
try:
77+
pro2 = subprocess.Popen(_RUN_GAP, stdin=pro1.stdout, shell=True)
78+
pro2.wait()
79+
except KeyboardInterrupt:
80+
pro1.terminate()
81+
pro1.wait()
82+
pro2.terminate()
83+
pro2.wait()
84+
sys.exit("\033[31mKilled!\033[0m")
85+
except (subprocess.CalledProcessError, IOError, OSError):
86+
sys.exit(_ERR_PREFIX + "Something went wrong calling GAP!\033[0m")
87+
88+
suffix = ""
89+
if _ARGS.open:
90+
filename = (
91+
_DIR
92+
+ "/"
93+
+ os.getcwd().replace("/", "_")
94+
+ "_"
95+
+ _ARGS.open.replace("/", "_")
96+
+ ".html"
97+
)
98+
p = re.compile(r"<tr class='missed'><td><a name=\"line(\d+)\">")
99+
with open(filename, "r") as f:
100+
m = p.search(f.read())
101+
if m:
102+
suffix += f"#line{m.group(1)}"
103+
else:
104+
filename = _DIR + "/index.html"
105+
106+
if exists(filename) and isfile(filename):
107+
if _ARGS.open:
108+
filename += suffix
109+
try:
110+
webbrowser.get("safari").open(f"file://{filename}", new=2)
111+
except Exception:
112+
webbrowser.open(f"file://{filename}", new=2)
113+
else:
114+
sys.exit(f"\n{_ERR_PREFIX}Failed to open file://{filename}\033[0m")
115+
116+
print(f"\n{_INFO_PREFIX}SUCCESS!\033[0m")
117+
sys.exit(0)

gap/attributes/factor.gd

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,8 @@ DeclareOperation("NonTrivialFactorization",
1515
DeclareOperation("Factorization", [IsLambdaOrb, IsPosInt, IsPerm]);
1616
DeclareOperation("Factorization", [IsSemigroup, IsMultiplicativeElement]);
1717
DeclareOperation("TraceSchreierTreeForward", [IsSemigroupData, IsPosInt]);
18+
19+
DeclareOperation("MonoidFactorization",
20+
[IsMonoid, IsMultiplicativeElementWithOne]);
21+
DeclareOperation("MinimalMonoidFactorization",
22+
[IsMonoid, IsMultiplicativeElementWithOne]);

gap/attributes/factor.gi

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,3 +451,34 @@ function(S, x)
451451

452452
return word1;
453453
end);
454+
455+
SEMIGROUPS._MonoidFactorization := function(M, word)
456+
local pos, i;
457+
458+
pos := Position(GeneratorsOfSemigroup(M), One(M));
459+
if pos = fail then
460+
return word;
461+
fi;
462+
# Words are in terms of GeneratorsOfSemigroup(S) but we want it in terms of
463+
# GeneratorsOfMonoid(S), so we have to normalise
464+
i := 1;
465+
while i <= Length(word) do
466+
if word[i] = pos then
467+
Remove(word, i);
468+
else
469+
if word[i] > pos then
470+
word[i] := word[i] - 1;
471+
fi;
472+
i := i + 1;
473+
fi;
474+
od;
475+
return word;
476+
end;
477+
478+
InstallMethod(MonoidFactorization, "for a monoid and element-with-one",
479+
[IsMonoid, IsMultiplicativeElementWithOne],
480+
{M, x} -> SEMIGROUPS._MonoidFactorization(M, Factorization(M, x)));
481+
482+
InstallMethod(MinimalMonoidFactorization, "for a monoid and element-with-one",
483+
[IsMonoid, IsMultiplicativeElementWithOne],
484+
{M, x} -> SEMIGROUPS._MonoidFactorization(M, MinimalFactorization(M, x)));

gap/congruences/congwordgraph.gi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
## This file contains implementation for left, right, and two-sided
1111
## congruences that are defined in terms of a IsWordGraph.
1212

13+
# TODO promote this to a proper operation
1314
BindGlobal("_MonoidFactorization", function(M, x)
1415
local word, pos, i;
1516

gap/semigroups/semifp.gi

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -957,16 +957,27 @@ SEMIGROUPS.WordToExtRepObj := function(word)
957957
return ext_rep_obj;
958958
end;
959959

960-
SEMIGROUPS.ExtRepObjToString := function(ext_rep_obj)
961-
local alphabet, out, i;
962-
alphabet := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
960+
SEMIGROUPS.ExtRepObjToString := function(arg...)
961+
local ext_rep_obj, names, out, i;
962+
963+
if Length(arg) = 1 then
964+
ext_rep_obj := arg[1];
965+
names := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
966+
elif Length(arg) = 2 then
967+
ext_rep_obj := arg[1];
968+
names := Concatenation(arg[2]);
969+
else
970+
ErrorNoReturn("expected 1 or 2 arguments, found ", Length(arg));
971+
fi;
972+
963973
out := "";
964974
for i in [1, 3 .. Length(ext_rep_obj) - 1] do
965-
if ext_rep_obj[i] > Length(alphabet) then
975+
if ext_rep_obj[i] > Length(names) then
966976
ErrorNoReturn("the maximum value in an odd position of the ",
967-
"argument must be at most ", Length(alphabet));
977+
"argument must be at most ", Length(names), " found ",
978+
ext_rep_obj[i]);
968979
fi;
969-
Add(out, alphabet[ext_rep_obj[i]]);
980+
Add(out, names[ext_rep_obj[i]]);
970981
if ext_rep_obj[i + 1] > 1 then
971982
Append(out, " ^ ");
972983
Append(out, String(ext_rep_obj[i + 1]));

gap/tools/display.gd

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#############################################################################
22
##
33
## tools/display.gd
4-
## Copyright (C) 2013-2022 James D. Mitchell
4+
## Copyright (C) 2013-2024 James D. Mitchell
55
##
66
## Licensing information can be found in the README file of this package.
77
##
@@ -18,7 +18,24 @@ DeclareOperation("TexString", [IsObject, IsObject]);
1818
DeclareOperation("TikzLeftCayleyDigraph", [IsSemigroup]);
1919
DeclareOperation("TikzRightCayleyDigraph", [IsSemigroup]);
2020

21+
DeclareOperation("GraphvizDClasses", [IsSemigroup, IsRecord]);
22+
DeclareOperation("GraphvizDClasses", [IsSemigroup]);
23+
24+
DeclareOperation("GraphvizLeftCayleyDigraph", [IsSemigroup, IsHomogeneousList]);
25+
DeclareOperation("GraphvizLeftCayleyDigraph", [IsSemigroup]);
26+
DeclareOperation("GraphvizRightCayleyDigraph", [IsSemigroup, IsHomogeneousList]);
27+
DeclareOperation("GraphvizRightCayleyDigraph", [IsSemigroup]);
28+
DeclareOperation("DotLeftCayleyDigraph", [IsSemigroup, IsHomogeneousList]);
2129
DeclareOperation("DotLeftCayleyDigraph", [IsSemigroup]);
30+
DeclareOperation("DotRightCayleyDigraph", [IsSemigroup, IsHomogeneousList]);
2231
DeclareOperation("DotRightCayleyDigraph", [IsSemigroup]);
2332

33+
# TODO homogeneous list?
34+
DeclareOperation("GraphvizWordGraph", [IsDigraph]);
35+
DeclareOperation("GraphvizWordGraph", [IsDigraph, IsList, IsList]);
36+
37+
DeclareOperation("DotWordGraph", [IsDigraph]);
38+
DeclareOperation("DotWordGraph", [IsDigraph, IsList, IsList]);
39+
40+
DeclareAttribute("GraphvizSemilatticeOfIdempotents", IsInverseSemigroup);
2441
DeclareAttribute("DotSemilatticeOfIdempotents", IsInverseSemigroup);

0 commit comments

Comments
 (0)