passagemath-graphs 10.6.1rc1__cp310-cp310-musllinux_1_2_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_graphs-10.6.1rc1.dist-info/METADATA +292 -0
- passagemath_graphs-10.6.1rc1.dist-info/RECORD +260 -0
- passagemath_graphs-10.6.1rc1.dist-info/WHEEL +5 -0
- passagemath_graphs-10.6.1rc1.dist-info/top_level.txt +2 -0
- passagemath_graphs.libs/libgcc_s-69c45f16.so.1 +0 -0
- passagemath_graphs.libs/libgmp-8e78bd9b.so.10.5.0 +0 -0
- passagemath_graphs.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
- sage/all__sagemath_graphs.py +39 -0
- sage/combinat/abstract_tree.py +2723 -0
- sage/combinat/all__sagemath_graphs.py +34 -0
- sage/combinat/binary_tree.py +5306 -0
- sage/combinat/cluster_algebra_quiver/all.py +22 -0
- sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
- sage/combinat/cluster_algebra_quiver/interact.py +124 -0
- sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
- sage/combinat/cluster_algebra_quiver/mutation_type.py +1555 -0
- sage/combinat/cluster_algebra_quiver/quiver.py +2290 -0
- sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
- sage/combinat/designs/MOLS_handbook_data.py +570 -0
- sage/combinat/designs/all.py +58 -0
- sage/combinat/designs/bibd.py +1655 -0
- sage/combinat/designs/block_design.py +1071 -0
- sage/combinat/designs/covering_array.py +269 -0
- sage/combinat/designs/covering_design.py +530 -0
- sage/combinat/designs/database.py +5615 -0
- sage/combinat/designs/design_catalog.py +122 -0
- sage/combinat/designs/designs_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/designs_pyx.pxd +21 -0
- sage/combinat/designs/designs_pyx.pyx +993 -0
- sage/combinat/designs/difference_family.py +3951 -0
- sage/combinat/designs/difference_matrices.py +279 -0
- sage/combinat/designs/evenly_distributed_sets.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
- sage/combinat/designs/ext_rep.py +1064 -0
- sage/combinat/designs/gen_quadrangles_with_spread.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
- sage/combinat/designs/group_divisible_designs.py +361 -0
- sage/combinat/designs/incidence_structures.py +2357 -0
- sage/combinat/designs/latin_squares.py +581 -0
- sage/combinat/designs/orthogonal_arrays.py +2244 -0
- sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
- sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +967 -0
- sage/combinat/designs/resolvable_bibd.py +815 -0
- sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
- sage/combinat/designs/subhypergraph_search.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/subhypergraph_search.pyx +530 -0
- sage/combinat/designs/twographs.py +306 -0
- sage/combinat/finite_state_machine.py +14874 -0
- sage/combinat/finite_state_machine_generators.py +2006 -0
- sage/combinat/graph_path.py +448 -0
- sage/combinat/interval_posets.py +3908 -0
- sage/combinat/nu_tamari_lattice.py +269 -0
- sage/combinat/ordered_tree.py +1446 -0
- sage/combinat/posets/all.py +46 -0
- sage/combinat/posets/bubble_shuffle.py +247 -0
- sage/combinat/posets/cartesian_product.py +493 -0
- sage/combinat/posets/d_complete.py +182 -0
- sage/combinat/posets/elements.py +273 -0
- sage/combinat/posets/forest.py +30 -0
- sage/combinat/posets/hasse_cython.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/hasse_cython.pyx +174 -0
- sage/combinat/posets/hasse_diagram.py +3672 -0
- sage/combinat/posets/hochschild_lattice.py +158 -0
- sage/combinat/posets/incidence_algebras.py +794 -0
- sage/combinat/posets/lattices.py +5117 -0
- sage/combinat/posets/linear_extension_iterator.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/linear_extension_iterator.pyx +292 -0
- sage/combinat/posets/linear_extensions.py +1037 -0
- sage/combinat/posets/mobile.py +275 -0
- sage/combinat/posets/moebius_algebra.py +776 -0
- sage/combinat/posets/poset_examples.py +2178 -0
- sage/combinat/posets/posets.py +9360 -0
- sage/combinat/rooted_tree.py +1070 -0
- sage/combinat/shard_order.py +239 -0
- sage/combinat/tamari_lattices.py +384 -0
- sage/combinat/yang_baxter_graph.py +923 -0
- sage/databases/all__sagemath_graphs.py +1 -0
- sage/databases/knotinfo_db.py +1231 -0
- sage/ext_data/all__sagemath_graphs.py +1 -0
- sage/ext_data/graphs/graph_plot_js.html +330 -0
- sage/ext_data/kenzo/CP2.txt +45 -0
- sage/ext_data/kenzo/CP3.txt +349 -0
- sage/ext_data/kenzo/CP4.txt +4774 -0
- sage/ext_data/kenzo/README.txt +49 -0
- sage/ext_data/kenzo/S4.txt +20 -0
- sage/graphs/all.py +42 -0
- sage/graphs/asteroidal_triples.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/asteroidal_triples.pyx +320 -0
- sage/graphs/base/all.py +1 -0
- sage/graphs/base/boost_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/boost_graph.pxd +106 -0
- sage/graphs/base/boost_graph.pyx +3045 -0
- sage/graphs/base/c_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/c_graph.pxd +106 -0
- sage/graphs/base/c_graph.pyx +5096 -0
- sage/graphs/base/dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/dense_graph.pxd +28 -0
- sage/graphs/base/dense_graph.pyx +801 -0
- sage/graphs/base/graph_backends.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/graph_backends.pxd +5 -0
- sage/graphs/base/graph_backends.pyx +797 -0
- sage/graphs/base/overview.py +85 -0
- sage/graphs/base/sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/sparse_graph.pxd +90 -0
- sage/graphs/base/sparse_graph.pyx +1653 -0
- sage/graphs/base/static_dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_dense_graph.pxd +5 -0
- sage/graphs/base/static_dense_graph.pyx +1032 -0
- sage/graphs/base/static_sparse_backend.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_sparse_backend.pxd +27 -0
- sage/graphs/base/static_sparse_backend.pyx +1583 -0
- sage/graphs/base/static_sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_sparse_graph.pxd +37 -0
- sage/graphs/base/static_sparse_graph.pyx +1375 -0
- sage/graphs/bipartite_graph.py +2732 -0
- sage/graphs/centrality.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/centrality.pyx +1038 -0
- sage/graphs/cographs.py +519 -0
- sage/graphs/comparability.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/comparability.pyx +851 -0
- sage/graphs/connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/connectivity.pxd +157 -0
- sage/graphs/connectivity.pyx +4813 -0
- sage/graphs/convexity_properties.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/convexity_properties.pxd +16 -0
- sage/graphs/convexity_properties.pyx +870 -0
- sage/graphs/digraph.py +4754 -0
- sage/graphs/digraph_generators.py +1993 -0
- sage/graphs/distances_all_pairs.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/distances_all_pairs.pxd +12 -0
- sage/graphs/distances_all_pairs.pyx +2938 -0
- sage/graphs/domination.py +1363 -0
- sage/graphs/dot2tex_utils.py +100 -0
- sage/graphs/edge_connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/edge_connectivity.pyx +1215 -0
- sage/graphs/generators/all.py +1 -0
- sage/graphs/generators/basic.py +1769 -0
- sage/graphs/generators/chessboard.py +538 -0
- sage/graphs/generators/classical_geometries.py +1611 -0
- sage/graphs/generators/degree_sequence.py +235 -0
- sage/graphs/generators/distance_regular.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/generators/distance_regular.pyx +2846 -0
- sage/graphs/generators/families.py +4759 -0
- sage/graphs/generators/intersection.py +565 -0
- sage/graphs/generators/platonic_solids.py +262 -0
- sage/graphs/generators/random.py +2623 -0
- sage/graphs/generators/smallgraphs.py +5741 -0
- sage/graphs/generators/world_map.py +724 -0
- sage/graphs/generic_graph.py +26867 -0
- sage/graphs/generic_graph_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/generic_graph_pyx.pxd +34 -0
- sage/graphs/generic_graph_pyx.pyx +1673 -0
- sage/graphs/genus.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/genus.pyx +622 -0
- sage/graphs/graph.py +9645 -0
- sage/graphs/graph_coloring.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_coloring.pyx +2284 -0
- sage/graphs/graph_database.py +1177 -0
- sage/graphs/graph_decompositions/all.py +1 -0
- sage/graphs/graph_decompositions/bandwidth.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
- sage/graphs/graph_decompositions/clique_separators.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/clique_separators.pyx +616 -0
- sage/graphs/graph_decompositions/cutwidth.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
- sage/graphs/graph_decompositions/fast_digraph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
- sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
- sage/graphs/graph_decompositions/graph_products.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/graph_products.pyx +508 -0
- sage/graphs/graph_decompositions/modular_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
- sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
- sage/graphs/graph_decompositions/slice_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
- sage/graphs/graph_decompositions/slice_decomposition.pyx +1106 -0
- sage/graphs/graph_decompositions/tree_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
- sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
- sage/graphs/graph_decompositions/vertex_separation.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
- sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
- sage/graphs/graph_editor.py +82 -0
- sage/graphs/graph_generators.py +3314 -0
- sage/graphs/graph_generators_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_generators_pyx.pyx +95 -0
- sage/graphs/graph_input.py +812 -0
- sage/graphs/graph_latex.py +2064 -0
- sage/graphs/graph_list.py +410 -0
- sage/graphs/graph_plot.py +1756 -0
- sage/graphs/graph_plot_js.py +338 -0
- sage/graphs/hyperbolicity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/hyperbolicity.pyx +1704 -0
- sage/graphs/hypergraph_generators.py +364 -0
- sage/graphs/independent_sets.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/independent_sets.pxd +13 -0
- sage/graphs/independent_sets.pyx +402 -0
- sage/graphs/isgci.py +1033 -0
- sage/graphs/isoperimetric_inequalities.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/isoperimetric_inequalities.pyx +489 -0
- sage/graphs/line_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/line_graph.pyx +743 -0
- sage/graphs/lovasz_theta.py +77 -0
- sage/graphs/matching.py +1633 -0
- sage/graphs/matching_covered_graph.py +3590 -0
- sage/graphs/orientations.py +1489 -0
- sage/graphs/partial_cube.py +459 -0
- sage/graphs/path_enumeration.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/path_enumeration.pyx +2040 -0
- sage/graphs/pq_trees.py +1129 -0
- sage/graphs/print_graphs.py +201 -0
- sage/graphs/schnyder.py +865 -0
- sage/graphs/spanning_tree.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/spanning_tree.pyx +1457 -0
- sage/graphs/strongly_regular_db.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/strongly_regular_db.pyx +3340 -0
- sage/graphs/traversals.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/traversals.pxd +9 -0
- sage/graphs/traversals.pyx +1872 -0
- sage/graphs/trees.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/trees.pxd +15 -0
- sage/graphs/trees.pyx +310 -0
- sage/graphs/tutte_polynomial.py +713 -0
- sage/graphs/views.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/views.pyx +794 -0
- sage/graphs/weakly_chordal.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/weakly_chordal.pyx +604 -0
- sage/groups/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
- sage/knots/all.py +6 -0
- sage/knots/free_knotinfo_monoid.py +507 -0
- sage/knots/gauss_code.py +291 -0
- sage/knots/knot.py +682 -0
- sage/knots/knot_table.py +284 -0
- sage/knots/knotinfo.py +2900 -0
- sage/knots/link.py +4715 -0
- sage/sandpiles/all.py +13 -0
- sage/sandpiles/examples.py +225 -0
- sage/sandpiles/sandpile.py +6365 -0
- sage/topology/all.py +22 -0
- sage/topology/cell_complex.py +1214 -0
- sage/topology/cubical_complex.py +1976 -0
- sage/topology/delta_complex.py +1806 -0
- sage/topology/filtered_simplicial_complex.py +744 -0
- sage/topology/moment_angle_complex.py +823 -0
- sage/topology/simplicial_complex.py +5160 -0
- sage/topology/simplicial_complex_catalog.py +92 -0
- sage/topology/simplicial_complex_examples.py +1680 -0
- sage/topology/simplicial_complex_homset.py +205 -0
- sage/topology/simplicial_complex_morphism.py +836 -0
- sage/topology/simplicial_set.py +4102 -0
- sage/topology/simplicial_set_catalog.py +55 -0
- sage/topology/simplicial_set_constructions.py +2954 -0
- sage/topology/simplicial_set_examples.py +865 -0
- sage/topology/simplicial_set_morphism.py +1464 -0
@@ -0,0 +1,581 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-graphs
|
2
|
+
# sage.doctest: needs sage.modules
|
3
|
+
r"""
|
4
|
+
Mutually orthogonal Latin squares (MOLS)
|
5
|
+
|
6
|
+
The main function of this module is :func:`mutually_orthogonal_latin_squares`
|
7
|
+
and can be can be used to generate MOLS (or check that they exist)::
|
8
|
+
|
9
|
+
sage: MOLS = designs.mutually_orthogonal_latin_squares(4,8) # needs sage.schemes
|
10
|
+
|
11
|
+
For more information on MOLS, see the :wikipedia:`Wikipedia entry on MOLS
|
12
|
+
<Graeco-Latin_square#Mutually_orthogonal_Latin_squares>`. If you are only
|
13
|
+
interested by latin squares, see :mod:`~sage.combinat.matrices.latin`.
|
14
|
+
|
15
|
+
The functions defined here are
|
16
|
+
|
17
|
+
.. csv-table::
|
18
|
+
:class: contentstable
|
19
|
+
:widths: 30, 70
|
20
|
+
:delim: |
|
21
|
+
|
22
|
+
:meth:`mutually_orthogonal_latin_squares` | Return `k` Mutually Orthogonal `n\times n` Latin Squares.
|
23
|
+
:meth:`are_mutually_orthogonal_latin_squares` | Check that the list ``l`` of matrices in are MOLS.
|
24
|
+
:meth:`latin_square_product` | Return the product of two (or more) latin squares.
|
25
|
+
:meth:`MOLS_table` | Print the MOLS table.
|
26
|
+
|
27
|
+
**Table of MOLS**
|
28
|
+
|
29
|
+
Sage can produce a table of MOLS similar to the one from the Handbook of
|
30
|
+
Combinatorial Designs [DesignHandbook]_ (`available here
|
31
|
+
<http://books.google.fr/books?id=S9FA9rq1BgoC&dq=handbook%20combinatorial%20designs%20MOLS%2010000&pg=PA176>`_).
|
32
|
+
|
33
|
+
::
|
34
|
+
|
35
|
+
sage: from sage.combinat.designs.latin_squares import MOLS_table
|
36
|
+
sage: MOLS_table(600) # long time
|
37
|
+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
38
|
+
________________________________________________________________________________
|
39
|
+
0| +oo +oo 1 2 3 4 1 6 7 8 2 10 5 12 4 4 15 16 5 18
|
40
|
+
20| 4 5 3 22 7 24 4 26 5 28 4 30 31 5 4 5 8 36 4 5
|
41
|
+
40| 7 40 5 42 5 6 4 46 8 48 6 5 5 52 5 6 7 7 5 58
|
42
|
+
60| 5 60 5 6 63 7 5 66 5 6 6 70 7 72 5 7 6 6 6 78
|
43
|
+
80| 9 80 8 82 6 6 6 6 7 88 6 7 6 6 6 6 7 96 6 8
|
44
|
+
100| 8 100 6 102 7 7 6 106 6 108 6 6 13 112 6 7 6 8 6 6
|
45
|
+
120| 7 120 6 6 6 124 6 126 127 7 6 130 6 7 6 7 7 136 6 138
|
46
|
+
140| 6 7 6 10 10 7 6 7 6 148 6 150 7 8 8 7 6 156 7 6
|
47
|
+
160| 9 7 6 162 6 7 6 166 7 168 6 8 6 172 6 6 14 9 6 178
|
48
|
+
180| 6 180 6 6 7 9 6 10 6 8 6 190 7 192 6 7 6 196 6 198
|
49
|
+
200| 7 7 6 7 6 8 6 8 14 11 10 210 6 7 6 7 7 8 6 10
|
50
|
+
220| 6 12 6 222 13 8 6 226 6 228 6 7 7 232 6 7 6 7 6 238
|
51
|
+
240| 7 240 6 242 6 7 6 12 7 7 6 250 6 12 9 7 255 256 6 12
|
52
|
+
260| 6 8 8 262 7 8 7 10 7 268 7 270 15 16 6 13 10 276 6 9
|
53
|
+
280| 7 280 6 282 6 12 6 7 15 288 6 6 6 292 6 6 7 10 10 12
|
54
|
+
300| 7 7 7 7 15 15 6 306 7 7 7 310 7 312 7 10 7 316 7 10
|
55
|
+
320| 15 15 6 16 8 12 6 7 7 9 6 330 7 8 7 6 7 336 6 7
|
56
|
+
340| 6 10 10 342 7 7 6 346 6 348 8 12 18 352 6 9 7 9 6 358
|
57
|
+
360| 7 360 6 7 7 7 6 366 15 15 7 15 7 372 7 15 7 13 7 378
|
58
|
+
380| 7 12 7 382 15 15 7 15 7 388 7 16 7 7 7 7 8 396 7 7
|
59
|
+
400| 15 400 7 15 11 8 7 15 8 408 7 13 8 12 10 9 18 15 7 418
|
60
|
+
420| 7 420 7 15 7 16 6 7 7 7 6 430 15 432 6 15 6 18 7 438
|
61
|
+
440| 7 15 7 442 7 13 7 11 15 448 7 15 7 7 7 15 7 456 7 16
|
62
|
+
460| 7 460 7 462 15 15 7 466 8 8 7 15 7 15 10 18 7 15 6 478
|
63
|
+
480| 15 15 6 15 8 7 6 486 7 15 6 490 6 16 6 7 15 15 6 498
|
64
|
+
500| 7 8 9 502 7 15 6 15 7 508 6 15 511 18 7 15 8 12 8 15
|
65
|
+
520| 8 520 10 522 12 15 8 16 15 528 7 15 8 12 7 15 8 15 10 15
|
66
|
+
540| 12 540 7 15 18 7 7 546 7 8 7 18 7 7 7 7 7 556 7 12
|
67
|
+
560| 15 7 7 562 7 7 6 7 7 568 6 570 7 7 15 22 8 576 7 7
|
68
|
+
580| 7 8 7 10 7 8 7 586 7 18 17 7 15 592 8 15 7 7 8 598
|
69
|
+
|
70
|
+
Comparison with the results from the Handbook of Combinatorial Designs (2ed)
|
71
|
+
[DesignHandbook]_::
|
72
|
+
|
73
|
+
sage: MOLS_table(600,compare=True) # long time
|
74
|
+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
75
|
+
________________________________________________________________________________
|
76
|
+
0| + +
|
77
|
+
20|
|
78
|
+
40|
|
79
|
+
60|
|
80
|
+
80|
|
81
|
+
100|
|
82
|
+
120|
|
83
|
+
140|
|
84
|
+
160|
|
85
|
+
180|
|
86
|
+
200| -
|
87
|
+
220|
|
88
|
+
240|
|
89
|
+
260|
|
90
|
+
280|
|
91
|
+
300|
|
92
|
+
320| -
|
93
|
+
340|
|
94
|
+
360| - -
|
95
|
+
380| -
|
96
|
+
400|
|
97
|
+
420| -
|
98
|
+
440|
|
99
|
+
460|
|
100
|
+
480|
|
101
|
+
500| -
|
102
|
+
520|
|
103
|
+
540|
|
104
|
+
560|
|
105
|
+
580|
|
106
|
+
|
107
|
+
.. TODO::
|
108
|
+
|
109
|
+
Look at [ColDin01]_.
|
110
|
+
|
111
|
+
REFERENCES:
|
112
|
+
|
113
|
+
.. [Stinson2004] Douglas R. Stinson,
|
114
|
+
*Combinatorial designs: construction and analysis*,
|
115
|
+
Springer, 2004.
|
116
|
+
|
117
|
+
.. [ColDin01] Charles Colbourn, Jeffrey Dinitz,
|
118
|
+
*Mutually orthogonal latin squares: a brief survey of constructions*,
|
119
|
+
Volume 95, Issues 1-2, Pages 9-48,
|
120
|
+
Journal of Statistical Planning and Inference,
|
121
|
+
Springer, 1 May 2001.
|
122
|
+
|
123
|
+
Functions
|
124
|
+
---------
|
125
|
+
"""
|
126
|
+
from itertools import repeat
|
127
|
+
from sage.rings.integer import Integer
|
128
|
+
from sage.categories.sets_cat import EmptySetError
|
129
|
+
from sage.misc.unknown import Unknown
|
130
|
+
from sage.arith.misc import is_prime_power
|
131
|
+
from sage.rings.finite_rings.finite_field_constructor import GF
|
132
|
+
|
133
|
+
|
134
|
+
def are_mutually_orthogonal_latin_squares(l, verbose=False):
|
135
|
+
r"""
|
136
|
+
Check whether the list of matrices in ``l`` form mutually orthogonal latin
|
137
|
+
squares.
|
138
|
+
|
139
|
+
INPUT:
|
140
|
+
|
141
|
+
- ``verbose`` -- if ``True`` then print why the list of matrices provided are
|
142
|
+
not mutually orthogonal latin squares
|
143
|
+
|
144
|
+
EXAMPLES::
|
145
|
+
|
146
|
+
sage: from sage.combinat.designs.latin_squares import are_mutually_orthogonal_latin_squares
|
147
|
+
sage: m1 = matrix([[0,1,2],[2,0,1],[1,2,0]])
|
148
|
+
sage: m2 = matrix([[0,1,2],[1,2,0],[2,0,1]])
|
149
|
+
sage: m3 = matrix([[0,1,2],[2,0,1],[1,2,0]])
|
150
|
+
sage: are_mutually_orthogonal_latin_squares([m1,m2])
|
151
|
+
True
|
152
|
+
sage: are_mutually_orthogonal_latin_squares([m1,m3])
|
153
|
+
False
|
154
|
+
sage: are_mutually_orthogonal_latin_squares([m2,m3])
|
155
|
+
True
|
156
|
+
sage: are_mutually_orthogonal_latin_squares([m1,m2,m3], verbose=True)
|
157
|
+
Squares 0 and 2 are not orthogonal
|
158
|
+
False
|
159
|
+
|
160
|
+
sage: m = designs.mutually_orthogonal_latin_squares(7,8) # needs sage.schemes
|
161
|
+
sage: are_mutually_orthogonal_latin_squares(m) # needs sage.schemes
|
162
|
+
True
|
163
|
+
|
164
|
+
TESTS:
|
165
|
+
|
166
|
+
Not a latin square::
|
167
|
+
|
168
|
+
sage: m1 = matrix([[0,1,0],[2,0,1],[1,2,0]])
|
169
|
+
sage: m2 = matrix([[0,1,2],[1,2,0],[2,0,1]])
|
170
|
+
sage: are_mutually_orthogonal_latin_squares([m1,m2], verbose=True)
|
171
|
+
Matrix 0 is not row latin
|
172
|
+
False
|
173
|
+
sage: m1 = matrix([[0,1,2],[1,0,2],[1,2,0]])
|
174
|
+
sage: are_mutually_orthogonal_latin_squares([m1,m2], verbose=True)
|
175
|
+
Matrix 0 is not column latin
|
176
|
+
False
|
177
|
+
sage: m1 = matrix([[0,0,0],[1,1,1],[2,2,2]])
|
178
|
+
sage: m2 = matrix([[0,1,2],[0,1,2],[0,1,2]])
|
179
|
+
sage: are_mutually_orthogonal_latin_squares([m1,m2])
|
180
|
+
False
|
181
|
+
"""
|
182
|
+
|
183
|
+
if not l:
|
184
|
+
raise ValueError("the list must be non empty")
|
185
|
+
|
186
|
+
n = l[0].ncols()
|
187
|
+
k = len(l)
|
188
|
+
if any(M.ncols() != n or M.nrows() != n for M in l):
|
189
|
+
if verbose:
|
190
|
+
print("Not all matrices are square matrices of the same dimensions")
|
191
|
+
return False
|
192
|
+
|
193
|
+
# Check that all matrices are latin squares
|
194
|
+
for i,M in enumerate(l):
|
195
|
+
if any(len(set(R)) != n for R in M):
|
196
|
+
if verbose:
|
197
|
+
print("Matrix {} is not row latin".format(i))
|
198
|
+
return False
|
199
|
+
if any(len(set(R)) != n for R in zip(*M)):
|
200
|
+
if verbose:
|
201
|
+
print("Matrix {} is not column latin".format(i))
|
202
|
+
return False
|
203
|
+
|
204
|
+
from .designs_pyx import is_orthogonal_array
|
205
|
+
return is_orthogonal_array(list(zip(*[[x for R in M for x in R] for M in l])),k,n, verbose=verbose, terminology='MOLS')
|
206
|
+
|
207
|
+
|
208
|
+
def mutually_orthogonal_latin_squares(k, n, partitions=False, check=True):
|
209
|
+
r"""
|
210
|
+
Return `k` Mutually Orthogonal `n\times n` Latin Squares (MOLS).
|
211
|
+
|
212
|
+
For more information on Mutually Orthogonal Latin Squares, see
|
213
|
+
:mod:`~sage.combinat.designs.latin_squares`.
|
214
|
+
|
215
|
+
INPUT:
|
216
|
+
|
217
|
+
- ``k`` -- integer; number of MOLS. If ``k`` is ``None`` it is set to the largest
|
218
|
+
value available
|
219
|
+
|
220
|
+
- ``n`` -- integer; size of the latin square
|
221
|
+
|
222
|
+
- ``partitions`` -- boolean; a Latin Square can be seen as 3 partitions of
|
223
|
+
the `n^2` cells of the array into `n` sets of size `n`, respectively:
|
224
|
+
|
225
|
+
* The partition of rows
|
226
|
+
* The partition of columns
|
227
|
+
* The partition of number (cells numbered with 0, cells numbered with 1,
|
228
|
+
...)
|
229
|
+
|
230
|
+
These partitions have the additional property that any two sets from
|
231
|
+
different partitions intersect on exactly one element.
|
232
|
+
|
233
|
+
When ``partitions`` is set to ``True``, this function returns a list of `k+2`
|
234
|
+
partitions satisfying this intersection property instead of the `k+2` MOLS
|
235
|
+
(though the data is exactly the same in both cases).
|
236
|
+
|
237
|
+
- ``check`` -- boolean (default: ``True``); whether to check that output is
|
238
|
+
correct before returning it. As this is expected to be useless, you may
|
239
|
+
want to disable it whenever you want speed.
|
240
|
+
|
241
|
+
EXAMPLES::
|
242
|
+
|
243
|
+
sage: designs.mutually_orthogonal_latin_squares(4,5) # needs sage.schemes
|
244
|
+
[
|
245
|
+
[0 1 2 3 4] [0 1 2 3 4] [0 1 2 3 4] [0 1 2 3 4]
|
246
|
+
[1 2 3 4 0] [2 3 4 0 1] [3 4 0 1 2] [4 0 1 2 3]
|
247
|
+
[2 3 4 0 1] [4 0 1 2 3] [1 2 3 4 0] [3 4 0 1 2]
|
248
|
+
[3 4 0 1 2] [1 2 3 4 0] [4 0 1 2 3] [2 3 4 0 1]
|
249
|
+
[4 0 1 2 3], [3 4 0 1 2], [2 3 4 0 1], [1 2 3 4 0]
|
250
|
+
]
|
251
|
+
|
252
|
+
sage: designs.mutually_orthogonal_latin_squares(3,7) # needs sage.schemes
|
253
|
+
[
|
254
|
+
[0 1 2 3 4 5 6] [0 1 2 3 4 5 6] [0 1 2 3 4 5 6]
|
255
|
+
[1 2 3 4 5 6 0] [2 3 4 5 6 0 1] [3 4 5 6 0 1 2]
|
256
|
+
[2 3 4 5 6 0 1] [4 5 6 0 1 2 3] [6 0 1 2 3 4 5]
|
257
|
+
[3 4 5 6 0 1 2] [6 0 1 2 3 4 5] [2 3 4 5 6 0 1]
|
258
|
+
[4 5 6 0 1 2 3] [1 2 3 4 5 6 0] [5 6 0 1 2 3 4]
|
259
|
+
[5 6 0 1 2 3 4] [3 4 5 6 0 1 2] [1 2 3 4 5 6 0]
|
260
|
+
[6 0 1 2 3 4 5], [5 6 0 1 2 3 4], [4 5 6 0 1 2 3]
|
261
|
+
]
|
262
|
+
|
263
|
+
sage: designs.mutually_orthogonal_latin_squares(2,5,partitions=True) # needs sage.schemes
|
264
|
+
[[[0, 1, 2, 3, 4],
|
265
|
+
[5, 6, 7, 8, 9],
|
266
|
+
[10, 11, 12, 13, 14],
|
267
|
+
[15, 16, 17, 18, 19],
|
268
|
+
[20, 21, 22, 23, 24]],
|
269
|
+
[[0, 5, 10, 15, 20],
|
270
|
+
[1, 6, 11, 16, 21],
|
271
|
+
[2, 7, 12, 17, 22],
|
272
|
+
[3, 8, 13, 18, 23],
|
273
|
+
[4, 9, 14, 19, 24]],
|
274
|
+
[[0, 9, 13, 17, 21],
|
275
|
+
[1, 5, 14, 18, 22],
|
276
|
+
[2, 6, 10, 19, 23],
|
277
|
+
[3, 7, 11, 15, 24],
|
278
|
+
[4, 8, 12, 16, 20]],
|
279
|
+
[[0, 8, 11, 19, 22],
|
280
|
+
[1, 9, 12, 15, 23],
|
281
|
+
[2, 5, 13, 16, 24],
|
282
|
+
[3, 6, 14, 17, 20],
|
283
|
+
[4, 7, 10, 18, 21]]]
|
284
|
+
|
285
|
+
What is the maximum number of MOLS of size 8 that Sage knows how to build?::
|
286
|
+
|
287
|
+
sage: designs.orthogonal_arrays.largest_available_k(8)-2 # needs sage.schemes
|
288
|
+
7
|
289
|
+
|
290
|
+
If you only want to know if Sage is able to build a given set of
|
291
|
+
MOLS, query the ``orthogonal_arrays.*`` functions::
|
292
|
+
|
293
|
+
sage: designs.orthogonal_arrays.is_available(5+2, 5) # 5 MOLS of order 5
|
294
|
+
False
|
295
|
+
sage: designs.orthogonal_arrays.is_available(4+2,6) # 4 MOLS of order 6 # needs sage.schemes
|
296
|
+
False
|
297
|
+
|
298
|
+
Sage, however, is not able to prove that the second MOLS do not exist::
|
299
|
+
|
300
|
+
sage: designs.orthogonal_arrays.exists(4+2,6) # 4 MOLS of order 6 # needs sage.schemes
|
301
|
+
Unknown
|
302
|
+
|
303
|
+
If you ask for such a MOLS then you will respectively get an informative
|
304
|
+
:exc:`EmptySetError` or :exc:`NotImplementedError`::
|
305
|
+
|
306
|
+
sage: designs.mutually_orthogonal_latin_squares(5, 5)
|
307
|
+
Traceback (most recent call last):
|
308
|
+
...
|
309
|
+
EmptySetError: there exist at most n-1 MOLS of size n if n>=2
|
310
|
+
sage: designs.mutually_orthogonal_latin_squares(4,6) # needs sage.schemes
|
311
|
+
Traceback (most recent call last):
|
312
|
+
...
|
313
|
+
NotImplementedError: I don't know how to build 4 MOLS of order 6
|
314
|
+
|
315
|
+
TESTS:
|
316
|
+
|
317
|
+
The special case `n=1`::
|
318
|
+
|
319
|
+
sage: designs.mutually_orthogonal_latin_squares(3, 1)
|
320
|
+
[[0], [0], [0]]
|
321
|
+
|
322
|
+
Wrong input for `k`::
|
323
|
+
|
324
|
+
sage: designs.mutually_orthogonal_latin_squares(None, 1)
|
325
|
+
Traceback (most recent call last):
|
326
|
+
...
|
327
|
+
TypeError: k must be a positive integer
|
328
|
+
|
329
|
+
sage: designs.mutually_orthogonal_latin_squares(-1, 1)
|
330
|
+
Traceback (most recent call last):
|
331
|
+
...
|
332
|
+
ValueError: k must be positive
|
333
|
+
|
334
|
+
sage: designs.mutually_orthogonal_latin_squares(2,10)
|
335
|
+
[
|
336
|
+
[1 8 9 0 2 4 6 3 5 7] [1 7 6 5 0 9 8 2 3 4]
|
337
|
+
[7 2 8 9 0 3 5 4 6 1] [8 2 1 7 6 0 9 3 4 5]
|
338
|
+
[6 1 3 8 9 0 4 5 7 2] [9 8 3 2 1 7 0 4 5 6]
|
339
|
+
[5 7 2 4 8 9 0 6 1 3] [0 9 8 4 3 2 1 5 6 7]
|
340
|
+
[0 6 1 3 5 8 9 7 2 4] [2 0 9 8 5 4 3 6 7 1]
|
341
|
+
[9 0 7 2 4 6 8 1 3 5] [4 3 0 9 8 6 5 7 1 2]
|
342
|
+
[8 9 0 1 3 5 7 2 4 6] [6 5 4 0 9 8 7 1 2 3]
|
343
|
+
[2 3 4 5 6 7 1 8 9 0] [3 4 5 6 7 1 2 8 0 9]
|
344
|
+
[3 4 5 6 7 1 2 0 8 9] [5 6 7 1 2 3 4 0 9 8]
|
345
|
+
[4 5 6 7 1 2 3 9 0 8], [7 1 2 3 4 5 6 9 8 0]
|
346
|
+
]
|
347
|
+
|
348
|
+
Verify the construction from [KD2015]_::
|
349
|
+
|
350
|
+
sage: designs.mutually_orthogonal_latin_squares(2, 9)
|
351
|
+
[
|
352
|
+
[0 1 2 3 4 5 6 7 8] [0 1 2 3 4 5 6 7 8]
|
353
|
+
[2 3 6 4 1 8 0 5 7] [3 8 4 7 5 2 1 0 6]
|
354
|
+
[3 8 4 7 5 2 1 0 6] [4 7 1 5 8 6 3 2 0]
|
355
|
+
[4 7 1 5 8 6 3 2 0] [5 0 8 2 6 1 7 4 3]
|
356
|
+
[5 0 8 2 6 1 7 4 3] [6 4 0 1 3 7 2 8 5]
|
357
|
+
[6 4 0 1 3 7 2 8 5] [7 6 5 0 2 4 8 3 1]
|
358
|
+
[7 6 5 0 2 4 8 3 1] [8 2 7 6 0 3 5 1 4]
|
359
|
+
[8 2 7 6 0 3 5 1 4] [1 5 3 8 7 0 4 6 2]
|
360
|
+
[1 5 3 8 7 0 4 6 2], [2 3 6 4 1 8 0 5 7]
|
361
|
+
]
|
362
|
+
"""
|
363
|
+
from sage.combinat.designs.orthogonal_arrays import orthogonal_array
|
364
|
+
from sage.matrix.constructor import Matrix
|
365
|
+
from .database import MOLS_constructions
|
366
|
+
|
367
|
+
if k is None:
|
368
|
+
raise TypeError('k must be a positive integer')
|
369
|
+
try:
|
370
|
+
Integer(k)
|
371
|
+
except TypeError:
|
372
|
+
raise
|
373
|
+
if k < 0:
|
374
|
+
raise ValueError('k must be positive')
|
375
|
+
|
376
|
+
if n == 1:
|
377
|
+
matrices = [Matrix([[0]])] * k
|
378
|
+
|
379
|
+
elif k >= n:
|
380
|
+
raise EmptySetError("there exist at most n-1 MOLS of size n if n>=2")
|
381
|
+
|
382
|
+
elif n in MOLS_constructions and k <= MOLS_constructions[n][0]:
|
383
|
+
_, construction = MOLS_constructions[n]
|
384
|
+
|
385
|
+
matrices = construction()[:k]
|
386
|
+
|
387
|
+
# Implements the construction from Theorem 5.2.4 of [KD2015]_ for prime powers.
|
388
|
+
# This was implemented to fix :issue:`26107`, which pointed out that this
|
389
|
+
# function was unacceptably slow when n was a large prime power
|
390
|
+
elif is_prime_power(n):
|
391
|
+
F = list(GF(n))
|
392
|
+
|
393
|
+
# We need the first element of the list to be 0
|
394
|
+
assert F[0] == 0
|
395
|
+
|
396
|
+
# This dictionary is used to convert from field elements to integers
|
397
|
+
conv = {F[i] : i for i in range(n)}
|
398
|
+
|
399
|
+
# Make the matrices
|
400
|
+
matrices = [Matrix([[conv[F[i] + F[r]*F[j]] for i in range(n)]
|
401
|
+
for j in range(n)]) for r in range(1, k+1)]
|
402
|
+
|
403
|
+
elif orthogonal_array(k + 2, n, existence=True) is not Unknown:
|
404
|
+
# Forwarding non-existence results
|
405
|
+
if orthogonal_array(k + 2, n, existence=True):
|
406
|
+
pass
|
407
|
+
else:
|
408
|
+
raise EmptySetError("there does not exist {} MOLS of order {}!".format(k, n))
|
409
|
+
|
410
|
+
# make sure that the first two columns are "11, 12, ..., 1n, 21, 22, ..."
|
411
|
+
OA = sorted(orthogonal_array(k + 2, n, check=False))
|
412
|
+
|
413
|
+
# We first define matrices as lists of n^2 values
|
414
|
+
matrices = [[] for _ in repeat(None, k)]
|
415
|
+
for L in OA:
|
416
|
+
for i in range(2, k + 2):
|
417
|
+
matrices[i-2].append(L[i])
|
418
|
+
|
419
|
+
# The real matrices
|
420
|
+
matrices = [[M[i*n:(i+1)*n] for i in range(n)] for M in matrices]
|
421
|
+
matrices = [Matrix(M) for M in matrices]
|
422
|
+
|
423
|
+
else:
|
424
|
+
raise NotImplementedError("I don't know how to build {} MOLS of order {}".format(k, n))
|
425
|
+
|
426
|
+
if check:
|
427
|
+
assert are_mutually_orthogonal_latin_squares(matrices)
|
428
|
+
|
429
|
+
# partitions have been requested but have not been computed yet
|
430
|
+
if partitions is True:
|
431
|
+
partitions = [[[i*n+j for j in range(n)] for i in range(n)],
|
432
|
+
[[j*n+i for j in range(n)] for i in range(n)]]
|
433
|
+
for m in matrices:
|
434
|
+
partition = [[] for _ in repeat(None, n)]
|
435
|
+
for i in range(n):
|
436
|
+
for j in range(n):
|
437
|
+
partition[m[i,j]].append(i*n+j)
|
438
|
+
partitions.append(partition)
|
439
|
+
|
440
|
+
if partitions:
|
441
|
+
return partitions
|
442
|
+
else:
|
443
|
+
return matrices
|
444
|
+
|
445
|
+
|
446
|
+
def latin_square_product(M, N, *others):
|
447
|
+
r"""
|
448
|
+
Return the product of two (or more) latin squares.
|
449
|
+
|
450
|
+
Given two Latin Squares `M,N` of respective sizes `m,n`, the direct product
|
451
|
+
`M\times N` of size `mn` is defined by `(M\times
|
452
|
+
N)((i_1,i_2),(j_1,j_2))=(M(i_1,j_1),N(i_2,j_2))` where `i_1,j_1\in [m],
|
453
|
+
i_2,j_2\in [n]`
|
454
|
+
|
455
|
+
Each pair of values `(i,j)\in [m]\times [n]` is then relabeled to `in+j`.
|
456
|
+
|
457
|
+
This is Lemma 6.25 of [Stinson2004]_.
|
458
|
+
|
459
|
+
INPUT:
|
460
|
+
|
461
|
+
- ``M``, ``N``, ``*others`` -- an arbitrary number of latin squares
|
462
|
+
(greater than or equal to 2)
|
463
|
+
|
464
|
+
EXAMPLES::
|
465
|
+
|
466
|
+
sage: from sage.combinat.designs.latin_squares import latin_square_product
|
467
|
+
sage: m=designs.mutually_orthogonal_latin_squares(3,4)[0] # needs sage.schemes
|
468
|
+
sage: latin_square_product(m,m,m) # needs sage.schemes
|
469
|
+
64 x 64 sparse matrix over Integer Ring (use the '.str()' method to see the entries)
|
470
|
+
"""
|
471
|
+
from sage.matrix.constructor import Matrix
|
472
|
+
m = M.nrows()
|
473
|
+
n = N.nrows()
|
474
|
+
|
475
|
+
D = {((i,j),(ii,jj)):(M[i,ii],N[j,jj])
|
476
|
+
for i in range(m)
|
477
|
+
for ii in range(m)
|
478
|
+
for j in range(n)
|
479
|
+
for jj in range(n)}
|
480
|
+
|
481
|
+
L = lambda i_j: i_j[0] * n + i_j[1]
|
482
|
+
D = {(L(c[0]), L(c[1])): L(v) for c, v in D.items()}
|
483
|
+
P = Matrix(D)
|
484
|
+
|
485
|
+
if others:
|
486
|
+
return latin_square_product(P, others[0], *others[1:])
|
487
|
+
else:
|
488
|
+
return P
|
489
|
+
|
490
|
+
|
491
|
+
def MOLS_table(start, stop=None, compare=False, width=None):
|
492
|
+
r"""
|
493
|
+
Print the MOLS table that Sage can produce.
|
494
|
+
|
495
|
+
INPUT:
|
496
|
+
|
497
|
+
- ``start``, ``stop`` -- integers; print the table of MOLS for value of
|
498
|
+
`n` such that ``start<=n<stop``. If only one integer is given as input,
|
499
|
+
it is interpreted as the value of ``stop`` with ``start=0`` (same
|
500
|
+
behaviour as ``range``).
|
501
|
+
|
502
|
+
- ``compare`` -- boolean; if sets to ``True`` the MOLS displays
|
503
|
+
with `+` and `-` entries its difference with the table from the
|
504
|
+
Handbook of Combinatorial Designs (2ed).
|
505
|
+
|
506
|
+
- ``width`` -- integer; the width of each column of the table. By default,
|
507
|
+
it is computed from range of values determined by the parameters ``start``
|
508
|
+
and ``stop``.
|
509
|
+
|
510
|
+
EXAMPLES::
|
511
|
+
|
512
|
+
sage: # needs sage.schemes
|
513
|
+
sage: from sage.combinat.designs.latin_squares import MOLS_table
|
514
|
+
sage: MOLS_table(100)
|
515
|
+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
516
|
+
________________________________________________________________________________
|
517
|
+
0| +oo +oo 1 2 3 4 1 6 7 8 2 10 5 12 4 4 15 16 5 18
|
518
|
+
20| 4 5 3 22 7 24 4 26 5 28 4 30 31 5 4 5 8 36 4 5
|
519
|
+
40| 7 40 5 42 5 6 4 46 8 48 6 5 5 52 5 6 7 7 5 58
|
520
|
+
60| 5 60 5 6 63 7 5 66 5 6 6 70 7 72 5 7 6 6 6 78
|
521
|
+
80| 9 80 8 82 6 6 6 6 7 88 6 7 6 6 6 6 7 96 6 8
|
522
|
+
sage: MOLS_table(100, width=4)
|
523
|
+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
524
|
+
____________________________________________________________________________________________________
|
525
|
+
0| +oo +oo 1 2 3 4 1 6 7 8 2 10 5 12 4 4 15 16 5 18
|
526
|
+
20| 4 5 3 22 7 24 4 26 5 28 4 30 31 5 4 5 8 36 4 5
|
527
|
+
40| 7 40 5 42 5 6 4 46 8 48 6 5 5 52 5 6 7 7 5 58
|
528
|
+
60| 5 60 5 6 63 7 5 66 5 6 6 70 7 72 5 7 6 6 6 78
|
529
|
+
80| 9 80 8 82 6 6 6 6 7 88 6 7 6 6 6 6 7 96 6 8
|
530
|
+
sage: MOLS_table(100, compare=True)
|
531
|
+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
532
|
+
________________________________________________________________________________
|
533
|
+
0| + +
|
534
|
+
20|
|
535
|
+
40|
|
536
|
+
60|
|
537
|
+
80|
|
538
|
+
sage: MOLS_table(50, 100, compare=True)
|
539
|
+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
540
|
+
________________________________________________________________________________
|
541
|
+
40|
|
542
|
+
60|
|
543
|
+
80|
|
544
|
+
"""
|
545
|
+
from .orthogonal_arrays import largest_available_k
|
546
|
+
if stop is None:
|
547
|
+
start,stop = 0,start
|
548
|
+
# make start and stop be congruent to 0 mod 20
|
549
|
+
start = start - (start % 20)
|
550
|
+
stop = stop-1
|
551
|
+
stop = stop + (20-(stop % 20))
|
552
|
+
assert start % 20 == 0 and stop % 20 == 0
|
553
|
+
if stop <= start:
|
554
|
+
return
|
555
|
+
|
556
|
+
# choose an appropriate width (needs to be >= 3 because "+oo" should fit)
|
557
|
+
if width is None:
|
558
|
+
width = max(3, Integer(stop-1).ndigits(10))
|
559
|
+
|
560
|
+
print(" " * (width + 2) + " ".join("{i:>{width}}".format(i=i,width=width)
|
561
|
+
for i in range(20)))
|
562
|
+
print(" " * (width + 1) + "_" * ((width + 1) * 20), end="")
|
563
|
+
for i in range(start,stop):
|
564
|
+
if i % 20 == 0:
|
565
|
+
print("\n{:>{width}}|".format(i, width=width), end="")
|
566
|
+
k = largest_available_k(i)-2
|
567
|
+
if compare:
|
568
|
+
from . import MOLS_handbook_data
|
569
|
+
lower_bound = MOLS_handbook_data.lower_bound(i)
|
570
|
+
if i < 2 or lower_bound == k:
|
571
|
+
c = ""
|
572
|
+
elif lower_bound < k:
|
573
|
+
c = "+"
|
574
|
+
else:
|
575
|
+
c = "-"
|
576
|
+
else:
|
577
|
+
if i < 2:
|
578
|
+
c = "+oo"
|
579
|
+
else:
|
580
|
+
c = k
|
581
|
+
print(' {:>{width}}'.format(c, width=width), end="")
|