Skip to content

Commit

Permalink
Reduce the amount we copy digraphs
Browse files Browse the repository at this point in the history
  • Loading branch information
Joseph-Edwards committed Sep 4, 2024
1 parent ffead72 commit 3bd82a7
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 93 deletions.
22 changes: 22 additions & 0 deletions doc/attr.xml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,28 @@ gap> DigraphNrEdges(D);
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphNrAdjacencies">
<ManSection>
<Attr Name="DigraphNrAdjacencies" Arg="digraph" />
<Returns>An integer.</Returns>
<Description> Returns the number of pairs of adjacent vertices of the digraph <A>digraph</A>. This
function is agnostic to the direction of an edge, so if <A>digraph</A> constains both the edges <M>(a,

Check failure on line 146 in doc/attr.xml

View workflow job for this annotation

GitHub Actions / codespell

constains ==> constrains, contains
b)</M> and <M>(b, a)</M>, this only counts as one adjacency. The following equality holds for
any digraph <C>D</C> with no multiple edges: <C>DigraphNrAdjacencies(D) * 2 - DigraphNrLoops(D)
= DigraphNrEdges(DigraphSymmetricClosure(D))</C>
<Example><![CDATA[
gap> 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
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphNrLoops">
<ManSection>
<Attr Name="DigraphNrLoops" Arg="digraph"/>
Expand Down
1 change: 1 addition & 0 deletions doc/z-chap4.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down
4 changes: 2 additions & 2 deletions gap/attr.gi
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
114 changes: 34 additions & 80 deletions gap/planar.gi
Original file line number Diff line number Diff line change
Expand Up @@ -30,129 +30,83 @@
# 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
########################################################################

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);
2 changes: 1 addition & 1 deletion src/digraphs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 2 additions & 8 deletions src/planar.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
6 changes: 6 additions & 0 deletions tst/standard/attr.tst
Original file line number Diff line number Diff line change
Expand Up @@ -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 := [],
Expand Down
2 changes: 2 additions & 0 deletions tst/standard/examples.tst
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions tst/standard/planar.tst
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
4 changes: 4 additions & 0 deletions tst/testinstall.tst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 3bd82a7

Please sign in to comment.