Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add interface to nauty's genktreeg #36924

Merged
merged 7 commits into from
Dec 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build/pkgs/nauty/package-version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.8.8
2.8.8.p0
13 changes: 5 additions & 8 deletions build/pkgs/nauty/spkg-configure.m4
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
# We don't use the "converseg" program, but we need to ensure that we
# only detect nauty >= 2.6 because we use the digraph6 format from
# that version -- and converseg was added in nauty-2.6.
#
# We also don't use the "genposetg" program (added in nauty 2.8) yet.
# We require it here to prepare Sage for the use of the major new features
# added in 2.7 and 2.8 (https://pallini.di.uniroma1.it/changes24-28.txt).
# We use the "genktreeg" program (added in nauty 2.8.8). This ensures that we
# detect nauty >= 2.8.8 and so we can use the major new features added in nauty
# since version 2.6. For instance, we use the digraph6 format from nauty >= 2.6
# (https://pallini.di.uniroma1.it/changes24-28.txt).
AC_DEFUN([SAGE_TEST_NAUTY_PROGS], [
m4_foreach([nautyprog], [directg, gentourng, geng, genbg, gentreeg, converseg, genposetg], [
m4_foreach([nautyprog], [directg, gentourng, geng, genbg, gentreeg, genktreeg, genposetg], [
AC_PATH_PROG([$2]nautyprog, [[$1]nautyprog])
AS_IF([test x$[$2]nautyprog = x], [sage_spkg_install_nauty=yes])
])
Expand Down
11 changes: 6 additions & 5 deletions build/pkgs/nauty/spkg-install.in
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ sdh_make

# No install target so we resort to manual copy
PROGRAMS="
addedgeg addptg amtog ancestorg assembleg biplabg catg complg converseg copyg countg cubhamg deledgeg
delptg dimacs2g directg dreadnaut dretodot dretog edgetransg genbg genbgL geng gengL genposetg genquarticg genrang
genspecialg gentourng gentreeg hamheuristic labelg linegraphg listg multig nbrhoodg
newedgeg pickg planarg productg ranlabg shortg showg subdivideg twohamg underlyingg vcolg
watercluster2 NRswitchg"
addedgeg addptg amtog ancestorg assembleg biplabg catg complg converseg copyg
countg countneg cubhamg deledgeg delptg dimacs2g directg dreadnaut dretodot
dretog edgetransg genbg genbgL geng gengL genposetg genquarticg genrang
genspecialg gentourng gentreeg genktreeg hamheuristic labelg linegraphg listg
multig nbrhoodg newedgeg pickg planarg productg ranlabg ransubg shortg showg
subdivideg twohamg underlyingg vcolg watercluster2 NRswitchg"
sdh_install $PROGRAMS "$SAGE_LOCAL/bin"

sdh_install nauty.h "$SAGE_LOCAL/include/nauty"
Expand Down
6 changes: 3 additions & 3 deletions src/sage/features/nauty.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class NautyExecutable(Executable):
EXAMPLES::

sage: from sage.features.nauty import NautyExecutable
sage: NautyExecutable('converseg').is_present() # optional - nauty
sage: NautyExecutable('converseg').is_present() # needs nauty
FeatureTestResult('nauty_converseg', True)
"""
def __init__(self, name):
Expand All @@ -49,7 +49,7 @@ class Nauty(JoinFeature):
EXAMPLES::

sage: from sage.features.nauty import Nauty
sage: Nauty().is_present() # optional - nauty
sage: Nauty().is_present() # needs nauty
FeatureTestResult('nauty', True)
"""
def __init__(self):
Expand All @@ -62,7 +62,7 @@ def __init__(self):
"""
JoinFeature.__init__(self, "nauty",
[NautyExecutable(name)
for name in ('directg', 'gentourng', 'geng', 'genbg', 'gentreeg', 'converseg')])
for name in ('directg', 'gentourng', 'geng', 'genbg', 'gentreeg', 'genktreeg')])


def all_features():
Expand Down
115 changes: 115 additions & 0 deletions src/sage/graphs/graph_generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -1192,6 +1192,121 @@ def nauty_genbg(self, options="", debug=False):
G = BipartiteGraph(s[:-1], format='graph6', partition=partition)
yield G

def nauty_genktreeg(self, options="", debug=False):
r"""
Return a generator which creates all `k`-trees using nauty..

A `k`-tree is an undirected graph formed by starting with a complete
graph on `k + 1` vertices and then repeatedly add vertices in such a
way that each added vertex `v` has exactly `k` neighbors `U` such that,
together, the `k + 1` vertices formed by `v` and `U` form a clique.
See the :wikipedia:`K-tree` for more details.

INPUT:

- ``options`` -- string (default: ``""``); a string passed to
``genktreeg`` as if it was run at a system command line. At a minimum,
you *must* pass the number of vertices you desire. Sage expects the
graphs to be in nauty's "graph6" format, do not set an option to
change this default or results will be unpredictable.

- ``debug`` -- boolean (default: ``False``); if ``True`` the first line
of ``genktreeg``'s output to standard error is captured and the first
call to the generator's ``next()`` function will return this line as a
string. A line leading with ">A" indicates a successful initiation of
the program with some information on the arguments, while a line
beginning with ">E" indicates an error with the input.

The possible options, obtained as output of ``genktreeg --help``::

n : the number of vertices
-k<int> : the value of `k`(default: 2)
res/mod : only generate subset res out of subsets 0..mod-1
-l : canonically label output graphs

Options which cause ``genktreeg`` to use an output format different than
the graph6 format are not listed above (-u, -s, -h) as they will confuse
the creation of a Sage graph. The res/mod option can be useful when
using the output in a routine run several times in parallel.

OUTPUT:

A generator which will produce the graphs as Sage graphs.
These will be simple graphs: no loops, no multiple edges, no
directed edges.

EXAMPLES:

A `k`-tree is a maximal graph with treewidth `k`::

sage: # needs nauty
sage: gen = graphs.nauty_genktreeg("10 -k4")
sage: G = next(gen); G
Graph on 10 vertices
sage: G.treewidth()
4

A list of all 2-trees with 6, 7 and 8 vertices. This agrees with
:oeis:`A054581`::

sage: # needs nauty
sage: gen = graphs.nauty_genktreeg("6")
sage: len(list(gen))
5
sage: gen = graphs.nauty_genktreeg("7")
sage: len(list(gen))
12
sage: gen = graphs.nauty_genktreeg("8")
sage: len(list(gen))
39

The ``debug`` switch can be used to examine ``geng``'s reaction to the
input in the ``options`` string. We illustrate success. (A failure
will be a string beginning with ">E".) Passing the "-q" switch to
``geng`` will suppress the indicator of a successful initiation, and so
the first returned value might be an empty string if ``debug`` is
``True``::

sage: gen = graphs.nauty_genktreeg("7", debug=True) # needs nauty
sage: print(next(gen)) # needs nauty
>A ...genktreeg k=2 n=7

TESTS:

Wrong input::

sage: # needs nauty
sage: list(graphs.nauty_genktreeg("4 -k5", debug=True))
['>E genktreeg: n cannot be less than k\n']
sage: list(graphs.nauty_genktreeg("10 -k 4", debug=True))
['>E genktreeg -k: missing argument value\n']
sage: list(graphs.nauty_genktreeg("-c3", debug=False))
Traceback (most recent call last):
...
ValueError: wrong format of parameter option
"""
import shlex
from sage.features.nauty import NautyExecutable
geng_path = NautyExecutable("genktreeg").absolute_filename()
sp = subprocess.Popen(shlex.quote(geng_path) + " {0}".format(options), shell=True,
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, close_fds=True,
encoding='latin-1')
msg = sp.stderr.readline()
if debug:
yield msg
elif msg.startswith('>E'):
raise ValueError('wrong format of parameter option')
gen = sp.stdout
while True:
try:
s = next(gen)
except StopIteration:
# Exhausted list of graphs from nauty geng
return
G = graph.Graph(s[:-1], format='graph6')
yield G

def cospectral_graphs(self, vertices, matrix_function=None, graphs=None):
r"""
Find all sets of graphs on ``vertices`` vertices (with
Expand Down
Loading