From 50709a8d4c8cdd40b51023d8b81a37ba33f4d74d Mon Sep 17 00:00:00 2001 From: Mark Toner Date: Thu, 3 Apr 2025 14:41:08 +0100 Subject: [PATCH 01/13] Added files --- gap/crossing-number.gd | 0 gap/crossing-number.gi | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 gap/crossing-number.gd create mode 100644 gap/crossing-number.gi diff --git a/gap/crossing-number.gd b/gap/crossing-number.gd new file mode 100644 index 000000000..e69de29bb diff --git a/gap/crossing-number.gi b/gap/crossing-number.gi new file mode 100644 index 000000000..e69de29bb From ca37fb001586a34da8b83fa96f5796f254a96291 Mon Sep 17 00:00:00 2001 From: Mark Toner Date: Thu, 3 Apr 2025 14:48:42 +0100 Subject: [PATCH 02/13] added created files --- doc/crossingnumber.xml | 245 ++++++++++ doc/z-chapter91.xml | 14 + gap/crossing-number.gd | 34 ++ gap/crossing-number.gi | 828 ++++++++++++++++++++++++++++++++ tst/standard/crossingnumber.tst | 424 ++++++++++++++++ 5 files changed, 1545 insertions(+) create mode 100644 doc/crossingnumber.xml create mode 100644 doc/z-chapter91.xml create mode 100644 tst/standard/crossingnumber.tst diff --git a/doc/crossingnumber.xml b/doc/crossingnumber.xml new file mode 100644 index 000000000..23e0392cb --- /dev/null +++ b/doc/crossingnumber.xml @@ -0,0 +1,245 @@ +<#GAPDoc Label="DigraphCrossingNumberUpperBound"> + + + A non-negative integer. + + If digraph is a digraph, then DigraphCrossingNumberUpperBound(digraph) + returns the best known upper bound for the crossing number of digraph +

+ + If digraph is planar it will return 0, if the digraph contains multiple parallel edges there + could be a lack of applicable theorems and the upper bound could become infinite. If the crossing + for digraph can be calculated this method will return that value. + + D := CompleteDigraph(5);; +gap> DigraphCrossingNumberUpperBound(D); +4 +gap> D := Digraph([[1, 2, 4, 4], [1, 3, 4], [2, 1], [1, 2]]); + +gap> DigraphCrossingNumberUpperBound(D); +0 +gap> D := CompleteBipartiteDigraph(5,4);; +gap> DigraphCrossingNumberUpperBound(D); +32]]> + + +<#/GAPDoc> + +<#GAPDoc Label="DigraphCrossingNumberLowerBound"> + + + A non-negative integer. + + If digraph is a digraph, then DigraphCrossingNumberLowerBound(digraph) + returns the best known lower bound for the crossing number of digraph +

+ + If digraph is planar it will return 0. If the crossing + for digraph can be calculated this method will return that value. + + D := CompleteDigraph(6);; +gap> DigraphCrossingNumberLowerBound(D); +12 +gap> D := Digraph([[1, 2, 4, 4, 5], [1, 3, 4, 5], [2, 1, 5], [1, 2, 4, 5], [1,2]]); + +gap> DigraphCrossingNumberLowerBound(D); +0 +gap> D := CompleteBipartiteDigraph([5,4,5,6]);; +gap> DigraphCrossingNumberLowerBound(D); +2282]]> + + +<#/GAPDoc> + +<#GAPDoc Label="DigraphAddVertexCrossingPoint"> + + + A digraph + + If digraph is a digraph and edge1,edge2 are edges in the + digraph, then adds a new vertex to digraph between edge1 + and edge2. Changes the edges of digraph by removing both + edge1 and edge2 and adding an edge from edge1[1] + to the new vertex and from the new vertex to edge1[2], + likewise for edge[2] for four new edges total. Returns the + updated digraph if successful. Fails if edge1 = edge2, + if any of the edges are loops, or if the edges are not present in the + digraph. + D := CycleDigraph(4);; +gap> DigraphAddVertexCrossingPoint(D,[1,2],[2,3]); + +gap> D := CompleteDigraph(4);; +gap> DigraphAddVertexCrossingPoint(D,[3,5],[4,3]); + +]]> + + +<#/GAPDoc> + +<#GAPDoc Label="IsCubicDigraph"> + + + true or false. + + A cubic digraph is a digraph where each vertex has degree three. + Returns true if digraph is a cubic digraph and false if + it is not. Will always return false if digraph has loops or + is a multidigraph. + D := RandomTournament(4); + +gap> IsCubicDigraph(D); +true +gap> D := Digraph([[2,4], [3, 6], [4,5], [],[1],[4,5]]); + +gap> IsCubicDigraph(D); +true +gap> D := CycleDigraph(7); + +gap> IsCubicDigraph(D); +false +gap> D := Digraph([[1,1,1]]); + +gap> IsCubicDigraph(D); +false +gap> D := CompleteMultipartiteDigraph([2,3,4,1]); + +gap> IsCubicDigraph(D); +false]]> + + +<#/GAPDoc> + +<#GAPDoc Label="IsSemicompleteDigraph"> + + + true or false. + + A semicomplete digraph is a digraph with at least on edge between + every pair of vertices. Returns true if digrah is semicomplete + and false if it is not. Will always return false if + digraph has loops or is a multidigraph. Returns true if + digraph is a tournament or complete digraph. + D := RandomTournament(4); + +gap> IsSemiComplete(D); +true +gap> D := Digraph([[2,4], [3, 6], [4,5], [],[1],[4,5]]); + +gap> IsSemicompleteDigraph(D); +false +gap> D := CompleteDigraph(7); + +gap> IsCubicDigraph(D); +true +gap> D := Digraph([[1,1,1]]); + +gap> IsSemicompleteDigraph(D); +false +gap> D := CompleteMultipartiteDigraph([2,3,4,1]); + +gap> IsCubicDigraph(D); +false]]> + + +<#/GAPDoc> + +<#GAPDoc Label="DigraphAllThreeCycles"> + + + A list of lists of three positive integers + + Returns all possible three cycles in the digraph digraph.

+ + A three cycle of a digraph is a directed cycle of length 3. + + The returned list is sorted in increasing order of first vertex. + Looping and repeated edges are not considered for creating possible + three cycles. + D := CompleteDigraph(4);; +gap> DigraphAllThreeCircuits(D); +[ [ 1, 2, 3 ], [ 1, 2, 4 ], [ 1, 3, 2 ], [ 1, 3, 4 ], [ 1, 4, 2 ], + [ 1, 4, 3 ], [ 2, 3, 4 ], [ 2, 4, 3 ] ] +gap> D := Digraph([[2],[3],[1]]);; +gap> DigraphAllThreeCircuits(D); +[ [ 1, 2, 3 ] ] +gap> D := Digraph([[2,4,5],[1,3],[1,5],[5],[1,4]]);; +gap> DigraphAllThreeCircuits(D); +[ [ 1, 2, 3 ], [ 1, 4, 5 ] ] +gap> D := CompleteDigraph(3);; +gap> DigraphAllThreeCircuits(D); +[ [ 1, 2, 3 ], [ 1, 3, 2 ] ] +gap> D := DigraphAddAllLoops(D);; +gap> DigraphAllThreeCircuits(D); +[ [ 1, 2, 3 ], [ 1, 3, 2 ] ] +]]> + + +<#/GAPDoc> + + +<#GAPDoc Label="DigraphAllTriangles"> + + + A list of lists of three positive integers + + Returns all possible triangles in the digraph digraph.

+ + A triangles of a digraph is an undirected cycle of length 3. + + The returned list is sorted in lexicographic order on vertices. + Looping and repeated edges are not considered for creating possible + triangless. + D := CompleteDigraph(4);; +gap> DigraphAllTriangles(D); +[ [ 1, 2, 3 ], [ 1, 2, 4 ], [ 1, 3, 4 ], [ 2, 3, 4 ] ] +gap> D := Digraph([[2],[3],[1]]);; +gap> DigraphAllTriangles(D); +[ [ 1, 2, 3 ] ] +gap> D := Digraph([[2,4,5],[1,3],[1,5],[5],[4]]);; +gap> DigraphAllTriangles(D); +[ [ 1, 2, 3 ], [ 1, 3, 5 ], [ 1, 4, 5 ] ] +gap> D := CompleteDigraph(3);; +gap> D := DigraphAddAllLoops(D);; +gap> DigraphAllTriangles(D); +[ [ 1, 2, 3 ] ] +]]> + + +<#/GAPDoc> + +<#GAPDoc Label="DigraphLargePlanarSubdigraph"> + + + A digraph. + + An implementation of Algorithm A described by Calinescu et al. + which finds a large planar subgraph of a non-planar graph. + + +<#/GAPDoc> + +<#GAPDoc Label="CompleteMultipartiteDigraphPartitionSize"> + + + A list of positive integers. + + Returns a list of the sizes of the partitions of a complete multipartite + digraph digraph, the partitions are sorted in increasing order. +

