Skip to content
This repository was archived by the owner on Jan 30, 2023. It is now read-only.

Commit 077a46f

Browse files
committed
trac #33670: add interface to nauty's gentreeg
1 parent 78bfb6c commit 077a46f

File tree

4 files changed

+128
-2
lines changed

4 files changed

+128
-2
lines changed

build/pkgs/nauty/spkg-configure.m4

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# only detect nauty >= 2.6 because we use the digraph6 format from
33
# that version -- and converseg was added in nauty-2.6.
44
AC_DEFUN([SAGE_TEST_NAUTY_PROGS], [
5-
m4_foreach([nautyprog], [directg, gentourng, geng, genbg, converseg], [
5+
m4_foreach([nautyprog], [directg, gentourng, geng, genbg, gentreeg, converseg], [
66
AC_PATH_PROG([$2]nautyprog, [[$1]nautyprog])
77
AS_IF([test x$[$2]nautyprog = x], [sage_spkg_install_nauty=yes])
88
])

src/sage/features/nauty.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def __init__(self):
5252
"""
5353
JoinFeature.__init__(self, "nauty",
5454
[NautyExecutable(name)
55-
for name in ('directg', 'gentourng', 'geng', 'genbg', 'converseg')])
55+
for name in ('directg', 'gentourng', 'geng', 'genbg', 'gentreeg', 'converseg')])
5656

5757

5858
def all_features():

src/sage/graphs/generators/families.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from math import sin, cos, pi
2323
from sage.graphs.graph import Graph
2424
from itertools import combinations
25+
import subprocess
2526

2627

2728
def JohnsonGraph(n, k):
@@ -3414,6 +3415,129 @@ def trees(vertices):
34143415
from sage.graphs.trees import TreeIterator
34153416
return iter(TreeIterator(vertices))
34163417

3418+
def nauty_gentreeg(options="", debug=False):
3419+
r"""
3420+
Return a generator which creates non-isomorphic trees from nauty's gentreeg
3421+
program.
3422+
3423+
INPUT:
3424+
3425+
- ``options`` -- string (default: ``""``); a string passed to ``gentreeg``
3426+
as if it was run at a system command line. At a minimum, you *must* pass
3427+
the number of vertices you desire. Sage expects the graphs to be in
3428+
nauty's "sparse6" format, do not set an option to change this default or
3429+
results will be unpredictable.
3430+
3431+
- ``debug`` -- boolean (default: ``False``); if ``True`` the first line of
3432+
``gentreeg``'s output to standard error is captured and the first call to
3433+
the generator's ``next()`` function will return this line as a string. A
3434+
line leading with ">A" indicates a successful initiation of the program
3435+
with some information on the arguments, while a line beginning with ">E"
3436+
indicates an error with the input.
3437+
3438+
The possible options, obtained as output of ``gentreeg -help``::
3439+
3440+
n : the number of vertices. Must be in range 1..128
3441+
res/mod : only generate subset res out of subsets 0..mod-1
3442+
-D<int> : an upper bound for the maximum degree
3443+
-Z<int>:<int> : bounds on the diameter
3444+
-q : suppress auxiliary output
3445+
3446+
Options which cause ``gentreeg`` to use an output format different than the
3447+
sparse6 format are not listed above (-p, -l, -u) as they will confuse the
3448+
creation of a Sage graph. The res/mod option can be useful when using the
3449+
output in a routine run several times in parallel.
3450+
3451+
OUTPUT:
3452+
3453+
A generator which will produce the graphs as Sage graphs. These will be
3454+
simple graphs: no loops, no multiple edges, no directed edges.
3455+
3456+
.. SEEALSO::
3457+
3458+
:meth:`trees` -- another generator of trees
3459+
3460+
EXAMPLES:
3461+
3462+
The generator can be used to construct trees for testing, one at a time
3463+
(usually inside a loop). Or it can be used to create an entire list all at
3464+
once if there is sufficient memory to contain it::
3465+
3466+
sage: gen = graphs.nauty_gentreeg("4")
3467+
sage: next(gen)
3468+
Graph on 4 vertices
3469+
sage: next(gen)
3470+
Graph on 4 vertices
3471+
sage: next(gen)
3472+
Traceback (most recent call last):
3473+
...
3474+
StopIteration
3475+
3476+
The number of trees on the first few vertex counts. This aggrees with
3477+
:oeis:`A000055`::
3478+
3479+
sage: [len(list(graphs.nauty_gentreeg(str(i)))) for i in range(1, 15)]
3480+
[1, 1, 1, 2, 3, 6, 11, 23, 47, 106, 235, 551, 1301, 3159]
3481+
3482+
The ``debug`` switch can be used to examine ``gentreeg``'s reaction to the
3483+
input in the ``options`` string. We illustrate success. (A failure will be
3484+
a string beginning with ">E".) Passing the "-q" switch to ``gentreeg`` will
3485+
suppress the indicator of a successful initiation, and so the first returned
3486+
value might be an empty string if ``debug`` is ``True``::
3487+
3488+
sage: gen = graphs.nauty_gentreeg("4", debug=True)
3489+
sage: print(next(gen))
3490+
>A ...gentreeg Z=2:3 D=3 n=4
3491+
sage: gen = graphs.nauty_gentreeg("4 -q", debug=True)
3492+
sage: next(gen)
3493+
''
3494+
3495+
TESTS:
3496+
3497+
The number `n` of vertices must be in range 1..128::
3498+
3499+
sage: list(graphs.nauty_gentreeg("0", debug=False))
3500+
Traceback (most recent call last):
3501+
...
3502+
ValueError: wrong format of parameter options
3503+
sage: list(graphs.nauty_gentreeg("0", debug=True))
3504+
['>E gentreeg: n must be in the range 1..128\n']
3505+
sage: list(graphs.nauty_gentreeg("200", debug=True))
3506+
['>E gentreeg: n must be in the range 1..128\n']
3507+
3508+
Wrong input::
3509+
3510+
sage: list(graphs.nauty_gentreeg("3 -x", debug=False))
3511+
Traceback (most recent call last):
3512+
...
3513+
ValueError: wrong format of parameter options
3514+
sage: list(graphs.nauty_gentreeg("3 -x", debug=True))
3515+
['>E Usage: ...gentreeg [-D#] [-Z#:#] [-ulps] [-q] n [res/mod] ...
3516+
sage: list(graphs.nauty_gentreeg("3", debug=True))
3517+
['>A ...gentreeg Z=2:2 D=2 n=3\n', Graph on 3 vertices]
3518+
"""
3519+
import shlex
3520+
from sage.features.nauty import NautyExecutable
3521+
gen_path = NautyExecutable("gentreeg").absolute_filename()
3522+
sp = subprocess.Popen(shlex.quote(gen_path) + " {0}".format(options), shell=True,
3523+
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
3524+
stderr=subprocess.PIPE, close_fds=True,
3525+
encoding='latin-1')
3526+
msg = sp.stderr.readline()
3527+
if debug:
3528+
yield msg
3529+
elif msg.startswith('>E'):
3530+
raise ValueError('wrong format of parameter options')
3531+
gen = sp.stdout
3532+
while True:
3533+
try:
3534+
s = next(gen)
3535+
except StopIteration:
3536+
# Exhausted list of graphs from nauty geng
3537+
return
3538+
G = Graph(s[:-1], format='sparse6', loops=False, multiedges=False)
3539+
yield G
3540+
34173541
def RingedTree(k, vertex_labels = True):
34183542
r"""
34193543
Return the ringed tree on k-levels.

src/sage/graphs/graph_generators.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ def __append_to_doc(methods):
276276
"SwitchedSquaredSkewHadamardMatrixGraph",
277277
"strongly_regular_graph",
278278
"trees",
279+
"nauty_gentreeg",
279280
"triangulations",
280281
"TuranGraph",
281282
"UstimenkoGraph",
@@ -2342,6 +2343,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None
23422343
TabacjnGraph = staticmethod(families.TabacjnGraph)
23432344
TadpoleGraph = staticmethod(families.TadpoleGraph)
23442345
trees = staticmethod(families.trees)
2346+
nauty_gentreeg = staticmethod(families.nauty_gentreeg)
23452347
TuranGraph = staticmethod(families.TuranGraph)
23462348
UstimenkoGraph = staticmethod(distance_regular.UstimenkoGraph)
23472349
WheelGraph = staticmethod(families.WheelGraph)

0 commit comments

Comments
 (0)