Skip to content

Commit

Permalink
Replace Dot -> Graphviz
Browse files Browse the repository at this point in the history
  • Loading branch information
james-d-mitchell committed May 9, 2024
1 parent 3cb60b5 commit 0eafd3d
Show file tree
Hide file tree
Showing 11 changed files with 1,520 additions and 1,183 deletions.
1 change: 1 addition & 0 deletions PackageInfo.g
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ Dependencies := rec(
NeededOtherPackages := [["datastructures", ">=0.2.5"],
["digraphs", ">=1.6.2"],
["genss", ">=1.6.5"],
["graphviz", ">=0.0.0"],
["images", ">=1.3.1"],
["IO", ">=4.5.1"],
["orb", ">=4.8.2"]],
Expand Down
16 changes: 9 additions & 7 deletions doc/display.xml
Original file line number Diff line number Diff line change
Expand Up @@ -265,13 +265,15 @@ gap> FileString("t3.dot", DotString(S));
gap> S := DualSymmetricInverseMonoid(4);
<inverse block bijection monoid of degree 4 with 3 generators>
gap> DotSemilatticeOfIdempotents(S);
"//dot\ngraph graphname {\n node [shape=point]\nranksep=2;\nsubgraph \
cluster_1{\n15 \n}\nsubgraph cluster_2{\n5 11 14 12 13 8 \n}\nsubgraph\
cluster_3{\n2 10 6 3 4 9 7 \n}\nsubgraph cluster_4{\n1 \n}\n2 -- 1\n3\
-- 1\n4 -- 1\n5 -- 2\n5 -- 3\n5 -- 4\n6 -- 1\n7 -- 1\n8 -- 2\n8 -- 6\
\n8 -- 7\n9 -- 1\n10 -- 1\n11 -- 2\n11 -- 9\n11 -- 10\n12 -- 3\n12 -- \
6\n12 -- 9\n13 -- 3\n13 -- 7\n13 -- 10\n14 -- 4\n14 -- 6\n14 -- 10\n15\
-- 5\n15 -- 8\n15 -- 11\n15 -- 12\n15 -- 13\n15 -- 14\n }"]]></Example>
"//dot\ngraph semilattice {\n\tnode[shape=point] ranksep=2 \nsubgraph \
cluster_1 {\n\t15\n}\nsubgraph cluster_2 {\n\t5\n\t11\n\t14\n\t12\n\t1\
3\n\t8\n}\nsubgraph cluster_3 {\n\t2\n\t10\n\t6\n\t3\n\t4\n\t9\n\t7\n}\
\nsubgraph cluster_4 {\n\t1\n}\n\t2 -- 1\n\t3 -- 1\n\t4 -- 1\n\t5 -- 2\
\n\t5 -- 3\n\t5 -- 4\n\t6 -- 1\n\t7 -- 1\n\t8 -- 2\n\t8 -- 6\n\t8 -- 7\
\n\t9 -- 1\n\t10 -- 1\n\t11 -- 2\n\t11 -- 9\n\t11 -- 10\n\t12 -- 3\n\t\
12 -- 6\n\t12 -- 9\n\t13 -- 3\n\t13 -- 7\n\t13 -- 10\n\t14 -- 4\n\t14 \
-- 6\n\t14 -- 10\n\t15 -- 5\n\t15 -- 8\n\t15 -- 11\n\t15 -- 12\n\t15 -\
- 13\n\t15 -- 14\n}\n"]]></Example>
</Description>
</ManSection>
<#/GAPDoc>
Expand Down
117 changes: 117 additions & 0 deletions etc/code-coverage-test-gap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/usr/bin/env python3
"""
"""

import argparse, tempfile, subprocess, re, sys, os, webbrowser
from os.path import exists, isdir, isfile

_ERR_PREFIX = "\033[31mcode-coverage-test-gap.py: error: "
_INFO_PREFIX = "\033[40;38;5;82m"

_PARSER = argparse.ArgumentParser(
prog="code-coverage-test-gap.py", usage="%(prog)s [options]"
)
_PARSER.add_argument(
"tstfiles",
nargs="+",
type=str,
help="the test files you want to check code coverage for"
+ "(must be at least one)",
)
_PARSER.add_argument(
"--gap-root",
nargs="?",
type=str,
help="the gap root directory (default: ~/gap)",
default="~/gap/",
)
_PARSER.add_argument(
"--open",
nargs="?",
type=str,
help=("open the html page for this file " + "(default: None)"),
default=None,
)

