diff --git a/doc/prop.xml b/doc/prop.xml index 9c6bc9f24..e8b720471 100644 --- a/doc/prop.xml +++ b/doc/prop.xml @@ -717,7 +717,8 @@ false false if it is not. A digraph is empty if it has no edges.

- IsNullDigraph is a synonym for IsEmptyDigraph. + is a synonym for . + See also .

&MUTABLE_RECOMPUTED_PROP; @@ -739,6 +740,93 @@ false]]> <#/GAPDoc> +<#GAPDoc Label="IsNonemptyDigraph"> + + + true or false. + + Returns true if the digraph digraph is nonempty, and + false if it is not. A digraph is nonempty if it has at + least one edge.

+ + See also . +

+ + &MUTABLE_RECOMPUTED_PROP; + + D := Digraph([[], []]); + +gap> IsNonemptyDigraph(D); +false +gap> D := Digraph([[], [1]]); + +gap> IsNonemptyDigraph(D); +true]]> + + +<#/GAPDoc> + +<#GAPDoc Label="DigraphHasAVertex"> + + + true or false. + + Returns true if the digraph digraph has at least one vertex, + and false if it does not.

+ + See also . +

+ + &MUTABLE_RECOMPUTED_PROP; + + D := Digraph([]); + +gap> DigraphHasAVertex(D); +false +gap> D := Digraph([[]]); + +gap> DigraphHasAVertex(D); +true +gap> D := Digraph([[], [1]]); + +gap> DigraphHasAVertex(D); +true]]> + + +<#/GAPDoc> + +<#GAPDoc Label="DigraphHasNoVertices"> + + + true or false. + + Returns true if the digraph digraph is the unique digraph + with zero vertices, and false otherwise.

+ + See also . +

+ + &MUTABLE_RECOMPUTED_PROP; + + D := Digraph([]); + +gap> DigraphHasNoVertices(D); +true +gap> D := Digraph([[]]); + +gap> DigraphHasNoVertices(D); +false +gap> D := Digraph([[], [1]]); + +gap> DigraphHasNoVertices(D); +false]]> + + +<#/GAPDoc> + <#GAPDoc Label="IsEulerianDigraph"> diff --git a/doc/z-chap5.xml b/doc/z-chap5.xml index 1b643c46a..906c65d76 100644 --- a/doc/z-chap5.xml +++ b/doc/z-chap5.xml @@ -1,5 +1,10 @@ Properties of digraphs +

