diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
index 5c6ffe49..5a751301 100644
--- a/.github/workflows/CI.yml
+++ b/.github/workflows/CI.yml
@@ -25,11 +25,11 @@ jobs:
matrix:
gap-branch:
- master
+ - stable-4.13
- stable-4.12
- - stable-4.11
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: gap-actions/setup-gap@v2
with:
GAP_PKGS_TO_BUILD: "io profiling AttributeScheduler grape datastructures orb digraphs NautyTracesInterface"
@@ -38,8 +38,13 @@ jobs:
- uses: gap-actions/build-pkg@v1
- uses: gap-actions/build-pkg-docs@v1
- uses: gap-actions/run-pkg-tests@v2
+ - uses: gap-actions/run-pkg-tests@v2
+ with:
+ only-needed: true
- uses: gap-actions/process-coverage@v2
- - uses: codecov/codecov-action@v3
+ - uses: codecov/codecov-action@v4
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
# The documentation job
manual:
@@ -49,7 +54,7 @@ jobs:
steps:
- run: sudo apt-get update
- run: sudo apt-get install sed texlive-latex-base texlive-latex-recommended texlive-latex-extra texlive-extra-utils texlive-fonts-recommended texlive-fonts-extra tex4ht
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: gap-actions/setup-gap@v2
with:
GAP_PKGS_TO_BUILD: "io profiling AttributeScheduler grape datastructures orb digraphs NautyTracesInterface"
@@ -60,7 +65,7 @@ jobs:
with:
use-latex: 'true'
- name: 'Upload documentation'
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: manual
path: ./doc/manual.pdf
diff --git a/PackageInfo.g b/PackageInfo.g
index 94aa820c..bedb5e1d 100644
--- a/PackageInfo.g
+++ b/PackageInfo.g
@@ -66,6 +66,16 @@ Persons := [
PostalAddress := "--",
Place := "Aachen",
Institution := "Chair of Algebra and Representation Theory",
+ ),
+ rec(
+ IsAuthor := true,
+ IsMaintainer := true,
+ FirstNames := "Lukas",
+ LastName := "Schnelle",
+ Email := "lukas.schnelle1@rwth-aachen.de",
+ PostalAddress := "--",
+ Place := "Aachen",
+ Institution := "Chair of Algebra and Representation Theory",
),
rec(
LastName := "GAP Team",
@@ -105,14 +115,14 @@ AbstractHTML := "The SimplicialSurfaces package
PackageDoc := rec(
BookName := "SimplicialSurfaces",
ArchiveURLSubset := ["doc"],
- HTMLStart := "doc/chap0.html",
+ HTMLStart := "doc/chap0_mj.html",
PDFFile := "doc/manual.pdf",
SixFile := "doc/manual.six",
LongTitle := "Computation with simplicial surfaces and folding processes.",
),
Dependencies := rec(
- GAP := ">= 4.11",
+ GAP := ">= 4.12",
NeededOtherPackages := [ [ "Grape", ">=4.8.2" ], [ "AttributeScheduler", ">=2018.08.03" ], ["Digraphs", ">=1.1.1"],[ "NautyTracesInterface", ">=0.2" ]],
SuggestedOtherPackages := [ [ "GAPDoc", ">= 1.6" ], ["AutoDoc", ">=2019.05.20"], [ "IO", ">=2.2" ]],
ExternalConditions := [ ],
diff --git a/doc/images/_Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.pdf b/doc/images/_Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.pdf
new file mode 100644
index 00000000..b2d0a87d
Binary files /dev/null and b/doc/images/_Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.pdf differ
diff --git a/doc/images/_Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.svg b/doc/images/_Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.svg
new file mode 100644
index 00000000..5b8c940e
--- /dev/null
+++ b/doc/images/_Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.svg
@@ -0,0 +1,428 @@
+
+
+
+
diff --git a/doc/tikz-files/Image_Butterfly_Faithful_Monomorphism_Hexagon.tex b/doc/tikz-files/Image_Butterfly_Faithful_Monomorphism_Hexagon.tex
new file mode 100644
index 00000000..db621e50
--- /dev/null
+++ b/doc/tikz-files/Image_Butterfly_Faithful_Monomorphism_Hexagon.tex
@@ -0,0 +1,319 @@
+\documentclass{standalone}
+
+\pagestyle{empty}
+% This document contains the TikZ-header for all our LaTeX-computations.
+% It especially contains all global graphic parameters.
+
+\usepackage{amsmath, amssymb, amsfonts} % Standard Math-stuff
+
+\usepackage{ifthen}
+
+\usepackage{tikz}
+\usetikzlibrary{calc}
+\usetikzlibrary{positioning}
+\usetikzlibrary{shapes}
+\usetikzlibrary{patterns}
+
+
+% Sometimes we want to implement different behaviour for the generated
+% HTML-pictures (for example, shading is not supported in HTML).
+% For that we define a macro to check whether we run the code with
+% htlatex. The code comes from
+% https://tex.stackexchange.com/questions/93852/what-is-the-correct-way-to-check-for-latex-pdflatex-and-html-in-the-same-latex
+\makeatletter
+\edef\texforht{TT\noexpand\fi
+ \@ifpackageloaded{tex4ht}
+ {\noexpand\iftrue}
+ {\noexpand\iffalse}}
+\makeatother
+
+
+% Define a text=none option for nodes that ignores the given text, from
+% https://tex.stackexchange.com/questions/59354/no-text-none-in-tikz
+\makeatletter
+\newif\iftikz@node@phantom
+\tikzset{
+ phantom/.is if=tikz@node@phantom,
+ text/.code=%
+ \edef\tikz@temp{#1}%
+ \ifx\tikz@temp\tikz@nonetext
+ \tikz@node@phantomtrue
+ \else
+ \tikz@node@phantomfalse
+ \let\tikz@textcolor\tikz@temp
+ \fi
+}
+\usepackage{etoolbox}
+\patchcmd\tikz@fig@continue{\tikz@node@transformations}{%
+ \iftikz@node@phantom
+ \setbox\pgfnodeparttextbox\hbox{}
+ \fi\tikz@node@transformations}{}{}
+\makeatother
+
+% Find the angle of a given line (within TikZ)
+\newcommand{\tikzAngleOfLine}{\tikz@AngleOfLine}
+\def\tikz@AngleOfLine(#1)(#2)#3{%
+ \pgfmathanglebetweenpoints{%
+ \pgfpointanchor{#1}{center}}{%
+ \pgfpointanchor{#2}{center}}
+ \pgfmathsetmacro{#3}{\pgfmathresult}%
+}
+
+% Now we define the global styles
+% The global styles are defined nestedly. You have to give your tikzpicture
+% the global options [vertexStyle, edgeStyle, faceStyle] to activate them.
+%
+% You can disable labels by using the option nolabels, i.e.
+% vertexStyle=nolabels to deactivate vertex labels.
+%
+% If you want to have a specific style for your picture, you can also use
+% this specific meta-style instead of the general style. For example if you
+% want to use double edges in one single picture - no matter the style of
+% the rest of the document - you can use edgeDouble instead of edgeStyle.
+%
+% To set the default style, modify the vertexStyle/.default entry.
+
+% Vertex styles
+\tikzset{
+ vertexNodePlain/.style = {fill=#1, shape=circle, inner sep=0pt, minimum size=2pt, text=none},
+ vertexNodePlain/.default=gray,
+ vertexPlain/labels/.style = {
+ vertexNode/.style={vertexNodePlain=##1},
+ vertexLabel/.style={gray}
+ },
+ vertexPlain/nolabels/.style = {
+ vertexNode/.style={vertexNodePlain=##1},
+ vertexLabel/.style={text=none}
+ },
+ vertexPlain/.style = vertexPlain/#1,
+ vertexPlain/.default=labels
+}
+\tikzset{
+ vertexNodeNormal/.style = {fill=#1, shape=circle, inner sep=0pt, minimum size=4pt, text=none},
+ vertexNodeNormal/.default = blue,
+ vertexNormal/labels/.style = {
+ vertexNode/.style={vertexNodeNormal=##1},
+ vertexLabel/.style={blue}
+ },
+ vertexNormal/nolabels/.style = {
+ vertexNode/.style={vertexNodeNormal=##1},
+ vertexLabel/.style={text=none}
+ },
+ vertexNormal/.style = vertexNormal/#1,
+ vertexNormal/.default=labels
+}
+\tikzset{
+ vertexNodeBallShading/pdf/.style = {ball color=#1},
+ vertexNodeBallShading/svg/.style = {fill=#1},
+ vertexNodeBallShading/.code = {% Conditional shading depending whether we want pdf or svg output
+ \if\texforht
+ \tikzset{vertexNodeBallShading/svg=#1!90!black}
+ \else
+ \tikzset{vertexNodeBallShading/pdf=#1}
+ \fi
+ },
+ vertexNodeBall/.style = {shape=circle, vertexNodeBallShading=#1, inner sep=2pt, outer sep=0pt, minimum size=3pt, font=\tiny},
+ vertexNodeBall/.default = white,
+ vertexBall/labels/.style = {
+ vertexNode/.style={vertexNodeBall=##1, text=black},
+ vertexLabel/.style={text=none}
+ },
+ vertexBall/nolabels/.style = {
+ vertexNode/.style={vertexNodeBall=##1, text=none},
+ vertexLabel/.style={text=none}
+ },
+ vertexBall/.style = vertexBall/#1,
+ vertexBall/.default=labels
+}
+\tikzset{
+ vertexStyle/.style={vertexNormal=#1},
+ vertexStyle/.default = labels
+}
+
+
+% 1) optional: colour of vertex
+% 2) position of the vertex
+% 3) relative position of the node
+% 4) name of the vertex
+\newcommand{\vertexLabelR}[4][]{
+ \ifthenelse{ \equal{#1}{} }
+ { \node[vertexNode] (#2 name) at (#2) {#4}; }
+ { \node[vertexNode=#1] (#2 name) at (#2) {#4}; }
+ \node[vertexLabel, #3] at (#2) {#4};
+}
+% 1) optional: colour of vertex
+% 2) position of the vertex
+% 3) absolute position of the node
+% 4) name of the vertex
+\newcommand{\vertexLabelA}[4][]{
+ \ifthenelse{ \equal{#1}{} }
+ { \node[vertexNode] (#2 name) at (#2) {#4}; }
+ { \node[vertexNode=#1] (#2 name) at (#2) {#4}; }
+ \node[vertexLabel] at (#3) {#4};
+}
+
+
+% Edge styles
+% If you have trouble with the double-lines overlapping, this might (?) help:
+% https://tex.stackexchange.com/questions/288159/closing-the-ends-of-double-line-in-tikz
+\newcommand{\edgeLabelColor}{blue!20!white}
+\tikzset{
+ edgeLineNone/.style = {draw=none},
+ edgeLineNone/.default=black,
+ edgeNone/labels/.style = {
+ edge/.style = {edgeLineNone=##1},
+ edgeLabel/.style = {fill=\edgeLabelColor,font=\small}
+ },
+ edgeNone/nolabels/.style = {
+ edge/.style = {edgeLineNone=##1},
+ edgeLabel/.style = {text=none}
+ },
+ edgeNone/.style = edgeNone/#1,
+ edgeNone/.default = labels
+}
+\tikzset{
+ edgeLinePlain/.style={line join=round, draw=#1},
+ edgeLinePlain/.default=black,
+ edgePlain/labels/.style = {
+ edge/.style={edgeLinePlain=##1},
+ edgeLabel/.style={fill=\edgeLabelColor,font=\small}
+ },
+ edgePlain/nolabels/.style = {
+ edge/.style={edgeLinePlain=##1},
+ edgeLabel/.style={text=none}
+ },
+ edgePlain/.style = edgePlain/#1,
+ edgePlain/.default = labels
+}
+\tikzset{
+ edgeLineDouble/.style = {very thin, double=#1, double distance=.8pt, line join=round},
+ edgeLineDouble/.default=gray!90!white,
+ edgeDouble/labels/.style = {
+ edge/.style = {edgeLineDouble=##1},
+ edgeLabel/.style = {fill=\edgeLabelColor,font=\small}
+ },
+ edgeDouble/nolabels/.style = {
+ edge/.style = {edgeLineDouble=##1},
+ edgeLabel/.style = {text=none}
+ },
+ edgeDouble/.style = edgeDouble/#1,
+ edgeDouble/.default = labels
+}
+\tikzset{
+ edgeStyle/.style = {edgePlain=#1},
+ edgeStyle/.default = labels
+}
+
+% Face styles
+% Here we have an exception - the style face is always defined.
+%
+\newcommand{\faceColorY}{yellow!60!white} % yellow
+\newcommand{\faceColorB}{blue!60!white} % blue
+\newcommand{\faceColorC}{cyan!60} % cyan
+\newcommand{\faceColorR}{red!60!white} % red
+\newcommand{\faceColorG}{green!60!white} % green
+\newcommand{\faceColorO}{orange!50!yellow!70!white} % orange
+
+% define default face colour (and default swap colour)
+\newcommand{\faceColor}{\faceColorY}
+\newcommand{\faceColorSwap}{\faceColorC}
+
+% define secondary default colours (to use in a single section)
+\newcommand{\faceColorFirst}{green!40!white}
+\newcommand{\faceColorSecond}{gray!15!white}
+\newcommand{\faceColorThird}{red!17!white}
+\newcommand{\faceColorFourth}{olive!20!white}
+
+\tikzset{
+ face/.style = {fill=#1},
+ face/.default = \faceColor,
+ faceY/.style = {face=\faceColorY},
+ faceB/.style = {face=\faceColorB},
+ faceC/.style = {face=\faceColorC},
+ faceR/.style = {face=\faceColorR},
+ faceG/.style = {face=\faceColorG},
+ faceO/.style = {face=\faceColorO}
+}
+\tikzset{
+ faceStyle/labels/.style = {
+ faceLabel/.style = {}
+ },
+ faceStyle/nolabels/.style = {
+ faceLabel/.style = {text=none}
+ },
+ faceStyle/.style = faceStyle/#1,
+ faceStyle/.default = labels
+}
+\tikzset{ face/.style={fill=#1} }
+\tikzset{ faceSwap/.code=
+ \ifdefined\swapColors
+ \tikzset{face=\faceColorSwap}
+ \else
+ \tikzset{face=\faceColor}
+ \fi
+}
+
+
+
+\usepackage{hyperref}
+
+
+\begin{document}
+
+
+
+\begin{tikzpicture}[vertexStyle, edgeStyle, faceStyle]
+
+ \newcommand{\setupCoord}{
+ \coordinate (Z) at (0,0);
+ \foreach \i in {1,...,6}{
+ \coordinate (A\i) at (180-60*\i:2.5);
+ }
+ }
+
+
+ \begin{scope}[shift={(3.5,0)}]
+ \setupCoord
+
+ \draw[edge,face]
+ (Z) -- (A1) -- node[edgeLabel]{1} (A2) -- cycle
+ (Z) -- node[edgeLabel]{9} (A2) -- node[edgeLabel]{2} (A3) -- cycle
+ (Z) -- node[edgeLabel]{10} (A3) -- node[edgeLabel]{3} (A4) -- cycle
+ (Z) -- node[edgeLabel]{11} (A4) -- node[edgeLabel]{4} (A5) -- cycle
+ (Z) -- node[edgeLabel]{12} (A5) -- node[edgeLabel]{5} (A6) -- cycle
+ (Z) -- node[edgeLabel]{13} (A6) -- node[edgeLabel]{6} (A1) -- node[edgeLabel]{8} (Z);
+
+ \foreach \p/\r/\n in {1/above left/1, 2/above right/2, 3/right/3, 4/below right/4, 5/below left/5, 6/left/6}{
+ \vertexLabelR{A\p}{\r}{\n}
+ }
+ \vertexLabelR{Z}{above}{8}
+
+ \foreach \i/\j/\n in {1/2/I, 2/3/II, 3/4/III, 4/5/IV, 5/6/V, 6/1/VI}{
+ \node[faceLabel] at (barycentric cs:A\i=1,A\j=1,Z=1) {$\n$};
+ }
+ \end{scope}
+
+
+ \node at (0,0) {$\rightarrow$};
+
+
+ \begin{scope}[shift={(-3.5,0)}]
+ \setupCoord
+
+ \draw[edge,face]
+ (Z) -- node[edgeLabel]{5} (A1) -- node[edgeLabel]{1} (A2) -- cycle
+ (Z) -- node[edgeLabel]{6} (A2) -- node[edgeLabel]{2} (A3) -- cycle
+ (Z) -- node[edgeLabel]{7} (A3) -- node[edgeLabel]{3} (A4) -- node[edgeLabel]{4} (Z);
+
+ \foreach \p/\r/\n in {1/above left/1, 2/above right/2, 3/right/3, 4/below right/4}{
+ \vertexLabelR{A\p}{\r}{\n}
+ }
+ \vertexLabelR{Z}{below left}{5}
+
+ \foreach \i/\j/\n in {1/2/I, 2/3/II, 3/4/III}{
+ \node[faceLabel] at (barycentric cs:A\i=1,A\j=1,Z=1) {$\n$};
+ }
+ \end{scope}
+\end{tikzpicture}
+
+\end{document}
diff --git a/gap/Morphisms/morphisms.gd b/gap/Morphisms/morphisms.gd
index c4f8da79..0294f658 100644
--- a/gap/Morphisms/morphisms.gd
+++ b/gap/Morphisms/morphisms.gd
@@ -422,6 +422,93 @@ DeclareOperation( "PolygonalIdentityMorphism", [IsPolygonalComplex] );
DeclareAttribute( "InversePolygonalMorphism", IsPolygonalMorphism and IsBijective );
+#!
+#!
+#! A polygonal morphism or fail
+#!
+#! Given two simplicial surfaces surf1 and surf2, return a butterfly-faithful
+#! monomorphism from surf1 to surf2 if it exists. Otherwise return fail.
+#! A homomorphism of simplicial surfaces is called butterfly-faithful if the homomorphism
+#! when restricted to a butterfly, i.e. restricted to two incident faces of an inner edge,
+#! becomes a bijection onto another butterfly. In other words, every butterfly of
+#! surf1 is being preserved and does not degenerate in surf2.
+#! As an example, consider the 3-half-umbrella and 6-umbrella.
+#!
+#! <br><img src="./images/_Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.svg"> </img> <br>
+#!
+#!
+#! \begin{center}
+#! \includegraphics{images/_Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.pdf}
+#! \end{center}
+#!
+#!
+#! Image omitted in terminal text
+#!
+#! @ExampleSession
+#! gap> six := SimplicialSurfaceByDownwardIncidence(
+#! > [[1,2],[2,3],[3,4],[4,5],[5,6],[6,1],,[1,8],[2,8],[3,8],[4,8],[5,8],[6,8]],
+#! > [[1,8,9],[2,9,10],[3,10,11],[4,11,12],[5,12,13],[6,13,8]]);;
+#! gap> three := SimplicialSurfaceByDownwardIncidence(
+#! > [[1,2],[2,3],[3,4],[5,4],[1,5],[2,5],[3,5]], [[1,5,6],[2,6,7],[3,7,4]]);;
+#! gap> mor_3_to_6 := ButterflyFaithfulMonomorphismIntoSimplicialSurface(three,
+#! > six);;
+#! gap> VertexMapAsImageList(mor_3_to_6);
+#! [ 1, 2, 3, 4, 8 ]
+#! gap> EdgeMapAsImageList(mor_3_to_6);
+#! [ 1, 2, 3, 11, 8, 9, 10 ]
+#! gap> FaceMapAsImageList(mor_3_to_6);
+#! [ 1, 2, 3 ]
+#! @EndExampleSession
+#!
+#!
+#
+DeclareOperation( "ButterflyFaithfulMonomorphismIntoSimplicialSurface", [IsSimplicialSurface, IsSimplicialSurface]);
+
+#!
+#!
+#! A list of polygonal morphisms
+#!
+#! Given two simplicial surfaces surf1 and surf2, return a list of all
+#! butterfly-faithful monomorphisms from surf1 to surf2.
+#! A homomorphism of simplicial surfaces is called butterfly-faithful if the homomorphism
+#! when restricted to a butterfly, i.e. restricted to two incident faces of an inner edge,
+#! becomes a bijection onto another butterfly. In other words, every butterfly of
+#! surf1 is being preserved and does not degenerate in surf2.
+#! As an example, consider the 3-half-umbrella and 6-umbrella. We would expect 12
+#! butterfly-faithful monomorphisms, namely by aligning the 3-half umbrella with 3
+#! consecutive faces of the 6-umbrella. There are 6 ways to do this and another 6 if
+#! we flip the 3-half-umbrella first.
+#!
+#! <br><img src="./images/_Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.svg"> </img> <br>
+#!
+#!
+#! \begin{center}
+#! \includegraphics{images/_Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.pdf}
+#! \end{center}
+#!
+#!
+#! Image omitted in terminal text
+#!
+#! @ExampleSession
+#! gap> six := SimplicialSurfaceByDownwardIncidence(
+#! > [[1,2],[2,3],[3,4],[4,5],[5,6],[6,1],,[1,8],[2,8],[3,8],[4,8],[5,8],[6,8]],
+#! > [[1,8,9],[2,9,10],[3,10,11],[4,11,12],[5,12,13],[6,13,8]]);;
+#! gap> three := SimplicialSurfaceByDownwardIncidence(
+#! > [[1,2],[2,3],[3,4],[5,4],[1,5],[2,5],[3,5]], [[1,5,6],[2,6,7],[3,7,4]]);;
+#! gap> all_mor_3_to_6 := AllButterflyFaithfulMonomorphismsIntoSimplicialSurface(
+#! > three, six);;
+#! gap> Length(all_mor_3_to_6);
+#! 12
+#! @EndExampleSession
+#!
+#!
+#
+DeclareOperation( "AllButterflyFaithfulMonomorphismsIntoSimplicialSurface", [IsSimplicialSurface, IsSimplicialSurface]);
+
#! @Section Images and pre-images
#! @SectionLabel Morphisms_Images
#!
@@ -1285,5 +1372,3 @@ DeclareAttribute( "VEFLabelMapAsImageList", IsPolygonalMorphism );
# attribute VertexMapping
# attribute EdgeMapping
# attribute FaceMapping
-
-
diff --git a/gap/Morphisms/morphisms.gi b/gap/Morphisms/morphisms.gi
index 521168f0..2d88d3a5 100644
--- a/gap/Morphisms/morphisms.gi
+++ b/gap/Morphisms/morphisms.gi
@@ -478,8 +478,334 @@ InstallMethod( InverseGeneralMapping, "for a polygonal morphism",
return InversePolygonalMorphism(polMor);
end
+);
+
+BindGlobal("__SIMPLICIAL_PermuteList",
+ function(list, perm)
+ return List(list, x -> x^perm);
+ end
+);
+
+BindGlobal("__SIMPLICIAL_AllBijections",
+ function(list1, list2)
+ local res, AllPermutations, i, bijection, g, tmp;
+ res := [];
+ if not (Length(list1) = Length(list2)) then
+ return [];
+ else
+ AllPermutations := [];
+ for g in SymmetricGroup(list2) do
+ Add(AllPermutations, __SIMPLICIAL_PermuteList(list2, g));
+ od;
+ for bijection in AllPermutations do
+ tmp := [];
+ for i in [1..Length(list1)] do
+ tmp[list1[i]] := bijection[i];
+ od;
+ Add(res, tmp);
+ od;
+ return res;
+ fi;
+ end
+);
+
+BindGlobal("__SIMPLICIAL_ImageCatFromListmap",
+ function(map, x_list)
+ local res, i;
+ res := [];
+ for i in x_list do
+ if IsBound(map[i]) then
+ Add(res, map[i]);
+ fi;
+ od;
+ return res;
+ end
);
+BindGlobal("__SIMPLICIAL_PreImageFromListmap",
+ function(map, y)
+ local res, i;
+ res := [];
+ for i in [1..Length(map)] do
+ if IsBound(map[i]) and map[i] = y then
+ Add(res, i);
+ fi;
+ od;
+ return res;
+ end
+);
+
+BindGlobal("__SIMPLICIAL_PreImagesCatFromListmap",
+ function(map, y_list)
+ return Concatenation(List(y_list, y -> __SIMPLICIAL_PreImageFromListmap(map, y)));
+ end
+);
+
+BindGlobal("__SIMPLICIAL_PreImagesFromListmap",
+ function(map)
+ return __SIMPLICIAL_PreImagesCatFromListmap(map, Compacted(map));
+ end
+);
+
+BindGlobal("__SIMPLICIAL_AllOneFaceIsomorphisms",
+ function(face1, surface1, face2, surface2)
+ local res, e, vertex_maps, vertex_map, mapped_e, i, edge, edge_map, face_map;
+ res := [];
+ vertex_maps := __SIMPLICIAL_AllBijections(VerticesOfFace(surface1, face1),
+ VerticesOfFace(surface2, face2));
+ for vertex_map in vertex_maps do
+ edge_map := [];
+ e := List([1,2,3], i -> Set(VerticesOfEdge(surface1, EdgesOfFace(surface1, face1)[i])));
+ mapped_e := List(e, e_i -> Set(List(e_i, v -> vertex_map[v])));
+ for i in [1..3] do
+ for edge in EdgesOfFace(surface2, face2) do
+ if Set(VerticesOfEdge(surface2, edge)) = Set(mapped_e[i]) then
+ edge_map[EdgesOfFace(surface1, face1)[i]]:= edge;
+ break;
+ fi;
+ od;
+ od;
+ face_map := [];
+ face_map[face1] := face2;
+ Add(res, [vertex_map, edge_map, face_map]);
+ od;
+ return res;
+ end
+);
+
+BindGlobal("__SIMPLICIAL_UpdateListmap",
+ function(map, element, image_of_element) # is used to update maps with new images, also updates when used in if-clauses !
+ if not IsBound(map[element]) then
+ map[element] := image_of_element;
+ return true;
+ elif map[element] = image_of_element then
+ return true;
+ else
+ return false;
+ fi;
+ end
+);
+
+BindGlobal("__SIMPLICIAL_IsInjectiveListmap",
+ function(map)
+ return IsDuplicateFree(Compacted(map));
+ end
+);
+
+InstallMethod(ButterflyFaithfulMonomorphismIntoSimplicialSurface, "for two simplicial surfaces",
+ [IsSimplicialSurface, IsSimplicialSurface],
+ function(surface1, surface2)
+ local possible_vertex_maps, possible_monomorphisms, starting_face, image_starting_face, mapped_edges, mapped_faces,
+ remaining_faces, cur_edges, cur_edge, mapped_vertices, monomorphism, cur_face, face_map, edge_map,
+ vertex_map, i, new_face, new_image_face, is_correct_morphism, new_vertex, new_image_vertex, new_edges, new_image_edges,
+ cur_new_edge, cur_new_image_edge, finished_cur_edges, faces1, faces2, face_counter1, face_counter2, face_degrees1, face_degrees2,
+ min_degrees, min_pos, possible_image_faces;
+
+ faces1 := Filtered(Faces(surface1), face -> ForAll(VerticesOfFace(surface1, face), v -> IsInnerVertex(surface1, v)));
+ faces2 := Filtered(Faces(surface2), face -> ForAll(VerticesOfFace(surface2, face), v -> IsInnerVertex(surface2, v)));
+ possible_image_faces := Faces(surface2);
+ if not faces1 = [] then # inner vertex degrees heuristic
+ face_counter1 := List(faces1, face -> Set(List(VerticesOfFace(surface1, face), v -> DegreeOfVertex(surface1, v))));
+ face_counter2 := List(faces1, face -> Set(List(VerticesOfFace(surface2, face), v -> DegreeOfVertex(surface2, v))));
+ if ForAny(face_counter2, fdegs2 -> not fdegs2 in face_counter1) then
+ return fail;
+ else
+ min_pos := PositionMinimum(List(Collected(face_counter2), fdeg2 -> fdeg2[2]));
+ min_degrees := Collected(face_counter2)[min_pos][1];
+ starting_face := Filtered(faces1, face -> min_degrees = Set(List(VerticesOfFace(surface1, face), v -> DegreeOfVertex(surface1, v))))[1];
+ possible_image_faces := Filtered(faces2, face -> min_degrees = Set(List(VerticesOfFace(surface2, face), v -> DegreeOfVertex(surface2, v))));
+ fi;
+ else
+ starting_face := Faces(surface1)[1];
+ fi;
+
+ for image_starting_face in possible_image_faces do
+ possible_monomorphisms := __SIMPLICIAL_AllOneFaceIsomorphisms(starting_face, surface1,
+ image_starting_face, surface2);
+ for i in [1..Length(possible_monomorphisms)] do
+ is_correct_morphism := true;
+ monomorphism := possible_monomorphisms[i];
+ vertex_map := monomorphism[1];
+ edge_map := monomorphism[2];
+ face_map := monomorphism[3];
+
+ cur_edges := Filtered(EdgesOfFace(surface1, starting_face), e -> IsInnerEdge(surface1, e));
+ finished_cur_edges := [];
+ remaining_faces := Difference(Faces(surface1), [starting_face]);
+ mapped_faces := __SIMPLICIAL_PreImagesFromListmap(face_map);
+ while not IsEmpty(remaining_faces) do
+ cur_edge := cur_edges[1];
+ # update face_map
+ if Length(Difference(FacesOfEdge(surface2, edge_map[cur_edge]), face_map)) = 1 then
+ new_image_face := Difference(FacesOfEdge(surface2, edge_map[cur_edge]), face_map)[1];
+ else
+ is_correct_morphism := false;
+ break;
+ fi;
+ new_face := Difference(FacesOfEdge(surface1, cur_edge), mapped_faces)[1];
+
+ if not new_face in remaining_faces then
+ is_correct_morphism := false;
+ break;
+ fi;
+
+ if __SIMPLICIAL_UpdateListmap(face_map, new_face, new_image_face) = false or __SIMPLICIAL_IsInjectiveListmap(face_map) = false then
+ is_correct_morphism := false;
+ break;
+ fi;
+ mapped_faces := __SIMPLICIAL_PreImagesFromListmap(face_map);
+
+ # update vertex_map
+ new_vertex := Difference(VerticesOfFace(surface1, new_face), VerticesOfEdge(surface1, cur_edge))[1];
+ new_image_vertex := Difference(VerticesOfFace(surface2, new_image_face), VerticesOfEdge(surface2, edge_map[cur_edge]))[1];
+ if __SIMPLICIAL_UpdateListmap(vertex_map, new_vertex, new_image_vertex) = false or __SIMPLICIAL_IsInjectiveListmap(vertex_map) = false then
+ is_correct_morphism := false;
+ break;
+ fi;
+
+ # update edge_map
+ new_edges := Difference(EdgesOfFace(surface1, new_face), [cur_edge]);
+ new_image_edges := Difference(EdgesOfFace(surface2, new_image_face), [edge_map[cur_edge]]);
+ for cur_new_edge in new_edges do
+ for cur_new_image_edge in new_image_edges do
+ if Set(__SIMPLICIAL_ImageCatFromListmap(vertex_map, VerticesOfEdge(surface1, cur_new_edge))) = Set(VerticesOfEdge(surface2, cur_new_image_edge)) then
+ if __SIMPLICIAL_UpdateListmap(edge_map, cur_new_edge, cur_new_image_edge) = false or __SIMPLICIAL_IsInjectiveListmap(edge_map) = false then
+ is_correct_morphism := false;
+ fi;
+ if cur_new_edge in cur_edges then
+ Add(finished_cur_edges, cur_new_edge);
+ fi;
+ fi;
+ od;
+ od;
+ if is_correct_morphism = false then
+ break;
+ fi;
+
+ # update cur_edges
+ cur_edges := Union(cur_edges, Filtered(EdgesOfFace(surface1, new_face), e -> IsInnerEdge(surface1, e)));
+ Add(finished_cur_edges, cur_edge);
+ cur_edges := Difference(cur_edges, finished_cur_edges);
+
+ # update remaining_faces
+ remaining_faces := Difference(remaining_faces, [new_face]);
+ od;
+
+ if is_correct_morphism = true then
+ return PolygonalMorphismByLists(surface1, surface2, monomorphism[1], monomorphism[2], monomorphism[3]);
+ fi;
+ od;
+ od;
+ return fail;
+ end
+);
+
+InstallMethod(AllButterflyFaithfulMonomorphismsIntoSimplicialSurface, "for two simplicial surfaces",
+ [IsSimplicialSurface, IsSimplicialSurface],
+ function(surface1, surface2)
+ local possible_vertex_maps, possible_monomorphisms, starting_face, image_starting_face, mapped_edges, mapped_faces,
+ remaining_faces, cur_edges, cur_edge, mapped_vertices, monomorphism, cur_face, face_map, edge_map,
+ vertex_map, i, new_face, new_image_face, is_correct_morphism, new_vertex, new_image_vertex, new_edges, new_image_edges,
+ cur_new_edge, cur_new_image_edge, finished_cur_edges, faces1, faces2, face_counter1, face_counter2, face_degrees1, face_degrees2,
+ min_degrees, min_pos, possible_image_faces, res;
+
+ res := [];
+ faces1 := Filtered(Faces(surface1), face -> ForAll(VerticesOfFace(surface1, face), v -> IsInnerVertex(surface1, v)));
+ faces2 := Filtered(Faces(surface2), face -> ForAll(VerticesOfFace(surface2, face), v -> IsInnerVertex(surface2, v)));
+ possible_image_faces := Faces(surface2);
+ if not faces1 = [] then # inner vertex degrees heuristic
+ face_counter1 := List(faces1, face -> Set(List(VerticesOfFace(surface1, face), v -> DegreeOfVertex(surface1, v))));
+ face_counter2 := List(faces1, face -> Set(List(VerticesOfFace(surface2, face), v -> DegreeOfVertex(surface2, v))));
+ if ForAny(face_counter2, fdegs2 -> not fdegs2 in face_counter1) then
+ return res; # empty list
+ else
+ min_pos := PositionMinimum(List(Collected(face_counter2), fdeg2 -> fdeg2[2]));
+ min_degrees := Collected(face_counter2)[min_pos][1];
+ starting_face := Filtered(faces1, face -> min_degrees = Set(List(VerticesOfFace(surface1, face), v -> DegreeOfVertex(surface1, v))))[1];
+ possible_image_faces := Filtered(faces2, face -> min_degrees = Set(List(VerticesOfFace(surface2, face), v -> DegreeOfVertex(surface2, v))));
+ fi;
+ else
+ starting_face := Faces(surface1)[1];
+ fi;
+
+ for image_starting_face in possible_image_faces do
+ possible_monomorphisms := __SIMPLICIAL_AllOneFaceIsomorphisms(starting_face, surface1,
+ image_starting_face, surface2);
+ for i in [1..Length(possible_monomorphisms)] do
+ is_correct_morphism := true;
+ monomorphism := possible_monomorphisms[i];
+ vertex_map := monomorphism[1];
+ edge_map := monomorphism[2];
+ face_map := monomorphism[3];
+
+ cur_edges := Filtered(EdgesOfFace(surface1, starting_face), e -> IsInnerEdge(surface1, e));
+ finished_cur_edges := [];
+ remaining_faces := Difference(Faces(surface1), [starting_face]);
+ mapped_faces := __SIMPLICIAL_PreImagesFromListmap(face_map);
+ while not IsEmpty(remaining_faces) do
+ cur_edge := cur_edges[1];
+ if Length(Difference(FacesOfEdge(surface2, edge_map[cur_edge]), face_map)) = 1 then
+ new_image_face := Difference(FacesOfEdge(surface2, edge_map[cur_edge]), face_map)[1];
+ else
+ is_correct_morphism := false;
+ break;
+ fi;
+ new_face := Difference(FacesOfEdge(surface1, cur_edge), mapped_faces)[1];
+
+ if not new_face in remaining_faces then
+ is_correct_morphism := false;
+ break;
+ fi;
+
+ if __SIMPLICIAL_UpdateListmap(face_map, new_face, new_image_face) = false or __SIMPLICIAL_IsInjectiveListmap(face_map) = false then
+ is_correct_morphism := false;
+ break;
+ fi;
+ mapped_faces := __SIMPLICIAL_PreImagesFromListmap(face_map);
+
+ new_vertex := Difference(VerticesOfFace(surface1, new_face), VerticesOfEdge(surface1, cur_edge))[1];
+ new_image_vertex := Difference(VerticesOfFace(surface2, new_image_face), VerticesOfEdge(surface2, edge_map[cur_edge]))[1];
+ if __SIMPLICIAL_UpdateListmap(vertex_map, new_vertex, new_image_vertex) = false or __SIMPLICIAL_IsInjectiveListmap(vertex_map) = false then
+ is_correct_morphism := false;
+ break;
+ fi;
+
+ # update edge_map
+ new_edges := Difference(EdgesOfFace(surface1, new_face), [cur_edge]);
+ new_image_edges := Difference(EdgesOfFace(surface2, new_image_face), [edge_map[cur_edge]]);
+ for cur_new_edge in new_edges do
+ for cur_new_image_edge in new_image_edges do
+ if Set(__SIMPLICIAL_ImageCatFromListmap(vertex_map, VerticesOfEdge(surface1, cur_new_edge))) = Set(VerticesOfEdge(surface2, cur_new_image_edge)) then
+ if __SIMPLICIAL_UpdateListmap(edge_map, cur_new_edge, cur_new_image_edge) = false or __SIMPLICIAL_IsInjectiveListmap(edge_map) = false then
+ is_correct_morphism := false;
+ fi;
+ if cur_new_edge in cur_edges then
+ Add(finished_cur_edges, cur_new_edge);
+ fi;
+ fi;
+ od;
+ od;
+ if is_correct_morphism = false then
+ break;
+ fi;
+
+ # update cur_edges
+ cur_edges := Union(cur_edges, Filtered(EdgesOfFace(surface1, new_face), e -> IsInnerEdge(surface1, e)));
+ Add(finished_cur_edges, cur_edge);
+ cur_edges := Difference(cur_edges, finished_cur_edges);
+
+ # update remaining_faces
+ remaining_faces := Difference(remaining_faces, [new_face]);
+ od;
+
+ if is_correct_morphism = true then
+ Add(res,PolygonalMorphismByLists(surface1, surface2, monomorphism[1], monomorphism[2], monomorphism[3]));
+ fi;
+ od;
+ od;
+ return res;
+ end
+);
##
## End of constructions
diff --git a/gap/Paths/paths.gd b/gap/Paths/paths.gd
index 4f297de6..da8f801f 100644
--- a/gap/Paths/paths.gd
+++ b/gap/Paths/paths.gd
@@ -600,13 +600,13 @@ DeclareAttribute( "AssociatedPolygonalComplex", IsVertexEdgePath );
#!
#! Image omitted in terminal text
#!
-#! @BeginExampleSession
+#! @BeginLogSession
#! gap> butterfly:=SimplicialSurfaceByDownwardIncidence(
#! > [[1,2],[1,3],[2,3],[3,4],[1,4]],[[1,2,3],[2,4,5]]);;
#! gap> AllClosedVertexEdgePaths(butterfly);
#! [ ( v3, E2, v1, E5, v4, E4, v3 ), ( v3, E3, v2, E1, v1, E2, v3 ),
#! ( v3, E3, v2, E1, v1, E5, v4, E4, v3 ) ]
-#! @EndExampleSession
+#! @EndLogSession
#! @Returns a list of vertex-edge-paths
#! @Arguments complex
DeclareOperation( "AllClosedVertexEdgePaths", [IsTwistedPolygonalComplex] );
@@ -1303,10 +1303,10 @@ DeclareAttribute( "AllThreeWaistsOfComplex", IsTwistedPolygonalComplex);
#! The definition of a waist is given at the beginning of section .
#!
#! For example, consider the double tetrahedron from the start of section :
-#! @BeginExampleSession
+#! @BeginLogSession
#! gap> AllWaistsOfComplex(doubleTetra);
#! [ ( v4, E10, v5, E8, v3, E7, v4 ), ( v6, E12, v5, E8, v3, E9, v6 ) ]
-#! @EndExampleSession
+#! @EndLogSession
#!
#! @Returns a set of closed vertex-edge-paths
#! @Arguments complex
diff --git a/gap/Paths/paths.gi b/gap/Paths/paths.gi
index 5fe355e1..fb2419f0 100644
--- a/gap/Paths/paths.gi
+++ b/gap/Paths/paths.gi
@@ -329,7 +329,7 @@ InstallMethod(ConcatenationOfPaths, "for a twisted polygonal complex and two ver
if Last(VerticesAsList(path1))<>VerticesAsList(path2)[1] then
Error("ConcatenationOfPaths: The last vertex of the first path has to be the first vertex of the second path");
fi;
- edges:=Union(EdgesAsList(path1), EdgesAsList(path2));
+ edges:=Concatenation(EdgesAsList(path1),EdgesAsList(path2));
return VertexEdgePathByEdges(surface, edges);
end
);
diff --git a/gap/PolygonalComplexes/animating.gd b/gap/PolygonalComplexes/animating.gd
index 67ce9b83..f01b0e32 100644
--- a/gap/PolygonalComplexes/animating.gd
+++ b/gap/PolygonalComplexes/animating.gd
@@ -143,12 +143,15 @@ DeclareOperation( "SetVertexCoordinates3DNC", [IsSimplicialSurface, IsList, IsRe
#! The 3D-coordinates of vertex vertex has to have the format [x,y,z].
#! If the format of the coordinates is not correct, then an error is shown.
#! This can happen, if the NC version is used to store the 3D-coordinates.
-#! The NC-version does not check the coordinate format saved in the print record.
+#! The NC-version does not check the coordinate format saved in the print record.
+#! The GetAllVertexCoordinates3DNC method returns all coordinates from the print record without checking them as a list.
#! @Returns a list
#! @Arguments surface, vertex, printRecord
DeclareOperation( "GetVertexCoordinates3D", [IsSimplicialSurface, IsPosInt, IsRecord] );
#! @Arguments surface, vertex, printRecord
DeclareOperation( "GetVertexCoordinates3DNC", [IsSimplicialSurface, IsPosInt, IsRecord] );
+#! @Arguments surface, printRecord
+DeclareOperation( "GetAllVertexCoordinates3DNC", [IsSimplicialSurface, IsRecord] );
#! @EndGroup
#! @BeginGroup DrawSurfaceToJavaScript
diff --git a/gap/PolygonalComplexes/animating.gi b/gap/PolygonalComplexes/animating.gi
index 9a01ddd2..d0e8c648 100644
--- a/gap/PolygonalComplexes/animating.gi
+++ b/gap/PolygonalComplexes/animating.gi
@@ -88,6 +88,14 @@ InstallMethod( GetVertexCoordinates3DNC,
RedispatchOnCondition(GetVertexCoordinates3DNC, true, [IsTwistedPolygonalComplex, IsPosInt, IsRecord],
[IsSimplicialSurface], 0);
+InstallMethod( GetAllVertexCoordinates3DNC,
+ "for a simplicial surface and a record",
+ [IsSimplicialSurface, IsRecord],
+ function(surface, printRecord)
+ return printRecord.vertexCoordinates3D;
+ end
+);
+
InstallMethod( CalculateParametersOfInnerCircle,
"for a simplicial surface and a record",
diff --git a/gap/PolygonalComplexes/drawing.gd b/gap/PolygonalComplexes/drawing.gd
index a973a60c..662dae41 100644
--- a/gap/PolygonalComplexes/drawing.gd
+++ b/gap/PolygonalComplexes/drawing.gd
@@ -1303,7 +1303,7 @@ DrawFacegraphToTikz( tetra, "facegraph_oct_rescaled", pr);;
#! work:
#!
#! @BeginLog
-tetra :=SimplicialSurfaceByVerticesInFaces([[1,2,3],[1,2,4],
+tetra := SimplicialSurfaceByVerticesInFaces([[1,2,3],[1,2,4],
[1,3,4],[2,3,4]]);;
DrawFacegraphToTikz(tetra, "facegraph_tetrahedron");;
#! @EndLog
@@ -1344,12 +1344,10 @@ DrawFacegraphToTikz(tetra,
#!
#! Image omitted in terminal text
#!
-#!
#!
#!
#! @EndChunk
-
#! @BeginChunk DrawFacegraphToTikz_Geodesics
#! This subsection covers the usage of the parameter that adds geodesics into
#! the drawings of DrawFacegraphToTikz
@@ -1429,5 +1427,4 @@ DrawFacegraphToTikz( oct,
#! is false) the generated tex-file will only consist of a
#! tikzpicture without header (it is not possible to compile it on
#! its own).
-#! @EndChunk
-
+#! @EndChunk
\ No newline at end of file
diff --git a/gap/PolygonalComplexes/drawing.gi b/gap/PolygonalComplexes/drawing.gi
index f6942b07..a7202043 100644
--- a/gap/PolygonalComplexes/drawing.gi
+++ b/gap/PolygonalComplexes/drawing.gi
@@ -2022,5 +2022,3 @@ InstallOtherMethod( DrawFacegraphToTikz,
return DrawFacegraphToTikz(surface,file,rec());
end
);
-
-
diff --git a/gap/PolygonalComplexes/embedding.gd b/gap/PolygonalComplexes/embedding.gd
index 95e41cdd..1fe18f8f 100644
--- a/gap/PolygonalComplexes/embedding.gd
+++ b/gap/PolygonalComplexes/embedding.gd
@@ -382,4 +382,4 @@ DeclareOperation( "DrawFacegraphToTikz", [IsSimplicialSurface ,IsString,IsRecord
#! @Subsection Output control
#! @SubsectionLabel DrawFacegraphToTikz_Output
-#! @InsertChunk DrawFacegraphToTikz_Output
+#! @InsertChunk DrawFacegraphToTikz_Output
\ No newline at end of file
diff --git a/gap/PolygonalComplexes/graphs.gd b/gap/PolygonalComplexes/graphs.gd
index ed76b65b..8b168352 100644
--- a/gap/PolygonalComplexes/graphs.gd
+++ b/gap/PolygonalComplexes/graphs.gd
@@ -441,13 +441,13 @@ DeclareAttribute( "FaceNautyGraph", IsPolygonalComplex );
#! Image omitted in terminal text
#!
#!
-#! @BeginExampleSession
+#! @BeginLogSession
#! gap> digraph:=CompleteDigraph(4);;
#! gap> tet1 := AllSimplicialSurfacesOfDigraph(digraph,true);
#! [ simplicial surface (4 vertices, 6 edges, and 4 faces) ]
#! gap> IsIsomorphic(tet1[1],Tetrahedron());
#! true
-#! @EndExampleSession
+#! @EndLogSession
#!
#! So the only vertex-faithful simplicial surface of the digraph is the tetrahedron.
#! But there is another simplicial surface, which is not vertex-faithful:
diff --git a/gap/utilities.g b/gap/utilities.g
index a50a15f2..7329a951 100644
--- a/gap/utilities.g
+++ b/gap/utilities.g
@@ -46,3 +46,65 @@ BindGlobal( "__SIMPLICIAL_ListToCycle",
);
+
+#############################################################################
+##
+#F LexicographicallyLeastDyclet . . . . . . . lexicographically least dyclet
+##
+## A dyclet represents the orbit of a list under the diherdral group of the
+## list. Find the lexicographically least representative of the dyclet.
+##
+
+# called for lists of sets
+BindGlobal( "__SIMPLICIAL_LexicographicallyLeastDyclet",
+ function(dyclet)
+
+ local n, min_dyclet, k, perm, mirror_dyclet;
+
+ if (Filtered(dyclet,i-> not IsInt(i))<>[]) or (Length(dyclet)=0) then
+ Error("Dyclet must be a list of integers");
+ return fail;
+ fi;
+ n := Size(dyclet);
+ # current candidate for minimal dyclet
+ min_dyclet := ShallowCopy(dyclet);
+ perm := Reversed(dyclet);
+ if perm < min_dyclet then min_dyclet := perm; fi;
+
+ # Generate all cyclic permutations and their mirror images
+ for k in [1..n-1] do
+ perm := Concatenation(dyclet{[1+k..n]}, dyclet{[1..k]});
+ mirror_dyclet := Reversed(perm);
+
+ if perm < min_dyclet then
+ min_dyclet := perm;
+ fi;
+
+ if mirror_dyclet < min_dyclet then
+ min_dyclet := mirror_dyclet;
+ fi;
+ od;
+
+ return min_dyclet;
+end
+);
+
+
+#############################################################################
+##
+#F LtDyclet . . . . . . . . . . . . less than comparisons of dyclets
+##
+BindGlobal( "__SIMPLICIAL_LtDyclet",
+ function( dyc1, dyc2 )
+
+ if __SIMPLICIAL_LexicographicallyLeastDyclet(dyc1)
+ < __SIMPLICIAL_LexicographicallyLeastDyclet(dyc2) then return true;
+ fi;
+
+ return false;
+
+end
+);
+
+
+