diff --git a/.gitignore b/.gitignore
index ad376dfd5..42ef9aa39 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,80 +1,62 @@
*.DS_Store
*.Plo
+*.Tpo
*.aux
*.bbl
*.blg
*.brf
*.digraphs
*.g6
+*.gcda
+*.gcno
+*.guess
*.gz
*.html
*.idx
*.ilg
*.ind
+*.la
+*.lab
*.lo
*.log
*.o
-*.orig
*.out
*.pdf
*.pnr
*.pyc
*.six
+*.status
+*.sub
*.swp
*.synctex.gz
*.tex
+*.tex
*.toc
*.top
*.tui
*.txt
-.libs/digraphs.la
-.libs/digraphs.lai
-.libs/**/digraphs.so
-.libs/graphs.la
-.libs/graphs.lai
-.libs/graphs.so
+.dirstamp
+.libs/*
Makefile
Makefile.in
-Transitions*
aclocal.m4
autom4te.*
bin/*
-cnf/ar-lib
-cnf/compile
-cnf/config.guess
-cnf/config.sub
-cnf/depcomp
-cnf/install-sh
-cnf/ltmain.sh
-cnf/missing
-cnf/pkgconfig.h.in
-config.status
+cnf/*
configure
+digraphs-config.h
digraphs-lib
-digraphs.la
-digraphs.tex
-digraphs_dev.tex
-digraphs_la-homos.Tpo
-digraphs_la-schreier-sims.Tpo
-graphs.la
+gh-pages/
libtool
-m4/libtool.m4
-m4/ltoptions.m4
-m4/ltsugar.m4
-m4/ltversion.m4
-m4/lt~obsolete.m4
-mt-cc.py
-pkgconfig.h.in~
-release-checklist.tst
-src/.deps/.dirstamp
-src/.deps/digraphs_la-digraphs.Plo
-src/.deps/digraphs_la-digraphs.Tpo
-src/.dirstamp
-src/.libs/digraphs_la-digraphs.o
-src/bliss-0.72/.deps/.dirstamp
-src/bliss-0.72/.dirstamp
-src/digraphs_la-digraphs.lo
+ltmain.sh
+m4/*
+planarity
+src/.deps/*
+src/.libs/*
src/_pkgconfig.h
+src/edge-addition-planarity-suite-Version_3.0.0.5/.libs
+src/edge-addition-planarity-suite-Version_3.0.0.5/c/.deps
+src/edge-addition-planarity-suite-Version_3.0.0.5/m4
src/stamp-h1
tags
tst/out/*
diff --git a/Makefile.am b/Makefile.am
index ff3b59ade..9d8817e41 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,31 +4,47 @@
# This file is part of the build system of a GAP kernel extension.
# Requires automake.
#
+
ACLOCAL_AMFLAGS = -I m4
+SUBDIRS = @PLANARITY_SUITE_DIR@
+
+PLANAR_INCLUDE = -I@PLANARITY_SUITE_DIR@/
+
BINARCHDIR = bin/$(GAPARCH)
-GAPINSTALLLIB = $(abs_top_srcdir)/$(BINARCHDIR)/digraphs.so
+GAPINSTALLLIB = $(abs_top_srcdir)/$(BINARCHDIR)/
lib_LTLIBRARIES = digraphs.la
-digraphs_la_SOURCES = src/digraphs.c src/homos.c src/perms.c src/schreier-sims.c
-digraphs_la_SOURCES += src/bliss-0.73/defs.cc src/bliss-0.73/graph.cc
-digraphs_la_SOURCES += src/bliss-0.73/partition.cc src/bliss-0.73/orbit.cc
-digraphs_la_SOURCES += src/bliss-0.73/uintseqhash.cc src/bliss-0.73/heap.cc
-digraphs_la_SOURCES += src/bliss-0.73/timer.cc src/bliss-0.73/utils.cc
+digraphs_la_SOURCES = src/digraphs.c
+digraphs_la_SOURCES += src/homos.c
+digraphs_la_SOURCES += src/perms.c
+digraphs_la_SOURCES += src/planar.c
+digraphs_la_SOURCES += src/schreier-sims.c
+digraphs_la_SOURCES += src/bliss-0.73/defs.cc
+digraphs_la_SOURCES += src/bliss-0.73/graph.cc
+digraphs_la_SOURCES += src/bliss-0.73/partition.cc
+digraphs_la_SOURCES += src/bliss-0.73/orbit.cc
+digraphs_la_SOURCES += src/bliss-0.73/uintseqhash.cc
+digraphs_la_SOURCES += src/bliss-0.73/heap.cc
+digraphs_la_SOURCES += src/bliss-0.73/timer.cc
+digraphs_la_SOURCES += src/bliss-0.73/utils.cc
digraphs_la_SOURCES += src/bliss-0.73/bliss_C.cc
-digraphs_la_CPPFLAGS = $(GAP_CPPFLAGS)
-digraphs_la_CXXFLAGS = -O3 -march=native -mpopcnt
-digraphs_la_CFLAGS = -O3 -march=native -mpopcnt $(GAP_CFLAGS)
+digraphs_la_CPPFLAGS = $(GAP_CPPFLAGS)
+digraphs_la_CXXFLAGS = -O3 -march=native -mpopcnt $(PLANAR_INCLUDE)
+digraphs_la_CFLAGS = -O3 -march=native -mpopcnt $(GAP_CFLAGS) $(PLANAR_INCLUDE)
digraphs_la_LDFLAGS = $(GAP_LDFLAGS) -module -avoid-version
+digraphs_la_LIBADD = @PLANARITY_SUITE_DIR@/libplanarity.la
+
if SYS_IS_CYGWIN
digraphs_la_LDFLAGS += -no-undefined -version-info 0:0:0 -Wl,$(GAPROOT)/bin/$(GAPARCH)/gap.dll
endif
all-local: digraphs.la
- $(mkdir_p) $(top_srcdir)/$(BINARCHDIR)
+ $(mkdir_p) $(top_srcdir)/$(BINARCHDIR) $(top_srcdir)/bin/lib
+ cp -RL @PLANARITY_SUITE_DIR@/.libs/* $(top_srcdir)/bin/lib/
if SYS_IS_CYGWIN
cp .libs/digraphs.dll $(GAPINSTALLLIB)
else
diff --git a/configure.ac b/configure.ac
index b4c933e74..94afe0a4f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
#
-# graphs:
+# digraphs
#
# This file is part of the build system of a GAP kernel extension.
# Requires GNU autoconf, GNU automake and GNU libtool.
@@ -14,6 +14,10 @@ AC_CONFIG_SRCDIR([src/digraphs.c])
AC_CONFIG_HEADER([src/_pkgconfig.h:cnf/pkgconfig.h.in])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_AUX_DIR([cnf])
+AC_CONFIG_SUBDIRS([src/edge-addition-planarity-suite-Version_3.0.0.5])
+
+PLANARITY_SUITE_DIR=src/edge-addition-planarity-suite-Version_3.0.0.5
+AC_SUBST(PLANARITY_SUITE_DIR)
dnl ##
dnl ## Get canonical host info
@@ -29,6 +33,8 @@ AM_PROG_AR
AX_PREFIX_CONFIG_H([src/digraphs-config.h],[],[src/_pkgconfig.h])
+AC_PREFIX_DEFAULT('${abs_top_builddir}/../../bin/')
+
dnl ##
dnl ## Set the language
dnl ##
diff --git a/doc/attr.xml b/doc/attr.xml
index e70a0630e..5b3761a41 100644
--- a/doc/attr.xml
+++ b/doc/attr.xml
@@ -1352,3 +1352,36 @@ gap> HamiltonianPath(g);
<#/GAPDoc>
+
+<#GAPDoc Label="MaximalAntiSymmetricSubdigraph">
+
+
+ A digraph.
+
+ If digraph is a digraph, then MaximalAntiSymmetricSubdigraph
+ returns a anti-symmetric subdigraph of digraph which does not have
+ multiple edges, has the same vertex set as digraph, and whose
+ edge list is formed from digraph by ignoring the multiplicity of
+ edges, and by having either an edge from the vertex u to the vertex
+ v, or the edge from v to u (but not both) whenever
+ both edges belong to digraph.
+
+
+ See for more information.
+ D := Digraph([[2, 2], [1, 3], [4], [3, 1]]);
+
+gap> not IsAntiSymmetricDigraph(D) and IsMultiDigraph(D);
+true
+gap> OutNeighbours(D);
+[ [ 2, 2 ], [ 1, 3 ], [ 4 ], [ 3, 1 ] ]
+gap> D := MaximalAntiSymmetricSubdigraph(D);
+
+gap> IsAntiSymmetricDigraph(D) and not IsMultiDigraph(D);
+true
+gap> OutNeighbours(D);
+[ [ 2 ], [ 3 ], [ 4 ], [ 1 ] ]
+]]>
+
+
+<#/GAPDoc>
diff --git a/doc/digraphs.bib b/doc/digraphs.bib
index 459a70e54..06d04084e 100644
--- a/doc/digraphs.bib
+++ b/doc/digraphs.bib
@@ -1,26 +1,41 @@
%% This BibTeX bibliography file was created using BibDesk.
-%% http://bibdesk.sourceforge.net/
+%% https://bibdesk.sourceforge.io/
-
-%% Created for James Mitchell at 2014-10-31 17:35:22 +0000
+%% Created for James Mitchell at 2018-12-13 18:13:21 +0000
%% Saved with string encoding Unicode (UTF-8)
-@article{McKay201494,
-title = "Practical graph isomorphism, \{II\} ",
-journal = "Journal of Symbolic Computation ",
-volume = "60",
-number = "0",
-pages = "94 - 112",
-year = "2014",
-note = "",
-issn = "0747-7171",
-doi = "http://dx.doi.org/10.1016/j.jsc.2013.09.003",
-url = "http://www.sciencedirect.com/science/article/pii/S0747717113001193",
-author = "Brendan D. McKay and Adolfo Piperno"
-}
+
+@incollection{Boyer2006aa,
+ Author = {John M. Boyer and Wendy J. Myrvold},
+ Booktitle = {Graph Algorithms and Applications 5},
+ Date-Added = {2018-12-13 18:10:56 +0000},
+ Date-Modified = {2018-12-13 18:11:05 +0000},
+ Doi = {10.1142/9789812773289_0014},
+ Month = {jun},
+ Pages = {241--273},
+ Publisher = {{WORLD} {SCIENTIFIC}},
+ Title = {On the Cutting Edge: Simplified O(n) Planarity by Edge Addition},
+ Url = {https://doi.org/10.1142/9789812773289_0014},
+ Year = {2006},
+ Bdsk-Url-1 = {https://doi.org/10.1142/9789812773289_0014}}
+
+@article{McKay201494,
+ Author = {Brendan D. McKay and Adolfo Piperno},
+ Doi = {http://dx.doi.org/10.1016/j.jsc.2013.09.003},
+ Issn = {0747-7171},
+ Journal = {Journal of Symbolic Computation},
+ Number = {0},
+ Pages = {94 - 112},
+ Title = {Practical graph isomorphism, \{II\}},
+ Url = {http://www.sciencedirect.com/science/article/pii/S0747717113001193},
+ Volume = {60},
+ Year = {2014},
+ Bdsk-Url-1 = {http://www.sciencedirect.com/science/article/pii/S0747717113001193},
+ Bdsk-Url-2 = {http://dx.doi.org/10.1016/j.jsc.2013.09.003}}
+
@article{Gabow2000aa,
Author = {Harold N. Gabow},
Date-Added = {2014-09-15 09:28:26 +0000},
@@ -35,76 +50,67 @@ @article{Gabow2000aa
Url = {http://www.sciencedirect.com/science/article/pii/S002001900000051X},
Volume = {74},
Year = {2000},
- Bdsk-File-1 = {YnBsaXN0MDDUAQIDBAUGJCVYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKgHCBMUFRYaIVUkbnVsbNMJCgsMDxJXTlMua2V5c1pOUy5vYmplY3RzViRjbGFzc6INDoACgAOiEBGABIAFgAdccmVsYXRpdmVQYXRoWWFsaWFzRGF0YV8QTS4uLy4uLy4uLy4uLy4uLy4uL1ZvbHVtZXMvR29vZ2xlRHJpdmUvRmlsZWQvMS1zMi4wLVMwMDIwMDE5MDAwMDAwNTFYLW1haW4ucGRm0hcLGBlXTlMuZGF0YU8RAY4AAAAAAY4AAgAAC0dvb2dsZURyaXZlAAAAAAAAAAAAAAAAAAAAAAAAAABCRAAB/////x8xLXMyLjAtUzAwMjAwMTkwMDAjRkZGRkZGRkYucGRmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////AAAAAAAAAAAAAAAA/////wAAEgBjdQAAAAAAAAAAAAAAAAAFRmlsZWQAAAIAPS86Vm9sdW1lczpHb29nbGVEcml2ZTpGaWxlZDoxLXMyLjAtUzAwMjAwMTkwMDAwMDA1MVgtbWFpbi5wZGYAAA4ARAAhADEALQBzADIALgAwAC0AUwAwADAAMgAwADAAMQA5ADAAMAAwADAAMAAwADUAMQBYAC0AbQBhAGkAbgAuAHAAZABmAA8AGAALAEcAbwBvAGcAbABlAEQAcgBpAHYAZQASACgvRmlsZWQvMS1zMi4wLVMwMDIwMDE5MDAwMDAwNTFYLW1haW4ucGRmABMAFC9Wb2x1bWVzL0dvb2dsZURyaXZl//8AAIAG0hscHR5aJGNsYXNzbmFtZVgkY2xhc3Nlc11OU011dGFibGVEYXRhox0fIFZOU0RhdGFYTlNPYmplY3TSGxwiI1xOU0RpY3Rpb25hcnmiIiBfEA9OU0tleWVkQXJjaGl2ZXLRJidUcm9vdIABAAgAEQAaACMALQAyADcAQABGAE0AVQBgAGcAagBsAG4AcQBzAHUAdwCEAI4A3gDjAOsCfQJ/AoQCjwKYAqYCqgKxAroCvwLMAs8C4QLkAukAAAAAAAACAQAAAAAAAAAoAAAAAAAAAAAAAAAAAAAC6w==},
+ Bdsk-File-1 = {YnBsaXN0MDDSAQIDBFxyZWxhdGl2ZVBhdGhZYWxpYXNEYXRhXxBNLi4vLi4vLi4vLi4vLi4vLi4vVm9sdW1lcy9Hb29nbGVEcml2ZS9GaWxlZC8xLXMyLjAtUzAwMjAwMTkwMDAwMDA1MVgtbWFpbi5wZGZPEQGOAAAAAAGOAAIAAAtHb29nbGVEcml2ZQAAAAAAAAAAAAAAAAAAAAAAAAAAQkQAAf////8fMS1zMi4wLVMwMDIwMDE5MDAwI0ZGRkZGRkZGLnBkZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////wAAAAAAAAAAAAAAAP////8AABIAY3UAAAAAAAAAAAAAAAAABUZpbGVkAAACAD0vOlZvbHVtZXM6R29vZ2xlRHJpdmU6RmlsZWQ6MS1zMi4wLVMwMDIwMDE5MDAwMDAwNTFYLW1haW4ucGRmAAAOAEQAIQAxAC0AcwAyAC4AMAAtAFMAMAAwADIAMAAwADEAOQAwADAAMAAwADAAMAA1ADEAWAAtAG0AYQBpAG4ALgBwAGQAZgAPABgACwBHAG8AbwBnAGwAZQBEAHIAaQB2AGUAEgAoL0ZpbGVkLzEtczIuMC1TMDAyMDAxOTAwMDAwMDUxWC1tYWluLnBkZgATABQvVm9sdW1lcy9Hb29nbGVEcml2Zf//AAAACAANABoAJAB0AAAAAAAAAgEAAAAAAAAABQAAAAAAAAAAAAAAAAAAAgY=},
Bdsk-Url-1 = {http://www.sciencedirect.com/science/article/pii/S002001900000051X},
Bdsk-Url-2 = {http://dx.doi.org/10.1016/S0020-0190(00)00051-X}}
-@InProceedings{JunttilaKaski,
- author = {Tommi Junttila and Petteri Kaski},
- title = {Engineering an efficient canonical labeling tool for
- large and sparse graphs},
- booktitle = {Proceedings of the Ninth Workshop on Algorithm Engineering
- and Experiments and
- the Fourth Workshop on Analytic Algorithms and
- Combinatorics},
- pages = {135--149},
- year = {2007},
- editor = {David Applegate and Gerth St{\o}lting Brodal and
- Daniel Panario and Robert Sedgewick},
- OPTaddress = {New Orleans, LA},
- OPTmonth = {January 6},
- publisher = {SIAM},
- OPTpublisher = {Society for Industrial and Applied Mathematics},
-}
+@inproceedings{JunttilaKaski,
+ Author = {Tommi Junttila and Petteri Kaski},
+ Booktitle = {Proceedings of the Ninth Workshop on Algorithm Engineering and Experiments and the Fourth Workshop on Analytic Algorithms and Combinatorics},
+ Editor = {David Applegate and Gerth St{\o}lting Brodal and Daniel Panario and Robert Sedgewick},
+ Optaddress = {New Orleans, LA},
+ Optmonth = {January 6},
+ Optpublisher = {Society for Industrial and Applied Mathematics},
+ Pages = {135--149},
+ Publisher = {SIAM},
+ Title = {Engineering an efficient canonical labeling tool for large and sparse graphs},
+ Year = {2007}}
-@article {CalderbankKantor1986,
- AUTHOR = {Calderbank, R. and Kantor, W. M.},
- TITLE = {The geometry of two-weight codes},
- JOURNAL = {Bull. London Math. Soc.},
- FJOURNAL = {The Bulletin of the London Mathematical Society},
- VOLUME = {18},
- YEAR = {1986},
- NUMBER = {2},
- PAGES = {97--122},
- ISSN = {0024-6093},
- CODEN = {LMSBBT},
- MRCLASS = {51E20 (05B25 05C25 94B60)},
- MRNUMBER = {818812 (87h:51022)},
-MRREVIEWER = {J. W. P. Hirschfeld},
- DOI = {10.1112/blms/18.2.97},
- URL = {http://dx.doi.org/10.1112/blms/18.2.97},
-}
+@article{CalderbankKantor1986,
+ Author = {Calderbank, R. and Kantor, W. M.},
+ Coden = {LMSBBT},
+ Doi = {10.1112/blms/18.2.97},
+ Fjournal = {The Bulletin of the London Mathematical Society},
+ Issn = {0024-6093},
+ Journal = {Bull. London Math. Soc.},
+ Mrclass = {51E20 (05B25 05C25 94B60)},
+ Mrnumber = {818812 (87h:51022)},
+ Mrreviewer = {J. W. P. Hirschfeld},
+ Number = {2},
+ Pages = {97--122},
+ Title = {The geometry of two-weight codes},
+ Url = {http://dx.doi.org/10.1112/blms/18.2.97},
+ Volume = {18},
+ Year = {1986},
+ Bdsk-Url-1 = {http://dx.doi.org/10.1112/blms/18.2.97}}
-@article {vanLintSchrijver1981,
- AUTHOR = {van Lint, J. H. and Schrijver, A.},
- TITLE = {Construction of strongly regular graphs, two-weight codes and
- partial geometries by finite fields},
- JOURNAL = {Combinatorica},
- FJOURNAL = {Combinatorica. An International Journal of the J\'anos Bolyai
- Mathematical Society},
- VOLUME = {1},
- YEAR = {1981},
- NUMBER = {1},
- PAGES = {63--73},
- ISSN = {0209-9683},
- CODEN = {COMBDI},
- MRCLASS = {05B25 (05C25 94B25)},
- MRNUMBER = {602417 (82d:05041)},
-MRREVIEWER = {Joseph A. Thas},
- DOI = {10.1007/BF02579178},
- URL = {http://dx.doi.org/10.1007/BF02579178},
-}
+@article{vanLintSchrijver1981,
+ Author = {van Lint, J. H. and Schrijver, A.},
+ Coden = {COMBDI},
+ Doi = {10.1007/BF02579178},
+ Fjournal = {Combinatorica. An International Journal of the J\'anos Bolyai Mathematical Society},
+ Issn = {0209-9683},
+ Journal = {Combinatorica},
+ Mrclass = {05B25 (05C25 94B25)},
+ Mrnumber = {602417 (82d:05041)},
+ Mrreviewer = {Joseph A. Thas},
+ Number = {1},
+ Pages = {63--73},
+ Title = {Construction of strongly regular graphs, two-weight codes and partial geometries by finite fields},
+ Url = {http://dx.doi.org/10.1007/BF02579178},
+ Volume = {1},
+ Year = {1981},
+ Bdsk-Url-1 = {http://dx.doi.org/10.1007/BF02579178}}
@article{Welsh1967aa,
-author = {Welsh, D. J. A. and Powell, M. B.},
-title = {An upper bound for the chromatic number of a graph and its application to timetabling problems},
-journal = {The Computer Journal},
-volume = {10},
-number = {1},
-pages = {85-86},
-year = {1967},
-doi = {10.1093/comjnl/10.1.85},
-URL = {http://dx.doi.org/10.1093/comjnl/10.1.85},
-eprint = {/oup/backfile/content_public/journal/comjnl/10/1/10.1093/comjnl/10.1.85/2/100085.pdf}
-}
-
+ Author = {Welsh, D. J. A. and Powell, M. B.},
+ Doi = {10.1093/comjnl/10.1.85},
+ Eprint = {/oup/backfile/content_public/journal/comjnl/10/1/10.1093/comjnl/10.1.85/2/100085.pdf},
+ Journal = {The Computer Journal},
+ Number = {1},
+ Pages = {85-86},
+ Title = {An upper bound for the chromatic number of a graph and its application to timetabling problems},
+ Url = {http://dx.doi.org/10.1093/comjnl/10.1.85},
+ Volume = {10},
+ Year = {1967},
+ Bdsk-Url-1 = {http://dx.doi.org/10.1093/comjnl/10.1.85}}
diff --git a/doc/main.xml b/doc/main.xml
index 40058ee12..b75c4d545 100644
--- a/doc/main.xml
+++ b/doc/main.xml
@@ -6,6 +6,9 @@
http://www.tcs.tkk.fi/Software/bliss/bliss">
+ https://github.com/graph-algorithms/edge-addition-planarity-suiteedge-addition-planarity-suite">
http://pallini.di.uniroma1.it/nauty">
diff --git a/doc/planar.xml b/doc/planar.xml
new file mode 100644
index 000000000..2bcc113ba
--- /dev/null
+++ b/doc/planar.xml
@@ -0,0 +1,318 @@
+#############################################################################
+##
+#W planar.xml
+#Y Copyright (C) 2018 James D. Mitchell
+##
+## Licensing information can be found in the README file of this package.
+##
+#############################################################################
+##
+
+<#GAPDoc Label="IsPlanarDigraph">
+
+
+ true or false.
+
+ A planar digraph is a digraph that can be embedded in the plane in
+ such a way that its edges do not intersect. A digraph is planar if and only
+ if it does not have a subdigraph that is homeomorphic to either the
+ complete graph on 5 vertices or the complete bipartite graph with
+ vertex sets of sizes 3 and 3.
+
+
+ IsPlanarDigraph returns true if the digraph digraph is
+ planar and false if it is not. The directions and multiplicities of
+ any edges in digraph are ignored by IsPlanarDigraph.
+
+
+ See also .
+
+
+ This method uses the reference implementation in
+ &edge-addition-planarity-suite; by John Boyer of the algorithms described
+ in .
+
+ IsPlanarDigraph(CompleteDigraph(4));
+true
+gap> IsPlanarDigraph(CompleteDigraph(5));
+false
+gap> IsPlanarDigraph(CompleteBipartiteDigraph(2, 3));
+true
+gap> IsPlanarDigraph(CompleteBipartiteDigraph(3, 3));
+false
+]]>
+
+
+<#/GAPDoc>
+
+<#GAPDoc Label="IsOuterPlanarDigraph">
+
+
+ true or false.
+
+ An outer planar digraph is a digraph that can be embedded in the
+ plane in such a way that its edges do not intersect, and all vertices
+ belong to the unbounded face of the embedding. A digraph is outer planar
+ if and only if it does not have a subdigraph that is homeomorphic to either
+ the complete graph on 4 vertices or the complete bipartite graph
+ with vertex sets of sizes 2 and 3.
+
+
+ IsOuterPlanarDigraph returns true if the digraph
+ digraph is outer planar and false if it is not. The
+ directions and multiplicities of any edges in digraph are ignored by
+ IsPlanarDigraph.
+
+ See also .
+
+ This method uses the reference implementation in
+ &edge-addition-planarity-suite; by John Boyer of the algorithms described
+ in .
+
+ IsOuterPlanarDigraph(CompleteDigraph(4));
+false
+gap> IsOuterPlanarDigraph(CompleteDigraph(5));
+false
+gap> IsOuterPlanarDigraph(CompleteBipartiteDigraph(2, 3));
+false
+gap> IsOuterPlanarDigraph(CompleteBipartiteDigraph(3, 3));
+false
+gap> IsOuterPlanarDigraph(CycleDigraph(10));
+true
+]]>
+
+
+<#/GAPDoc>
+
+<#GAPDoc Label="KuratowskiPlanarSubdigraph">
+
+
+ A list or fail.
+
+ KuratowskiPlanarSubdigraph returns the list of out-neighbours of a
+ (not necessarily induced) subdigraph of the digraph digraph that
+ witnesses the fact that digraph is not planar, or fail if
+ digraph is planar. In other words,
+ KuratowskiPlanarSubdigraph returns the out-neighbours of a
+ subdigraph of digraph that is homeomorphic to the complete graph
+ with 5 vertices, or to the complete bipartite graph with vertex sets
+ of sizes 3 and 3.
+
+ The directions and multiplicities of any edges in digraph are
+ ignored when considering whether or not digraph is planar.
+
+ See also
+ and .
+
+
+ This method uses the reference implementation in
+ &edge-addition-planarity-suite; by John Boyer of the algorithms described
+ in .
+
+ D := Digraph([[3, 5, 10], [8, 9, 10], [1, 4], [3, 6],
+> [1, 7, 11], [4, 7], [6, 8], [2, 7], [2, 11], [1, 2], [5, 9]]);
+
+gap> KuratowskiPlanarSubdigraph(D);
+fail
+gap> D := Digraph([[2, 4, 7, 9, 10], [1, 3, 4, 6, 9, 10], [6, 10],
+> [2, 5, 8, 9], [1, 2, 3, 4, 6, 7, 9, 10], [3, 4, 5, 7, 9, 10],
+> [3, 4, 5, 6, 9, 10], [3, 4, 5, 7, 9], [2, 3, 5, 6, 7, 8], [3, 5]]);
+
+gap> IsPlanarDigraph(D);
+false
+gap> KuratowskiPlanarSubdigraph(D);
+[ [ 2, 9, 7 ], [ 3 ], [ 6 ], [ 5, 9 ], [ 6 ], [ ], [ 4 ],
+ [ 7, 9, 3 ], [ ], [ ] ]
+]]>
+
+
+<#/GAPDoc>
+
+<#GAPDoc Label="KuratowskiOuterPlanarSubdigraph">
+
+
+ A list or fail.
+
+ KuratowskiOuterPlanarSubdigraph returns the list of out-neighbours
+ of a (not necessarily induced) subdigraph of the digraph digraph
+ that witnesses the fact that digraph is not outer planar, or
+ fail if digraph is outer planar. In other words,
+ KuratowskiOuterPlanarSubdigraph returns the out-neighbours of a
+ subdigraph of digraph that is homeomorphic to the complete graph
+ with 4 vertices, or to the complete bipartite graph with vertex sets
+ of sizes 2 and 3.
+
+ The directions and multiplicities of any edges in digraph are
+ ignored when considering whether or not digraph is outer planar.
+
+
+ See also
+ ,
+ , and
+ .
+
+
+ This method uses the reference implementation in
+ &edge-addition-planarity-suite; by John Boyer of the algorithms described
+ in .
+
+ D := Digraph([[3, 5, 10], [8, 9, 10], [1, 4], [3, 6],
+> [1, 7, 11], [4, 7], [6, 8], [2, 7], [2, 11], [1, 2], [5, 9]]);
+
+gap> KuratowskiOuterPlanarSubdigraph(D);
+[ [ 3, 5, 10 ], [ 9, 8, 10 ], [ 4 ], [ 6 ], [ 11 ], [ 7 ], [ 8 ],
+ [ ], [ 11 ], [ ], [ ] ]
+gap> D := Digraph([[2, 4, 7, 9, 10], [1, 3, 4, 6, 9, 10], [6, 10],
+> [2, 5, 8, 9], [1, 2, 3, 4, 6, 7, 9, 10], [3, 4, 5, 7, 9, 10],
+> [3, 4, 5, 6, 9, 10], [3, 4, 5, 7, 9], [2, 3, 5, 6, 7, 8], [3, 5]]);
+
+gap> IsOuterPlanarDigraph(D);
+false
+gap> KuratowskiOuterPlanarSubdigraph(D);
+[ [ ], [ ], [ ], [ 8, 9 ], [ ], [ ], [ 9, 4 ], [ 7, 9 ], [ ],
+ [ ] ]
+]]>
+
+
+<#/GAPDoc>
+
+<#GAPDoc Label="PlanarEmbedding">
+
+
+ A list or fail.
+
+ If digraph is a planar digraph, then
+ PlanarEmbedding returns the list of out-neighbours
+ of a subdigraph of digraph such that each vertex's
+ neighbours are given in clockwise order. If digraph is not planar,
+ then fail is returned.
+
+ The directions and multiplicities of any edges in digraph are
+ ignored by PlanarEmbedding.
+
+
+ See also
+ .
+
+
+ This method uses the reference implementation in
+ &edge-addition-planarity-suite; by John Boyer of the algorithms described
+ in .
+
+ D := Digraph([[3, 5, 10], [8, 9, 10], [1, 4], [3, 6],
+> [1, 7, 11], [4, 7], [6, 8], [2, 7], [2, 11], [1, 2], [5, 9]]);
+
+gap> PlanarEmbedding(D);
+[ [ 3, 10, 5 ], [ 10, 8, 9 ], [ 4 ], [ 6 ], [ 11, 7 ], [ 7 ], [ 8 ],
+ [ ], [ 11 ], [ ], [ ] ]
+gap> D := Digraph([[2, 4, 7, 9, 10], [1, 3, 4, 6, 9, 10], [6, 10],
+> [2, 5, 8, 9], [1, 2, 3, 4, 6, 7, 9, 10], [3, 4, 5, 7, 9, 10],
+> [3, 4, 5, 6, 9, 10], [3, 4, 5, 7, 9], [2, 3, 5, 6, 7, 8], [3, 5]]);
+
+gap> PlanarEmbedding(D);
+fail
+]]>
+
+
+<#/GAPDoc>
+
+<#GAPDoc Label="OuterPlanarEmbedding">
+
+
+ A list or fail.
+
+ If digraph is an outer planar digraph, then
+ OuterPlanarEmbedding returns the list of out-neighbours of a
+ subdigraph of digraph such that each vertex's neighbours are given
+ in clockwise order. If digraph is not outer planar, then fail
+ is returned.
+
+ The directions and multiplicities of any edges in digraph are
+ ignored by OuterPlanarEmbedding.
+
+
+ See also .
+
+
+ This method uses the reference implementation in
+ &edge-addition-planarity-suite; by John Boyer of the algorithms described
+ in .
+
+ D := Digraph([[3, 5, 10], [8, 9, 10], [1, 4], [3, 6],
+> [1, 7, 11], [4, 7], [6, 8], [2, 7], [2, 11], [1, 2], [5, 9]]);
+
+gap> OuterPlanarEmbedding(D);
+fail
+gap> D := Digraph([[2, 4, 7, 9, 10], [1, 3, 4, 6, 9, 10], [6, 10],
+> [2, 5, 8, 9], [1, 2, 3, 4, 6, 7, 9, 10], [3, 4, 5, 7, 9, 10],
+> [3, 4, 5, 6, 9, 10], [3, 4, 5, 7, 9], [2, 3, 5, 6, 7, 8], [3, 5]]);
+
+gap> OuterPlanarEmbedding(D);
+fail
+gap> OuterPlanarEmbedding(CompleteBipartiteDigraph(2, 2));
+[ [ 3, 4 ], [ 4, 3 ], [ ], [ ] ]
+]]>
+
+
+<#/GAPDoc>
+
+<#GAPDoc Label="SubdigraphHomeomorphicToK">
+
+
+
+
+ A list or fail.
+
+ These attributes return the list of out-neighbours of a subdigraph of
+ the digraph digraph which is homeomorphic to one of the following:
+ the complete bipartite graph with vertex sets of sizes 2 and
+ 3; the complete bipartite graph with vertex sets of sizes 3
+ and 3; or the complete graph with 4 vertices. If
+ digraph has no such subdigraphs, then fail is returned.
+
+
+ See also and for more details.
+
+ This method uses the reference implementation in
+ &edge-addition-planarity-suite; by John Boyer of the algorithms described
+ in .
+
+ D := Digraph([[3, 5, 10], [8, 9, 10], [1, 4], [3, 6], [1, 7, 11],
+> [4, 7], [6, 8], [2, 7], [2, 11], [1, 2], [5, 9]]);
+
+gap> SubdigraphHomeomorphicToK4(D);
+[ [ 3, 5, 10 ], [ 9, 8, 10 ], [ 4 ], [ 6 ], [ 7, 11 ], [ 7 ], [ 8 ],
+ [ ], [ 11 ], [ ], [ ] ]
+gap> SubdigraphHomeomorphicToK23(D);
+[ [ 3, 5, 10 ], [ 9, 8, 10 ], [ 4 ], [ 6 ], [ 11 ], [ 7 ], [ 8 ],
+ [ ], [ 11 ], [ ], [ ] ]
+gap> D := Digraph([[3, 5, 10], [8, 9, 10], [1, 4], [3, 6], [1, 11],
+> [4, 7], [6, 8], [2, 7], [2, 11], [1, 2], [5, 9]]);
+
+gap> SubdigraphHomeomorphicToK4(D);
+fail
+gap> SubdigraphHomeomorphicToK23(D);
+[ [ 3, 10, 5 ], [ 10, 8, 9 ], [ 4 ], [ 6 ], [ 11 ], [ 7 ], [ 8 ],
+ [ ], [ 11 ], [ ], [ ] ]
+gap> SubdigraphHomeomorphicToK33(D);
+fail
+gap> SubdigraphHomeomorphicToK23(NullDigraph(0));
+fail
+gap> SubdigraphHomeomorphicToK33(CompleteDigraph(5));
+fail
+gap> SubdigraphHomeomorphicToK33(CompleteBipartiteDigraph(3, 3));
+[ [ 4, 6, 5 ], [ 4, 5, 6 ], [ 6, 5, 4 ], [ ], [ ], [ ] ]
+gap> SubdigraphHomeomorphicToK4(CompleteDigraph(3));
+fail
+]]>
+
+
+<#/GAPDoc>
diff --git a/doc/z-chap2.xml b/doc/z-chap2.xml
index 52b01d9e7..4265e3f38 100644
--- a/doc/z-chap2.xml
+++ b/doc/z-chap2.xml
@@ -28,6 +28,7 @@
<#Include Label="InducedSubdigraph">
<#Include Label="ReducedDigraph">
<#Include Label="MaximalSymmetricSubdigraph">
+ <#Include Label="MaximalAntiSymmetricSubdigraph">
<#Include Label="UndirectedSpanningTree">
<#Include Label="QuotientDigraph">
<#Include Label="DigraphReverse">
diff --git a/doc/z-chap4.xml b/doc/z-chap4.xml
index fae693463..6193030fc 100644
--- a/doc/z-chap4.xml
+++ b/doc/z-chap4.xml
@@ -69,5 +69,13 @@
Associated semigroups
<#Include Label="AsSemigroup">
+
+ Planarity
+ <#Include Label="KuratowskiPlanarSubdigraph">
+ <#Include Label="KuratowskiOuterPlanarSubdigraph">
+ <#Include Label="PlanarEmbedding">
+ <#Include Label="OuterPlanarEmbedding">
+ <#Include Label="SubdigraphHomeomorphicToK">
+
diff --git a/doc/z-chap5.xml b/doc/z-chap5.xml
index 966f7d459..bd11f80f1 100644
--- a/doc/z-chap5.xml
+++ b/doc/z-chap5.xml
@@ -39,4 +39,9 @@
<#Include Label="IsCycleDigraph">
+ Planarity
+ <#Include Label="IsPlanarDigraph">
+ <#Include Label="IsOuterPlanarDigraph">
+
+
diff --git a/doc/z-title.xml b/doc/z-title.xml
index 61ea4188d..bb92d739f 100644
--- a/doc/z-title.xml
+++ b/doc/z-title.xml
@@ -1,6 +1,5 @@
&Digraphs;
- Methods for digraphs
Version &VERSION;
Jan De Beule
@@ -57,8 +56,8 @@
- We would like to thank Christopher Jefferson for his help in including the
- &bliss; tool in the package.
+ 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.
diff --git a/gap/attr.gd b/gap/attr.gd
index 1bb2dfe88..365b98346 100644
--- a/gap/attr.gd
+++ b/gap/attr.gd
@@ -64,6 +64,7 @@ DeclareAttribute("AdjacencyMatrix", IsDigraph);
DeclareAttribute("BooleanAdjacencyMatrix", IsDigraph);
DeclareAttribute("ReducedDigraph", IsDigraph);
DeclareAttribute("MaximalSymmetricSubdigraph", IsDigraph);
+DeclareAttribute("MaximalAntiSymmetricSubdigraph", IsDigraph);
DeclareAttribute("MaximalSymmetricSubdigraphWithoutLoops", IsDigraph);
DeclareOperation("DIGRAPHS_MaximalSymmetricSubdigraph", [IsDigraph, IsBool]);
diff --git a/gap/attr.gi b/gap/attr.gi
index e57a0ce67..348ce6b68 100644
--- a/gap/attr.gi
+++ b/gap/attr.gi
@@ -1483,3 +1483,50 @@ function(gr)
od;
return fail;
end);
+
+InstallMethod(MaximalAntiSymmetricSubdigraph, "for a digraph",
+[IsDigraph],
+function(D)
+ local n, m, out, i, j;
+
+ n := DigraphNrVertices(D);
+ if IsMultiDigraph(D) then
+ return MaximalAntiSymmetricSubdigraph(DigraphRemoveAllMultipleEdges(D));
+ elif n <= 1
+ or (HasIsAntisymmetricDigraph(D) and IsAntisymmetricDigraph(D)) then
+ return D;
+ fi;
+
+ # The average degree
+ m := Float(Sum(OutDegreeSequence(D)) / n);
+
+ if Float(n * (n - 1) / 2) < n * m * Log2(m) then
+ # The approximate complexity of using the adjacency matrix (first method)
+ # is n * (n - 1) / 2, and that of repeatedly calling AddSet (second method)
+ # is n * m * log2(m) where m is the mean degree of any vertex. Some
+ # experimenting showed that the comparison below is a reasonable way to
+ # decide which method to use.
+ out := BooleanAdjacencyMatrixMutableCopy(D);
+ for i in [1 .. n] do
+ for j in [i + 1 .. n] do
+ if out[i][j] then
+ out[j][i] := false;
+ fi;
+ od;
+ od;
+ out := DigraphByAdjacencyMatrixNC(out);
+ else
+ out := OutNeighboursMutableCopy(D);
+ Perform(out, Sort);
+ for i in [1 .. n] do
+ for j in out[i] do
+ if i <> j then
+ RemoveSet(out[j], i);
+ fi;
+ od;
+ od;
+ out := DigraphNC(out);
+ fi;
+ SetIsAntisymmetricDigraph(out, true);
+ return out;
+end);
diff --git a/gap/digraph.gi b/gap/digraph.gi
index cef0e544b..1f7a4cd0b 100644
--- a/gap/digraph.gi
+++ b/gap/digraph.gi
@@ -1142,6 +1142,7 @@ function(mat)
if IsInt(mat[1][1]) then
SetAdjacencyMatrix(out, mat);
else # boolean matrix
+ SetBooleanAdjacencyMatrix(out, mat);
SetIsMultiDigraph(out, false);
fi;
diff --git a/gap/oper.gd b/gap/oper.gd
index 99c093604..b04d11b0b 100644
--- a/gap/oper.gd
+++ b/gap/oper.gd
@@ -66,7 +66,7 @@ DeclareOperation("OutNeighboursOfVertexNC", [IsDigraph, IsPosInt]);
DeclareOperation("DigraphInEdges", [IsDigraph, IsPosInt]);
DeclareOperation("DigraphOutEdges", [IsDigraph, IsPosInt]);
DeclareOperation("IsDigraphEdge", [IsDigraph, IsList]);
-DeclareOperation("IsDigraphEdge", [IsDigraph, IsPosInt, IsPosInt]);
+DeclareOperation("IsDigraphEdge", [IsDigraph, IsInt, IsInt]);
DeclareOperation("DigraphConnectedComponent", [IsDigraph, IsPosInt]);
DeclareOperation("DigraphStronglyConnectedComponent", [IsDigraph, IsPosInt]);
diff --git a/gap/oper.gi b/gap/oper.gi
index 58e8acd7f..c2b251060 100644
--- a/gap/oper.gi
+++ b/gap/oper.gi
@@ -1004,14 +1004,14 @@ function(digraph, edge)
return IsDigraphEdge(digraph, edge[1], edge[2]);
end);
-InstallMethod(IsDigraphEdge, "for a digraph, pos int, pos int",
-[IsDigraph, IsPosInt, IsPosInt],
+InstallMethod(IsDigraphEdge, "for a digraph, int, int",
+[IsDigraph, IsInt, IsInt],
function(digraph, u, v)
local n;
n := DigraphNrVertices(digraph);
- if u > n or v > n then
+ if u > n or v > n or u <= 0 or v <= 0 then
return false;
elif HasAdjacencyMatrix(digraph) then
return AdjacencyMatrix(digraph)[u][v] <> 0;
diff --git a/gap/planar.gd b/gap/planar.gd
new file mode 100644
index 000000000..6afb5f1e8
--- /dev/null
+++ b/gap/planar.gd
@@ -0,0 +1,40 @@
+#############################################################################
+##
+## planar.gd
+## Copyright (C) 2018 James D. Mitchell
+##
+## Licensing information can be found in the README file of this package.
+##
+#############################################################################
+##
+
+# The methods in this file utilise the kernel module functions that wrap
+# Boyer's reference implementation (in C) of the planarity and subgraph
+# homeomorphism algorithms from:
+#
+# John M. Boyer and Wendy J. Myrvold, On the Cutting Edge: Simplified O(n)
+# Planarity by Edge Addition. Journal of Graph Algorithms and Applications, Vol.
+# 8, No. 3, pp. 241-273, 2004.
+
+# Attributes . . .
+
+DeclareAttribute("PlanarEmbedding", IsDigraph);
+DeclareAttribute("OuterPlanarEmbedding", IsDigraph);
+DeclareAttribute("KuratowskiPlanarSubdigraph", IsDigraph);
+DeclareAttribute("KuratowskiOuterPlanarSubdigraph", IsDigraph);
+DeclareAttribute("SubdigraphHomeomorphicToK23", IsDigraph);
+DeclareAttribute("SubdigraphHomeomorphicToK4", IsDigraph);
+DeclareAttribute("SubdigraphHomeomorphicToK33", IsDigraph);
+
+# Properties . . .
+
+DeclareProperty("IsPlanarDigraph", IsDigraph);
+DeclareProperty("IsOuterPlanarDigraph", IsDigraph);
+
+# True methods . . .
+
+InstallTrueMethod(IsBiconnectedDigraph,
+ IsOuterPlanarDigraph and IsHamiltonianDigraph);
+InstallTrueMethod(IsHamiltonianDigraph,
+ IsOuterPlanarDigraph and IsBiconnectedDigraph);
+InstallTrueMethod(IsPlanarDigraph, IsOuterPlanarDigraph);
diff --git a/gap/planar.gi b/gap/planar.gi
new file mode 100644
index 000000000..d05d6556d
--- /dev/null
+++ b/gap/planar.gi
@@ -0,0 +1,142 @@
+#############################################################################
+##
+## planar.gi
+## Copyright (C) 2018 James D. Mitchell
+##
+## Licensing information can be found in the README file of this package.
+##
+#############################################################################
+##
+
+# The methods in this file utilise the kernel module functions that wrap
+# Boyer's reference implementation (in C) of the planarity and subgraph
+# homeomorphism algorithms from:
+#
+# John M. Boyer and Wendy J. Myrvold, On the Cutting Edge: Simplified O(n)
+# Planarity by Edge Addition. Journal of Graph Algorithms and Applications,
+# Vol. 8, No. 3, pp. 241-273, 2004.
+
+########################################################################
+#
+# This file is organised as follows:
+#
+# 1. Attributes
+#
+# 2. Properties
+#
+########################################################################
+
+########################################################################
+# 1. Attributes
+########################################################################
+
+InstallMethod(PlanarEmbedding, "for a digraph", [IsDigraph],
+function(D)
+ if DigraphNrEdges(D) = 0 or DigraphNrVertices(D) < 3 then
+ return [];
+ elif HasIsPlanarDigraph(D) and not IsPlanarDigraph(D) then
+ return fail;
+ fi;
+ D := DigraphRemoveAllMultipleEdges(D);
+ D := MaximalAntiSymmetricSubdigraph(D);
+ return PLANAR_EMBEDDING(D);
+end);
+
+InstallMethod(OuterPlanarEmbedding, "for a digraph", [IsDigraph],
+function(D)
+ if DigraphNrEdges(D) = 0 or DigraphNrVertices(D) < 3 then
+ return [];
+ elif HasIsOuterPlanarDigraph(D) and not IsOuterPlanarDigraph(D) then
+ return fail;
+ fi;
+ D := DigraphRemoveAllMultipleEdges(D);
+ D := MaximalAntiSymmetricSubdigraph(D);
+ return OUTER_PLANAR_EMBEDDING(D);
+end);
+
+InstallMethod(KuratowskiPlanarSubdigraph, "for a digraph", [IsDigraph],
+function(D)
+ if IsPlanarDigraph(D) then
+ return fail;
+ fi;
+ D := DigraphRemoveAllMultipleEdges(D);
+ D := MaximalAntiSymmetricSubdigraph(D);
+ return KURATOWSKI_PLANAR_SUBGRAPH(D);
+end);
+
+InstallMethod(KuratowskiOuterPlanarSubdigraph, "for a digraph", [IsDigraph],
+function(D)
+ if IsOuterPlanarDigraph(D) then
+ return fail;
+ fi;
+ D := DigraphRemoveAllMultipleEdges(D);
+ D := MaximalAntiSymmetricSubdigraph(D);
+ return KURATOWSKI_OUTER_PLANAR_SUBGRAPH(D);
+end);
+
+InstallMethod(SubdigraphHomeomorphicToK23, "for a digraph", [IsDigraph],
+function(D)
+ if IsOuterPlanarDigraph(D) then
+ return fail;
+ fi;
+ D := DigraphRemoveAllMultipleEdges(D);
+ D := MaximalAntiSymmetricSubdigraph(D);
+ return SUBGRAPH_HOMEOMORPHIC_TO_K23(D);
+end);
+
+InstallMethod(SubdigraphHomeomorphicToK4, "for a digraph", [IsDigraph],
+function(D)
+ if IsOuterPlanarDigraph(D) then
+ return fail;
+ fi;
+ D := DigraphRemoveAllMultipleEdges(D);
+ D := MaximalAntiSymmetricSubdigraph(D);
+ return SUBGRAPH_HOMEOMORPHIC_TO_K4(D);
+end);
+
+InstallMethod(SubdigraphHomeomorphicToK33, "for a digraph", [IsDigraph],
+function(D)
+ if IsPlanarDigraph(D) then
+ return fail;
+ fi;
+ D := DigraphRemoveAllMultipleEdges(D);
+ D := MaximalAntiSymmetricSubdigraph(D);
+ return SUBGRAPH_HOMEOMORPHIC_TO_K33(D);
+end);
+
+########################################################################
+# 2. Properties
+########################################################################
+
+InstallMethod(IsPlanarDigraph, "for a digraph", [IsDigraph],
+function(D)
+ local C, v, e;
+ C := MaximalAntiSymmetricSubdigraph(DigraphRemoveAllMultipleEdges(D));
+ v := DigraphNrVertices(C);
+ e := DigraphNrEdges(C);
+ if v < 5 or e < 9 then
+ return true;
+ elif (IsConnectedDigraph(D) and e > 3 * v - 6)
+ or (HasChromaticNumber(D) and ChromaticNumber(D) > 4) then
+ return false;
+ fi;
+ return IS_PLANAR(C);
+end);
+
+InstallMethod(IsOuterPlanarDigraph, "for a digraph", [IsDigraph],
+function(D)
+ local C, v, e;
+ if HasIsPlanarDigraph(D) and not IsPlanarDigraph(D) then
+ return false;
+ fi;
+ C := MaximalAntiSymmetricSubdigraph(DigraphRemoveAllMultipleEdges(D));
+ v := DigraphNrVertices(D);
+ e := DigraphNrEdges(D);
+ if v < 4 or e < 6 then
+ return true;
+ elif HasChromaticNumber(D) and ChromaticNumber(D) > 3 then
+ # Outer planar graphs are 3-colourable
+ return false;
+ fi;
+ return IS_OUTER_PLANAR(C);
+end);
diff --git a/gap/prop.gi b/gap/prop.gi
index 10b6ce67d..6c27f6136 100644
--- a/gap/prop.gi
+++ b/gap/prop.gi
@@ -356,11 +356,8 @@ function(digraph)
return DigraphPeriod(digraph) = 1;
end);
-InstallMethod(IsAntisymmetricDigraph, "for a digraph",
-[IsDigraph],
+InstallMethod(IsAntisymmetricDigraph, "for a digraph", [IsDigraph],
function(digraph)
- # TODO check if the digraph has multiple edges, if not, then
- # this can return false if it has too many edges.
return IS_ANTISYMMETRIC_DIGRAPH(OutNeighbours(digraph));
end);
diff --git a/gap/utils.gi b/gap/utils.gi
index d854e3c12..dc79acd28 100644
--- a/gap/utils.gi
+++ b/gap/utils.gi
@@ -23,6 +23,7 @@ BindGlobal("DIGRAPHS_DocXMLFiles", ["attr.xml",
"isomorph.xml",
"oper.xml",
"orbits.xml",
+ "planar.xml",
"prop.xml",
"utils.xml",
"../PackageInfo.g"]);
diff --git a/init.g b/init.g
index 95c472fdf..017d503a2 100644
--- a/init.g
+++ b/init.g
@@ -45,5 +45,6 @@ ReadPackage("digraphs", "gap/io.gd");
ReadPackage("digraphs", "gap/grahom.gd");
ReadPackage("digraphs", "gap/orbits.gd");
ReadPackage("digraphs", "gap/cliques.gd");
+ReadPackage("digraphs", "gap/planar.gd");
DeclareInfoClass("InfoDigraphs");
diff --git a/makedoc.g b/makedoc.g
index c989a8eb8..2fdc1dd6e 100644
--- a/makedoc.g
+++ b/makedoc.g
@@ -20,6 +20,7 @@ _DocXMLFiles := ["attr.xml",
"isomorph.xml",
"oper.xml",
"orbits.xml",
+ "planar.xml",
"prop.xml",
"utils.xml",
"../PackageInfo.g"];
diff --git a/read.g b/read.g
index 4d5c27b81..62d264cfe 100644
--- a/read.g
+++ b/read.g
@@ -33,4 +33,5 @@ ReadPackage("digraphs", "gap/io.gi");
ReadPackage("digraphs", "gap/grahom.gi");
ReadPackage("digraphs", "gap/orbits.gi");
ReadPackage("digraphs", "gap/cliques.gi");
+ReadPackage("digraphs", "gap/planar.gi");
diff --git a/src/digraphs-debug.h b/src/digraphs-debug.h
index f1006cc29..8f660e574 100644
--- a/src/digraphs-debug.h
+++ b/src/digraphs-debug.h
@@ -36,4 +36,3 @@
#endif
#endif // DIGRAPHS_SRC_DIGRAPHS_DEBUG_H_
-
diff --git a/src/digraphs.c b/src/digraphs.c
index 6c506b95a..6d1d7d544 100644
--- a/src/digraphs.c
+++ b/src/digraphs.c
@@ -25,10 +25,13 @@
static Obj FuncDIGRAPH_OUT_NBS(Obj self, Obj digraph, Obj source, Obj range);
static Obj FuncDIGRAPH_SOURCE_RANGE(Obj self, Obj digraph);
+Obj IsDigraph;
+Obj IsDigraphEdge;
+
#if !defined(GAP_KERNEL_MAJOR_VERSION) || GAP_KERNEL_MAJOR_VERSION < 3
// compatibility with GAP <= 4.9
static inline Obj NEW_PLIST_IMM(UInt type, Int plen) {
- return NEW_PLIST(type | IMMUTABLE, plen);
+ return NEW_PLIST(type | IMMUTABLE, plen);
}
#endif
@@ -169,8 +172,9 @@ static Obj FuncGABOW_SCC(Obj self, Obj digraph) {
comp = NEW_PLIST_IMM(T_PLIST_CYC, nr);
SET_LEN_PLIST(comp, nr);
- memcpy(ADDR_OBJ(comp) + 1, CONST_ADDR_OBJ(stack1) + (end1 + 1),
- nr * sizeof(Obj));
+ memcpy(ADDR_OBJ(comp) + 1,
+ CONST_ADDR_OBJ(stack1) + (end1 + 1),
+ nr * sizeof(Obj));
nr = LEN_PLIST(comps) + 1;
SET_ELM_PLIST(comps, nr, comp);
@@ -620,7 +624,7 @@ static Obj FuncDIGRAPH_PATH(Obj self, Obj adj, Obj u, Obj v) {
return Fail;
}
-static Obj FuncIS_ANTISYMMETRIC_DIGRAPH(Obj self, Obj adj) {
+Obj FuncIS_ANTISYMMETRIC_DIGRAPH(Obj self, Obj adj) {
Int nr, i, j, k, l, level, last1, last2;
Obj nbs;
UInt *stack, *ptr;
@@ -1035,7 +1039,7 @@ static Obj FuncDIGRAPH_IN_OUT_NBS(Obj self, Obj adj) {
return inn;
}
-static Obj FuncADJACENCY_MATRIX(Obj self, Obj digraph) {
+Obj FuncADJACENCY_MATRIX(Obj self, Obj digraph) {
Int n, i, j, val, len, outj;
Obj adj, mat, adji, next;
@@ -2205,9 +2209,8 @@ Obj FuncDIGRAPH_HOMOS(Obj self, Obj args) {
Obj digraph1_gap =
ELM_PLIST(args, 1); // find homomorphisms from digraph1 . . .
Obj digraph2_gap = ELM_PLIST(args, 2); // . . . to digraph2
- Obj hook_gap =
- ELM_PLIST(args, 3); // apply this function to every homomorphism
- // Fail for no function
+ Obj hook_gap = ELM_PLIST(args, 3); // apply this function to every
+ // homomorphism Fail for no function
Obj user_param_gap =
ELM_PLIST(args, 4); // user_param_gap, which can be used in the hook
Obj limit_gap = ELM_PLIST(args, 5); // the maximum number of results
@@ -2378,8 +2381,8 @@ Obj FuncDIGRAPH_HOMOS(Obj self, Obj args) {
/*F * * * * * * * * * * * * * initialize package * * * * * * * * * * * * * * */
/******************************************************************************
-*V GVarFuncs . . . . . . . . . . . . . . . . . . list of functions to export
-*/
+ *V GVarFuncs . . . . . . . . . . . . . . . . . . list of functions to export
+ */
static StructGVarFunc GVarFuncs[] = {
#ifdef DEBUG
@@ -2574,23 +2577,75 @@ static StructGVarFunc GVarFuncs[] = {
FuncDIGRAPH_HOMOS,
"src/digraphs.c:FuncDIGRAPH_HOMOS"},
+ {"IS_PLANAR", 1, "digraph", FuncIS_PLANAR, "src/planar.c:FuncIS_PLANAR"},
+
+ {"PLANAR_EMBEDDING",
+ 1,
+ "digraph",
+ FuncPLANAR_EMBEDDING,
+ "src/planar.c:FuncPLANAR_EMBEDDING"},
+
+ {"KURATOWSKI_PLANAR_SUBGRAPH",
+ 1,
+ "digraph",
+ FuncKURATOWSKI_PLANAR_SUBGRAPH,
+ "src/planar.c:FuncKURATOWSKI_PLANAR_SUBGRAPH"},
+
+ {"IS_OUTER_PLANAR",
+ 1,
+ "digraph",
+ FuncIS_OUTER_PLANAR,
+ "src/planar.c:FuncIS_OUTER_PLANAR"},
+
+ {"OUTER_PLANAR_EMBEDDING",
+ 1,
+ "digraph",
+ FuncOUTER_PLANAR_EMBEDDING,
+ "src/planar.c:FuncOUTER_PLANAR_EMBEDDING"},
+
+ {"KURATOWSKI_OUTER_PLANAR_SUBGRAPH",
+ 1,
+ "digraph",
+ FuncKURATOWSKI_OUTER_PLANAR_SUBGRAPH,
+ "src/planar.c:FuncKURATOWSKI_OUTER_PLANAR_SUBGRAPH"},
+
+ {"SUBGRAPH_HOMEOMORPHIC_TO_K23",
+ 1,
+ "digraph",
+ FuncSUBGRAPH_HOMEOMORPHIC_TO_K23,
+ "src/planar.c:FuncSUBGRAPH_HOMEOMORPHIC_TO_K23"},
+
+ {"SUBGRAPH_HOMEOMORPHIC_TO_K33",
+ 1,
+ "digraph",
+ FuncSUBGRAPH_HOMEOMORPHIC_TO_K33,
+ "src/planar.c:FuncSUBGRAPH_HOMEOMORPHIC_TO_K33"},
+
+ {"SUBGRAPH_HOMEOMORPHIC_TO_K4",
+ 1,
+ "digraph",
+ FuncSUBGRAPH_HOMEOMORPHIC_TO_K4,
+ "src/planar.c:FuncSUBGRAPH_HOMEOMORPHIC_TO_K4"},
+
{0, 0, 0, 0, 0} /* Finish with an empty entry */
};
/******************************************************************************
-*F InitKernel( ) . . . . . . . . initialise kernel data structures
-*/
+ *F InitKernel( ) . . . . . . . . initialise kernel data structures
+ */
static Int InitKernel(StructInitInfo* module) {
/* init filters and functions */
InitHdlrFuncsFromTable(GVarFuncs);
+ ImportGVarFromLibrary("IsDigraph", &IsDigraph);
+ ImportGVarFromLibrary("IsDigraphEdge", &IsDigraphEdge);
/* return success */
return 0;
}
/******************************************************************************
-*F InitLibrary( ) . . . . . . . initialise library data structures
-*/
+ *F InitLibrary( ) . . . . . . . initialise library data structures
+ */
static Int InitLibrary(StructInitInfo* module) {
/* init filters and functions */
InitGVarFuncsFromTable(GVarFuncs);
@@ -2600,19 +2655,18 @@ static Int InitLibrary(StructInitInfo* module) {
}
/******************************************************************************
-*F InitInfopl() . . . . . . . . . . . . . . . . . table of init functions
-*/
+ *F InitInfopl() . . . . . . . . . . . . . . . . . table of init functions
+ */
static StructInitInfo module = {
#ifdef DIGRAPHSSTATIC
.type = MODULE_STATIC,
#else
.type = MODULE_DYNAMIC,
#endif
- .name = "digraphs",
- .initKernel = InitKernel,
+ .name = "digraphs",
+ .initKernel = InitKernel,
.initLibrary = InitLibrary,
- .postRestore = 0
-};
+ .postRestore = 0};
#ifndef DIGRAPHSSTATIC
StructInitInfo* Init__Dynamic(void) {
diff --git a/src/digraphs.h b/src/digraphs.h
index 4921e4d79..fad324269 100644
--- a/src/digraphs.h
+++ b/src/digraphs.h
@@ -31,4 +31,9 @@ Obj OutNeighbours(Obj digraph);
Obj DigraphSource(Obj digraph);
Obj DigraphRange(Obj digraph);
+Obj FuncIS_ANTISYMMETRIC_DIGRAPH(Obj self, Obj digraph);
+
+extern Obj IsDigraph;
+extern Obj IsDigraphEdge;
+
#endif // DIGRAPHS_SRC_DIGRAPHS_H_
diff --git a/src/perms.h b/src/perms.h
index 9778ef16f..f30f31ab4 100644
--- a/src/perms.h
+++ b/src/perms.h
@@ -43,9 +43,9 @@ struct perm_coll {
typedef struct perm_coll PermColl;
-void set_perms_degree(UIntS deg_arg);
+void set_perms_degree(UIntS deg_arg);
PermColl* new_perm_coll(UIntS upper_bound);
-void add_perm_coll(PermColl* coll, Perm gen);
+void add_perm_coll(PermColl* coll, Perm gen);
PermColl* copy_perm_coll(PermColl* coll);
// void reset_perm_coll(PermColl* coll);
void free_perm_coll(PermColl* coll);
diff --git a/src/planar.c b/src/planar.c
new file mode 100644
index 000000000..9d8c8b55e
--- /dev/null
+++ b/src/planar.c
@@ -0,0 +1,219 @@
+/********************************************************************************
+**
+*A planar.c Planarity testing
+**
+**
+** Copyright (C) 2018 - J. D. Mitchell
+**
+** This file is free software, see the digraphs/LICENSE.
+**
+********************************************************************************/
+
+#include "planar.h"
+
+// C headers
+#include // for INT_MAX
+#include // for true and false
+
+// Digraphs package headers
+#include "digraphs-debug.h" // for DIGRAPHS_ASSERT
+#include "digraphs.h" // for DigraphNrVertices, DigraphNrEdges, . . .
+
+// edge-addition-planarity-suite headers
+#include "c/graph.h"
+#include "c/graphK23Search.h"
+#include "c/graphK33Search.h"
+#include "c/graphK4Search.h"
+
+#if !defined(GAP_KERNEL_MAJOR_VERSION) || GAP_KERNEL_MAJOR_VERSION < 3
+// compatibility with GAP <= 4.9
+static inline Obj NEW_PLIST_IMM(UInt type, Int plen) {
+ return NEW_PLIST(type | IMMUTABLE, plen);
+}
+#endif
+
+// Forward declaration of the main function in this file.
+Obj boyers_planarity_check(Obj digraph, int flags, bool krtwsk);
+
+// GAP level functions
+Obj FuncIS_PLANAR(Obj self, Obj digraph) {
+ return boyers_planarity_check(digraph, EMBEDFLAGS_PLANAR, false);
+}
+
+Obj FuncKURATOWSKI_PLANAR_SUBGRAPH(Obj self, Obj digraph) {
+ Obj res = boyers_planarity_check(digraph, EMBEDFLAGS_PLANAR, true);
+ return (ELM_PLIST(res, 1) == False ? ELM_PLIST(res, 2) : Fail);
+}
+
+Obj FuncPLANAR_EMBEDDING(Obj self, Obj digraph) {
+ Obj res = boyers_planarity_check(digraph, EMBEDFLAGS_PLANAR, true);
+ return (ELM_PLIST(res, 1) == True ? ELM_PLIST(res, 2) : Fail);
+}
+
+Obj FuncIS_OUTER_PLANAR(Obj self, Obj digraph) {
+ return boyers_planarity_check(digraph, EMBEDFLAGS_OUTERPLANAR, false);
+}
+
+Obj FuncKURATOWSKI_OUTER_PLANAR_SUBGRAPH(Obj self, Obj digraph) {
+ Obj res = boyers_planarity_check(digraph, EMBEDFLAGS_OUTERPLANAR, true);
+ return (ELM_PLIST(res, 1) == False ? ELM_PLIST(res, 2) : Fail);
+}
+
+Obj FuncOUTER_PLANAR_EMBEDDING(Obj self, Obj digraph) {
+ Obj res = boyers_planarity_check(digraph, EMBEDFLAGS_OUTERPLANAR, true);
+ return (ELM_PLIST(res, 1) == True ? ELM_PLIST(res, 2) : Fail);
+}
+
+Obj FuncSUBGRAPH_HOMEOMORPHIC_TO_K23(Obj self, Obj digraph) {
+ Obj res = boyers_planarity_check(digraph, EMBEDFLAGS_SEARCHFORK23, true);
+ return (ELM_PLIST(res, 1) == False ? ELM_PLIST(res, 2) : Fail);
+}
+
+Obj FuncSUBGRAPH_HOMEOMORPHIC_TO_K33(Obj self, Obj digraph) {
+ Obj res = boyers_planarity_check(digraph, EMBEDFLAGS_SEARCHFORK33, true);
+ return (ELM_PLIST(res, 1) == False ? ELM_PLIST(res, 2) : Fail);
+}
+
+Obj FuncSUBGRAPH_HOMEOMORPHIC_TO_K4(Obj self, Obj digraph) {
+ Obj res = boyers_planarity_check(digraph, EMBEDFLAGS_SEARCHFORK4, true);
+ return (ELM_PLIST(res, 1) == False ? ELM_PLIST(res, 2) : Fail);
+}
+
+// The implementation of the main functions in this file.
+
+// This function only accepts digraphs without multiple edges
+
+Obj boyers_planarity_check(Obj digraph, int flags, bool krtwsk) {
+ DIGRAPHS_ASSERT(flags == EMBEDFLAGS_PLANAR || flags == EMBEDFLAGS_OUTERPLANAR
+ || flags == EMBEDFLAGS_SEARCHFORK23
+ || flags == EMBEDFLAGS_SEARCHFORK4
+ || flags == EMBEDFLAGS_SEARCHFORK33);
+
+ if (CALL_1ARGS(IsDigraph, digraph) != True) {
+ ErrorQuit("Digraphs: boyers_planarity_check (C): the 1st argument must be "
+ "a digraph, not %s",
+ (Int) TNAM_OBJ(digraph),
+ 0L);
+ }
+ Obj const out = OutNeighbours(digraph);
+ if (FuncIS_ANTISYMMETRIC_DIGRAPH(0L, out) != True) {
+ ErrorQuit("Digraphs: boyers_planarity_check (C): the 1st argument must be "
+ "an antisymmetric digraph",
+ 0L,
+ 0L);
+ }
+ Int V = DigraphNrVertices(digraph);
+ Int E = DigraphNrEdges(digraph);
+ if (V > INT_MAX) {
+ // Cannot currently test this, it might always be true, depending on the
+ // definition of Int.
+ ErrorQuit("Digraphs: boyers_planarity_check (C): the maximum number of "
+ "nodes is %d, found %d",
+ INT_MAX,
+ V);
+ return 0L;
+ } else if (2 * E > INT_MAX) {
+ // Cannot currently test this
+ ErrorQuit("Digraphs: boyers_planarity_check (C): the maximum number of "
+ "edges is %d, found %d",
+ INT_MAX / 2,
+ E);
+ return 0L;
+ }
+
+ graphP theGraph = gp_New();
+ switch (flags) {
+ case EMBEDFLAGS_SEARCHFORK33:
+ gp_AttachK33Search(theGraph);
+ break;
+ case EMBEDFLAGS_SEARCHFORK23:
+ gp_AttachK23Search(theGraph);
+ break;
+ case EMBEDFLAGS_SEARCHFORK4:
+ gp_AttachK4Search(theGraph);
+ break;
+ }
+ if (gp_InitGraph(theGraph, V) != OK) {
+ gp_Free(&theGraph);
+ ErrorQuit("Digraphs: boyers_planarity_check (C): invalid number of nodes!",
+ 0L,
+ 0L);
+ return 0L;
+ } 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;
+ }
+
+ int status;
+
+ for (Int v = 1; v <= LEN_LIST(out); ++v) {
+ DIGRAPHS_ASSERT(gp_VertexInRange(theGraph, v));
+ gp_SetVertexIndex(theGraph, v, v);
+ Obj const out_v = ELM_LIST(out, v);
+ for (Int w = 1; w <= LEN_LIST(out_v); ++w) {
+ DIGRAPHS_ASSERT(gp_VertexInRange(theGraph, w));
+ int u = INT_INTOBJ(ELM_LIST(out_v, w));
+ if (v != u) {
+ status = gp_AddEdge(theGraph, v, 0, u, 0);
+ if (status != OK) {
+ // Cannot currently test this, i.e. it shouldn't happen (and
+ // currently there is no example where it does happen)
+ gp_Free(&theGraph);
+ ErrorQuit("Digraphs: boyers_planarity_check (C): internal error, "
+ "can't add edge from %d to %d",
+ (Int) v,
+ (Int) u);
+ return 0L;
+ }
+ }
+ }
+ }
+ status = gp_Embed(theGraph, flags);
+ if (status == NOTOK) {
+ // Cannot currently test this, i.e. it shouldn't happen (and
+ // currently there is no example where it does happen)
+ gp_Free(&theGraph);
+ ErrorQuit("Digraphs: boyers_planarity_check (C): status is not ok", 0L, 0L);
+ }
+ Obj res;
+ if (krtwsk) {
+ // Kuratowski subgraph isolator
+ gp_SortVertices(theGraph);
+ Obj subgraph = NEW_PLIST_IMM(T_PLIST, theGraph->N);
+ SET_LEN_PLIST(subgraph, theGraph->N);
+ for (int i = 1; i <= theGraph->N; ++i) {
+ int nr = 0;
+ Obj list = NEW_PLIST_IMM(T_PLIST, 0);
+ int j = theGraph->V[i].link[1];
+ while (j) {
+ if (CALL_3ARGS(IsDigraphEdge,
+ digraph,
+ INTOBJ_INT((Int) i),
+ INTOBJ_INT((Int) theGraph->E[j].neighbor))
+ == True) {
+ AssPlist(list, ++nr, INTOBJ_INT(theGraph->E[j].neighbor));
+ }
+ j = theGraph->E[j].link[1];
+ }
+ if (nr == 0) {
+ RetypeBag(list, T_PLIST_EMPTY);
+ }
+ SET_ELM_PLIST(subgraph, i, list);
+ CHANGED_BAG(subgraph);
+ }
+ res = NEW_PLIST_IMM(T_PLIST, 2);
+ SET_LEN_PLIST(res, 2);
+ SET_ELM_PLIST(res, 1, (status == NONEMBEDDABLE ? False : True));
+ SET_ELM_PLIST(res, 2, subgraph);
+ CHANGED_BAG(res);
+ } else if (status == NONEMBEDDABLE) {
+ res = False;
+ } else {
+ res = True;
+ }
+ gp_Free(&theGraph);
+ return res;
+}
diff --git a/src/planar.h b/src/planar.h
new file mode 100644
index 000000000..d64960ca3
--- /dev/null
+++ b/src/planar.h
@@ -0,0 +1,30 @@
+/********************************************************************************
+**
+*A planar.h Planarity testing
+**
+**
+** Copyright (C) 2018 - J. D. Mitchell
+**
+** This file is free software, see the digraphs/LICENSE.
+**
+********************************************************************************/
+
+#ifndef DIGRAPHS_SRC_PLANAR_H_
+#define DIGRAPHS_SRC_PLANAR_H_
+
+// GAP headers
+#include "src/compiled.h"
+
+Obj FuncIS_PLANAR(Obj self, Obj digraph);
+Obj FuncKURATOWSKI_PLANAR_SUBGRAPH(Obj self, Obj digraph);
+Obj FuncPLANAR_EMBEDDING(Obj self, Obj digraph);
+
+Obj FuncIS_OUTER_PLANAR(Obj self, Obj digraph);
+Obj FuncKURATOWSKI_OUTER_PLANAR_SUBGRAPH(Obj self, Obj digraph);
+Obj FuncOUTER_PLANAR_EMBEDDING(Obj self, Obj digraph);
+
+Obj FuncSUBGRAPH_HOMEOMORPHIC_TO_K23(Obj self, Obj digraph);
+Obj FuncSUBGRAPH_HOMEOMORPHIC_TO_K33(Obj self, Obj digraph);
+Obj FuncSUBGRAPH_HOMEOMORPHIC_TO_K4(Obj self, Obj digraph);
+
+#endif // DIGRAPHS_SRC_PLANAR_H_
diff --git a/tst/standard/attr.tst b/tst/standard/attr.tst
index ff46ea535..04481e2ce 100644
--- a/tst/standard/attr.tst
+++ b/tst/standard/attr.tst
@@ -1678,6 +1678,30 @@ gap> gr := DigraphAddEdges(DigraphAddVertex(CycleDigraph(600)),
gap> HamiltonianPath(gr);
fail
+# MaximalAntiSymmetricSubdigraph
+gap> MaximalAntiSymmetricSubdigraph(NullDigraph(0));
+
+gap> IsAntisymmetricDigraph(DigraphCopy(last));
+true
+gap> MaximalAntiSymmetricSubdigraph(NullDigraph(1));
+
+gap> IsAntisymmetricDigraph(DigraphCopy(last));
+true
+gap> MaximalAntiSymmetricSubdigraph(CompleteDigraph(1));
+
+gap> IsAntisymmetricDigraph(DigraphCopy(last));
+true
+gap> MaximalAntiSymmetricSubdigraph(CompleteBipartiteDigraph(2, 30000));
+
+gap> IsAntisymmetricDigraph(DigraphCopy(last));
+true
+gap> MaximalAntiSymmetricSubdigraph(Digraph([[1, 1, 2, 2], []]));
+
+gap> OutNeighbours(last);
+[ [ 1, 2 ], [ ] ]
+gap> MaximalAntiSymmetricSubdigraph(CompleteDigraph(10));
+
+
# DIGRAPHS_UnbindVariables
gap> Unbind(adj);
gap> Unbind(adj1);
diff --git a/tst/standard/planar.tst b/tst/standard/planar.tst
new file mode 100644
index 000000000..0e0f3a504
--- /dev/null
+++ b/tst/standard/planar.tst
@@ -0,0 +1,244 @@
+#############################################################################
+##
+#W standard/planar.tst
+#Y Copyright (C) 2018 James D. Mitchell
+##
+## Licensing information can be found in the README file of this package.
+##
+#############################################################################
+##
+gap> START_TEST("Digraphs package: standard/planar.tst");
+gap> LoadPackage("digraphs", false);;
+
+#
+gap> DIGRAPHS_StartTest();
+
+# IsPlanarDigraph
+gap> D := NullDigraph(0);
+
+gap> IsPlanarDigraph(D);
+true
+gap> D := CompleteDigraph(4);
+
+gap> IsPlanarDigraph(D);
+true
+gap> D := CompleteDigraph(5);
+
+gap> IsPlanarDigraph(D);
+false
+gap> D := Digraph([[2, 4, 7, 9, 10], [1, 3, 4, 6, 9, 10], [6, 10],
+> [2, 5, 8, 9], [1, 2, 3, 4, 6, 7, 9, 10], [3, 4, 5, 7, 9, 10],
+> [3, 4, 5, 6, 9, 10], [3, 4, 5, 7, 9], [2, 3, 5, 6, 7, 8], [3, 5]]);
+
+gap> ChromaticNumber(D);
+5
+gap> IsPlanarDigraph(D);
+false
+gap> D := CompleteBipartiteDigraph(3, 3);
+
+gap> D := DigraphDisjointUnion(D, D);
+
+gap> IsPlanarDigraph(D);
+false
+
+# IsOuterPlanarDigraph
+gap> D := Digraph([[2, 4, 7, 9, 10], [1, 3, 4, 6, 9, 10], [6, 10],
+> [2, 5, 8, 9], [1, 2, 3, 4, 6, 7, 9, 10], [3, 4, 5, 7, 9, 10],
+> [3, 4, 5, 6, 9, 10], [3, 4, 5, 7, 9], [2, 3, 5, 6, 7, 8], [3, 5]]);
+
+gap> ChromaticNumber(D);
+5
+gap> IsPlanarDigraph(D);
+false
+gap> IsOuterPlanarDigraph(D);
+false
+gap> D := NullDigraph(0);
+
+gap> IsOuterPlanarDigraph(D);
+true
+gap> D := CompleteDigraph(4);
+
+gap> IsOuterPlanarDigraph(D);
+false
+gap> D := CompleteDigraph(4);
+
+gap> ChromaticNumber(D);
+4
+gap> IsOuterPlanarDigraph(D);
+false
+gap> D := Digraph([[3, 5, 10], [8, 9, 10], [1, 4], [3, 6], [1, 7, 11], [4, 7],
+> [6, 8], [2, 7], [2, 11], [1, 2], [5, 9]]);
+
+gap> IsOuterPlanarDigraph(D);
+false
+gap> IsPlanarDigraph(D);
+true
+
+# PlanarEmbedding
+gap> D := Digraph([[3, 5, 10], [8, 9, 10], [1, 4], [3, 6], [1, 7, 11], [4, 7],
+> [6, 8], [2, 7], [2, 11], [1, 2], [5, 9]]);
+
+gap> PlanarEmbedding(D);
+[ [ 3, 10, 5 ], [ 10, 8, 9 ], [ 4 ], [ 6 ], [ 11, 7 ], [ 7 ], [ 8 ], [ ],
+ [ 11 ], [ ], [ ] ]
+gap> D := Digraph([[2, 4, 7, 9, 10], [1, 3, 4, 6, 9, 10], [6, 10],
+> [2, 5, 8, 9], [1, 2, 3, 4, 6, 7, 9, 10], [3, 4, 5, 7, 9, 10],
+> [3, 4, 5, 6, 9, 10], [3, 4, 5, 7, 9], [2, 3, 5, 6, 7, 8], [3, 5]]);
+
+gap> IsPlanarDigraph(D);
+false
+gap> PlanarEmbedding(D);
+fail
+gap> D := NullDigraph(0);
+
+gap> PlanarEmbedding(D);
+[ ]
+gap> D := List(["D??", "D?_", "D?o", "D?w", "D?{", "DCO", "DCW", "DCc", "DCo",
+> "DCs", "DCw", "DC{", "DEk", "DEo", "DEs", "DEw", "DE{", "DFw", "DF{", "DQg",
+> "DQo", "DQw", "DQ{", "DTk", "DTw", "DT{", "DUW", "DUw", "DU{", "DV{", "D]w",
+> "D]{", "D^{", "D~{"], DigraphFromGraph6String);;
+gap> List(D, PlanarEmbedding);
+[ [ ], [ [ 5 ], [ ], [ ], [ ], [ ] ], [ [ 5 ], [ 5 ], [ ], [ ], [ ] ],
+ [ [ 5 ], [ 5 ], [ 5 ], [ ], [ ] ], [ [ 5 ], [ 5 ], [ 5 ], [ 5 ], [ ] ],
+ [ [ 4 ], [ 5 ], [ ], [ ], [ ] ], [ [ 4 ], [ 5 ], [ 5 ], [ ], [ ] ],
+ [ [ 4, 5 ], [ ], [ ], [ 5 ], [ ] ], [ [ 4, 5 ], [ 5 ], [ ], [ ], [ ] ]
+ , [ [ 4, 5 ], [ 5 ], [ ], [ 5 ], [ ] ],
+ [ [ 4, 5 ], [ 5 ], [ 5 ], [ ], [ ] ],
+ [ [ 4, 5 ], [ 5 ], [ 5 ], [ 5 ], [ ] ],
+ [ [ 4, 5 ], [ 4 ], [ 5 ], [ 5 ], [ ] ],
+ [ [ 4, 5 ], [ 5, 4 ], [ ], [ ], [ ] ],
+ [ [ 4, 5 ], [ 5, 4 ], [ ], [ 5 ], [ ] ],
+ [ [ 4, 5 ], [ 5, 4 ], [ 5 ], [ ], [ ] ],
+ [ [ 4, 5 ], [ 5, 4 ], [ 5 ], [ 5 ], [ ] ],
+ [ [ 4, 5 ], [ 5, 4 ], [ 4, 5 ], [ ], [ ] ],
+ [ [ 4, 5 ], [ 5, 4 ], [ 4, 5 ], [ 5 ], [ ] ],
+ [ [ 3, 5 ], [ 4 ], [ 5 ], [ ], [ ] ],
+ [ [ 3, 5 ], [ 5, 4 ], [ ], [ ], [ ] ],
+ [ [ 3, 5 ], [ 5, 4 ], [ 5 ], [ ], [ ] ],
+ [ [ 3, 5 ], [ 4, 5 ], [ 5 ], [ 5 ], [ ] ],
+ [ [ 3, 5, 4 ], [ ], [ 4, 5 ], [ 5 ], [ ] ],
+ [ [ 3, 5, 4 ], [ 5 ], [ 4, 5 ], [ ], [ ] ],
+ [ [ 3, 5, 4 ], [ 5 ], [ 4, 5 ], [ 5 ], [ ] ],
+ [ [ 3, 4 ], [ 4, 5 ], [ 5 ], [ ], [ ] ],
+ [ [ 3, 5, 4 ], [ 4, 5 ], [ 5 ], [ ], [ ] ],
+ [ [ 3, 5, 4 ], [ 4, 5 ], [ 5 ], [ 5 ], [ ] ],
+ [ [ 3, 5, 4 ], [ 5, 4 ], [ 4, 5 ], [ 5 ], [ ] ],
+ [ [ 3, 5, 4 ], [ 4, 5, 3 ], [ 5 ], [ ], [ ] ],
+ [ [ 3, 5, 4 ], [ 4, 5, 3 ], [ 5 ], [ 5 ], [ ] ],
+ [ [ 3, 5, 4 ], [ 4, 5, 3 ], [ 4, 5 ], [ 5 ], [ ] ], fail ]
+
+# OuterPlanarEmbedding
+gap> D := Digraph([[3, 5, 10], [8, 9, 10], [1, 4], [3, 6], [1, 7, 11], [4, 7],
+> [6, 8], [2, 7], [2, 11], [1, 2], [5, 9]]);
+
+gap> OuterPlanarEmbedding(D);
+fail
+gap> D := Digraph([[2, 4, 7, 9, 10], [1, 3, 4, 6, 9, 10], [6, 10],
+> [2, 5, 8, 9], [1, 2, 3, 4, 6, 7, 9, 10], [3, 4, 5, 7, 9, 10],
+> [3, 4, 5, 6, 9, 10], [3, 4, 5, 7, 9], [2, 3, 5, 6, 7, 8], [3, 5]]);
+
+gap> IsOuterPlanarDigraph(D);
+false
+gap> OuterPlanarEmbedding(D);
+fail
+gap> D := NullDigraph(0);
+
+gap> OuterPlanarEmbedding(D);
+[ ]
+gap> D := CompleteDigraph(3);
+
+gap> OuterPlanarEmbedding(D);
+[ [ 2, 3 ], [ 3 ], [ ] ]
+
+# SubdigraphHomeomorphicToK23/33/4
+gap> D := Digraph([[3, 5, 10], [8, 9, 10], [1, 4], [3, 6], [1, 7, 11], [4, 7],
+> [6, 8], [2, 7], [2, 11], [1, 2], [5, 9]]);
+
+gap> SubdigraphHomeomorphicToK4(D);
+[ [ 3, 5, 10 ], [ 9, 8, 10 ], [ 4 ], [ 6 ], [ 7, 11 ], [ 7 ], [ 8 ], [ ],
+ [ 11 ], [ ], [ ] ]
+gap> SubdigraphHomeomorphicToK23(D);
+[ [ 3, 5, 10 ], [ 9, 8, 10 ], [ 4 ], [ 6 ], [ 11 ], [ 7 ], [ 8 ], [ ],
+ [ 11 ], [ ], [ ] ]
+gap> D := Digraph([[3, 5, 10], [8, 9, 10], [1, 4], [3, 6], [1, 11], [4, 7],
+> [6, 8], [2, 7], [2, 11], [1, 2], [5, 9]]);
+
+gap> SubdigraphHomeomorphicToK4(D);
+fail
+gap> SubdigraphHomeomorphicToK23(D);
+[ [ 3, 10, 5 ], [ 10, 8, 9 ], [ 4 ], [ 6 ], [ 11 ], [ 7 ], [ 8 ], [ ],
+ [ 11 ], [ ], [ ] ]
+gap> SubdigraphHomeomorphicToK33(D);
+fail
+gap> SubdigraphHomeomorphicToK23(NullDigraph(0));
+fail
+gap> SubdigraphHomeomorphicToK33(CompleteDigraph(5));
+fail
+gap> SubdigraphHomeomorphicToK33(CompleteBipartiteDigraph(3, 3));
+[ [ 4, 6, 5 ], [ 4, 5, 6 ], [ 6, 5, 4 ], [ ], [ ], [ ] ]
+gap> SubdigraphHomeomorphicToK4(CompleteDigraph(3));
+fail
+
+# KuratowskiPlanarSubdigraph
+gap> D := Digraph([[3, 5, 10], [8, 9, 10], [1, 4], [3, 6], [1, 7, 11], [4, 7],
+> [6, 8], [2, 7], [2, 11], [1, 2], [5, 9]]);
+
+gap> KuratowskiPlanarSubdigraph(D);
+fail
+gap> D := Digraph([[2, 4, 7, 9, 10], [1, 3, 4, 6, 9, 10], [6, 10],
+> [2, 5, 8, 9], [1, 2, 3, 4, 6, 7, 9, 10], [3, 4, 5, 7, 9, 10],
+> [3, 4, 5, 6, 9, 10], [3, 4, 5, 7, 9], [2, 3, 5, 6, 7, 8], [3, 5]]);
+
+gap> IsPlanarDigraph(D);
+false
+gap> KuratowskiPlanarSubdigraph(D);
+[ [ 2, 9, 7 ], [ 3 ], [ 6 ], [ 5, 9 ], [ 6 ], [ ], [ 4 ], [ 7, 9, 3 ], [ ],
+ [ ] ]
+gap> D := NullDigraph(0);
+
+gap> KuratowskiPlanarSubdigraph(D);
+fail
+
+# KuratowskiOuterPlanarSubdigraph
+gap> D := Digraph([[3, 5, 10], [8, 9, 10], [1, 4], [3, 6], [1, 7, 11], [4, 7],
+> [6, 8], [2, 7], [2, 11], [1, 2], [5, 9]]);
+
+gap> KuratowskiOuterPlanarSubdigraph(D);
+[ [ 3, 5, 10 ], [ 9, 8, 10 ], [ 4 ], [ 6 ], [ 11 ], [ 7 ], [ 8 ], [ ],
+ [ 11 ], [ ], [ ] ]
+gap> D := Digraph([[2, 4, 7, 9, 10], [1, 3, 4, 6, 9, 10], [6, 10],
+> [2, 5, 8, 9], [1, 2, 3, 4, 6, 7, 9, 10], [3, 4, 5, 7, 9, 10],
+> [3, 4, 5, 6, 9, 10], [3, 4, 5, 7, 9], [2, 3, 5, 6, 7, 8], [3, 5]]);
+
+gap> IsOuterPlanarDigraph(D);
+false
+gap> KuratowskiOuterPlanarSubdigraph(D);
+[ [ ], [ ], [ ], [ 8, 9 ], [ ], [ ], [ 9, 4 ], [ 7, 9 ], [ ], [ ] ]
+gap> D := NullDigraph(0);
+
+gap> KuratowskiOuterPlanarSubdigraph(D);
+fail
+gap> D := CompleteDigraph(3);
+
+gap> KuratowskiOuterPlanarSubdigraph(D);
+fail
+
+# Kernel function boyers_planarity_check, errors
+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!
+gap> IS_PLANAR(NullDigraph(70000));
+Error, Digraphs: boyers_planarity_check (C): invalid number of edges!
+gap> IsPlanarDigraph(NullDigraph(70000));
+true
+gap> IS_PLANAR(CompleteDigraph(2));
+Error, Digraphs: boyers_planarity_check (C): the 1st argument must be an antis\
+ymmetric digraph
+
+#
+gap> DIGRAPHS_StopTest();
+gap> STOP_TEST("Digraphs package: standard/attr.tst", 0);
+
+#T# DigraphSource and DigraphRange