Vertex properties + <#Include Label="DigraphHasAVertex"> + <#Include Label="DigraphHasNoVertices"> +
+
Edge properties <#Include Label="DigraphHasLoops"> <#Include Label="IsAntisymmetricDigraph"> @@ -12,6 +17,7 @@ <#Include Label="IsFunctionalDigraph"> <#Include Label="IsPermutationDigraph"> <#Include Label="IsMultiDigraph"> + <#Include Label="IsNonemptyDigraph"> <#Include Label="IsReflexiveDigraph"> <#Include Label="IsSymmetricDigraph"> <#Include Label="IsTournament"> diff --git a/gap/attr.gi b/gap/attr.gi index 470047d1a..7debc92dd 100644 --- a/gap/attr.gi +++ b/gap/attr.gi @@ -1080,7 +1080,7 @@ function(D) # alter the answer for the diameter/girth if necessary. This function is # called, if appropriate, by DigraphDiameter and DigraphUndirectedGirth. - if DigraphNrVertices(D) = 0 and IsImmutableDigraph(D) then + if DigraphHasNoVertices(D) and IsImmutableDigraph(D) then SetDigraphDiameter(D, fail); SetDigraphUndirectedGirth(D, infinity); return rec(diameter := fail, girth := infinity); @@ -1491,10 +1491,10 @@ end); InstallMethod(DegreeMatrix, "for a digraph", [IsDigraph], function(D) - if DigraphNrVertices(D) = 0 then - return []; + if DigraphHasAVertex(D) then + return DiagonalMat(OutDegrees(D)); fi; - return DiagonalMat(OutDegrees(D)); + return []; end); InstallMethod(LaplacianMatrix, "for a digraph", [IsDigraph], @@ -1815,7 +1815,7 @@ function(D) SetDigraphAddAllLoopsAttr(D, C); SetIsReflexiveDigraph(C, true); SetIsMultiDigraph(C, ismulti); - SetDigraphHasLoops(C, DigraphNrVertices(C) > 0); + SetDigraphHasLoops(C, DigraphHasAVertex(C)); fi; return C; end); @@ -2264,7 +2264,7 @@ InstallMethod(UndirectedSpanningForest, "for a digraph by out-neighbours", [IsDigraphByOutNeighboursRep], function(D) local C; - if DigraphNrVertices(D) = 0 then + if DigraphHasNoVertices(D) then return fail; fi; C := MaximalSymmetricSubdigraph(D)!.OutNeighbours; @@ -2293,9 +2293,9 @@ InstallMethod(UndirectedSpanningForestAttr, "for an immutable digraph", InstallMethod(UndirectedSpanningTree, "for a mutable digraph", [IsMutableDigraph], function(D) - if DigraphNrVertices(D) = 0 - or not IsStronglyConnectedDigraph(D) - or not IsConnectedDigraph(UndirectedSpanningForest(DigraphMutableCopy(D))) + if not (DigraphHasAVertex(D) + and IsStronglyConnectedDigraph(D) + and IsConnectedDigraph(UndirectedSpanningForest(DigraphMutableCopy(D)))) then return fail; fi; @@ -2309,7 +2309,7 @@ InstallMethod(UndirectedSpanningTreeAttr, "for an immutable digraph", [IsImmutableDigraph], function(D) local out; - if DigraphNrVertices(D) = 0 + if DigraphHasNoVertices(D) or not IsStronglyConnectedDigraph(D) or (HasMaximalSymmetricSubdigraphAttr(D) and not IsStronglyConnectedDigraph(MaximalSymmetricSubdigraph(D))) diff --git a/gap/digraph.gi b/gap/digraph.gi index 0db23b548..e400ff2e9 100644 --- a/gap/digraph.gi +++ b/gap/digraph.gi @@ -1065,7 +1065,7 @@ p -> AsDigraph(AsTransformation(p))); InstallMethod(AsBinaryRelation, "for a digraph", [IsDigraphByOutNeighboursRep], function(D) local rel; - if DigraphNrVertices(D) = 0 then + if DigraphHasNoVertices(D) then ErrorNoReturn("the argument must be a digraph with at least 1 ", "vertex,"); elif IsMultiDigraph(D) then diff --git a/gap/grahom.gi b/gap/grahom.gi index d555639ae..9730df235 100644 --- a/gap/grahom.gi +++ b/gap/grahom.gi @@ -109,7 +109,7 @@ function(D, n) # Only the null D with 0 vertices can be coloured with 0 colours if n = 0 then - if DigraphNrVertices(D) = 0 then + if DigraphHasNoVertices(D) then return IdentityTransformation; fi; return fail; diff --git a/gap/isomorph.gi b/gap/isomorph.gi index 75cf6343c..914d49e5d 100644 --- a/gap/isomorph.gi +++ b/gap/isomorph.gi @@ -142,7 +142,7 @@ if DIGRAPHS_NautyAvailable then colors); colors := NautyColorData(colors); fi; - if DigraphNrVertices(D) = 0 then + if DigraphHasNoVertices(D) then # This circumvents Issue #17 in NautyTracesInterface, whereby a graph # with 0 vertices causes a seg fault. return [Group(()), ()]; diff --git a/gap/prop.gd b/gap/prop.gd index c5e143709..54c1e1375 100644 --- a/gap/prop.gd +++ b/gap/prop.gd @@ -11,6 +11,9 @@ # meaning it really has multiple edges!! DeclareProperty("IsMultiDigraph", IsDigraph); +DeclareProperty("DigraphHasAVertex", IsDigraph); +DeclareProperty("DigraphHasNoVertices", IsDigraph); + DeclareProperty("DigraphHasLoops", IsDigraph); DeclareProperty("IsAcyclicDigraph", IsDigraph); DeclareProperty("IsAperiodicDigraph", IsDigraph); @@ -32,6 +35,7 @@ DeclareProperty("IsUndirectedForest", IsDigraph); DeclareProperty("IsEdgeTransitive", IsDigraph); DeclareProperty("IsVertexTransitive", IsDigraph); DeclareProperty("IsEmptyDigraph", IsDigraph); +DeclareProperty("IsNonemptyDigraph", IsDigraph); DeclareProperty("IsEulerianDigraph", IsDigraph); DeclareProperty("IsFunctionalDigraph", IsDigraph); DeclareProperty("IsHamiltonianDigraph", IsDigraph); @@ -98,3 +102,49 @@ InstallTrueMethod(IsSymmetricDigraph, IsCompleteDigraph); InstallTrueMethod(IsSymmetricDigraph, IsDigraph and IsUndirectedForest); InstallTrueMethod(IsTransitiveDigraph, IsTournament and IsAcyclicDigraph); InstallTrueMethod(IsUndirectedForest, IsDigraph and IsUndirectedTree); + +InstallTrueMethod(IsNonemptyDigraph, IsDigraph and DigraphHasLoops); +InstallTrueMethod(DigraphHasLoops, IsReflexiveDigraph and DigraphHasAVertex); +InstallTrueMethod(DigraphHasAVertex, IsDigraph and IsNonemptyDigraph); +InstallTrueMethod(DigraphHasAVertex, IsDigraph and IsDirectedTree); + +# Implications that something is false + +InstallTrueMethod(HasDigraphHasLoops, IsAcyclicDigraph); +InstallTrueMethod(HasDigraphHasLoops, IsTournament); +InstallTrueMethod(HasDigraphHasLoops, IsUndirectedForest); +InstallTrueMethod(HasDigraphHasLoops, IsDirectedTree); +InstallTrueMethod(HasDigraphHasLoops, IsEmptyDigraph); +InstallTrueMethod(HasDigraphHasLoops, IsCompleteDigraph and IsNonemptyDigraph); +InstallTrueMethod(HasDigraphHasLoops, IsBipartiteDigraph); + +InstallTrueMethod(HasIsNonemptyDigraph, IsEmptyDigraph); +InstallTrueMethod(HasIsEmptyDigraph, IsNonemptyDigraph); +InstallTrueMethod(HasDigraphHasAVertex, DigraphHasNoVertices); +InstallTrueMethod(HasDigraphHasNoVertices, DigraphHasAVertex); + +InstallTrueMethod(HasIsAcyclicDigraph, IsCompleteDigraph and IsNonemptyDigraph); +InstallTrueMethod(HasIsAcyclicDigraph, IsDigraph and DigraphHasLoops); +InstallTrueMethod(HasIsAcyclicDigraph, + IsStronglyConnectedDigraph and IsNonemptyDigraph); +InstallTrueMethod(HasIsAntisymmetricDigraph, + IsCompleteDigraph and IsNonemptyDigraph); +InstallTrueMethod(HasIsChainDigraph, IsDigraph and DigraphHasLoops); +InstallTrueMethod(HasIsChainDigraph, IsSymmetricDigraph and IsNonemptyDigraph); +InstallTrueMethod(HasIsCompleteDigraph, IsDigraph and DigraphHasLoops); +InstallTrueMethod(HasIsReflexiveDigraph, + IsAcyclicDigraph and DigraphHasAVertex); + +InstallTrueMethod(HasIsSymmetricDigraph, IsDirectedTree and IsNonemptyDigraph); +InstallTrueMethod(HasIsSymmetricDigraph, IsTournament and IsNonemptyDigraph); +InstallTrueMethod(HasIsSymmetricDigraph, + IsAcyclicDigraph and IsNonemptyDigraph); + +InstallTrueMethod(HasIsMultiDigraph, IsChainDigraph); +InstallTrueMethod(HasIsMultiDigraph, IsCompleteDigraph); +InstallTrueMethod(HasIsMultiDigraph, IsCompleteMultipartiteDigraph); +InstallTrueMethod(HasIsMultiDigraph, IsCycleDigraph); +InstallTrueMethod(HasIsMultiDigraph, IsEmptyDigraph); +InstallTrueMethod(HasIsMultiDigraph, IsFunctionalDigraph); +InstallTrueMethod(HasIsMultiDigraph, IsTournament); +InstallTrueMethod(HasIsMultiDigraph, IsUndirectedForest); diff --git a/gap/prop.gi b/gap/prop.gi index cbc0fe0f7..d871a9a25 100644 --- a/gap/prop.gi +++ b/gap/prop.gi @@ -1,7 +1,7 @@ ############################################################################# ## ## prop.gi -## Copyright (C) 2014-19 James D. Mitchell +## Copyright (C) 2014-21 James D. Mitchell ## ## Licensing information can be found in the README file of this package. ## @@ -13,12 +13,21 @@ InstallMethod(IsMultiDigraph, "for a digraph by out-neighbours", [IsDigraphByOutNeighboursRep], IS_MULTI_DIGRAPH); +InstallMethod(DigraphHasNoVertices, "for a digraph", [IsDigraph], +D -> not DigraphHasAVertex(D)); + +InstallMethod(DigraphHasAVertex, "for a digraph", [IsDigraph], +D -> DigraphNrVertices(D) > 0); + +InstallMethod(IsNonemptyDigraph, "for a digraph", [IsDigraph], +D -> not IsEmptyDigraph(D)); + InstallMethod(IsChainDigraph, "for a digraph", [IsDigraph], D -> IsDirectedTree(D) and IsSubset([0, 1], OutDegreeSet(D))); InstallMethod(IsCycleDigraph, "for a digraph", [IsDigraph], function(D) - return DigraphNrVertices(D) > 0 + return DigraphHasAVertex(D) and DigraphNrEdges(D) = DigraphNrVertices(D) and IsStronglyConnectedDigraph(D); end); @@ -384,8 +393,8 @@ D -> DigraphNrEdges(D) = 2 * (DigraphNrVertices(D) - 1) InstallMethod(IsUndirectedForest, "for a digraph", [IsDigraph], function(D) - if not IsSymmetricDigraph(D) or DigraphNrVertices(D) = 0 - or IsMultiDigraph(D) then + if DigraphHasNoVertices(D) or not IsSymmetricDigraph(D) or IsMultiDigraph(D) + then return false; fi; return ForAll(DigraphConnectedComponents(D).comps, diff --git a/tst/standard/prop.tst b/tst/standard/prop.tst index 9540440d3..383c670a8 100644 --- a/tst/standard/prop.tst +++ b/tst/standard/prop.tst @@ -1,7 +1,7 @@ ############################################################################# ## #W standard/prop.tst -#Y Copyright (C) 2014-17 James D. Mitchell +#Y Copyright (C) 2014-21 James D. Mitchell ## Wilf A. Wilson ## ## Licensing information can be found in the README file of this package. @@ -139,7 +139,7 @@ gap> gr := Digraph([[1]]);; gap> DigraphHasLoops(gr); true gap> HasIsAcyclicDigraph(gr); -false +true gap> IsAcyclicDigraph(gr); false gap> gr := Digraph([[2], []]); @@ -1549,6 +1549,219 @@ true gap> IsEdgeTransitive(Digraph([[2], [3, 3, 3], []])); Error, the argument must be a digraph with no multiple edges, +# DigraphHasNoVertices and DigraphHasAVertex +gap> List([0 .. 3], i -> DigraphHasAVertex(EmptyDigraph(i))); +[ false, true, true, true ] +gap> List([0 .. 3], i -> DigraphHasNoVertices(EmptyDigraph(i))); +[ true, false, false, false ] +gap> DigraphHasAVertex(Digraph([])); +false +gap> DigraphHasNoVertices(Digraph([])); +true +gap> DigraphHasAVertex(Digraph([[1]])); +true +gap> DigraphHasNoVertices(Digraph([[1]])); +false + +# IsNonemptyDigraph +gap> ForAny([0 .. 10], i -> IsNonemptyDigraph(EmptyDigraph(i))); +false +gap> ForAny([0 .. 10], i -> IsNonemptyDigraph(Digraph( +> ListWithIdenticalEntries(i, [])))); +false +gap> IsNonemptyDigraph(Digraph([[], [3], []])); +true + +# Implications that something is false +# DigraphHasLoops +gap> D := Digraph([[2], [], [2]]);; +gap> SetIsAcyclicDigraph(D, true); +gap> HasDigraphHasLoops(D) and not DigraphHasLoops(D); +true + +# +gap> D := Digraph([[2], []]);; +gap> SetIsTournament(D, true); +gap> HasDigraphHasLoops(D) and not DigraphHasLoops(D); +true + +# +gap> D := Digraph([[2], [1, 3, 4], [2], [2], [6], [5]]);; +gap> SetIsUndirectedForest(D, true); +gap> HasDigraphHasLoops(D) and not DigraphHasLoops(D); +true + +# +gap> D := Digraph([[3], [1, 4], [], []]);; +gap> SetIsDirectedTree(D, true); +gap> HasDigraphHasLoops(D) and not DigraphHasLoops(D); +true + +# +gap> D := Digraph([[], []]);; +gap> SetIsEmptyDigraph(D, true); +gap> HasDigraphHasLoops(D) and not DigraphHasLoops(D); +true + +# +gap> D := Digraph([[2, 3], [1, 3], [1, 2]]);; +gap> SetIsCompleteDigraph(D, true); +gap> SetIsNonemptyDigraph(D, true); +gap> HasDigraphHasLoops(D) and not DigraphHasLoops(D); +true + +# +gap> D := Digraph([[2], []]);; +gap> SetIsBipartiteDigraph(D, true); +gap> HasDigraphHasLoops(D) and not DigraphHasLoops(D); +true + +# IsAcyclicDigraph +gap> D := Digraph([[2], [1]]);; +gap> SetIsCompleteDigraph(D, true); +gap> SetIsNonemptyDigraph(D, true); +gap> HasIsAcyclicDigraph(D) and not IsAcyclicDigraph(D); +true + +# +gap> D := Digraph([[2, 3], [2], [2]]);; +gap> SetDigraphHasLoops(D, true); +gap> HasIsAcyclicDigraph(D) and not IsAcyclicDigraph(D); +true + +# +gap> D := Digraph([[3], [1], [2]]);; +gap> SetIsStronglyConnectedDigraph(D, true); +gap> SetIsNonemptyDigraph(D, true); +gap> HasIsAcyclicDigraph(D) and not IsAcyclicDigraph(D); +true + +# Other +gap> D := Digraph([[], []]);; +gap> SetIsEmptyDigraph(D, true); +gap> HasIsNonemptyDigraph(D) and not IsNonemptyDigraph(D); +true + +# +gap> D := Digraph([[], [1]]);; +gap> SetIsNonemptyDigraph(D, true); +gap> HasIsEmptyDigraph(D) and not IsEmptyDigraph(D); +true + +# +gap> D := Digraph([]);; +gap> SetDigraphHasNoVertices(D, true); +gap> HasDigraphHasAVertex(D) and not DigraphHasAVertex(D); +true + +# +gap> D := Digraph([[]]);; +gap> SetDigraphHasAVertex(D, true); +gap> HasDigraphHasNoVertices(D) and not DigraphHasNoVertices(D); +true + +# +gap> D := Digraph([[2], [1]]);; +gap> SetIsCompleteDigraph(D, true); +gap> SetIsNonemptyDigraph(D, true); +gap> HasIsAntisymmetricDigraph(D) and not IsAntisymmetricDigraph(D); +true + +# +gap> D := Digraph([[2], [3], [3]]);; +gap> SetDigraphHasLoops(D, true); +gap> HasIsChainDigraph(D) and not IsChainDigraph(D); +true + +# +gap> D := Digraph([[2, 3], [1], [1, 4], [3]]);; +gap> SetIsSymmetricDigraph(D, true); +gap> SetIsNonemptyDigraph(D, true); +gap> HasIsChainDigraph(D) and not IsChainDigraph(D); +true + +# +gap> D := Digraph([[2], [3], [3]]);; +gap> SetDigraphHasLoops(D, true); +gap> HasIsCompleteDigraph(D) and not IsCompleteDigraph(D); +true + +# +gap> D := Digraph([[2], [5], [], [5], [6], []]);; +gap> SetIsAcyclicDigraph(D, true); +gap> SetDigraphHasAVertex(D, true); +gap> HasIsReflexiveDigraph(D) and not IsReflexiveDigraph(D); +true + +# IsSymmetricDigraph +gap> D := Digraph([[3], [], [2]]);; +gap> SetIsAcyclicDigraph(D, true); +gap> SetIsNonemptyDigraph(D, true); +gap> HasIsSymmetricDigraph(D) and not IsSymmetricDigraph(D); +true + +# +gap> D := Digraph([[3], [], [2]]);; +gap> SetIsDirectedTree(D, true); +gap> SetIsNonemptyDigraph(D, true); +gap> HasIsSymmetricDigraph(D) and not IsSymmetricDigraph(D); +true + +# +gap> D := Digraph([[3], [1], [2]]);; +gap> SetIsTournament(D, true); +gap> SetIsNonemptyDigraph(D, true); +gap> HasIsSymmetricDigraph(D) and not IsSymmetricDigraph(D); +true + +# IsMultiDigraph +gap> D := Digraph([[2], [3], [4], []]);; +gap> SetIsChainDigraph(D, true); +gap> HasIsMultiDigraph(D) and not IsMultiDigraph(D); +true + +# +gap> D := Digraph([[2, 3], [3, 1], [2, 1]]);; +gap> SetIsCompleteDigraph(D, true); +gap> HasIsMultiDigraph(D) and not IsMultiDigraph(D); +true + +# +gap> D := Digraph([[2, 3], [3, 1], [2, 1]]);; +gap> SetIsCompleteMultipartiteDigraph(D, true); +gap> HasIsMultiDigraph(D) and not IsMultiDigraph(D); +true + +# +gap> D := Digraph([[2], [1]]);; +gap> SetIsCycleDigraph(D, true); +gap> HasIsMultiDigraph(D) and not IsMultiDigraph(D); +true + +# +gap> D := Digraph([[], []]);; +gap> SetIsEmptyDigraph(D, true); +gap> HasIsMultiDigraph(D) and not IsMultiDigraph(D); +true + +# +gap> D := Digraph([[3], [2], [3], [1]]);; +gap> SetIsFunctionalDigraph(D, true); +gap> HasIsMultiDigraph(D) and not IsMultiDigraph(D); +true + +# +gap> D := Digraph([[3], [1], [2]]);; +gap> SetIsTournament(D, true); +gap> HasIsMultiDigraph(D) and not IsMultiDigraph(D); +true + +# +gap> D := Digraph([[2], [1, 3, 4], [2], [2], [6], [5]]);; +gap> SetIsUndirectedForest(D, true); +gap> HasIsMultiDigraph(D) and not IsMultiDigraph(D); +true + # DIGRAPHS_UnbindVariables gap> Unbind(adj); gap> Unbind(circuit);