+ D := CompleteBipartiteDigraph(3,4);; +gap> CompleteMultipartiteDigraphPartitionSize(D); +[ 3, 4 ] +gap> D:=CompleteMultipartiteDigraph([1,5,3]); +gap> CompleteMultipartiteDigraphPartitionSize(D); +[ [ 1, 2, 3 ] ]]]> + + +<#/GAPDoc> diff --git a/doc/z-chapter91.xml b/doc/z-chapter91.xml new file mode 100644 index 000000000..4f1e27ed4 --- /dev/null +++ b/doc/z-chapter91.xml @@ -0,0 +1,14 @@ +Crossing Numbers + + + diff --git a/gap/crossing-number.gd b/gap/crossing-number.gd index e69de29bb..fe63053df 100644 --- a/gap/crossing-number.gd +++ b/gap/crossing-number.gd @@ -0,0 +1,34 @@ +# Properties +DeclareProperty("IsSemicompleteDigraph",IsDigraph); +DeclareProperty("IsCubicDigraph",IsDigraph); + +# Operations +DeclareOperation("DigraphAddVertexCrossingPoint",[IsDigraph,IsList,IsList]); + +# Global Functions +DeclareGlobalFunction("DigraphCrossingNumberUpperBound"); +DeclareGlobalFunction("DigraphCrossingNumberLowerBound"); +DeclareGlobalFunction("DIGRAPHS_CrossingNumberInequality"); +DeclareGlobalFunction("DIGRAPHS_GetCompleteDigraphCrossingNumber"); +DeclareGlobalFunction("DIGRAPHS_CrossingNumberAlbertson"); +DeclareGlobalFunction("DIGRAPHS_CrossingNumberRound"); +DeclareGlobalFunction("DIGRAPHS_IsK22FreeDigraph"); +DeclareGlobalFunction("DIGRAPHS_ZarankiewiczTheorem"); +DeclareGlobalFunction("DIGRAPHS_CompleteTripartiteDigraphCrossingNumber"); +DeclareGlobalFunction("DIGRAPHS_Complete6partiteDigraphCrossingNumber"); +DeclareGlobalFunction("DIGRAPHS_Complete5partiteDigraphCrossingNumber"); +DeclareGlobalFunction("DIGRAPHS_Complete4partiteDigraphCrossingNumber"); +DeclareGlobalFunction("DIGRAPHS_IsomorphicToCirculantGraphCrossingNumber"); + + +# Attributes +DeclareAttribute("DIGRAPHS_CompleteDigraphCrossingNumber", IsCompleteDigraph); +DeclareAttribute("DIGRAPHS_TournamentCrossingNumber", IsTournament); +DeclareAttribute("DigraphCrossingNumber",IsDigraph); +DeclareAttribute("SemicompleteDigraphCrossingNumber",IsSemicompleteDigraph); +DeclareAttribute("DigraphAllThreeCycles", IsDigraph); +DeclareAttribute("DigraphAllTriangles", IsDigraph); +DeclareAttribute("DigraphLargePlanarSubdigraph", IsDigraph); +DeclareAttribute("DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber", IsCompleteMultipartiteDigraph); +DeclareAttribute("DIGRAPHS_CompleteBipartiteDigraphCrossingNumber",IsCompleteBipartiteDigraph); +DeclareAttribute("CompleteMultipartiteDigraphPartitionSize",IsCompleteMultipartiteDigraph); \ No newline at end of file diff --git a/gap/crossing-number.gi b/gap/crossing-number.gi index e69de29bb..70a7c6428 100644 --- a/gap/crossing-number.gi +++ b/gap/crossing-number.gi @@ -0,0 +1,828 @@ +# Crossing Number of a tournament +InstallMethod(DIGRAPHS_TournamentCrossingNumber, "for a tournament", [IsTournament], + function(D) + local KnownCrossingNumberArray, n; + if not IsTournament(D) then + ErrorNoReturn("argument must be a tournament"); + fi; + # Array of known crossing numbers for tournaments (complete graphs) from 0 - 14 vertices + KnownCrossingNumberArray := [0, 0, 0, 0, 0, 1, 3, 9, 18, 36, 60, 100, 150, 225, 315]; + n := DigraphNrVertices(D); + if n < 15 then + SetDigraphCrossingNumber(D,KnownCrossingNumberArray[n+1]); + return KnownCrossingNumberArray[n+1]; + elif n >= 15 then + return -1; + fi; +end); + + +# Crossing Number Inequality +InstallGlobalFunction(DIGRAPHS_CrossingNumberInequality, + function(D) + local res, n, e, completeBound, tournamentBound, digraph, nrLoops, temp; + # If digraph has loops remove them first + e := DigraphNrEdges(D); + nrLoops := DigraphNrLoops(D); + if nrLoops > 0 then + e := e - DigraphNrLoops(D); + fi; + + # If digraph is Planar crossing number is 0 + if IsPlanarDigraph(D) then + SetDigraphCrossingNumber(D,0); + return 0; + fi; + + n := DigraphNrVertices(D); + res := -1; + + if DIGRAPHS_IsK22FreeDigraph(D) and (e >= 1000*n) then + temp := 1/(10^8) * (Float(e))^4 / (Float(n)^3); + if temp > res then + res := temp; + fi; + fi; + # If digraph has e >= 6.95n use one equation + if Float(e) >= 6.95 * Float(n) then + temp := (Float(e)^3) / (29* (n^2)); + # Deal with division errors + temp := DIGRAPHS_CrossingNumberRound(temp); + if temp > res then + res := temp; + fi; + # Otherwise we use a different one + else + temp := ((Float(e^3)) / (29*(Float(n)^2))) - (35/29)*Float(n); + temp := DIGRAPHS_CrossingNumberRound(temp); + if temp > res then + res := temp; + fi; + fi; + return res; +end); + +# Private Helper function to deal with division errors in the CNI +InstallGlobalFunction(DIGRAPHS_CrossingNumberRound, + function(val) + local tolerance; + tolerance := 0.0001; + if val - Trunc(val) < 0.0001 then + return Int(Trunc(val)); + else + return Int(Ceil(val)); + fi; +end); + + +# Get the known crossing number for a comple digraph on n vertices +InstallGlobalFunction(DIGRAPHS_GetCompleteDigraphCrossingNumber, + function(n) + local KnownCrossingNumberArray; + if n > 15 then + ErrorNoReturn("Crossing number unknown for digraph on this number of vertices"); + fi; + KnownCrossingNumberArray := [0, 0, 0, 0, 0, 4, 12, 36, 72, 144, 240, 400, 600, 900, 1260]; + # +1 due to first array index being 1 representing n=0 + return KnownCrossingNumberArray[n+1]; +end); + +# Crossing number for a complete digraph +InstallMethod(DIGRAPHS_CompleteDigraphCrossingNumber, "for a complete digraph", [IsCompleteDigraph], + function(D) + local n, completeDigraphCrossingNumber; + if not IsCompleteDigraph(D) then + ErrorNoReturn("the 1st argument must be a complete digraph,"); + fi; + n := DigraphNrVertices(D); + if n < 15 then + # 1 due to list's indexing at 1 and the complete graph of 0 vertices being included + completeDigraphCrossingNumber := DIGRAPHS_GetCompleteDigraphCrossingNumber(n); + SetDigraphCrossingNumber(D,completeDigraphCrossingNumber); + return completeDigraphCrossingNumber; + elif n >= 15 then + ErrorNoReturn("Complete Digraph contains too many vertices for known crossing number"); + fi; +end); + + +# Computes if a digraph has K2,2 subgraph +InstallGlobalFunction(DIGRAPHS_IsK22FreeDigraph, + function(D) + local i,j,k,l,intersect,adjacencyMatrix,vertices,neighbours,numberVertices,jCount,lCount; + if not IsDigraph(D) then + ErrorNoReturn("the 1st argument must be a digraph,"); + fi; + numberVertices := DigraphNrVertices(D); + # If the digraph is a complete bipartite digraph with m>=2 and n>=2 then it has K2,2 as a subgraph + if IsCompleteBipartiteDigraph(D) and Length(DigraphBicomponents(D)[1]) > 1 and Length(DigraphBicomponents(D)[2]) > 1 then + return false; + # If the digraph has fewer than 4 vertices then it is is trivially K2,2 free + elif numberVertices < 4 then + return true; + # If a digraph is a complete digraph or tournament it is K2,2 free as as there are no unconnected nodes + elif IsCompleteDigraph(D) or IsTournament(D) then + return true; + fi; + # Check if for every pair of distinct unconnected vertices (x1,x2) (x1 <-!-> x2, x1!=x2) that their intersection contains two distinct unconnected vertices + # This means there is a K2,2 subgraph + # Create boolean adjacency matrix + adjacencyMatrix := BooleanAdjacencyMatrix(D); + neighbours := OutNeighbors(D); + vertices := DigraphVertices(D); + for i in vertices do + for jCount in [i+1..numberVertices] do + j := vertices[jCount]; + # If there are more than 1 vertex that both i and j connect to and i and j are not connected + intersect := Intersection(neighbours[i],neighbours[j]); + if Length(intersect) >= 2 and adjacencyMatrix[i][j] = false and adjacencyMatrix[j][i] = false then + # For every pair of vertices in the intersection + for k in intersect do + for lCount in [k+1..Length(intersect)] do + l := intersect[lCount]; + # if k and l are unconnected + if adjacencyMatrix[k][l] = false and adjacencyMatrix[l][k] = false then + return false; + fi; + od; + od; + fi; + od; + od; + return true; +end); + +# Semicomplete Digraph generator +InstallMethod(RandomDigraphCons, +"for SemicompleteDigraph, a positive integer, and a float", +[IsSemicompleteDigraph, IsPosInt, IsFloat], +function(_, n, p) + local adjacencyList, vertices, probability, i, j; + + adjacencyList := EmptyPlist(n); + + vertices := [1 .. n]; + probability := [0 .. 99]; + + for i in vertices do + Add(adjacencyList, []); + od; + + + for i in vertices do + for j in [i+1..n] do + # Decide if there should be a second vertex using some probability p + # Random number < p means it should be added + if Float(Random(probability) / 100) < p then + Add(adjacencyList[j],i); + Add(adjacencyList[i],j); + # Create only one edge between each vertex + # Decide orientation from a random number + elif Random([1..2]) < 2 then + Add(adjacencyList[i],j); + else + Add(adjacencyList[j],i); + fi; + od; + od; + return DigraphNC(adjacencyList); + +end); + +# Random cubic digraph generation +InstallMethod(RandomDigraphCons, +"for CubicDigraph and a positive integer", +[IsCubicDigraph, IsPosInt], +function(_, n) + local adjacencyList, edge1, edge2, edges, edgeList, i, D, edgeIndex, numberVertices; + if n = 0 then + return EmptyDigraph(0); + elif n < 4 then + ErrorNoReturn("Cubic Digraphs must have at least 4 vertices"); + elif n mod 2 = 1 then + ErrorNoReturn("Cubic Digraphs exist only for even vertices"); + fi; + + # Create a tournament on 4 vertices + D := RandomTournament(4); + + # For i in range from 4 to n + for i in [1 .. n-4] do + # Skip odd i as no cubic digraph can exist with odd number of vertices + if i mod 2 = 1 then + continue; + fi; + # Select two random edges + edgeList := DigraphEdges(D); + edges := [1..DigraphNrEdges(D)]; + edgeIndex := Random(edges); + edge1 := edgeList[edgeIndex]; + # Remove edge1 so edge2 != edge1 + Remove(edges,edgeIndex); + edge2 := edgeList[Random(edges)]; + + # Split the edges by adding a new vertex in between each + D := DigraphRemoveEdge(D,edge1); + D := DigraphRemoveEdge(D,edge2); + numberVertices := DigraphNrVertices(D); + D := DigraphAddVertices(D,2); + D := DigraphAddEdge(D,[edge1[1],numberVertices+1]); + D := DigraphAddEdge(D,[numberVertices+1,edge1[2]]); + D := DigraphAddEdge(D,[edge2[1],numberVertices+2]); + D := DigraphAddEdge(D,[numberVertices+2,edge2[2]]); + # Determine orientation of link between new vertices + if Random([1..2]) < 2 then + D := DigraphAddEdge(D,[numberVertices+1,numberVertices+2]); + else + D := DigraphAddEdge(D,[numberVertices+2,numberVertices+1]); + fi; + od; + + return D; +end); + +# Check if a digraph is cubic +InstallMethod(IsCubicDigraph, "for a digraph", [IsDigraph], + function(D) + # If all nodes have degree three then the digraph is cubic + local degrees; + # If the digraph has an odd number of vertices it can never be cubic + if DigraphNrVertices(D) mod 2 = 1 then + return false; + # If D is a multidigraph we are going to exclude it from being a cubic digraph + elif IsMultiDigraph(D) then + return false; + # Cubic digraphs cannot have loops + elif DigraphHasLoops(D) then + return false; + + fi; + # Need to consider edges in and out of each vertex + degrees := OutDegrees(D) + InDegrees(D); + if ForAll( degrees, x -> x = 3) then + return true; + else + return false; + fi; +end); + +# Check if a digraph is semicomplete +InstallMethod(IsSemicompleteDigraph, "for a digraph", [IsDigraph], + function(D) + local i,j,adjacencyMatrix, numberVertices, jCount, vertices; + # If a digraph is complete or a tournament it is by definition semi-complete + if IsTournament(D) or IsCompleteDigraph(D) then + return true; + fi; + # Semicomplete digraphs cannot have loops + if DigraphHasLoops(D) then + return false; + fi; + if IsMultiDigraph(D) then + return false; + fi; + # Check that for all vertices that do not have a directed edge one way between + vertices := DigraphVertices(D); + adjacencyMatrix := BooleanAdjacencyMatrix(D); + numberVertices := DigraphNrVertices(D); + for i in vertices do + for jCount in [i+1..numberVertices] do + j := vertices[jCount]; + # If no edge exists from i -> j or j -> i for all i,j then the digraph isn't semicomplete + if adjacencyMatrix[i][j] = false and adjacencyMatrix[j][i] = false then + return false; + fi; + od; + od; + return true; +end); + +# Compute the crossing number of a digraph +InstallMethod(DigraphCrossingNumber, "for a digraph", [IsDigraph], +function(D) + local n,temp; + + # If Digraph is planar return 0 + if IsPlanarDigraph(D) then + SetDigraphCrossingNumber(D,0); + return 0; + fi; + + n := DigraphNrVertices(D); + + # If Digraph is a complete graph with fewer than 15 vertices + if IsCompleteDigraph(D) and (n < 15) then + temp := DIGRAPHS_CompleteDigraphCrossingNumber(D); + SetDigraphCrossingNumber(D,temp); + return temp; + fi; + + # If Digraph is a tournament with fewer than 15 vertices + if IsTournament(D) and (n < 15) then + temp := DIGRAPHS_TournamentCrossingNumber(D); + SetDigraphCrossingNumber(D,temp); + return temp; + fi; + + # If Digraph is bipartite + if IsCompleteBipartiteDigraph(D) then + temp := DIGRAPHS_CompleteBipartiteDigraphCrossingNumber(D); + if temp <> -1 then + SetDigraphCrossingNumber(D,temp); + return temp; + fi; + fi; + + + # If Digraph is multipartite + if IsCompleteMultipartiteDigraph(D) then + temp := DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber(D); + if temp <> -1 then + SetDigraphCrossingNumber(D,temp); + return temp; + fi; + fi; + + # If its isomorphic to a circulant graph with known crossing number + temp := DIGRAPHS_IsomorphicToCirculantGraphCrossingNumber(D); + if temp <> -1 then + SetDigraphCrossingNumber(D,temp); + return temp; + fi; + + return -1; +end); + + +# Compute a lower bound for the crossing number of a digraph +InstallGlobalFunction(DigraphCrossingNumberLowerBound, +function(D) + local temp,res;# Compute a lower boud for the crossing number of a digraphgument must be a digraph,"); + fi; + + res := 0; + + # Check if there is an exact way to compute the crossing number + if DigraphCrossingNumber(D) <> -1 then + return DigraphCrossingNumber(D); + fi; + + # The Albertson conjecture + temp := DIGRAPHS_CrossingNumberAlbertson(D); + if temp <> -1 then + res := temp; + fi; + + # The Crossing Number Inequality + temp := DIGRAPHS_CrossingNumberInequality(D); + if temp <> -1 then + res := temp; + fi; + + return res; +end); + +# Compute an upper bound for the crossing number of a digraph +InstallGlobalFunction(DigraphCrossingNumberUpperBound, +function(D) + local res, temp, componentsSize, n,e; + + if not IsDigraph(D) then + ErrorNoReturn("Argument must be a digraph"); + fi; + + if IsPlanarDigraph(D) then + return 0; + fi; + + # Check if there is an exact way to compute the crossing number + res := DigraphCrossingNumber(D); + if res <> -1 then + return res; + fi; + + res := infinity; + + n := DigraphNrVertices(D); + + # Zarankiewicz's theorem for bipartite digraphs + if IsBipartiteDigraph(D) then + componentsSize := CompleteMultipartiteDigraphPartitionSize(D); + temp := DIGRAPHS_ZarankiewiczTheorem(componentsSize[1],componentsSize[2]); + if temp < res then + res := temp; + fi; + fi; + + # Guy's Theorem (Valid for all non-multi digraphs) + if not IsMultiDigraph(D) then + n := Float(n); + temp := Trunc(n/2) * Trunc((n-1)/2) * Trunc((n-2)/2) * Trunc((n-3)/2); + if temp < res then + res := temp; + fi; + else + e := DigraphNrEdges(D); + temp := e^e; + if temp < res then + res := temp; + fi; + fi; + + return res; +end); + +# Compute the upper and lower bound for the crossing number of a semicomplete digraph +InstallMethod(SemicompleteDigraphCrossingNumber, "for a semicomplete digraph", [IsSemicompleteDigraph], + function(D) + local n, crossingNumberCompleteDigraph, crossingNumberTournament, x; + + if IsPlanarDigraph(D) then + SetDigraphCrossingNumber(D,0); + return 0; + fi; + + n := DigraphNrVertices(D); + + if n < 15 then + # Get the crossing number of the tournament with the same number of vertices + crossingNumberTournament := DIGRAPHS_GetCompleteDigraphCrossingNumber(n) / 4; + # Get the crossing number of the complete graph with the same number of vertices + crossingNumberCompleteDigraph := DIGRAPHS_GetCompleteDigraphCrossingNumber(n); + else + # Get lower bound for tournament with the same number of vertices using CNI + crossingNumberTournament := DIGRAPHS_CrossingNumberInequality(RandomTournament(n)); + # Get upper bound for complete digraph with the same number of vertices using Guy's Theorem + x := Float(n); + crossingNumberCompleteDigraph := Int(Trunc(x/2) * Trunc((x-1)/2) * Trunc((x-2)/2) * Trunc((x-3)/2)); + fi; + # If the cn of tournament and complete digraph are equal crossing number is known + # The only examples I know where this is the case are for planar digraphs + if crossingNumberCompleteDigraph = crossingNumberTournament then + SetDigraphCrossingNumber(D,crossingNumberCompleteDigraph); + return crossingNumberCompleteDigraph; + elif crossingNumberCompleteDigraph < crossingNumberTournament then + # This code should never run + ErrorNoReturn("Error, lower bound higher than upper bound"); + else + return [crossingNumberTournament,crossingNumberCompleteDigraph]; + fi; + return; +end); + +# The Albertson Conjecture for lower bound of crossing numbers +InstallGlobalFunction(DIGRAPHS_CrossingNumberAlbertson, + function(D) + local chromaticNumber; + if not IsDigraph(D) then + ErrorNoReturn("the 1st argument must be a digraph,"); + fi; + chromaticNumber := ChromaticNumber(D); + # Chromatic number must be less than 16 as that is the highest complete digraph we have a known cn for + if chromaticNumber < 15 then + # +1 as complete digraph crossing numebr array starts at 0 + return DIGRAPHS_GetCompleteDigraphCrossingNumber(chromaticNumber)/4; + else + #Chromatic number too large for known crossing number + return -1; + fi; +end); + +InstallMethod(RandomDigraphCons, "for SemicompleteDigraph and an integer", +[IsSemicompleteDigraph, IsInt], +{_, n} +-> RandomDigraphCons(IsSemicompleteDigraph, n, Float(Random([0 .. n])) / n)); + +InstallMethod(RandomDigraphCons, +"for SemicompleteDigraph, an integer, and a rational", +[IsSemicompleteDigraph, IsInt, IsRat], +{_, n, p} -> RandomDigraphCons(IsSemicompleteDigraph, n, Float(p))); + + +# Compute a large planar subdigraph of a non-planar digeaph +InstallMethod(DigraphLargePlanarSubdigraph, "for a digraph", [IsDigraph], + function(D) + local E1, E2, spanningSubdigraph, T, triangle, triangles, antisymmetric, edge, vertex; + if not IsDigraph(D) then + ErrorNoReturn("the 1st argument must be a digraph,"); + fi; + # Starting with E1 = Empty Set + E1 := [[],[]]; + # Make digraph antisymmetric + antisymmetric := MaximalAntiSymmetricSubdigraph(D); + # For as long as possible find triangles T whose vertices + # are in different components of G[E1] (spanning subgraph of G induced by E1) + # Find all triangles in the digraph + triangles:= DigraphAllTriangles(antisymmetric); + + # Get G[E1] + spanningSubdigraph := Digraph(DigraphNrVertices(D),E1[1],E1[2]); + for triangle in triangles do + # Check if triangle's vertices are in different components of G[E1] + if (DigraphConnectedComponent(spanningSubdigraph, triangle[1]) <> DigraphConnectedComponent(spanningSubdigraph, triangle[2])) and (DigraphConnectedComponent(spanningSubdigraph, triangle[1]) <> DigraphConnectedComponent(spanningSubdigraph, triangle[3])) then + # If they are add the edges of each vertex to E1 + Add(E1[1],triangle[1]); + Add(E1[2],triangle[2]); + Add(E1[1],triangle[2]); + Add(E1[2],triangle[3]); + Add(E1[1],triangle[1]); + Add(E1[2],triangle[3]); + # Recompute G[E1]f + spanningSubdigraph := Digraph(DigraphNrVertices(D),E1[1],E1[2]); + + fi; + od; + # Repeatedly find edges in G whose endpoints are are in different components of G[E2] and add e to E2 + for edge in DigraphEdges(antisymmetric) do + if DigraphConnectedComponent(spanningSubdigraph, edge[1]) <> DigraphConnectedComponent(spanningSubdigraph, edge[2]) then + spanningSubdigraph := DigraphAddEdge(spanningSubdigraph,edge); + fi; + od; + for edge in DigraphEdges(spanningSubdigraph) do + if IsDigraphEdge(D,edge[2],edge[1]) then + spanningSubdigraph := DigraphAddEdge(spanningSubdigraph,[edge[2],edge[1]]); + fi; + od; + #Print(DigraphEdges(spanningSubdigraph)); + return spanningSubdigraph; +end); + +# Find all 3-cycles within a digraph +InstallMethod(DigraphAllThreeCycles, "for a digraph", [IsDigraph], + function(D) + local threeCycles, adjacencyList, edge, min, vertex; + if not IsDigraph(D) then + ErrorNoReturn("the 1st argument must be a digraph,"); + fi; + threeCycles := []; + adjacencyList := AdjacencyMatrix(D); + for edge in DigraphEdges(D) do + for vertex in DigraphVertices(D) do + # if u != w, v != w, u is connected to w and v is connected to w (where u,v distinct to prevent errors due to loops) + if edge[1] <> edge[2] and vertex <> edge[1] and vertex <> edge[2] and adjacencyList[vertex][edge[1]] = 1 and adjacencyList[edge[2]][vertex] = 1 then + # Sort to prevent multiple cycles with same vertices, take the lowest first vertex + min := Minimum(edge[1],edge[2],vertex); + if min = vertex then + Add(threeCycles, [min,edge[1],edge[2]]); + elif min = edge[1] then + Add(threeCycles, [min,edge[2],vertex]); + else + Add(threeCycles, [min,vertex,edge[1]]); + fi; + fi; + od; + od; + SetDigraphAllThreeCycles(D,threeCycles); + return Set(threeCycles); +end); + +# Find all triangles within a digraph +InstallMethod(DigraphAllTriangles, "for a digraph", [IsDigraph], + function(D) + local triangles, adjacencyList, edge, temp, vertex; + if not IsDigraph(D) then + ErrorNoReturn("the 1st argument must be a digraph,"); + fi; + triangles := []; + adjacencyList := AdjacencyMatrix(D); + for edge in DigraphEdges(D) do + for vertex in DigraphVertices(D) do + # if u != w, v != w, u is connected to w and v is connected to w (where u,v distinct to prevent errors due to loop) + if edge[1] <> edge[2] and vertex <> edge[1] and vertex <> edge[2] and + (adjacencyList[vertex][edge[1]] = 1 or adjacencyList[edge[1]][vertex] = 1) and + (adjacencyList[edge[2]][vertex] = 1 or adjacencyList[vertex][edge[2]] = 1) then + temp := [edge[1],edge[2],vertex]; + # Sort to prevent multiple triangles with same vertices + Sort(temp); + Add(triangles, temp); + fi; + od; + od; + return Set(triangles); +end); + +# Add an artificial vertex between two given edges +InstallMethod(DigraphAddVertexCrossingPoint, "for a digraph, list, and list", [IsDigraph, IsList, IsList], + function(arg) + local n, D, Edge1, Edge2; + if IsEmpty(arg) then + ErrorNoReturn("at least 3 arguments required,"); + elif not IsDigraph(arg[1]) then + ErrorNoReturn("the 1st argument must be a digraph,"); + elif not IsDigraphEdge(arg[1],arg[2]) then + ErrorNoReturn("the 2nd argument must be an edge on the digraph,"); + elif not IsDigraphEdge(arg[1],arg[3]) then + ErrorNoReturn("the 3rd argument must be an edge on the digraph,"); + fi; + + D := arg[1]; + Edge1 := arg[2]; + Edge2 := arg[3]; + + if Edge1[1] = Edge1[2] or Edge2[1] = Edge2[2] then + ErrorNoReturn("the function is not suitable for self-loop edges"); + elif Edge1 = Edge2 then + ErrorNoReturn("the function is not suitable for identical edges"); + fi; + + # Add a new artificial vertex to the graph + D := DigraphAddVertices(D,1); + n := DigraphNrVertices(D); + # Remove the existing edges + D := DigraphRemoveEdge(D,Edge1); + D := DigraphRemoveEdge(D,Edge2); + # Add the new edges in (between E1 source and artificial vertex, artificial vertex and E1 destination. Same for E2) + D := DigraphAddEdges(D, [[Edge1[1],n],[n,Edge1[2]],[Edge2[1],n],[n,Edge2[2]]]); + return D; +end); + +# Compute crossing number of a complete multipartite digraphs +InstallMethod(DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber, "for a multipartite digraph", [IsCompleteMultipartiteDigraph], + function(D) + local componentsSize, crossingNumber; + if not IsCompleteMultipartiteDigraph(D) then + ErrorNoReturn("method only applicable for complete multipartite digraphs"); + fi; + componentsSize := CompleteMultipartiteDigraphPartitionSize(D); + if Length(componentsSize) = 3 then + crossingNumber := DIGRAPHS_CompleteTripartiteDigraphCrossingNumber(componentsSize); + SetDigraphCrossingNumber(D,crossingNumber); + return crossingNumber; + elif Length(componentsSize) = 4 then + crossingNumber := DIGRAPHS_Complete4partiteDigraphCrossingNumber(componentsSize); + SetDigraphCrossingNumber(D,crossingNumber); + return crossingNumber; + elif Length(componentsSize) = 5 then + crossingNumber := DIGRAPHS_Complete5partiteDigraphCrossingNumber(componentsSize); + SetDigraphCrossingNumber(D,crossingNumber); + return crossingNumber; + elif Length(componentsSize) = 6 then + crossingNumber := DIGRAPHS_Complete6partiteDigraphCrossingNumber(componentsSize); + SetDigraphCrossingNumber(D,crossingNumber); + return crossingNumber; + fi; +end); + +# Compute the crossing number of a complete 4-partite digraph +InstallGlobalFunction(DIGRAPHS_Complete4partiteDigraphCrossingNumber, + function(arg...) + local k,l,m,n; + k := arg[1][1]; + l := arg[1][2]; + m := arg[1][3]; + n := Float(arg[1][4]); + if k = 2 and l = 2 and m = 2 then + return Int(4 * (6*(Trunc(n/2) * Trunc((n-1)/2))+3*n)); + fi; + return -1; +end); + +# Compute the crossing number of a complete 5-partite digraph +InstallGlobalFunction(DIGRAPHS_Complete5partiteDigraphCrossingNumber, + function(arg...) + local j,k,l,m,n; + j := arg[1][1]; + k := arg[1][2]; + l := arg[1][3]; + m := arg[1][4]; + n := Float(arg[1][5]); + # Ho (2009) + if j = 1 and k = 1 and l = 1 and m = 1 then + return Int(4 * (2*(Trunc(n/2) * Trunc((n-1)/2))+n)); + elif j = 1 and k = 1 and l = 1 and m = 2 then + return Int(4 * (4*(Trunc(n/2) * Trunc((n-1)/2))+2*n)); + fi; + return -1; +end); + +# Compute the crossing number of a complete 6-partite digraph +InstallGlobalFunction(DIGRAPHS_Complete6partiteDigraphCrossingNumber, + function(arg...) + local i,j,k,l,m,n; + i := arg[1][1]; + j := arg[1][2]; + k := arg[1][3]; + l := arg[1][4]; + m := arg[1][5]; + n := Float(arg[1][6]); + # Lu and Huang + if i = 1 and j = 1 and k = 1 and l = 1 and m = 1 then + return Int(4 * (4*(Trunc(n/2) * Trunc((n-1)/2))+2*n+1+Trunc(n/2))); + fi; + return -1; +end); + +# Compute the crossing number of a complete tripartite digraph +InstallGlobalFunction(DIGRAPHS_CompleteTripartiteDigraphCrossingNumber, + function(arg...) + local l,m,n; + l := arg[1][1]; + m := arg[1][2]; + n := Float(arg[1][3]); + if l > 2 or m > 4 then + return -1; + elif l = 1 and m > 1 then + if m = 2 then + # Ho (2008) + return Int(4 * Trunc(n/2) * Trunc((n-1)/2)); + elif m = 3 then + # Asano + return Int(4 * (2* Trunc(n/2) * Trunc((n-1)/2) + Trunc(n/2))); + elif m = 4 then + # Huang and Zhao + return Int(4 * (4* Trunc(n/2) * Trunc((n-1)/2) + 2 * Trunc(n/2))); + fi; + elif l = 2 then + if m = 2 then + # Klesc and Schrotter + return Int(4 * 2 * Trunc(n/2) * Trunc((n-1)/2)); + elif m = 3 then + # Asano + return Int(4 * (4 * Trunc(n/2) * Trunc((n-1)/2) + n)); + elif m = 4 then + # Ho (2013) + return Int(4 * (6* Trunc(n/2) * Trunc((n-1)/2) + 2*n)); + fi; + fi; + return -1; +end); + +# Compute the crossing number of a complete bipartite digraph +InstallMethod(DIGRAPHS_CompleteBipartiteDigraphCrossingNumber, "for a bipartite digraph", [IsCompleteBipartiteDigraph], + function(D) + local componentsSize, crossingNumber; + if not IsCompleteBipartiteDigraph(D) then + ErrorNoReturn("method only applicable for complete bipartite digraphs"); + fi; + componentsSize := CompleteMultipartiteDigraphPartitionSize(D); + # Zarankiewicz's theorem holds with equality for all m < 7 for Km,n where m <= n + if componentsSize[1] < 7 then + crossingNumber := DIGRAPHS_ZarankiewiczTheorem(componentsSize[1],componentsSize[2]); + SetDigraphCrossingNumber(D,crossingNumber); + return crossingNumber; + # Zarankiewicz's theorem is also known to hold for K7,7-10 and K8,8-10 + elif componentsSize[1] < 9 and componentsSize[2] < 11 then + crossingNumber := DIGRAPHS_ZarankiewiczTheorem(componentsSize[1],componentsSize[2]); + SetDigraphCrossingNumber(D,crossingNumber); + return crossingNumber; + else + return -1; + fi; +end); + +# Implementation of Zarankiewicz's theorem +InstallGlobalFunction(DIGRAPHS_ZarankiewiczTheorem, + function(arg) + local m,n, crossingNumber; + m := Float(arg[1]); + n := Float(arg[2]); + return Int(4 * Trunc(n/2) * Trunc((n-1)/2) * Trunc(m/2) * Trunc((m-1)/2)); +end); + +# Compute the partition sizes of a complete multipartite digraph +InstallMethod(CompleteMultipartiteDigraphPartitionSize, "for a complete multipartite digraph", [IsCompleteMultipartiteDigraph], + function(D) + local i, neighbours, typesSeen, dictionary, componentsSize; + # Create a dictionary for the set of outneighbours + dictionary := NewDictionary(Set(OutNeighbours(D)),true); + neighbours := OutNeighbors(D); + typesSeen := []; + componentsSize := []; + for i in [1..Length(neighbours)] do + # If we've already seen the outneighbours for a given vertex increment the number of times we've seen it + if neighbours[i] in typesSeen then + AddDictionary(dictionary, neighbours[i], LookupDictionary(dictionary,neighbours[i])+1); + else + # Oherwise add the outneighbours to the seen array and add it to the dictionary + Append(typesSeen, [neighbours[i]]); + AddDictionary(dictionary,neighbours[i],1); + fi; + od; + # Add the number of times we have seen each neighbour set to an array + for i in [1..Length(typesSeen)] do + Add(componentsSize,LookupDictionary(dictionary,typesSeen[i])); + od; + # Sort the array due to convential notation of CompleteMultidigraphs + componentsSize := AsSortedList(componentsSize); + SetCompleteMultipartiteDigraphPartitionSize(D,componentsSize); + return componentsSize; +end); + +# Compute the crossing number of a digraph if it is isomorphic to a circulant digraph with known crossing number +InstallGlobalFunction(DIGRAPHS_IsomorphicToCirculantGraphCrossingNumber, + function(D) + local n; + n := DigraphNrVertices(D); + if n >= 8 and IsIsomorphicDigraph(D, CirculantGraph(n,[1,3])) then + return Trunc(Float(n)/3) + (n mod 3); + elif n >= 8 and n mod 2 = 0 and IsIsomorphicDigraph(D, CirculantGraph(n,[1,(n/2)-1])) then + return n/2; + elif n >= 3 and IsIsomorphicDigraph(D, CirculantGraph(3*n,[1,n])) then + return n; + elif n >= 3 and IsIsomorphicDigraph(D, CirculantGraph(2*n+2,[1,n])) then + return n+1; + elif n >= 3 and IsIsomorphicDigraph(D, CirculantGraph(3*n+1,[1,n])) then + return n + 1; + fi; + return -1; +end); diff --git a/tst/standard/crossingnumber.tst b/tst/standard/crossingnumber.tst new file mode 100644 index 000000000..131de8750 --- /dev/null +++ b/tst/standard/crossingnumber.tst @@ -0,0 +1,424 @@ +# This is a file containing all tests I (Mark Toner) have written + +gap> START_TEST("Digraphs package: standard/crossingnumber.tst"); +gap> LoadPackage("digraphs", false);; + +# +gap> DIGRAPHS_StartTest(); + +# Tests function for finding crossing number of Complete Digraphs + +# Test for Complete Digraph on 0 vertices +gap> D:= CompleteDigraph(0); + +gap> DIGRAPHS_CompleteDigraphCrossingNumber(D); +0 + +# Test for non-Complete Digraph +gap> D:= CompleteBipartiteDigraph(3,3); + +gap> DIGRAPHS_CompleteDigraphCrossingNumber(D); +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 2nd choice method found for `DIGRAPHS_CompleteDigraphCrossingNumber'\ + on 1 arguments + +# Test for Complete Digraph on 14 vertices +gap> D:= CompleteDigraph(14); + +gap> DIGRAPHS_CompleteDigraphCrossingNumber(D); +1260 + +# Test for Complete Digraph on 15 vertices +gap> D:= CompleteDigraph(15); + +gap> DIGRAPHS_CompleteDigraphCrossingNumber(D); +Error, Complete Digraph contains too many vertices for known crossing number + +# Tests function for finding partitions size of CompleteMultipartiteDigraph + +# Test for complete bipartite digraph +gap> D := CompleteBipartiteDigraph(2,3); + +gap> CompleteMultipartiteDigraphPartitionSize(D); +[ 2, 3 ] + +# Test for valid complete multipartite digraph (1) +gap> D := CompleteMultipartiteDigraph([2,3,4]); + +gap> CompleteMultipartiteDigraphPartitionSize(D); +[ 2, 3, 4 ] + +# Test for valid complete multipartite digraph (2) +gap> D := CompleteMultipartiteDigraph([1,1,2,3]); + +gap> CompleteMultipartiteDigraphPartitionSize(D); +[ 1, 1, 2, 3 ] + +# tests for DIGRAPHS_CrossingNumberInequality function +# test crossing number is 0 for planar Graph +gap> D:= WindmillGraph(4,3); + +gap> DIGRAPHS_CrossingNumberInequality(D); +0 + +# test crossing number is correct for a graph with e >= 6.95n (1) +gap> D:= CompleteDigraph(10); + +gap> DIGRAPHS_CrossingNumberInequality(D); +252 + +# test crossing number is correct for a graph with e >= 6.95n (2) +gap> D := CompleteDigraph(8); + +gap> DIGRAPHS_CrossingNumberInequality(D); +95 + +# test crossing number is correct for a graph with e <= 6.95n (1) +gap> D := CompleteDigraph(5); + +gap> DIGRAPHS_CrossingNumberInequality(D); +5 + +# test crossing number is correct for a graph with e <= 6.95n (2) +gap> D := CompleteDigraph(6); + +gap> DIGRAPHS_CrossingNumberInequality(D); +19 + +# test crossing number for empty graph +gap> D := Digraph([]); + +gap> DIGRAPHS_CrossingNumberInequality(D); +0 + +# test crossing number for graph with no edges +gap> D := Digraph([[],[],[],[],[]]); + +gap> DIGRAPHS_CrossingNumberInequality(D); +0 + +# Cubic Digraph Construction tests + +# Test for 0 vertices +gap> D:= RandomDigraph(IsCubicDigraph,0); +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 1st choice method found for `RandomDigraph' on 2 arguments + +# Test for 2 vertices +gap> D:= RandomDigraph(IsCubicDigraph,2); +Error, Cubic Digraphs must have at least 4 vertices + +# Test for 4 vertices +gap> D:= RandomDigraph(IsCubicDigraph,4); + + +# Test for 7 vertices +gap> D:= RandomDigraph(IsCubicDigraph,7); +Error, Cubic Digraphs exist only for even vertices + +# Test for 10 vertices +gap> D:= RandomDigraph(IsCubicDigraph,10); + + +# Test for 500 vertices +gap> D:= RandomDigraph(IsCubicDigraph,500); + + +# Test for 2000 vertices +gap> D:= RandomDigraph(IsCubicDigraph,2000); + + +# Tests for finding all triangles in a digraph + +# Test for an empty digraph +gap> D := EmptyDigraph(0);; +gap> DigraphAllThreeCycles(D); +[ ] + +# Test for a digraph with loops +gap> D := CompleteDigraph(3);; +gap> D := DigraphAddAllLoops(D);; +gap> DigraphAllThreeCycles(D); +[ [ 1, 2, 3 ], [ 1, 3, 2 ] ] + +# Test for a regular expected digraph (1) +gap> D := CompleteDigraph(4);; +gap> DigraphAllThreeCycles(D); +[ [ 1, 2, 3 ], [ 1, 2, 4 ], [ 1, 3, 2 ], [ 1, 3, 4 ], [ 1, 4, 2 ], + [ 1, 4, 3 ], [ 2, 3, 4 ], [ 2, 4, 3 ] ] + +# Test for a regular expected digraph (2) +gap> D := Digraph([[2],[3],[1]]);; +gap> DigraphAllThreeCycles(D); +[ [ 1, 2, 3 ] ] + +# Test for a regular expected digraph (3) +gap> D := Digraph([[2,4,5],[1,3],[1,5],[5],[1,4]]);; +gap> DigraphAllThreeCycles(D); +[ [ 1, 2, 3 ], [ 1, 4, 5 ] ] + +# Tests for finding all triangles in a digraph + +# Test for an empty digraph +gap> D := EmptyDigraph(0); + +gap> DigraphAllTriangles(D); +[ ] + +# Test for a digraph with loops +gap> D := CompleteDigraph(3);; +gap> D := DigraphAddAllLoops(D);; +gap> DigraphAllTriangles(D); +[ [ 1, 2, 3 ] ] + +# Test for a regular expected digraph (1) +gap> D := CompleteDigraph(4);; +gap> DigraphAllTriangles(D); +[ [ 1, 2, 3 ], [ 1, 2, 4 ], [ 1, 3, 4 ], [ 2, 3, 4 ] ] + +# Test for a regular expected digraph (2) +gap> D := Digraph([[2],[3],[1]]);; +gap> DigraphAllTriangles(D); +[ [ 1, 2, 3 ] ] + +# Test for a regular expected digraph (3) +gap> D := Digraph([[2,4,5],[1,3],[1,5],[5],[4]]);; +gap> DigraphAllTriangles(D); +[ [ 1, 2, 3 ], [ 1, 3, 5 ], [ 1, 4, 5 ] ] + +# tests for DIGRAPHS_CrossingNumberAlbertson function + +# Test that the method fails for a digraph with loops +gap> D:= CompleteDigraph(5); + +gap> D:=DigraphAddAllLoops(D); + +gap> DIGRAPHS_CrossingNumberAlbertson(D); +Error, the argument must be a digraph with no loops, + +# Test for digraph with valid chromatic number (1) +gap> D:= CompleteDigraph(5); + +gap> DIGRAPHS_CrossingNumberAlbertson(D); +1 + +# Test for digraph with valid chromatic number (2) +gap> D:= CompleteDigraph(10); + +gap> DIGRAPHS_CrossingNumberAlbertson(D); +60 + +# Test for digraph with valid chromatic number (3) +gap> D:= CompleteBipartiteDigraph(2,5); + +gap> DIGRAPHS_CrossingNumberAlbertson(D); +0 + +# Test for digraph with chromatic number higher than 14 +gap> D:= CompleteDigraph(15); + +gap> DIGRAPHS_CrossingNumberAlbertson(D); +-1 + +# Tests for the IsCubicDigraph method + +# Test for an empty digraph with 0 vertices +gap> D := EmptyDigraph(0);; +gap> IsCubicDigraph(D); +true + +# Test for a cubic digraph (1) +gap> D := RandomTournament(4);; +gap> IsCubicDigraph(D); +true + +# Test for a cubic digraph (2) +gap> D := Digraph([[4,5],[3,4,6],[5,6],[5],[],[1]]);; +gap> IsCubicDigraph(D); +true + +# Test for a non cubic digraph (1) +gap> D := CompleteBipartiteDigraph(3,3);; +gap> IsCubicDigraph(D); +false + +# Test for a non cubic digraph (2) +gap> D := RandomDigraph(9);; +gap> IsCubicDigraph(D); +false + +# Test for a digraph with loops +gap> D := RandomTournament(4);; +gap> D := DigraphAddAllLoops(D);; +gap> IsCubicDigraph(D); +false + +# Test for a multidigraph (will always return false for a multidigraph so randomness unimportant) +gap> D := RandomMultiDigraph(10);; +gap> IsCubicDigraph(D); +false + +# Tests to determine if a digraph is semicomplete or not + +# Test for a semicomplete digraph (1) +gap> D:= Digraph([[2,3],[3],[]]); + +gap> IsSemicompleteDigraph(D); +true + +# Test for a semicomplete digraph (2) +gap> D:= Digraph([[2,3,4,5],[3,5],[4],[1,2],[1,2,3,4]]); + +gap> IsSemicompleteDigraph(D); +true + +# Test for an empty digraph +gap> D := EmptyDigraph(0); + +gap> IsSemicompleteDigraph(D); +true + +# Test for a tournament +gap> D := RandomTournament(15); + +gap> IsSemicompleteDigraph(D); +true + +# Test for a complete digraph +gap> D := CompleteDigraph(15); + +gap> IsSemicompleteDigraph(D); +true + +# Test for a non-semicomplete digraph (1) +gap> D := CycleDigraph(9); + +gap> IsSemicompleteDigraph(D); +false + +# Test for a non-semicomplete digraph (2) +gap> D := BinaryTree(6); + +gap> IsSemicompleteDigraph(D); +false + +# tests for DIGRAPHS_IsK22FreeDigraph function + +# test that a complete digraph is K22-free +gap> D:= CompleteDigraph(9); + +gap> DIGRAPHS_IsK22FreeDigraph(D); +true + +# test that a complete bipartite graph is not K22-free +gap> D:= CompleteBipartiteDigraph(3,2); + +gap> DIGRAPHS_IsK22FreeDigraph(D); +false + +# test that a digraph with fewer than 4 vertices is K22-free +gap> D:= CompleteDigraph(3); + +gap> DIGRAPHS_IsK22FreeDigraph(D); +true + +# test that a digraph that is not K2,2 free is correctly identified as such +gap> D:= Digraph([[3,4],[3,4],[1,2],[1,2]]); + +gap> DIGRAPHS_IsK22FreeDigraph(D); +false + +# Tests for random semicomplete digraph generation + +# Test for n = 10, p not given +gap> D:= RandomDigraph(IsSemicompleteDigraph,10);; +gap> IsSemicompleteDigraph(D); +true + +# Test for n = 3, p not given +gap> D:= RandomDigraph(IsSemicompleteDigraph,3);; +gap> IsSemicompleteDigraph(D); +true + +# Test for n = 9, p=0 +gap> D:= RandomDigraph(IsSemicompleteDigraph,9);; +gap> IsSemicompleteDigraph(D); +true + +# Test for n = 9, p=1 +gap> D:= RandomDigraph(IsSemicompleteDigraph,9,1);; +gap> IsSemicompleteDigraph(D); +true + +# Test for n = 9, p=0.5 +gap> D:= RandomDigraph(IsSemicompleteDigraph,9,0.5);; +gap> IsSemicompleteDigraph(D); +true + +# Test for n=-1 +gap> D:= RandomDigraph(IsSemicompleteDigraph,-1); +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 1st choice method found for `RandomDigraph' on 2 arguments + +# Test for n=1, p=-1 +gap> D:= RandomDigraph(IsSemicompleteDigraph,1,-1); + + +# Test for n=1, p=1.1 +gap> D:= RandomDigraph(IsSemicompleteDigraph,1,1.1);; +gap> IsSemicompleteDigraph(D); +true + +# Test for n=s, p=1 +gap> D:= RandomDigraph(IsSemicompleteDigraph,"s",-1); +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 1st choice method found for `RandomDigraph' on 3 arguments + +# Test for no n,p +gap> D:= RandomDigraph(IsSemicompleteDigraph); +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 1st choice method found for `RandomDigraph' on 1 arguments + +# Tests for semicomplete digraph crossing number calculator + +# Test for a planar SemicompleteDigraph +gap> D := RandomDigraph(IsSemicompleteDigraph, 4);; +gap> SemicompleteDigraphCrossingNumber(D); +0 + +# Test for a semicomplete digraph without known crossing number (<15 vertices) (1) +gap> D := RandomDigraph(IsSemicompleteDigraph, 5);; +gap> SemicompleteDigraphCrossingNumber(D); +[ 1, 4 ] + +# Test for a semicomplete digraph without known crossing number (<15 vertices) (2) +gap> D := RandomDigraph(IsSemicompleteDigraph, 12);; +gap> SemicompleteDigraphCrossingNumber(D); +[ 150, 600 ] + +# Test for a semicomplete digraph without known crossing number (>=15 vertices) +gap> D := RandomDigraph(IsSemicompleteDigraph, 15);; +gap> SemicompleteDigraphCrossingNumber(D); +[ 178, 1764 ] + +# Tests function for finding crossing number of Tournaments + +# Test for tournament on 0 vertices +gap> D:= RandomTournament(0); + +gap> DIGRAPHS_TournamentCrossingNumber(D); +0 + +# Test for tournament on 14 vertices +gap> D:= RandomTournament(14); + +gap> DIGRAPHS_TournamentCrossingNumber(D); +315 + +# Test for tournament on 15 vertices +gap> D:= RandomTournament(15); + +gap> DIGRAPHS_TournamentCrossingNumber(D); +-1 +gap> DIGRAPHS_StopTest(); +gap> STOP_TEST("Digraphs package: standard/constructors.tst", 0); From 7e8ea3f91d5f858f68a67ab5092850e287764aec Mon Sep 17 00:00:00 2001 From: Mark Toner Date: Thu, 3 Apr 2025 14:58:10 +0100 Subject: [PATCH 03/13] added created files --- PackageInfo.g | 7 +++++++ doc/digraphs.bib | 14 ++++++++++++++ gap/utils.gi | 1 + 3 files changed, 22 insertions(+) diff --git a/PackageInfo.g b/PackageInfo.g index a816705c0..82013b98f 100644 --- a/PackageInfo.g +++ b/PackageInfo.g @@ -373,6 +373,13 @@ Persons := [ IsMaintainer := false, Email := "bspiers972@outlook.com"), + rec( + LastName := "Toner", + FirstNames := "Mark", + IsAuthor := true, + IsMaintainer := false, + Email := "mark.toner@live.com"), + rec( LastName := "Tsalakou", FirstNames := "Maria", diff --git a/doc/digraphs.bib b/doc/digraphs.bib index 2c4e9247f..faa34367c 100644 --- a/doc/digraphs.bib +++ b/doc/digraphs.bib @@ -193,3 +193,17 @@ @InProceedings{US14 pages="313--324", isbn="978-3-319-11812-3" } + +@article{CA1997, +title = {A Better Approximation Algorithm for Finding Planar Subgraphs}, +journal = {Journal of Algorithms}, +volume = {27}, +number = {2}, +pages = {269-302}, +year = {1998}, +issn = {0196-6774}, +doi = {https://doi.org/10.1006/jagm.1997.0920}, +url = {https://www.sciencedirect.com/science/article/pii/S0196677497909202}, +author = {Gruia Călinescu and Cristina G Fernandes and Ulrich Finkler and Howard Karloff}, +abstract = {The MAXIMUM PLANAR SUBGRAPH problem—given a graphG, find a largest planar subgraph ofG—has applications in circuit layout, facility layout, and graph drawing. No previous polynomial-time approximation algorithm for this NP-Complete problem was known to achieve a performance ratio larger than 1/3, which is achieved simply by producing a spanning tree ofG. We present the first approximation algorithm for MAXIMUM PLANAR SUBGRAPH with higher performance ratio (4/9 instead of 1/3). We also apply our algorithm to find large outerplanar subgraphs. Last, we show that both MAXIMUM PLANAR SUBGRAPH and its complement, the problem of removing as few edges as possible to leave a planar subgraph, are Max SNP-Hard.} +} \ No newline at end of file diff --git a/gap/utils.gi b/gap/utils.gi index 932054ada..ea86a7638 100644 --- a/gap/utils.gi +++ b/gap/utils.gi @@ -18,6 +18,7 @@ BindGlobal("DIGRAPHS_DocXMLFiles", "attr.xml", "cliques.xml", "constructors.xml", + "crossingnumber.xml", "digraph.xml", "display.xml", "examples.xml", From 693c8d3ae8c7c51abcf3f2e46736e87fc70035d2 Mon Sep 17 00:00:00 2001 From: Mark Toner Date: Thu, 3 Apr 2025 16:27:53 +0100 Subject: [PATCH 04/13] Final commit --- doc/title.xml | 322 +++++++++++++++++++++++++++++++++++++++++ gap/crossing-number.gi | 5 +- init.g | 1 + read.g | 2 + 4 files changed, 329 insertions(+), 1 deletion(-) create mode 100644 doc/title.xml diff --git a/doc/title.xml b/doc/title.xml new file mode 100644 index 000000000..9ad2fb6a3 --- /dev/null +++ b/doc/title.xml @@ -0,0 +1,322 @@ + + + + + + Digraphs + + + Graphs, digraphs, and multidigraphs in &GAP; + + + 1.10.0 + + + Jan De Beule
+