_ARGS = _PARSER.parse_args()
if not _ARGS.gap_root[-1] == "/":
_ARGS.gap_root += "/"

if exists("gap") and isdir("gap"):
_PROFILE_DIR = "/gap/"
elif exists("lib") and isdir("lib"):
_PROFILE_DIR = "/lib/"
else:
sys.exit(_ERR_PREFIX + "no directory gap or lib to profile!\033[0m")

_ARGS.gap_root = os.path.expanduser(_ARGS.gap_root)
if not (exists(_ARGS.gap_root) and isdir(_ARGS.gap_root)):
sys.exit(_ERR_PREFIX + "can't find GAP root directory!\033[0m")

for f in _ARGS.tstfiles:
if not (exists(f) and isfile(f)):
sys.exit(_ERR_PREFIX + f + " does not exist!\033[0m")

_DIR = tempfile.mkdtemp()
print(f"{_INFO_PREFIX}Using temporary directory: {_DIR}\033[0m")

_COMMANDS = 'echo "'
for f in _ARGS.tstfiles:
_COMMANDS += f'Test(\\"{f}\\");;\n'
_COMMANDS += (
'''UncoverageLineByLine();;
LoadPackage(\\"profiling\\", false);;
filesdir := \\"'''
+ os.getcwd()
+ _PROFILE_DIR
+ """\\";;\n"""
)
_COMMANDS += 'outdir := \\"' + _DIR + '\\";;\n'
_COMMANDS += 'x := ReadLineByLineProfile(\\"' + _DIR + '/profile.gz\\");;\n'
_COMMANDS += 'OutputAnnotatedCodeCoverageFiles(x, filesdir, outdir);"'

pro1 = subprocess.Popen(_COMMANDS, stdout=subprocess.PIPE, shell=True)
_RUN_GAP = _ARGS.gap_root + "gap -A -m 1g -T --cover " + _DIR + "/profile.gz"

try:
pro2 = subprocess.Popen(_RUN_GAP, stdin=pro1.stdout, shell=True)
pro2.wait()
except KeyboardInterrupt:
pro1.terminate()
pro1.wait()
pro2.terminate()
pro2.wait()
sys.exit("\033[31mKilled!\033[0m")
except (subprocess.CalledProcessError, IOError, OSError):
sys.exit(_ERR_PREFIX + "Something went wrong calling GAP!\033[0m")

suffix = ""
if _ARGS.open:
filename = (
_DIR
+ "/"
+ os.getcwd().replace("/", "_")
+ "_"
+ _ARGS.open.replace("/", "_")
+ ".html"
)
p = re.compile(r"<tr class='missed'><td><a name=\"line(\d+)\">")
with open(filename, "r") as f:
m = p.search(f.read())
if m:
suffix += f"#line{m.group(1)}"
else:
filename = _DIR + "/index.html"

if exists(filename) and isfile(filename):
if _ARGS.open:
filename += suffix
try:
webbrowser.get("safari").open(f"file://{filename}", new=2)
except Exception:
webbrowser.open(f"file://{filename}", new=2)
else:
sys.exit(f"\n{_ERR_PREFIX}Failed to open file://{filename}\033[0m")

print(f"\n{_INFO_PREFIX}SUCCESS!\033[0m")
sys.exit(0)
5 changes: 5 additions & 0 deletions gap/attributes/factor.gd
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,8 @@ DeclareOperation("NonTrivialFactorization",
DeclareOperation("Factorization", [IsLambdaOrb, IsPosInt, IsPerm]);
DeclareOperation("Factorization", [IsSemigroup, IsMultiplicativeElement]);
DeclareOperation("TraceSchreierTreeForward", [IsSemigroupData, IsPosInt]);

DeclareOperation("MonoidFactorization",
[IsMonoid, IsMultiplicativeElementWithOne]);
DeclareOperation("MinimalMonoidFactorization",
[IsMonoid, IsMultiplicativeElementWithOne]);
31 changes: 31 additions & 0 deletions gap/attributes/factor.gi
Original file line number Diff line number Diff line change
Expand Up @@ -451,3 +451,34 @@ function(S, x)

return word1;
end);

SEMIGROUPS._MonoidFactorization := function(M, word)
local pos, i;

pos := Position(GeneratorsOfSemigroup(M), One(M));
if pos = fail then
return word;
fi;
# Words are in terms of GeneratorsOfSemigroup(S) but we want it in terms of
# GeneratorsOfMonoid(S), so we have to normalise
i := 1;
while i <= Length(word) do
if word[i] = pos then
Remove(word, i);
else
if word[i] > pos then
word[i] := word[i] - 1;
fi;
i := i + 1;
fi;
od;
return word;
end;

