|
22 | 22 | from math import sin, cos, pi |
23 | 23 | from sage.graphs.graph import Graph |
24 | 24 | from itertools import combinations |
| 25 | +import subprocess |
25 | 26 |
|
26 | 27 |
|
27 | 28 | def JohnsonGraph(n, k): |
@@ -3414,6 +3415,129 @@ def trees(vertices): |
3414 | 3415 | from sage.graphs.trees import TreeIterator |
3415 | 3416 | return iter(TreeIterator(vertices)) |
3416 | 3417 |
|
| 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 | + |
3417 | 3541 | def RingedTree(k, vertex_labels = True): |
3418 | 3542 | r""" |
3419 | 3543 | Return the ringed tree on k-levels. |
|
0 commit comments