+Vrije Universiteit Brussel, Vakgroep Wiskunde, Pleinlaan 2, B - 1050 Brussels, Belgium
+
+jdebeule@cage.ugent.be +https://wids.research.vub.be/en/jan-de-beule + + + + Julius Jonusas
+j.jonusas@gmail.com +http://julius.jonusas.work + +
+ + James Mitchell
+
+Mathematical Institute, North Haugh, St Andrews, Fife, KY16 9SS, Scotland
+
+jdm3@st-andrews.ac.uk +https://jdbm.me + +
+ + Wilf A. Wilson
+gap@wilf-wilson.net +https://wilf.me + +
+ + Michael Young
+
+Jack Cole Building, North Haugh, St Andrews, Fife, KY16 9SX, Scotland
+
+mct25@st-andrews.ac.uk +https://myoung.uk/work/ + +
+ + Marina Anagnostopoulou-Merkouri
+
+Mathematical Institute, North Haugh, St Andrews, Fife, KY16 9SS, Scotland
+
+mam49@st-andrews.ac.uk + +
+ + Finn Buck
+
+Mathematical Institute, North Haugh, St Andrews, Fife, KY16 9SS, Scotland
+
+finneganlbuck@gmail.com + +
+ + Stuart Burrell
+stuartburrell1994@gmail.com +https://stuartburrell.github.io + +
+ + Graham Campbell
+ +
+ + Raiyan Chowdhury
+ +
+ + Reinis Cirpons
+
+Mathematical Institute, North Haugh, St Andrews, Fife, KY16 9SS, Scotland
+
+rc234@st-andrews.ac.uk + +
+ + Ashley Clayton
+
+Mathematical Institute, North Haugh, St Andrews, Fife, KY16 9SS, Scotland
+
+ac323@st-andrews.ac.uk + +
+ + Tom Conti-Leslie
+tom.contileslie@gmail.com +https://tomcontileslie.com + +
+ + Joseph Edwards
+
+Mathematical Institute, North Haugh, St Andrews, Fife, KY16 9SS, Scotland
+
+jde1@st-andrews.ac.uk +https://github.com/Joseph-Edwards + +
+ + Luna Elliott
+luna.elliott142857@gmail.com +https://research.manchester.ac.uk/en/persons/luna-elliott + +
+ + Isuru Fernando
+isuruf@gmail.com + +
+ + Ewan Gilligan
+eg207@st-andrews.ac.uk + +
+ + Gillis Frankie
+fotg1@st-andrews.ac.uk + +
+ + Sebastian Gutsche
+gutsche@momo.math.rwth-aachen.de + +
+ + Samantha Harper
+seh25@st-andrews.ac.uk + +
+ + Max Horn
+
+Fachbereich Mathematik, TU Kaiserslautern, Gottlieb-Daimler-Straße 48, 67663 Kaiserslautern, Germany
+
+horn@mathematik.uni-kl.de +https://www.quendi.de/math + +
+ + Christopher Jefferson
+
+Jack Cole Building, North Haugh, St Andrews, Fife, KY16 9SX, Scotland
+
+caj21@st-andrews.ac.uk +https://heather.cafe/ + +
+ + Malachi Johns
+zlj1@st-andrews.ac.uk + +
+ + Olexandr Konovalov
+
+Jack Cole Building, North Haugh, St Andrews, Fife, KY16 9SX, Scotland
+
+obk1@st-andrews.ac.uk +https://olexandr-konovalov.github.io/ + +
+ + Hyeokjun Kwon
+hk78@st-andrews.ac.uk + +
+ + Aidan Lau
+ +
+ + Andrea Lee
+ahwl1@st-andrews.ac.uk + +
+ + Saffron McIver
+sm544@st-andrews.ac.uk + +
+ + Michael Orlitzky
+michael@orlitzky.com +https://michael.orlitzky.com/ + +
+ + Matthew Pancer
+mp322@st-andrews.ac.uk + +
+ + Markus Pfeiffer
+markus.pfeiffer@morphism.de +https://markusp.morphism.de/ + +
+ + Daniel Pointon
+dp211@st-andrews.ac.uk + +
+ + Lea Racine
+
+Jack Cole Building, North Haugh, St Andrews, Fife, KY16 9SX, Scotland
+
+lr217@st-andrews.ac.uk + +
+ + Christopher Russell
+ +
+ + Artur Schaefer
+as305@st-and.ac.uk + +
+ + Isabella Scott
+iscott@uchicago.edu + +
+ + Kamran Sharma
+
+Jack Cole Building, North Haugh, St Andrews, Fife, KY16 9SX, Scotland
+
+kks4@st-andrews.ac.uk + +
+ + Finn Smith
+
+Mathematical Institute, North Haugh, St Andrews, Fife, KY16 9SS, Scotland
+
+fls3@st-andrews.ac.uk + +
+ + Ben Spiers
+bspiers972@outlook.com + +
+ + Mark Toner
+mark.toner@live.com + +
+ + Maria Tsalakou
+
+Mathematical Institute, North Haugh, St Andrews, Fife, KY16 9SS, Scotland
+
+mt200@st-andrews.ac.uk +https://mariatsalakou.github.io/ + +
+ + Meike Weiss
+
+Chair of Algebra and Representation Theory, Pontdriesch 10-16, 52062 Aachen
+
+weiss@art.rwth-aachen.de +https://bit.ly/4e6pUeP + +
+ + Murray Whyte
+
+Mathematical Institute, North Haugh, St Andrews, Fife, KY16 9SS, Scotland
+
+mw231@st-andrews.ac.uk + +
+ + Fabian Zickgraf
+f.zickgraf@dashdos.com + +
+ + 14 February 2025 + + + The &Digraphs; package is a &GAP; package containing + methods for graphs, digraphs, and multidigraphs. + + + Jan De Beule, Julius Jonušas, James D. Mitchell, + Wilf A. Wilson, Michael Young et al.

