From 2b47fbb61cf370bddf9d56bf9a92335c5b7c507f Mon Sep 17 00:00:00 2001 From: Flynn Fehre Date: Thu, 9 Mar 2023 19:40:04 +0100 Subject: [PATCH 01/44] Added DrawConvexFacegraphToTikz --- doc/Image_convex_facegraph_Double6Gon.tex | 47 +++++ gap/PolygonalComplexes/drawing.gd | 17 ++ gap/PolygonalComplexes/drawing.gi | 228 ++++++++++++++++++++++ gap/PolygonalComplexes/embedding.gd | 64 ++++++ 4 files changed, 356 insertions(+) create mode 100644 doc/Image_convex_facegraph_Double6Gon.tex diff --git a/doc/Image_convex_facegraph_Double6Gon.tex b/doc/Image_convex_facegraph_Double6Gon.tex new file mode 100644 index 00000000..a919f0e3 --- /dev/null +++ b/doc/Image_convex_facegraph_Double6Gon.tex @@ -0,0 +1,47 @@ +\begin{tikzpicture}[vertexBall, edgeDouble=nolabels, faceStyle=nolabels, scale=4] + +\coordinate (V1) at (1. , 0.); +\coordinate (V2) at (0.5000000010362841 , 0.8660254031861397); +\coordinate (V3) at (-0.4999999979274318 , 0.8660254049810364); +\coordinate (V4) at (-1. , 3.589793029841612e-09); +\coordinate (V5) at (-0.5000000041451365 , -0.866025401391243); +\coordinate (V6) at (0.4999999948185802 , -0.8660254067759328); +\coordinate (V7) at (0.8333333326424773 , -5.982988363998724e-10); +\coordinate (V8) at (0.3888888898100303 , 0.7216878361878827); +\coordinate (V9) at (-0.4351851836499495 , 0.6976315766169703); +\coordinate (V10) at (-0.8225308646325142 , -0.02806563506918342); +\coordinate (V11) at (-0.3870884810657467 , -0.7263654412350147); +\coordinate (V12) at (0.4077074718085085 , -0.698411178156174); +\draw[edge] (V1) -- node[edgeLabel] {$1$} (V6); +\draw[edge] (V1) -- node[edgeLabel] {$2$} (V2); +\draw[edge] (V2) -- node[edgeLabel] {$3$} (V3); +\draw[edge] (V3) -- node[edgeLabel] {$4$} (V4); +\draw[edge] (V4) -- node[edgeLabel] {$5$} (V5); +\draw[edge] (V5) -- node[edgeLabel] {$6$} (V6); +\draw[edge] (V1) -- node[edgeLabel] {$7$} (V7); +\draw[edge] (V6) -- node[edgeLabel] {$8$} (V12); +\draw[edge] (V7) -- node[edgeLabel] {$9$} (V12); +\draw[edge] (V2) -- node[edgeLabel] {$10$} (V8); +\draw[edge] (V7) -- node[edgeLabel] {$11$} (V8); +\draw[edge] (V3) -- node[edgeLabel] {$12$} (V9); +\draw[edge] (V8) -- node[edgeLabel] {$13$} (V9); +\draw[edge] (V4) -- node[edgeLabel] {$14$} (V10); +\draw[edge] (V9) -- node[edgeLabel] {$15$} (V10); +\draw[edge] (V5) -- node[edgeLabel] {$16$} (V11); +\draw[edge] (V10) -- node[edgeLabel] {$17$} (V11); +\draw[edge] (V11) -- node[edgeLabel] {$18$} (V12); +% Draw the faces +\vertexLabelR{V1}{left}{$1$} +\vertexLabelR{V2}{left}{$2$} +\vertexLabelR{V3}{left}{$3$} +\vertexLabelR{V4}{left}{$4$} +\vertexLabelR{V5}{left}{$5$} +\vertexLabelR{V6}{left}{$6$} +\vertexLabelR{V7}{left}{$7$} +\vertexLabelR{V8}{left}{$8$} +\vertexLabelR{V9}{left}{$9$} +\vertexLabelR{V10}{left}{$10$} +\vertexLabelR{V11}{left}{$11$} +\vertexLabelR{V12}{left}{$12$} +\end{tikzpicture} + diff --git a/gap/PolygonalComplexes/drawing.gd b/gap/PolygonalComplexes/drawing.gd index e50ce384..1f09d3f9 100644 --- a/gap/PolygonalComplexes/drawing.gd +++ b/gap/PolygonalComplexes/drawing.gd @@ -999,3 +999,20 @@ DrawFacegraphToTikz( oct, #! its own). #! @EndChunk +#! @BeginChunk DrawConvexFacegraphToTikz_example +#! @BeginLog +double6Gon := SimplicialSurfaceByVerticesInFaces([[1,2,3],[1,3,4],[1,4,5], +[1,5,6],[1,6,7],[1,2,7],[2,3,8],[3,4,8],[4,5,8],[5,6,8],[6,7,8],[2,7,8]]);; +#! @EndLog +#! +#! +#! \input{Image_Double6gon.tex} +#! +#! @BeginLog +DrawConvexFacegraphToTikz( double6Gon, "convex_facegraph_Double6Gon.tex" );; +#! @EndLog +#! +#! +#! \input{Image_convex_facegraph_Double6Gon.tex} +#! +#! @EndChunk \ No newline at end of file diff --git a/gap/PolygonalComplexes/drawing.gi b/gap/PolygonalComplexes/drawing.gi index f6942b07..427b5dec 100644 --- a/gap/PolygonalComplexes/drawing.gi +++ b/gap/PolygonalComplexes/drawing.gi @@ -2024,3 +2024,231 @@ InstallOtherMethod( DrawFacegraphToTikz, ); +InstallMethod( DrawConvexFacegraphToTikz, + "for a closed vertex-faithful simplicial sphere, a file name and a record", + [IsSimplicialSurface, IsString, IsRecord], + function(surf, name, record) + local graph, SplitListPosition, ThreeSplitListPosition, InFilterFunc, IntersectionFilterFunc, CorrectFacesOfVertexFilter, WeightedCentric, TwoWeightedCentric, MainHelp, RegularPolygon, DrawConvexFaceGraph, DrawGraph; + if not( IsClosedSurface(surf) and IsVertexFaithful(surf) and EulerCharacteristic(surf)=2) and not IsBound(printRecord.faceCoordinates2D) then + return fail; + fi; + + SplitListPosition := function(list, v) # help function + local i, res1, res2; + res1:=[]; + res2:=[]; + for i in [2..v] do + Add(res1,list[i]); + od; + for i in [v..Length(list)] do + Add(res2, list[i]); + od; + Add(res1,list[1]); + Add(res2, list[1]); + return [res1,res2]; + end; + + ThreeSplitListPosition := function(list, v, w) # helpt function + local i, res1, res2, res3; + if w > v then + res1 := []; + res2 := []; + res3 := []; + for i in [2..v] do + Add(res1,list[i]); + od; + for i in [v..w] do + Add(res2, list[i]); + od; + for i in [w..Length(list)] do + Add(res3, list[i]); + od; + Add(res1, list[1]); + Add(res2, list[1]); + Add(res3, list[1]); + elif w < v then + res1 := []; + res2 := []; + res3 := []; + for i in [2..w] do + Add(res1,list[i]); + od; + for i in [w..v] do + Add(res2, list[i]); + od; + for i in [v..Length(list)] do + Add(res3, list[i]); + od; + Add(res1, list[1]); + Add(res2, list[1]); + Add(res3, list[1]); + fi; + return [res1, res2, res3]; + end; + + InFilterFunc := function(cur1, cur2, list) # help function + if cur1 in list and cur2 in list then + return true; + else + return false; + fi; + end; + + IntersectionFilterFunc := function(faceGraph, list) # help function + if not IsEmpty(Intersection(faceGraph, list)) then + return true; + else + return false; + fi; + end; + + CorrectFacesOfVertexFilter := function(cur1, cur2, faceGraph, list) # help function + return InFilterFunc(cur1, cur2, list) and IntersectionFilterFunc(faceGraph, list); + end; + + WeightedCentric := function(list) # help function + return Float(2/3)*list[1]+Float(1/6)*(list[2]+list[3]); + end; + + TwoWeightedCentric := function(list) # help function + local res; + res := []; + Add(res, Float(2/3)*list[1] + Float(5/18)*list[2] + Float(1/18)*list[3]); + Add(res, Float(2/3)*list[1] + Float(1/18)*list[2] + Float(5/18)*list[3]); + return res; + end; + + MainHelp := function(surf, cur, faceGraph) #surf simp. surface, cur list of lists of [v,[x,y]], faceGraph list of [v,[x,y]] with the added vertices of wanted faceGraph + local n, mainHelp1, mainHelp2, cur1, cur2, curi, mainHelpi, i, v, newv, res, neighbours, verticesOfFaceGraph, correctFacesOfVertex, toSplitVertex, toSplitVertex1, toSplitVertex2, toSplitVertexPos, toSplitVertexPos1, toSplitVertexPos2, alreadyPositionedVertices; + if Length(cur) >= 2 then # More than one convex drawing plane + res := []; + faceGraph := MainHelp(surf, [cur[1]], faceGraph)[2]; + for i in [1..Length(cur)] do + mainHelpi := MainHelp(surf, [cur[i]], faceGraph); + curi := mainHelpi[1]; + res := Concatenation(res, curi); + faceGraph := Set(Concatenation(faceGraph, mainHelpi[2])); + od; + return [res, faceGraph]; + elif Length(cur)=1 then # Only one convex drawing plane + cur := cur[1]; + n:=Length(cur); + if n < 2 then + return [[[]], faceGraph]; + fi; + neighbours := NeighbourFacesOfFace(surf, cur[1][1]); + verticesOfFaceGraph := List(faceGraph, x -> x[1]); + if Length(Intersection(verticesOfFaceGraph, neighbours)) = 2 then # 2 neighbours of cur[1] have been positioned already + if Length(neighbours) = 2 then # There are only 2 neighbours which means no vertex has to be positioned + Remove(cur, 1); + else # There are 3 neighbours which means there is a new vertex that has to be positioned + for v in neighbours do + if not v in verticesOfFaceGraph then + newv := [v, WeightedCentric([cur[1][2], cur[2][2], cur[n][2]])]; + Add(faceGraph, newv); + Remove(cur, 1); + Add(cur, newv); + fi; + od; + fi; + return [[cur], faceGraph]; + elif Length(Intersection(verticesOfFaceGraph, neighbours)) = 1 then # 1 neighbour of cur[1] has been positioned already + if Length(neighbours) = 1 then # There is only 1 neighbour which means no vertex has to be positioned + Remove(cur, 1); + elif Length(neighbours) = 2 then # There are only 2 neighbours which means 1 vertex has to be positioned + for v in neighbours do + if not v in verticesOfFaceGraph then + newv := [v, WeightedCentric([cur[1][2], cur[2][2], cur[n][2]])]; + Add(faceGraph, newv); + Remove(cur, 1); + Add(cur, newv); + fi; + od; + else # There are 3 neighbours which means 2 vertices have to be positioned + correctFacesOfVertex := Filtered(FacesOfVertices(surf), x -> CorrectFacesOfVertexFilter(cur[1][1], cur[2][1], List(faceGraph, y -> y[1]), x)); + for v in Difference(Difference(neighbours, correctFacesOfVertex[1]), verticesOfFaceGraph) do + newv := [v, TwoWeightedCentric([cur[1][2], cur[2][2], cur[n][2]])[2]]; + Add(faceGraph, newv); + Add(cur, newv); + od; + for v in Difference(Intersection(neighbours, correctFacesOfVertex[1]), verticesOfFaceGraph) do + newv := [v, TwoWeightedCentric([cur[1][2], cur[2][2], cur[n][2]])[1]]; + Add(faceGraph, newv); + Add(cur, newv); + od; + fi; + Remove(cur, 1); + return [[cur], faceGraph]; + elif Length(Intersection(verticesOfFaceGraph, neighbours)) = 3 then # 3 neighbours of cur[1] have been positioned already + alreadyPositionedVertices := Difference(neighbours, [cur[2][1], cur[n][1]]); + if Length(Intersection(List(cur, x -> x[1]), alreadyPositionedVertices)) = 2 then # case 3: edge slices convex drawing plane in three and splits it + toSplitVertex1 := Intersection(List(cur, x -> x[1]), alreadyPositionedVertices)[1]; + toSplitVertex2 := Intersection(List(cur, x -> x[1]), alreadyPositionedVertices)[2]; + toSplitVertexPos1 := Position(List(cur, x -> x[1]), toSplitVertex1); + toSplitVertexPos2 := Position(List(cur, x -> x[1]), toSplitVertex2); + return [ThreeSplitListPosition(cur, toSplitVertexPos1, toSplitVertexPos2), faceGraph]; + elif Length(Intersection(List(cur, x -> x[1]), alreadyPositionedVertices)) = 1 then # case 2: edge slices convex drawing plane in two and splits it + toSplitVertex := Intersection(List(cur, x -> x[1]), alreadyPositionedVertices)[1]; + toSplitVertexPos := Position(List(cur, x -> x[1]), toSplitVertex); + return [SplitListPosition(cur, toSplitVertexPos), faceGraph]; + elif Length(Intersection(List(cur, x -> x[1]), alreadyPositionedVertices)) = 0 then # case 1: edge does not violate convex drawing plane + Remove(cur, 1); + return [[cur], faceGraph]; + else + # Print("Failure at 3 neighbours of cur[1] have been positioned already!"); + Error(); + fi; + fi; + fi; + end; + + RegularPolygon := function(list) #returns vertices of a regular polygon as a list of [vert, [x,y]] + local n, res, i; + res:=[]; + n:=Length(list); + for i in [1..n] do + Add(res,[list[i],[Cos(2*3.14159265*((i-1)/n)),Sin(2*3.14159265*((i-1)/n))]]); + od; + return res; + end; + + DrawConvexFaceGraph := function(surf) + local cur, faceGraph, path, mainHelp, maxPathPos; + maxPathPos := PositionMaximum(List(UmbrellaPathsOfVertices(surf), x -> Length(FacesAsList(x)))); + path := UmbrellaPathOfVertex(surf, maxPathPos); # Start with the biggest UmbrellaPath + # path := UmbrellaPathOfVertex(surf, Vertices(surf)[1]); # Start with the UmbrellaPath of the vertex 1 + cur := [RegularPolygon(FacesAsList(path))]; + faceGraph := RegularPolygon(FacesAsList(path)); + while Length(faceGraph) x[1]); + if "scale" in RecNames(record) and "faceCoordinates2D" in RecNames(record) then + return DrawFacegraphToTikz(surf, name, record); + elif (not "scale" in RecNames(record)) and "faceCoordinates2D" in RecNames(record) then + record.scale := 4; + elif "scale" in RecNames(record) and (not "faceCoordinates2D" in RecNames(record)) then + record.faceCoordinates2D := List(graph, x -> x[2]); + else + record.faceCoordinates2D := List(graph, x -> x[2]); + record.scale := 4; + fi; + + return DrawFacegraphToTikz(surf, name, record); + + end +); + +InstallOtherMethod( DrawConvexFacegraphToTikz, + "for a simplicial surface and a file name", + [IsSimplicialSurface, IsString], + function(surf, name) + return DrawConvexFacegraphToTikz(surf, name, rec()); + end +); diff --git a/gap/PolygonalComplexes/embedding.gd b/gap/PolygonalComplexes/embedding.gd index 8be9e2a3..cd9940fa 100644 --- a/gap/PolygonalComplexes/embedding.gd +++ b/gap/PolygonalComplexes/embedding.gd @@ -363,3 +363,67 @@ DeclareOperation( "DrawFacegraphToTikz", [IsSimplicialSurface ,IsString,IsRecord #! @Subsection Output control #! @SubsectionLabel DrawFacegraphToTikz_Output #! @InsertChunk DrawFacegraphToTikz_Output +#! +#! @BeginGroup DrawConvexFacegraphToTikz +#! @Description +#! Draw the face graph of the given surface into a tex-file (using TikZ). +#! An introduction to the use of this method (along with several examples) +#! can be found at the start of section . +#! If surface is a simplicial vertex faithful sphere and the function +#! is used without the argument printRecord, then the drawing printed +#! into file is a planar embedding of the face graph of surface, +#! where the vertices of the surface are identified by the faces of the +#! embedding. DrawConvexFacegraphToTikz differs from DrawFacegraphToTikz +#! () by constructing the face graph +#! by successively manipulating a convex drawing plane and calculating new face coordinates. +#! The new coordinates are then drawn with DrawFacegraphToTikz. +#! This results in an embedding which maps the faces +#! of one of the largest umbrella paths on the outer ring as a +#! regular polygon. Trying to use the function for a surface that is not a +#! vertex-faithful sphere results in returning fail. +#! +#! * If the given file does not end in .tex the ending +#! .tex will be added to it. +#! * The given file will be overwritten without asking if it already exists. +#! If you don't have permission to write in that file, this method will +#! throw an error. +#! * The particulars of the drawing are determined by the +#! given printRecord. If this is not given and surface is a +#! simplicial sphere, the default settings are used. +#! * The printRecord will be modified and returned by this method. +#! It contains the data to recreate the drawing of the surface. +#! +#! +#! There are several parameters to change the output of this method. +#! Since the design of the parameters is the design of the parameters +#! of DrawFacegraphToTikz(), +#! one can also refer to the corresponding subsections for a better +#! understanding. +#! There are the following classes of parameters: +#! * Colours +#! (): Change the +#! colours of edges and faces represented as vertices. +#! * Labels +#! (): Modify the labels +#! of vertices, edges and faces. +#! * Scale +#! (): These +#! parameters control the size of the drawing. +#! * faceCoordinates2D +#! (): +#! Modify the 2D-coordinates of the faces. +#! * Geodesics +#! (): Draw the +#! geodesics of the simplicial surface into the file. +#! * Output control +#! (): Modify how the +#! &LaTeX;-output behaves and how much information is printed to the +#! console. +#! +#! Consider the following example of the double-6-gon: +#! @InsertChunk DrawConvexFacegraphToTikz_example +#! +#! @Returns a record +#! @Arguments surface, file[, printRecord] +DeclareOperation( "DrawConvexFacegraphToTikz", [IsSimplicialSurface, IsString, IsRecord]); +#! @EndGroup \ No newline at end of file From 78c321b769fe5f46451fb8842308164ff13de38c Mon Sep 17 00:00:00 2001 From: Flynn Fehre Date: Sat, 11 Mar 2023 10:30:30 +0100 Subject: [PATCH 02/44] changed WeightedCentric for improved space between the facenodes --- gap/PolygonalComplexes/drawing.gi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gap/PolygonalComplexes/drawing.gi b/gap/PolygonalComplexes/drawing.gi index 427b5dec..69474205 100644 --- a/gap/PolygonalComplexes/drawing.gi +++ b/gap/PolygonalComplexes/drawing.gi @@ -2107,14 +2107,14 @@ InstallMethod( DrawConvexFacegraphToTikz, end; WeightedCentric := function(list) # help function - return Float(2/3)*list[1]+Float(1/6)*(list[2]+list[3]); + return Float(1/2)*list[1]+Float(1/4)*(list[2]+list[3]); end; TwoWeightedCentric := function(list) # help function local res; res := []; - Add(res, Float(2/3)*list[1] + Float(5/18)*list[2] + Float(1/18)*list[3]); - Add(res, Float(2/3)*list[1] + Float(1/18)*list[2] + Float(5/18)*list[3]); + Add(res, Float(1/2)*list[1] + Float(7/18)*list[2] + Float(2/18)*list[3]); + Add(res, Float(1/2)*list[1] + Float(2/18)*list[2] + Float(7/18)*list[3]); return res; end; From e30293b9e075b9c69e1b7533ad2e8285840de35c Mon Sep 17 00:00:00 2001 From: Flynn Fehre Date: Thu, 18 May 2023 13:44:43 +0200 Subject: [PATCH 03/44] first correction --- gap/PolygonalComplexes/drawing.gi | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/gap/PolygonalComplexes/drawing.gi b/gap/PolygonalComplexes/drawing.gi index 69474205..cebcd12f 100644 --- a/gap/PolygonalComplexes/drawing.gi +++ b/gap/PolygonalComplexes/drawing.gi @@ -2048,7 +2048,7 @@ InstallMethod( DrawConvexFacegraphToTikz, return [res1,res2]; end; - ThreeSplitListPosition := function(list, v, w) # helpt function + ThreeSplitListPosition := function(list, v, w) # help function local i, res1, res2, res3; if w > v then res1 := []; @@ -2130,9 +2130,9 @@ InstallMethod( DrawConvexFacegraphToTikz, faceGraph := Set(Concatenation(faceGraph, mainHelpi[2])); od; return [res, faceGraph]; - elif Length(cur)=1 then # Only one convex drawing plane + elif Length(cur) = 1 then # Only one convex drawing plane cur := cur[1]; - n:=Length(cur); + n := Length(cur); if n < 2 then return [[[]], faceGraph]; fi; @@ -2142,13 +2142,21 @@ InstallMethod( DrawConvexFacegraphToTikz, if Length(neighbours) = 2 then # There are only 2 neighbours which means no vertex has to be positioned Remove(cur, 1); else # There are 3 neighbours which means there is a new vertex that has to be positioned + alreadyPositionedVertices := Difference(neighbours, [cur[2][1], cur[n][1]]); + if Length(Intersection(List(cur, x -> x[1]), alreadyPositionedVertices)) = 1 then # case 2: edge slices convex drawing plane in two and splits it + toSplitVertex := Intersection(List(cur, x -> x[1]), alreadyPositionedVertices)[1]; + toSplitVertexPos := Position(List(cur, x -> x[1]), toSplitVertex); + return [SplitListPosition(cur, toSplitVertexPos), faceGraph]; + fi; for v in neighbours do - if not v in verticesOfFaceGraph then + if v=25 then Error(); fi; # debug + if (not v in verticesOfFaceGraph) then # and (ForAny(VerticesOfFace(surf, v), faceVertex -> Length(Intersection(List(cur, x -> x[1]), FacesAsList(UmbrellaPathOfVertex(surf, faceVertex)))) >= 3)) newv := [v, WeightedCentric([cur[1][2], cur[2][2], cur[n][2]])]; Add(faceGraph, newv); Remove(cur, 1); Add(cur, newv); fi; + if v=25 then Error(); fi; # debug od; fi; return [[cur], faceGraph]; @@ -2252,3 +2260,4 @@ InstallOtherMethod( DrawConvexFacegraphToTikz, return DrawConvexFacegraphToTikz(surf, name, rec()); end ); + From f0319a97d0479ae1730d11b1e1f0e6457f4d7609 Mon Sep 17 00:00:00 2001 From: Flynn Fehre Date: Sat, 20 May 2023 14:23:36 +0200 Subject: [PATCH 04/44] solved an error with DrawConvexFacegraphToTikz and added a new parameter 'spread' for this function --- gap/PolygonalComplexes/drawing.gd | 46 ++++++- gap/PolygonalComplexes/drawing.gi | 198 +++++++++++------------------- 2 files changed, 117 insertions(+), 127 deletions(-) diff --git a/gap/PolygonalComplexes/drawing.gd b/gap/PolygonalComplexes/drawing.gd index 1f09d3f9..14f009fd 100644 --- a/gap/PolygonalComplexes/drawing.gd +++ b/gap/PolygonalComplexes/drawing.gd @@ -899,11 +899,15 @@ DrawFacegraphToTikz( tetra, "facegraph_oct_rescaled", pr);; #! * faceCoordinates2D: Modify the coordinates of the faces which are #! represented as vertices in the embedding. #! +#! * spread (Only available for DrawConvexFacegraphToTikz +#! ): Modify the spread of +#! the coordinates. +#! #! We will exemplify them with the tetrahedron to make clear how the parameters #! 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 @@ -931,6 +935,46 @@ DrawFacegraphToTikz(tetra, #! #! #! +#! +#! spread(Only available for DrawConvexFacegraphToTikz +#! ): Modifies the position of the +#! vertices representing the faces. The spread parameter can be chosen as a float in the +#! interval (0, 1). Choosing the parameter outside the interval results in +#! an error. Choosing a number close to 1 modifies the face coordinates such +#! that they tend torwards the outer ring of the face graph. Choosing a number +#! close to 0 modifies the face coordinates such that they tend torwards the +#! middle of the face graph. The default spread is set at 0.5. +#! +#! We will exemplify this parameter with the icosahedron. +#! @BeginLog +icosahedron := SimplicialSurfaceByVerticesInFaces([ [ 1, 2, 3 ], [ 1, 2, 4 ], + [ 1, 4, 5 ], [ 1, 5, 6 ], [ 1, 3, 6 ], [ 2, 3, 7 ], [ 2, 4, 8 ], [ 4, 5, 9 ], + [ 5, 6, 10 ], [ 3, 6, 11 ], [ 2, 7, 8 ], [ 4, 8, 9 ], [ 5, 9, 10 ], [ 6, 10, 11 ], + [ 3, 7, 11 ], [ 7, 8, 12 ], [ 8, 9, 12 ], [ 9, 10, 12 ], [ 10, 11, 12 ], + [ 7, 11, 12 ] ]);; +DrawConvexFacegraphToTikz(icosahedron, "convex_facegraph_icosahedron_default_spread");; +#! @EndLog +#! +#! \input{_TIKZ_convex_facegraph_icosahedron_default_spread.tex} +#! +#! +#! @BeginLog +pr := rec(spread := 0.3);; +DrawConvexFacegraphToTikz(icosahedron, + "convex_facegraph_icosahedron_low_spread", pr);; +#! @EndLog +#! +#! \input{_TIKZ_convex_facegraph_icosahedron_low_spread.tex} +#! +#! +#! @BeginLog +pr := rec(spread := 0.7);; +DrawConvexFacegraphToTikz(icosahedron, + "convex_facegraph_icosahedron_high_spread", pr);; +#! @EndLog +#! +#! \input{_TIKZ_convex_facegraph_icosahedron_high_spread.tex} +#! #! @EndChunk diff --git a/gap/PolygonalComplexes/drawing.gi b/gap/PolygonalComplexes/drawing.gi index cebcd12f..05cd943d 100644 --- a/gap/PolygonalComplexes/drawing.gi +++ b/gap/PolygonalComplexes/drawing.gi @@ -2028,8 +2028,10 @@ InstallMethod( DrawConvexFacegraphToTikz, "for a closed vertex-faithful simplicial sphere, a file name and a record", [IsSimplicialSurface, IsString, IsRecord], function(surf, name, record) - local graph, SplitListPosition, ThreeSplitListPosition, InFilterFunc, IntersectionFilterFunc, CorrectFacesOfVertexFilter, WeightedCentric, TwoWeightedCentric, MainHelp, RegularPolygon, DrawConvexFaceGraph, DrawGraph; - if not( IsClosedSurface(surf) and IsVertexFaithful(surf) and EulerCharacteristic(surf)=2) and not IsBound(printRecord.faceCoordinates2D) then + local graph, SplitListPosition, InFilterFunc, + IntersectionFilterFunc, CorrectFacesOfVertexFilter, WeightedCentricParameters, + TwoWeightedCentricParameters, MainHelp, RegularPolygon, DrawConvexFaceGraph, DrawGraph, q; + if not (IsClosedSurface(surf) and IsVertexFaithful(surf) and EulerCharacteristic(surf) = 2) and not IsBound(printRecord.faceCoordinates2D) then return fail; fi; @@ -2038,52 +2040,15 @@ InstallMethod( DrawConvexFacegraphToTikz, res1:=[]; res2:=[]; for i in [2..v] do - Add(res1,list[i]); + Add(res1, list[i]); od; - for i in [v..Length(list)] do + for i in [(v + 1)..Length(list)] do Add(res2, list[i]); od; - Add(res1,list[1]); + Add(res1, list[1]); Add(res2, list[1]); - return [res1,res2]; - end; - - ThreeSplitListPosition := function(list, v, w) # help function - local i, res1, res2, res3; - if w > v then - res1 := []; - res2 := []; - res3 := []; - for i in [2..v] do - Add(res1,list[i]); - od; - for i in [v..w] do - Add(res2, list[i]); - od; - for i in [w..Length(list)] do - Add(res3, list[i]); - od; - Add(res1, list[1]); - Add(res2, list[1]); - Add(res3, list[1]); - elif w < v then - res1 := []; - res2 := []; - res3 := []; - for i in [2..w] do - Add(res1,list[i]); - od; - for i in [w..v] do - Add(res2, list[i]); - od; - for i in [v..Length(list)] do - Add(res3, list[i]); - od; - Add(res1, list[1]); - Add(res2, list[1]); - Add(res3, list[1]); - fi; - return [res1, res2, res3]; + Add(res2, list[v]); + return [res1, res2]; end; InFilterFunc := function(cur1, cur2, list) # help function @@ -2106,105 +2071,81 @@ InstallMethod( DrawConvexFacegraphToTikz, return InFilterFunc(cur1, cur2, list) and IntersectionFilterFunc(faceGraph, list); end; - WeightedCentric := function(list) # help function - return Float(1/2)*list[1]+Float(1/4)*(list[2]+list[3]); + WeightedCentricParameters := function(list, p) # help function + return Float(p)*list[1] + Float((1-p)/2)*(list[2] + list[3]); end; - TwoWeightedCentric := function(list) # help function + TwoWeightedCentricParameters := function(list, p, q) # help function local res; res := []; - Add(res, Float(1/2)*list[1] + Float(7/18)*list[2] + Float(2/18)*list[3]); - Add(res, Float(1/2)*list[1] + Float(2/18)*list[2] + Float(7/18)*list[3]); + Add(res, p*list[1] + (1-p)*q*list[2] + (1-p)*(1-q)*list[3]); + Add(res, p*list[1] + (1-p)*(1-q)*list[2] + (1-p)*q*list[3]); return res; end; - MainHelp := function(surf, cur, faceGraph) #surf simp. surface, cur list of lists of [v,[x,y]], faceGraph list of [v,[x,y]] with the added vertices of wanted faceGraph - local n, mainHelp1, mainHelp2, cur1, cur2, curi, mainHelpi, i, v, newv, res, neighbours, verticesOfFaceGraph, correctFacesOfVertex, toSplitVertex, toSplitVertex1, toSplitVertex2, toSplitVertexPos, toSplitVertexPos1, toSplitVertexPos2, alreadyPositionedVertices; + RegularPolygon := function(list) #returns vertices of a regular polygon as a list of [vert, [x,y]] + local n, res, i; + res := []; + n := Length(list); + for i in [1..n] do + Add(res, [list[i], [Cos(2*3.14159265*((i-1)/n)), Sin(2*3.14159265*((i-1)/n))]]); + od; + return res; + end; + + MainHelp := function(surf, cur, faceGraph, spread, q) + local res, mainHelpi, curi, curLength, i, toSplitVertex, toSplitVertexPos, nodesOfFaceGraph, alreadyPositionedNeighbours, neighbours, v, newv, correctFacesOfVertex; if Length(cur) >= 2 then # More than one convex drawing plane res := []; - faceGraph := MainHelp(surf, [cur[1]], faceGraph)[2]; for i in [1..Length(cur)] do - mainHelpi := MainHelp(surf, [cur[i]], faceGraph); + mainHelpi := MainHelp(surf, [cur[i]], faceGraph, spread, q); curi := mainHelpi[1]; res := Concatenation(res, curi); faceGraph := Set(Concatenation(faceGraph, mainHelpi[2])); od; return [res, faceGraph]; - elif Length(cur) = 1 then # Only one convex drawing plane - cur := cur[1]; - n := Length(cur); - if n < 2 then + else # Only one convex drawing plane + cur := cur[1]; # deabstracting the only current list + curLength := Length(cur); + if curLength < 2 then return [[[]], faceGraph]; - fi; - neighbours := NeighbourFacesOfFace(surf, cur[1][1]); - verticesOfFaceGraph := List(faceGraph, x -> x[1]); - if Length(Intersection(verticesOfFaceGraph, neighbours)) = 2 then # 2 neighbours of cur[1] have been positioned already - if Length(neighbours) = 2 then # There are only 2 neighbours which means no vertex has to be positioned - Remove(cur, 1); - else # There are 3 neighbours which means there is a new vertex that has to be positioned - alreadyPositionedVertices := Difference(neighbours, [cur[2][1], cur[n][1]]); - if Length(Intersection(List(cur, x -> x[1]), alreadyPositionedVertices)) = 1 then # case 2: edge slices convex drawing plane in two and splits it - toSplitVertex := Intersection(List(cur, x -> x[1]), alreadyPositionedVertices)[1]; - toSplitVertexPos := Position(List(cur, x -> x[1]), toSplitVertex); - return [SplitListPosition(cur, toSplitVertexPos), faceGraph]; - fi; - for v in neighbours do - if v=25 then Error(); fi; # debug - if (not v in verticesOfFaceGraph) then # and (ForAny(VerticesOfFace(surf, v), faceVertex -> Length(Intersection(List(cur, x -> x[1]), FacesAsList(UmbrellaPathOfVertex(surf, faceVertex)))) >= 3)) - newv := [v, WeightedCentric([cur[1][2], cur[2][2], cur[n][2]])]; + else + neighbours := NeighbourFacesOfFace(surf, cur[1][1]); + nodesOfFaceGraph := List(faceGraph, x -> x[1]); + alreadyPositionedNeighbours := Difference(neighbours, [cur[2][1], cur[curLength][1]]); + if Length(Intersection(List(cur, x -> x[1]), alreadyPositionedNeighbours)) = 0 then # case 1: edge does not violate convex drawing plane + if Length(Intersection(nodesOfFaceGraph, neighbours)) = 1 then # Only one neighbour has been positioned already, so 2 more have to be added + correctFacesOfVertex := Filtered(FacesOfVertices(surf), x -> CorrectFacesOfVertexFilter(cur[1][1], cur[2][1], List(faceGraph, y -> y[1]), x)); + for v in Difference(Difference(neighbours, correctFacesOfVertex[1]), nodesOfFaceGraph) do + newv := [v, TwoWeightedCentricParameters([cur[1][2], cur[2][2], cur[curLength][2]], spread, q)[2]]; Add(faceGraph, newv); - Remove(cur, 1); Add(cur, newv); - fi; - if v=25 then Error(); fi; # debug - od; - fi; - return [[cur], faceGraph]; - elif Length(Intersection(verticesOfFaceGraph, neighbours)) = 1 then # 1 neighbour of cur[1] has been positioned already - if Length(neighbours) = 1 then # There is only 1 neighbour which means no vertex has to be positioned - Remove(cur, 1); - elif Length(neighbours) = 2 then # There are only 2 neighbours which means 1 vertex has to be positioned - for v in neighbours do - if not v in verticesOfFaceGraph then - newv := [v, WeightedCentric([cur[1][2], cur[2][2], cur[n][2]])]; + od; + for v in Difference(Intersection(neighbours, correctFacesOfVertex[1]), nodesOfFaceGraph) do + newv := [v, TwoWeightedCentricParameters([cur[1][2], cur[2][2], cur[curLength][2]], spread, q)[1]]; Add(faceGraph, newv); - Remove(cur, 1); Add(cur, newv); - fi; - od; - else # There are 3 neighbours which means 2 vertices have to be positioned - correctFacesOfVertex := Filtered(FacesOfVertices(surf), x -> CorrectFacesOfVertexFilter(cur[1][1], cur[2][1], List(faceGraph, y -> y[1]), x)); - for v in Difference(Difference(neighbours, correctFacesOfVertex[1]), verticesOfFaceGraph) do - newv := [v, TwoWeightedCentric([cur[1][2], cur[2][2], cur[n][2]])[2]]; - Add(faceGraph, newv); - Add(cur, newv); - od; - for v in Difference(Intersection(neighbours, correctFacesOfVertex[1]), verticesOfFaceGraph) do - newv := [v, TwoWeightedCentric([cur[1][2], cur[2][2], cur[n][2]])[1]]; - Add(faceGraph, newv); - Add(cur, newv); - od; - fi; - Remove(cur, 1); - return [[cur], faceGraph]; - elif Length(Intersection(verticesOfFaceGraph, neighbours)) = 3 then # 3 neighbours of cur[1] have been positioned already - alreadyPositionedVertices := Difference(neighbours, [cur[2][1], cur[n][1]]); - if Length(Intersection(List(cur, x -> x[1]), alreadyPositionedVertices)) = 2 then # case 3: edge slices convex drawing plane in three and splits it - toSplitVertex1 := Intersection(List(cur, x -> x[1]), alreadyPositionedVertices)[1]; - toSplitVertex2 := Intersection(List(cur, x -> x[1]), alreadyPositionedVertices)[2]; - toSplitVertexPos1 := Position(List(cur, x -> x[1]), toSplitVertex1); - toSplitVertexPos2 := Position(List(cur, x -> x[1]), toSplitVertex2); - return [ThreeSplitListPosition(cur, toSplitVertexPos1, toSplitVertexPos2), faceGraph]; - elif Length(Intersection(List(cur, x -> x[1]), alreadyPositionedVertices)) = 1 then # case 2: edge slices convex drawing plane in two and splits it - toSplitVertex := Intersection(List(cur, x -> x[1]), alreadyPositionedVertices)[1]; + od; + Remove(cur, 1); + return [[cur], faceGraph]; + elif Length(Intersection(nodesOfFaceGraph, neighbours)) = 2 then # Only two neighbours have been positioned already, so 1 more has to be added + for v in neighbours do + if not v in nodesOfFaceGraph then # and (ForAny(VerticesOfFace(surf, v), faceVertex -> Length(Intersection(List(cur, x -> x[1]), FacesAsList(UmbrellaPathOfVertex(surf, faceVertex)))) >= 3)) + newv := [v, WeightedCentricParameters([cur[1][2], cur[2][2], cur[curLength][2]], spread)]; + Add(faceGraph, newv); + Remove(cur, 1); + Add(cur, newv); + fi; + od; + return [[cur], faceGraph]; + elif Length(Intersection(nodesOfFaceGraph, neighbours)) = 3 then # All three neighbours have been positioned already, so no more have to be added + Remove(cur, 1); + return [[cur], faceGraph]; + fi; + else # case 2: edge slices convex drawing plane in two and splits it + toSplitVertex := Intersection(List(cur, x -> x[1]), alreadyPositionedNeighbours)[1]; toSplitVertexPos := Position(List(cur, x -> x[1]), toSplitVertex); return [SplitListPosition(cur, toSplitVertexPos), faceGraph]; - elif Length(Intersection(List(cur, x -> x[1]), alreadyPositionedVertices)) = 0 then # case 1: edge does not violate convex drawing plane - Remove(cur, 1); - return [[cur], faceGraph]; - else - # Print("Failure at 3 neighbours of cur[1] have been positioned already!"); - Error(); fi; fi; fi; @@ -2220,22 +2161,28 @@ InstallMethod( DrawConvexFacegraphToTikz, return res; end; - DrawConvexFaceGraph := function(surf) + DrawConvexFaceGraph := function(surf, spread, q) local cur, faceGraph, path, mainHelp, maxPathPos; maxPathPos := PositionMaximum(List(UmbrellaPathsOfVertices(surf), x -> Length(FacesAsList(x)))); path := UmbrellaPathOfVertex(surf, maxPathPos); # Start with the biggest UmbrellaPath # path := UmbrellaPathOfVertex(surf, Vertices(surf)[1]); # Start with the UmbrellaPath of the vertex 1 cur := [RegularPolygon(FacesAsList(path))]; faceGraph := RegularPolygon(FacesAsList(path)); - while Length(faceGraph)= Float(1) or record.spread <= Float(0) then + Error("The spread parameter has to be chosen in the interval (0, 1) !"); + fi; + q := Float(7/9); # another parameter that controls the spread but probably not important enough to let the user control it. q must be chosen in the interval ((1/2), 1). + graph := DrawConvexFaceGraph(surf, Float(record.spread), q); SortBy(graph, x -> x[1]); if "scale" in RecNames(record) and "faceCoordinates2D" in RecNames(record) then return DrawFacegraphToTikz(surf, name, record); @@ -2249,7 +2196,6 @@ InstallMethod( DrawConvexFacegraphToTikz, fi; return DrawFacegraphToTikz(surf, name, record); - end ); From 1f6f96ab6a6352dc7967bd06cb9a58ef63fde358 Mon Sep 17 00:00:00 2001 From: Flynn Fehre Date: Sat, 20 May 2023 19:43:29 +0200 Subject: [PATCH 05/44] minor corrections --- gap/PolygonalComplexes/drawing.gd | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/gap/PolygonalComplexes/drawing.gd b/gap/PolygonalComplexes/drawing.gd index 14f009fd..cb9f8b13 100644 --- a/gap/PolygonalComplexes/drawing.gd +++ b/gap/PolygonalComplexes/drawing.gd @@ -932,11 +932,8 @@ DrawFacegraphToTikz(tetra, #! #! \input{_TIKZ_facegraph_tetrahedron_Coordinates.tex} #! -#! #! -#! -#! -#! spread(Only available for DrawConvexFacegraphToTikz +#! spread (Only available for DrawConvexFacegraphToTikz #! ): Modifies the position of the #! vertices representing the faces. The spread parameter can be chosen as a float in the #! interval (0, 1). Choosing the parameter outside the interval results in @@ -947,12 +944,14 @@ DrawFacegraphToTikz(tetra, #! #! We will exemplify this parameter with the icosahedron. #! @BeginLog -icosahedron := SimplicialSurfaceByVerticesInFaces([ [ 1, 2, 3 ], [ 1, 2, 4 ], - [ 1, 4, 5 ], [ 1, 5, 6 ], [ 1, 3, 6 ], [ 2, 3, 7 ], [ 2, 4, 8 ], [ 4, 5, 9 ], - [ 5, 6, 10 ], [ 3, 6, 11 ], [ 2, 7, 8 ], [ 4, 8, 9 ], [ 5, 9, 10 ], [ 6, 10, 11 ], - [ 3, 7, 11 ], [ 7, 8, 12 ], [ 8, 9, 12 ], [ 9, 10, 12 ], [ 10, 11, 12 ], - [ 7, 11, 12 ] ]);; -DrawConvexFacegraphToTikz(icosahedron, "convex_facegraph_icosahedron_default_spread");; +icosahedron := SimplicialSurfaceByVerticesInFaces([ [ 1, 2, 3 ], + [ 1, 2, 4 ], [ 1, 4, 5 ], [ 1, 5, 6 ], [ 1, 3, 6 ], [ 2, 3, 7 ], + [ 2, 4, 8 ], [ 4, 5, 9 ], [ 5, 6, 10 ], [ 3, 6, 11 ], + [ 2, 7, 8 ], [ 4, 8, 9 ], [ 5, 9, 10 ], [ 6, 10, 11 ], + [ 3, 7, 11 ], [ 7, 8, 12 ], [ 8, 9, 12 ], [ 9, 10, 12 ], + [ 10, 11, 12 ], [ 7, 11, 12 ] ]);; +DrawConvexFacegraphToTikz(icosahedron, +"convex_facegraph_icosahedron_default_spread");; #! @EndLog #! #! \input{_TIKZ_convex_facegraph_icosahedron_default_spread.tex} @@ -975,6 +974,8 @@ DrawConvexFacegraphToTikz(icosahedron, #! #! \input{_TIKZ_convex_facegraph_icosahedron_high_spread.tex} #! +#! +#! #! @EndChunk From 679f7245ce9e2939175fa12efcf4d83d4950e094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Mon, 2 Oct 2023 15:15:07 +0200 Subject: [PATCH 06/44] Adaptation of SubcomplexByFaces to edge-coloured complexes --- gap/PolygonalComplexes/modification.gd | 11 ++++++++++ gap/PolygonalComplexes/modification.gi | 28 ++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/gap/PolygonalComplexes/modification.gd b/gap/PolygonalComplexes/modification.gd index 8e68605a..48f8c05f 100755 --- a/gap/PolygonalComplexes/modification.gd +++ b/gap/PolygonalComplexes/modification.gd @@ -576,6 +576,17 @@ DeclareOperation( "SplitEdgePathNC", [IsPolygonalComplex, IsVertexEdgePath and I #! The NC-version does not check whether the given set of faces #! actually consists only of faces in complex. It also does not #! check whether the result of SubsurfaceByFaces is a surface. +#! +#! In Chapter edge colouring will be introduced. +#! If we compute a subcomplex of an edge-coloured complex, it will be edge-coloured again, +#! induced by the edge-colouring of the given complex. +#! @BeginExampleSession +#! gap> colEdges:=[ 1, 2, 1, 2, 1, 2, 3, 3, 3, 3, 3, 3 ];; +#! gap> colSurface:=EdgeColouredPolygonalComplex(hex,colEdges); +#! tame coloured surface (MMB with 7 vertices, 12 edges and 6 faces) +#! gap> SubsurfaceByFaces(colSurface,[1,2]); +#! tame coloured surface (BMB with 4 vertices, 5 edges and 2 faces) +#! @EndExampleSession #! #! @Returns a twisted polygonal complex #! @Arguments complex, faces diff --git a/gap/PolygonalComplexes/modification.gi b/gap/PolygonalComplexes/modification.gi index ef540ba2..132b5f1e 100755 --- a/gap/PolygonalComplexes/modification.gi +++ b/gap/PolygonalComplexes/modification.gi @@ -498,7 +498,8 @@ InstallOtherMethod( SubcomplexByFaces, InstallMethod( SubcomplexByFacesNC, "for a polygonal complex and a set of faces", [IsPolygonalComplex, IsSet], function(complex, subfaces) - local subVertices, subEdges, newVerticesOfEdges, newEdgesOfFaces, e, f; + local subVertices, subEdges, newVerticesOfEdges, newEdgesOfFaces, e, f, + subcomplex, colEdges, colEdgesSub, edge; subEdges := __SIMPLICIAL_UnionSets( EdgesOfFaces(complex){subfaces} ); @@ -514,8 +515,18 @@ InstallMethod( SubcomplexByFacesNC, "for a polygonal complex and a set of faces" newEdgesOfFaces[f] := EdgesOfFaces(complex)[f]; od; - return PolygonalComplexByDownwardIncidenceNC( subVertices, subEdges, + subcomplex:=PolygonalComplexByDownwardIncidenceNC( subVertices, subEdges, subfaces, newVerticesOfEdges, newEdgesOfFaces ); + if IsEdgeColouredPolygonalComplex(complex) then + colEdges:=ColoursOfEdges(complex); + colEdgesSub:=[]; + for edge in Edges(subcomplex) do + colEdgesSub[edge]:=colEdges[edge]; + od; + subcomplex:=EdgeColouredPolygonalComplexNC(subcomplex,colEdgesSub); + fi; + + return subcomplex; end ); InstallMethod( SubcomplexByFacesNC, @@ -523,7 +534,7 @@ InstallMethod( SubcomplexByFacesNC, [IsTwistedPolygonalComplex, IsSet], function(complex, subfaces) local remChambers, vofC, eofC, fofC, c, zeroClass, oneClass, - twoClass, cl; + twoClass, cl, subcomplex, colEdges, colEdgesSub, edge; remChambers := Union( ChambersOfFaces(complex){subfaces} ); vofC := []; @@ -541,7 +552,16 @@ InstallMethod( SubcomplexByFacesNC, twoClass := Set(twoClass); twoClass := Difference(twoClass, [[]]); - return TwistedPolygonalComplexByChamberRelationsNC( vofC, eofC, fofC, zeroClass, oneClass, twoClass ); + subcomplex:=TwistedPolygonalComplexByChamberRelationsNC( vofC, eofC, fofC, zeroClass, oneClass, twoClass ); + if IsEdgeColouredTwistedPolygonalComplex(complex) then + colEdges:=ColoursOfEdges(complex); + colEdgesSub:=[]; + for edge in Edges(subcomplex) do + colEdgesSub[edge]:=colEdges[edge]; + od; + subcomplex:=EdgeColouredTwistedPolygonalComplexNC(subcomplex,colEdgesSub); + fi; + return subcomplex; end ); InstallOtherMethod( SubcomplexByFacesNC, From 1defacc9f7a162444d1af58fe5e5eb83a94bd300 Mon Sep 17 00:00:00 2001 From: Lukas Schnelle Date: Wed, 24 Jan 2024 12:20:31 +0100 Subject: [PATCH 07/44] add function to return all coordinates of a printrecord --- gap/PolygonalComplexes/animating.gd | 5 ++++- gap/PolygonalComplexes/animating.gi | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/gap/PolygonalComplexes/animating.gd b/gap/PolygonalComplexes/animating.gd index 67ce9b83..85b8861e 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 command 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..e3fb62fe 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 surfaceand a record", + [IsSimplicialSurface, IsRecord], + function(surface, printRecord) + return printRecord.vertexCoordinates3D; + end +); + InstallMethod( CalculateParametersOfInnerCircle, "for a simplicial surface and a record", From ac7cd5c010d00847f7e8ebbe7f28b9549955384a Mon Sep 17 00:00:00 2001 From: Lukas Schnelle Date: Wed, 24 Jan 2024 12:20:52 +0100 Subject: [PATCH 08/44] add myself as author --- PackageInfo.g | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/PackageInfo.g b/PackageInfo.g index 4470a478..c0103aad 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", From 772bfc640c06f07b2470aadb228b7fdb9ca35aa5 Mon Sep 17 00:00:00 2001 From: Lukas Schnelle Date: Wed, 24 Jan 2024 14:02:11 +0100 Subject: [PATCH 09/44] address comments from MeikeWeiss --- gap/PolygonalComplexes/animating.gd | 2 +- gap/PolygonalComplexes/animating.gi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gap/PolygonalComplexes/animating.gd b/gap/PolygonalComplexes/animating.gd index 85b8861e..f01b0e32 100644 --- a/gap/PolygonalComplexes/animating.gd +++ b/gap/PolygonalComplexes/animating.gd @@ -144,7 +144,7 @@ DeclareOperation( "SetVertexCoordinates3DNC", [IsSimplicialSurface, IsList, IsRe #! 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 GetAllVertexCoordinates3DNC command returns all coordinates from the print record without checking them as a list. +#! 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] ); diff --git a/gap/PolygonalComplexes/animating.gi b/gap/PolygonalComplexes/animating.gi index e3fb62fe..d0e8c648 100644 --- a/gap/PolygonalComplexes/animating.gi +++ b/gap/PolygonalComplexes/animating.gi @@ -89,7 +89,7 @@ RedispatchOnCondition(GetVertexCoordinates3DNC, true, [IsTwistedPolygonalComplex [IsSimplicialSurface], 0); InstallMethod( GetAllVertexCoordinates3DNC, - "for a simplicial surfaceand a record", + "for a simplicial surface and a record", [IsSimplicialSurface, IsRecord], function(surface, printRecord) return printRecord.vertexCoordinates3D; From 0ddc4a5d900b1df2a029653b16ed3e3e2eccc7ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Wed, 14 Feb 2024 15:56:49 +0100 Subject: [PATCH 10/44] corrected IsWaist --- gap/Paths/paths.gd | 7 +++++-- gap/Paths/paths.gi | 33 ++++++++++++++++++++++++++------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/gap/Paths/paths.gd b/gap/Paths/paths.gd index 416e637c..112ec37b 100644 --- a/gap/Paths/paths.gd +++ b/gap/Paths/paths.gd @@ -1197,7 +1197,10 @@ DeclareAttribute( "ViewInformation", IsEdgeFacePath ); #! @Section Waists #! @SectionLabel Waists #! This section deals with a specific type of closed vertex-edge-paths, namely waists. -#! A n-waist is a closed vertex-edge path of length n such that all edges are inner and no two are incident to the same face. +#! A n-waist is a closed vertex-edge path of length n such that all edges are inner and no two are incident to the same face. +#! Moreover, a simplicial surface X can only have a n-waist for n>3 if X does not have a 3-waist and the vertex-edge path describing the n-waist must be distance-faithful. +#! A closed vertex-edge path P is distance-faithful if for any two vertices of P at least one shortest edge path between them is contained in P. +#! #! This will be illustrated on the following double tetrahedron: #! #! <img src="./images/_Wrapper_Image_Example3Waist-1.svg"> </img> @@ -1305,7 +1308,7 @@ DeclareAttribute( "AllThreeWaistsOfComplex", IsTwistedPolygonalComplex); #! For example, consider the double tetrahedron from the start of section : #! @BeginExampleSession #! gap> AllWaistsOfComplex(doubleTetra); -#! [ ( v5, E10, v4, E7, v3, E8, v5 ), ( v5, E12, v6, E9, v3, E8, v5 ) ] +#! [ ( v4, E7, v3, E8, v5, E10, v4 ), ( v5, E8, v3, E9, v6, E12, v5 ) ] #! @EndExampleSession #! #! @Returns a set of closed vertex-edge-paths diff --git a/gap/Paths/paths.gi b/gap/Paths/paths.gi index f2060662..32cec17a 100644 --- a/gap/Paths/paths.gi +++ b/gap/Paths/paths.gi @@ -951,9 +951,9 @@ InstallMethod(ShiftCyclicPath, InstallMethod(IsWaist, "for a complex and a vertex-edge path", [IsTwistedPolygonalComplex, IsVertexEdgePath], function(complex,path) - local edges, incidentFaces, e, foe; + local edges, incidentFaces, e, foe, edgeGraph, vertices, subdigr, i, lastV, vertex; + edges:=EdgesAsList(path); - incidentFaces:=[]; if ForAll(edges, e->IsInnerEdge(complex,e)) and IsClosedPath(path) then # check if the edges are not incident to the same faces @@ -965,6 +965,21 @@ InstallMethod(IsWaist, "for a complex and a vertex-edge path", return false; fi; od; + + # check distance-faithful + if Length(edges)>3 then + edgeGraph:=EdgeDigraphsGraph(complex); + vertices:=ShallowCopy(VerticesAsList(path)); + Remove(vertices); + subdigr:=InducedSubdigraph(edgeGraph,vertices); + lastV:=Position(DigraphVertexLabels(subdigr),Last(vertices)); + for i in [1..Length(vertices)-1] do + vertex:=Position(DigraphVertexLabels(subdigr),vertices[i]); + if DigraphShortestDistance(edgeGraph,vertices[i],Last(vertices))<>DigraphShortestDistance(subdigr,vertex,lastV) then + return false; + fi; + od; + fi; else return false; fi; @@ -1007,14 +1022,18 @@ end InstallMethod(AllWaistsOfComplex, "for a twisted polygonal complex", [IsTwistedPolygonalComplex], function(complex) - local cycles, waists, c, edges, incident, incidentFaces, e, foe; - - cycles:=AllClosedVertexEdgePaths(complex); + local threeWaists, cycles, waists, c, edges, incident, incidentFaces, e, foe; + + threeWaists:=AllThreeWaistsOfComplex(complex); + if threeWaists<>[] then + return Concatenation(threeWaists,AllTwoWaistsOfComplex(complex)); + fi; + cycles:=AllClosedVertexEdgePaths(complex); waists:=[]; for c in cycles do - if IsWaist(complex,c) then - Add(waists,c); + if IsWaist(complex,c) then + Add(waists,c); fi; od; return waists; From 2a4599d2977a2feead640d5638b3f109b1f7e40f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Wed, 14 Feb 2024 16:09:46 +0100 Subject: [PATCH 11/44] added example --- gap/Paths/paths.gd | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gap/Paths/paths.gd b/gap/Paths/paths.gd index 112ec37b..e8cfd924 100644 --- a/gap/Paths/paths.gd +++ b/gap/Paths/paths.gd @@ -1309,6 +1309,9 @@ DeclareAttribute( "AllThreeWaistsOfComplex", IsTwistedPolygonalComplex); #! @BeginExampleSession #! gap> AllWaistsOfComplex(doubleTetra); #! [ ( v4, E7, v3, E8, v5, E10, v4 ), ( v5, E8, v3, E9, v6, E12, v5 ) ] +#! gap> AllWaistsOfComplex(Octahedron()); +#! [ ( v1, E1, v2, E7, v6, E11, v4, E3, v1 ), ( v3, E2, v1, E4, v5, E12, v6, E9, v3 ), +#! ( v3, E5, v2, E6, v5, E10, v4, E8, v3 ) ] #! @EndExampleSession #! #! @Returns a set of closed vertex-edge-paths From 289b0f31699e70a59d83725b622432b661bd7f66 Mon Sep 17 00:00:00 2001 From: Flynn Fehre Date: Fri, 23 Feb 2024 14:08:45 +0100 Subject: [PATCH 12/44] Added the functions ButterflyFaithfulMonomorphismIntoSimplicialSurface and AllButterflyFaithfulMonomorphismsIntoSimplicialSurface as well as their documentation --- ...utterfly_Faithful_Monomorphism_Hexagon.tex | 51 ++ gap/Morphisms/morphisms.gd | 77 ++- gap/Morphisms/morphisms.gi | 515 ++++++++++++++++++ 3 files changed, 641 insertions(+), 2 deletions(-) create mode 100644 doc/Image_Butterfly_Faithful_Monomorphism_Hexagon.tex diff --git a/doc/Image_Butterfly_Faithful_Monomorphism_Hexagon.tex b/doc/Image_Butterfly_Faithful_Monomorphism_Hexagon.tex new file mode 100644 index 00000000..cac13053 --- /dev/null +++ b/doc/Image_Butterfly_Faithful_Monomorphism_Hexagon.tex @@ -0,0 +1,51 @@ + +\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} diff --git a/gap/Morphisms/morphisms.gd b/gap/Morphisms/morphisms.gd index 2e53ea2c..1bbb7a8f 100644 --- a/gap/Morphisms/morphisms.gd +++ b/gap/Morphisms/morphisms.gd @@ -376,6 +376,81 @@ 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. +#! +#! \begin{tikzpicture}[vertexStyle, edgeStyle, faceStyle] +#! \input{Image_Butterfly_Faithful_Monomorphism_Hexagon.tex} +#! \end{tikzpicture} +#! +#! @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. +#! +#! \begin{tikzpicture}[vertexStyle, edgeStyle, faceStyle] +#! \input{Image_Butterfly_Faithful_Monomorphism_Hexagon.tex} +#! \end{tikzpicture} +#! +#! @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 #! @@ -1095,5 +1170,3 @@ DeclareAttribute( "VEFLabelMapAsImageList", IsPolygonalMorphism ); # attribute VertexMapping # attribute EdgeMapping # attribute FaceMapping - - diff --git a/gap/Morphisms/morphisms.gi b/gap/Morphisms/morphisms.gi index 521168f0..e98c202f 100644 --- a/gap/Morphisms/morphisms.gi +++ b/gap/Morphisms/morphisms.gi @@ -478,8 +478,523 @@ InstallMethod( InverseGeneralMapping, "for a polygonal morphism", return InversePolygonalMorphism(polMor); end +); + +InstallMethod(ButterflyFaithfulMonomorphismIntoSimplicialSurface, "for two simplicial surfaces", + [IsSimplicialSurface, IsSimplicialSurface], + function(surface1, surface2) + local PermuteList, AllBijections, AllOneFaceIsomorphisms, MyImage, MyPreImage, MyImageCat, + MyPreImages, MyPreImagesCat, MyUpdateMap, SurfaceIdentityMap, RemoveElement, MyLess, + VertexDegreesOfFace, MyIsInjective, MonomorphismIntoSimplicialSurface; + PermuteList := function(list, perm) + return List(list, x -> x^perm); + end; + + 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, 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; + # res := List(AllPermutations, x -> IndexInducedMap(list1, x)); + return res; + fi; + end; + + MyImage := function(map, x) + return map[x]; + end; + + MyImageCat := 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; + + MyPreImage := 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; + + MyPreImagesCat := function(map, y_list) + return Concatenation(List(y_list, y -> MyPreImage(map, y))); + end; + + MyPreImages := function(map) + return MyPreImagesCat(map, Compacted(map)); + end; + + AllOneFaceIsomorphisms := function(face1, surface1, face2, surface2) + local res, e, vertex_maps, vertex_map, mapped_e, i, edge, edge_map, face_map; + res := []; + vertex_maps := AllBijections(VerticesOfFace(surface1, face1), + VerticesOfFace(surface2, face2)); + # edge_map := []; + 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]))); + # Error(); + for i in [1..3] do + for edge in EdgesOfFace(surface2, face2) do + # Error(); + if Set(VerticesOfEdge(surface2, edge)) = Set(mapped_e[i]) then + # Error(); + # mapped_e[i] := edge; + 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; + + MyUpdateMap := 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; + + SurfaceIdentityMap := function(surface) + return [[1..NumberOfVertices(surface)], [1..NumberOfEdges(surface)], [1..NumberOfFaces(surface)]]; + end; + + RemoveElement := function(list, element) + if not element in list then + return fail; + else + Remove(list, Position(list, element)); + fi; + end; + + MyLess := function(fdeg1, fdeg2) + return fdeg1 < fdeg2; + end; + + VertexDegreesOfFace := function(surface, face) + return Set(List(VerticesOfFace(surface, face), v -> DegreeOfVertex(surface, v))); + end; + + MyIsInjective := function(map) + return IsDuplicateFree(Compacted(map)); + end; + MonomorphismIntoSimplicialSurface := 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)))); + # face_counter1 := ListCounter(CounterOfFaces(surface1)); + # face_counter2 := ListCounter(CounterOfFaces(surface2)); + # face_degrees1 := List(face_counter1, fdegs1 -> Set(fdegs1[1])); + # face_degrees2 := List(face_counter2, fdegs2 -> Set(fdegs2[1])); + if ForAny(face_counter2, fdegs2 -> not fdegs2 in face_counter1) then + # Error("heuristic"); + 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 := 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 := MyPreImages(face_map); + while not IsEmpty(remaining_faces) do + cur_edge := cur_edges[1]; + # Error("Mono"); + # update face_map + if Length(Difference(FacesOfEdge(surface2, edge_map[cur_edge]), face_map)) = 1 then + # Error("Mono"); + new_image_face := Difference(FacesOfEdge(surface2, edge_map[cur_edge]), face_map)[1]; + else # QUESTION not sure if this case is correct + # Error("Mono"); + is_correct_morphism := false; + break; + fi; + new_face := Difference(FacesOfEdge(surface1, cur_edge), mapped_faces)[1]; + + if not new_face in remaining_faces then + # Error("Mono"); + is_correct_morphism := false; + break; + fi; + + if MyUpdateMap(face_map, new_face, new_image_face) = false or MyIsInjective(face_map) = false then + # Error("Mono"); + is_correct_morphism := false; + break; + fi; + mapped_faces := MyPreImages(face_map); + + # update vertex_map + # new_vertex := Difference(VerticesOfFace(surface1, new_face), + # Intersection(List(FacesOfEdge(surface1, cur_edge), F -> VerticesOfFace(surface1, F))))[1]; # QUESTION requires vertex-faithful + new_vertex := Difference(VerticesOfFace(surface1, new_face), VerticesOfEdge(surface1, cur_edge))[1]; + # new_image_vertex := Difference(VerticesOfFace(surface2, new_image_face), + # Intersection(List(FacesOfEdge(surface2, edge_map[cur_edge]), F -> VerticesOfFace(surface2, F))))[1]; # QUESTION requires vertex-faithful + new_image_vertex := Difference(VerticesOfFace(surface2, new_image_face), VerticesOfEdge(surface2, edge_map[cur_edge]))[1]; + if MyUpdateMap(vertex_map, new_vertex, new_image_vertex) = false or MyIsInjective(vertex_map) = false then + # Error("Mono"); + 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 + # Error("MonoEdge"); + if Set(MyImageCat(vertex_map, VerticesOfEdge(surface1, cur_new_edge))) = Set(VerticesOfEdge(surface2, cur_new_image_edge)) then # QUESTION requires vertex-faithful + if MyUpdateMap(edge_map, cur_new_edge, cur_new_image_edge) = false or MyIsInjective(edge_map) = false then + # Error("Mono"); + is_correct_morphism := false; + fi; + if cur_new_edge in cur_edges then + Add(finished_cur_edges, cur_new_edge); + fi; + # Error("MonoEdge"); + 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]); + # Error("Mono"); + od; + + if is_correct_morphism = true then + # return monomorphism; # uncomment for the lists that make the homomorphism FLAG(LISTS) + return PolygonalMorphismByLists(surface1, surface2, monomorphism[1], monomorphism[2], monomorphism[3]); #FLAG(MORPHISMS) + fi; + od; + od; + return fail; + end; + return MonomorphismIntoSimplicialSurface(surface1, surface2); + end ); +InstallMethod(AllButterflyFaithfulMonomorphismsIntoSimplicialSurface, "for two simplicial surfaces", + [IsSimplicialSurface, IsSimplicialSurface], + function(surface1, surface2) + local PermuteList, AllBijections, AllOneFaceIsomorphisms, MyImage, MyPreImage, MyImageCat, + MyPreImages, MyPreImagesCat, MyUpdateMap, SurfaceIdentityMap, RemoveElement, MyLess, + VertexDegreesOfFace, MyIsInjective, AllMonomorphismsIntoSimplicialSurface; + PermuteList := function(list, perm) + return List(list, x -> x^perm); + end; + + 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, 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; + # res := List(AllPermutations, x -> IndexInducedMap(list1, x)); + return res; + fi; + end; + + MyImage := function(map, x) + return map[x]; + end; + + MyImageCat := 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; + + MyPreImage := 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; + + MyPreImagesCat := function(map, y_list) + return Concatenation(List(y_list, y -> MyPreImage(map, y))); + end; + + MyPreImages := function(map) + return MyPreImagesCat(map, Compacted(map)); + end; + + AllOneFaceIsomorphisms := function(face1, surface1, face2, surface2) + local res, e, vertex_maps, vertex_map, mapped_e, i, edge, edge_map, face_map; + res := []; + vertex_maps := AllBijections(VerticesOfFace(surface1, face1), + VerticesOfFace(surface2, face2)); + # edge_map := []; + 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]))); + # Error(); + for i in [1..3] do + for edge in EdgesOfFace(surface2, face2) do + # Error(); + if Set(VerticesOfEdge(surface2, edge)) = Set(mapped_e[i]) then + # Error(); + # mapped_e[i] := edge; + 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; + + MyUpdateMap := 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; + + SurfaceIdentityMap := function(surface) + return [[1..NumberOfVertices(surface)], [1..NumberOfEdges(surface)], [1..NumberOfFaces(surface)]]; + end; + + RemoveElement := function(list, element) + if not element in list then + return fail; + else + Remove(list, Position(list, element)); + fi; + end; + + MyLess := function(fdeg1, fdeg2) + return fdeg1 < fdeg2; + end; + + VertexDegreesOfFace := function(surface, face) + return Set(List(VerticesOfFace(surface, face), v -> DegreeOfVertex(surface, v))); + end; + + MyIsInjective := function(map) + return IsDuplicateFree(Compacted(map)); + end; + + AllMonomorphismsIntoSimplicialSurface := 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)))); + # face_counter1 := ListCounter(CounterOfFaces(surface1)); + # face_counter2 := ListCounter(CounterOfFaces(surface2)); + # face_degrees1 := List(face_counter1, fdegs1 -> Set(fdegs1[1])); + # face_degrees2 := List(face_counter2, fdegs2 -> Set(fdegs2[1])); + if ForAny(face_counter2, fdegs2 -> not fdegs2 in face_counter1) then + # Error("heuristic"); + 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 := 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 := MyPreImages(face_map); + while not IsEmpty(remaining_faces) do + cur_edge := cur_edges[1]; + # Error("Mono"); + # update face_map + if Length(Difference(FacesOfEdge(surface2, edge_map[cur_edge]), face_map)) = 1 then + # Error("Mono"); + new_image_face := Difference(FacesOfEdge(surface2, edge_map[cur_edge]), face_map)[1]; + else # QUESTION not sure if this case is correct + # Error("Mono"); + is_correct_morphism := false; + break; + fi; + new_face := Difference(FacesOfEdge(surface1, cur_edge), mapped_faces)[1]; + + if not new_face in remaining_faces then + # Error("Mono"); + is_correct_morphism := false; + break; + fi; + + if MyUpdateMap(face_map, new_face, new_image_face) = false or MyIsInjective(face_map) = false then + # Error("Mono"); + is_correct_morphism := false; + break; + fi; + mapped_faces := MyPreImages(face_map); + + # update vertex_map + # new_vertex := Difference(VerticesOfFace(surface1, new_face), + # Intersection(List(FacesOfEdge(surface1, cur_edge), F -> VerticesOfFace(surface1, F))))[1]; # QUESTION requires vertex-faithful + new_vertex := Difference(VerticesOfFace(surface1, new_face), VerticesOfEdge(surface1, cur_edge))[1]; + # new_image_vertex := Difference(VerticesOfFace(surface2, new_image_face), + # Intersection(List(FacesOfEdge(surface2, edge_map[cur_edge]), F -> VerticesOfFace(surface2, F))))[1]; # QUESTION requires vertex-faithful + new_image_vertex := Difference(VerticesOfFace(surface2, new_image_face), VerticesOfEdge(surface2, edge_map[cur_edge]))[1]; + if MyUpdateMap(vertex_map, new_vertex, new_image_vertex) = false or MyIsInjective(vertex_map) = false then + # Error("Mono"); + 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 + # Error("MonoEdge"); + if Set(MyImageCat(vertex_map, VerticesOfEdge(surface1, cur_new_edge))) = Set(VerticesOfEdge(surface2, cur_new_image_edge)) then # QUESTION requires vertex-faithful + if MyUpdateMap(edge_map, cur_new_edge, cur_new_image_edge) = false or MyIsInjective(edge_map) = false then + # Error("Mono"); + is_correct_morphism := false; + fi; + if cur_new_edge in cur_edges then + Add(finished_cur_edges, cur_new_edge); + fi; + # Error("MonoEdge"); + 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]); + # Error("Mono"); + od; + + if is_correct_morphism = true then + # Add(res, monomorphism); # uncomment to add the list the monomorphism is made of FLAG(LISTS) + Add(res,PolygonalMorphismByLists(surface1, surface2, monomorphism[1], monomorphism[2], monomorphism[3])); # FLAG(MORPHISMS) + fi; + od; + od; + return res; + end; + return AllMonomorphismsIntoSimplicialSurface(surface1, surface2); + end +); ## ## End of constructions From 825093b20dc6c363dd57f14f69c3504874f19827 Mon Sep 17 00:00:00 2001 From: Flynn Fehre Date: Sun, 10 Mar 2024 19:01:25 +0100 Subject: [PATCH 13/44] removed everything related to DrawConvexFacegraphToTikz in order to split the monomorphism_function branch from the other changes --- gap/PolygonalComplexes/drawing.gd | 91 --------------- gap/PolygonalComplexes/drawing.gi | 185 ------------------------------ 2 files changed, 276 deletions(-) diff --git a/gap/PolygonalComplexes/drawing.gd b/gap/PolygonalComplexes/drawing.gd index 555dea13..b1e2b3d3 100644 --- a/gap/PolygonalComplexes/drawing.gd +++ b/gap/PolygonalComplexes/drawing.gd @@ -1299,10 +1299,6 @@ DrawFacegraphToTikz( tetra, "facegraph_oct_rescaled", pr);; #! * faceCoordinates2D: Modify the coordinates of the faces which are #! represented as vertices in the embedding. #! -#! * spread (Only available for DrawConvexFacegraphToTikz -#! ): Modify the spread of -#! the coordinates. -#! #! We will exemplify them with the tetrahedron to make clear how the parameters #! work: #! @@ -1350,75 +1346,6 @@ DrawFacegraphToTikz(tetra, #! #! -#! spread (Only available for DrawConvexFacegraphToTikz -#! ): Modifies the position of the -#! vertices representing the faces. The spread parameter can be chosen as a float in the -#! interval (0, 1). Choosing the parameter outside the interval results in -#! an error. Choosing a number close to 1 modifies the face coordinates such -#! that they tend torwards the outer ring of the face graph. Choosing a number -#! close to 0 modifies the face coordinates such that they tend torwards the -#! middle of the face graph. The default spread is set at 0.5. -#! -#! We will exemplify this parameter with the icosahedron. -#! @BeginLog -icosahedron := SimplicialSurfaceByVerticesInFaces([ [ 1, 2, 3 ], - [ 1, 2, 4 ], [ 1, 4, 5 ], [ 1, 5, 6 ], [ 1, 3, 6 ], [ 2, 3, 7 ], - [ 2, 4, 8 ], [ 4, 5, 9 ], [ 5, 6, 10 ], [ 3, 6, 11 ], - [ 2, 7, 8 ], [ 4, 8, 9 ], [ 5, 9, 10 ], [ 6, 10, 11 ], - [ 3, 7, 11 ], [ 7, 8, 12 ], [ 8, 9, 12 ], [ 9, 10, 12 ], - [ 10, 11, 12 ], [ 7, 11, 12 ] ]);; -DrawConvexFacegraphToTikz(icosahedron, -"convex_facegraph_icosahedron_default_spread");; -#! @EndLog - -#! -#! -#! spread (Only available for DrawConvexFacegraphToTikz -#! ): Modifies the position of the -#! vertices representing the faces. The spread parameter can be chosen as a float in the -#! interval (0, 1). Choosing the parameter outside the interval results in -#! an error. Choosing a number close to 1 modifies the face coordinates such -#! that they tend torwards the outer ring of the face graph. Choosing a number -#! close to 0 modifies the face coordinates such that they tend torwards the -#! middle of the face graph. The default spread is set at 0.5. -#! -#! We will exemplify this parameter with the icosahedron. -#! @BeginLog -icosahedron := SimplicialSurfaceByVerticesInFaces([ [ 1, 2, 3 ], - [ 1, 2, 4 ], [ 1, 4, 5 ], [ 1, 5, 6 ], [ 1, 3, 6 ], [ 2, 3, 7 ], - [ 2, 4, 8 ], [ 4, 5, 9 ], [ 5, 6, 10 ], [ 3, 6, 11 ], - [ 2, 7, 8 ], [ 4, 8, 9 ], [ 5, 9, 10 ], [ 6, 10, 11 ], - [ 3, 7, 11 ], [ 7, 8, 12 ], [ 8, 9, 12 ], [ 9, 10, 12 ], - [ 10, 11, 12 ], [ 7, 11, 12 ] ]);; -DrawConvexFacegraphToTikz(icosahedron, -"convex_facegraph_icosahedron_default_spread");; -#! @EndLog -#! -#! \input{_TIKZ_convex_facegraph_icosahedron_default_spread.tex} -#! -#! -#! @BeginLog -pr := rec(spread := 0.3);; -DrawConvexFacegraphToTikz(icosahedron, - "convex_facegraph_icosahedron_low_spread", pr);; -#! @EndLog -#! -#! \input{_TIKZ_convex_facegraph_icosahedron_low_spread.tex} -#! -#! -#! @BeginLog -pr := rec(spread := 0.7);; -DrawConvexFacegraphToTikz(icosahedron, - "convex_facegraph_icosahedron_high_spread", pr);; -#! @EndLog -#! -#! \input{_TIKZ_convex_facegraph_icosahedron_high_spread.tex} -#! -#! -#! -#! @EndChunk - - #! @BeginChunk DrawFacegraphToTikz_Geodesics #! This subsection covers the usage of the parameter that adds geodesics into #! the drawings of DrawFacegraphToTikz @@ -1498,22 +1425,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 - -#! @BeginChunk DrawConvexFacegraphToTikz_example -#! @BeginLog -double6Gon := SimplicialSurfaceByVerticesInFaces([[1,2,3],[1,3,4],[1,4,5], -[1,5,6],[1,6,7],[1,2,7],[2,3,8],[3,4,8],[4,5,8],[5,6,8],[6,7,8],[2,7,8]]);; -#! @EndLog -#! -#! -#! \input{Image_Double6gon.tex} -#! -#! @BeginLog -DrawConvexFacegraphToTikz( double6Gon, "convex_facegraph_Double6Gon.tex" );; -#! @EndLog -#! -#! -#! \input{Image_convex_facegraph_Double6Gon.tex} -#! #! @EndChunk \ No newline at end of file diff --git a/gap/PolygonalComplexes/drawing.gi b/gap/PolygonalComplexes/drawing.gi index 05cd943d..a7202043 100644 --- a/gap/PolygonalComplexes/drawing.gi +++ b/gap/PolygonalComplexes/drawing.gi @@ -2022,188 +2022,3 @@ InstallOtherMethod( DrawFacegraphToTikz, return DrawFacegraphToTikz(surface,file,rec()); end ); - - -InstallMethod( DrawConvexFacegraphToTikz, - "for a closed vertex-faithful simplicial sphere, a file name and a record", - [IsSimplicialSurface, IsString, IsRecord], - function(surf, name, record) - local graph, SplitListPosition, InFilterFunc, - IntersectionFilterFunc, CorrectFacesOfVertexFilter, WeightedCentricParameters, - TwoWeightedCentricParameters, MainHelp, RegularPolygon, DrawConvexFaceGraph, DrawGraph, q; - if not (IsClosedSurface(surf) and IsVertexFaithful(surf) and EulerCharacteristic(surf) = 2) and not IsBound(printRecord.faceCoordinates2D) then - return fail; - fi; - - SplitListPosition := function(list, v) # help function - local i, res1, res2; - res1:=[]; - res2:=[]; - for i in [2..v] do - Add(res1, list[i]); - od; - for i in [(v + 1)..Length(list)] do - Add(res2, list[i]); - od; - Add(res1, list[1]); - Add(res2, list[1]); - Add(res2, list[v]); - return [res1, res2]; - end; - - InFilterFunc := function(cur1, cur2, list) # help function - if cur1 in list and cur2 in list then - return true; - else - return false; - fi; - end; - - IntersectionFilterFunc := function(faceGraph, list) # help function - if not IsEmpty(Intersection(faceGraph, list)) then - return true; - else - return false; - fi; - end; - - CorrectFacesOfVertexFilter := function(cur1, cur2, faceGraph, list) # help function - return InFilterFunc(cur1, cur2, list) and IntersectionFilterFunc(faceGraph, list); - end; - - WeightedCentricParameters := function(list, p) # help function - return Float(p)*list[1] + Float((1-p)/2)*(list[2] + list[3]); - end; - - TwoWeightedCentricParameters := function(list, p, q) # help function - local res; - res := []; - Add(res, p*list[1] + (1-p)*q*list[2] + (1-p)*(1-q)*list[3]); - Add(res, p*list[1] + (1-p)*(1-q)*list[2] + (1-p)*q*list[3]); - return res; - end; - - RegularPolygon := function(list) #returns vertices of a regular polygon as a list of [vert, [x,y]] - local n, res, i; - res := []; - n := Length(list); - for i in [1..n] do - Add(res, [list[i], [Cos(2*3.14159265*((i-1)/n)), Sin(2*3.14159265*((i-1)/n))]]); - od; - return res; - end; - - MainHelp := function(surf, cur, faceGraph, spread, q) - local res, mainHelpi, curi, curLength, i, toSplitVertex, toSplitVertexPos, nodesOfFaceGraph, alreadyPositionedNeighbours, neighbours, v, newv, correctFacesOfVertex; - if Length(cur) >= 2 then # More than one convex drawing plane - res := []; - for i in [1..Length(cur)] do - mainHelpi := MainHelp(surf, [cur[i]], faceGraph, spread, q); - curi := mainHelpi[1]; - res := Concatenation(res, curi); - faceGraph := Set(Concatenation(faceGraph, mainHelpi[2])); - od; - return [res, faceGraph]; - else # Only one convex drawing plane - cur := cur[1]; # deabstracting the only current list - curLength := Length(cur); - if curLength < 2 then - return [[[]], faceGraph]; - else - neighbours := NeighbourFacesOfFace(surf, cur[1][1]); - nodesOfFaceGraph := List(faceGraph, x -> x[1]); - alreadyPositionedNeighbours := Difference(neighbours, [cur[2][1], cur[curLength][1]]); - if Length(Intersection(List(cur, x -> x[1]), alreadyPositionedNeighbours)) = 0 then # case 1: edge does not violate convex drawing plane - if Length(Intersection(nodesOfFaceGraph, neighbours)) = 1 then # Only one neighbour has been positioned already, so 2 more have to be added - correctFacesOfVertex := Filtered(FacesOfVertices(surf), x -> CorrectFacesOfVertexFilter(cur[1][1], cur[2][1], List(faceGraph, y -> y[1]), x)); - for v in Difference(Difference(neighbours, correctFacesOfVertex[1]), nodesOfFaceGraph) do - newv := [v, TwoWeightedCentricParameters([cur[1][2], cur[2][2], cur[curLength][2]], spread, q)[2]]; - Add(faceGraph, newv); - Add(cur, newv); - od; - for v in Difference(Intersection(neighbours, correctFacesOfVertex[1]), nodesOfFaceGraph) do - newv := [v, TwoWeightedCentricParameters([cur[1][2], cur[2][2], cur[curLength][2]], spread, q)[1]]; - Add(faceGraph, newv); - Add(cur, newv); - od; - Remove(cur, 1); - return [[cur], faceGraph]; - elif Length(Intersection(nodesOfFaceGraph, neighbours)) = 2 then # Only two neighbours have been positioned already, so 1 more has to be added - for v in neighbours do - if not v in nodesOfFaceGraph then # and (ForAny(VerticesOfFace(surf, v), faceVertex -> Length(Intersection(List(cur, x -> x[1]), FacesAsList(UmbrellaPathOfVertex(surf, faceVertex)))) >= 3)) - newv := [v, WeightedCentricParameters([cur[1][2], cur[2][2], cur[curLength][2]], spread)]; - Add(faceGraph, newv); - Remove(cur, 1); - Add(cur, newv); - fi; - od; - return [[cur], faceGraph]; - elif Length(Intersection(nodesOfFaceGraph, neighbours)) = 3 then # All three neighbours have been positioned already, so no more have to be added - Remove(cur, 1); - return [[cur], faceGraph]; - fi; - else # case 2: edge slices convex drawing plane in two and splits it - toSplitVertex := Intersection(List(cur, x -> x[1]), alreadyPositionedNeighbours)[1]; - toSplitVertexPos := Position(List(cur, x -> x[1]), toSplitVertex); - return [SplitListPosition(cur, toSplitVertexPos), faceGraph]; - fi; - fi; - fi; - end; - - RegularPolygon := function(list) #returns vertices of a regular polygon as a list of [vert, [x,y]] - local n, res, i; - res:=[]; - n:=Length(list); - for i in [1..n] do - Add(res,[list[i],[Cos(2*3.14159265*((i-1)/n)),Sin(2*3.14159265*((i-1)/n))]]); - od; - return res; - end; - - DrawConvexFaceGraph := function(surf, spread, q) - local cur, faceGraph, path, mainHelp, maxPathPos; - maxPathPos := PositionMaximum(List(UmbrellaPathsOfVertices(surf), x -> Length(FacesAsList(x)))); - path := UmbrellaPathOfVertex(surf, maxPathPos); # Start with the biggest UmbrellaPath - # path := UmbrellaPathOfVertex(surf, Vertices(surf)[1]); # Start with the UmbrellaPath of the vertex 1 - cur := [RegularPolygon(FacesAsList(path))]; - faceGraph := RegularPolygon(FacesAsList(path)); - while Length(faceGraph) < NumberOfFaces(surf) do - mainHelp := MainHelp(surf, cur, faceGraph, spread, q); - cur := mainHelp[1]; - faceGraph := mainHelp[2]; - od; - return faceGraph; - end; - - if not "spread" in RecNames(record) then - record.spread := Float(1/2); - elif record.spread >= Float(1) or record.spread <= Float(0) then - Error("The spread parameter has to be chosen in the interval (0, 1) !"); - fi; - q := Float(7/9); # another parameter that controls the spread but probably not important enough to let the user control it. q must be chosen in the interval ((1/2), 1). - graph := DrawConvexFaceGraph(surf, Float(record.spread), q); - SortBy(graph, x -> x[1]); - if "scale" in RecNames(record) and "faceCoordinates2D" in RecNames(record) then - return DrawFacegraphToTikz(surf, name, record); - elif (not "scale" in RecNames(record)) and "faceCoordinates2D" in RecNames(record) then - record.scale := 4; - elif "scale" in RecNames(record) and (not "faceCoordinates2D" in RecNames(record)) then - record.faceCoordinates2D := List(graph, x -> x[2]); - else - record.faceCoordinates2D := List(graph, x -> x[2]); - record.scale := 4; - fi; - - return DrawFacegraphToTikz(surf, name, record); - end -); - -InstallOtherMethod( DrawConvexFacegraphToTikz, - "for a simplicial surface and a file name", - [IsSimplicialSurface, IsString], - function(surf, name) - return DrawConvexFacegraphToTikz(surf, name, rec()); - end -); - From f22203d2bbf61dda2bae454717be7da4e5260eaf Mon Sep 17 00:00:00 2001 From: Flynn Fehre Date: Sun, 10 Mar 2024 19:22:38 +0100 Subject: [PATCH 14/44] removed everything related to ButterflyFaithfulMonomorphismIntoSimplicialSurface in order to split facegraph_function branch --- gap/Morphisms/morphisms.gd | 75 ------ gap/Morphisms/morphisms.gi | 516 ------------------------------------- 2 files changed, 591 deletions(-) diff --git a/gap/Morphisms/morphisms.gd b/gap/Morphisms/morphisms.gd index 8b01c12c..a494e951 100644 --- a/gap/Morphisms/morphisms.gd +++ b/gap/Morphisms/morphisms.gd @@ -422,81 +422,6 @@ 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. -#! -#! \begin{tikzpicture}[vertexStyle, edgeStyle, faceStyle] -#! \input{Image_Butterfly_Faithful_Monomorphism_Hexagon.tex} -#! \end{tikzpicture} -#! -#! @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. -#! -#! \begin{tikzpicture}[vertexStyle, edgeStyle, faceStyle] -#! \input{Image_Butterfly_Faithful_Monomorphism_Hexagon.tex} -#! \end{tikzpicture} -#! -#! @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 #! diff --git a/gap/Morphisms/morphisms.gi b/gap/Morphisms/morphisms.gi index e98c202f..b8726847 100644 --- a/gap/Morphisms/morphisms.gi +++ b/gap/Morphisms/morphisms.gi @@ -480,522 +480,6 @@ InstallMethod( InverseGeneralMapping, "for a polygonal morphism", end ); -InstallMethod(ButterflyFaithfulMonomorphismIntoSimplicialSurface, "for two simplicial surfaces", - [IsSimplicialSurface, IsSimplicialSurface], - function(surface1, surface2) - local PermuteList, AllBijections, AllOneFaceIsomorphisms, MyImage, MyPreImage, MyImageCat, - MyPreImages, MyPreImagesCat, MyUpdateMap, SurfaceIdentityMap, RemoveElement, MyLess, - VertexDegreesOfFace, MyIsInjective, MonomorphismIntoSimplicialSurface; - PermuteList := function(list, perm) - return List(list, x -> x^perm); - end; - - 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, 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; - # res := List(AllPermutations, x -> IndexInducedMap(list1, x)); - return res; - fi; - end; - - MyImage := function(map, x) - return map[x]; - end; - - MyImageCat := 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; - - MyPreImage := 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; - - MyPreImagesCat := function(map, y_list) - return Concatenation(List(y_list, y -> MyPreImage(map, y))); - end; - - MyPreImages := function(map) - return MyPreImagesCat(map, Compacted(map)); - end; - - AllOneFaceIsomorphisms := function(face1, surface1, face2, surface2) - local res, e, vertex_maps, vertex_map, mapped_e, i, edge, edge_map, face_map; - res := []; - vertex_maps := AllBijections(VerticesOfFace(surface1, face1), - VerticesOfFace(surface2, face2)); - # edge_map := []; - 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]))); - # Error(); - for i in [1..3] do - for edge in EdgesOfFace(surface2, face2) do - # Error(); - if Set(VerticesOfEdge(surface2, edge)) = Set(mapped_e[i]) then - # Error(); - # mapped_e[i] := edge; - 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; - - MyUpdateMap := 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; - - SurfaceIdentityMap := function(surface) - return [[1..NumberOfVertices(surface)], [1..NumberOfEdges(surface)], [1..NumberOfFaces(surface)]]; - end; - - RemoveElement := function(list, element) - if not element in list then - return fail; - else - Remove(list, Position(list, element)); - fi; - end; - - MyLess := function(fdeg1, fdeg2) - return fdeg1 < fdeg2; - end; - - VertexDegreesOfFace := function(surface, face) - return Set(List(VerticesOfFace(surface, face), v -> DegreeOfVertex(surface, v))); - end; - - MyIsInjective := function(map) - return IsDuplicateFree(Compacted(map)); - end; - MonomorphismIntoSimplicialSurface := 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)))); - # face_counter1 := ListCounter(CounterOfFaces(surface1)); - # face_counter2 := ListCounter(CounterOfFaces(surface2)); - # face_degrees1 := List(face_counter1, fdegs1 -> Set(fdegs1[1])); - # face_degrees2 := List(face_counter2, fdegs2 -> Set(fdegs2[1])); - if ForAny(face_counter2, fdegs2 -> not fdegs2 in face_counter1) then - # Error("heuristic"); - 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 := 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 := MyPreImages(face_map); - while not IsEmpty(remaining_faces) do - cur_edge := cur_edges[1]; - # Error("Mono"); - # update face_map - if Length(Difference(FacesOfEdge(surface2, edge_map[cur_edge]), face_map)) = 1 then - # Error("Mono"); - new_image_face := Difference(FacesOfEdge(surface2, edge_map[cur_edge]), face_map)[1]; - else # QUESTION not sure if this case is correct - # Error("Mono"); - is_correct_morphism := false; - break; - fi; - new_face := Difference(FacesOfEdge(surface1, cur_edge), mapped_faces)[1]; - - if not new_face in remaining_faces then - # Error("Mono"); - is_correct_morphism := false; - break; - fi; - - if MyUpdateMap(face_map, new_face, new_image_face) = false or MyIsInjective(face_map) = false then - # Error("Mono"); - is_correct_morphism := false; - break; - fi; - mapped_faces := MyPreImages(face_map); - - # update vertex_map - # new_vertex := Difference(VerticesOfFace(surface1, new_face), - # Intersection(List(FacesOfEdge(surface1, cur_edge), F -> VerticesOfFace(surface1, F))))[1]; # QUESTION requires vertex-faithful - new_vertex := Difference(VerticesOfFace(surface1, new_face), VerticesOfEdge(surface1, cur_edge))[1]; - # new_image_vertex := Difference(VerticesOfFace(surface2, new_image_face), - # Intersection(List(FacesOfEdge(surface2, edge_map[cur_edge]), F -> VerticesOfFace(surface2, F))))[1]; # QUESTION requires vertex-faithful - new_image_vertex := Difference(VerticesOfFace(surface2, new_image_face), VerticesOfEdge(surface2, edge_map[cur_edge]))[1]; - if MyUpdateMap(vertex_map, new_vertex, new_image_vertex) = false or MyIsInjective(vertex_map) = false then - # Error("Mono"); - 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 - # Error("MonoEdge"); - if Set(MyImageCat(vertex_map, VerticesOfEdge(surface1, cur_new_edge))) = Set(VerticesOfEdge(surface2, cur_new_image_edge)) then # QUESTION requires vertex-faithful - if MyUpdateMap(edge_map, cur_new_edge, cur_new_image_edge) = false or MyIsInjective(edge_map) = false then - # Error("Mono"); - is_correct_morphism := false; - fi; - if cur_new_edge in cur_edges then - Add(finished_cur_edges, cur_new_edge); - fi; - # Error("MonoEdge"); - 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]); - # Error("Mono"); - od; - - if is_correct_morphism = true then - # return monomorphism; # uncomment for the lists that make the homomorphism FLAG(LISTS) - return PolygonalMorphismByLists(surface1, surface2, monomorphism[1], monomorphism[2], monomorphism[3]); #FLAG(MORPHISMS) - fi; - od; - od; - return fail; - end; - return MonomorphismIntoSimplicialSurface(surface1, surface2); - end -); - -InstallMethod(AllButterflyFaithfulMonomorphismsIntoSimplicialSurface, "for two simplicial surfaces", - [IsSimplicialSurface, IsSimplicialSurface], - function(surface1, surface2) - local PermuteList, AllBijections, AllOneFaceIsomorphisms, MyImage, MyPreImage, MyImageCat, - MyPreImages, MyPreImagesCat, MyUpdateMap, SurfaceIdentityMap, RemoveElement, MyLess, - VertexDegreesOfFace, MyIsInjective, AllMonomorphismsIntoSimplicialSurface; - PermuteList := function(list, perm) - return List(list, x -> x^perm); - end; - - 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, 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; - # res := List(AllPermutations, x -> IndexInducedMap(list1, x)); - return res; - fi; - end; - - MyImage := function(map, x) - return map[x]; - end; - - MyImageCat := 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; - - MyPreImage := 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; - - MyPreImagesCat := function(map, y_list) - return Concatenation(List(y_list, y -> MyPreImage(map, y))); - end; - - MyPreImages := function(map) - return MyPreImagesCat(map, Compacted(map)); - end; - - AllOneFaceIsomorphisms := function(face1, surface1, face2, surface2) - local res, e, vertex_maps, vertex_map, mapped_e, i, edge, edge_map, face_map; - res := []; - vertex_maps := AllBijections(VerticesOfFace(surface1, face1), - VerticesOfFace(surface2, face2)); - # edge_map := []; - 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]))); - # Error(); - for i in [1..3] do - for edge in EdgesOfFace(surface2, face2) do - # Error(); - if Set(VerticesOfEdge(surface2, edge)) = Set(mapped_e[i]) then - # Error(); - # mapped_e[i] := edge; - 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; - - MyUpdateMap := 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; - - SurfaceIdentityMap := function(surface) - return [[1..NumberOfVertices(surface)], [1..NumberOfEdges(surface)], [1..NumberOfFaces(surface)]]; - end; - - RemoveElement := function(list, element) - if not element in list then - return fail; - else - Remove(list, Position(list, element)); - fi; - end; - - MyLess := function(fdeg1, fdeg2) - return fdeg1 < fdeg2; - end; - - VertexDegreesOfFace := function(surface, face) - return Set(List(VerticesOfFace(surface, face), v -> DegreeOfVertex(surface, v))); - end; - - MyIsInjective := function(map) - return IsDuplicateFree(Compacted(map)); - end; - - AllMonomorphismsIntoSimplicialSurface := 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)))); - # face_counter1 := ListCounter(CounterOfFaces(surface1)); - # face_counter2 := ListCounter(CounterOfFaces(surface2)); - # face_degrees1 := List(face_counter1, fdegs1 -> Set(fdegs1[1])); - # face_degrees2 := List(face_counter2, fdegs2 -> Set(fdegs2[1])); - if ForAny(face_counter2, fdegs2 -> not fdegs2 in face_counter1) then - # Error("heuristic"); - 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 := 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 := MyPreImages(face_map); - while not IsEmpty(remaining_faces) do - cur_edge := cur_edges[1]; - # Error("Mono"); - # update face_map - if Length(Difference(FacesOfEdge(surface2, edge_map[cur_edge]), face_map)) = 1 then - # Error("Mono"); - new_image_face := Difference(FacesOfEdge(surface2, edge_map[cur_edge]), face_map)[1]; - else # QUESTION not sure if this case is correct - # Error("Mono"); - is_correct_morphism := false; - break; - fi; - new_face := Difference(FacesOfEdge(surface1, cur_edge), mapped_faces)[1]; - - if not new_face in remaining_faces then - # Error("Mono"); - is_correct_morphism := false; - break; - fi; - - if MyUpdateMap(face_map, new_face, new_image_face) = false or MyIsInjective(face_map) = false then - # Error("Mono"); - is_correct_morphism := false; - break; - fi; - mapped_faces := MyPreImages(face_map); - - # update vertex_map - # new_vertex := Difference(VerticesOfFace(surface1, new_face), - # Intersection(List(FacesOfEdge(surface1, cur_edge), F -> VerticesOfFace(surface1, F))))[1]; # QUESTION requires vertex-faithful - new_vertex := Difference(VerticesOfFace(surface1, new_face), VerticesOfEdge(surface1, cur_edge))[1]; - # new_image_vertex := Difference(VerticesOfFace(surface2, new_image_face), - # Intersection(List(FacesOfEdge(surface2, edge_map[cur_edge]), F -> VerticesOfFace(surface2, F))))[1]; # QUESTION requires vertex-faithful - new_image_vertex := Difference(VerticesOfFace(surface2, new_image_face), VerticesOfEdge(surface2, edge_map[cur_edge]))[1]; - if MyUpdateMap(vertex_map, new_vertex, new_image_vertex) = false or MyIsInjective(vertex_map) = false then - # Error("Mono"); - 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 - # Error("MonoEdge"); - if Set(MyImageCat(vertex_map, VerticesOfEdge(surface1, cur_new_edge))) = Set(VerticesOfEdge(surface2, cur_new_image_edge)) then # QUESTION requires vertex-faithful - if MyUpdateMap(edge_map, cur_new_edge, cur_new_image_edge) = false or MyIsInjective(edge_map) = false then - # Error("Mono"); - is_correct_morphism := false; - fi; - if cur_new_edge in cur_edges then - Add(finished_cur_edges, cur_new_edge); - fi; - # Error("MonoEdge"); - 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]); - # Error("Mono"); - od; - - if is_correct_morphism = true then - # Add(res, monomorphism); # uncomment to add the list the monomorphism is made of FLAG(LISTS) - Add(res,PolygonalMorphismByLists(surface1, surface2, monomorphism[1], monomorphism[2], monomorphism[3])); # FLAG(MORPHISMS) - fi; - od; - od; - return res; - end; - return AllMonomorphismsIntoSimplicialSurface(surface1, surface2); - end -); - ## ## End of constructions ## From 48e525d0cfd2f01def4cbc154a2d185a2455907b Mon Sep 17 00:00:00 2001 From: Flynn Fehre Date: Mon, 11 Mar 2024 17:57:18 +0100 Subject: [PATCH 15/44] pre-compiled old images for new image structure --- ...utterfly_Faithful_Monomorphism_Hexagon.tex | 51 - doc/Image_convex_facegraph_Double6Gon.tex | 47 - ...utterfly_Faithful_Monomorphism_Hexagon.pdf | Bin 0 -> 40202 bytes ...utterfly_Faithful_Monomorphism_Hexagon.svg | 428 ++++++ .../Image_convex_facegraph_Double6Gon.pdf | Bin 0 -> 13477 bytes .../Image_convex_facegraph_Double6Gon.svg | 822 ++++++++++ ...x_facegraph_icosahedron_default_spread.pdf | Bin 0 -> 15238 bytes ...x_facegraph_icosahedron_default_spread.svg | 1358 +++++++++++++++++ ...nvex_facegraph_icosahedron_high_spread.pdf | Bin 0 -> 15240 bytes ...nvex_facegraph_icosahedron_high_spread.svg | 1358 +++++++++++++++++ ...onvex_facegraph_icosahedron_low_spread.pdf | Bin 0 -> 15225 bytes ...onvex_facegraph_icosahedron_low_spread.svg | 1358 +++++++++++++++++ ...utterfly_Faithful_Monomorphism_Hexagon.tex | 319 ++++ .../Image_convex_facegraph_Double6Gon.tex | 312 ++++ ...x_facegraph_icosahedron_default_spread.tex | 340 +++++ ...nvex_facegraph_icosahedron_high_spread.tex | 341 +++++ ...onvex_facegraph_icosahedron_low_spread.tex | 341 +++++ gap/Morphisms/morphisms.gd | 32 +- gap/PolygonalComplexes/drawing.gd | 62 +- 19 files changed, 7049 insertions(+), 120 deletions(-) delete mode 100644 doc/Image_Butterfly_Faithful_Monomorphism_Hexagon.tex delete mode 100644 doc/Image_convex_facegraph_Double6Gon.tex create mode 100644 doc/images/Image_Butterfly_Faithful_Monomorphism_Hexagon.pdf create mode 100644 doc/images/Image_Butterfly_Faithful_Monomorphism_Hexagon.svg create mode 100644 doc/images/Image_convex_facegraph_Double6Gon.pdf create mode 100644 doc/images/Image_convex_facegraph_Double6Gon.svg create mode 100644 doc/images/_TIKZ_convex_facegraph_icosahedron_default_spread.pdf create mode 100644 doc/images/_TIKZ_convex_facegraph_icosahedron_default_spread.svg create mode 100644 doc/images/_TIKZ_convex_facegraph_icosahedron_high_spread.pdf create mode 100644 doc/images/_TIKZ_convex_facegraph_icosahedron_high_spread.svg create mode 100644 doc/images/_TIKZ_convex_facegraph_icosahedron_low_spread.pdf create mode 100644 doc/images/_TIKZ_convex_facegraph_icosahedron_low_spread.svg create mode 100644 doc/tikz-files/Image_Butterfly_Faithful_Monomorphism_Hexagon.tex create mode 100644 doc/tikz-files/Image_convex_facegraph_Double6Gon.tex create mode 100644 doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_default_spread.tex create mode 100644 doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_high_spread.tex create mode 100644 doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_low_spread.tex diff --git a/doc/Image_Butterfly_Faithful_Monomorphism_Hexagon.tex b/doc/Image_Butterfly_Faithful_Monomorphism_Hexagon.tex deleted file mode 100644 index cac13053..00000000 --- a/doc/Image_Butterfly_Faithful_Monomorphism_Hexagon.tex +++ /dev/null @@ -1,51 +0,0 @@ - -\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} diff --git a/doc/Image_convex_facegraph_Double6Gon.tex b/doc/Image_convex_facegraph_Double6Gon.tex deleted file mode 100644 index a919f0e3..00000000 --- a/doc/Image_convex_facegraph_Double6Gon.tex +++ /dev/null @@ -1,47 +0,0 @@ -\begin{tikzpicture}[vertexBall, edgeDouble=nolabels, faceStyle=nolabels, scale=4] - -\coordinate (V1) at (1. , 0.); -\coordinate (V2) at (0.5000000010362841 , 0.8660254031861397); -\coordinate (V3) at (-0.4999999979274318 , 0.8660254049810364); -\coordinate (V4) at (-1. , 3.589793029841612e-09); -\coordinate (V5) at (-0.5000000041451365 , -0.866025401391243); -\coordinate (V6) at (0.4999999948185802 , -0.8660254067759328); -\coordinate (V7) at (0.8333333326424773 , -5.982988363998724e-10); -\coordinate (V8) at (0.3888888898100303 , 0.7216878361878827); -\coordinate (V9) at (-0.4351851836499495 , 0.6976315766169703); -\coordinate (V10) at (-0.8225308646325142 , -0.02806563506918342); -\coordinate (V11) at (-0.3870884810657467 , -0.7263654412350147); -\coordinate (V12) at (0.4077074718085085 , -0.698411178156174); -\draw[edge] (V1) -- node[edgeLabel] {$1$} (V6); -\draw[edge] (V1) -- node[edgeLabel] {$2$} (V2); -\draw[edge] (V2) -- node[edgeLabel] {$3$} (V3); -\draw[edge] (V3) -- node[edgeLabel] {$4$} (V4); -\draw[edge] (V4) -- node[edgeLabel] {$5$} (V5); -\draw[edge] (V5) -- node[edgeLabel] {$6$} (V6); -\draw[edge] (V1) -- node[edgeLabel] {$7$} (V7); -\draw[edge] (V6) -- node[edgeLabel] {$8$} (V12); -\draw[edge] (V7) -- node[edgeLabel] {$9$} (V12); -\draw[edge] (V2) -- node[edgeLabel] {$10$} (V8); -\draw[edge] (V7) -- node[edgeLabel] {$11$} (V8); -\draw[edge] (V3) -- node[edgeLabel] {$12$} (V9); -\draw[edge] (V8) -- node[edgeLabel] {$13$} (V9); -\draw[edge] (V4) -- node[edgeLabel] {$14$} (V10); -\draw[edge] (V9) -- node[edgeLabel] {$15$} (V10); -\draw[edge] (V5) -- node[edgeLabel] {$16$} (V11); -\draw[edge] (V10) -- node[edgeLabel] {$17$} (V11); -\draw[edge] (V11) -- node[edgeLabel] {$18$} (V12); -% Draw the faces -\vertexLabelR{V1}{left}{$1$} -\vertexLabelR{V2}{left}{$2$} -\vertexLabelR{V3}{left}{$3$} -\vertexLabelR{V4}{left}{$4$} -\vertexLabelR{V5}{left}{$5$} -\vertexLabelR{V6}{left}{$6$} -\vertexLabelR{V7}{left}{$7$} -\vertexLabelR{V8}{left}{$8$} -\vertexLabelR{V9}{left}{$9$} -\vertexLabelR{V10}{left}{$10$} -\vertexLabelR{V11}{left}{$11$} -\vertexLabelR{V12}{left}{$12$} -\end{tikzpicture} - diff --git a/doc/images/Image_Butterfly_Faithful_Monomorphism_Hexagon.pdf b/doc/images/Image_Butterfly_Faithful_Monomorphism_Hexagon.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b2d0a87dda591ffb4fe7cbb90cf604b6ee57f04b GIT binary patch literal 40202 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 i{H-4;;a@*0%EiRl#RJ!)0C + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/images/Image_convex_facegraph_Double6Gon.pdf b/doc/images/Image_convex_facegraph_Double6Gon.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2eae434c30dbb356ce6526a616703a773980630e GIT binary patch literal 13477 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/images/_TIKZ_convex_facegraph_icosahedron_default_spread.pdf b/doc/images/_TIKZ_convex_facegraph_icosahedron_default_spread.pdf new file mode 100644 index 0000000000000000000000000000000000000000..843ae751a6ed200f8596e02c3fae964d11546599 GIT binary patch literal 15238 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 ID@wrsf5q7V$^ZZW literal 0 HcmV?d00001 diff --git a/doc/images/_TIKZ_convex_facegraph_icosahedron_default_spread.svg b/doc/images/_TIKZ_convex_facegraph_icosahedron_default_spread.svg new file mode 100644 index 00000000..093f1270 --- /dev/null +++ b/doc/images/_TIKZ_convex_facegraph_icosahedron_default_spread.svg @@ -0,0 +1,1358 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/images/_TIKZ_convex_facegraph_icosahedron_high_spread.pdf b/doc/images/_TIKZ_convex_facegraph_icosahedron_high_spread.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5b17f1319a595643c017ae16c4d18312da956b28 GIT binary patch literal 15240 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/images/_TIKZ_convex_facegraph_icosahedron_low_spread.pdf b/doc/images/_TIKZ_convex_facegraph_icosahedron_low_spread.pdf new file mode 100644 index 0000000000000000000000000000000000000000..40fc5bb952fe78b9ed1a3189e30aeb16738e10cc GIT binary patch literal 15225 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 COyQ9L literal 0 HcmV?d00001 diff --git a/doc/images/_TIKZ_convex_facegraph_icosahedron_low_spread.svg b/doc/images/_TIKZ_convex_facegraph_icosahedron_low_spread.svg new file mode 100644 index 00000000..cd4fd7ba --- /dev/null +++ b/doc/images/_TIKZ_convex_facegraph_icosahedron_low_spread.svg @@ -0,0 +1,1358 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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/doc/tikz-files/Image_convex_facegraph_Double6Gon.tex b/doc/tikz-files/Image_convex_facegraph_Double6Gon.tex new file mode 100644 index 00000000..3e6fd2b7 --- /dev/null +++ b/doc/tikz-files/Image_convex_facegraph_Double6Gon.tex @@ -0,0 +1,312 @@ +\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}[vertexBall, edgeDouble=nolabels, faceStyle=nolabels, scale=4] + + \coordinate (V1) at (1. , 0.); + \coordinate (V2) at (0.5000000010362841 , 0.8660254031861397); + \coordinate (V3) at (-0.4999999979274318 , 0.8660254049810364); + \coordinate (V4) at (-1. , 3.589793029841612e-09); + \coordinate (V5) at (-0.5000000041451365 , -0.866025401391243); + \coordinate (V6) at (0.4999999948185802 , -0.8660254067759328); + \coordinate (V7) at (0.8333333326424773 , -5.982988363998724e-10); + \coordinate (V8) at (0.3888888898100303 , 0.7216878361878827); + \coordinate (V9) at (-0.4351851836499495 , 0.6976315766169703); + \coordinate (V10) at (-0.8225308646325142 , -0.02806563506918342); + \coordinate (V11) at (-0.3870884810657467 , -0.7263654412350147); + \coordinate (V12) at (0.4077074718085085 , -0.698411178156174); + \draw[edge] (V1) -- node[edgeLabel] {$1$} (V6); + \draw[edge] (V1) -- node[edgeLabel] {$2$} (V2); + \draw[edge] (V2) -- node[edgeLabel] {$3$} (V3); + \draw[edge] (V3) -- node[edgeLabel] {$4$} (V4); + \draw[edge] (V4) -- node[edgeLabel] {$5$} (V5); + \draw[edge] (V5) -- node[edgeLabel] {$6$} (V6); + \draw[edge] (V1) -- node[edgeLabel] {$7$} (V7); + \draw[edge] (V6) -- node[edgeLabel] {$8$} (V12); + \draw[edge] (V7) -- node[edgeLabel] {$9$} (V12); + \draw[edge] (V2) -- node[edgeLabel] {$10$} (V8); + \draw[edge] (V7) -- node[edgeLabel] {$11$} (V8); + \draw[edge] (V3) -- node[edgeLabel] {$12$} (V9); + \draw[edge] (V8) -- node[edgeLabel] {$13$} (V9); + \draw[edge] (V4) -- node[edgeLabel] {$14$} (V10); + \draw[edge] (V9) -- node[edgeLabel] {$15$} (V10); + \draw[edge] (V5) -- node[edgeLabel] {$16$} (V11); + \draw[edge] (V10) -- node[edgeLabel] {$17$} (V11); + \draw[edge] (V11) -- node[edgeLabel] {$18$} (V12); + % Draw the faces + \vertexLabelR{V1}{left}{$1$} + \vertexLabelR{V2}{left}{$2$} + \vertexLabelR{V3}{left}{$3$} + \vertexLabelR{V4}{left}{$4$} + \vertexLabelR{V5}{left}{$5$} + \vertexLabelR{V6}{left}{$6$} + \vertexLabelR{V7}{left}{$7$} + \vertexLabelR{V8}{left}{$8$} + \vertexLabelR{V9}{left}{$9$} + \vertexLabelR{V10}{left}{$10$} + \vertexLabelR{V11}{left}{$11$} + \vertexLabelR{V12}{left}{$12$} + \end{tikzpicture} + +\end{document} + + diff --git a/doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_default_spread.tex b/doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_default_spread.tex new file mode 100644 index 00000000..e527e1bc --- /dev/null +++ b/doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_default_spread.tex @@ -0,0 +1,340 @@ +\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}[vertexBall, edgeDouble=nolabels, faceStyle=nolabels, scale=4] + + \coordinate (V1) at (1. , 0.); + \coordinate (V2) at (0.3090169889123937 , -0.9510565180700449); + \coordinate (V3) at (-0.8090169969069803 , -0.5877852488074289); + \coordinate (V4) at (-0.8090169926869255 , 0.587785254615836); + \coordinate (V5) at (0.3090169957405858 , 0.9510565158514307); + \coordinate (V6) at (0.6545084961632449 , -5.546535453149204e-10); + \coordinate (V7) at (0.2002100305571999 , -0.5895321377810976); + \coordinate (V8) at (-0.4717023517592329 , -0.4560155144296473); + \coordinate (V9) at (-0.5777924021353646 , 0.3025649579663135); + \coordinate (V10) at (0.1158813737393728 , 0.6224745714410109); + \coordinate (V11) at (0.417989412602686 , -0.1600986570320857); + \coordinate (V12) at (-0.2867457540694981 , -0.3391323294699786); + \coordinate (V13) at (-0.4037883433167264 , 0.1450338487604777); + \coordinate (V14) at (0.01213378276305652 , 0.4310209935389311); + \coordinate (V15) at (0.3945647857088452 , 0.1765698733073889); + \coordinate (V16) at (0.2359494642111798 , -0.1206899425566903); + \coordinate (V17) at (-0.1546590631070234 , -0.1844779471328884); + \coordinate (V18) at (-0.2810942085002772 , 0.06104281296509385); + \coordinate (V19) at (-0.03005439329815793 , 0.2932358838093986); + \coordinate (V20) at (0.2593032045979817 , 0.1658676993992546); + \draw[edge] (V1) -- node[edgeLabel] {$1$} (V2); + \draw[edge] (V1) -- node[edgeLabel] {$2$} (V5); + \draw[edge] (V2) -- node[edgeLabel] {$3$} (V3); + \draw[edge] (V3) -- node[edgeLabel] {$4$} (V4); + \draw[edge] (V4) -- node[edgeLabel] {$5$} (V5); + \draw[edge] (V1) -- node[edgeLabel] {$6$} (V6); + \draw[edge] (V2) -- node[edgeLabel] {$7$} (V7); + \draw[edge] (V6) -- node[edgeLabel] {$8$} (V11); + \draw[edge] (V7) -- node[edgeLabel] {$9$} (V11); + \draw[edge] (V5) -- node[edgeLabel] {$10$} (V10); + \draw[edge] (V6) -- node[edgeLabel] {$11$} (V15); + \draw[edge] (V10) -- node[edgeLabel] {$12$} (V15); + \draw[edge] (V3) -- node[edgeLabel] {$13$} (V8); + \draw[edge] (V7) -- node[edgeLabel] {$14$} (V12); + \draw[edge] (V8) -- node[edgeLabel] {$15$} (V12); + \draw[edge] (V4) -- node[edgeLabel] {$16$} (V9); + \draw[edge] (V8) -- node[edgeLabel] {$17$} (V13); + \draw[edge] (V9) -- node[edgeLabel] {$18$} (V13); + \draw[edge] (V9) -- node[edgeLabel] {$19$} (V14); + \draw[edge] (V10) -- node[edgeLabel] {$20$} (V14); + \draw[edge] (V11) -- node[edgeLabel] {$21$} (V16); + \draw[edge] (V15) -- node[edgeLabel] {$22$} (V20); + \draw[edge] (V16) -- node[edgeLabel] {$23$} (V20); + \draw[edge] (V12) -- node[edgeLabel] {$24$} (V17); + \draw[edge] (V16) -- node[edgeLabel] {$25$} (V17); + \draw[edge] (V13) -- node[edgeLabel] {$26$} (V18); + \draw[edge] (V17) -- node[edgeLabel] {$27$} (V18); + \draw[edge] (V14) -- node[edgeLabel] {$28$} (V19); + \draw[edge] (V18) -- node[edgeLabel] {$29$} (V19); + \draw[edge] (V19) -- node[edgeLabel] {$30$} (V20); + % Draw the faces + \vertexLabelR{V1}{left}{$1$} + \vertexLabelR{V2}{left}{$2$} + \vertexLabelR{V3}{left}{$3$} + \vertexLabelR{V4}{left}{$4$} + \vertexLabelR{V5}{left}{$5$} + \vertexLabelR{V6}{left}{$6$} + \vertexLabelR{V7}{left}{$7$} + \vertexLabelR{V8}{left}{$8$} + \vertexLabelR{V9}{left}{$9$} + \vertexLabelR{V10}{left}{$10$} + \vertexLabelR{V11}{left}{$11$} + \vertexLabelR{V12}{left}{$12$} + \vertexLabelR{V13}{left}{$13$} + \vertexLabelR{V14}{left}{$14$} + \vertexLabelR{V15}{left}{$15$} + \vertexLabelR{V16}{left}{$16$} + \vertexLabelR{V17}{left}{$17$} + \vertexLabelR{V18}{left}{$18$} + \vertexLabelR{V19}{left}{$19$} + \vertexLabelR{V20}{left}{$20$} + \end{tikzpicture} + +\end{document} + + diff --git a/doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_high_spread.tex b/doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_high_spread.tex new file mode 100644 index 00000000..4783561d --- /dev/null +++ b/doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_high_spread.tex @@ -0,0 +1,341 @@ +\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}[vertexBall, edgeDouble=nolabels, faceStyle=nolabels, scale=4] + + \coordinate (V1) at (1. , 0.); + \coordinate (V2) at (0.3090169889123937 , -0.9510565180700449); + \coordinate (V3) at (-0.8090169969069803 , -0.5877852488074289); + \coordinate (V4) at (-0.8090169926869255 , 0.587785254615836); + \coordinate (V5) at (0.3090169957405858 , 0.9510565158514307); + \coordinate (V6) at (0.7927050976979469 , -3.327921271889523e-10); + \coordinate (V7) at (0.2424730992248824 , -0.7390375056311521); + \coordinate (V8) at (-0.6182970511232349 , -0.488652952881346); + \coordinate (V9) at (-0.6555846775013854 , 0.4363679932957395); + \coordinate (V10) at (0.2138651127700633 , 0.753907349238458); + \coordinate (V11) at (0.6257282990590397 , -0.1221815949309928); + \coordinate (V12) at (-0.4759335274339455 , -0.4043145436795418); + \coordinate (V13) at (-0.5299770435427567 , 0.3239876612138216); + \coordinate (V14) at (0.1445119225113219 , 0.6121867255933728); + \coordinate (V15) at (0.6209603013165698 , 0.1266425475472756); + \coordinate (V16) at (0.4597638254237214 , -0.1271779158715349); + \coordinate (V17) at (-0.3282846657626078 , -0.2658951127485535); + \coordinate (V18) at (-0.4273051358160279 , 0.2413450347190398); + \coordinate (V19) at (0.1004588251932902 , 0.5013390228086395); + \coordinate (V20) at (0.5253135731118553 , 0.1614011047413686); + \draw[edge] (V1) -- node[edgeLabel] {$1$} (V2); + \draw[edge] (V1) -- node[edgeLabel] {$2$} (V5); + \draw[edge] (V2) -- node[edgeLabel] {$3$} (V3); + \draw[edge] (V3) -- node[edgeLabel] {$4$} (V4); + \draw[edge] (V4) -- node[edgeLabel] {$5$} (V5); + \draw[edge] (V1) -- node[edgeLabel] {$6$} (V6); + \draw[edge] (V2) -- node[edgeLabel] {$7$} (V7); + \draw[edge] (V6) -- node[edgeLabel] {$8$} (V11); + \draw[edge] (V7) -- node[edgeLabel] {$9$} (V11); + \draw[edge] (V5) -- node[edgeLabel] {$10$} (V10); + \draw[edge] (V6) -- node[edgeLabel] {$11$} (V15); + \draw[edge] (V10) -- node[edgeLabel] {$12$} (V15); + \draw[edge] (V3) -- node[edgeLabel] {$13$} (V8); + \draw[edge] (V7) -- node[edgeLabel] {$14$} (V12); + \draw[edge] (V8) -- node[edgeLabel] {$15$} (V12); + \draw[edge] (V4) -- node[edgeLabel] {$16$} (V9); + \draw[edge] (V8) -- node[edgeLabel] {$17$} (V13); + \draw[edge] (V9) -- node[edgeLabel] {$18$} (V13); + \draw[edge] (V9) -- node[edgeLabel] {$19$} (V14); + \draw[edge] (V10) -- node[edgeLabel] {$20$} (V14); + \draw[edge] (V11) -- node[edgeLabel] {$21$} (V16); + \draw[edge] (V15) -- node[edgeLabel] {$22$} (V20); + \draw[edge] (V16) -- node[edgeLabel] {$23$} (V20); + \draw[edge] (V12) -- node[edgeLabel] {$24$} (V17); + \draw[edge] (V16) -- node[edgeLabel] {$25$} (V17); + \draw[edge] (V13) -- node[edgeLabel] {$26$} (V18); + \draw[edge] (V17) -- node[edgeLabel] {$27$} (V18); + \draw[edge] (V14) -- node[edgeLabel] {$28$} (V19); + \draw[edge] (V18) -- node[edgeLabel] {$29$} (V19); + \draw[edge] (V19) -- node[edgeLabel] {$30$} (V20); + % Draw the faces + \vertexLabelR{V1}{left}{$1$} + \vertexLabelR{V2}{left}{$2$} + \vertexLabelR{V3}{left}{$3$} + \vertexLabelR{V4}{left}{$4$} + \vertexLabelR{V5}{left}{$5$} + \vertexLabelR{V6}{left}{$6$} + \vertexLabelR{V7}{left}{$7$} + \vertexLabelR{V8}{left}{$8$} + \vertexLabelR{V9}{left}{$9$} + \vertexLabelR{V10}{left}{$10$} + \vertexLabelR{V11}{left}{$11$} + \vertexLabelR{V12}{left}{$12$} + \vertexLabelR{V13}{left}{$13$} + \vertexLabelR{V14}{left}{$14$} + \vertexLabelR{V15}{left}{$15$} + \vertexLabelR{V16}{left}{$16$} + \vertexLabelR{V17}{left}{$17$} + \vertexLabelR{V18}{left}{$18$} + \vertexLabelR{V19}{left}{$19$} + \vertexLabelR{V20}{left}{$20$} + \end{tikzpicture} + +\end{document} + + + diff --git a/doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_low_spread.tex b/doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_low_spread.tex new file mode 100644 index 00000000..15ae0fe6 --- /dev/null +++ b/doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_low_spread.tex @@ -0,0 +1,341 @@ +\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}[vertexBall, edgeDouble=nolabels, faceStyle=nolabels, scale=4] + + \coordinate (V1) at (1. , 0.); + \coordinate (V2) at (0.3090169889123937 , -0.9510565180700449); + \coordinate (V3) at (-0.8090169969069803 , -0.5877852488074289); + \coordinate (V4) at (-0.8090169926869255 , 0.587785254615836); + \coordinate (V5) at (0.3090169957405858 , 0.9510565158514307); + \coordinate (V6) at (0.5163118946285428 , -7.765149634408886e-10); + \coordinate (V7) at (0.1614864032665868 , -0.4460855978160754); + \coordinate (V8) at (-0.3197938757917752 , -0.4593389774950907); + \coordinate (V9) at (-0.5292706366829111 , 0.1424753670618677); + \coordinate (V10) at (-0.009741685598258207 , 0.4910417935991915); + \coordinate (V11) at (0.2412985701850865 , -0.1664845467062768); + \coordinate (V12) at (-0.1497258880922867 , -0.3025990736622617); + \coordinate (V13) at (-0.3151656185658844 , -0.02476406050888025); + \coordinate (V14) at (-0.1270187743825422 , 0.2664627757024033); + \coordinate (V15) at (0.1747098689598691 , 0.1979538832885492); + \coordinate (V16) at (0.08113396435917979 , -0.08657118064268243); + \coordinate (V17) at (-0.08457670923818356 , -0.1467718202157678); + \coordinate (V18) at (-0.1944452295320299 , -0.07340624254900144); + \coordinate (V19) at (-0.1356899517998978 , 0.1140932896727264); + \coordinate (V20) at (0.03635327717978389 , 0.1223482232574671); + \draw[edge] (V1) -- node[edgeLabel] {$1$} (V2); + \draw[edge] (V1) -- node[edgeLabel] {$2$} (V5); + \draw[edge] (V2) -- node[edgeLabel] {$3$} (V3); + \draw[edge] (V3) -- node[edgeLabel] {$4$} (V4); + \draw[edge] (V4) -- node[edgeLabel] {$5$} (V5); + \draw[edge] (V1) -- node[edgeLabel] {$6$} (V6); + \draw[edge] (V2) -- node[edgeLabel] {$7$} (V7); + \draw[edge] (V6) -- node[edgeLabel] {$8$} (V11); + \draw[edge] (V7) -- node[edgeLabel] {$9$} (V11); + \draw[edge] (V5) -- node[edgeLabel] {$10$} (V10); + \draw[edge] (V6) -- node[edgeLabel] {$11$} (V15); + \draw[edge] (V10) -- node[edgeLabel] {$12$} (V15); + \draw[edge] (V3) -- node[edgeLabel] {$13$} (V8); + \draw[edge] (V7) -- node[edgeLabel] {$14$} (V12); + \draw[edge] (V8) -- node[edgeLabel] {$15$} (V12); + \draw[edge] (V4) -- node[edgeLabel] {$16$} (V9); + \draw[edge] (V8) -- node[edgeLabel] {$17$} (V13); + \draw[edge] (V9) -- node[edgeLabel] {$18$} (V13); + \draw[edge] (V9) -- node[edgeLabel] {$19$} (V14); + \draw[edge] (V10) -- node[edgeLabel] {$20$} (V14); + \draw[edge] (V11) -- node[edgeLabel] {$21$} (V16); + \draw[edge] (V15) -- node[edgeLabel] {$22$} (V20); + \draw[edge] (V16) -- node[edgeLabel] {$23$} (V20); + \draw[edge] (V12) -- node[edgeLabel] {$24$} (V17); + \draw[edge] (V16) -- node[edgeLabel] {$25$} (V17); + \draw[edge] (V13) -- node[edgeLabel] {$26$} (V18); + \draw[edge] (V17) -- node[edgeLabel] {$27$} (V18); + \draw[edge] (V14) -- node[edgeLabel] {$28$} (V19); + \draw[edge] (V18) -- node[edgeLabel] {$29$} (V19); + \draw[edge] (V19) -- node[edgeLabel] {$30$} (V20); + % Draw the faces + \vertexLabelR{V1}{left}{$1$} + \vertexLabelR{V2}{left}{$2$} + \vertexLabelR{V3}{left}{$3$} + \vertexLabelR{V4}{left}{$4$} + \vertexLabelR{V5}{left}{$5$} + \vertexLabelR{V6}{left}{$6$} + \vertexLabelR{V7}{left}{$7$} + \vertexLabelR{V8}{left}{$8$} + \vertexLabelR{V9}{left}{$9$} + \vertexLabelR{V10}{left}{$10$} + \vertexLabelR{V11}{left}{$11$} + \vertexLabelR{V12}{left}{$12$} + \vertexLabelR{V13}{left}{$13$} + \vertexLabelR{V14}{left}{$14$} + \vertexLabelR{V15}{left}{$15$} + \vertexLabelR{V16}{left}{$16$} + \vertexLabelR{V17}{left}{$17$} + \vertexLabelR{V18}{left}{$18$} + \vertexLabelR{V19}{left}{$19$} + \vertexLabelR{V20}{left}{$20$} +\end{tikzpicture} + +\end{document} + + + diff --git a/gap/Morphisms/morphisms.gd b/gap/Morphisms/morphisms.gd index 8b01c12c..62f3f9e1 100644 --- a/gap/Morphisms/morphisms.gd +++ b/gap/Morphisms/morphisms.gd @@ -435,11 +435,17 @@ DeclareAttribute( "InversePolygonalMorphism", IsPolygonalMorphism and IsBijectiv #! 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. -#! -#! \begin{tikzpicture}[vertexStyle, edgeStyle, faceStyle] -#! \input{Image_Butterfly_Faithful_Monomorphism_Hexagon.tex} -#! \end{tikzpicture} -#! +#! +#! <br><img src="./images/Image_Butterfly_Faithful_Monomorphism_Hexagon.svg"> </img> <br> +#! +#! +#! \begin{center} +#! \includegraphics{images/Image_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]], @@ -476,11 +482,17 @@ DeclareOperation( "ButterflyFaithfulMonomorphismIntoSimplicialSurface", [IsSimpl #! 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. -#! -#! \begin{tikzpicture}[vertexStyle, edgeStyle, faceStyle] -#! \input{Image_Butterfly_Faithful_Monomorphism_Hexagon.tex} -#! \end{tikzpicture} -#! +#! +#! <br><img src="./images/Image_Butterfly_Faithful_Monomorphism_Hexagon.svg"> </img> <br> +#! +#! +#! \begin{center} +#! \includegraphics{images/Image_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]], diff --git a/gap/PolygonalComplexes/drawing.gd b/gap/PolygonalComplexes/drawing.gd index 555dea13..aa864a77 100644 --- a/gap/PolygonalComplexes/drawing.gd +++ b/gap/PolygonalComplexes/drawing.gd @@ -1393,26 +1393,48 @@ icosahedron := SimplicialSurfaceByVerticesInFaces([ [ 1, 2, 3 ], DrawConvexFacegraphToTikz(icosahedron, "convex_facegraph_icosahedron_default_spread");; #! @EndLog -#! -#! \input{_TIKZ_convex_facegraph_icosahedron_default_spread.tex} +#! +#! <br><img src="./images/_TIKZ_convex_facegraph_icosahedron_default_spread.svg"> </img> <br> +#! +#! +#! \begin{center} +#! \includegraphics{images/_TIKZ_convex_facegraph_icosahedron_default_spread.pdf} +#! \end{center} +#! +#! +#! Image omitted in terminal text #! -#! #! @BeginLog pr := rec(spread := 0.3);; DrawConvexFacegraphToTikz(icosahedron, "convex_facegraph_icosahedron_low_spread", pr);; #! @EndLog -#! -#! \input{_TIKZ_convex_facegraph_icosahedron_low_spread.tex} +#! +#! <br><img src="./images/_TIKZ_convex_facegraph_icosahedron_low_spread.svg"> </img> <br> +#! +#! +#! \begin{center} +#! \includegraphics{images/_TIKZ_convex_facegraph_icosahedron_low_spread.pdf} +#! \end{center} +#! +#! +#! Image omitted in terminal text #! -#! #! @BeginLog pr := rec(spread := 0.7);; DrawConvexFacegraphToTikz(icosahedron, "convex_facegraph_icosahedron_high_spread", pr);; #! @EndLog -#! -#! \input{_TIKZ_convex_facegraph_icosahedron_high_spread.tex} +#! +#! <br><img src="./images/_TIKZ_convex_facegraph_icosahedron_high_spread.svg"> </img> <br> +#! +#! +#! \begin{center} +#! \includegraphics{images/_TIKZ_convex_facegraph_icosahedron_high_spread.pdf} +#! \end{center} +#! +#! +#! Image omitted in terminal text #! #! #! @@ -1506,14 +1528,30 @@ double6Gon := SimplicialSurfaceByVerticesInFaces([[1,2,3],[1,3,4],[1,4,5], [1,5,6],[1,6,7],[1,2,7],[2,3,8],[3,4,8],[4,5,8],[5,6,8],[6,7,8],[2,7,8]]);; #! @EndLog #! -#! -#! \input{Image_Double6gon.tex} +#! +#! <br><img src="./images/_Wrapper_Image_Double6gon.svg"> </img> <br> +#! +#! +#! \begin{center} +#! \includegraphics{images/_Wrapper_Image_Double6gon.pdf} +#! \end{center} +#! +#! +#! Image omitted in terminal text #! #! @BeginLog DrawConvexFacegraphToTikz( double6Gon, "convex_facegraph_Double6Gon.tex" );; #! @EndLog #! -#! -#! \input{Image_convex_facegraph_Double6Gon.tex} +#! +#! <br><img src="./images/Image_convex_facegraph_Double6Gon.svg"> </img> <br> +#! +#! +#! \begin{center} +#! \includegraphics{images/Image_convex_facegraph_Double6Gon.pdf} +#! \end{center} +#! +#! +#! Image omitted in terminal text #! #! @EndChunk \ No newline at end of file From f9bf72cd000d7e594534b1e27884b5628c61004b Mon Sep 17 00:00:00 2001 From: Flynn Fehre Date: Mon, 11 Mar 2024 18:05:43 +0100 Subject: [PATCH 16/44] again deleting everything related to ButterflyFaithfulMonomorphismIntoSimplicialSurface --- ...utterfly_Faithful_Monomorphism_Hexagon.pdf | Bin 40202 -> 0 bytes ...utterfly_Faithful_Monomorphism_Hexagon.svg | 428 ------------------ 2 files changed, 428 deletions(-) delete mode 100644 doc/images/Image_Butterfly_Faithful_Monomorphism_Hexagon.pdf delete mode 100644 doc/images/Image_Butterfly_Faithful_Monomorphism_Hexagon.svg diff --git a/doc/images/Image_Butterfly_Faithful_Monomorphism_Hexagon.pdf b/doc/images/Image_Butterfly_Faithful_Monomorphism_Hexagon.pdf deleted file mode 100644 index b2d0a87dda591ffb4fe7cbb90cf604b6ee57f04b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40202 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 i{H-4;;a@*0%EiRl#RJ!)0C - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From f9a2d2437ae1197fc00dd89635a2f61cc839ba74 Mon Sep 17 00:00:00 2001 From: Flynn Fehre Date: Mon, 11 Mar 2024 18:14:47 +0100 Subject: [PATCH 17/44] again deleting everything related to DrawConvexFacegraphToTikz --- .../Image_convex_facegraph_Double6Gon.pdf | Bin 13477 -> 0 bytes .../Image_convex_facegraph_Double6Gon.svg | 822 ---------- ...x_facegraph_icosahedron_default_spread.pdf | Bin 15238 -> 0 bytes ...x_facegraph_icosahedron_default_spread.svg | 1358 ----------------- ...nvex_facegraph_icosahedron_high_spread.pdf | Bin 15240 -> 0 bytes ...nvex_facegraph_icosahedron_high_spread.svg | 1358 ----------------- ...onvex_facegraph_icosahedron_low_spread.pdf | Bin 15225 -> 0 bytes ...onvex_facegraph_icosahedron_low_spread.svg | 1358 ----------------- 8 files changed, 4896 deletions(-) delete mode 100644 doc/images/Image_convex_facegraph_Double6Gon.pdf delete mode 100644 doc/images/Image_convex_facegraph_Double6Gon.svg delete mode 100644 doc/images/_TIKZ_convex_facegraph_icosahedron_default_spread.pdf delete mode 100644 doc/images/_TIKZ_convex_facegraph_icosahedron_default_spread.svg delete mode 100644 doc/images/_TIKZ_convex_facegraph_icosahedron_high_spread.pdf delete mode 100644 doc/images/_TIKZ_convex_facegraph_icosahedron_high_spread.svg delete mode 100644 doc/images/_TIKZ_convex_facegraph_icosahedron_low_spread.pdf delete mode 100644 doc/images/_TIKZ_convex_facegraph_icosahedron_low_spread.svg diff --git a/doc/images/Image_convex_facegraph_Double6Gon.pdf b/doc/images/Image_convex_facegraph_Double6Gon.pdf deleted file mode 100644 index 2eae434c30dbb356ce6526a616703a773980630e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13477 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/images/_TIKZ_convex_facegraph_icosahedron_default_spread.pdf b/doc/images/_TIKZ_convex_facegraph_icosahedron_default_spread.pdf deleted file mode 100644 index 843ae751a6ed200f8596e02c3fae964d11546599..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15238 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 ID@wrsf5q7V$^ZZW diff --git a/doc/images/_TIKZ_convex_facegraph_icosahedron_default_spread.svg b/doc/images/_TIKZ_convex_facegraph_icosahedron_default_spread.svg deleted file mode 100644 index 093f1270..00000000 --- a/doc/images/_TIKZ_convex_facegraph_icosahedron_default_spread.svg +++ /dev/null @@ -1,1358 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/images/_TIKZ_convex_facegraph_icosahedron_high_spread.pdf b/doc/images/_TIKZ_convex_facegraph_icosahedron_high_spread.pdf deleted file mode 100644 index 5b17f1319a595643c017ae16c4d18312da956b28..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15240 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/images/_TIKZ_convex_facegraph_icosahedron_low_spread.pdf b/doc/images/_TIKZ_convex_facegraph_icosahedron_low_spread.pdf deleted file mode 100644 index 40fc5bb952fe78b9ed1a3189e30aeb16738e10cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15225 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 COyQ9L diff --git a/doc/images/_TIKZ_convex_facegraph_icosahedron_low_spread.svg b/doc/images/_TIKZ_convex_facegraph_icosahedron_low_spread.svg deleted file mode 100644 index cd4fd7ba..00000000 --- a/doc/images/_TIKZ_convex_facegraph_icosahedron_low_spread.svg +++ /dev/null @@ -1,1358 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 2c7a2821335300be8ef9e90215932d7961754d4d Mon Sep 17 00:00:00 2001 From: Flynn Fehre Date: Tue, 12 Mar 2024 11:27:52 +0100 Subject: [PATCH 18/44] fixing the documentation --- gap/PolygonalComplexes/drawing.gd | 2 + gap/PolygonalComplexes/embedding.gd | 66 +---------------------------- 2 files changed, 3 insertions(+), 65 deletions(-) diff --git a/gap/PolygonalComplexes/drawing.gd b/gap/PolygonalComplexes/drawing.gd index b1e2b3d3..662dae41 100644 --- a/gap/PolygonalComplexes/drawing.gd +++ b/gap/PolygonalComplexes/drawing.gd @@ -1345,6 +1345,8 @@ DrawFacegraphToTikz(tetra, #! Image omitted in terminal text #! #! +#! +#! @EndChunk #! @BeginChunk DrawFacegraphToTikz_Geodesics #! This subsection covers the usage of the parameter that adds geodesics into diff --git a/gap/PolygonalComplexes/embedding.gd b/gap/PolygonalComplexes/embedding.gd index 9c85cdc4..1fe18f8f 100644 --- a/gap/PolygonalComplexes/embedding.gd +++ b/gap/PolygonalComplexes/embedding.gd @@ -382,68 +382,4 @@ DeclareOperation( "DrawFacegraphToTikz", [IsSimplicialSurface ,IsString,IsRecord #! @Subsection Output control #! @SubsectionLabel DrawFacegraphToTikz_Output -#! @InsertChunk DrawFacegraphToTikz_Output -#! -#! @BeginGroup DrawConvexFacegraphToTikz -#! @Description -#! Draw the face graph of the given surface into a tex-file (using TikZ). -#! An introduction to the use of this method (along with several examples) -#! can be found at the start of section . -#! If surface is a simplicial vertex faithful sphere and the function -#! is used without the argument printRecord, then the drawing printed -#! into file is a planar embedding of the face graph of surface, -#! where the vertices of the surface are identified by the faces of the -#! embedding. DrawConvexFacegraphToTikz differs from DrawFacegraphToTikz -#! () by constructing the face graph -#! by successively manipulating a convex drawing plane and calculating new face coordinates. -#! The new coordinates are then drawn with DrawFacegraphToTikz. -#! This results in an embedding which maps the faces -#! of one of the largest umbrella paths on the outer ring as a -#! regular polygon. Trying to use the function for a surface that is not a -#! vertex-faithful sphere results in returning fail. -#! -#! * If the given file does not end in .tex the ending -#! .tex will be added to it. -#! * The given file will be overwritten without asking if it already exists. -#! If you don't have permission to write in that file, this method will -#! throw an error. -#! * The particulars of the drawing are determined by the -#! given printRecord. If this is not given and surface is a -#! simplicial sphere, the default settings are used. -#! * The printRecord will be modified and returned by this method. -#! It contains the data to recreate the drawing of the surface. -#! -#! -#! There are several parameters to change the output of this method. -#! Since the design of the parameters is the design of the parameters -#! of DrawFacegraphToTikz(), -#! one can also refer to the corresponding subsections for a better -#! understanding. -#! There are the following classes of parameters: -#! * Colours -#! (): Change the -#! colours of edges and faces represented as vertices. -#! * Labels -#! (): Modify the labels -#! of vertices, edges and faces. -#! * Scale -#! (): These -#! parameters control the size of the drawing. -#! * faceCoordinates2D -#! (): -#! Modify the 2D-coordinates of the faces. -#! * Geodesics -#! (): Draw the -#! geodesics of the simplicial surface into the file. -#! * Output control -#! (): Modify how the -#! &LaTeX;-output behaves and how much information is printed to the -#! console. -#! -#! Consider the following example of the double-6-gon: -#! @InsertChunk DrawConvexFacegraphToTikz_example -#! -#! @Returns a record -#! @Arguments surface, file[, printRecord] -DeclareOperation( "DrawConvexFacegraphToTikz", [IsSimplicialSurface, IsString, IsRecord]); -#! @EndGroup \ No newline at end of file +#! @InsertChunk DrawFacegraphToTikz_Output \ No newline at end of file From 2323da88a4b13af543b1c09182f4a9ebfc14b595 Mon Sep 17 00:00:00 2001 From: Flynn Fehre Date: Wed, 13 Mar 2024 17:19:42 +0100 Subject: [PATCH 19/44] deleted unnecessary comments and functions from ButterflyFaithfulMonomorphismsIntoSimplicialSurface --- gap/Morphisms/morphisms.gi | 126 ++++--------------------------------- 1 file changed, 12 insertions(+), 114 deletions(-) diff --git a/gap/Morphisms/morphisms.gi b/gap/Morphisms/morphisms.gi index e98c202f..65df50bf 100644 --- a/gap/Morphisms/morphisms.gi +++ b/gap/Morphisms/morphisms.gi @@ -483,9 +483,9 @@ InstallMethod( InverseGeneralMapping, "for a polygonal morphism", InstallMethod(ButterflyFaithfulMonomorphismIntoSimplicialSurface, "for two simplicial surfaces", [IsSimplicialSurface, IsSimplicialSurface], function(surface1, surface2) - local PermuteList, AllBijections, AllOneFaceIsomorphisms, MyImage, MyPreImage, MyImageCat, - MyPreImages, MyPreImagesCat, MyUpdateMap, SurfaceIdentityMap, RemoveElement, MyLess, - VertexDegreesOfFace, MyIsInjective, MonomorphismIntoSimplicialSurface; + local PermuteList, AllBijections, AllOneFaceIsomorphisms, MyPreImage, MyImageCat, + MyPreImages, MyPreImagesCat, MyUpdateMap, + MyIsInjective, MonomorphismIntoSimplicialSurface; PermuteList := function(list, perm) return List(list, x -> x^perm); end; @@ -507,15 +507,10 @@ InstallMethod(ButterflyFaithfulMonomorphismIntoSimplicialSurface, "for two simpl od; Add(res, tmp); od; - # res := List(AllPermutations, x -> IndexInducedMap(list1, x)); return res; fi; end; - MyImage := function(map, x) - return map[x]; - end; - MyImageCat := function(map, x_list) local res, i; res := []; @@ -551,18 +546,13 @@ InstallMethod(ButterflyFaithfulMonomorphismIntoSimplicialSurface, "for two simpl res := []; vertex_maps := AllBijections(VerticesOfFace(surface1, face1), VerticesOfFace(surface2, face2)); - # edge_map := []; 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]))); - # Error(); for i in [1..3] do for edge in EdgesOfFace(surface2, face2) do - # Error(); if Set(VerticesOfEdge(surface2, edge)) = Set(mapped_e[i]) then - # Error(); - # mapped_e[i] := edge; edge_map[EdgesOfFace(surface1, face1)[i]]:= edge; break; fi; @@ -586,26 +576,6 @@ InstallMethod(ButterflyFaithfulMonomorphismIntoSimplicialSurface, "for two simpl fi; end; - SurfaceIdentityMap := function(surface) - return [[1..NumberOfVertices(surface)], [1..NumberOfEdges(surface)], [1..NumberOfFaces(surface)]]; - end; - - RemoveElement := function(list, element) - if not element in list then - return fail; - else - Remove(list, Position(list, element)); - fi; - end; - - MyLess := function(fdeg1, fdeg2) - return fdeg1 < fdeg2; - end; - - VertexDegreesOfFace := function(surface, face) - return Set(List(VerticesOfFace(surface, face), v -> DegreeOfVertex(surface, v))); - end; - MyIsInjective := function(map) return IsDuplicateFree(Compacted(map)); end; @@ -622,12 +592,7 @@ InstallMethod(ButterflyFaithfulMonomorphismIntoSimplicialSurface, "for two simpl 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)))); - # face_counter1 := ListCounter(CounterOfFaces(surface1)); - # face_counter2 := ListCounter(CounterOfFaces(surface2)); - # face_degrees1 := List(face_counter1, fdegs1 -> Set(fdegs1[1])); - # face_degrees2 := List(face_counter2, fdegs2 -> Set(fdegs2[1])); if ForAny(face_counter2, fdegs2 -> not fdegs2 in face_counter1) then - # Error("heuristic"); return fail; else min_pos := PositionMinimum(List(Collected(face_counter2), fdeg2 -> fdeg2[2])); @@ -655,40 +620,30 @@ InstallMethod(ButterflyFaithfulMonomorphismIntoSimplicialSurface, "for two simpl mapped_faces := MyPreImages(face_map); while not IsEmpty(remaining_faces) do cur_edge := cur_edges[1]; - # Error("Mono"); # update face_map if Length(Difference(FacesOfEdge(surface2, edge_map[cur_edge]), face_map)) = 1 then - # Error("Mono"); new_image_face := Difference(FacesOfEdge(surface2, edge_map[cur_edge]), face_map)[1]; - else # QUESTION not sure if this case is correct - # Error("Mono"); + 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 - # Error("Mono"); is_correct_morphism := false; break; fi; if MyUpdateMap(face_map, new_face, new_image_face) = false or MyIsInjective(face_map) = false then - # Error("Mono"); is_correct_morphism := false; break; fi; mapped_faces := MyPreImages(face_map); # update vertex_map - # new_vertex := Difference(VerticesOfFace(surface1, new_face), - # Intersection(List(FacesOfEdge(surface1, cur_edge), F -> VerticesOfFace(surface1, F))))[1]; # QUESTION requires vertex-faithful new_vertex := Difference(VerticesOfFace(surface1, new_face), VerticesOfEdge(surface1, cur_edge))[1]; - # new_image_vertex := Difference(VerticesOfFace(surface2, new_image_face), - # Intersection(List(FacesOfEdge(surface2, edge_map[cur_edge]), F -> VerticesOfFace(surface2, F))))[1]; # QUESTION requires vertex-faithful new_image_vertex := Difference(VerticesOfFace(surface2, new_image_face), VerticesOfEdge(surface2, edge_map[cur_edge]))[1]; if MyUpdateMap(vertex_map, new_vertex, new_image_vertex) = false or MyIsInjective(vertex_map) = false then - # Error("Mono"); is_correct_morphism := false; break; fi; @@ -698,16 +653,13 @@ InstallMethod(ButterflyFaithfulMonomorphismIntoSimplicialSurface, "for two simpl 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 - # Error("MonoEdge"); - if Set(MyImageCat(vertex_map, VerticesOfEdge(surface1, cur_new_edge))) = Set(VerticesOfEdge(surface2, cur_new_image_edge)) then # QUESTION requires vertex-faithful + if Set(MyImageCat(vertex_map, VerticesOfEdge(surface1, cur_new_edge))) = Set(VerticesOfEdge(surface2, cur_new_image_edge)) then if MyUpdateMap(edge_map, cur_new_edge, cur_new_image_edge) = false or MyIsInjective(edge_map) = false then - # Error("Mono"); is_correct_morphism := false; fi; if cur_new_edge in cur_edges then Add(finished_cur_edges, cur_new_edge); fi; - # Error("MonoEdge"); fi; od; od; @@ -722,12 +674,10 @@ InstallMethod(ButterflyFaithfulMonomorphismIntoSimplicialSurface, "for two simpl # update remaining_faces remaining_faces := Difference(remaining_faces, [new_face]); - # Error("Mono"); od; if is_correct_morphism = true then - # return monomorphism; # uncomment for the lists that make the homomorphism FLAG(LISTS) - return PolygonalMorphismByLists(surface1, surface2, monomorphism[1], monomorphism[2], monomorphism[3]); #FLAG(MORPHISMS) + return PolygonalMorphismByLists(surface1, surface2, monomorphism[1], monomorphism[2], monomorphism[3]); fi; od; od; @@ -740,9 +690,9 @@ InstallMethod(ButterflyFaithfulMonomorphismIntoSimplicialSurface, "for two simpl InstallMethod(AllButterflyFaithfulMonomorphismsIntoSimplicialSurface, "for two simplicial surfaces", [IsSimplicialSurface, IsSimplicialSurface], function(surface1, surface2) - local PermuteList, AllBijections, AllOneFaceIsomorphisms, MyImage, MyPreImage, MyImageCat, - MyPreImages, MyPreImagesCat, MyUpdateMap, SurfaceIdentityMap, RemoveElement, MyLess, - VertexDegreesOfFace, MyIsInjective, AllMonomorphismsIntoSimplicialSurface; + local PermuteList, AllBijections, AllOneFaceIsomorphisms, MyPreImage, MyImageCat, + MyPreImages, MyPreImagesCat, MyUpdateMap, + MyIsInjective, AllMonomorphismsIntoSimplicialSurface; PermuteList := function(list, perm) return List(list, x -> x^perm); end; @@ -764,15 +714,10 @@ InstallMethod(AllButterflyFaithfulMonomorphismsIntoSimplicialSurface, "for two s od; Add(res, tmp); od; - # res := List(AllPermutations, x -> IndexInducedMap(list1, x)); return res; fi; end; - MyImage := function(map, x) - return map[x]; - end; - MyImageCat := function(map, x_list) local res, i; res := []; @@ -808,18 +753,13 @@ InstallMethod(AllButterflyFaithfulMonomorphismsIntoSimplicialSurface, "for two s res := []; vertex_maps := AllBijections(VerticesOfFace(surface1, face1), VerticesOfFace(surface2, face2)); - # edge_map := []; 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]))); - # Error(); for i in [1..3] do for edge in EdgesOfFace(surface2, face2) do - # Error(); if Set(VerticesOfEdge(surface2, edge)) = Set(mapped_e[i]) then - # Error(); - # mapped_e[i] := edge; edge_map[EdgesOfFace(surface1, face1)[i]]:= edge; break; fi; @@ -843,26 +783,6 @@ InstallMethod(AllButterflyFaithfulMonomorphismsIntoSimplicialSurface, "for two s fi; end; - SurfaceIdentityMap := function(surface) - return [[1..NumberOfVertices(surface)], [1..NumberOfEdges(surface)], [1..NumberOfFaces(surface)]]; - end; - - RemoveElement := function(list, element) - if not element in list then - return fail; - else - Remove(list, Position(list, element)); - fi; - end; - - MyLess := function(fdeg1, fdeg2) - return fdeg1 < fdeg2; - end; - - VertexDegreesOfFace := function(surface, face) - return Set(List(VerticesOfFace(surface, face), v -> DegreeOfVertex(surface, v))); - end; - MyIsInjective := function(map) return IsDuplicateFree(Compacted(map)); end; @@ -881,12 +801,7 @@ InstallMethod(AllButterflyFaithfulMonomorphismsIntoSimplicialSurface, "for two s 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)))); - # face_counter1 := ListCounter(CounterOfFaces(surface1)); - # face_counter2 := ListCounter(CounterOfFaces(surface2)); - # face_degrees1 := List(face_counter1, fdegs1 -> Set(fdegs1[1])); - # face_degrees2 := List(face_counter2, fdegs2 -> Set(fdegs2[1])); if ForAny(face_counter2, fdegs2 -> not fdegs2 in face_counter1) then - # Error("heuristic"); return res; # empty list else min_pos := PositionMinimum(List(Collected(face_counter2), fdeg2 -> fdeg2[2])); @@ -914,40 +829,28 @@ InstallMethod(AllButterflyFaithfulMonomorphismsIntoSimplicialSurface, "for two s mapped_faces := MyPreImages(face_map); while not IsEmpty(remaining_faces) do cur_edge := cur_edges[1]; - # Error("Mono"); - # update face_map if Length(Difference(FacesOfEdge(surface2, edge_map[cur_edge]), face_map)) = 1 then - # Error("Mono"); new_image_face := Difference(FacesOfEdge(surface2, edge_map[cur_edge]), face_map)[1]; - else # QUESTION not sure if this case is correct - # Error("Mono"); + 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 - # Error("Mono"); is_correct_morphism := false; break; fi; if MyUpdateMap(face_map, new_face, new_image_face) = false or MyIsInjective(face_map) = false then - # Error("Mono"); is_correct_morphism := false; break; fi; mapped_faces := MyPreImages(face_map); - # update vertex_map - # new_vertex := Difference(VerticesOfFace(surface1, new_face), - # Intersection(List(FacesOfEdge(surface1, cur_edge), F -> VerticesOfFace(surface1, F))))[1]; # QUESTION requires vertex-faithful new_vertex := Difference(VerticesOfFace(surface1, new_face), VerticesOfEdge(surface1, cur_edge))[1]; - # new_image_vertex := Difference(VerticesOfFace(surface2, new_image_face), - # Intersection(List(FacesOfEdge(surface2, edge_map[cur_edge]), F -> VerticesOfFace(surface2, F))))[1]; # QUESTION requires vertex-faithful new_image_vertex := Difference(VerticesOfFace(surface2, new_image_face), VerticesOfEdge(surface2, edge_map[cur_edge]))[1]; if MyUpdateMap(vertex_map, new_vertex, new_image_vertex) = false or MyIsInjective(vertex_map) = false then - # Error("Mono"); is_correct_morphism := false; break; fi; @@ -957,16 +860,13 @@ InstallMethod(AllButterflyFaithfulMonomorphismsIntoSimplicialSurface, "for two s 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 - # Error("MonoEdge"); - if Set(MyImageCat(vertex_map, VerticesOfEdge(surface1, cur_new_edge))) = Set(VerticesOfEdge(surface2, cur_new_image_edge)) then # QUESTION requires vertex-faithful + if Set(MyImageCat(vertex_map, VerticesOfEdge(surface1, cur_new_edge))) = Set(VerticesOfEdge(surface2, cur_new_image_edge)) then if MyUpdateMap(edge_map, cur_new_edge, cur_new_image_edge) = false or MyIsInjective(edge_map) = false then - # Error("Mono"); is_correct_morphism := false; fi; if cur_new_edge in cur_edges then Add(finished_cur_edges, cur_new_edge); fi; - # Error("MonoEdge"); fi; od; od; @@ -981,12 +881,10 @@ InstallMethod(AllButterflyFaithfulMonomorphismsIntoSimplicialSurface, "for two s # update remaining_faces remaining_faces := Difference(remaining_faces, [new_face]); - # Error("Mono"); od; if is_correct_morphism = true then - # Add(res, monomorphism); # uncomment to add the list the monomorphism is made of FLAG(LISTS) - Add(res,PolygonalMorphismByLists(surface1, surface2, monomorphism[1], monomorphism[2], monomorphism[3])); # FLAG(MORPHISMS) + Add(res,PolygonalMorphismByLists(surface1, surface2, monomorphism[1], monomorphism[2], monomorphism[3])); fi; od; od; From 4f40180bc750e6af4a0fb4daaf4707f64c21a8b2 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 23 Mar 2024 22:55:14 +0100 Subject: [PATCH 20/44] CI: test with GAP 4.13; test with mininimal set of packages loaded --- .github/workflows/CI.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 5c6ffe49..2641e351 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -25,11 +25,12 @@ 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,6 +39,9 @@ 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 @@ -49,7 +53,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 +64,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 From 68c1e13743e1602f537092bc6ffe4686a4e73aee Mon Sep 17 00:00:00 2001 From: Flynn Fehre Date: Fri, 29 Mar 2024 16:25:35 +0100 Subject: [PATCH 21/44] changed image names to _Wrapper_... and modularised help functions for ButterflyFaithfulMonomorphismIntoSimplicialSurface and AllButterflyFaithfulMonomorphismsIntoSimplicialSurface --- ...tterfly_Faithful_Monomorphism_Hexagon.pdf} | Bin ...tterfly_Faithful_Monomorphism_Hexagon.svg} | 0 gap/Morphisms/morphisms.gd | 8 +- gap/Morphisms/morphisms.gi | 677 ++++++++---------- 4 files changed, 299 insertions(+), 386 deletions(-) rename doc/images/{Image_Butterfly_Faithful_Monomorphism_Hexagon.pdf => _Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.pdf} (100%) rename doc/images/{Image_Butterfly_Faithful_Monomorphism_Hexagon.svg => _Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.svg} (100%) diff --git a/doc/images/Image_Butterfly_Faithful_Monomorphism_Hexagon.pdf b/doc/images/_Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.pdf similarity index 100% rename from doc/images/Image_Butterfly_Faithful_Monomorphism_Hexagon.pdf rename to doc/images/_Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.pdf diff --git a/doc/images/Image_Butterfly_Faithful_Monomorphism_Hexagon.svg b/doc/images/_Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.svg similarity index 100% rename from doc/images/Image_Butterfly_Faithful_Monomorphism_Hexagon.svg rename to doc/images/_Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.svg diff --git a/gap/Morphisms/morphisms.gd b/gap/Morphisms/morphisms.gd index 62f3f9e1..0294f658 100644 --- a/gap/Morphisms/morphisms.gd +++ b/gap/Morphisms/morphisms.gd @@ -436,11 +436,11 @@ DeclareAttribute( "InversePolygonalMorphism", IsPolygonalMorphism and IsBijectiv #! 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/Image_Butterfly_Faithful_Monomorphism_Hexagon.svg"> </img> <br> +#! <br><img src="./images/_Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.svg"> </img> <br> #! #! #! \begin{center} -#! \includegraphics{images/Image_Butterfly_Faithful_Monomorphism_Hexagon.pdf} +#! \includegraphics{images/_Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.pdf} #! \end{center} #! #! @@ -483,11 +483,11 @@ DeclareOperation( "ButterflyFaithfulMonomorphismIntoSimplicialSurface", [IsSimpl #! 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/Image_Butterfly_Faithful_Monomorphism_Hexagon.svg"> </img> <br> +#! <br><img src="./images/_Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.svg"> </img> <br> #! #! #! \begin{center} -#! \includegraphics{images/Image_Butterfly_Faithful_Monomorphism_Hexagon.pdf} +#! \includegraphics{images/_Wrapper_Butterfly_Faithful_Monomorphism_Hexagon.pdf} #! \end{center} #! #! diff --git a/gap/Morphisms/morphisms.gi b/gap/Morphisms/morphisms.gi index 65df50bf..2d88d3a5 100644 --- a/gap/Morphisms/morphisms.gi +++ b/gap/Morphisms/morphisms.gi @@ -480,417 +480,330 @@ InstallMethod( InverseGeneralMapping, "for a polygonal morphism", end ); -InstallMethod(ButterflyFaithfulMonomorphismIntoSimplicialSurface, "for two simplicial surfaces", - [IsSimplicialSurface, IsSimplicialSurface], - function(surface1, surface2) - local PermuteList, AllBijections, AllOneFaceIsomorphisms, MyPreImage, MyImageCat, - MyPreImages, MyPreImagesCat, MyUpdateMap, - MyIsInjective, MonomorphismIntoSimplicialSurface; - PermuteList := function(list, perm) - return List(list, x -> x^perm); - end; - - 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, 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; - - MyImageCat := 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; - - MyPreImage := 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; +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; - return res; - end; - - MyPreImagesCat := function(map, y_list) - return Concatenation(List(y_list, y -> MyPreImage(map, y))); - end; - - MyPreImages := function(map) - return MyPreImagesCat(map, Compacted(map)); - end; - - AllOneFaceIsomorphisms := function(face1, surface1, face2, surface2) - local res, e, vertex_maps, vertex_map, mapped_e, i, edge, edge_map, face_map; - res := []; - vertex_maps := 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; + for bijection in AllPermutations do + tmp := []; + for i in [1..Length(list1)] do + tmp[list1[i]] := bijection[i]; od; - face_map := []; - face_map[face1] := face2; - Add(res, [vertex_map, edge_map, face_map]); + Add(res, tmp); od; return res; - end; - - MyUpdateMap := 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; - - MyIsInjective := function(map) - return IsDuplicateFree(Compacted(map)); - end; - MonomorphismIntoSimplicialSurface := 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; + 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 +); - for image_starting_face in possible_image_faces do - possible_monomorphisms := 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 := MyPreImages(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 MyUpdateMap(face_map, new_face, new_image_face) = false or MyIsInjective(face_map) = false then - is_correct_morphism := false; - break; - fi; - mapped_faces := MyPreImages(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 MyUpdateMap(vertex_map, new_vertex, new_image_vertex) = false or MyIsInjective(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(MyImageCat(vertex_map, VerticesOfEdge(surface1, cur_new_edge))) = Set(VerticesOfEdge(surface2, cur_new_image_edge)) then - if MyUpdateMap(edge_map, cur_new_edge, cur_new_image_edge) = false or MyIsInjective(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; +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 +); - # 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); +BindGlobal("__SIMPLICIAL_PreImagesCatFromListmap", + function(map, y_list) + return Concatenation(List(y_list, y -> __SIMPLICIAL_PreImageFromListmap(map, y))); + end +); - # update remaining_faces - remaining_faces := Difference(remaining_faces, [new_face]); - od; +BindGlobal("__SIMPLICIAL_PreImagesFromListmap", + function(map) + return __SIMPLICIAL_PreImagesCatFromListmap(map, Compacted(map)); + end +); - if is_correct_morphism = true then - return PolygonalMorphismByLists(surface1, surface2, monomorphism[1], monomorphism[2], monomorphism[3]); +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; - return fail; - end; - return MonomorphismIntoSimplicialSurface(surface1, surface2); + face_map := []; + face_map[face1] := face2; + Add(res, [vertex_map, edge_map, face_map]); + od; + return res; end ); -InstallMethod(AllButterflyFaithfulMonomorphismsIntoSimplicialSurface, "for two simplicial surfaces", +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 PermuteList, AllBijections, AllOneFaceIsomorphisms, MyPreImage, MyImageCat, - MyPreImages, MyPreImagesCat, MyUpdateMap, - MyIsInjective, AllMonomorphismsIntoSimplicialSurface; - PermuteList := function(list, perm) - return List(list, x -> x^perm); - end; - - 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, 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; + 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; - end; - - MyImageCat := 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; - - MyPreImage := 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; - - MyPreImagesCat := function(map, y_list) - return Concatenation(List(y_list, y -> MyPreImage(map, y))); - end; - - MyPreImages := function(map) - return MyPreImagesCat(map, Compacted(map)); - end; - - AllOneFaceIsomorphisms := function(face1, surface1, face2, surface2) - local res, e, vertex_maps, vertex_map, mapped_e, i, edge, edge_map, face_map; - res := []; - vertex_maps := 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; + 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; - face_map := []; - face_map[face1] := face2; - Add(res, [vertex_map, edge_map, face_map]); - od; - return res; - end; - - MyUpdateMap := 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; - MyIsInjective := function(map) - return IsDuplicateFree(Compacted(map)); - end; - - AllMonomorphismsIntoSimplicialSurface := 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)))); + if is_correct_morphism = true then + return PolygonalMorphismByLists(surface1, surface2, monomorphism[1], monomorphism[2], monomorphism[3]); fi; - else - starting_face := Faces(surface1)[1]; + 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 := 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 := MyPreImages(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 MyUpdateMap(face_map, new_face, new_image_face) = false or MyIsInjective(face_map) = false then - is_correct_morphism := false; - break; - fi; - mapped_faces := MyPreImages(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 MyUpdateMap(vertex_map, new_vertex, new_image_vertex) = false or MyIsInjective(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(MyImageCat(vertex_map, VerticesOfEdge(surface1, cur_new_edge))) = Set(VerticesOfEdge(surface2, cur_new_image_edge)) then - if MyUpdateMap(edge_map, cur_new_edge, cur_new_image_edge) = false or MyIsInjective(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; + 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]; - # 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); + if not new_face in remaining_faces then + is_correct_morphism := false; + break; + fi; - # update remaining_faces - remaining_faces := Difference(remaining_faces, [new_face]); - od; + 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; - if is_correct_morphism = true then - Add(res,PolygonalMorphismByLists(surface1, surface2, monomorphism[1], monomorphism[2], monomorphism[3])); + # 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; - return res; - end; - return AllMonomorphismsIntoSimplicialSurface(surface1, surface2); + od; + return res; end ); From 1e728c25bffeb7e24eef86a09f218595d6fe0299 Mon Sep 17 00:00:00 2001 From: Flynn Fehre Date: Tue, 9 Apr 2024 12:17:07 +0200 Subject: [PATCH 22/44] deleted .tex-files from another branch --- ...x_facegraph_icosahedron_default_spread.tex | 340 ----------------- ...nvex_facegraph_icosahedron_high_spread.tex | 341 ------------------ ...onvex_facegraph_icosahedron_low_spread.tex | 341 ------------------ 3 files changed, 1022 deletions(-) delete mode 100644 doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_default_spread.tex delete mode 100644 doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_high_spread.tex delete mode 100644 doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_low_spread.tex diff --git a/doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_default_spread.tex b/doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_default_spread.tex deleted file mode 100644 index e527e1bc..00000000 --- a/doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_default_spread.tex +++ /dev/null @@ -1,340 +0,0 @@ -\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}[vertexBall, edgeDouble=nolabels, faceStyle=nolabels, scale=4] - - \coordinate (V1) at (1. , 0.); - \coordinate (V2) at (0.3090169889123937 , -0.9510565180700449); - \coordinate (V3) at (-0.8090169969069803 , -0.5877852488074289); - \coordinate (V4) at (-0.8090169926869255 , 0.587785254615836); - \coordinate (V5) at (0.3090169957405858 , 0.9510565158514307); - \coordinate (V6) at (0.6545084961632449 , -5.546535453149204e-10); - \coordinate (V7) at (0.2002100305571999 , -0.5895321377810976); - \coordinate (V8) at (-0.4717023517592329 , -0.4560155144296473); - \coordinate (V9) at (-0.5777924021353646 , 0.3025649579663135); - \coordinate (V10) at (0.1158813737393728 , 0.6224745714410109); - \coordinate (V11) at (0.417989412602686 , -0.1600986570320857); - \coordinate (V12) at (-0.2867457540694981 , -0.3391323294699786); - \coordinate (V13) at (-0.4037883433167264 , 0.1450338487604777); - \coordinate (V14) at (0.01213378276305652 , 0.4310209935389311); - \coordinate (V15) at (0.3945647857088452 , 0.1765698733073889); - \coordinate (V16) at (0.2359494642111798 , -0.1206899425566903); - \coordinate (V17) at (-0.1546590631070234 , -0.1844779471328884); - \coordinate (V18) at (-0.2810942085002772 , 0.06104281296509385); - \coordinate (V19) at (-0.03005439329815793 , 0.2932358838093986); - \coordinate (V20) at (0.2593032045979817 , 0.1658676993992546); - \draw[edge] (V1) -- node[edgeLabel] {$1$} (V2); - \draw[edge] (V1) -- node[edgeLabel] {$2$} (V5); - \draw[edge] (V2) -- node[edgeLabel] {$3$} (V3); - \draw[edge] (V3) -- node[edgeLabel] {$4$} (V4); - \draw[edge] (V4) -- node[edgeLabel] {$5$} (V5); - \draw[edge] (V1) -- node[edgeLabel] {$6$} (V6); - \draw[edge] (V2) -- node[edgeLabel] {$7$} (V7); - \draw[edge] (V6) -- node[edgeLabel] {$8$} (V11); - \draw[edge] (V7) -- node[edgeLabel] {$9$} (V11); - \draw[edge] (V5) -- node[edgeLabel] {$10$} (V10); - \draw[edge] (V6) -- node[edgeLabel] {$11$} (V15); - \draw[edge] (V10) -- node[edgeLabel] {$12$} (V15); - \draw[edge] (V3) -- node[edgeLabel] {$13$} (V8); - \draw[edge] (V7) -- node[edgeLabel] {$14$} (V12); - \draw[edge] (V8) -- node[edgeLabel] {$15$} (V12); - \draw[edge] (V4) -- node[edgeLabel] {$16$} (V9); - \draw[edge] (V8) -- node[edgeLabel] {$17$} (V13); - \draw[edge] (V9) -- node[edgeLabel] {$18$} (V13); - \draw[edge] (V9) -- node[edgeLabel] {$19$} (V14); - \draw[edge] (V10) -- node[edgeLabel] {$20$} (V14); - \draw[edge] (V11) -- node[edgeLabel] {$21$} (V16); - \draw[edge] (V15) -- node[edgeLabel] {$22$} (V20); - \draw[edge] (V16) -- node[edgeLabel] {$23$} (V20); - \draw[edge] (V12) -- node[edgeLabel] {$24$} (V17); - \draw[edge] (V16) -- node[edgeLabel] {$25$} (V17); - \draw[edge] (V13) -- node[edgeLabel] {$26$} (V18); - \draw[edge] (V17) -- node[edgeLabel] {$27$} (V18); - \draw[edge] (V14) -- node[edgeLabel] {$28$} (V19); - \draw[edge] (V18) -- node[edgeLabel] {$29$} (V19); - \draw[edge] (V19) -- node[edgeLabel] {$30$} (V20); - % Draw the faces - \vertexLabelR{V1}{left}{$1$} - \vertexLabelR{V2}{left}{$2$} - \vertexLabelR{V3}{left}{$3$} - \vertexLabelR{V4}{left}{$4$} - \vertexLabelR{V5}{left}{$5$} - \vertexLabelR{V6}{left}{$6$} - \vertexLabelR{V7}{left}{$7$} - \vertexLabelR{V8}{left}{$8$} - \vertexLabelR{V9}{left}{$9$} - \vertexLabelR{V10}{left}{$10$} - \vertexLabelR{V11}{left}{$11$} - \vertexLabelR{V12}{left}{$12$} - \vertexLabelR{V13}{left}{$13$} - \vertexLabelR{V14}{left}{$14$} - \vertexLabelR{V15}{left}{$15$} - \vertexLabelR{V16}{left}{$16$} - \vertexLabelR{V17}{left}{$17$} - \vertexLabelR{V18}{left}{$18$} - \vertexLabelR{V19}{left}{$19$} - \vertexLabelR{V20}{left}{$20$} - \end{tikzpicture} - -\end{document} - - diff --git a/doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_high_spread.tex b/doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_high_spread.tex deleted file mode 100644 index 4783561d..00000000 --- a/doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_high_spread.tex +++ /dev/null @@ -1,341 +0,0 @@ -\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}[vertexBall, edgeDouble=nolabels, faceStyle=nolabels, scale=4] - - \coordinate (V1) at (1. , 0.); - \coordinate (V2) at (0.3090169889123937 , -0.9510565180700449); - \coordinate (V3) at (-0.8090169969069803 , -0.5877852488074289); - \coordinate (V4) at (-0.8090169926869255 , 0.587785254615836); - \coordinate (V5) at (0.3090169957405858 , 0.9510565158514307); - \coordinate (V6) at (0.7927050976979469 , -3.327921271889523e-10); - \coordinate (V7) at (0.2424730992248824 , -0.7390375056311521); - \coordinate (V8) at (-0.6182970511232349 , -0.488652952881346); - \coordinate (V9) at (-0.6555846775013854 , 0.4363679932957395); - \coordinate (V10) at (0.2138651127700633 , 0.753907349238458); - \coordinate (V11) at (0.6257282990590397 , -0.1221815949309928); - \coordinate (V12) at (-0.4759335274339455 , -0.4043145436795418); - \coordinate (V13) at (-0.5299770435427567 , 0.3239876612138216); - \coordinate (V14) at (0.1445119225113219 , 0.6121867255933728); - \coordinate (V15) at (0.6209603013165698 , 0.1266425475472756); - \coordinate (V16) at (0.4597638254237214 , -0.1271779158715349); - \coordinate (V17) at (-0.3282846657626078 , -0.2658951127485535); - \coordinate (V18) at (-0.4273051358160279 , 0.2413450347190398); - \coordinate (V19) at (0.1004588251932902 , 0.5013390228086395); - \coordinate (V20) at (0.5253135731118553 , 0.1614011047413686); - \draw[edge] (V1) -- node[edgeLabel] {$1$} (V2); - \draw[edge] (V1) -- node[edgeLabel] {$2$} (V5); - \draw[edge] (V2) -- node[edgeLabel] {$3$} (V3); - \draw[edge] (V3) -- node[edgeLabel] {$4$} (V4); - \draw[edge] (V4) -- node[edgeLabel] {$5$} (V5); - \draw[edge] (V1) -- node[edgeLabel] {$6$} (V6); - \draw[edge] (V2) -- node[edgeLabel] {$7$} (V7); - \draw[edge] (V6) -- node[edgeLabel] {$8$} (V11); - \draw[edge] (V7) -- node[edgeLabel] {$9$} (V11); - \draw[edge] (V5) -- node[edgeLabel] {$10$} (V10); - \draw[edge] (V6) -- node[edgeLabel] {$11$} (V15); - \draw[edge] (V10) -- node[edgeLabel] {$12$} (V15); - \draw[edge] (V3) -- node[edgeLabel] {$13$} (V8); - \draw[edge] (V7) -- node[edgeLabel] {$14$} (V12); - \draw[edge] (V8) -- node[edgeLabel] {$15$} (V12); - \draw[edge] (V4) -- node[edgeLabel] {$16$} (V9); - \draw[edge] (V8) -- node[edgeLabel] {$17$} (V13); - \draw[edge] (V9) -- node[edgeLabel] {$18$} (V13); - \draw[edge] (V9) -- node[edgeLabel] {$19$} (V14); - \draw[edge] (V10) -- node[edgeLabel] {$20$} (V14); - \draw[edge] (V11) -- node[edgeLabel] {$21$} (V16); - \draw[edge] (V15) -- node[edgeLabel] {$22$} (V20); - \draw[edge] (V16) -- node[edgeLabel] {$23$} (V20); - \draw[edge] (V12) -- node[edgeLabel] {$24$} (V17); - \draw[edge] (V16) -- node[edgeLabel] {$25$} (V17); - \draw[edge] (V13) -- node[edgeLabel] {$26$} (V18); - \draw[edge] (V17) -- node[edgeLabel] {$27$} (V18); - \draw[edge] (V14) -- node[edgeLabel] {$28$} (V19); - \draw[edge] (V18) -- node[edgeLabel] {$29$} (V19); - \draw[edge] (V19) -- node[edgeLabel] {$30$} (V20); - % Draw the faces - \vertexLabelR{V1}{left}{$1$} - \vertexLabelR{V2}{left}{$2$} - \vertexLabelR{V3}{left}{$3$} - \vertexLabelR{V4}{left}{$4$} - \vertexLabelR{V5}{left}{$5$} - \vertexLabelR{V6}{left}{$6$} - \vertexLabelR{V7}{left}{$7$} - \vertexLabelR{V8}{left}{$8$} - \vertexLabelR{V9}{left}{$9$} - \vertexLabelR{V10}{left}{$10$} - \vertexLabelR{V11}{left}{$11$} - \vertexLabelR{V12}{left}{$12$} - \vertexLabelR{V13}{left}{$13$} - \vertexLabelR{V14}{left}{$14$} - \vertexLabelR{V15}{left}{$15$} - \vertexLabelR{V16}{left}{$16$} - \vertexLabelR{V17}{left}{$17$} - \vertexLabelR{V18}{left}{$18$} - \vertexLabelR{V19}{left}{$19$} - \vertexLabelR{V20}{left}{$20$} - \end{tikzpicture} - -\end{document} - - - diff --git a/doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_low_spread.tex b/doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_low_spread.tex deleted file mode 100644 index 15ae0fe6..00000000 --- a/doc/tikz-files/_TIKZ_convex_facegraph_icosahedron_low_spread.tex +++ /dev/null @@ -1,341 +0,0 @@ -\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}[vertexBall, edgeDouble=nolabels, faceStyle=nolabels, scale=4] - - \coordinate (V1) at (1. , 0.); - \coordinate (V2) at (0.3090169889123937 , -0.9510565180700449); - \coordinate (V3) at (-0.8090169969069803 , -0.5877852488074289); - \coordinate (V4) at (-0.8090169926869255 , 0.587785254615836); - \coordinate (V5) at (0.3090169957405858 , 0.9510565158514307); - \coordinate (V6) at (0.5163118946285428 , -7.765149634408886e-10); - \coordinate (V7) at (0.1614864032665868 , -0.4460855978160754); - \coordinate (V8) at (-0.3197938757917752 , -0.4593389774950907); - \coordinate (V9) at (-0.5292706366829111 , 0.1424753670618677); - \coordinate (V10) at (-0.009741685598258207 , 0.4910417935991915); - \coordinate (V11) at (0.2412985701850865 , -0.1664845467062768); - \coordinate (V12) at (-0.1497258880922867 , -0.3025990736622617); - \coordinate (V13) at (-0.3151656185658844 , -0.02476406050888025); - \coordinate (V14) at (-0.1270187743825422 , 0.2664627757024033); - \coordinate (V15) at (0.1747098689598691 , 0.1979538832885492); - \coordinate (V16) at (0.08113396435917979 , -0.08657118064268243); - \coordinate (V17) at (-0.08457670923818356 , -0.1467718202157678); - \coordinate (V18) at (-0.1944452295320299 , -0.07340624254900144); - \coordinate (V19) at (-0.1356899517998978 , 0.1140932896727264); - \coordinate (V20) at (0.03635327717978389 , 0.1223482232574671); - \draw[edge] (V1) -- node[edgeLabel] {$1$} (V2); - \draw[edge] (V1) -- node[edgeLabel] {$2$} (V5); - \draw[edge] (V2) -- node[edgeLabel] {$3$} (V3); - \draw[edge] (V3) -- node[edgeLabel] {$4$} (V4); - \draw[edge] (V4) -- node[edgeLabel] {$5$} (V5); - \draw[edge] (V1) -- node[edgeLabel] {$6$} (V6); - \draw[edge] (V2) -- node[edgeLabel] {$7$} (V7); - \draw[edge] (V6) -- node[edgeLabel] {$8$} (V11); - \draw[edge] (V7) -- node[edgeLabel] {$9$} (V11); - \draw[edge] (V5) -- node[edgeLabel] {$10$} (V10); - \draw[edge] (V6) -- node[edgeLabel] {$11$} (V15); - \draw[edge] (V10) -- node[edgeLabel] {$12$} (V15); - \draw[edge] (V3) -- node[edgeLabel] {$13$} (V8); - \draw[edge] (V7) -- node[edgeLabel] {$14$} (V12); - \draw[edge] (V8) -- node[edgeLabel] {$15$} (V12); - \draw[edge] (V4) -- node[edgeLabel] {$16$} (V9); - \draw[edge] (V8) -- node[edgeLabel] {$17$} (V13); - \draw[edge] (V9) -- node[edgeLabel] {$18$} (V13); - \draw[edge] (V9) -- node[edgeLabel] {$19$} (V14); - \draw[edge] (V10) -- node[edgeLabel] {$20$} (V14); - \draw[edge] (V11) -- node[edgeLabel] {$21$} (V16); - \draw[edge] (V15) -- node[edgeLabel] {$22$} (V20); - \draw[edge] (V16) -- node[edgeLabel] {$23$} (V20); - \draw[edge] (V12) -- node[edgeLabel] {$24$} (V17); - \draw[edge] (V16) -- node[edgeLabel] {$25$} (V17); - \draw[edge] (V13) -- node[edgeLabel] {$26$} (V18); - \draw[edge] (V17) -- node[edgeLabel] {$27$} (V18); - \draw[edge] (V14) -- node[edgeLabel] {$28$} (V19); - \draw[edge] (V18) -- node[edgeLabel] {$29$} (V19); - \draw[edge] (V19) -- node[edgeLabel] {$30$} (V20); - % Draw the faces - \vertexLabelR{V1}{left}{$1$} - \vertexLabelR{V2}{left}{$2$} - \vertexLabelR{V3}{left}{$3$} - \vertexLabelR{V4}{left}{$4$} - \vertexLabelR{V5}{left}{$5$} - \vertexLabelR{V6}{left}{$6$} - \vertexLabelR{V7}{left}{$7$} - \vertexLabelR{V8}{left}{$8$} - \vertexLabelR{V9}{left}{$9$} - \vertexLabelR{V10}{left}{$10$} - \vertexLabelR{V11}{left}{$11$} - \vertexLabelR{V12}{left}{$12$} - \vertexLabelR{V13}{left}{$13$} - \vertexLabelR{V14}{left}{$14$} - \vertexLabelR{V15}{left}{$15$} - \vertexLabelR{V16}{left}{$16$} - \vertexLabelR{V17}{left}{$17$} - \vertexLabelR{V18}{left}{$18$} - \vertexLabelR{V19}{left}{$19$} - \vertexLabelR{V20}{left}{$20$} -\end{tikzpicture} - -\end{document} - - - From b5eb0fd8f3f5313938ebe26783137f5822b41560 Mon Sep 17 00:00:00 2001 From: Flynn Fehre Date: Tue, 9 Apr 2024 16:45:13 +0200 Subject: [PATCH 23/44] deleted one more .tex-file from another branch --- .../Image_convex_facegraph_Double6Gon.tex | 312 ------------------ 1 file changed, 312 deletions(-) delete mode 100644 doc/tikz-files/Image_convex_facegraph_Double6Gon.tex diff --git a/doc/tikz-files/Image_convex_facegraph_Double6Gon.tex b/doc/tikz-files/Image_convex_facegraph_Double6Gon.tex deleted file mode 100644 index 3e6fd2b7..00000000 --- a/doc/tikz-files/Image_convex_facegraph_Double6Gon.tex +++ /dev/null @@ -1,312 +0,0 @@ -\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}[vertexBall, edgeDouble=nolabels, faceStyle=nolabels, scale=4] - - \coordinate (V1) at (1. , 0.); - \coordinate (V2) at (0.5000000010362841 , 0.8660254031861397); - \coordinate (V3) at (-0.4999999979274318 , 0.8660254049810364); - \coordinate (V4) at (-1. , 3.589793029841612e-09); - \coordinate (V5) at (-0.5000000041451365 , -0.866025401391243); - \coordinate (V6) at (0.4999999948185802 , -0.8660254067759328); - \coordinate (V7) at (0.8333333326424773 , -5.982988363998724e-10); - \coordinate (V8) at (0.3888888898100303 , 0.7216878361878827); - \coordinate (V9) at (-0.4351851836499495 , 0.6976315766169703); - \coordinate (V10) at (-0.8225308646325142 , -0.02806563506918342); - \coordinate (V11) at (-0.3870884810657467 , -0.7263654412350147); - \coordinate (V12) at (0.4077074718085085 , -0.698411178156174); - \draw[edge] (V1) -- node[edgeLabel] {$1$} (V6); - \draw[edge] (V1) -- node[edgeLabel] {$2$} (V2); - \draw[edge] (V2) -- node[edgeLabel] {$3$} (V3); - \draw[edge] (V3) -- node[edgeLabel] {$4$} (V4); - \draw[edge] (V4) -- node[edgeLabel] {$5$} (V5); - \draw[edge] (V5) -- node[edgeLabel] {$6$} (V6); - \draw[edge] (V1) -- node[edgeLabel] {$7$} (V7); - \draw[edge] (V6) -- node[edgeLabel] {$8$} (V12); - \draw[edge] (V7) -- node[edgeLabel] {$9$} (V12); - \draw[edge] (V2) -- node[edgeLabel] {$10$} (V8); - \draw[edge] (V7) -- node[edgeLabel] {$11$} (V8); - \draw[edge] (V3) -- node[edgeLabel] {$12$} (V9); - \draw[edge] (V8) -- node[edgeLabel] {$13$} (V9); - \draw[edge] (V4) -- node[edgeLabel] {$14$} (V10); - \draw[edge] (V9) -- node[edgeLabel] {$15$} (V10); - \draw[edge] (V5) -- node[edgeLabel] {$16$} (V11); - \draw[edge] (V10) -- node[edgeLabel] {$17$} (V11); - \draw[edge] (V11) -- node[edgeLabel] {$18$} (V12); - % Draw the faces - \vertexLabelR{V1}{left}{$1$} - \vertexLabelR{V2}{left}{$2$} - \vertexLabelR{V3}{left}{$3$} - \vertexLabelR{V4}{left}{$4$} - \vertexLabelR{V5}{left}{$5$} - \vertexLabelR{V6}{left}{$6$} - \vertexLabelR{V7}{left}{$7$} - \vertexLabelR{V8}{left}{$8$} - \vertexLabelR{V9}{left}{$9$} - \vertexLabelR{V10}{left}{$10$} - \vertexLabelR{V11}{left}{$11$} - \vertexLabelR{V12}{left}{$12$} - \end{tikzpicture} - -\end{document} - - From 053a2196a4ec99c2e4e654cc324c2b8b58b6d898 Mon Sep 17 00:00:00 2001 From: alice Date: Mon, 9 Sep 2024 21:14:36 +0200 Subject: [PATCH 24/44] bug fix in ConcatenationPaths --- gap/Paths/paths.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gap/Paths/paths.gi b/gap/Paths/paths.gi index f2060662..abf099dd 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 ); From 728b3c6e87bcdad1fe5fb5df2b82d57375fcc4c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Tue, 10 Sep 2024 16:07:22 +0200 Subject: [PATCH 25/44] PackageInfo.g --- PackageInfo.g | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PackageInfo.g b/PackageInfo.g index 94aa820c..ce5c2fd0 100644 --- a/PackageInfo.g +++ b/PackageInfo.g @@ -112,7 +112,7 @@ PackageDoc := rec( ), 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 := [ ], From 37f027f9f3d777a1383c3450dfdc40be48602760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Tue, 10 Sep 2024 19:05:47 +0200 Subject: [PATCH 26/44] changed github checks --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 5c6ffe49..1091702b 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -25,8 +25,8 @@ jobs: matrix: gap-branch: - master + - stable-4.13 - stable-4.12 - - stable-4.11 steps: - uses: actions/checkout@v3 From 72858e1f468f28eaaa3a3aea0c9b7c77ff62b5bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Wed, 11 Sep 2024 09:44:01 +0200 Subject: [PATCH 27/44] use cycle methods of Digraphs --- gap/Paths/paths.gd | 6 +- gap/Paths/paths.gi | 9 +- gap/PolygonalComplexes/graphs.gi | 296 ++++--------------------------- unit_tests/Test_Graphs.g | 2 +- 4 files changed, 45 insertions(+), 268 deletions(-) diff --git a/gap/Paths/paths.gd b/gap/Paths/paths.gd index 416e637c..4f297de6 100644 --- a/gap/Paths/paths.gd +++ b/gap/Paths/paths.gd @@ -604,8 +604,8 @@ DeclareAttribute( "AssociatedPolygonalComplex", IsVertexEdgePath ); #! gap> butterfly:=SimplicialSurfaceByDownwardIncidence( #! > [[1,2],[1,3],[2,3],[3,4],[1,4]],[[1,2,3],[2,4,5]]);; #! gap> AllClosedVertexEdgePaths(butterfly); -#! [ ( v1, E1, v2, E3, v3, E2, v1 ), ( v1, E1, v2, E3, v3, E4, v4, E5, v1 ), -#! ( v1, E5, v4, E4, v3, E2, v1 ) ] +#! [ ( v3, E2, v1, E5, v4, E4, v3 ), ( v3, E3, v2, E1, v1, E2, v3 ), +#! ( v3, E3, v2, E1, v1, E5, v4, E4, v3 ) ] #! @EndExampleSession #! @Returns a list of vertex-edge-paths #! @Arguments complex @@ -1305,7 +1305,7 @@ DeclareAttribute( "AllThreeWaistsOfComplex", IsTwistedPolygonalComplex); #! For example, consider the double tetrahedron from the start of section : #! @BeginExampleSession #! gap> AllWaistsOfComplex(doubleTetra); -#! [ ( v5, E10, v4, E7, v3, E8, v5 ), ( v5, E12, v6, E9, v3, E8, v5 ) ] +#! [ ( v4, E10, v5, E8, v3, E7, v4 ), ( v6, E12, v5, E8, v3, E9, v6 ) ] #! @EndExampleSession #! #! @Returns a set of closed vertex-edge-paths diff --git a/gap/Paths/paths.gi b/gap/Paths/paths.gi index f2060662..f067a577 100644 --- a/gap/Paths/paths.gi +++ b/gap/Paths/paths.gi @@ -406,20 +406,19 @@ InstallMethod(AllClosedVertexEdgePaths, "for a complex", # First calculate all cycles of the edge graph. # These cycles result in all closed vertex edge path of the complex except cycles of length two. graph:=EdgeDigraphsGraph(newComplex); - cycles:=__SIMPLICIAL_AllCyclesOfGraph(graph); + cycles:=DigraphAllUndirectedSimpleCircuits(graph); newCycles:=[]; # Compute for all cycles the corresponding edges in the complex. for c in cycles do - nodesOfCycle:=Flat(__SIMPLICIAL_NodesOfCycle(c)); # CommonEdgesOfVertices returns all edges that are possible between two vertices. edgeList:=[]; - for e in CommonEdgesOfVertices(newComplex, Last(nodesOfCycle),nodesOfCycle[1]) do + for e in CommonEdgesOfVertices(newComplex, Last(c),c[1]) do Add(edgeList,[e]); od; - for i in [1..Length(nodesOfCycle)-1] do - edges:=CommonEdgesOfVertices(newComplex, nodesOfCycle[i],nodesOfCycle[i+1]); + for i in [1..Length(c)-1] do + edges:=CommonEdgesOfVertices(newComplex, c[i],c[i+1]); newEdgeList:=[]; # Add the possibilities for the next edge to each edge list computed so far. diff --git a/gap/PolygonalComplexes/graphs.gi b/gap/PolygonalComplexes/graphs.gi index a31d9e9e..2c48a45a 100644 --- a/gap/PolygonalComplexes/graphs.gi +++ b/gap/PolygonalComplexes/graphs.gi @@ -803,272 +803,49 @@ BindGlobal("__SIMPLICIAL_AdjacencyMatrixFromList", return mat; end); +BindGlobal("__SIMPLICIAL_EdgesFromCycle", + function(digraph,cycle) -# The following function computes all cycles of a graph by: -# 1. Calculation of a cycle base (CyclesBasisOfGraph) by first computing a spanning tree and then adding each edge -# which is not in the tree. Each edge gives a different cycle named base cycles. -# 2. Iterate through all possible combinations of base cycles and combine them by applying XOR to the adjacency matrices. -# In this way you get all cycles of the graph. -BindGlobal("__SIMPLICIAL_AllCyclesOfGraph", - function(digraph) - - local CycleOnEdge,CycleBasisOfGraph,XORAdjacencyMatrices, - MultipleCyclesInMatrix,cyclebasis, allcycles, nullmat, mat, i, k, pos, neighs,c,cycle; - - # Find a cycle in the original graph all of whose edges are in - # tree except for the edge e. - CycleOnEdge := function( tree, root, e ) - - local cycle, i, path1, path2, l1, l2; - - if e[1] = e[2] then - Error("CycleOnEdge: edge is a loop"); - return false; - fi; - - # first find paths from the root to the two vertices of e - if root = e[1] then path1 := [root]; - else path1 := DigraphPath(tree, root, e[1])[1]; fi; - if root = e[2] then path2 := [root]; - else path2 := DigraphPath(tree, root, e[2])[1]; fi; - l1 := Length(path1); l2 := Length(path2); - - # now skip the common entries in the path - cycle := []; i := 1; - while i <= Minimum(l1,l2) and path1[i] = path2[i] do - i := i + 1; - od; - - cycle := [path1[i-1]]; - Append(cycle, path1{[i..l1]}); - Append(cycle, Reversed(path2{[i..l2]})); - - return __SIMPLICIAL_AdjacencyMatrixFromList(cycle,DigraphNrVertices(tree)); - end;; - - # This function computes a cycle basis for the undirected graph - # dig, which is assumed to be a symmetric digraph. - # The cycle Basis consists of lower triangular matrices whose - # entries are boolean lists. - CycleBasisOfGraph := function( dig ) - - local tree, dige, base, root, e; - - if not IsSymmetricDigraph(dig) then - Error("the digraph is assumed to be symmetric"); - fi; - - base := Set([]); - tree := UndirectedSpanningTree(dig); - dige := DigraphEdges(tree); - - root := DigraphVertices(dig)[1]; - - for e in DigraphEdges(dig) do - if not e in dige then - AddSet(base, CycleOnEdge(tree,root, e)); - fi; - od; - - - return base; - end;; - - # This method combines two adjacency matrices with the operator XOR. - XORAdjacencyMatrices := function( mat1, mat2 ) - - local j, res, nd; - - res :=[]; - for j in [1.. Length(mat1)] do - nd := IntersectionBlist(mat1[j],mat2[j]); - FlipBlist(nd); - res[j] := IntersectionBlist( UnionBlist(mat1[j],mat2[j]), nd ); - od; - - return res; - end;; - - cyclebasis := CycleBasisOfGraph( digraph ); - - if cyclebasis=[] then - return []; - fi; - - neighs := OutNeighbours(digraph); - allcycles := []; - - nullmat := XORAdjacencyMatrices(cyclebasis[1],cyclebasis[1]); - for k in [0..2^Length(cyclebasis)-1] do - # combine the matrices encoded by k - mat := nullmat; - i := k; - pos := 0; - while i>0 do - pos := pos + 1; - if i mod 2 <> 0 then - mat := XORAdjacencyMatrices(mat,cyclebasis[pos]); - fi; - i := Int(i/2); - od; + local edgesOfCycle, i, edge; - if SizeBlist(Flat(mat))<>0 then - for c in __SIMPLICIAL_NodesOfCycle(mat) do - cycle:=__SIMPLICIAL_AdjacencyMatrixFromList(c,Length(mat)); - if not cycle in allcycles then - Add(allcycles,cycle); - fi; - od; + edgesOfCycle:=[]; + for i in [1..Length(cycle)] do + if i0 then - blocked[u]:=blocked[u]-1; - fi; - od; - return blocked; - end; - - # Computes the degree labeling - DegreeLabeling:=function(digraph) - local degree,color,labeling,v,u,i,minDegree,x; - - degree:=List(DigraphVertices(digraph),i->0); - color:=List(DigraphVertices(digraph),i->false); - labeling:=List(DigraphVertices(digraph),i->0); - degree:=List(DigraphVertices(digraph),i->OutDegreeOfVertex(digraph,i)); - - for i in [1..DigraphNrVertices(digraph)] do - minDegree:=DigraphNrVertices(digraph); - for x in DigraphVertices(digraph) do - if color[x]=false and degree[x]key and blocked[v]=1 then - extendedPath:=Concatenation(path,[v]); - if IsDigraphEdge(digraph,v,First(path)) then - Add(C,extendedPath); - else - data:=CCExtension(digraph,extendedPath,C,key,blocked); - C:=data[1]; - blocked:=data[2]; - fi; - fi; - od; - blocked:=UnblockNeighbours(digraph,Last(path),blocked); - return [C,blocked]; - end; - - SetDigraphVertexLabels(digraph,DegreeLabeling(digraph)); - temp:=Triplets(digraph); - T:=temp[1]; - C:=temp[2]; - blocked:=List(DigraphVertices(digraph),i->0); - while T<>[] do - triple:=Remove(T); - blocked:=BlockNeighbours(digraph,triple[2],blocked); - temp:=CCExtension(digraph,triple,C,DigraphVertexLabel(digraph,triple[2]),blocked); - C:=temp[1]; - blocked:=temp[2]; - blocked:=UnblockNeighbours(digraph,triple[2],blocked); - od; - return C; - - end + end ); BindGlobal("__SIMPLICIAL_IsNonSeparating", function(digraph,cycle) - local edgesOfCycle, e, digraphRemoved; + local edgesOfCycle, e, digraphRemoved; - if not IsSymmetricDigraph(digraph) then - return false; - fi; + if not IsSymmetricDigraph(digraph) then + return false; + fi; - edgesOfCycle:=[]; - for e in __SIMPLICIAL_EdgesFromAdjacencyMat(cycle) do - Append(edgesOfCycle,[e,Reversed(e)]); - od; + edgesOfCycle:=__SIMPLICIAL_EdgesFromCycle(digraph,cycle); + #for e in __SIMPLICIAL_EdgesFromAdjacencyMat(cycle) do + # Append(edgesOfCycle,[e,Reversed(e)]); + #od; - digraphRemoved:=DigraphRemoveEdges(digraph,edgesOfCycle); - if IsConnectedDigraph(digraphRemoved) then - return true; - else - return false; - fi; + digraphRemoved:=DigraphRemoveEdges(digraph,edgesOfCycle); + if IsConnectedDigraph(digraphRemoved) then + return true; + else + return false; + fi; - end + end ); InstallOtherMethod(AllSimplicialSurfacesOfDigraph,"for a digraph", @@ -1089,17 +866,18 @@ InstallMethod(AllSimplicialSurfacesOfDigraph,"for a digraph and a Boolean", Error("SimplicialSurfaceOfDigraph: Given digraph has to be simple, symmetric and connected"); fi; if vertexFaithful then - allCycles:=List(__SIMPLICIAL_AllChordlessCyclesOfGraph(digraph),c->__SIMPLICIAL_AdjacencyMatrixFromList(c,DigraphNrVertices(digraph))); - allCycles:=Filtered(allCycles,c->__SIMPLICIAL_IsNonSeparating(digraph,c)); + #allCycles:=List(DigraphAllChordlessCycles(digraph),c->__SIMPLICIAL_AdjacencyMatrixFromList(c,DigraphNrVertices(digraph))); + allCycles:=DigraphAllChordlessCycles(digraph); + allCycles:=Filtered(allCycles,c->__SIMPLICIAL_IsNonSeparating(digraph,c)); else - allCycles:=__SIMPLICIAL_AllCyclesOfGraph(digraph); + allCycles:=DigraphAllUndirectedSimpleCircuits(digraph); fi; edgesOfGraph:=Filtered(DigraphEdges(digraph),e->not IsSortedList(e)); edgesOfCycles:=[]; for cycle in [1..Length(allCycles)] do; - edgesOfCycles[cycle]:=List(__SIMPLICIAL_EdgesFromAdjacencyMat(allCycles[cycle]),e->Position(edgesOfGraph,e)); + edgesOfCycles[cycle]:=List(__SIMPLICIAL_EdgesFromCycle(digraph,allCycles[cycle]),e->Position(edgesOfGraph,e)); od; possibleCyclesPairs:=[]; @@ -1195,10 +973,10 @@ InstallMethod(AllSimplicialSurfacesOfDigraph,"for a digraph and a Boolean", # if we search vertex-faithful simplicial surfaces all cycles of length three and four have to be part of the resulting cycle combination if vertexFaithful and IsIsomorphicDigraph(graph, CompleteDigraph(4)) then - smallCy:=Filtered([1..Length(allCycles)], c->SizeBlist(Flat(allCycles[c]))<4); + smallCy:=Filtered(allCycles, c->Length(c)<4); smallCy:=BlistList([1..Length(allCycles)],smallCy); elif vertexFaithful then - smallCy:=Filtered([1..Length(allCycles)], c->SizeBlist(Flat(allCycles[c]))<5); + smallCy:=Filtered(allCycles, c->Length(c)<5); smallCy:=BlistList([1..Length(allCycles)],smallCy); fi; @@ -1257,7 +1035,7 @@ InstallMethod(AllSimplicialSurfacesOfDigraph,"for a digraph and a Boolean", umbrellaDesk:=[]; for cycle in ListBlist([1..Length(vertexCycleComb)],vertexCycleComb) do - Add(umbrellaDesk,NodesOfCycle(allCycles[cycle])); + Add(umbrellaDesk,CycleFromList(allCycles[cycle])); od; face:=SimplicialSurfaceByUmbrellaDescriptor(umbrellaDesk); diff --git a/unit_tests/Test_Graphs.g b/unit_tests/Test_Graphs.g index e1b691a4..0eb2a73b 100644 --- a/unit_tests/Test_Graphs.g +++ b/unit_tests/Test_Graphs.g @@ -69,7 +69,7 @@ if IsPackageMarkedForLoading( "Digraphs", ">=0.10.1" ) then list1:=AllSimplicialSurfacesOfDigraph(dig,true); Assert(0,Length(list1)=1); Assert(0,IsIsomorphic(list1[1],surface)); - + list2:=AllSimplicialSurfacesOfDigraph(dig); Assert(0, Length(Filtered(list2,IsVertexFaithful))=1); Assert(0,IsIsomorphic(Filtered(list2,IsVertexFaithful)[1],surface)); From 3547e090110569655d465c838a79ec114af2397d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Wed, 11 Sep 2024 10:10:56 +0200 Subject: [PATCH 28/44] added package requirement --- gap/Paths/paths.gi | 4 ++ gap/PolygonalComplexes/graphs.gi | 117 +------------------------------ 2 files changed, 7 insertions(+), 114 deletions(-) diff --git a/gap/Paths/paths.gi b/gap/Paths/paths.gi index f067a577..5fe355e1 100644 --- a/gap/Paths/paths.gi +++ b/gap/Paths/paths.gi @@ -391,6 +391,7 @@ InstallMethod(ShiftCyclicPath, end ); +if IsPackageMarkedForLoading( "Digraphs", ">=1.9.0" ) then InstallMethod(AllClosedVertexEdgePaths, "for a complex", [IsTwistedPolygonalComplex], function(complex) @@ -443,6 +444,7 @@ InstallMethod(AllClosedVertexEdgePaths, "for a complex", return Union(newCycles,AllTwoWaistsOfComplex(complex)); end ); +fi; ####################################### ## @@ -1003,6 +1005,7 @@ InstallMethod( AllThreeWaistsOfComplex, "for a twisted polygonal complex", end ); +if IsPackageMarkedForLoading( "Digraphs", ">=1.9.0" ) then InstallMethod(AllWaistsOfComplex, "for a twisted polygonal complex", [IsTwistedPolygonalComplex], function(complex) @@ -1019,6 +1022,7 @@ InstallMethod(AllWaistsOfComplex, "for a twisted polygonal complex", return waists; end ); +fi; ## ## End of waists ## diff --git a/gap/PolygonalComplexes/graphs.gi b/gap/PolygonalComplexes/graphs.gi index 2c48a45a..c038db10 100644 --- a/gap/PolygonalComplexes/graphs.gi +++ b/gap/PolygonalComplexes/graphs.gi @@ -722,87 +722,7 @@ InstallMethod( OnEdgeFacePaths, ## ## All Surfaces Of A Graph ## - -# Calculate from a adjacency matrix the corresponding edges -BindGlobal( "__SIMPLICIAL_EdgesFromAdjacencyMat", - function(mat) - local edges, i, j; - - edges := Set([]); - for j in [1 .. Length(mat)] do - edges := Union(edges, List(ListBlist([1..j],mat[j]), i-> [j,i] )); - od; - - return edges; -end); - -# The function converts a boolean list describing one or more cycles -# into lists of nodes of the cycles. -BindGlobal("__SIMPLICIAL_NodesOfCycle", - function(cycle) - local edges,firstNod,actualNod,nodes,found,e,cycles; - - edges:=__SIMPLICIAL_EdgesFromAdjacencyMat(cycle); - cycles:=[]; - # We have to use each edge exactly one time - while edges<>[] do - firstNod:=(edges[1])[1]; - actualNod:=(edges[1])[2]; - Remove(edges,1); - nodes:=[actualNod]; - # Walk along the cycle - while actualNod<>firstNod do - found:=false; - for e in edges do - if found=false then - if e[1]=actualNod then - actualNod:=e[2]; - Add(nodes,actualNod); - Remove(edges,Position(edges,e)); - found:=true; - elif e[2]=actualNod then - actualNod:=e[1]; - Add(nodes,actualNod); - Remove(edges,Position(edges,e)); - found:=true; - fi; - fi; - od; - od; - Add(cycles,nodes); - od; - return cycles; -end); - -# We want to store graphs as adjacency matrices. This function -# turns a cycle into a boolean lower triangular matrix. -BindGlobal("__SIMPLICIAL_AdjacencyMatrixFromList", - function(cycle, n) - - local mat, i, j, k; - - mat := []; - for i in [ 1 .. n] do - mat[i] := BlistList([1..i],[]); - od; - - for i in [ 1 .. Length(cycle)] do - if i < Length(cycle) then - j := cycle[i+1]; - else - j := cycle[1]; - fi; - k := cycle[i]; - if k < j then - mat[j]:= UnionBlist(mat[j],BlistList( [1..j],[k] )); - elif j < k then - mat[k] := UnionBlist(mat[k],BlistList([1..k],[j])); - fi; - od; - - return mat; -end); - +if IsPackageMarkedForLoading( "Digraphs", ">=1.9.0" ) then BindGlobal("__SIMPLICIAL_EdgesFromCycle", function(digraph,cycle) @@ -834,9 +754,6 @@ BindGlobal("__SIMPLICIAL_IsNonSeparating", fi; edgesOfCycle:=__SIMPLICIAL_EdgesFromCycle(digraph,cycle); - #for e in __SIMPLICIAL_EdgesFromAdjacencyMat(cycle) do - # Append(edgesOfCycle,[e,Reversed(e)]); - #od; digraphRemoved:=DigraphRemoveEdges(digraph,edgesOfCycle); if IsConnectedDigraph(digraphRemoved) then @@ -860,13 +777,12 @@ InstallMethod(AllSimplicialSurfacesOfDigraph,"for a digraph and a Boolean", function(digraph,vertexFaithful) local allCycles,edgesOfGraph, faces,edgesOfCycles,CyclesOfEdges,cyclesOfEdges,FindSurface,FindCycleComb, - NodesOfCycle,cycle,cyclePair,IsPartOf,possibleCyclesPairs,commonEdges,Possible,e; + cycle,cyclePair,IsPartOf,possibleCyclesPairs,commonEdges,Possible,e; if IsMultiDigraph(digraph) or DigraphHasLoops(digraph) or not IsSymmetricDigraph(digraph) or not IsConnectedDigraph(digraph) then Error("SimplicialSurfaceOfDigraph: Given digraph has to be simple, symmetric and connected"); fi; if vertexFaithful then - #allCycles:=List(DigraphAllChordlessCycles(digraph),c->__SIMPLICIAL_AdjacencyMatrixFromList(c,DigraphNrVertices(digraph))); allCycles:=DigraphAllChordlessCycles(digraph); allCycles:=Filtered(allCycles,c->__SIMPLICIAL_IsNonSeparating(digraph,c)); else @@ -930,34 +846,6 @@ InstallMethod(AllSimplicialSurfacesOfDigraph,"for a digraph and a Boolean", return true; end;; - # The function computes for a given cycle the sequence of nodes of the cycle. - NodesOfCycle:=function(cycle) - local edges,firstNod,actualNode,nodes,e; - - edges:=__SIMPLICIAL_EdgesFromAdjacencyMat(cycle); - - firstNod:=(edges[1])[1]; - actualNode:=(edges[1])[2]; - nodes:=[actualNode]; - Remove(edges,1); - - while actualNode<>firstNod do - for e in edges do - if e[1]=actualNode then - actualNode:=e[2]; - Add(nodes,actualNode); - Remove(edges,Position(edges,e)); - elif e[2]=actualNode then - actualNode:=e[1]; - Add(nodes,actualNode); - Remove(edges,Position(edges,e)); - fi; - od; - od; - - return CycleFromList(nodes); - end;; - IsPartOf:=function(face,faces) local f; for f in faces do @@ -1155,3 +1043,4 @@ InstallMethod(AllSimplicialSurfacesOfDigraph,"for a digraph and a Boolean", end ); +fi; \ No newline at end of file From f16a73c62015f74fde0c366a52308f9677064102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Wed, 11 Sep 2024 10:33:23 +0200 Subject: [PATCH 29/44] added package requirement in tests --- unit_tests/Test_Graphs.g | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unit_tests/Test_Graphs.g b/unit_tests/Test_Graphs.g index 0eb2a73b..d5417cd0 100644 --- a/unit_tests/Test_Graphs.g +++ b/unit_tests/Test_Graphs.g @@ -61,7 +61,9 @@ if IsPackageMarkedForLoading( "Digraphs", ">=0.10.1" ) then od; Assert(0, Set(DigraphEdges(digButterfly))=Set(Filtered(Union(FacesOfEdges(butterfly),reversedButterfly),i->Length(i)=2))); end); +fi; +if IsPackageMarkedForLoading( "Digraphs", ">=1.9.0" ) then BindGlobal( "__SIMPLICIAL_Test_AllSimplicialSurfacesOfDigraph", function() local dig, surface, list1, list2; surface:=SimplicialSurfaceByVerticesInFaces([[1,4,5],[1,4,6],[1,5,7],[1,6,7],[2,3,5],[2,3,6],[2,4,5],[2,4,6],[3,5,7],[3,6,7]]); From 0c478811ef266756ca317aab5225c7de3120fa27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Wed, 11 Sep 2024 10:46:45 +0200 Subject: [PATCH 30/44] added requirement --- unit_tests/test_main.g | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/unit_tests/test_main.g b/unit_tests/test_main.g index 9099608d..69149f02 100644 --- a/unit_tests/test_main.g +++ b/unit_tests/test_main.g @@ -61,7 +61,9 @@ BindGlobal( "SIMPLICIAL_TestAll", function() __SIMPLICIAL_Test_EdgeNautyGraph(); __SIMPLICIAL_Test_FaceDigraphsGraph(); __SIMPLICIAL_Test_FaceNautyGraph(); - __SIMPLICIAL_Test_AllSimplicialSurfacesOfDigraph(); + if IsPackageMarkedForLoading( "Digraphs", ">=0.10.1" ) then + __SIMPLICIAL_Test_AllSimplicialSurfacesOfDigraph(); + fi; __SIMPLICIAL_Test_FaceTwoColouring(); From f532c7ddc832bff8408c9d9433d92244f6d7d93d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Wed, 11 Sep 2024 10:54:41 +0200 Subject: [PATCH 31/44] corrected wrong package version --- unit_tests/test_main.g | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unit_tests/test_main.g b/unit_tests/test_main.g index 69149f02..6744607b 100644 --- a/unit_tests/test_main.g +++ b/unit_tests/test_main.g @@ -61,7 +61,7 @@ BindGlobal( "SIMPLICIAL_TestAll", function() __SIMPLICIAL_Test_EdgeNautyGraph(); __SIMPLICIAL_Test_FaceDigraphsGraph(); __SIMPLICIAL_Test_FaceNautyGraph(); - if IsPackageMarkedForLoading( "Digraphs", ">=0.10.1" ) then + if IsPackageMarkedForLoading( "Digraphs", ">=1.9.0" ) then __SIMPLICIAL_Test_AllSimplicialSurfacesOfDigraph(); fi; From f4d62f89fb30881a36c8827d2e4fdfe74def1f59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Wed, 11 Sep 2024 11:13:49 +0200 Subject: [PATCH 32/44] no automatic generated tests --- gap/Paths/paths.gd | 8 ++++---- gap/PolygonalComplexes/graphs.gd | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/gap/Paths/paths.gd b/gap/Paths/paths.gd index 416e637c..b3b72466 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); #! [ ( v1, E1, v2, E3, v3, E2, v1 ), ( v1, E1, v2, E3, v3, E4, v4, E5, v1 ), #! ( v1, E5, v4, E4, v3, E2, v1 ) ] -#! @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); #! [ ( v5, E10, v4, E7, v3, E8, v5 ), ( v5, E12, v6, E9, v3, E8, v5 ) ] -#! @EndExampleSession +#! @EndLogSession #! #! @Returns a set of closed vertex-edge-paths #! @Arguments complex diff --git a/gap/PolygonalComplexes/graphs.gd b/gap/PolygonalComplexes/graphs.gd index 95be24f0..8b168352 100644 --- a/gap/PolygonalComplexes/graphs.gd +++ b/gap/PolygonalComplexes/graphs.gd @@ -441,17 +441,17 @@ 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: -#! @BeginExampleSession +#! @BeginLogSession #! gap> list := AllSimplicialSurfacesOfDigraph(digraph,false); #! [ simplicial surface (4 vertices, 6 edges, and 4 faces), #! simplicial surface (3 vertices, 6 edges, and 4 faces)] @@ -459,7 +459,7 @@ DeclareAttribute( "FaceNautyGraph", IsPolygonalComplex ); #! [ simplicial surface (4 vertices, 6 edges, and 4 faces) ] #! gap> IsIsomorphic(tet2[1],Tetrahedron()); #! true -#! @EndExampleSession +#! @EndLogSession #! #! Since it takes a long time to compute all cycles, you should only call the method for digraphs with twelve or less nodes for vertexfaithful false. #! For vertexfaithful true, the method needs to consider only chordless and non-separating cycles. This makes the method fast for digraphs up to 28 nodes. From 067e9492d2706b8afa8af3f3b5f00bc3d6a06359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Wed, 11 Sep 2024 11:35:57 +0200 Subject: [PATCH 33/44] changed ExampleSession to LogSession --- gap/PolygonalComplexes/graphs.gd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gap/PolygonalComplexes/graphs.gd b/gap/PolygonalComplexes/graphs.gd index 95be24f0..ed76b65b 100644 --- a/gap/PolygonalComplexes/graphs.gd +++ b/gap/PolygonalComplexes/graphs.gd @@ -451,7 +451,7 @@ DeclareAttribute( "FaceNautyGraph", IsPolygonalComplex ); #! #! So the only vertex-faithful simplicial surface of the digraph is the tetrahedron. #! But there is another simplicial surface, which is not vertex-faithful: -#! @BeginExampleSession +#! @BeginLogSession #! gap> list := AllSimplicialSurfacesOfDigraph(digraph,false); #! [ simplicial surface (4 vertices, 6 edges, and 4 faces), #! simplicial surface (3 vertices, 6 edges, and 4 faces)] @@ -459,7 +459,7 @@ DeclareAttribute( "FaceNautyGraph", IsPolygonalComplex ); #! [ simplicial surface (4 vertices, 6 edges, and 4 faces) ] #! gap> IsIsomorphic(tet2[1],Tetrahedron()); #! true -#! @EndExampleSession +#! @EndLogSession #! #! Since it takes a long time to compute all cycles, you should only call the method for digraphs with twelve or less nodes for vertexfaithful false. #! For vertexfaithful true, the method needs to consider only chordless and non-separating cycles. This makes the method fast for digraphs up to 28 nodes. From 955957c608056d5f7bcf0e59c8c61859e84f000c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Wed, 11 Sep 2024 11:43:08 +0200 Subject: [PATCH 34/44] confused --- gap/PolygonalComplexes/graphs.gd | 1 - 1 file changed, 1 deletion(-) diff --git a/gap/PolygonalComplexes/graphs.gd b/gap/PolygonalComplexes/graphs.gd index 8b168352..73d6d30c 100644 --- a/gap/PolygonalComplexes/graphs.gd +++ b/gap/PolygonalComplexes/graphs.gd @@ -448,7 +448,6 @@ DeclareAttribute( "FaceNautyGraph", IsPolygonalComplex ); #! gap> IsIsomorphic(tet1[1],Tetrahedron()); #! true #! @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: #! @BeginLogSession From 5bf45794d44de228e8ddaed02c6826ab8d455ab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Wed, 11 Sep 2024 12:00:40 +0200 Subject: [PATCH 35/44] changed documentation --- gap/Paths/paths.gd | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/gap/Paths/paths.gd b/gap/Paths/paths.gd index e8cfd924..c3693517 100644 --- a/gap/Paths/paths.gd +++ b/gap/Paths/paths.gd @@ -1197,11 +1197,18 @@ DeclareAttribute( "ViewInformation", IsEdgeFacePath ); #! @Section Waists #! @SectionLabel Waists #! This section deals with a specific type of closed vertex-edge-paths, namely waists. -#! A n-waist is a closed vertex-edge path of length n such that all edges are inner and no two are incident to the same face. -#! Moreover, a simplicial surface X can only have a n-waist for n>3 if X does not have a 3-waist and the vertex-edge path describing the n-waist must be distance-faithful. -#! A closed vertex-edge path P is distance-faithful if for any two vertices of P at least one shortest edge path between them is contained in P. +#! In order to introduce the definition of a waist of a simplicial surface, we first +#! present the definition of a distance-faithful path. Here, a closed edge path P of +#! a given simplicial surface is called distance-faithful if for any two vertices of the +#! path P at least one shortest edge path between them is contained in P. +#! Using the above notion we introduce waists of simplicial surfaces. +#! Let therefore n be a natural number. If n satisfies 2<=n<=3, +#! then an n-waist of a given simplicial surface is defined as a circular edge +#! path of length n such that all edges are inner and no two are incident to the same face. +#! Moreover, if the given simplicial surface is closed without 3-waists and the inequality +#! n>=4 holds, we define an n-waist as a closed distance-faithful edge path of length n. #! -#! This will be illustrated on the following double tetrahedron: +#! This will be illustrated on the following simplicial surface constructed by three tetrahedra: #! #! <img src="./images/_Wrapper_Image_Example3Waist-1.svg"> </img> #! @@ -1214,7 +1221,7 @@ DeclareAttribute( "ViewInformation", IsEdgeFacePath ); #! Image omitted in terminal text #! #! @BeginExampleSession -#! gap> doubleTetra:=SimplicialSurfaceByVerticesInFaces( +#! gap> tripleTetra:=SimplicialSurfaceByVerticesInFaces( #! > [[1,3,5],[2,5,6],[2,3,5],[2,3,6],[1,4,5],[3,4,6],[1,3,4],[4,5,6]]);; #! @EndExampleSession @@ -1223,17 +1230,17 @@ DeclareAttribute( "ViewInformation", IsEdgeFacePath ); #! Return whether the given path vertexEdgePath is a waist in complex. #! The definition of a waist is given at the beginning of section . #! -#! For example, consider the double tetrahedron from the start of section . +#! For example, consider the simplicial surface from the start of section . #! The path around a face is not a waist: #! @BeginExampleSession -#! gap> path:=VertexEdgePathByEdges(doubleTetra,[1,3,8]);; -#! gap> IsWaist(doubleTetra, path); +#! gap> path:=VertexEdgePathByEdges(triple,[1,3,8]);; +#! gap> IsWaist(tripleTetra, path); #! false #! @EndExampleSession #! A path of length three, where the edges are pairwise incident to two different faces, is a waist: #! @BeginExampleSession -#! gap> waist:=VertexEdgePathByEdges(doubleTetra,[7,8,10]);; -#! gap> IsWaist(doubleTetra, waist); +#! gap> waist:=VertexEdgePathByEdges(tripleTetra,[7,8,10]);; +#! gap> IsWaist(tripleTetra, waist); #! true #! @EndExampleSession #! @@ -1284,9 +1291,9 @@ DeclareAttribute( "AllTwoWaistsOfComplex", IsTwistedPolygonalComplex); #! vertices so that there exist no face in complex that is incident to more #! than one of the visited edges. #! -#! For example, consider the double tetrahedron from the start of section : +#! For example, consider the simplicial surface from the start of section : #! @BeginExampleSession -#! gap> AllThreeWaistsOfComplex(doubleTetra); +#! gap> AllThreeWaistsOfComplex(tripleTetra); #! [ ( v4, E7, v3, E8, v5, E10, v4 ), ( v5, E8, v3, E9, v6, E12, v5 ) ] #! @EndExampleSession #! The tetrahedron does not have any 3-waist: @@ -1305,9 +1312,9 @@ DeclareAttribute( "AllThreeWaistsOfComplex", IsTwistedPolygonalComplex); #! Return the set of all waists contained in the given polygonal complex complex. #! The definition of a waist is given at the beginning of section . #! -#! For example, consider the double tetrahedron from the start of section : +#! For example, consider the simplicial surface from the start of section : #! @BeginExampleSession -#! gap> AllWaistsOfComplex(doubleTetra); +#! gap> AllWaistsOfComplex(tripleTetra); #! [ ( v4, E7, v3, E8, v5, E10, v4 ), ( v5, E8, v3, E9, v6, E12, v5 ) ] #! gap> AllWaistsOfComplex(Octahedron()); #! [ ( v1, E1, v2, E7, v6, E11, v4, E3, v1 ), ( v3, E2, v1, E4, v5, E12, v6, E9, v3 ), From 714a6ed38fa52cc6af248080a3af57c62217b1ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Wed, 11 Sep 2024 12:12:10 +0200 Subject: [PATCH 36/44] corrected error --- gap/Paths/paths.gd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gap/Paths/paths.gd b/gap/Paths/paths.gd index c3693517..a8c5b602 100644 --- a/gap/Paths/paths.gd +++ b/gap/Paths/paths.gd @@ -1202,11 +1202,11 @@ DeclareAttribute( "ViewInformation", IsEdgeFacePath ); #! a given simplicial surface is called distance-faithful if for any two vertices of the #! path P at least one shortest edge path between them is contained in P. #! Using the above notion we introduce waists of simplicial surfaces. -#! Let therefore n be a natural number. If n satisfies 2<=n<=3, +#! Let therefore n be a natural number. If n is equal to 2 or 3, #! then an n-waist of a given simplicial surface is defined as a circular edge #! path of length n such that all edges are inner and no two are incident to the same face. -#! Moreover, if the given simplicial surface is closed without 3-waists and the inequality -#! n>=4 holds, we define an n-waist as a closed distance-faithful edge path of length n. +#! Moreover, if the given simplicial surface is closed without 3-waists and n is at least 4, +#! then we define an n-waist as a closed distance-faithful edge path of length n. #! #! This will be illustrated on the following simplicial surface constructed by three tetrahedra: #! From c8915fc6a08502ae19e41e50b8c2c2d11d30e0df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Wed, 11 Sep 2024 12:21:04 +0200 Subject: [PATCH 37/44] fixed hopefully --- gap/Paths/paths.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gap/Paths/paths.gd b/gap/Paths/paths.gd index 36ce1cba..f67d62f0 100644 --- a/gap/Paths/paths.gd +++ b/gap/Paths/paths.gd @@ -1233,7 +1233,7 @@ DeclareAttribute( "ViewInformation", IsEdgeFacePath ); #! For example, consider the simplicial surface from the start of section . #! The path around a face is not a waist: #! @BeginExampleSession -#! gap> path:=VertexEdgePathByEdges(triple,[1,3,8]);; +#! gap> path:=VertexEdgePathByEdges(tripleTetra,[1,3,8]);; #! gap> IsWaist(tripleTetra, path); #! false #! @EndExampleSession From 65a4bf6b6bf51f6e778d5e64538f06be1be5e4f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Wed, 11 Sep 2024 12:38:22 +0200 Subject: [PATCH 38/44] added example --- gap/Paths/paths.gd | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gap/Paths/paths.gd b/gap/Paths/paths.gd index f67d62f0..c906f4c6 100644 --- a/gap/Paths/paths.gd +++ b/gap/Paths/paths.gd @@ -1243,6 +1243,13 @@ DeclareAttribute( "ViewInformation", IsEdgeFacePath ); #! gap> IsWaist(tripleTetra, waist); #! true #! @EndExampleSession +#! The octahedron has a waist of length four: +#! @BeginExampleSession +#! gap> path:=VertexEdgePathByEdges(Octahedron(),[5,6,10,8]); +#! ( v3, E5, v2, E6, v5, E10, v4, E8, v3 ) +#! gap> IsWaist(Octahedron(),path); +#! true +#! @EndExampleSession #! #! @Returns true or false #! @Arguments complex, vertexEdgePath From 90f847b55599f62ef0c14ca3c99c6be821e8d742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Wed, 11 Sep 2024 13:03:26 +0200 Subject: [PATCH 39/44] changed doc --- gap/PolygonalComplexes/modification.gd | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/gap/PolygonalComplexes/modification.gd b/gap/PolygonalComplexes/modification.gd index 48f8c05f..8c26ba03 100755 --- a/gap/PolygonalComplexes/modification.gd +++ b/gap/PolygonalComplexes/modification.gd @@ -577,13 +577,18 @@ DeclareOperation( "SplitEdgePathNC", [IsPolygonalComplex, IsVertexEdgePath and I #! actually consists only of faces in complex. It also does not #! check whether the result of SubsurfaceByFaces is a surface. #! -#! In Chapter edge colouring will be introduced. -#! If we compute a subcomplex of an edge-coloured complex, it will be edge-coloured again, -#! induced by the edge-colouring of the given complex. +#! In Chapter the edge colouring of twisted +#! polygonal complexes will be introduced. +#! +#! The hexagon from above can be coloured as follows: #! @BeginExampleSession #! gap> colEdges:=[ 1, 2, 1, 2, 1, 2, 3, 3, 3, 3, 3, 3 ];; #! gap> colSurface:=EdgeColouredPolygonalComplex(hex,colEdges); #! tame coloured surface (MMB with 7 vertices, 12 edges and 6 faces) +#! @EndExampleSession +#! If we compute a subcomplex of an edge-coloured complex, it will be edge-coloured again, +#! induced by the edge-colouring of the given complex: +#! @BeginExampleSession #! gap> SubsurfaceByFaces(colSurface,[1,2]); #! tame coloured surface (BMB with 4 vertices, 5 edges and 2 faces) #! @EndExampleSession From dc8582f7d4b047c1acb1e3d6e9c8870c6cf251c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Wed, 11 Sep 2024 13:25:07 +0200 Subject: [PATCH 40/44] just a test for understanding the problem --- unit_tests/test_main.g | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/unit_tests/test_main.g b/unit_tests/test_main.g index 6744607b..c755132b 100644 --- a/unit_tests/test_main.g +++ b/unit_tests/test_main.g @@ -61,9 +61,9 @@ BindGlobal( "SIMPLICIAL_TestAll", function() __SIMPLICIAL_Test_EdgeNautyGraph(); __SIMPLICIAL_Test_FaceDigraphsGraph(); __SIMPLICIAL_Test_FaceNautyGraph(); - if IsPackageMarkedForLoading( "Digraphs", ">=1.9.0" ) then - __SIMPLICIAL_Test_AllSimplicialSurfacesOfDigraph(); - fi; + #if IsPackageMarkedForLoading( "Digraphs", ">=1.9.0" ) then + # __SIMPLICIAL_Test_AllSimplicialSurfacesOfDigraph(); + #fi; __SIMPLICIAL_Test_FaceTwoColouring(); From 3b653ab3e3995fcb208e9e75104d693977dd9ec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Wed, 11 Sep 2024 13:37:42 +0200 Subject: [PATCH 41/44] does it works now? --- unit_tests/Test_Graphs.g | 15 ++++++++------- unit_tests/test_main.g | 6 +++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/unit_tests/Test_Graphs.g b/unit_tests/Test_Graphs.g index d5417cd0..0fc0cbe1 100644 --- a/unit_tests/Test_Graphs.g +++ b/unit_tests/Test_Graphs.g @@ -68,21 +68,22 @@ if IsPackageMarkedForLoading( "Digraphs", ">=1.9.0" ) then local dig, surface, list1, list2; surface:=SimplicialSurfaceByVerticesInFaces([[1,4,5],[1,4,6],[1,5,7],[1,6,7],[2,3,5],[2,3,6],[2,4,5],[2,4,6],[3,5,7],[3,6,7]]); dig:=FaceDigraphsGraph(surface); - list1:=AllSimplicialSurfacesOfDigraph(dig,true); - Assert(0,Length(list1)=1); - Assert(0,IsIsomorphic(list1[1],surface)); list2:=AllSimplicialSurfacesOfDigraph(dig); Assert(0, Length(Filtered(list2,IsVertexFaithful))=1); Assert(0,IsIsomorphic(Filtered(list2,IsVertexFaithful)[1],surface)); Assert(0,Length(list2)=11); + list1:=AllSimplicialSurfacesOfDigraph(dig,true); + Assert(0,Length(list1)=1); + Assert(0,IsIsomorphic(list1[1],surface)); + dig:=DigraphByEdges([ [ 1, 2 ], [ 1, 4 ], [ 1, 5 ], [ 2, 1 ], [ 2, 3 ], [ 2, 6 ], [ 3, 2 ], [ 3, 4 ], [ 3, 5 ], [ 4, 1 ], [ 4, 3 ], [ 4, 6 ], [ 5, 1 ],[ 5, 3 ], [ 5, 6 ], [ 6, 2 ], [ 6, 4 ], [ 6, 5 ] ]); - list1:=AllSimplicialSurfacesOfDigraph(dig,true); - list2:=AllSimplicialSurfacesOfDigraph(dig,false); - Assert(0,Length(list1)=0); - Assert(0,Length(list2)=2); + list1:=AllSimplicialSurfacesOfDigraph(dig,false); + list2:=AllSimplicialSurfacesOfDigraph(dig,true); + Assert(0,Length(list1)=2); + Assert(0,Length(list2)=0); #One of the smallest face graph with more than one vertex-faithful surface dig:=DigraphByEdges([ [ 1, 9 ], [ 9, 1 ], [ 1, 13 ], [ 13, 1 ], [ 1, 14 ], [ 14, 1 ], [ 2, 6 ], [ 6, 2 ], [ 2, 7 ], [ 7, 2 ], [ 2, 10 ], diff --git a/unit_tests/test_main.g b/unit_tests/test_main.g index c755132b..6744607b 100644 --- a/unit_tests/test_main.g +++ b/unit_tests/test_main.g @@ -61,9 +61,9 @@ BindGlobal( "SIMPLICIAL_TestAll", function() __SIMPLICIAL_Test_EdgeNautyGraph(); __SIMPLICIAL_Test_FaceDigraphsGraph(); __SIMPLICIAL_Test_FaceNautyGraph(); - #if IsPackageMarkedForLoading( "Digraphs", ">=1.9.0" ) then - # __SIMPLICIAL_Test_AllSimplicialSurfacesOfDigraph(); - #fi; + if IsPackageMarkedForLoading( "Digraphs", ">=1.9.0" ) then + __SIMPLICIAL_Test_AllSimplicialSurfacesOfDigraph(); + fi; __SIMPLICIAL_Test_FaceTwoColouring(); From 3a026aff7ed0ca93821809644d408e8dfbbb7007 Mon Sep 17 00:00:00 2001 From: Lukas Schnelle Date: Thu, 12 Sep 2024 08:50:10 +0200 Subject: [PATCH 42/44] remove old code from manual generation --- makedoc.g | 470 +----------------------------------------------------- 1 file changed, 2 insertions(+), 468 deletions(-) diff --git a/makedoc.g b/makedoc.g index f28e054a..0ffcdf1f 100644 --- a/makedoc.g +++ b/makedoc.g @@ -8,491 +8,25 @@ if fail = LoadPackage("GAPDoc", "1.6") then QUIT_GAP(1); fi; - -# We generate the names automatically by a hash-function. Therefore we -# have to clean up old files periodically. To know which files have -# become obsolete, we save the current files in this global list. -BindGlobal("__SIMPLICIAL_ImageNames",[]); -MakeReadWriteGlobal("__SIMPLICIAL_ImageNames"); - -# We specify the documentation directory directly since we want to use it -# in our preprocessing method. -BindGlobal("__SIMPLICIAL_DocDirectory", "doc/"); - - -# The additional LaTeX-header to make tikz-pictures -# Careful: The file TikZHeader.tex has to lie in the same directory as -# the primary documentation file and the generated image files. -BindGlobal("__SIMPLICIAL_TikZHeader", "\\input{TikZHeader.tex}\n\n" ); - # We load the package since we need it for some computations in the manual if fail = LoadPackage("SimplicialSurfaces") then Error("SimplicialSurfaces package has to be available."); fi; -Exec( "pwd > _TMP_foo"); -manualposition := StringFile("_TMP_foo"); -Exec("rm _TMP_foo"); -RemoveCharacters(manualposition, "\n"); -manualposition := Concatenation(manualposition,"/doc/manual.pdf"); -manualposition := Concatenation("You can find the image in the manual. Most probably it is here: ", manualposition); - -# Now we have the XML-tree of the documentation -# We need to change the -Tags into proper GAPDoc tags -# For that we define a function that changes one node -preProcessTikz := function( node ) - local cont, n1, n2, n3, file, output, name, htmlString, consoleString, - path, tmpName, tmpFile, sysDirPath, md5, out, inStream, outStream, - hash, tmpImageName, latexString; - - if node.name = "Alt" and IsBound(node.attributes.Only) and - node.attributes.Only in ["TikZ","Tikz"] then - - # get the content of the tag - cont := GetTextXMLTree(node); - - - # We want to save our image in the file - # _IMAGE_.tex - # (that gives _IMAGE_-1.svg) - # - # This gives us the benefit of recognizing duplicates and - # minimizing compiling time (especially if we don't change the pictures - # between different versions of the code). - # - # At the same time this is problematic if we have \input-clauses inside - # our document since a change in the referred document should be - # reflected in a different overall image. - # - # To circumvent this issue, we proceed as follows: - # 1) Write the picture into a temporary file _IMAGE_TMP.tex - # We use a sed-command to remove all leading whitespaces - # (otherwise the same picture might be compiled twice). - # 2) Call ../flatex/flatex _IMAGE_TMP.tex - # This creates the file _IMAGE_TMP.flt - # 3) Calculate the hash of this file - # 4) Check if _IMAGE_-1.svg (and the tex-file) already exist - # If they do, do nothing. - # 5) Otherwise call mv _IMAGE_TMP.tex _IMAGE_.tex - # 6) Compile this image via htlatex _IMAGE_.tex - # 7) Store the name _IMAGE_ in our list - # 8) Include _IMAGE_-1.svg in the HTML document - - # Step 1 - path := __SIMPLICIAL_DocDirectory; - tmpImageName := "_IMAGE_TMP"; - tmpName := Concatenation( path, tmpImageName, ".tex"); - tmpFile := Filename( DirectoryCurrent(), tmpName ); - output := OutputTextFile( tmpFile, false ); - SetPrintFormattingStatus( output, false ); - AppendTo( output, - "\\nonstopmode\n", - "\\documentclass{standalone}\n\n", - __SIMPLICIAL_TikZHeader, - "\\def\\pgfsysdriver{pgfsys-tex4ht.def}\n\n", - "\\begin{document}\n"); - AppendTo( output, cont ); - AppendTo( output, "\\end{document}" ); - CloseStream(output); - - # Now we remove the leading whitespace - Exec( "sh -c \" cd ", path, - "; sed 's/^[ \\t]*//g' -i ", - Concatenation(tmpImageName, ".tex"), "; \"" ); - - # Step 2 - # TODO separate the calls to these shell-files into a function and call - # that. Furthermore, add into the README a short test if a user has all - # necessary capabilities (and maybe an installation for them) - Exec( "sh -c \" cd ", path, "; ../flatex/flatex ", - Concatenation(tmpImageName, ".tex"), "> /dev/null; \"" ); - - # Step 3 - sysDirPath := DirectoriesSystemPrograms(); - md5 := Filename( sysDirPath, "md5sum" ); - if md5 = fail then - Error("There is no md5sum installed."); - fi; - - inStream := InputTextNone(); - out := ""; - outStream := OutputTextString(out, true); - Process( Directory(path), md5, inStream, outStream, [ Concatenation(tmpImageName, ".flt") ] ); - CloseStream(inStream); - CloseStream(outStream); - hash := SplitString( out, " " )[1]; - - # Step 4 - name := Concatenation( "_IMAGE_", hash ); - if not IsExistingFile( - Filename( DirectoryCurrent(), - Concatenation( path, name, ".tex" ) ) ) or - not IsExistingFile( - Filename( DirectoryCurrent(), - Concatenation( path, name, "-1.svg" )) ) or - not IsExistingFile( - Filename( DirectoryCurrent(), - Concatenation( path, name, ".pdf" )) ) then - # Either tex or svg or pdf are not there. We will write them now. - - # Step 5 - Exec( "sh -c \" cd ", path, "; mv _IMAGE_TMP.tex ", Concatenation(name, ".tex"), "; \" " ); - - # Step 6 - Exec( "sh -c \" cd ", path, "; pdflatex -halt-on-error ", Concatenation(name, ".tex"), "; \" " ); - Exec( "sh -c \" cd ", path, "; htlatex ", Concatenation(name, ".tex"), "; \" " ); - - # After compiling we do some post-processing on the image. - # We will modify - # - subscripts, since baseline-shift is not supported in Firefox - # (see https://stackoverflow.com/questions/12332448/subscripts-and-superscripts-in-svg) - # As this bug was recognized 16 years ago it is unlikely to - # change in the near future. We therefore apply the suggested - # fix in the stackoverflow-answer. - # WARNING: I am just messing around on the assumption that all - # subscripts have the same height. If that turns out to be - # wrong, you have to think of a more sophisticated mechanism. - Exec( "sh -c \" cd ", path, - "; sed 's/baseline-shift=\\\"sub\\\"/dy=\\\"3\\\"/g' -i ", - Concatenation(name, "-1.svg"), ";\" "); - # I do not really understand why there has to be so much - # escaping but it does not work with less. - fi; - - # Step 7 - Add( __SIMPLICIAL_ImageNames, name); - - # Step 8 will be done in the htmlString below - - - # Inclusion in the LaTeX-version is centered - latexString := Concatenation( "\n\\begin{center}\n", - "\\includegraphics{", name, ".pdf}\n\\end{center}\n" ); - n1 := ParseTreeXMLString(latexString); - n1.name := "Alt"; - n1.attributes.Only := "LaTeX"; - - # To include it in the HTML-version we have to use a different node - htmlString := Concatenation( - "

]]>
"); - n2 := ParseTreeXMLString(htmlString); - n2.name := "Alt"; - n2.attributes.Only := "HTML"; - - - # Generate the text version - consoleString := "\n[an image that is not shown in text version. "; - consoleString := Concatenation( consoleString, manualposition); - consoleString := Concatenation( consoleString, "]\n"); - n3 := ParseTreeXMLString(consoleString); - n3.name := "Alt"; - n3.attributes.Only := "Text"; - - - # Replace this node by the new nodes - node.content := [n1,n2,n3]; - node.attributes.Only := "HTML,LaTeX,Text"; - fi; -end; - - - -# Now we have the XML-tree of the documentation -# We need to change the -Tags into proper GAPDoc tags -# For that we define a function that changes one node -preProcessJavaScript := function( node ) - local cont, name, path, n1, n2, n3, consoleString, htmlString, latexString, tmpImageName, tmpName; - - if node.name = "Alt" and IsBound(node.attributes.Only) and - node.attributes.Only in ["JavaScript","Javascript"] then - - # get the content of the tag (we need to remove whitespaces) - cont := GetTextXMLTree(node); - cont := ReplacedString( cont, " ", "" ); - cont := ReplacedString( cont, "\n", "" ); - cont := ReplacedString( cont, ".html", "" ); - path := __SIMPLICIAL_DocDirectory; - tmpImageName := "_IMAGE_TMP"; - tmpName := Concatenation( path, tmpImageName, ".tex"); - PrintTo("doc/Test.js", "var page = require('webpage').create();\n"); - AppendTo( "doc/Test.js", "page.viewportSize = { width: 1920, height: 1080 };\n"); - AppendTo( "doc/Test.js", "page.clipRect = { top: 400, left: 750, width: 375, height: 300 };\n"); - AppendTo( "doc/Test.js", Concatenation("page.open('doc/", cont, ".html', function() {\n") ); - AppendTo( "doc/Test.js", Concatenation("page.render('doc/", cont, ".png');\n") ); - AppendTo( "doc/Test.js", "phantom.exit();\n" ); - AppendTo( "doc/Test.js", "});" ); - Exec("./doc/phantomjs /doc/Test.js"); - name := cont; - - - - Add( __SIMPLICIAL_ImageNames, name); - - - - - # Inclusion in the LaTeX-version is centered - latexString := Concatenation( "\n\\begin{center}\n", "\\includegraphics{", name, ".png}\n\\end{center}\n" ); - n1 := ParseTreeXMLString(latexString); - n1.name := "Alt"; - n1.attributes.Only := "LaTeX"; - - # To include it in the HTML-version we have to use a different node - htmlString := Concatenation( - "

]]>
"); - n2 := ParseTreeXMLString(htmlString); - n2.name := "Alt"; - n2.attributes.Only := "HTML"; - - - # Generate the text version - consoleString := "\n[an image that is not shown in text version]\n"; - n3 := ParseTreeXMLString(consoleString); - n3.name := "Alt"; - n3.attributes.Only := "Text"; - - - # Replace this node by the new nodes - node.content := [n1,n2,n3]; - node.attributes.Only := "HTML,LaTeX,Text"; - - fi; -end; - - - -BindGlobal( "CleanImageDirectory", function( ) - local allFiles, file; - - # First we remove the temporary files - Exec( "sh -c \" cd ", __SIMPLICIAL_DocDirectory, "; rm -f _IMAGE_TMP*;\"" ); - - # Secondly we remove all old image files - allFiles := DirectoryContents( __SIMPLICIAL_DocDirectory ); - for file in allFiles do - # We only do something with temporary image files - if StartsWith( file, "_IMAGE_" ) then - if ForAny( __SIMPLICIAL_ImageNames, n -> StartsWith(file,n) ) then - # This is a file to an existing picture - if not ForAny( [".tex", ".svg", ".pdf"], e -> EndsWith(file,e) ) then - # Does not end in one of those file extensions - Exec( "sh -c \" cd ", __SIMPLICIAL_DocDirectory, "; rm -f ", file, ";\"" ); - fi; - else - # This is an old file that can be removed - Exec( "sh -c \" cd ", __SIMPLICIAL_DocDirectory, "; rm -f ", file, ";\"" ); - fi; - fi; - od; -end -); - -# We now want to put this preprocessing within the MakeGAPDocDoc-function. -# To do so we have to redefine the original global variable and add our -# method into the code. All code that is not commented with MB is original -# GAPDoc-code. - -MakeReadWriteGlobal("MakeGAPDocDoc"); -UnbindGlobal("MakeGAPDocDoc"); # MB unbind this to modify it -BindGlobal("MakeGAPDocDoc", function(path, main, files, bookname, opts...) - local special, gaproot, str, r, t, l, latex, null, log, pos, h, i, j; - special := Filtered(opts, a-> a in ["MathML", "Tth", "MathJax", "nopdf"]); - if Length(special) > 0 then - opts := Filtered(opts, a-> not a in ["MathML", "Tth", "MathJax", "nopdf"]); - fi; - if IsBound(opts[1]) then - gaproot := opts[1]; - else - gaproot := false; - fi; - # ensure that path is directory object - if IsString(path) then - path := Directory(path); - fi; - # ensure that .xml is stripped from name of main file - if Length(main)>3 and main{[Length(main)-3..Length(main)]} = ".xml" then - main := main{[1..Length(main)-4]}; - fi; - # compose the XML document - Info(InfoGAPDoc, 1, "#I Composing XML document . . .\n"); - str := ComposedDocument("GAPDoc", path, - Concatenation(main, ".xml"), files, true); - # parse the XML document - Info(InfoGAPDoc, 1, "#I Parsing XML document . . .\n"); - r := ParseTreeXMLString(str[1], str[2]); - - #MB precompile the images - Exec( "sh -c \" cd ", __SIMPLICIAL_DocDirectory, "; rm -f _TIKZ_*;\"" ); - __SIMPLICIAL_MANUAL_MODE := true; - Read("gap/PolygonalComplexes/drawing.gd"); - Read("gap/Library/library_images.gd"); - Read("gap/PolygonalComplexes/distances_images.gd"); - Read("gap/PolygonalComplexes/animating_images.gd"); - Read("gap/ColouredComplexes/edgeColouring_images.gd"); - Read("gap/ColouredComplexes/variColouring_images.gd"); - Read("gap/ColouredComplexes/isoscelesColouring_images.gd"); - Read("gap/Flags/flags_images.gd"); - __SIMPLICIAL_MANUAL_MODE := false; - # Fortunately there already is a method to apply this function to all nodes of the tree - ApplyToNodesParseTree( r, preProcessTikz ); - ApplyToNodesParseTree( r, preProcessJavaScript ); - - CleanImageDirectory(); - - # clean the result - Info(InfoGAPDoc, 1, "#I Checking XML structure . . .\n"); - CheckAndCleanGapDocTree(r); - # produce text version - Info(InfoGAPDoc, 1, - "#I Text version (also produces labels for hyperlinks):\n"); - t := GAPDoc2Text(r, path); - GAPDoc2TextPrintTextFiles(t, path); - # produce LaTeX version - Info(InfoGAPDoc, 1, "#I Constructing LaTeX version and calling pdflatex:\n"); - r.bibpath := path; - l := GAPDoc2LaTeX(r); - Info(InfoGAPDoc, 1, "#I Writing LaTeX file, \c"); - Info(InfoGAPDoc, 2, Concatenation(main, ".tex"), "\n#I "); - FileString(Filename(path, Concatenation(main, ".tex")), l); - if "nopdf" in special then - Info(InfoGAPDoc, 1, " NO PDF generated!\n"); - PrintSixFile(Filename(path, "manual.six"), r, bookname); - else - if Filename(DirectoriesSystemPrograms(), "pdflatex") = fail then - Info(InfoGAPDoc, 1, "\n#W WARNING: cannot find 'pdflatex', please install TeX.\n"); - Info(InfoGAPDoc, 1, "#W WARNING: will NOT produce pdf version from LaTeX file.\n"); - else - # call latex and pdflatex (with bibtex, makeindex and dvips) - latex := "latex -interaction=nonstopmode "; - # sh-syntax for redirecting stderr and stdout to /dev/null - null := " > /dev/null 2>&1 "; - Info(InfoGAPDoc, 1, "4 x pdflatex with bibtex and makeindex, \c"); - Exec(Concatenation("sh -c \" cd ", Filename(path,""), - "; rm -f ", main, ".aux ", main, ".pdf ", main, ".log ", - "; pdf", latex, main, null, - "; bibtex ", main, null, - "; pdf", latex, main, null, - "; makeindex ", main, null, - "; pdf", latex, main, null, - "; pdf", latex, main, null,"\"")); - # check log file for errors, warning, overfull boxes - log := Filename(path, Concatenation(main, ".log")); - log := StringFile(log); - if log = fail then - Info(InfoGAPDoc, 1, "\n#W WARNING: Something wrong, don't find log file ", - Filename(path, Concatenation(main, ".log")), "\n"); - else - log := SplitString(log, "\n", ""); - pos := Filtered([1..Length(log)], i-> Length(log[i]) > 0 - and log[i][1] = '!'); - if Length(pos) > 0 then - Info(InfoGAPDoc, 1, "\n#W There were LaTeX errors:\n"); - for i in pos do - for j in [i..Minimum(i+2, Length(log))] do - Info(InfoGAPDoc, 1, log[j], "\n"); - od; - Info(InfoGAPDoc, 1, "____________________\n"); - od; - fi; - pos := Filtered([1..Length(log)], i-> Length(log[i]) > 13 - and log[i]{[1..14]} = "LaTeX Warning:"); - if Length(pos) > 0 then - Info(InfoGAPDoc, 1, "\n#W There were LaTeX Warnings:\n"); - for i in pos do - for j in [i..Minimum(i+2, Length(log))] do - Info(InfoGAPDoc, 1, log[j], "\n"); - od; - Info(InfoGAPDoc, 1, "____________________\n"); - od; - fi; - pos := Filtered([1..Length(log)], i-> Length(log[i]) > 7 - and log[i]{[1..8]} = "Overfull"); - if Length(pos) > 0 then - Info(InfoGAPDoc, 1, "\n#W There are overfull boxes:\n"); - for i in pos do - Info(InfoGAPDoc, 1, log[i], "\n"); - od; - fi; - fi; - # check for BibTeX warnings - log := StringFile(Filename(path, Concatenation(main, ".blg"))); - if log <> fail then - log := SplitString(log, "\n", ""); - log := Filtered(log, z-> PositionSublist(z, "Warning--") = 1); - if Length(log) > 0 then - Info(InfoGAPDoc, 1, "\n#W BibTeX had warnings:\n", - JoinStringsWithSeparator(log, "\n")); - fi; - fi; - - if not IsExistingFile(Filename(path, Concatenation(main, ".pdf"))) then - Info(InfoGAPDoc, 1, "\n#I ERROR: no .pdf file produced (writing incomplete .six file)\n"); - PrintSixFile(Filename(path, "manual.six"), r, bookname); - else - Exec(Concatenation("sh -c \" cd ", Filename(path,""), - "; mv ", main, ".pdf manual.pdf; ", - "\"")); - Info(InfoGAPDoc, 1, "\n"); - # read page number information for .six file - Info(InfoGAPDoc, 1, "#I Writing manual.six file ... \c"); - Info(InfoGAPDoc, 2, Filename(path, "manual.six"), "\n"); - Info(InfoGAPDoc, 1, "\n"); - AddPageNumbersToSix(r, Filename(path, Concatenation(main, ".pnr"))); - # print manual.six file - PrintSixFile(Filename(path, "manual.six"), r, bookname); - fi; - fi; - fi; - # produce html version - Info(InfoGAPDoc, 1, "#I Finally the HTML version . . .\n"); - # if MathJax version is also produced we include links to them - if "MathJax" in special then - r.LinkToMathJax := true; - fi; - h := GAPDoc2HTML(r, path, gaproot); - GAPDoc2HTMLPrintHTMLFiles(h, path); - Unbind(r.LinkToMathJax); - if "Tth" in special then - Info(InfoGAPDoc, 1, - "#I - also HTML version with 'tth' translated formulae . . .\n"); - h := GAPDoc2HTML(r, path, gaproot, "Tth"); - GAPDoc2HTMLPrintHTMLFiles(h, path); - fi; - if "MathML" in special then - Info(InfoGAPDoc, 1, "#I - also HTML + MathML version with 'ttm' . . .\n"); - h := GAPDoc2HTML(r, path, gaproot, "MathML"); - GAPDoc2HTMLPrintHTMLFiles(h, path); - fi; - if "MathJax" in special then - Info(InfoGAPDoc, 1, "#I - also HTML version for MathJax . . .\n"); - h := GAPDoc2HTML(r, path, gaproot, "MathJax"); - GAPDoc2HTMLPrintHTMLFiles(h, path); - fi; - - return r; -end); - # Create binary and index files for the library __SIMPLICIAL_LibraryConstructBinary(); __SIMPLICIAL_LibraryConstructIndex(); -# After all this preparatory work we can finally call the function to create -# the documentation - AutoDoc( rec( scaffold := rec( MainPage := false), - dir := __SIMPLICIAL_DocDirectory, + dir := "doc/", extract_examples := true, autodoc := rec( files := [ ], scan_dirs := ["doc", "gap", "gap/PolygonalComplexes", "gap/Paths", "gap/Library", "gap/ColouredComplexes", "gap/Flags", "gap/Morphisms"]), gapdoc := rec( files := ["doc/PolygonalStructuresDefinitions.xml", "doc/ExampleImplementations.xml"], - LaTeXOptions := rec( LateExtraPreamble := __SIMPLICIAL_TikZHeader ) + LaTeXOptions := rec( LateExtraPreamble := "\\input{TikZHeader.tex}\n\n" ) )) ); From e3c1efeb68bbb3f2bd18a1c914b6ec3985f0a8fb Mon Sep 17 00:00:00 2001 From: alice Date: Thu, 12 Sep 2024 11:27:21 +0200 Subject: [PATCH 43/44] Bug fix in __SIMPLICIAL_ComputeNewVertexEdgePaths --- gap/PolygonalComplexes/modification.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gap/PolygonalComplexes/modification.gi b/gap/PolygonalComplexes/modification.gi index 132b5f1e..545862e7 100755 --- a/gap/PolygonalComplexes/modification.gi +++ b/gap/PolygonalComplexes/modification.gi @@ -309,7 +309,7 @@ BindGlobal( "__SIMPLICIAL_ComputeNewVertexEdgePaths", Add(extOld, PathAsList(vePath)[i]); Add(newPaths, [ extNew, extOld ]); - + new := new + 1; used:=true; fi; od; From b18e577b674576036e868392fad539ab0344ef37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Meike=20Wei=C3=9F?= Date: Thu, 12 Sep 2024 11:29:44 +0200 Subject: [PATCH 44/44] bugfix --- gap/Paths/paths.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gap/Paths/paths.gi b/gap/Paths/paths.gi index 21cf374b..9f3aec5c 100644 --- a/gap/Paths/paths.gi +++ b/gap/Paths/paths.gi @@ -647,7 +647,7 @@ InstallMethod( EdgeFacePathByFaces, local i; __SIMPLICIAL_CheckEdge(complex, firstEdge, "EdgeFacePathByFaces"); - __SIMPLICIAL_CheckFace(complex, lastEdge, "EdgeFacePathByFaces"); + __SIMPLICIAL_CheckEdge(complex, lastEdge, "EdgeFacePathByFaces"); if Length(faceList) > 0 then __SIMPLICIAL_CheckFace(complex, faceList[1], "EdgeFacePathByFaces"); for i in [2..Length(faceList)] do