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);