+ + &Digraphs; is free software; you can redistribute it and/or modify + it under the terms of the + https://www.fsf.org/licenses/gpl.html as published by the + Free Software Foundation; either version 3 of the License, or (at + your option) any later version. + + + We would like to thank Christopher Jefferson for his help in including + &BLISS; in &Digraphs;. + + This package's methods for computing digraph homomorphisms are based + on work by Max Neunhöffer, and independently Artur Schäfer. + + + \ No newline at end of file diff --git a/gap/crossing-number.gi b/gap/crossing-number.gi index 70a7c6428..444402a8d 100644 --- a/gap/crossing-number.gi +++ b/gap/crossing-number.gi @@ -357,7 +357,10 @@ end); # Compute a lower bound for the crossing number of a digraph InstallGlobalFunction(DigraphCrossingNumberLowerBound, function(D) - local temp,res;# Compute a lower boud for the crossing number of a digraphgument must be a digraph,"); + local temp,res; + + if not IsDigraph(D) then + ErrorNoReturn("Argument must be a digraph"); fi; res := 0; diff --git a/init.g b/init.g index 9edfe8d60..d880ab2f2 100644 --- a/init.g +++ b/init.g @@ -71,5 +71,6 @@ ReadPackage("digraphs", "gap/cliques.gd"); ReadPackage("digraphs", "gap/planar.gd"); ReadPackage("digraphs", "gap/examples.gd"); ReadPackage("digraphs", "gap/weights.gd"); +ReadPackage("digraphs", "gap/crossing-number.gd"); DeclareInfoClass("InfoDigraphs"); diff --git a/read.g b/read.g index 7307adee3..29f1f20cf 100644 --- a/read.g +++ b/read.g @@ -39,3 +39,5 @@ ReadPackage("digraphs", "gap/cliques.gi"); ReadPackage("digraphs", "gap/planar.gi"); ReadPackage("digraphs", "gap/examples.gi"); ReadPackage("digraphs", "gap/weights.gi"); +ReadPackage("digraphs", "gap/crossing-number.gi"); + From 8b2bee240b6f92b57ab38b37988d444a23904b63 Mon Sep 17 00:00:00 2001 From: Mark Toner Date: Thu, 3 Apr 2025 16:34:34 +0100 Subject: [PATCH 05/13] Fixed comment typos --- gap/crossing-number.gi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gap/crossing-number.gi b/gap/crossing-number.gi index 444402a8d..e295605d1 100644 --- a/gap/crossing-number.gi +++ b/gap/crossing-number.gi @@ -483,7 +483,7 @@ InstallGlobalFunction(DIGRAPHS_CrossingNumberAlbertson, chromaticNumber := ChromaticNumber(D); # Chromatic number must be less than 16 as that is the highest complete digraph we have a known cn for if chromaticNumber < 15 then - # +1 as complete digraph crossing numebr array starts at 0 + # +1 as complete digraph crossing number array starts at 0 return DIGRAPHS_GetCompleteDigraphCrossingNumber(chromaticNumber)/4; else #Chromatic number too large for known crossing number @@ -796,7 +796,7 @@ InstallMethod(CompleteMultipartiteDigraphPartitionSize, "for a complete multipar if neighbours[i] in typesSeen then AddDictionary(dictionary, neighbours[i], LookupDictionary(dictionary,neighbours[i])+1); else - # Oherwise add the outneighbours to the seen array and add it to the dictionary + # Otherwise add the outneighbours to the seen array and add it to the dictionary Append(typesSeen, [neighbours[i]]); AddDictionary(dictionary,neighbours[i],1); fi; @@ -805,7 +805,7 @@ InstallMethod(CompleteMultipartiteDigraphPartitionSize, "for a complete multipar for i in [1..Length(typesSeen)] do Add(componentsSize,LookupDictionary(dictionary,typesSeen[i])); od; - # Sort the array due to convential notation of CompleteMultidigraphs + # Sort the array due to conventional notation of CompleteMultidigraphs componentsSize := AsSortedList(componentsSize); SetCompleteMultipartiteDigraphPartitionSize(D,componentsSize); return componentsSize; From 9259bbb63e5fda86ba6a52556acacd6ae7d3ce01 Mon Sep 17 00:00:00 2001 From: Mark Toner Date: Mon, 7 Apr 2025 17:26:16 +0100 Subject: [PATCH 06/13] Started linting --- gap/crossing-number.gd | 17 ++-- gap/crossing-number.gi | 188 ++++++++++++++++++++++------------------- 2 files changed, 109 insertions(+), 96 deletions(-) diff --git a/gap/crossing-number.gd b/gap/crossing-number.gd index fe63053df..7fcab662c 100644 --- a/gap/crossing-number.gd +++ b/gap/crossing-number.gd @@ -1,9 +1,9 @@ # Properties -DeclareProperty("IsSemicompleteDigraph",IsDigraph); -DeclareProperty("IsCubicDigraph",IsDigraph); +DeclareProperty("IsSemicompleteDigraph", IsDigraph); +DeclareProperty("IsCubicDigraph", IsDigraph); # Operations -DeclareOperation("DigraphAddVertexCrossingPoint",[IsDigraph,IsList,IsList]); +DeclareOperation("DigraphAddVertexCrossingPoint", [IsDigraph, IsList, IsList]); # Global Functions DeclareGlobalFunction("DigraphCrossingNumberUpperBound"); @@ -20,15 +20,16 @@ DeclareGlobalFunction("DIGRAPHS_Complete5partiteDigraphCrossingNumber"); DeclareGlobalFunction("DIGRAPHS_Complete4partiteDigraphCrossingNumber"); DeclareGlobalFunction("DIGRAPHS_IsomorphicToCirculantGraphCrossingNumber"); - # Attributes DeclareAttribute("DIGRAPHS_CompleteDigraphCrossingNumber", IsCompleteDigraph); DeclareAttribute("DIGRAPHS_TournamentCrossingNumber", IsTournament); -DeclareAttribute("DigraphCrossingNumber",IsDigraph); -DeclareAttribute("SemicompleteDigraphCrossingNumber",IsSemicompleteDigraph); +DeclareAttribute("DigraphCrossingNumber", IsDigraph); +DeclareAttribute("SemicompleteDigraphCrossingNumber", IsSemicompleteDigraph); DeclareAttribute("DigraphAllThreeCycles", IsDigraph); DeclareAttribute("DigraphAllTriangles", IsDigraph); DeclareAttribute("DigraphLargePlanarSubdigraph", IsDigraph); -DeclareAttribute("DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber", IsCompleteMultipartiteDigraph); -DeclareAttribute("DIGRAPHS_CompleteBipartiteDigraphCrossingNumber",IsCompleteBipartiteDigraph); +DeclareAttribute("DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber", + IsCompleteMultipartiteDigraph); +DeclareAttribute("DIGRAPHS_CompleteBipartiteDigraphCrossingNumber", + IsCompleteBipartiteDigraph); DeclareAttribute("CompleteMultipartiteDigraphPartitionSize",IsCompleteMultipartiteDigraph); \ No newline at end of file diff --git a/gap/crossing-number.gi b/gap/crossing-number.gi index e295605d1..cbf7cb451 100644 --- a/gap/crossing-number.gi +++ b/gap/crossing-number.gi @@ -1,26 +1,27 @@ # Crossing Number of a tournament -InstallMethod(DIGRAPHS_TournamentCrossingNumber, "for a tournament", [IsTournament], +InstallMethod(DIGRAPHS_TournamentCrossingNumber, "for a tournament", + [IsTournament], function(D) local KnownCrossingNumberArray, n; if not IsTournament(D) then ErrorNoReturn("argument must be a tournament"); fi; - # Array of known crossing numbers for tournaments (complete graphs) from 0 - 14 vertices - KnownCrossingNumberArray := [0, 0, 0, 0, 0, 1, 3, 9, 18, 36, 60, 100, 150, 225, 315]; + # Array of known crossing numbers for tournaments from 0 - 14 vertices + KnownCrossingNumberArray := [0, 0, 0, 0, 0, 1, 3, 9, 18, 36, 60, 100, + 150, 225, 315]; n := DigraphNrVertices(D); if n < 15 then - SetDigraphCrossingNumber(D,KnownCrossingNumberArray[n+1]); - return KnownCrossingNumberArray[n+1]; + SetDigraphCrossingNumber(D, KnownCrossingNumberArray[n + 1]); + return KnownCrossingNumberArray[n + 1]; elif n >= 15 then return -1; fi; end); - # Crossing Number Inequality InstallGlobalFunction(DIGRAPHS_CrossingNumberInequality, function(D) - local res, n, e, completeBound, tournamentBound, digraph, nrLoops, temp; + local res, n, e, nrLoops, temp; # If digraph has loops remove them first e := DigraphNrEdges(D); nrLoops := DigraphNrLoops(D); @@ -30,22 +31,22 @@ InstallGlobalFunction(DIGRAPHS_CrossingNumberInequality, # If digraph is Planar crossing number is 0 if IsPlanarDigraph(D) then - SetDigraphCrossingNumber(D,0); + SetDigraphCrossingNumber(D, 0); return 0; fi; n := DigraphNrVertices(D); res := -1; - if DIGRAPHS_IsK22FreeDigraph(D) and (e >= 1000*n) then - temp := 1/(10^8) * (Float(e))^4 / (Float(n)^3); + if DIGRAPHS_IsK22FreeDigraph(D) and (e >= 1000 * n) then + temp := 1/(10 ^ 8) * (Float(e)) ^ 4 / (Float(n) ^ 3); if temp > res then res := temp; fi; fi; # If digraph has e >= 6.95n use one equation if Float(e) >= 6.95 * Float(n) then - temp := (Float(e)^3) / (29* (n^2)); + temp := (Float(e) ^ 3) / (29 * (n ^ 2)); # Deal with division errors temp := DIGRAPHS_CrossingNumberRound(temp); if temp > res then @@ -53,7 +54,7 @@ InstallGlobalFunction(DIGRAPHS_CrossingNumberInequality, fi; # Otherwise we use a different one else - temp := ((Float(e^3)) / (29*(Float(n)^2))) - (35/29)*Float(n); + temp := ((Float(e ^ 3)) / (29 * (Float(n) ^ 2))) - (35 / 29) * Float(n); temp := DIGRAPHS_CrossingNumberRound(temp); if temp > res then res := temp; @@ -67,28 +68,30 @@ InstallGlobalFunction(DIGRAPHS_CrossingNumberRound, function(val) local tolerance; tolerance := 0.0001; - if val - Trunc(val) < 0.0001 then + if val - Trunc(val) < tolerance then return Int(Trunc(val)); else return Int(Ceil(val)); fi; end); - # Get the known crossing number for a comple digraph on n vertices InstallGlobalFunction(DIGRAPHS_GetCompleteDigraphCrossingNumber, function(n) local KnownCrossingNumberArray; if n > 15 then - ErrorNoReturn("Crossing number unknown for digraph on this number of vertices"); + ErrorNoReturn("Crossing number unknown for digraph on this + number of vertices"); fi; - KnownCrossingNumberArray := [0, 0, 0, 0, 0, 4, 12, 36, 72, 144, 240, 400, 600, 900, 1260]; + KnownCrossingNumberArray := [0, 0, 0, 0, 0, 4, 12, 36, 72, 144, + 240, 400, 600, 900, 1260]; # +1 due to first array index being 1 representing n=0 - return KnownCrossingNumberArray[n+1]; + return KnownCrossingNumberArray[n + 1]; end); # Crossing number for a complete digraph -InstallMethod(DIGRAPHS_CompleteDigraphCrossingNumber, "for a complete digraph", [IsCompleteDigraph], +InstallMethod(DIGRAPHS_CompleteDigraphCrossingNumber, + "for a complete digraph", [IsCompleteDigraph], function(D) local n, completeDigraphCrossingNumber; if not IsCompleteDigraph(D) then @@ -96,52 +99,64 @@ InstallMethod(DIGRAPHS_CompleteDigraphCrossingNumber, "for a complete digraph", fi; n := DigraphNrVertices(D); if n < 15 then - # 1 due to list's indexing at 1 and the complete graph of 0 vertices being included - completeDigraphCrossingNumber := DIGRAPHS_GetCompleteDigraphCrossingNumber(n); - SetDigraphCrossingNumber(D,completeDigraphCrossingNumber); + # 1 due to list's indexing at 1 and the complete + # graph of 0 vertices being included + completeDigraphCrossingNumber := + DIGRAPHS_GetCompleteDigraphCrossingNumber(n); + SetDigraphCrossingNumber(D, completeDigraphCrossingNumber); return completeDigraphCrossingNumber; - elif n >= 15 then - ErrorNoReturn("Complete Digraph contains too many vertices for known crossing number"); + elif n >= 15 then + ErrorNoReturn("Complete Digraph contains too many + vertices for known crossing number"); fi; end); - # Computes if a digraph has K2,2 subgraph InstallGlobalFunction(DIGRAPHS_IsK22FreeDigraph, function(D) - local i,j,k,l,intersect,adjacencyMatrix,vertices,neighbours,numberVertices,jCount,lCount; + local i,j,k,l,intersect,adjacencyMatrix, + vertices,neighbours,numberVertices,jCount,lCount; if not IsDigraph(D) then ErrorNoReturn("the 1st argument must be a digraph,"); fi; numberVertices := DigraphNrVertices(D); - # If the digraph is a complete bipartite digraph with m>=2 and n>=2 then it has K2,2 as a subgraph - if IsCompleteBipartiteDigraph(D) and Length(DigraphBicomponents(D)[1]) > 1 and Length(DigraphBicomponents(D)[2]) > 1 then + # If the digraph is a complete bipartite digraph with m>=2 and n>=2 + # then it has K2,2 as a subgraph + if IsCompleteBipartiteDigraph(D) and + Length(DigraphBicomponents(D)[1]) > 1 and + Length(DigraphBicomponents(D)[2]) > 1 then return false; - # If the digraph has fewer than 4 vertices then it is is trivially K2,2 free + # If the digraph has fewer than 4 vertices then it is is + # trivially K2,2 free elif numberVertices < 4 then return true; - # If a digraph is a complete digraph or tournament it is K2,2 free as as there are no unconnected nodes + # If a digraph is a complete digraph or tournament it is K2,2 + # free as as there are no unconnected nodes elif IsCompleteDigraph(D) or IsTournament(D) then return true; fi; - # Check if for every pair of distinct unconnected vertices (x1,x2) (x1 <-!-> x2, x1!=x2) that their intersection contains two distinct unconnected vertices - # This means there is a K2,2 subgraph + # Check if for every pair of distinct unconnected vertices (x1,x2) + # (x1 <-!-> x2, x1!=x2) that their intersection contains + # two distinct unconnected vertices. This means there is K2,2 subgraph # Create boolean adjacency matrix adjacencyMatrix := BooleanAdjacencyMatrix(D); neighbours := OutNeighbors(D); vertices := DigraphVertices(D); for i in vertices do - for jCount in [i+1..numberVertices] do + for jCount in [i + 1 .. numberVertices] do j := vertices[jCount]; - # If there are more than 1 vertex that both i and j connect to and i and j are not connected - intersect := Intersection(neighbours[i],neighbours[j]); - if Length(intersect) >= 2 and adjacencyMatrix[i][j] = false and adjacencyMatrix[j][i] = false then + # If there are more than 1 vertex that both i and j + # connect to and i and j are not connected + intersect := Intersection(neighbours[i], neighbours[j]); + if Length(intersect) >= 2 and adjacencyMatrix[i][j] = false + and adjacencyMatrix[j][i] = false then # For every pair of vertices in the intersection for k in intersect do - for lCount in [k+1..Length(intersect)] do + for lCount in [k + 1 .. Length(intersect)] do l := intersect[lCount]; # if k and l are unconnected - if adjacencyMatrix[k][l] = false and adjacencyMatrix[l][k] = false then + if adjacencyMatrix[k][l] = false and + adjacencyMatrix[l][k] = false then return false; fi; od; @@ -168,20 +183,19 @@ function(_, n, p) Add(adjacencyList, []); od; - for i in vertices do for j in [i+1..n] do # Decide if there should be a second vertex using some probability p # Random number < p means it should be added if Float(Random(probability) / 100) < p then - Add(adjacencyList[j],i); - Add(adjacencyList[i],j); + Add(adjacencyList[j], i); + Add(adjacencyList[i], j); # Create only one edge between each vertex # Decide orientation from a random number - elif Random([1..2]) < 2 then - Add(adjacencyList[i],j); + elif Random([1 .. 2]) < 2 then + Add(adjacencyList[i], j); else - Add(adjacencyList[j],i); + Add(adjacencyList[j], i); fi; od; od; @@ -194,7 +208,7 @@ InstallMethod(RandomDigraphCons, "for CubicDigraph and a positive integer", [IsCubicDigraph, IsPosInt], function(_, n) - local adjacencyList, edge1, edge2, edges, edgeList, i, D, edgeIndex, numberVertices; + local edge1, edge2, edges, edgeList, i, D, edgeIndex, numberVertices; if n = 0 then return EmptyDigraph(0); elif n < 4 then @@ -207,14 +221,14 @@ function(_, n) D := RandomTournament(4); # For i in range from 4 to n - for i in [1 .. n-4] do + for i in [1 .. n - 4] do # Skip odd i as no cubic digraph can exist with odd number of vertices if i mod 2 = 1 then continue; fi; # Select two random edges edgeList := DigraphEdges(D); - edges := [1..DigraphNrEdges(D)]; + edges := [1 .. DigraphNrEdges(D)]; edgeIndex := Random(edges); edge1 := edgeList[edgeIndex]; # Remove edge1 so edge2 != edge1 @@ -222,19 +236,19 @@ function(_, n) edge2 := edgeList[Random(edges)]; # Split the edges by adding a new vertex in between each - D := DigraphRemoveEdge(D,edge1); - D := DigraphRemoveEdge(D,edge2); + D := DigraphRemoveEdge(D, edge1); + D := DigraphRemoveEdge(D, edge2); numberVertices := DigraphNrVertices(D); - D := DigraphAddVertices(D,2); - D := DigraphAddEdge(D,[edge1[1],numberVertices+1]); - D := DigraphAddEdge(D,[numberVertices+1,edge1[2]]); - D := DigraphAddEdge(D,[edge2[1],numberVertices+2]); - D := DigraphAddEdge(D,[numberVertices+2,edge2[2]]); + D := DigraphAddVertices(D, 2); + D := DigraphAddEdge(D,[edge1[1], numberVertices + 1]); + D := DigraphAddEdge(D,[numberVertices + 1,edge1[2]]); + D := DigraphAddEdge(D,[edge2[1], numberVertices + 2]); + D := DigraphAddEdge(D,[numberVertices + 2, edge2[2]]); # Determine orientation of link between new vertices - if Random([1..2]) < 2 then - D := DigraphAddEdge(D,[numberVertices+1,numberVertices+2]); + if Random([1 .. 2]) < 2 then + D := DigraphAddEdge(D,[numberVertices + 1,numberVertices + 2]); else - D := DigraphAddEdge(D,[numberVertices+2,numberVertices+1]); + D := DigraphAddEdge(D, [numberVertices + 2,numberVertices + 1]); fi; od; @@ -248,29 +262,26 @@ InstallMethod(IsCubicDigraph, "for a digraph", [IsDigraph], local degrees; # If the digraph has an odd number of vertices it can never be cubic if DigraphNrVertices(D) mod 2 = 1 then - return false; - # If D is a multidigraph we are going to exclude it from being a cubic digraph + return false; + # If D is a multidigraph we are going to exclude + # it from being a cubic digraph elif IsMultiDigraph(D) then return false; # Cubic digraphs cannot have loops elif DigraphHasLoops(D) then return false; - fi; # Need to consider edges in and out of each vertex degrees := OutDegrees(D) + InDegrees(D); - if ForAll( degrees, x -> x = 3) then - return true; - else - return false; - fi; + return ForAll(degrees, x -> x = 3); end); # Check if a digraph is semicomplete InstallMethod(IsSemicompleteDigraph, "for a digraph", [IsDigraph], function(D) - local i,j,adjacencyMatrix, numberVertices, jCount, vertices; - # If a digraph is complete or a tournament it is by definition semi-complete + local i, j, adjacencyMatrix, numberVertices, jCount, vertices; + # If a digraph is complete or a tournament + # it is by definition semi-complete if IsTournament(D) or IsCompleteDigraph(D) then return true; fi; @@ -281,15 +292,18 @@ InstallMethod(IsSemicompleteDigraph, "for a digraph", [IsDigraph], if IsMultiDigraph(D) then return false; fi; - # Check that for all vertices that do not have a directed edge one way between + # Check that for all vertices that do not have a + # directed edge one way between vertices := DigraphVertices(D); adjacencyMatrix := BooleanAdjacencyMatrix(D); numberVertices := DigraphNrVertices(D); for i in vertices do for jCount in [i+1..numberVertices] do j := vertices[jCount]; - # If no edge exists from i -> j or j -> i for all i,j then the digraph isn't semicomplete - if adjacencyMatrix[i][j] = false and adjacencyMatrix[j][i] = false then + # If no edge exists from i -> j or j -> i + # for all i,j then the digraph isn't semicomplete + if adjacencyMatrix[i][j] = false and + adjacencyMatrix[j][i] = false then return false; fi; od; @@ -300,11 +314,11 @@ end); # Compute the crossing number of a digraph InstallMethod(DigraphCrossingNumber, "for a digraph", [IsDigraph], function(D) - local n,temp; + local n, temp; # If Digraph is planar return 0 if IsPlanarDigraph(D) then - SetDigraphCrossingNumber(D,0); + SetDigraphCrossingNumber(D, 0); return 0; fi; @@ -313,14 +327,14 @@ function(D) # If Digraph is a complete graph with fewer than 15 vertices if IsCompleteDigraph(D) and (n < 15) then temp := DIGRAPHS_CompleteDigraphCrossingNumber(D); - SetDigraphCrossingNumber(D,temp); + SetDigraphCrossingNumber(D, temp); return temp; fi; # If Digraph is a tournament with fewer than 15 vertices if IsTournament(D) and (n < 15) then temp := DIGRAPHS_TournamentCrossingNumber(D); - SetDigraphCrossingNumber(D,temp); + SetDigraphCrossingNumber(D, temp); return temp; fi; @@ -328,25 +342,24 @@ function(D) if IsCompleteBipartiteDigraph(D) then temp := DIGRAPHS_CompleteBipartiteDigraphCrossingNumber(D); if temp <> -1 then - SetDigraphCrossingNumber(D,temp); + SetDigraphCrossingNumber(D, temp); return temp; fi; fi; - # If Digraph is multipartite if IsCompleteMultipartiteDigraph(D) then temp := DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber(D); if temp <> -1 then - SetDigraphCrossingNumber(D,temp); + SetDigraphCrossingNumber(D, temp); return temp; fi; fi; - # If its isomorphic to a circulant graph with known crossing number + # If its isomorphic to a circulant graph with known crossing number temp := DIGRAPHS_IsomorphicToCirculantGraphCrossingNumber(D); if temp <> -1 then - SetDigraphCrossingNumber(D,temp); + SetDigraphCrossingNumber(D, temp); return temp; fi; @@ -357,7 +370,7 @@ end); # Compute a lower bound for the crossing number of a digraph InstallGlobalFunction(DigraphCrossingNumberLowerBound, function(D) - local temp,res; + local temp, res; if not IsDigraph(D) then ErrorNoReturn("Argument must be a digraph"); @@ -375,7 +388,7 @@ function(D) if temp <> -1 then res := temp; fi; - + # The Crossing Number Inequality temp := DIGRAPHS_CrossingNumberInequality(D); if temp <> -1 then @@ -388,13 +401,13 @@ end); # Compute an upper bound for the crossing number of a digraph InstallGlobalFunction(DigraphCrossingNumberUpperBound, function(D) - local res, temp, componentsSize, n,e; + local res, temp, componentsSize, n, e; if not IsDigraph(D) then ErrorNoReturn("Argument must be a digraph"); fi; - if IsPlanarDigraph(D) then + if IsPlanarDigraph(D) then return 0; fi; @@ -411,7 +424,8 @@ function(D) # Zarankiewicz's theorem for bipartite digraphs if IsBipartiteDigraph(D) then componentsSize := CompleteMultipartiteDigraphPartitionSize(D); - temp := DIGRAPHS_ZarankiewiczTheorem(componentsSize[1],componentsSize[2]); + temp := DIGRAPHS_ZarankiewiczTheorem(componentsSize[1], + componentsSize[2]); if temp < res then res := temp; fi; @@ -501,11 +515,10 @@ InstallMethod(RandomDigraphCons, [IsSemicompleteDigraph, IsInt, IsRat], {_, n, p} -> RandomDigraphCons(IsSemicompleteDigraph, n, Float(p))); - # Compute a large planar subdigraph of a non-planar digeaph InstallMethod(DigraphLargePlanarSubdigraph, "for a digraph", [IsDigraph], function(D) - local E1, E2, spanningSubdigraph, T, triangle, triangles, antisymmetric, edge, vertex; + local E1, spanningSubdigraph, triangle, triangles, antisymmetric, edge; if not IsDigraph(D) then ErrorNoReturn("the 1st argument must be a digraph,"); fi; @@ -635,8 +648,7 @@ InstallMethod(DigraphAddVertexCrossingPoint, "for a digraph, list, and list", [I D := DigraphRemoveEdge(D,Edge1); D := DigraphRemoveEdge(D,Edge2); # Add the new edges in (between E1 source and artificial vertex, artificial vertex and E1 destination. Same for E2) - D := DigraphAddEdges(D, [[Edge1[1],n],[n,Edge1[2]],[Edge2[1],n],[n,Edge2[2]]]); - return D; + return DigraphAddEdges(D, [[Edge1[1],n],[n,Edge1[2]],[Edge2[1],n],[n,Edge2[2]]]); end); # Compute crossing number of a complete multipartite digraphs @@ -776,7 +788,7 @@ end); # Implementation of Zarankiewicz's theorem InstallGlobalFunction(DIGRAPHS_ZarankiewiczTheorem, function(arg) - local m,n, crossingNumber; + local m, n; m := Float(arg[1]); n := Float(arg[2]); return Int(4 * Trunc(n/2) * Trunc((n-1)/2) * Trunc(m/2) * Trunc((m-1)/2)); From d26692d17ce0766bb58c682195b4b9c2b8a87b03 Mon Sep 17 00:00:00 2001 From: Mark Toner Date: Wed, 16 Apr 2025 11:21:49 +0100 Subject: [PATCH 07/13] Linted code --- gap/crossing-number.gd | 7 +- gap/crossing-number.gi | 359 +++++++++++++++++++++++------------------ 2 files changed, 205 insertions(+), 161 deletions(-) diff --git a/gap/crossing-number.gd b/gap/crossing-number.gd index 7fcab662c..7c8d973e8 100644 --- a/gap/crossing-number.gd +++ b/gap/crossing-number.gd @@ -28,8 +28,9 @@ DeclareAttribute("SemicompleteDigraphCrossingNumber", IsSemicompleteDigraph); DeclareAttribute("DigraphAllThreeCycles", IsDigraph); DeclareAttribute("DigraphAllTriangles", IsDigraph); DeclareAttribute("DigraphLargePlanarSubdigraph", IsDigraph); -DeclareAttribute("DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber", +DeclareAttribute("DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber", IsCompleteMultipartiteDigraph); -DeclareAttribute("DIGRAPHS_CompleteBipartiteDigraphCrossingNumber", +DeclareAttribute("DIGRAPHS_CompleteBipartiteDigraphCrossingNumber", IsCompleteBipartiteDigraph); -DeclareAttribute("CompleteMultipartiteDigraphPartitionSize",IsCompleteMultipartiteDigraph); \ No newline at end of file +DeclareAttribute("CompleteMultipartiteDigraphPartitionSize", + IsCompleteMultipartiteDigraph); \ No newline at end of file diff --git a/gap/crossing-number.gi b/gap/crossing-number.gi index cbf7cb451..fb52042b7 100644 --- a/gap/crossing-number.gi +++ b/gap/crossing-number.gi @@ -11,7 +11,7 @@ InstallMethod(DIGRAPHS_TournamentCrossingNumber, "for a tournament", 150, 225, 315]; n := DigraphNrVertices(D); if n < 15 then - SetDigraphCrossingNumber(D, KnownCrossingNumberArray[n + 1]); + SetDigraphCrossingNumber(D, KnownCrossingNumberArray[n + 1]); return KnownCrossingNumberArray[n + 1]; elif n >= 15 then return -1; @@ -28,7 +28,7 @@ InstallGlobalFunction(DIGRAPHS_CrossingNumberInequality, if nrLoops > 0 then e := e - DigraphNrLoops(D); fi; - + # If digraph is Planar crossing number is 0 if IsPlanarDigraph(D) then SetDigraphCrossingNumber(D, 0); @@ -39,7 +39,7 @@ InstallGlobalFunction(DIGRAPHS_CrossingNumberInequality, res := -1; if DIGRAPHS_IsK22FreeDigraph(D) and (e >= 1000 * n) then - temp := 1/(10 ^ 8) * (Float(e)) ^ 4 / (Float(n) ^ 3); + temp := 1 / (10 ^ 8) * (Float(e)) ^ 4 / (Float(n) ^ 3); if temp > res then res := temp; fi; @@ -54,7 +54,8 @@ InstallGlobalFunction(DIGRAPHS_CrossingNumberInequality, fi; # Otherwise we use a different one else - temp := ((Float(e ^ 3)) / (29 * (Float(n) ^ 2))) - (35 / 29) * Float(n); + temp := ((Float(e ^ 3)) / (29 * (Float(n) ^ 2))) - + (35 / 29) * Float(n); temp := DIGRAPHS_CrossingNumberRound(temp); if temp > res then res := temp; @@ -80,7 +81,7 @@ InstallGlobalFunction(DIGRAPHS_GetCompleteDigraphCrossingNumber, function(n) local KnownCrossingNumberArray; if n > 15 then - ErrorNoReturn("Crossing number unknown for digraph on this + ErrorNoReturn("Crossing number unknown for digraph on this number of vertices"); fi; KnownCrossingNumberArray := [0, 0, 0, 0, 0, 4, 12, 36, 72, 144, @@ -99,14 +100,14 @@ InstallMethod(DIGRAPHS_CompleteDigraphCrossingNumber, fi; n := DigraphNrVertices(D); if n < 15 then - # 1 due to list's indexing at 1 and the complete + # 1 due to list's indexing at 1 and the complete # graph of 0 vertices being included - completeDigraphCrossingNumber := + completeDigraphCrossingNumber := DIGRAPHS_GetCompleteDigraphCrossingNumber(n); - SetDigraphCrossingNumber(D, completeDigraphCrossingNumber); + SetDigraphCrossingNumber(D, completeDigraphCrossingNumber); return completeDigraphCrossingNumber; elif n >= 15 then - ErrorNoReturn("Complete Digraph contains too many + ErrorNoReturn("Complete Digraph contains too many vertices for known crossing number"); fi; end); @@ -114,29 +115,29 @@ end); # Computes if a digraph has K2,2 subgraph InstallGlobalFunction(DIGRAPHS_IsK22FreeDigraph, function(D) - local i,j,k,l,intersect,adjacencyMatrix, - vertices,neighbours,numberVertices,jCount,lCount; + local i, j, k, l, intersect, adjacencyMatrix, + vertices, neighbours, numberVertices, jCount, lCount; if not IsDigraph(D) then ErrorNoReturn("the 1st argument must be a digraph,"); fi; numberVertices := DigraphNrVertices(D); - # If the digraph is a complete bipartite digraph with m>=2 and n>=2 - # then it has K2,2 as a subgraph - if IsCompleteBipartiteDigraph(D) and + # If the digraph is a complete bipartite digraph with m>=2 and n>=2 + # then it has K2,2 as a subgraph + if IsCompleteBipartiteDigraph(D) and Length(DigraphBicomponents(D)[1]) > 1 and Length(DigraphBicomponents(D)[2]) > 1 then return false; - # If the digraph has fewer than 4 vertices then it is is + # If the digraph has fewer than 4 vertices then it is is # trivially K2,2 free elif numberVertices < 4 then return true; - # If a digraph is a complete digraph or tournament it is K2,2 + # If a digraph is a complete digraph or tournament it is K2,2 # free as as there are no unconnected nodes elif IsCompleteDigraph(D) or IsTournament(D) then return true; fi; - # Check if for every pair of distinct unconnected vertices (x1,x2) - # (x1 <-!-> x2, x1!=x2) that their intersection contains + # Check if for every pair of distinct unconnected vertices (x1,x2) + # (x1 <-!-> x2, x1!=x2) that their intersection contains # two distinct unconnected vertices. This means there is K2,2 subgraph # Create boolean adjacency matrix adjacencyMatrix := BooleanAdjacencyMatrix(D); @@ -145,17 +146,17 @@ InstallGlobalFunction(DIGRAPHS_IsK22FreeDigraph, for i in vertices do for jCount in [i + 1 .. numberVertices] do j := vertices[jCount]; - # If there are more than 1 vertex that both i and j + # If there are more than 1 vertex that both i and j # connect to and i and j are not connected intersect := Intersection(neighbours[i], neighbours[j]); - if Length(intersect) >= 2 and adjacencyMatrix[i][j] = false + if Length(intersect) >= 2 and adjacencyMatrix[i][j] = false and adjacencyMatrix[j][i] = false then # For every pair of vertices in the intersection for k in intersect do for lCount in [k + 1 .. Length(intersect)] do l := intersect[lCount]; # if k and l are unconnected - if adjacencyMatrix[k][l] = false and + if adjacencyMatrix[k][l] = false and adjacencyMatrix[l][k] = false then return false; fi; @@ -184,7 +185,7 @@ function(_, n, p) od; for i in vertices do - for j in [i+1..n] do + for j in [i + 1 .. n] do # Decide if there should be a second vertex using some probability p # Random number < p means it should be added if Float(Random(probability) / 100) < p then @@ -232,7 +233,7 @@ function(_, n) edgeIndex := Random(edges); edge1 := edgeList[edgeIndex]; # Remove edge1 so edge2 != edge1 - Remove(edges,edgeIndex); + Remove(edges, edgeIndex); edge2 := edgeList[Random(edges)]; # Split the edges by adding a new vertex in between each @@ -240,15 +241,15 @@ function(_, n) D := DigraphRemoveEdge(D, edge2); numberVertices := DigraphNrVertices(D); D := DigraphAddVertices(D, 2); - D := DigraphAddEdge(D,[edge1[1], numberVertices + 1]); - D := DigraphAddEdge(D,[numberVertices + 1,edge1[2]]); - D := DigraphAddEdge(D,[edge2[1], numberVertices + 2]); - D := DigraphAddEdge(D,[numberVertices + 2, edge2[2]]); + D := DigraphAddEdge(D, [edge1[1], numberVertices + 1]); + D := DigraphAddEdge(D, [numberVertices + 1, edge1[2]]); + D := DigraphAddEdge(D, [edge2[1], numberVertices + 2]); + D := DigraphAddEdge(D, [numberVertices + 2, edge2[2]]); # Determine orientation of link between new vertices if Random([1 .. 2]) < 2 then - D := DigraphAddEdge(D,[numberVertices + 1,numberVertices + 2]); + D := DigraphAddEdge(D, [numberVertices + 1, numberVertices + 2]); else - D := DigraphAddEdge(D, [numberVertices + 2,numberVertices + 1]); + D := DigraphAddEdge(D, [numberVertices + 2, numberVertices + 1]); fi; od; @@ -280,7 +281,7 @@ end); InstallMethod(IsSemicompleteDigraph, "for a digraph", [IsDigraph], function(D) local i, j, adjacencyMatrix, numberVertices, jCount, vertices; - # If a digraph is complete or a tournament + # If a digraph is complete or a tournament # it is by definition semi-complete if IsTournament(D) or IsCompleteDigraph(D) then return true; @@ -292,17 +293,17 @@ InstallMethod(IsSemicompleteDigraph, "for a digraph", [IsDigraph], if IsMultiDigraph(D) then return false; fi; - # Check that for all vertices that do not have a - # directed edge one way between + # Check that for all vertices that do not have a + # directed edge one way between them vertices := DigraphVertices(D); adjacencyMatrix := BooleanAdjacencyMatrix(D); numberVertices := DigraphNrVertices(D); for i in vertices do - for jCount in [i+1..numberVertices] do + for jCount in [i + 1 .. numberVertices] do j := vertices[jCount]; # If no edge exists from i -> j or j -> i # for all i,j then the digraph isn't semicomplete - if adjacencyMatrix[i][j] = false and + if adjacencyMatrix[i][j] = false and adjacencyMatrix[j][i] = false then return false; fi; @@ -366,7 +367,6 @@ function(D) return -1; end); - # Compute a lower bound for the crossing number of a digraph InstallGlobalFunction(DigraphCrossingNumberLowerBound, function(D) @@ -375,14 +375,11 @@ function(D) if not IsDigraph(D) then ErrorNoReturn("Argument must be a digraph"); fi; - res := 0; - # Check if there is an exact way to compute the crossing number if DigraphCrossingNumber(D) <> -1 then return DigraphCrossingNumber(D); fi; - # The Albertson conjecture temp := DIGRAPHS_CrossingNumberAlbertson(D); if temp <> -1 then @@ -434,13 +431,14 @@ function(D) # Guy's Theorem (Valid for all non-multi digraphs) if not IsMultiDigraph(D) then n := Float(n); - temp := Trunc(n/2) * Trunc((n-1)/2) * Trunc((n-2)/2) * Trunc((n-3)/2); + temp := Trunc(n / 2) * Trunc((n - 1) / 2) * + Trunc((n - 2) / 2) * Trunc((n - 3) / 2); if temp < res then res := temp; fi; else e := DigraphNrEdges(D); - temp := e^e; + temp := e ^ e; if temp < res then res := temp; fi; @@ -449,40 +447,44 @@ function(D) return res; end); -# Compute the upper and lower bound for the crossing number of a semicomplete digraph -InstallMethod(SemicompleteDigraphCrossingNumber, "for a semicomplete digraph", [IsSemicompleteDigraph], +# Compute the bounds for the crossing number of a semicomplete digraph +InstallMethod(SemicompleteDigraphCrossingNumber, +"for a semicomplete digraph", [IsSemicompleteDigraph], function(D) local n, crossingNumberCompleteDigraph, crossingNumberTournament, x; - if IsPlanarDigraph(D) then - SetDigraphCrossingNumber(D,0); + SetDigraphCrossingNumber(D, 0); return 0; fi; n := DigraphNrVertices(D); - if n < 15 then - # Get the crossing number of the tournament with the same number of vertices - crossingNumberTournament := DIGRAPHS_GetCompleteDigraphCrossingNumber(n) / 4; - # Get the crossing number of the complete graph with the same number of vertices - crossingNumberCompleteDigraph := DIGRAPHS_GetCompleteDigraphCrossingNumber(n); + # Get the crossing number of the tournament equal vertices + crossingNumberTournament := + DIGRAPHS_GetCompleteDigraphCrossingNumber(n) / 4; + # Get the crossing number of the complete graph with equal vertices + crossingNumberCompleteDigraph := + DIGRAPHS_GetCompleteDigraphCrossingNumber(n); else - # Get lower bound for tournament with the same number of vertices using CNI - crossingNumberTournament := DIGRAPHS_CrossingNumberInequality(RandomTournament(n)); - # Get upper bound for complete digraph with the same number of vertices using Guy's Theorem + # Get lower bound for tournament with equal vertices using CNI + crossingNumberTournament := + DIGRAPHS_CrossingNumberInequality(RandomTournament(n)); + # Get upper bound for complete digraph + # with equal number of vertices using Guy's Theorem x := Float(n); - crossingNumberCompleteDigraph := Int(Trunc(x/2) * Trunc((x-1)/2) * Trunc((x-2)/2) * Trunc((x-3)/2)); + crossingNumberCompleteDigraph := Int(Trunc(x / 2) * + Trunc((x - 1) / 2) * Trunc((x - 2) / 2) * Trunc((x - 3) / 2)); fi; - # If the cn of tournament and complete digraph are equal crossing number is known - # The only examples I know where this is the case are for planar digraphs + # If the cn of tournament and complete digraph + # are equal crossing number is known if crossingNumberCompleteDigraph = crossingNumberTournament then - SetDigraphCrossingNumber(D,crossingNumberCompleteDigraph); + SetDigraphCrossingNumber(D, crossingNumberCompleteDigraph); return crossingNumberCompleteDigraph; elif crossingNumberCompleteDigraph < crossingNumberTournament then # This code should never run ErrorNoReturn("Error, lower bound higher than upper bound"); else - return [crossingNumberTournament,crossingNumberCompleteDigraph]; + return [crossingNumberTournament, crossingNumberCompleteDigraph]; fi; return; end); @@ -493,16 +495,17 @@ InstallGlobalFunction(DIGRAPHS_CrossingNumberAlbertson, local chromaticNumber; if not IsDigraph(D) then ErrorNoReturn("the 1st argument must be a digraph,"); - fi; + fi; chromaticNumber := ChromaticNumber(D); - # Chromatic number must be less than 16 as that is the highest complete digraph we have a known cn for + # Chromatic number must be less than 16 as that is + # the highest complete digraph we have a known cn for if chromaticNumber < 15 then - # +1 as complete digraph crossing number array starts at 0 - return DIGRAPHS_GetCompleteDigraphCrossingNumber(chromaticNumber)/4; + return DIGRAPHS_GetCompleteDigraphCrossingNumber(chromaticNumber + + 1) / 4; else - #Chromatic number too large for known crossing number + # Chromatic number too large for known crossing number return -1; - fi; + fi; end); InstallMethod(RandomDigraphCons, "for SemicompleteDigraph and an integer", @@ -523,43 +526,49 @@ InstallMethod(DigraphLargePlanarSubdigraph, "for a digraph", [IsDigraph], ErrorNoReturn("the 1st argument must be a digraph,"); fi; # Starting with E1 = Empty Set - E1 := [[],[]]; + E1 := [[], []]; # Make digraph antisymmetric antisymmetric := MaximalAntiSymmetricSubdigraph(D); - # For as long as possible find triangles T whose vertices - # are in different components of G[E1] (spanning subgraph of G induced by E1) + # For as long as possible find triangles T whose vertices + # are in different components of G[E1] # Find all triangles in the digraph - triangles:= DigraphAllTriangles(antisymmetric); + triangles := DigraphAllTriangles(antisymmetric); # Get G[E1] - spanningSubdigraph := Digraph(DigraphNrVertices(D),E1[1],E1[2]); + spanningSubdigraph := Digraph(DigraphNrVertices(D), E1[1], E1[2]); for triangle in triangles do # Check if triangle's vertices are in different components of G[E1] - if (DigraphConnectedComponent(spanningSubdigraph, triangle[1]) <> DigraphConnectedComponent(spanningSubdigraph, triangle[2])) and (DigraphConnectedComponent(spanningSubdigraph, triangle[1]) <> DigraphConnectedComponent(spanningSubdigraph, triangle[3])) then + if (DigraphConnectedComponent(spanningSubdigraph, triangle[1]) <> + DigraphConnectedComponent(spanningSubdigraph, triangle[2])) and + (DigraphConnectedComponent(spanningSubdigraph, triangle[1]) <> + DigraphConnectedComponent(spanningSubdigraph, triangle[3])) then # If they are add the edges of each vertex to E1 - Add(E1[1],triangle[1]); - Add(E1[2],triangle[2]); - Add(E1[1],triangle[2]); - Add(E1[2],triangle[3]); - Add(E1[1],triangle[1]); - Add(E1[2],triangle[3]); + Add(E1[1], triangle[1]); + Add(E1[2], triangle[2]); + Add(E1[1], triangle[2]); + Add(E1[2], triangle[3]); + Add(E1[1], triangle[1]); + Add(E1[2], triangle[3]); # Recompute G[E1]f - spanningSubdigraph := Digraph(DigraphNrVertices(D),E1[1],E1[2]); + spanningSubdigraph := Digraph(DigraphNrVertices(D), + E1[1], E1[2]); fi; od; - # Repeatedly find edges in G whose endpoints are are in different components of G[E2] and add e to E2 + # Repeatedly find edges in G whose endpoints are in + # different components of G[E2] and add e to E2 for edge in DigraphEdges(antisymmetric) do - if DigraphConnectedComponent(spanningSubdigraph, edge[1]) <> DigraphConnectedComponent(spanningSubdigraph, edge[2]) then - spanningSubdigraph := DigraphAddEdge(spanningSubdigraph,edge); + if DigraphConnectedComponent(spanningSubdigraph, edge[1]) <> + DigraphConnectedComponent(spanningSubdigraph, edge[2]) then + spanningSubdigraph := DigraphAddEdge(spanningSubdigraph, edge); fi; od; for edge in DigraphEdges(spanningSubdigraph) do - if IsDigraphEdge(D,edge[2],edge[1]) then - spanningSubdigraph := DigraphAddEdge(spanningSubdigraph,[edge[2],edge[1]]); + if IsDigraphEdge(D, edge[2], edge[1]) then + spanningSubdigraph := DigraphAddEdge(spanningSubdigraph, + [edge[2], edge[1]]); fi; od; - #Print(DigraphEdges(spanningSubdigraph)); return spanningSubdigraph; end); @@ -574,21 +583,26 @@ InstallMethod(DigraphAllThreeCycles, "for a digraph", [IsDigraph], adjacencyList := AdjacencyMatrix(D); for edge in DigraphEdges(D) do for vertex in DigraphVertices(D) do - # if u != w, v != w, u is connected to w and v is connected to w (where u,v distinct to prevent errors due to loops) - if edge[1] <> edge[2] and vertex <> edge[1] and vertex <> edge[2] and adjacencyList[vertex][edge[1]] = 1 and adjacencyList[edge[2]][vertex] = 1 then - # Sort to prevent multiple cycles with same vertices, take the lowest first vertex - min := Minimum(edge[1],edge[2],vertex); + # if u != w, v != w, + # u is connected to w and v is connected to w + # where u,v distinct to prevent errors due to loops + if edge[1] <> edge[2] and vertex <> edge[1] and vertex <> edge[2] + and adjacencyList[vertex][edge[1]] = 1 and + adjacencyList[edge[2]][vertex] = 1 then + # Sort to prevent multiple cycles with same vertices + # lowest vertex first + min := Minimum(edge[1], edge[2], vertex); if min = vertex then - Add(threeCycles, [min,edge[1],edge[2]]); + Add(threeCycles, [min, edge[1], edge[2]]); elif min = edge[1] then - Add(threeCycles, [min,edge[2],vertex]); + Add(threeCycles, [min, edge[2], vertex]); else - Add(threeCycles, [min,vertex,edge[1]]); + Add(threeCycles, [min, vertex, edge[1]]); fi; fi; od; od; - SetDigraphAllThreeCycles(D,threeCycles); + SetDigraphAllThreeCycles(D, threeCycles); return Set(threeCycles); end); @@ -603,11 +617,15 @@ InstallMethod(DigraphAllTriangles, "for a digraph", [IsDigraph], adjacencyList := AdjacencyMatrix(D); for edge in DigraphEdges(D) do for vertex in DigraphVertices(D) do - # if u != w, v != w, u is connected to w and v is connected to w (where u,v distinct to prevent errors due to loop) - if edge[1] <> edge[2] and vertex <> edge[1] and vertex <> edge[2] and - (adjacencyList[vertex][edge[1]] = 1 or adjacencyList[edge[1]][vertex] = 1) and - (adjacencyList[edge[2]][vertex] = 1 or adjacencyList[vertex][edge[2]] = 1) then - temp := [edge[1],edge[2],vertex]; + # if u != w, v != w, u is connected to w and v is connected to w + # where u,v distinct to prevent errors due to loop + if edge[1] <> edge[2] and vertex <> edge[1] + and vertex <> edge[2] and + (adjacencyList[vertex][edge[1]] = 1 or + adjacencyList[edge[1]][vertex] = 1) and + (adjacencyList[edge[2]][vertex] = 1 or + adjacencyList[vertex][edge[2]] = 1) then + temp := [edge[1], edge[2], vertex]; # Sort to prevent multiple triangles with same vertices Sort(temp); Add(triangles, temp); @@ -618,16 +636,17 @@ InstallMethod(DigraphAllTriangles, "for a digraph", [IsDigraph], end); # Add an artificial vertex between two given edges -InstallMethod(DigraphAddVertexCrossingPoint, "for a digraph, list, and list", [IsDigraph, IsList, IsList], - function(arg) +InstallMethod(DigraphAddVertexCrossingPoint, "for a digraph, + list, and list", [IsDigraph, IsList, IsList], + function(arg...) local n, D, Edge1, Edge2; if IsEmpty(arg) then ErrorNoReturn("at least 3 arguments required,"); elif not IsDigraph(arg[1]) then ErrorNoReturn("the 1st argument must be a digraph,"); - elif not IsDigraphEdge(arg[1],arg[2]) then + elif not IsDigraphEdge(arg[1], arg[2]) then ErrorNoReturn("the 2nd argument must be an edge on the digraph,"); - elif not IsDigraphEdge(arg[1],arg[3]) then + elif not IsDigraphEdge(arg[1], arg[3]) then ErrorNoReturn("the 3rd argument must be an edge on the digraph,"); fi; @@ -639,41 +658,49 @@ InstallMethod(DigraphAddVertexCrossingPoint, "for a digraph, list, and list", [I ErrorNoReturn("the function is not suitable for self-loop edges"); elif Edge1 = Edge2 then ErrorNoReturn("the function is not suitable for identical edges"); - fi; + fi; # Add a new artificial vertex to the graph - D := DigraphAddVertices(D,1); + D := DigraphAddVertices(D, 1); n := DigraphNrVertices(D); # Remove the existing edges - D := DigraphRemoveEdge(D,Edge1); - D := DigraphRemoveEdge(D,Edge2); - # Add the new edges in (between E1 source and artificial vertex, artificial vertex and E1 destination. Same for E2) - return DigraphAddEdges(D, [[Edge1[1],n],[n,Edge1[2]],[Edge2[1],n],[n,Edge2[2]]]); + D := DigraphRemoveEdge(D, Edge1); + D := DigraphRemoveEdge(D, Edge2); + # Add the new edges in (between E1 source and artificial vertex, + # artificial vertex and E1 destination. Same for E2) + return DigraphAddEdges(D, [[Edge1[1], n], [n, Edge1[2]], + [Edge2[1], n], [n, Edge2[2]]]); end); # Compute crossing number of a complete multipartite digraphs -InstallMethod(DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber, "for a multipartite digraph", [IsCompleteMultipartiteDigraph], +InstallMethod(DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber, +"for a multipartite digraph", [IsCompleteMultipartiteDigraph], function(D) local componentsSize, crossingNumber; if not IsCompleteMultipartiteDigraph(D) then - ErrorNoReturn("method only applicable for complete multipartite digraphs"); + ErrorNoReturn("method only applicable for + complete multipartite digraphs"); fi; componentsSize := CompleteMultipartiteDigraphPartitionSize(D); if Length(componentsSize) = 3 then - crossingNumber := DIGRAPHS_CompleteTripartiteDigraphCrossingNumber(componentsSize); - SetDigraphCrossingNumber(D,crossingNumber); + crossingNumber := + DIGRAPHS_CompleteTripartiteDigraphCrossingNumber(componentsSize); + SetDigraphCrossingNumber(D, crossingNumber); return crossingNumber; elif Length(componentsSize) = 4 then - crossingNumber := DIGRAPHS_Complete4partiteDigraphCrossingNumber(componentsSize); - SetDigraphCrossingNumber(D,crossingNumber); + crossingNumber := + DIGRAPHS_Complete4partiteDigraphCrossingNumber(componentsSize); + SetDigraphCrossingNumber(D, crossingNumber); return crossingNumber; elif Length(componentsSize) = 5 then - crossingNumber := DIGRAPHS_Complete5partiteDigraphCrossingNumber(componentsSize); - SetDigraphCrossingNumber(D,crossingNumber); + crossingNumber := + DIGRAPHS_Complete5partiteDigraphCrossingNumber(componentsSize); + SetDigraphCrossingNumber(D, crossingNumber); return crossingNumber; elif Length(componentsSize) = 6 then - crossingNumber := DIGRAPHS_Complete6partiteDigraphCrossingNumber(componentsSize); - SetDigraphCrossingNumber(D,crossingNumber); + crossingNumber := + DIGRAPHS_Complete6partiteDigraphCrossingNumber(componentsSize); + SetDigraphCrossingNumber(D, crossingNumber); return crossingNumber; fi; end); @@ -681,13 +708,13 @@ end); # Compute the crossing number of a complete 4-partite digraph InstallGlobalFunction(DIGRAPHS_Complete4partiteDigraphCrossingNumber, function(arg...) - local k,l,m,n; + local k, l, m, n; k := arg[1][1]; l := arg[1][2]; m := arg[1][3]; n := Float(arg[1][4]); if k = 2 and l = 2 and m = 2 then - return Int(4 * (6*(Trunc(n/2) * Trunc((n-1)/2))+3*n)); + return Int(4 * (6 * (Trunc(n / 2) * Trunc((n - 1) / 2)) + 3 * n)); fi; return -1; end); @@ -695,7 +722,7 @@ end); # Compute the crossing number of a complete 5-partite digraph InstallGlobalFunction(DIGRAPHS_Complete5partiteDigraphCrossingNumber, function(arg...) - local j,k,l,m,n; + local j, k, l, m, n; j := arg[1][1]; k := arg[1][2]; l := arg[1][3]; @@ -703,9 +730,9 @@ InstallGlobalFunction(DIGRAPHS_Complete5partiteDigraphCrossingNumber, n := Float(arg[1][5]); # Ho (2009) if j = 1 and k = 1 and l = 1 and m = 1 then - return Int(4 * (2*(Trunc(n/2) * Trunc((n-1)/2))+n)); + return Int(4 * (2 * (Trunc(n / 2) * Trunc((n - 1) / 2)) + n)); elif j = 1 and k = 1 and l = 1 and m = 2 then - return Int(4 * (4*(Trunc(n/2) * Trunc((n-1)/2))+2*n)); + return Int(4 * (4 * (Trunc(n / 2) * Trunc((n - 1) / 2)) + 2 * n)); fi; return -1; end); @@ -713,7 +740,7 @@ end); # Compute the crossing number of a complete 6-partite digraph InstallGlobalFunction(DIGRAPHS_Complete6partiteDigraphCrossingNumber, function(arg...) - local i,j,k,l,m,n; + local i, j, k, l, m, n; i := arg[1][1]; j := arg[1][2]; k := arg[1][3]; @@ -722,7 +749,8 @@ InstallGlobalFunction(DIGRAPHS_Complete6partiteDigraphCrossingNumber, n := Float(arg[1][6]); # Lu and Huang if i = 1 and j = 1 and k = 1 and l = 1 and m = 1 then - return Int(4 * (4*(Trunc(n/2) * Trunc((n-1)/2))+2*n+1+Trunc(n/2))); + return Int(4 * (4 * (Trunc(n / 2) * + Trunc((n - 1) / 2)) + 2 * n + 1 + Trunc(n / 2))); fi; return -1; end); @@ -730,7 +758,7 @@ end); # Compute the crossing number of a complete tripartite digraph InstallGlobalFunction(DIGRAPHS_CompleteTripartiteDigraphCrossingNumber, function(arg...) - local l,m,n; + local l, m, n; l := arg[1][1]; m := arg[1][2]; n := Float(arg[1][3]); @@ -739,46 +767,52 @@ InstallGlobalFunction(DIGRAPHS_CompleteTripartiteDigraphCrossingNumber, elif l = 1 and m > 1 then if m = 2 then # Ho (2008) - return Int(4 * Trunc(n/2) * Trunc((n-1)/2)); + return Int(4 * Trunc(n / 2) * Trunc((n - 1) / 2)); elif m = 3 then # Asano - return Int(4 * (2* Trunc(n/2) * Trunc((n-1)/2) + Trunc(n/2))); + return Int(4 * (2 * Trunc(n / 2) * + Trunc((n - 1) / 2) + Trunc(n / 2))); elif m = 4 then # Huang and Zhao - return Int(4 * (4* Trunc(n/2) * Trunc((n-1)/2) + 2 * Trunc(n/2))); + return Int(4 * (4 * Trunc(n / 2) * + Trunc((n - 1) / 2) + 2 * Trunc(n / 2))); fi; elif l = 2 then if m = 2 then # Klesc and Schrotter - return Int(4 * 2 * Trunc(n/2) * Trunc((n-1)/2)); + return Int(4 * 2 * Trunc(n / 2) * Trunc((n - 1) / 2)); elif m = 3 then - # Asano - return Int(4 * (4 * Trunc(n/2) * Trunc((n-1)/2) + n)); + # Asano + return Int(4 * (4 * Trunc(n / 2) * Trunc((n - 1) / 2) + n)); elif m = 4 then # Ho (2013) - return Int(4 * (6* Trunc(n/2) * Trunc((n-1)/2) + 2*n)); + return Int(4 * (6 * Trunc(n / 2) * Trunc((n - 1) / 2) + 2 * n)); fi; fi; return -1; end); # Compute the crossing number of a complete bipartite digraph -InstallMethod(DIGRAPHS_CompleteBipartiteDigraphCrossingNumber, "for a bipartite digraph", [IsCompleteBipartiteDigraph], +InstallMethod(DIGRAPHS_CompleteBipartiteDigraphCrossingNumber, +"for a bipartite digraph", [IsCompleteBipartiteDigraph], function(D) local componentsSize, crossingNumber; if not IsCompleteBipartiteDigraph(D) then ErrorNoReturn("method only applicable for complete bipartite digraphs"); fi; componentsSize := CompleteMultipartiteDigraphPartitionSize(D); - # Zarankiewicz's theorem holds with equality for all m < 7 for Km,n where m <= n + # Zarankiewicz's theorem holds with equality for all m < 7 + # for Km,n where m <= n if componentsSize[1] < 7 then - crossingNumber := DIGRAPHS_ZarankiewiczTheorem(componentsSize[1],componentsSize[2]); - SetDigraphCrossingNumber(D,crossingNumber); + crossingNumber := + DIGRAPHS_ZarankiewiczTheorem(componentsSize[1], componentsSize[2]); + SetDigraphCrossingNumber(D, crossingNumber); return crossingNumber; # Zarankiewicz's theorem is also known to hold for K7,7-10 and K8,8-10 elif componentsSize[1] < 9 and componentsSize[2] < 11 then - crossingNumber := DIGRAPHS_ZarankiewiczTheorem(componentsSize[1],componentsSize[2]); - SetDigraphCrossingNumber(D,crossingNumber); + crossingNumber := + DIGRAPHS_ZarankiewiczTheorem(componentsSize[1], componentsSize[2]); + SetDigraphCrossingNumber(D, crossingNumber); return crossingNumber; else return -1; @@ -787,57 +821,66 @@ end); # Implementation of Zarankiewicz's theorem InstallGlobalFunction(DIGRAPHS_ZarankiewiczTheorem, - function(arg) + function(arg...) local m, n; m := Float(arg[1]); n := Float(arg[2]); - return Int(4 * Trunc(n/2) * Trunc((n-1)/2) * Trunc(m/2) * Trunc((m-1)/2)); + return Int(4 * Trunc(n / 2) * Trunc((n - 1) / 2) * + Trunc(m / 2) * Trunc((m - 1) / 2)); end); # Compute the partition sizes of a complete multipartite digraph -InstallMethod(CompleteMultipartiteDigraphPartitionSize, "for a complete multipartite digraph", [IsCompleteMultipartiteDigraph], +InstallMethod(CompleteMultipartiteDigraphPartitionSize, +"for a complete multipartite digraph", [IsCompleteMultipartiteDigraph], function(D) local i, neighbours, typesSeen, dictionary, componentsSize; # Create a dictionary for the set of outneighbours - dictionary := NewDictionary(Set(OutNeighbours(D)),true); + dictionary := NewDictionary(Set(OutNeighbours(D)), true); neighbours := OutNeighbors(D); typesSeen := []; componentsSize := []; - for i in [1..Length(neighbours)] do - # If we've already seen the outneighbours for a given vertex increment the number of times we've seen it + for i in [1 .. Length(neighbours)] do + # If we've already seen the outneighbours for a given vertex + # increment the number of times we've seen it if neighbours[i] in typesSeen then - AddDictionary(dictionary, neighbours[i], LookupDictionary(dictionary,neighbours[i])+1); + AddDictionary(dictionary, neighbours[i], + LookupDictionary(dictionary, neighbours[i]) + 1); else - # Otherwise add the outneighbours to the seen array and add it to the dictionary + # Otherwise add the outneighbours to the seen array + # and add it to the dictionary Append(typesSeen, [neighbours[i]]); - AddDictionary(dictionary,neighbours[i],1); + AddDictionary(dictionary, neighbours[i], 1); fi; od; # Add the number of times we have seen each neighbour set to an array - for i in [1..Length(typesSeen)] do - Add(componentsSize,LookupDictionary(dictionary,typesSeen[i])); + for i in [1 .. Length(typesSeen)] do + Add(componentsSize, LookupDictionary(dictionary, typesSeen[i])); od; # Sort the array due to conventional notation of CompleteMultidigraphs componentsSize := AsSortedList(componentsSize); - SetCompleteMultipartiteDigraphPartitionSize(D,componentsSize); + SetCompleteMultipartiteDigraphPartitionSize(D, componentsSize); return componentsSize; end); -# Compute the crossing number of a digraph if it is isomorphic to a circulant digraph with known crossing number +# Compute the crossing number of a digraph if +# it is isomorphic to a circulant digraph with known crossing number InstallGlobalFunction(DIGRAPHS_IsomorphicToCirculantGraphCrossingNumber, function(D) local n; n := DigraphNrVertices(D); - if n >= 8 and IsIsomorphicDigraph(D, CirculantGraph(n,[1,3])) then - return Trunc(Float(n)/3) + (n mod 3); - elif n >= 8 and n mod 2 = 0 and IsIsomorphicDigraph(D, CirculantGraph(n,[1,(n/2)-1])) then - return n/2; - elif n >= 3 and IsIsomorphicDigraph(D, CirculantGraph(3*n,[1,n])) then + if n >= 8 and IsIsomorphicDigraph(D, CirculantGraph(n, [1, 3])) then + return Trunc(Float(n) / 3) + (n mod 3); + elif n >= 8 and n mod 2 = 0 and + IsIsomorphicDigraph(D, CirculantGraph(n, [1, (n / 2) - 1])) then + return n / 2; + elif n >= 3 and IsIsomorphicDigraph(D, CirculantGraph(3 * n, [1, n])) then return n; - elif n >= 3 and IsIsomorphicDigraph(D, CirculantGraph(2*n+2,[1,n])) then - return n+1; - elif n >= 3 and IsIsomorphicDigraph(D, CirculantGraph(3*n+1,[1,n])) then - return n + 1; + elif n >= 3 and + IsIsomorphicDigraph(D, CirculantGraph(2 * n + 2, [1, n])) then + return n + 1; + elif n >= 3 and + IsIsomorphicDigraph(D, CirculantGraph(3 * n + 1, [1, n])) then + return n + 1; fi; return -1; end); From cd254041d165056b2bf78508bb6da7ff9a257189 Mon Sep 17 00:00:00 2001 From: Mark Toner Date: Mon, 2 Jun 2025 14:47:09 +0100 Subject: [PATCH 08/13] Fixed some errors introduced during linting, albertson off by 1 error --- gap/crossing-number.gd | 9 +++------ gap/crossing-number.gi | 42 ++++++++++++++---------------------------- 2 files changed, 17 insertions(+), 34 deletions(-) diff --git a/gap/crossing-number.gd b/gap/crossing-number.gd index 7c8d973e8..395eb8905 100644 --- a/gap/crossing-number.gd +++ b/gap/crossing-number.gd @@ -28,9 +28,6 @@ DeclareAttribute("SemicompleteDigraphCrossingNumber", IsSemicompleteDigraph); DeclareAttribute("DigraphAllThreeCycles", IsDigraph); DeclareAttribute("DigraphAllTriangles", IsDigraph); DeclareAttribute("DigraphLargePlanarSubdigraph", IsDigraph); -DeclareAttribute("DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber", - IsCompleteMultipartiteDigraph); -DeclareAttribute("DIGRAPHS_CompleteBipartiteDigraphCrossingNumber", - IsCompleteBipartiteDigraph); -DeclareAttribute("CompleteMultipartiteDigraphPartitionSize", - IsCompleteMultipartiteDigraph); \ No newline at end of file +DeclareAttribute("DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber", IsCompleteMultipartiteDigraph); +DeclareAttribute("DIGRAPHS_CompleteBipartiteDigraphCrossingNumber", IsCompleteBipartiteDigraph); +DeclareAttribute("CompleteMultipartiteDigraphPartitionSize", IsCompleteMultipartiteDigraph); \ No newline at end of file diff --git a/gap/crossing-number.gi b/gap/crossing-number.gi index fb52042b7..cb8ce9ed4 100644 --- a/gap/crossing-number.gi +++ b/gap/crossing-number.gi @@ -7,8 +7,7 @@ InstallMethod(DIGRAPHS_TournamentCrossingNumber, "for a tournament", ErrorNoReturn("argument must be a tournament"); fi; # Array of known crossing numbers for tournaments from 0 - 14 vertices - KnownCrossingNumberArray := [0, 0, 0, 0, 0, 1, 3, 9, 18, 36, 60, 100, - 150, 225, 315]; + KnownCrossingNumberArray := [0, 0, 0, 0, 0, 1, 3, 9, 18, 36, 60, 100, 150, 225, 315]; n := DigraphNrVertices(D); if n < 15 then SetDigraphCrossingNumber(D, KnownCrossingNumberArray[n + 1]); @@ -54,8 +53,7 @@ InstallGlobalFunction(DIGRAPHS_CrossingNumberInequality, fi; # Otherwise we use a different one else - temp := ((Float(e ^ 3)) / (29 * (Float(n) ^ 2))) - - (35 / 29) * Float(n); + temp := ((Float(e ^ 3)) / (29 * (Float(n) ^ 2))) - (35 / 29) * Float(n); temp := DIGRAPHS_CrossingNumberRound(temp); if temp > res then res := temp; @@ -81,11 +79,9 @@ InstallGlobalFunction(DIGRAPHS_GetCompleteDigraphCrossingNumber, function(n) local KnownCrossingNumberArray; if n > 15 then - ErrorNoReturn("Crossing number unknown for digraph on this - number of vertices"); + ErrorNoReturn("Crossing number unknown for digraph on this number of vertices"); fi; - KnownCrossingNumberArray := [0, 0, 0, 0, 0, 4, 12, 36, 72, 144, - 240, 400, 600, 900, 1260]; + KnownCrossingNumberArray := [0, 0, 0, 0, 0, 4, 12, 36, 72, 144, 240, 400, 600, 900, 1260]; # +1 due to first array index being 1 representing n=0 return KnownCrossingNumberArray[n + 1]; end); @@ -107,8 +103,7 @@ InstallMethod(DIGRAPHS_CompleteDigraphCrossingNumber, SetDigraphCrossingNumber(D, completeDigraphCrossingNumber); return completeDigraphCrossingNumber; elif n >= 15 then - ErrorNoReturn("Complete Digraph contains too many - vertices for known crossing number"); + ErrorNoReturn("Complete Digraph contains too many vertices for known crossing number"); fi; end); @@ -431,8 +426,7 @@ function(D) # Guy's Theorem (Valid for all non-multi digraphs) if not IsMultiDigraph(D) then n := Float(n); - temp := Trunc(n / 2) * Trunc((n - 1) / 2) * - Trunc((n - 2) / 2) * Trunc((n - 3) / 2); + temp := Trunc(n / 2) * Trunc((n - 1) / 2) * Trunc((n - 2) / 2) * Trunc((n - 3) / 2); if temp < res then res := temp; fi; @@ -500,8 +494,7 @@ InstallGlobalFunction(DIGRAPHS_CrossingNumberAlbertson, # Chromatic number must be less than 16 as that is # the highest complete digraph we have a known cn for if chromaticNumber < 15 then - return DIGRAPHS_GetCompleteDigraphCrossingNumber(chromaticNumber - + 1) / 4; + return DIGRAPHS_GetCompleteDigraphCrossingNumber(chromaticNumber) / 4; else # Chromatic number too large for known crossing number return -1; @@ -678,8 +671,7 @@ InstallMethod(DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber, function(D) local componentsSize, crossingNumber; if not IsCompleteMultipartiteDigraph(D) then - ErrorNoReturn("method only applicable for - complete multipartite digraphs"); + ErrorNoReturn("method only applicable for complete multipartite digraphs"); fi; componentsSize := CompleteMultipartiteDigraphPartitionSize(D); if Length(componentsSize) = 3 then @@ -749,8 +741,7 @@ InstallGlobalFunction(DIGRAPHS_Complete6partiteDigraphCrossingNumber, n := Float(arg[1][6]); # Lu and Huang if i = 1 and j = 1 and k = 1 and l = 1 and m = 1 then - return Int(4 * (4 * (Trunc(n / 2) * - Trunc((n - 1) / 2)) + 2 * n + 1 + Trunc(n / 2))); + return Int(4 * (4 * (Trunc(n / 2) * Trunc((n - 1) / 2)) + 2 * n + 1 + Trunc(n / 2))); fi; return -1; end); @@ -770,12 +761,10 @@ InstallGlobalFunction(DIGRAPHS_CompleteTripartiteDigraphCrossingNumber, return Int(4 * Trunc(n / 2) * Trunc((n - 1) / 2)); elif m = 3 then # Asano - return Int(4 * (2 * Trunc(n / 2) * - Trunc((n - 1) / 2) + Trunc(n / 2))); + return Int(4 * (2 * Trunc(n / 2) * Trunc((n - 1) / 2) + Trunc(n / 2))); elif m = 4 then # Huang and Zhao - return Int(4 * (4 * Trunc(n / 2) * - Trunc((n - 1) / 2) + 2 * Trunc(n / 2))); + return Int(4 * (4 * Trunc(n / 2) * Trunc((n - 1) / 2) + 2 * Trunc(n / 2))); fi; elif l = 2 then if m = 2 then @@ -825,13 +814,11 @@ InstallGlobalFunction(DIGRAPHS_ZarankiewiczTheorem, local m, n; m := Float(arg[1]); n := Float(arg[2]); - return Int(4 * Trunc(n / 2) * Trunc((n - 1) / 2) * - Trunc(m / 2) * Trunc((m - 1) / 2)); + return Int(4 * Trunc(n / 2) * Trunc((n - 1) / 2) * Trunc(m / 2) * Trunc((m - 1) / 2)); end); # Compute the partition sizes of a complete multipartite digraph -InstallMethod(CompleteMultipartiteDigraphPartitionSize, -"for a complete multipartite digraph", [IsCompleteMultipartiteDigraph], +InstallMethod(CompleteMultipartiteDigraphPartitionSize, "for a complete multipartite digraph", [IsCompleteMultipartiteDigraph], function(D) local i, neighbours, typesSeen, dictionary, componentsSize; # Create a dictionary for the set of outneighbours @@ -843,8 +830,7 @@ InstallMethod(CompleteMultipartiteDigraphPartitionSize, # If we've already seen the outneighbours for a given vertex # increment the number of times we've seen it if neighbours[i] in typesSeen then - AddDictionary(dictionary, neighbours[i], - LookupDictionary(dictionary, neighbours[i]) + 1); + AddDictionary(dictionary, neighbours[i], LookupDictionary(dictionary, neighbours[i]) + 1); else # Otherwise add the outneighbours to the seen array # and add it to the dictionary From b3ffb26207cbd58ae1eeb38358420becf169dab7 Mon Sep 17 00:00:00 2001 From: Mark Toner Date: Wed, 4 Jun 2025 13:07:56 +0100 Subject: [PATCH 09/13] Fixed indentation errors --- gap/crossing-number.gd | 2 +- gap/crossing-number.gi | 17 +++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/gap/crossing-number.gd b/gap/crossing-number.gd index 395eb8905..c8d6eb8bd 100644 --- a/gap/crossing-number.gd +++ b/gap/crossing-number.gd @@ -28,6 +28,6 @@ DeclareAttribute("SemicompleteDigraphCrossingNumber", IsSemicompleteDigraph); DeclareAttribute("DigraphAllThreeCycles", IsDigraph); DeclareAttribute("DigraphAllTriangles", IsDigraph); DeclareAttribute("DigraphLargePlanarSubdigraph", IsDigraph); -DeclareAttribute("DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber", IsCompleteMultipartiteDigraph); +DeclareAttribute("DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber",IsCompleteMultipartiteDigraph); DeclareAttribute("DIGRAPHS_CompleteBipartiteDigraphCrossingNumber", IsCompleteBipartiteDigraph); DeclareAttribute("CompleteMultipartiteDigraphPartitionSize", IsCompleteMultipartiteDigraph); \ No newline at end of file diff --git a/gap/crossing-number.gi b/gap/crossing-number.gi index cb8ce9ed4..c8d2ae621 100644 --- a/gap/crossing-number.gi +++ b/gap/crossing-number.gi @@ -136,7 +136,7 @@ InstallGlobalFunction(DIGRAPHS_IsK22FreeDigraph, # two distinct unconnected vertices. This means there is K2,2 subgraph # Create boolean adjacency matrix adjacencyMatrix := BooleanAdjacencyMatrix(D); - neighbours := OutNeighbors(D); + neighbours := OutNeighbours(D); vertices := DigraphVertices(D); for i in vertices do for jCount in [i + 1 .. numberVertices] do @@ -629,8 +629,7 @@ InstallMethod(DigraphAllTriangles, "for a digraph", [IsDigraph], end); # Add an artificial vertex between two given edges -InstallMethod(DigraphAddVertexCrossingPoint, "for a digraph, - list, and list", [IsDigraph, IsList, IsList], +InstallMethod(DigraphAddVertexCrossingPoint, "for a digraph, list, and list", [IsDigraph, IsList, IsList], function(arg...) local n, D, Edge1, Edge2; if IsEmpty(arg) then @@ -661,13 +660,11 @@ InstallMethod(DigraphAddVertexCrossingPoint, "for a digraph, D := DigraphRemoveEdge(D, Edge2); # Add the new edges in (between E1 source and artificial vertex, # artificial vertex and E1 destination. Same for E2) - return DigraphAddEdges(D, [[Edge1[1], n], [n, Edge1[2]], - [Edge2[1], n], [n, Edge2[2]]]); + return DigraphAddEdges(D, [[Edge1[1], n], [n, Edge1[2]], [Edge2[1], n], [n, Edge2[2]]]); end); # Compute crossing number of a complete multipartite digraphs -InstallMethod(DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber, -"for a multipartite digraph", [IsCompleteMultipartiteDigraph], +InstallMethod(DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber, "for a multipartite digraph", [IsCompleteMultipartiteDigraph], function(D) local componentsSize, crossingNumber; if not IsCompleteMultipartiteDigraph(D) then @@ -782,8 +779,7 @@ InstallGlobalFunction(DIGRAPHS_CompleteTripartiteDigraphCrossingNumber, end); # Compute the crossing number of a complete bipartite digraph -InstallMethod(DIGRAPHS_CompleteBipartiteDigraphCrossingNumber, -"for a bipartite digraph", [IsCompleteBipartiteDigraph], +InstallMethod(DIGRAPHS_CompleteBipartiteDigraphCrossingNumber, "for a bipartite digraph", [IsCompleteBipartiteDigraph], function(D) local componentsSize, crossingNumber; if not IsCompleteBipartiteDigraph(D) then @@ -823,7 +819,7 @@ InstallMethod(CompleteMultipartiteDigraphPartitionSize, "for a complete multipar local i, neighbours, typesSeen, dictionary, componentsSize; # Create a dictionary for the set of outneighbours dictionary := NewDictionary(Set(OutNeighbours(D)), true); - neighbours := OutNeighbors(D); + neighbours := OutNeighbours(D); typesSeen := []; componentsSize := []; for i in [1 .. Length(neighbours)] do @@ -848,6 +844,7 @@ InstallMethod(CompleteMultipartiteDigraphPartitionSize, "for a complete multipar return componentsSize; end); + # Compute the crossing number of a digraph if # it is isomorphic to a circulant digraph with known crossing number InstallGlobalFunction(DIGRAPHS_IsomorphicToCirculantGraphCrossingNumber, From 0aa653ee5658ae1f5b0f48526674aa48263d6854 Mon Sep 17 00:00:00 2001 From: Mark Toner Date: Wed, 4 Jun 2025 13:45:37 +0100 Subject: [PATCH 10/13] Linted tst file --- gap/crossing-number.gd | 9 ++-- gap/crossing-number.gi | 65 ++++++++++++++-------- tst/standard/crossingnumber.tst | 96 ++++++++++++++++----------------- 3 files changed, 97 insertions(+), 73 deletions(-) diff --git a/gap/crossing-number.gd b/gap/crossing-number.gd index c8d6eb8bd..17a448aad 100644 --- a/gap/crossing-number.gd +++ b/gap/crossing-number.gd @@ -28,6 +28,9 @@ DeclareAttribute("SemicompleteDigraphCrossingNumber", IsSemicompleteDigraph); DeclareAttribute("DigraphAllThreeCycles", IsDigraph); DeclareAttribute("DigraphAllTriangles", IsDigraph); DeclareAttribute("DigraphLargePlanarSubdigraph", IsDigraph); -DeclareAttribute("DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber",IsCompleteMultipartiteDigraph); -DeclareAttribute("DIGRAPHS_CompleteBipartiteDigraphCrossingNumber", IsCompleteBipartiteDigraph); -DeclareAttribute("CompleteMultipartiteDigraphPartitionSize", IsCompleteMultipartiteDigraph); \ No newline at end of file +DeclareAttribute("DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber", + IsCompleteMultipartiteDigraph); +DeclareAttribute("DIGRAPHS_CompleteBipartiteDigraphCrossingNumber", + IsCompleteBipartiteDigraph); +DeclareAttribute("CompleteMultipartiteDigraphPartitionSize", + IsCompleteMultipartiteDigraph); \ No newline at end of file diff --git a/gap/crossing-number.gi b/gap/crossing-number.gi index c8d2ae621..df3ed14de 100644 --- a/gap/crossing-number.gi +++ b/gap/crossing-number.gi @@ -7,7 +7,8 @@ InstallMethod(DIGRAPHS_TournamentCrossingNumber, "for a tournament", ErrorNoReturn("argument must be a tournament"); fi; # Array of known crossing numbers for tournaments from 0 - 14 vertices - KnownCrossingNumberArray := [0, 0, 0, 0, 0, 1, 3, 9, 18, 36, 60, 100, 150, 225, 315]; + KnownCrossingNumberArray := + [0, 0, 0, 0, 0, 1, 3, 9, 18, 36, 60, 100, 150, 225, 315]; n := DigraphNrVertices(D); if n < 15 then SetDigraphCrossingNumber(D, KnownCrossingNumberArray[n + 1]); @@ -53,7 +54,9 @@ InstallGlobalFunction(DIGRAPHS_CrossingNumberInequality, fi; # Otherwise we use a different one else - temp := ((Float(e ^ 3)) / (29 * (Float(n) ^ 2))) - (35 / 29) * Float(n); + temp := + ((Float(e ^ 3)) / (29 * (Float(n) ^ 2))) - + (35 / 29) * Float(n); temp := DIGRAPHS_CrossingNumberRound(temp); if temp > res then res := temp; @@ -79,9 +82,11 @@ InstallGlobalFunction(DIGRAPHS_GetCompleteDigraphCrossingNumber, function(n) local KnownCrossingNumberArray; if n > 15 then - ErrorNoReturn("Crossing number unknown for digraph on this number of vertices"); + ErrorNoReturn("Crossing number unknown for digraph on this number", + "of vertices"); fi; - KnownCrossingNumberArray := [0, 0, 0, 0, 0, 4, 12, 36, 72, 144, 240, 400, 600, 900, 1260]; + KnownCrossingNumberArray := + [0, 0, 0, 0, 0, 4, 12, 36, 72, 144, 240, 400, 600, 900, 1260]; # +1 due to first array index being 1 representing n=0 return KnownCrossingNumberArray[n + 1]; end); @@ -103,7 +108,8 @@ InstallMethod(DIGRAPHS_CompleteDigraphCrossingNumber, SetDigraphCrossingNumber(D, completeDigraphCrossingNumber); return completeDigraphCrossingNumber; elif n >= 15 then - ErrorNoReturn("Complete Digraph contains too many vertices for known crossing number"); + ErrorNoReturn("Complete Digraph contains too many vertices", + " for known crossing number"); fi; end); @@ -426,7 +432,8 @@ function(D) # Guy's Theorem (Valid for all non-multi digraphs) if not IsMultiDigraph(D) then n := Float(n); - temp := Trunc(n / 2) * Trunc((n - 1) / 2) * Trunc((n - 2) / 2) * Trunc((n - 3) / 2); + temp := Trunc(n / 2) * Trunc((n - 1) / 2) * + Trunc((n - 2) / 2) * Trunc((n - 3) / 2); if temp < res then res := temp; fi; @@ -494,7 +501,8 @@ InstallGlobalFunction(DIGRAPHS_CrossingNumberAlbertson, # Chromatic number must be less than 16 as that is # the highest complete digraph we have a known cn for if chromaticNumber < 15 then - return DIGRAPHS_GetCompleteDigraphCrossingNumber(chromaticNumber) / 4; + return DIGRAPHS_GetCompleteDigraphCrossingNumber(chromaticNumber) / + 4; else # Chromatic number too large for known crossing number return -1; @@ -629,7 +637,8 @@ InstallMethod(DigraphAllTriangles, "for a digraph", [IsDigraph], end); # Add an artificial vertex between two given edges -InstallMethod(DigraphAddVertexCrossingPoint, "for a digraph, list, and list", [IsDigraph, IsList, IsList], +InstallMethod(DigraphAddVertexCrossingPoint, "for a digraph, list, and list", + [IsDigraph, IsList, IsList], function(arg...) local n, D, Edge1, Edge2; if IsEmpty(arg) then @@ -660,15 +669,18 @@ InstallMethod(DigraphAddVertexCrossingPoint, "for a digraph, list, and list", [I D := DigraphRemoveEdge(D, Edge2); # Add the new edges in (between E1 source and artificial vertex, # artificial vertex and E1 destination. Same for E2) - return DigraphAddEdges(D, [[Edge1[1], n], [n, Edge1[2]], [Edge2[1], n], [n, Edge2[2]]]); + return DigraphAddEdges(D, [[Edge1[1], n], [n, Edge1[2]], [Edge2[1], n], + [n, Edge2[2]]]); end); # Compute crossing number of a complete multipartite digraphs -InstallMethod(DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber, "for a multipartite digraph", [IsCompleteMultipartiteDigraph], +InstallMethod(DIGRAPHS_CompleteMultipartiteDigraphCrossingNumber, + "for a multipartite digraph", [IsCompleteMultipartiteDigraph], function(D) local componentsSize, crossingNumber; if not IsCompleteMultipartiteDigraph(D) then - ErrorNoReturn("method only applicable for complete multipartite digraphs"); + ErrorNoReturn("method only applicable for complete", + "multipartite digraphs"); fi; componentsSize := CompleteMultipartiteDigraphPartitionSize(D); if Length(componentsSize) = 3 then @@ -738,7 +750,8 @@ InstallGlobalFunction(DIGRAPHS_Complete6partiteDigraphCrossingNumber, n := Float(arg[1][6]); # Lu and Huang if i = 1 and j = 1 and k = 1 and l = 1 and m = 1 then - return Int(4 * (4 * (Trunc(n / 2) * Trunc((n - 1) / 2)) + 2 * n + 1 + Trunc(n / 2))); + return Int(4 * (4 * (Trunc(n / 2) * Trunc((n - 1) / 2)) + + 2 * n + 1 + Trunc(n / 2))); fi; return -1; end); @@ -755,13 +768,16 @@ InstallGlobalFunction(DIGRAPHS_CompleteTripartiteDigraphCrossingNumber, elif l = 1 and m > 1 then if m = 2 then # Ho (2008) - return Int(4 * Trunc(n / 2) * Trunc((n - 1) / 2)); + return Int(4 * Trunc(n / 2) * + Trunc((n - 1) / 2)); elif m = 3 then # Asano - return Int(4 * (2 * Trunc(n / 2) * Trunc((n - 1) / 2) + Trunc(n / 2))); + return Int(4 * (2 * Trunc(n / 2) * Trunc((n - 1) / 2) + + Trunc(n / 2))); elif m = 4 then # Huang and Zhao - return Int(4 * (4 * Trunc(n / 2) * Trunc((n - 1) / 2) + 2 * Trunc(n / 2))); + return Int(4 * (4 * Trunc(n / 2) * Trunc((n - 1) / 2) + + 2 * Trunc(n / 2))); fi; elif l = 2 then if m = 2 then @@ -769,17 +785,20 @@ InstallGlobalFunction(DIGRAPHS_CompleteTripartiteDigraphCrossingNumber, return Int(4 * 2 * Trunc(n / 2) * Trunc((n - 1) / 2)); elif m = 3 then # Asano - return Int(4 * (4 * Trunc(n / 2) * Trunc((n - 1) / 2) + n)); + return Int(4 * (4 * Trunc(n / 2) * + Trunc((n - 1) / 2) + n)); elif m = 4 then # Ho (2013) - return Int(4 * (6 * Trunc(n / 2) * Trunc((n - 1) / 2) + 2 * n)); + return Int(4 * (6 * Trunc(n / 2) * + Trunc((n - 1) / 2) + 2 * n)); fi; fi; return -1; end); # Compute the crossing number of a complete bipartite digraph -InstallMethod(DIGRAPHS_CompleteBipartiteDigraphCrossingNumber, "for a bipartite digraph", [IsCompleteBipartiteDigraph], +InstallMethod(DIGRAPHS_CompleteBipartiteDigraphCrossingNumber, + "for a bipartite digraph", [IsCompleteBipartiteDigraph], function(D) local componentsSize, crossingNumber; if not IsCompleteBipartiteDigraph(D) then @@ -810,11 +829,13 @@ InstallGlobalFunction(DIGRAPHS_ZarankiewiczTheorem, local m, n; m := Float(arg[1]); n := Float(arg[2]); - return Int(4 * Trunc(n / 2) * Trunc((n - 1) / 2) * Trunc(m / 2) * Trunc((m - 1) / 2)); + return Int(4 * Trunc(n / 2) * Trunc((n - 1) / 2) * + Trunc(m / 2) * Trunc((m - 1) / 2)); end); # Compute the partition sizes of a complete multipartite digraph -InstallMethod(CompleteMultipartiteDigraphPartitionSize, "for a complete multipartite digraph", [IsCompleteMultipartiteDigraph], +InstallMethod(CompleteMultipartiteDigraphPartitionSize, + "for a complete multipartite digraph", [IsCompleteMultipartiteDigraph], function(D) local i, neighbours, typesSeen, dictionary, componentsSize; # Create a dictionary for the set of outneighbours @@ -826,7 +847,8 @@ InstallMethod(CompleteMultipartiteDigraphPartitionSize, "for a complete multipar # If we've already seen the outneighbours for a given vertex # increment the number of times we've seen it if neighbours[i] in typesSeen then - AddDictionary(dictionary, neighbours[i], LookupDictionary(dictionary, neighbours[i]) + 1); + AddDictionary(dictionary, neighbours[i], + LookupDictionary(dictionary, neighbours[i]) + 1); else # Otherwise add the outneighbours to the seen array # and add it to the dictionary @@ -844,7 +866,6 @@ InstallMethod(CompleteMultipartiteDigraphPartitionSize, "for a complete multipar return componentsSize; end); - # Compute the crossing number of a digraph if # it is isomorphic to a circulant digraph with known crossing number InstallGlobalFunction(DIGRAPHS_IsomorphicToCirculantGraphCrossingNumber, diff --git a/tst/standard/crossingnumber.tst b/tst/standard/crossingnumber.tst index 131de8750..90dad2d9f 100644 --- a/tst/standard/crossingnumber.tst +++ b/tst/standard/crossingnumber.tst @@ -9,13 +9,13 @@ gap> DIGRAPHS_StartTest(); # Tests function for finding crossing number of Complete Digraphs # Test for Complete Digraph on 0 vertices -gap> D:= CompleteDigraph(0); +gap> D := CompleteDigraph(0); gap> DIGRAPHS_CompleteDigraphCrossingNumber(D); 0 # Test for non-Complete Digraph -gap> D:= CompleteBipartiteDigraph(3,3); +gap> D := CompleteBipartiteDigraph(3, 3); gap> DIGRAPHS_CompleteDigraphCrossingNumber(D); Error, no method found! For debugging hints type ?Recovery from NoMethodFound @@ -23,13 +23,13 @@ Error, no 2nd choice method found for `DIGRAPHS_CompleteDigraphCrossingNumber'\ on 1 arguments # Test for Complete Digraph on 14 vertices -gap> D:= CompleteDigraph(14); +gap> D := CompleteDigraph(14); gap> DIGRAPHS_CompleteDigraphCrossingNumber(D); 1260 # Test for Complete Digraph on 15 vertices -gap> D:= CompleteDigraph(15); +gap> D := CompleteDigraph(15); gap> DIGRAPHS_CompleteDigraphCrossingNumber(D); Error, Complete Digraph contains too many vertices for known crossing number @@ -37,32 +37,32 @@ Error, Complete Digraph contains too many vertices for known crossing number # Tests function for finding partitions size of CompleteMultipartiteDigraph # Test for complete bipartite digraph -gap> D := CompleteBipartiteDigraph(2,3); +gap> D := CompleteBipartiteDigraph(2, 3); gap> CompleteMultipartiteDigraphPartitionSize(D); [ 2, 3 ] # Test for valid complete multipartite digraph (1) -gap> D := CompleteMultipartiteDigraph([2,3,4]); +gap> D := CompleteMultipartiteDigraph([2, 3, 4]); gap> CompleteMultipartiteDigraphPartitionSize(D); [ 2, 3, 4 ] # Test for valid complete multipartite digraph (2) -gap> D := CompleteMultipartiteDigraph([1,1,2,3]); +gap> D := CompleteMultipartiteDigraph([1, 1, 2, 3]); gap> CompleteMultipartiteDigraphPartitionSize(D); [ 1, 1, 2, 3 ] # tests for DIGRAPHS_CrossingNumberInequality function # test crossing number is 0 for planar Graph -gap> D:= WindmillGraph(4,3); +gap> D := WindmillGraph(4, 3); gap> DIGRAPHS_CrossingNumberInequality(D); 0 # test crossing number is correct for a graph with e >= 6.95n (1) -gap> D:= CompleteDigraph(10); +gap> D := CompleteDigraph(10); gap> DIGRAPHS_CrossingNumberInequality(D); 252 @@ -92,7 +92,7 @@ gap> DIGRAPHS_CrossingNumberInequality(D); 0 # test crossing number for graph with no edges -gap> D := Digraph([[],[],[],[],[]]); +gap> D := Digraph([[], [], [], [], []]); gap> DIGRAPHS_CrossingNumberInequality(D); 0 @@ -100,32 +100,32 @@ gap> DIGRAPHS_CrossingNumberInequality(D); # Cubic Digraph Construction tests # Test for 0 vertices -gap> D:= RandomDigraph(IsCubicDigraph,0); +gap> D := RandomDigraph(IsCubicDigraph, 0); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `RandomDigraph' on 2 arguments # Test for 2 vertices -gap> D:= RandomDigraph(IsCubicDigraph,2); +gap> D := RandomDigraph(IsCubicDigraph, 2); Error, Cubic Digraphs must have at least 4 vertices # Test for 4 vertices -gap> D:= RandomDigraph(IsCubicDigraph,4); +gap> D := RandomDigraph(IsCubicDigraph, 4); # Test for 7 vertices -gap> D:= RandomDigraph(IsCubicDigraph,7); +gap> D := RandomDigraph(IsCubicDigraph, 7); Error, Cubic Digraphs exist only for even vertices # Test for 10 vertices -gap> D:= RandomDigraph(IsCubicDigraph,10); +gap> D := RandomDigraph(IsCubicDigraph, 10); # Test for 500 vertices -gap> D:= RandomDigraph(IsCubicDigraph,500); +gap> D := RandomDigraph(IsCubicDigraph, 500); # Test for 2000 vertices -gap> D:= RandomDigraph(IsCubicDigraph,2000); +gap> D := RandomDigraph(IsCubicDigraph, 2000); # Tests for finding all triangles in a digraph @@ -148,12 +148,12 @@ gap> DigraphAllThreeCycles(D); [ 1, 4, 3 ], [ 2, 3, 4 ], [ 2, 4, 3 ] ] # Test for a regular expected digraph (2) -gap> D := Digraph([[2],[3],[1]]);; +gap> D := Digraph([[2], [3], [1]]);; gap> DigraphAllThreeCycles(D); [ [ 1, 2, 3 ] ] # Test for a regular expected digraph (3) -gap> D := Digraph([[2,4,5],[1,3],[1,5],[5],[1,4]]);; +gap> D := Digraph([[2, 4, 5], [1, 3], [1, 5], [5], [1, 4]]);; gap> DigraphAllThreeCycles(D); [ [ 1, 2, 3 ], [ 1, 4, 5 ] ] @@ -177,45 +177,45 @@ gap> DigraphAllTriangles(D); [ [ 1, 2, 3 ], [ 1, 2, 4 ], [ 1, 3, 4 ], [ 2, 3, 4 ] ] # Test for a regular expected digraph (2) -gap> D := Digraph([[2],[3],[1]]);; +gap> D := Digraph([[2], [3], [1]]);; gap> DigraphAllTriangles(D); [ [ 1, 2, 3 ] ] # Test for a regular expected digraph (3) -gap> D := Digraph([[2,4,5],[1,3],[1,5],[5],[4]]);; +gap> D := Digraph([[2, 4, 5], [1, 3], [1, 5], [5], [4]]);; gap> DigraphAllTriangles(D); [ [ 1, 2, 3 ], [ 1, 3, 5 ], [ 1, 4, 5 ] ] # tests for DIGRAPHS_CrossingNumberAlbertson function # Test that the method fails for a digraph with loops -gap> D:= CompleteDigraph(5); +gap> D := CompleteDigraph(5); -gap> D:=DigraphAddAllLoops(D); +gap> D := DigraphAddAllLoops(D); gap> DIGRAPHS_CrossingNumberAlbertson(D); Error, the argument must be a digraph with no loops, # Test for digraph with valid chromatic number (1) -gap> D:= CompleteDigraph(5); +gap> D := CompleteDigraph(5); gap> DIGRAPHS_CrossingNumberAlbertson(D); 1 # Test for digraph with valid chromatic number (2) -gap> D:= CompleteDigraph(10); +gap> D := CompleteDigraph(10); gap> DIGRAPHS_CrossingNumberAlbertson(D); 60 # Test for digraph with valid chromatic number (3) -gap> D:= CompleteBipartiteDigraph(2,5); +gap> D := CompleteBipartiteDigraph(2, 5); gap> DIGRAPHS_CrossingNumberAlbertson(D); 0 # Test for digraph with chromatic number higher than 14 -gap> D:= CompleteDigraph(15); +gap> D := CompleteDigraph(15); gap> DIGRAPHS_CrossingNumberAlbertson(D); -1 @@ -233,12 +233,12 @@ gap> IsCubicDigraph(D); true # Test for a cubic digraph (2) -gap> D := Digraph([[4,5],[3,4,6],[5,6],[5],[],[1]]);; +gap> D := Digraph([[4, 5], [3, 4, 6], [5, 6], [5], [], [1]]);; gap> IsCubicDigraph(D); true # Test for a non cubic digraph (1) -gap> D := CompleteBipartiteDigraph(3,3);; +gap> D := CompleteBipartiteDigraph(3, 3);; gap> IsCubicDigraph(D); false @@ -261,13 +261,13 @@ false # Tests to determine if a digraph is semicomplete or not # Test for a semicomplete digraph (1) -gap> D:= Digraph([[2,3],[3],[]]); +gap> D := Digraph([[2, 3], [3], []]); gap> IsSemicompleteDigraph(D); true # Test for a semicomplete digraph (2) -gap> D:= Digraph([[2,3,4,5],[3,5],[4],[1,2],[1,2,3,4]]); +gap> D := Digraph([[2, 3, 4, 5], [3, 5], [4], [1, 2], [1, 2, 3, 4]]); gap> IsSemicompleteDigraph(D); true @@ -305,25 +305,25 @@ false # tests for DIGRAPHS_IsK22FreeDigraph function # test that a complete digraph is K22-free -gap> D:= CompleteDigraph(9); +gap> D := CompleteDigraph(9); gap> DIGRAPHS_IsK22FreeDigraph(D); true # test that a complete bipartite graph is not K22-free -gap> D:= CompleteBipartiteDigraph(3,2); +gap> D := CompleteBipartiteDigraph(3, 2); gap> DIGRAPHS_IsK22FreeDigraph(D); false # test that a digraph with fewer than 4 vertices is K22-free -gap> D:= CompleteDigraph(3); +gap> D := CompleteDigraph(3); gap> DIGRAPHS_IsK22FreeDigraph(D); true # test that a digraph that is not K2,2 free is correctly identified as such -gap> D:= Digraph([[3,4],[3,4],[1,2],[1,2]]); +gap> D := Digraph([[3, 4], [3, 4], [1, 2], [1, 2]]); gap> DIGRAPHS_IsK22FreeDigraph(D); false @@ -331,51 +331,51 @@ false # Tests for random semicomplete digraph generation # Test for n = 10, p not given -gap> D:= RandomDigraph(IsSemicompleteDigraph,10);; +gap> D := RandomDigraph(IsSemicompleteDigraph, 10);; gap> IsSemicompleteDigraph(D); true # Test for n = 3, p not given -gap> D:= RandomDigraph(IsSemicompleteDigraph,3);; +gap> D := RandomDigraph(IsSemicompleteDigraph, 3);; gap> IsSemicompleteDigraph(D); true # Test for n = 9, p=0 -gap> D:= RandomDigraph(IsSemicompleteDigraph,9);; +gap> D := RandomDigraph(IsSemicompleteDigraph, 9);; gap> IsSemicompleteDigraph(D); true # Test for n = 9, p=1 -gap> D:= RandomDigraph(IsSemicompleteDigraph,9,1);; +gap> D := RandomDigraph(IsSemicompleteDigraph, 9, 1);; gap> IsSemicompleteDigraph(D); true # Test for n = 9, p=0.5 -gap> D:= RandomDigraph(IsSemicompleteDigraph,9,0.5);; +gap> D := RandomDigraph(IsSemicompleteDigraph, 9, 0.5);; gap> IsSemicompleteDigraph(D); true # Test for n=-1 -gap> D:= RandomDigraph(IsSemicompleteDigraph,-1); +gap> D := RandomDigraph(IsSemicompleteDigraph, -1); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `RandomDigraph' on 2 arguments # Test for n=1, p=-1 -gap> D:= RandomDigraph(IsSemicompleteDigraph,1,-1); +gap> D := RandomDigraph(IsSemicompleteDigraph, 1, -1); # Test for n=1, p=1.1 -gap> D:= RandomDigraph(IsSemicompleteDigraph,1,1.1);; +gap> D := RandomDigraph(IsSemicompleteDigraph, 1, 1.1);; gap> IsSemicompleteDigraph(D); true # Test for n=s, p=1 -gap> D:= RandomDigraph(IsSemicompleteDigraph,"s",-1); +gap> D := RandomDigraph(IsSemicompleteDigraph, "s", -1); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `RandomDigraph' on 3 arguments # Test for no n,p -gap> D:= RandomDigraph(IsSemicompleteDigraph); +gap> D := RandomDigraph(IsSemicompleteDigraph); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `RandomDigraph' on 1 arguments @@ -404,19 +404,19 @@ gap> SemicompleteDigraphCrossingNumber(D); # Tests function for finding crossing number of Tournaments # Test for tournament on 0 vertices -gap> D:= RandomTournament(0); +gap> D := RandomTournament(0); gap> DIGRAPHS_TournamentCrossingNumber(D); 0 # Test for tournament on 14 vertices -gap> D:= RandomTournament(14); +gap> D := RandomTournament(14); gap> DIGRAPHS_TournamentCrossingNumber(D); 315 # Test for tournament on 15 vertices -gap> D:= RandomTournament(15); +gap> D := RandomTournament(15); gap> DIGRAPHS_TournamentCrossingNumber(D); -1 From 0a2f0877bc7d3f32685e8e774f24ef0b5be99285 Mon Sep 17 00:00:00 2001 From: Mark Toner Date: Wed, 4 Jun 2025 13:50:43 +0100 Subject: [PATCH 11/13] Fixed linting for doc --- doc/crossingnumber.xml | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/doc/crossingnumber.xml b/doc/crossingnumber.xml index 23e0392cb..aedf36dc4 100644 --- a/doc/crossingnumber.xml +++ b/doc/crossingnumber.xml @@ -19,7 +19,7 @@ gap> D := Digraph([[1, 2, 4, 4], [1, 3, 4], [2, 1], [1, 2]]); gap> DigraphCrossingNumberUpperBound(D); 0 -gap> D := CompleteBipartiteDigraph(5,4);; +gap> D := CompleteBipartiteDigraph(5, 4);; gap> DigraphCrossingNumberUpperBound(D); 32]]> @@ -42,11 +42,11 @@ gap> DigraphCrossingNumberUpperBound(D); gap> D := CompleteDigraph(6);; gap> DigraphCrossingNumberLowerBound(D); 12 -gap> D := Digraph([[1, 2, 4, 4, 5], [1, 3, 4, 5], [2, 1, 5], [1, 2, 4, 5], [1,2]]); +gap> D := Digraph([[1, 2, 4, 4, 5], [1, 3, 4, 5], [2, 1, 5], [1, 2, 4, 5], [1, 2]]); gap> DigraphCrossingNumberLowerBound(D); 0 -gap> D := CompleteBipartiteDigraph([5,4,5,6]);; +gap> D := CompleteBipartiteDigraph([5, 4, 5, 6]);; gap> DigraphCrossingNumberLowerBound(D); 2282]]> @@ -69,10 +69,10 @@ gap> DigraphCrossingNumberLowerBound(D); digraph. D := CycleDigraph(4);; -gap> DigraphAddVertexCrossingPoint(D,[1,2],[2,3]); +gap> DigraphAddVertexCrossingPoint(D, [1, 2], [2, 3]); gap> D := CompleteDigraph(4);; -gap> DigraphAddVertexCrossingPoint(D,[3,5],[4,3]); +gap> DigraphAddVertexCrossingPoint(D, [3, 5], [4, 3]); ]]> @@ -93,7 +93,7 @@ gap> D := RandomTournament(4); gap> IsCubicDigraph(D); true -gap> D := Digraph([[2,4], [3, 6], [4,5], [],[1],[4,5]]); +gap> D := Digraph([[2, 4], [3, 6], [4, 5], [], [1], [4, 5]]); gap> IsCubicDigraph(D); true @@ -101,11 +101,11 @@ gap> D := CycleDigraph(7); gap> IsCubicDigraph(D); false -gap> D := Digraph([[1,1,1]]); +gap> D := Digraph([[1, 1, 1]]); gap> IsCubicDigraph(D); false -gap> D := CompleteMultipartiteDigraph([2,3,4,1]); +gap> D := CompleteMultipartiteDigraph([2, 3, 4, 1]); gap> IsCubicDigraph(D); false]]> @@ -128,7 +128,7 @@ gap> D := RandomTournament(4); gap> IsSemiComplete(D); true -gap> D := Digraph([[2,4], [3, 6], [4,5], [],[1],[4,5]]); +gap> D := Digraph([[2, 4], [3, 6], [4, 5], [], [1], [4, 5]]); gap> IsSemicompleteDigraph(D); false @@ -136,11 +136,11 @@ gap> D := CompleteDigraph(7); gap> IsCubicDigraph(D); true -gap> D := Digraph([[1,1,1]]); +gap> D := Digraph([[1, 1, 1]]); gap> IsSemicompleteDigraph(D); false -gap> D := CompleteMultipartiteDigraph([2,3,4,1]); +gap> D := CompleteMultipartiteDigraph([2, 3, 4, 1]); gap> IsCubicDigraph(D); false]]> @@ -165,10 +165,10 @@ gap> D := CompleteDigraph(4);; gap> DigraphAllThreeCircuits(D); [ [ 1, 2, 3 ], [ 1, 2, 4 ], [ 1, 3, 2 ], [ 1, 3, 4 ], [ 1, 4, 2 ], [ 1, 4, 3 ], [ 2, 3, 4 ], [ 2, 4, 3 ] ] -gap> D := Digraph([[2],[3],[1]]);; +gap> D := Digraph([[2], [3], [1]]);; gap> DigraphAllThreeCircuits(D); [ [ 1, 2, 3 ] ] -gap> D := Digraph([[2,4,5],[1,3],[1,5],[5],[1,4]]);; +gap> D := Digraph([[2, 4, 5], [1, 3], [1, 5], [5], [1, 4]]);; gap> DigraphAllThreeCircuits(D); [ [ 1, 2, 3 ], [ 1, 4, 5 ] ] gap> D := CompleteDigraph(3);; @@ -199,10 +199,10 @@ gap> DigraphAllThreeCircuits(D); gap> D := CompleteDigraph(4);; gap> DigraphAllTriangles(D); [ [ 1, 2, 3 ], [ 1, 2, 4 ], [ 1, 3, 4 ], [ 2, 3, 4 ] ] -gap> D := Digraph([[2],[3],[1]]);; +gap> D := Digraph([[2], [3], [1]]);; gap> DigraphAllTriangles(D); [ [ 1, 2, 3 ] ] -gap> D := Digraph([[2,4,5],[1,3],[1,5],[5],[4]]);; +gap> D := Digraph([[2, 4, 5], [1, 3], [1, 5], [5], [4]]);; gap> DigraphAllTriangles(D); [ [ 1, 2, 3 ], [ 1, 3, 5 ], [ 1, 4, 5 ] ] gap> D := CompleteDigraph(3);; @@ -234,10 +234,10 @@ gap> DigraphAllTriangles(D); digraph digraph, the partitions are sorted in increasing order.

