Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better dot #1007

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
10 changes: 9 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,17 @@ jobs:
# removed in the fullness of time.
LDFLAGS: "-pthread"
with:
GAP_PKGS_TO_BUILD: "digraphs io orb datastructures profiling"
GAP_PKGS_TO_BUILD: "Digraphs io orb datastructures profiling"
# TODO remove the following when graphviz is released
GAP_PKGS_TO_CLONE: "james-d-mitchell/Digraphs digraphs/graphviz"
GAPBRANCH: ${{ matrix.gap-branch }}
ABI: ${{ matrix.ABI }}
- name: "Checkout digraphs graphviz branch (TMP REMOVE)!"
run: |
cd $HOME/gap/pkg/Digraphs
git remote -v
git fetch origin graphviz --depth 1
git checkout graphviz
- name: "Build Semigroups"
uses: gap-actions/build-pkg@v1
with:
Expand Down
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
55 changes: 55 additions & 0 deletions doc/semicons.xml
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,61 @@ true]]></Example>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="FreeSemilattice">
<ManSection>
<Func Name="FreeSemilattice" Arg="[filt, ] n"/>
<Returns>
A free semilattice with <A>n</A> generators.
</Returns>
<Description>
If <A>n</A> is a positive integer, then this function returns a free
semilattice with <A>n</A> generators in the representation given by the
filter <A>filt</A>.

The optional argument <A>filt</A> may be one of the following:
<List>
<Item><C>IsTransformationSemigroup</C>
(the default, if <A>filt</A> is not specified),</Item>
<Item><C>IsTransformationMonoid</C>,</Item>
<Item><C>IsPartialPermSemigroup</C>,</Item>
<Item><C>IsPartialPermMonoid</C>,</Item>
<Item><C>IsFpSemigroup</C>,</Item>
<Item><C>IsFpMonoid</C>,</Item>
<Item><C>IsBipartitionSemigroup</C>,</Item>
<Item><C>IsBipartitionMonoid</C>,</Item>
<Item><C>IsPBRSemigroup</C>,</Item>
<Item><C>IsPBRMonoid</C>,</Item>
<Item><C>IsBooleanMatSemigroup</C>,</Item>
<Item><C>IsBooleanMatMonoid</C>,</Item>
<Item><C>IsNTPMatrixSemigroup</C>,</Item>
<Item><C>IsNTPMatrixMonoid</C>,</Item>
<Item><C>IsMaxPlusMatrixSemigroup</C>,</Item>
<Item><C>IsMaxPlusMatrixMonoid</C>,</Item>
<Item><C>IsMinPlusMatrixSemigroup</C>,</Item>
<Item><C>IsMinPlusMatrixMonoid</C>,</Item>
<Item><C>IsTropicalMaxPlusMatrixSemigroup</C>,</Item>
<Item><C>IsTropicalMaxPlusMatrixMonoid</C>,</Item>
<Item><C>IsTropicalMinPlusMatrixSemigroup</C>,</Item>
<Item><C>IsTropicalMinPlusMatrixMonoid</C>,</Item>
<Item><C>IsProjectiveMaxPlusMatrixSemigroup</C>,</Item>
<Item><C>IsProjectiveMaxPlusMatrixMonoid</C>,</Item>
<Item><C>IsIntegerMatrixSemigroup.</C></Item>
<Item><C>IsIntegerMatrixMonoid.</C></Item>
</List>

<Example><![CDATA[
gap> S := FreeSemilattice(IsTransformationSemigroup, 5);
<inverse transformation semigroup of size 31, degree 6 with 5
generators>
gap> T := FreeSemilattice(IsPartialPermSemigroup, 3);
<inverse partial perm semigroup of size 7, rank 3 with 3 generators>
gap> U := FreeSemilattice(IsBooleanMatSemigroup, 4);
<inverse semigroup of size 15, 5x5 boolean matrices with 4 generators>
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="ZeroSemigroup">
<ManSection>
<Func Name="ZeroSemigroup" Arg="[filt, ]n"/>
Expand Down
1 change: 1 addition & 0 deletions doc/z-chap07.xml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@
<#Include Label = "TrivialSemigroup">
<#Include Label = "MonogenicSemigroup">
<#Include Label = "RectangularBand">
<#Include Label = "FreeSemilattice">
<#Include Label = "ZeroSemigroup">
<#Include Label = "LeftZeroSemigroup">
<#Include Label = "BrandtSemigroup">
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
2 changes: 2 additions & 0 deletions gap/semigroups/semicons.gd
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ DeclareGlobalFunction("TrivialSemigroup");
DeclareConstructor("TrivialSemigroupCons", [IsSemigroup, IsInt]);
DeclareGlobalFunction("RectangularBand");
DeclareConstructor("RectangularBandCons", [IsSemigroup, IsPosInt, IsPosInt]);
DeclareGlobalFunction("FreeSemilattice");
DeclareConstructor("FreeSemilatticeCons", [IsSemigroup, IsPosInt]);
DeclareGlobalFunction("MonogenicSemigroup");
DeclareConstructor("MonogenicSemigroupCons", [IsSemigroup, IsPosInt, IsPosInt]);
DeclareGlobalFunction("ZeroSemigroup");
Expand Down
Loading
Loading