diff --git a/doc/attr.xml b/doc/attr.xml
index 3a6769da8..42649c41b 100644
--- a/doc/attr.xml
+++ b/doc/attr.xml
@@ -138,6 +138,28 @@ gap> DigraphNrEdges(D);
<#/GAPDoc>
+<#GAPDoc Label="DigraphNrAdjacencies">
+
+
+ An integer.
+ Returns the number of pairs of adjacent vertices of the digraph digraph. This
+ function is agnostic to the direction of an edge, so if digraph constains both the edges (a,
+ b) and (b, a), this only counts as one adjacency. The following equality holds for
+ any digraph D with no multiple edges: DigraphNrAdjacencies(D) * 2 - DigraphNrLoops(D)
+ = DigraphNrEdges(DigraphSymmetricClosure(D))
+ gr := Digraph([
+> [1, 3, 4, 5], [1, 2, 3, 5], [2, 4, 5], [2, 4, 5], [1]]);;
+gap> DigraphNrAdjacencies(gr);
+13
+gap> DigraphNrAdjacencies(gr) * 2 - DigraphNrLoops(gr) =
+> DigraphNrEdges(DigraphSymmetricClosure(gr));
+true
+]]>
+
+
+<#/GAPDoc>
+
<#GAPDoc Label="DigraphNrLoops">
diff --git a/doc/z-chap4.xml b/doc/z-chap4.xml
index 0f2ebe1ee..79113ce92 100644
--- a/doc/z-chap4.xml
+++ b/doc/z-chap4.xml
@@ -4,6 +4,7 @@
<#Include Label="DigraphNrVertices">
<#Include Label="DigraphEdges">
<#Include Label="DigraphNrEdges">
+ <#Include Label="DigraphNrAdjacencies">
<#Include Label="DigraphNrLoops">
<#Include Label="DigraphSinks">
<#Include Label="DigraphSources">
diff --git a/gap/attr.gi b/gap/attr.gi
index 68fdd903c..3078cdd72 100644
--- a/gap/attr.gi
+++ b/gap/attr.gi
@@ -701,8 +701,8 @@ function(D)
return m;
end);
-InstallMethod(DigraphNrAdjacencies, "for a digraph", [IsDigraphByOutNeighboursRep],
-DIGRAPH_NRADJACENCIES);
+InstallMethod(DigraphNrAdjacencies, "for a digraph",
+[IsDigraphByOutNeighboursRep], DIGRAPH_NRADJACENCIES);
InstallMethod(DigraphNrLoops,
"for a digraph by out-neighbours",
diff --git a/gap/planar.gi b/gap/planar.gi
index 386e5c180..0d7f85cd0 100644
--- a/gap/planar.gi
+++ b/gap/planar.gi
@@ -30,95 +30,50 @@
# 1. Attributes
########################################################################
-InstallMethod(PlanarEmbedding, "for a digraph", [IsDigraph],
+HasTrivialRotaionSystem :=
function(D)
- local C;
+ if IsMultiDigraph(D) then
+ ErrorNoReturn("expected a digraph with no multiple edges");
+ fi;
if HasIsPlanarDigraph(D) and not IsPlanarDigraph(D) then
- return fail;
+ return false;
fi;
- C := DigraphMutableCopy(D);
- DigraphRemoveAllMultipleEdges(C);
- DigraphRemoveLoops(C);
- if IsEmptyDigraph(C) or DigraphNrVertices(C) < 3 then
- return OutNeighbors(C);
+ if DigraphNrVertices(D) < 3 then
+ return true;
fi;
- return PLANAR_EMBEDDING(C);
-end);
+ return DigraphNrAdjacencies(D) = DigraphNrLoops(D);
+end;
-InstallMethod(OuterPlanarEmbedding, "for a digraph", [IsDigraph],
+InstallMethod(PlanarEmbedding, "for a digraph", [IsDigraph],
function(D)
- local C;
- if HasIsPlanarDigraph(D) and not IsPlanarDigraph(D) then
- return fail;
- fi;
- C := DigraphMutableCopy(D);
- DigraphRemoveAllMultipleEdges(C);
- DigraphRemoveLoops(C);
- if IsEmptyDigraph(C) or DigraphNrVertices(C) < 3 then
- return OutNeighbors(C);
+ if HasTrivialRotaionSystem(D) then;
+ return OutNeighbors(D);
fi;
- return OUTER_PLANAR_EMBEDDING(C);
+ return PLANAR_EMBEDDING(D);
end);
-InstallMethod(KuratowskiPlanarSubdigraph, "for a digraph", [IsDigraph],
+InstallMethod(OuterPlanarEmbedding, "for a digraph", [IsDigraph],
function(D)
- local C;
- C := DigraphMutableCopy(D);
- DigraphRemoveAllMultipleEdges(C);
- DigraphRemoveLoops(C);
- if IsPlanarDigraph(C) then
- return fail;
+ if HasTrivialRotaionSystem(D) then;
+ return OutNeighbors(D);
fi;
- return KURATOWSKI_PLANAR_SUBGRAPH(C);
+ return OUTER_PLANAR_EMBEDDING(D);
end);
+InstallMethod(KuratowskiPlanarSubdigraph, "for a digraph", [IsDigraph],
+KURATOWSKI_PLANAR_SUBGRAPH);
+
InstallMethod(KuratowskiOuterPlanarSubdigraph, "for a digraph", [IsDigraph],
-function(D)
- local C;
- C := DigraphMutableCopy(D);
- DigraphRemoveAllMultipleEdges(C);
- DigraphRemoveLoops(C);
- if IsOuterPlanarDigraph(C) then
- return fail;
- fi;
- return KURATOWSKI_OUTER_PLANAR_SUBGRAPH(C);
-end);
+KURATOWSKI_OUTER_PLANAR_SUBGRAPH);
InstallMethod(SubdigraphHomeomorphicToK23, "for a digraph", [IsDigraph],
-function(D)
- local C;
- C := DigraphMutableCopy(D);
- DigraphRemoveAllMultipleEdges(C);
- DigraphRemoveLoops(C);
- if IsOuterPlanarDigraph(C) then
- return fail;
- fi;
- return SUBGRAPH_HOMEOMORPHIC_TO_K23(C);
-end);
+SUBGRAPH_HOMEOMORPHIC_TO_K23);
InstallMethod(SubdigraphHomeomorphicToK4, "for a digraph", [IsDigraph],
-function(D)
- local C;
- C := DigraphMutableCopy(D);
- DigraphRemoveAllMultipleEdges(C);
- DigraphRemoveLoops(C);
- if IsOuterPlanarDigraph(C) then
- return fail;
- fi;
- return SUBGRAPH_HOMEOMORPHIC_TO_K4(D);
-end);
+SUBGRAPH_HOMEOMORPHIC_TO_K4);
InstallMethod(SubdigraphHomeomorphicToK33, "for a digraph", [IsDigraph],
-function(D)
- local C;
- C := DigraphMutableCopy(D);
- DigraphRemoveAllMultipleEdges(C);
- DigraphRemoveLoops(C);
- if IsPlanarDigraph(C) then
- return fail;
- fi;
- return SUBGRAPH_HOMEOMORPHIC_TO_K33(C);
-end);
+SUBGRAPH_HOMEOMORPHIC_TO_K33);
########################################################################
# 2. Properties
@@ -126,33 +81,32 @@ end);
InstallMethod(IsPlanarDigraph, "for a digraph", [IsDigraph],
function(D)
- local C, v, e;
- C := MaximalAntiSymmetricSubdigraph(DigraphMutableCopyIfMutable(D));
+ local v, n_antisymmetric_edges;
v := DigraphNrVertices(D);
- e := DigraphNrEdges(C);
- if v < 5 or e < 9 then
+ n_antisymmetric_edges := DigraphNrAdjacencies(D) - DigraphNrLoops(D);
+ if v < 5 or n_antisymmetric_edges < 9 then
return true;
- elif (IsConnectedDigraph(D) and e > 3 * v - 6)
+ elif (IsConnectedDigraph(D) and n_antisymmetric_edges > 3 * v - 6)
or (HasChromaticNumber(D) and ChromaticNumber(D) > 4) then
return false;
fi;
- return IS_PLANAR(C);
+ return IS_PLANAR(D);
end);
InstallMethod(IsOuterPlanarDigraph, "for a digraph", [IsDigraph],
function(D)
- local C, v, e;
+ local v, n_antisymmetric_edges;
if HasIsPlanarDigraph(D) and not IsPlanarDigraph(D) then
return false;
fi;
v := DigraphNrVertices(D);
- e := DigraphNrEdges(D);
- if v < 4 or e < 6 then
+ n_antisymmetric_edges := DigraphNrAdjacencies(D) - DigraphNrLoops(D);
+
+ if v < 4 or n_antisymmetric_edges < 6 then
return true;
elif HasChromaticNumber(D) and ChromaticNumber(D) > 3 then
# Outer planar graphs are 3-colourable
return false;
fi;
- C := DigraphMutableCopyIfMutable(D);
- return IS_OUTER_PLANAR(MaximalAntiSymmetricSubdigraph(C));
+ return IS_OUTER_PLANAR(D);
end);
diff --git a/src/digraphs.c b/src/digraphs.c
index 2a397b7d5..90183ccef 100644
--- a/src/digraphs.c
+++ b/src/digraphs.c
@@ -148,7 +148,7 @@ Int DigraphNrAdjacencies(Obj D) {
Obj const out_v = ELM_LIST(out, v);
for (Int w = 1; w <= LEN_LIST(out_v); ++w) {
Int u = INT_INTOBJ(ELM_LIST(out_v, w));
- if (v < u
+ if (v <= u
|| CALL_3ARGS(IsDigraphEdge, D, INTOBJ_INT(u), INTOBJ_INT(v))
== False) {
++nr;
diff --git a/src/planar.c b/src/planar.c
index c36071a79..57bc95cd0 100644
--- a/src/planar.c
+++ b/src/planar.c
@@ -147,16 +147,10 @@ Obj boyers_planarity_check(Obj digraph, int flags, bool krtwsk) {
if (gp_InitGraph(theGraph, V) != OK) {
gp_Free(&theGraph);
- ErrorQuit("Digraphs: boyers_planarity_check (C): invalid number of nodes!",
- 0L,
- 0L);
- return 0L;
+ return Fail;
} else if (gp_EnsureArcCapacity(theGraph, 2 * E) != OK) {
gp_Free(&theGraph);
- ErrorQuit("Digraphs: boyers_planarity_check (C): invalid number of edges!",
- 0L,
- 0L);
- return 0L;
+ return Fail;
}
switch (flags) {
diff --git a/tst/standard/attr.tst b/tst/standard/attr.tst
index 167efe8be..a51a6bed2 100644
--- a/tst/standard/attr.tst
+++ b/tst/standard/attr.tst
@@ -192,6 +192,12 @@ gap> AdjacencyMatrix(Digraph(rec(DigraphNrVertices := 0,
> DigraphRange := [])));
[ ]
+# DigraphNrAdjacencies
+gap> G := RandomDigraph(50);;
+gap> DigraphNrAdjacencies(G) * 2 - DigraphNrLoops(G) =
+> DigraphNrEdges(DigraphSymmetricClosure(G));
+true
+
# DigraphTopologicalSort
gap> r := rec(DigraphNrVertices := 20000,
> DigraphSource := [],
diff --git a/tst/standard/examples.tst b/tst/standard/examples.tst
index e3307afbd..938397521 100644
--- a/tst/standard/examples.tst
+++ b/tst/standard/examples.tst
@@ -249,6 +249,8 @@ gap> DigraphNrVertices(D);
8
gap> DigraphNrEdges(D);
26
+gap> DigraphNrAdjacencies(D);
+13
gap> DigraphUndirectedGirth(D);
3
gap> LollipopGraph(IsMutableDigraph, 5, 3);
diff --git a/tst/standard/planar.tst b/tst/standard/planar.tst
index 80bf205fa..c8f4c8ecf 100644
--- a/tst/standard/planar.tst
+++ b/tst/standard/planar.tst
@@ -235,9 +235,9 @@ gap> IS_PLANAR(2);
Error, Digraphs: boyers_planarity_check (C): the 1st argument must be a digrap\
h, not integer
gap> IS_PLANAR(NullDigraph(0));
-Error, Digraphs: boyers_planarity_check (C): invalid number of nodes!
+fail
gap> IS_PLANAR(NullDigraph(70000));
-Error, Digraphs: boyers_planarity_check (C): invalid number of edges!
+fail
gap> IsPlanarDigraph(NullDigraph(70000));
true
gap> IS_PLANAR(CompleteDigraph(2));
diff --git a/tst/testinstall.tst b/tst/testinstall.tst
index e165c78c2..0012bcd8e 100644
--- a/tst/testinstall.tst
+++ b/tst/testinstall.tst
@@ -246,9 +246,13 @@ gap> gr := DigraphRemoveEdge(gr, [1, 2]);;
gap> gr := DigraphRemoveEdges(gr, [[1, 2], [2, 1]]);;
gap> DigraphNrEdges(gr);
40
+gap> DigraphNrAdjacencies(gr);
+20
gap> gr2 := DigraphClosure(gr, 7);;
gap> DigraphNrEdges(gr2);
42
+gap> DigraphNrAdjacencies(gr2);
+21
# Fix seg fault cause by wrong handling of no edges in
# FuncDIGRAPH_SOURCE_RANGE