D := CompleteBipartiteDigraph(3,4);; +gap> D := CompleteBipartiteDigraph(3, 4);; gap> CompleteMultipartiteDigraphPartitionSize(D); [ 3, 4 ] -gap> D:=CompleteMultipartiteDigraph([1,5,3]); +gap> D := CompleteMultipartiteDigraph([1, 5, 3]); gap> CompleteMultipartiteDigraphPartitionSize(D); [ [ 1, 2, 3 ] ]]]> From 8825369bc4bee591102733900a7125f44102f4e3 Mon Sep 17 00:00:00 2001 From: Mark Toner Date: Wed, 4 Jun 2025 13:55:31 +0100 Subject: [PATCH 12/13] Fixed test issue --- tst/standard/digraph.tst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tst/standard/digraph.tst b/tst/standard/digraph.tst index 6d76604db..7f8d56c8f 100644 --- a/tst/standard/digraph.tst +++ b/tst/standard/digraph.tst @@ -570,7 +570,7 @@ gap> RandomDigraph("a"); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `RandomDigraph' on 1 arguments gap> RandomDigraph(4, 0); - + gap> RandomDigraph(10, 1.01); Error, the 2nd argument

must be between 0 and 1, gap> RandomDigraph(10, -0.01); @@ -593,7 +593,7 @@ gap> RandomDigraph(IsImmutableDigraph, "a"); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `RandomDigraph' on 2 arguments gap> RandomDigraph(IsImmutableDigraph, 4, 0); - + gap> RandomDigraph(IsImmutableDigraph, 10, 1.01); Error, the 2nd argument