InstallMethod(MonoidFactorization, "for a monoid and element-with-one",
[IsMonoid, IsMultiplicativeElementWithOne],
{M, x} -> SEMIGROUPS._MonoidFactorization(M, Factorization(M, x)));

InstallMethod(MinimalMonoidFactorization, "for a monoid and element-with-one",
[IsMonoid, IsMultiplicativeElementWithOne],
{M, x} -> SEMIGROUPS._MonoidFactorization(M, MinimalFactorization(M, x)));
1 change: 1 addition & 0 deletions gap/congruences/congwordgraph.gi
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
## This file contains implementation for left, right, and two-sided
## congruences that are defined in terms of a IsWordGraph.

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

Expand Down
23 changes: 17 additions & 6 deletions gap/semigroups/semifp.gi
Original file line number Diff line number Diff line change
Expand Up @@ -957,16 +957,27 @@ SEMIGROUPS.WordToExtRepObj := function(word)
return ext_rep_obj;
end;

SEMIGROUPS.ExtRepObjToString := function(ext_rep_obj)
local alphabet, out, i;
alphabet := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
SEMIGROUPS.ExtRepObjToString := function(arg...)
local ext_rep_obj, names, out, i;

if Length(arg) = 1 then
ext_rep_obj := arg[1];
names := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
elif Length(arg) = 2 then
ext_rep_obj := arg[1];
names := Concatenation(arg[2]);
else
ErrorNoReturn("expected 1 or 2 arguments, found ", Length(arg));
fi;

out := "";
for i in [1, 3 .. Length(ext_rep_obj) - 1] do
if ext_rep_obj[i] > Length(alphabet) then
if ext_rep_obj[i] > Length(names) then
ErrorNoReturn("the maximum value in an odd position of the ",
"argument must be at most ", Length(alphabet));
"argument must be at most ", Length(names), " found ",
ext_rep_obj[i]);
fi;
Add(out, alphabet[ext_rep_obj[i]]);
Add(out, names[ext_rep_obj[i]]);
if ext_rep_obj[i + 1] > 1 then
Append(out, " ^ ");
Append(out, String(ext_rep_obj[i + 1]));
Expand Down
19 changes: 18 additions & 1 deletion gap/tools/display.gd
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#############################################################################
##
## tools/display.gd
## Copyright (C) 2013-2022 James D. Mitchell
## Copyright (C) 2013-2024 James D. Mitchell
##
## Licensing information can be found in the README file of this package.
##
Expand All @@ -18,7 +18,24 @@ DeclareOperation("TexString", [IsObject, IsObject]);
DeclareOperation("TikzLeftCayleyDigraph", [IsSemigroup]);
DeclareOperation("TikzRightCayleyDigraph", [IsSemigroup]);

DeclareOperation("GraphvizDClasses", [IsSemigroup, IsRecord]);
DeclareOperation("GraphvizDClasses", [IsSemigroup]);

DeclareOperation("GraphvizLeftCayleyDigraph", [IsSemigroup, IsHomogeneousList]);
DeclareOperation("GraphvizLeftCayleyDigraph", [IsSemigroup]);
DeclareOperation("GraphvizRightCayleyDigraph", [IsSemigroup, IsHomogeneousList]);
DeclareOperation("GraphvizRightCayleyDigraph", [IsSemigroup]);
DeclareOperation("DotLeftCayleyDigraph", [IsSemigroup, IsHomogeneousList]);
DeclareOperation("DotLeftCayleyDigraph", [IsSemigroup]);
DeclareOperation("DotRightCayleyDigraph", [IsSemigroup, IsHomogeneousList]);
DeclareOperation("DotRightCayleyDigraph", [IsSemigroup]);

# TODO homogeneous list?
DeclareOperation("GraphvizWordGraph", [IsDigraph]);
DeclareOperation("GraphvizWordGraph", [IsDigraph, IsList, IsList]);

DeclareOperation("DotWordGraph", [IsDigraph]);
DeclareOperation("DotWordGraph", [IsDigraph, IsList, IsList]);

DeclareAttribute("GraphvizSemilatticeOfIdempotents", IsInverseSemigroup);
DeclareAttribute("DotSemilatticeOfIdempotents", IsInverseSemigroup);
Loading

0 comments on commit 0eafd3d

Please sign in to comment.