must be between 0 and 1, gap> RandomDigraph(IsImmutableDigraph, 10, -0.01); @@ -616,7 +616,7 @@ gap> RandomDigraph(IsMutableDigraph, "a"); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `RandomDigraph' on 2 arguments gap> RandomDigraph(IsMutableDigraph, 4, 0); - + gap> RandomDigraph(IsMutableDigraph, 10, 1.01); Error, the 2nd argument

must be between 0 and 1, gap> RandomDigraph(IsMutableDigraph, 10, -0.01); From fffdc1322ce3a6e4b437fefe549fe28a839da561 Mon Sep 17 00:00:00 2001 From: Mark Toner Date: Sat, 7 Jun 2025 11:26:57 +0100 Subject: [PATCH 13/13] Made requested changes --- doc/digraphs.bib | 2 +- doc/title.xml | 322 --------------------------------------- tst/standard/digraph.tst | 6 +- 3 files changed, 4 insertions(+), 326 deletions(-) delete mode 100644 doc/title.xml diff --git a/doc/digraphs.bib b/doc/digraphs.bib index 64ec63f28..3033f578d 100644 --- a/doc/digraphs.bib +++ b/doc/digraphs.bib @@ -72,7 +72,7 @@ @article{Gab00 Journal = {Information Processing Letters}, Keywords = {Algorithms}, Number = {34}, - Pages = {107 - 114},: + Pages = {107 - 114}, Title = {Path-based depth-first search for strong and biconnected components}, Url = {https://www.sciencedirect.com/science/article/pii/S002001900000051X}, diff --git a/doc/title.xml b/doc/title.xml deleted file mode 100644 index 9ad2fb6a3..000000000 --- a/doc/title.xml +++ /dev/null @@ -1,322 +0,0 @@ - - - - - - Digraphs - - - Graphs, digraphs, and multidigraphs in &GAP; - - - 1.10.0 - - - Jan De Beule
-

-Vrije Universiteit Brussel, Vakgroep Wiskunde, Pleinlaan 2, B - 1050 Brussels, Belgium
-
-jdebeule@cage.ugent.be -https://wids.research.vub.be/en/jan-de-beule - - - - Julius Jonusas
-j.jonusas@gmail.com -http://julius.jonusas.work - -
- - James Mitchell
-
-Mathematical Institute, North Haugh, St Andrews, Fife, KY16 9SS, Scotland
-
-jdm3@st-andrews.ac.uk -https://jdbm.me - -
- - Wilf A. Wilson
-gap@wilf-wilson.net -https://wilf.me - -
- - Michael Young
-
-Jack Cole Building, North Haugh, St Andrews, Fife, KY16 9SX, Scotland
-
-mct25@st-andrews.ac.uk -https://myoung.uk/work/ - -
- - Marina Anagnostopoulou-Merkouri
-
-Mathematical Institute, North Haugh, St Andrews, Fife, KY16 9SS, Scotland
-
-mam49@st-andrews.ac.uk - -
- - Finn Buck
-
-Mathematical Institute, North Haugh, St Andrews, Fife, KY16 9SS, Scotland
-
-finneganlbuck@gmail.com - -
- - Stuart Burrell
-stuartburrell1994@gmail.com -https://stuartburrell.github.io - -
- - Graham Campbell
- -
- - Raiyan Chowdhury
- -
- - Reinis Cirpons
-
-Mathematical Institute, North Haugh, St Andrews, Fife, KY16 9SS, Scotland
-
-rc234@st-andrews.ac.uk - -
- - Ashley Clayton
-
-Mathematical Institute, North Haugh, St Andrews, Fife, KY16 9SS, Scotland
-
-ac323@st-andrews.ac.uk - -
- - Tom Conti-Leslie
-tom.contileslie@gmail.com -https://tomcontileslie.com - -
- - Joseph Edwards
-
-Mathematical Institute, North Haugh, St Andrews, Fife, KY16 9SS, Scotland
-
-jde1@st-andrews.ac.uk -https://github.com/Joseph-Edwards - -
- - Luna Elliott
-luna.elliott142857@gmail.com -https://research.manchester.ac.uk/en/persons/luna-elliott - -
- - Isuru Fernando
-isuruf@gmail.com - -
- - Ewan Gilligan
-eg207@st-andrews.ac.uk - -
- - Gillis Frankie
-fotg1@st-andrews.ac.uk - -
- - Sebastian Gutsche
-gutsche@momo.math.rwth-aachen.de - -
- - Samantha Harper
-seh25@st-andrews.ac.uk - -
- - Max Horn
-
-Fachbereich Mathematik, TU Kaiserslautern, Gottlieb-Daimler-Straße 48, 67663 Kaiserslautern, Germany
-
-horn@mathematik.uni-kl.de -https://www.quendi.de/math - -
- - Christopher Jefferson
-
-Jack Cole Building, North Haugh, St Andrews, Fife, KY16 9SX, Scotland
-
-caj21@st-andrews.ac.uk -https://heather.cafe/ - -
- - Malachi Johns
-zlj1@st-andrews.ac.uk - -
- - Olexandr Konovalov
-
-Jack Cole Building, North Haugh, St Andrews, Fife, KY16 9SX, Scotland
-
-obk1@st-andrews.ac.uk -https://olexandr-konovalov.github.io/ - -
- - Hyeokjun Kwon
-hk78@st-andrews.ac.uk - -
- - Aidan Lau
- -
- - Andrea Lee
-ahwl1@st-andrews.ac.uk - -
- - Saffron McIver
-sm544@st-andrews.ac.uk - -
- - Michael Orlitzky
-michael@orlitzky.com -https://michael.orlitzky.com/ - -
- - Matthew Pancer
-mp322@st-andrews.ac.uk - -
- - Markus Pfeiffer
-markus.pfeiffer@morphism.de -https://markusp.morphism.de/ - -
- - Daniel Pointon
-dp211@st-andrews.ac.uk - -
- - Lea Racine
-
-Jack Cole Building, North Haugh, St Andrews, Fife, KY16 9SX, Scotland
-
-lr217@st-andrews.ac.uk - -
- - Christopher Russell
- -
- - Artur Schaefer
-as305@st-and.ac.uk - -
- - Isabella Scott
-iscott@uchicago.edu - -
- - Kamran Sharma
-
-Jack Cole Building, North Haugh, St Andrews, Fife, KY16 9SX, Scotland
-
-kks4@st-andrews.ac.uk - -
- - Finn Smith
-
-Mathematical Institute, North Haugh, St Andrews, Fife, KY16 9SS, Scotland
-
-fls3@st-andrews.ac.uk - -
- - Ben Spiers
-bspiers972@outlook.com - -
- - Mark Toner
-mark.toner@live.com - -
- - Maria Tsalakou
-
-Mathematical Institute, North Haugh, St Andrews, Fife, KY16 9SS, Scotland
-
-mt200@st-andrews.ac.uk -https://mariatsalakou.github.io/ - -
- - Meike Weiss
-
-Chair of Algebra and Representation Theory, Pontdriesch 10-16, 52062 Aachen
-
-weiss@art.rwth-aachen.de -https://bit.ly/4e6pUeP - -
- - Murray Whyte
-
-Mathematical Institute, North Haugh, St Andrews, Fife, KY16 9SS, Scotland
-
-mw231@st-andrews.ac.uk - -
- - Fabian Zickgraf
-f.zickgraf@dashdos.com - -
- - 14 February 2025 - - - The &Digraphs; package is a &GAP; package containing - methods for graphs, digraphs, and multidigraphs. - - - Jan De Beule, Julius Jonušas, James D. Mitchell, - Wilf A. Wilson, Michael Young et al.

- - &Digraphs; is free software; you can redistribute it and/or modify - it under the terms of the - https://www.fsf.org/licenses/gpl.html as published by the - Free Software Foundation; either version 3 of the License, or (at - your option) any later version. - - - We would like to thank Christopher Jefferson for his help in including - &BLISS; in &Digraphs;. - - This package's methods for computing digraph homomorphisms are based - on work by Max Neunhöffer, and independently Artur Schäfer. - - - \ No newline at end of file diff --git a/tst/standard/digraph.tst b/tst/standard/digraph.tst index 7f8d56c8f..6d76604db 100644 --- a/tst/standard/digraph.tst +++ b/tst/standard/digraph.tst @@ -570,7 +570,7 @@ gap> RandomDigraph("a"); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `RandomDigraph' on 1 arguments gap> RandomDigraph(4, 0); - + gap> RandomDigraph(10, 1.01); Error, the 2nd argument

must be between 0 and 1, gap> RandomDigraph(10, -0.01); @@ -593,7 +593,7 @@ gap> RandomDigraph(IsImmutableDigraph, "a"); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `RandomDigraph' on 2 arguments gap> RandomDigraph(IsImmutableDigraph, 4, 0); - + gap> RandomDigraph(IsImmutableDigraph, 10, 1.01); Error, the 2nd argument

must be between 0 and 1, gap> RandomDigraph(IsImmutableDigraph, 10, -0.01); @@ -616,7 +616,7 @@ gap> RandomDigraph(IsMutableDigraph, "a"); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `RandomDigraph' on 2 arguments gap> RandomDigraph(IsMutableDigraph, 4, 0); - + gap> RandomDigraph(IsMutableDigraph, 10, 1.01); Error, the 2nd argument

must be between 0 and 1, gap> RandomDigraph(IsMutableDigraph, 10, -0.01);