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,3340 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-graphs
|
2
|
+
r"""
|
3
|
+
Database of strongly regular graphs
|
4
|
+
|
5
|
+
This module manages a database associating to a set of four integers
|
6
|
+
`(v,k,\lambda,\mu)` a strongly regular graphs with these parameters, when one
|
7
|
+
exists.
|
8
|
+
|
9
|
+
Using Andries Brouwer's `database of strongly regular graphs
|
10
|
+
<https://www.win.tue.nl/~aeb/graphs/srg/srgtab.html>`__, it can also return
|
11
|
+
non-existence results. Note that some constructions are missing, and that some
|
12
|
+
strongly regular graphs that exist in the database cannot be automatically built
|
13
|
+
by Sage. Help us if you know any.
|
14
|
+
An outline of the implementation can be found in [CP2016]_.
|
15
|
+
|
16
|
+
.. NOTE::
|
17
|
+
|
18
|
+
Any missing/incorrect information in the database must be reported to
|
19
|
+
`Andries E. Brouwer <https://www.win.tue.nl/~aeb/>`__ directly, in order to
|
20
|
+
have a unique and updated source of information.
|
21
|
+
|
22
|
+
REFERENCES:
|
23
|
+
|
24
|
+
[BL1984]_
|
25
|
+
|
26
|
+
Functions
|
27
|
+
---------
|
28
|
+
"""
|
29
|
+
|
30
|
+
import json
|
31
|
+
import os
|
32
|
+
|
33
|
+
from libc.math cimport sqrt, floor
|
34
|
+
from libc.stdint cimport uint_fast32_t
|
35
|
+
|
36
|
+
from sage.arith.misc import divisors, is_prime_power, is_square
|
37
|
+
from sage.categories.sets_cat import EmptySetError
|
38
|
+
from sage.graphs.graph import Graph
|
39
|
+
from sage.misc.cachefunc import cached_function
|
40
|
+
from sage.misc.lazy_import import LazyImport
|
41
|
+
from sage.misc.unknown import Unknown
|
42
|
+
from sage.rings.sum_of_squares cimport two_squares_c
|
43
|
+
|
44
|
+
orthogonal_array = LazyImport('sage.combinat.designs.orthogonal_arrays', 'orthogonal_array')
|
45
|
+
balanced_incomplete_block_design = LazyImport('sage.combinat.designs.bibd', 'balanced_incomplete_block_design')
|
46
|
+
GF = LazyImport('sage.rings.finite_rings.finite_field_constructor', 'GF')
|
47
|
+
Matrix = LazyImport('sage.matrix.constructor', 'Matrix')
|
48
|
+
LinearCode = LazyImport('sage.coding.linear_code', 'LinearCode')
|
49
|
+
|
50
|
+
cdef dict _brouwer_database = None
|
51
|
+
_small_srg_database = None
|
52
|
+
|
53
|
+
|
54
|
+
@cached_function
|
55
|
+
def is_paley(int v, int k, int l, int mu):
|
56
|
+
r"""
|
57
|
+
Test whether some Paley graph is `(v,k,\lambda,\mu)`-strongly regular.
|
58
|
+
|
59
|
+
INPUT:
|
60
|
+
|
61
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
62
|
+
|
63
|
+
OUTPUT:
|
64
|
+
|
65
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
66
|
+
exists, and ``None`` otherwise.
|
67
|
+
|
68
|
+
EXAMPLES::
|
69
|
+
|
70
|
+
sage: from sage.graphs.strongly_regular_db import is_paley
|
71
|
+
sage: t = is_paley(13,6,2,3); t
|
72
|
+
(..., 13)
|
73
|
+
sage: g = t[0](*t[1:]); g # needs sage.rings.finite_rings
|
74
|
+
Paley graph with parameter 13: Graph on 13 vertices
|
75
|
+
sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings
|
76
|
+
(13, 6, 2, 3)
|
77
|
+
sage: t = is_paley(5,5,5,5); t
|
78
|
+
"""
|
79
|
+
if (v % 4 == 1 and is_prime_power(v) and
|
80
|
+
k == (v - 1)//2 and
|
81
|
+
l == (v - 5)//4 and
|
82
|
+
mu == (v - 1)//4):
|
83
|
+
from sage.graphs.generators.families import PaleyGraph
|
84
|
+
return (PaleyGraph, v)
|
85
|
+
|
86
|
+
|
87
|
+
@cached_function
|
88
|
+
def is_mathon_PC_srg(int v, int k, int l, int mu):
|
89
|
+
r"""
|
90
|
+
Test whether some Mathon's Pseudocyclic s.r.g. is `(v,k,\lambda,\mu)`-strongly regular.
|
91
|
+
|
92
|
+
INPUT:
|
93
|
+
|
94
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
95
|
+
|
96
|
+
OUTPUT:
|
97
|
+
|
98
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
99
|
+
exists, and ``None`` otherwise.
|
100
|
+
|
101
|
+
.. TODO::
|
102
|
+
|
103
|
+
The current implementation only gives a subset of all possible graphs that can be
|
104
|
+
obtained using this construction. A full implementation should rely on a database
|
105
|
+
of conference matrices (or, equivalently, on a database of s.r.g.'s with parameters
|
106
|
+
`(4t+1,2t,t-1,t)`. Currently we make an extra assumption that `4t+1` is a prime power.
|
107
|
+
The first case where we miss a construction is `t=11`, where we could (recursively)
|
108
|
+
use the graph for `t=1` to construct a graph on 83205 vertices.
|
109
|
+
|
110
|
+
EXAMPLES::
|
111
|
+
|
112
|
+
sage: from sage.graphs.strongly_regular_db import is_mathon_PC_srg
|
113
|
+
sage: t = is_mathon_PC_srg(45,22,10,11); t # needs sage.libs.pari
|
114
|
+
(..., 1)
|
115
|
+
sage: g = t[0](*t[1:]); g # needs database_graphs sage.libs.pari
|
116
|
+
Mathon's PC SRG on 45 vertices: Graph on 45 vertices
|
117
|
+
sage: g.is_strongly_regular(parameters=True) # needs database_graphs sage.libs.pari
|
118
|
+
(45, 22, 10, 11)
|
119
|
+
|
120
|
+
TESTS::
|
121
|
+
|
122
|
+
sage: t = is_mathon_PC_srg(5,5,5,5); t # needs sage.libs.pari
|
123
|
+
sage: mu = 1895 # t=5 case -- the construction cannot work # needs sage.libs.pari
|
124
|
+
sage: t = is_mathon_PC_srg(4*mu+1,2*mu,mu-1,mu); t # needs sage.libs.pari
|
125
|
+
"""
|
126
|
+
cdef int t
|
127
|
+
if (v % 4 == 1 and
|
128
|
+
k == (v - 1)//2 and
|
129
|
+
l == (v - 5)//4 and
|
130
|
+
mu == (v - 1)//4):
|
131
|
+
from sage.rings.integer_ring import ZZ
|
132
|
+
K = ZZ['x']
|
133
|
+
x = K.gen()
|
134
|
+
rpoly = (w for w in (x*(4*x*(4*x - 1) - 1) - mu).roots() if w[0] > 0)
|
135
|
+
try:
|
136
|
+
t = next(rpoly)[0]
|
137
|
+
if (is_prime_power(4*t - 1) and
|
138
|
+
is_prime_power(4*t + 1)): # extra assumption in TODO!
|
139
|
+
from sage.graphs.generators.families import \
|
140
|
+
MathonPseudocyclicStronglyRegularGraph
|
141
|
+
return (MathonPseudocyclicStronglyRegularGraph, t)
|
142
|
+
except StopIteration:
|
143
|
+
pass
|
144
|
+
|
145
|
+
|
146
|
+
@cached_function
|
147
|
+
def is_muzychuk_S6(int v, int k, int l, int mu):
|
148
|
+
r"""
|
149
|
+
Test whether some Muzychuk S6 graph is (v, k, l, mu)-strongly regular.
|
150
|
+
|
151
|
+
Tests whether a :func:`~sage.graphs.graph_generators.GraphGenerators.MuzychukS6Graph`
|
152
|
+
has parameters (v, k, l, mu).
|
153
|
+
|
154
|
+
INPUT:
|
155
|
+
|
156
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
157
|
+
|
158
|
+
OUTPUT:
|
159
|
+
|
160
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the required graph if it exists,
|
161
|
+
and ``None`` otherwise.
|
162
|
+
|
163
|
+
EXAMPLES::
|
164
|
+
|
165
|
+
sage: # needs sage.libs.pari
|
166
|
+
sage: from sage.graphs.strongly_regular_db import is_muzychuk_S6
|
167
|
+
sage: t = is_muzychuk_S6(378, 116, 34, 36)
|
168
|
+
sage: G = t[0](*t[1:]); G
|
169
|
+
Muzychuk S6 graph with parameters (3,3): Graph on 378 vertices
|
170
|
+
sage: G.is_strongly_regular(parameters=True)
|
171
|
+
(378, 116, 34, 36)
|
172
|
+
sage: t = is_muzychuk_S6(5, 5, 5, 5); t
|
173
|
+
"""
|
174
|
+
cdef int n, d
|
175
|
+
from sage.rings.integer_ring import ZZ
|
176
|
+
n_list = [n for n in range(l - 1) if ZZ(n).is_prime_power()]
|
177
|
+
for n in n_list:
|
178
|
+
d = 2
|
179
|
+
while n**d * ((n**d - 1)//(n - 1) + 1) <= v:
|
180
|
+
if (v == n**d * ((n**d - 1)//(n - 1) + 1) and
|
181
|
+
k == n**(d - 1)*(n**d - 1)//(n - 1) - 1 and
|
182
|
+
l == mu - 2 and
|
183
|
+
mu == n**(d - 1) * (n**(d - 1) - 1)//(n - 1)):
|
184
|
+
from sage.graphs.generators.families import MuzychukS6Graph
|
185
|
+
return (MuzychukS6Graph, n, d)
|
186
|
+
d += 1
|
187
|
+
|
188
|
+
|
189
|
+
@cached_function
|
190
|
+
def is_orthogonal_array_block_graph(int v, int k, int l, int mu):
|
191
|
+
r"""
|
192
|
+
Test whether some (pseudo)Orthogonal Array graph is `(v,k,\lambda,\mu)`-strongly regular.
|
193
|
+
|
194
|
+
We know how to construct graphs with parameters of an Orthogonal Array (`OA(m,n)`),
|
195
|
+
also known as Latin squares graphs `L_m(n)`, in several cases where no orthogonal
|
196
|
+
array is known, or even in some cases for which they are known not to exist.
|
197
|
+
|
198
|
+
Such graphs are usually called pseudo-Latin squares graphs. Namely, Sage
|
199
|
+
can construct a graph with parameters of an `OA(m,n)`-graph whenever there
|
200
|
+
exists a skew-Hadamard matrix of order `n+1`, and `m=(n+1)/2` or
|
201
|
+
`m=(n-1)/2`. The construction in the former case is due to Goethals-Seidel
|
202
|
+
[BL1984]_, and in the latter case due to Pasechnik [Pas1992]_.
|
203
|
+
|
204
|
+
INPUT:
|
205
|
+
|
206
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
207
|
+
|
208
|
+
OUTPUT:
|
209
|
+
|
210
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
211
|
+
exists, and ``None`` otherwise.
|
212
|
+
|
213
|
+
EXAMPLES::
|
214
|
+
|
215
|
+
sage: # needs sage.combinat sage.modules
|
216
|
+
sage: from sage.graphs.strongly_regular_db import is_orthogonal_array_block_graph
|
217
|
+
sage: t = is_orthogonal_array_block_graph(64, 35, 18, 20); t
|
218
|
+
(..., 5, 8)
|
219
|
+
sage: g = t[0](*t[1:]); g
|
220
|
+
OA(5,8): Graph on 64 vertices
|
221
|
+
sage: g.is_strongly_regular(parameters=True)
|
222
|
+
(64, 35, 18, 20)
|
223
|
+
sage: t = is_orthogonal_array_block_graph(225,98,43,42); t
|
224
|
+
(..., 4)
|
225
|
+
sage: g = t[0](*t[1:]); g
|
226
|
+
Pasechnik Graph_4: Graph on 225 vertices
|
227
|
+
sage: g.is_strongly_regular(parameters=True)
|
228
|
+
(225, 98, 43, 42)
|
229
|
+
sage: t = is_orthogonal_array_block_graph(225,112,55,56); t
|
230
|
+
(..., 4)
|
231
|
+
sage: g = t[0](*t[1:]); g
|
232
|
+
skewhad^2_4: Graph on 225 vertices
|
233
|
+
sage: g.is_strongly_regular(parameters=True)
|
234
|
+
(225, 112, 55, 56)
|
235
|
+
|
236
|
+
sage: t = is_orthogonal_array_block_graph(5,5,5,5); t # needs sage.combinat sage.modules
|
237
|
+
"""
|
238
|
+
# notations from
|
239
|
+
# https://www.win.tue.nl/~aeb/graphs/OA.html
|
240
|
+
from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix
|
241
|
+
try:
|
242
|
+
m, n = latin_squares_graph_parameters(v, k, l, mu)
|
243
|
+
except Exception:
|
244
|
+
return
|
245
|
+
if orthogonal_array(m, n, existence=True) is True:
|
246
|
+
from sage.graphs.generators.intersection import OrthogonalArrayBlockGraph
|
247
|
+
return (lambda m, n: OrthogonalArrayBlockGraph(m, n), m, n)
|
248
|
+
|
249
|
+
elif n > 2 and skew_hadamard_matrix(n+1, existence=True) is True:
|
250
|
+
if m == (n + 1)/2:
|
251
|
+
from sage.graphs.generators.families import SquaredSkewHadamardMatrixGraph as G
|
252
|
+
elif m == (n - 1)//2:
|
253
|
+
from sage.graphs.generators.families import PasechnikGraph as G
|
254
|
+
else:
|
255
|
+
return
|
256
|
+
return (G, (n+1)//4)
|
257
|
+
|
258
|
+
|
259
|
+
@cached_function
|
260
|
+
def is_johnson(int v, int k, int l, int mu):
|
261
|
+
r"""
|
262
|
+
Test whether some Johnson graph is `(v,k,\lambda,\mu)`-strongly regular.
|
263
|
+
|
264
|
+
INPUT:
|
265
|
+
|
266
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
267
|
+
|
268
|
+
OUTPUT:
|
269
|
+
|
270
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
271
|
+
exists, and ``None`` otherwise.
|
272
|
+
|
273
|
+
EXAMPLES::
|
274
|
+
|
275
|
+
sage: from sage.graphs.strongly_regular_db import is_johnson
|
276
|
+
sage: t = is_johnson(10,6,3,4); t
|
277
|
+
(..., 5)
|
278
|
+
sage: g = t[0](*t[1:]); g
|
279
|
+
Johnson graph with parameters 5,2: Graph on 10 vertices
|
280
|
+
sage: g.is_strongly_regular(parameters=True)
|
281
|
+
(10, 6, 3, 4)
|
282
|
+
|
283
|
+
sage: t = is_johnson(5,5,5,5); t
|
284
|
+
"""
|
285
|
+
# Using notations of https://www.win.tue.nl/~aeb/graphs/Johnson.html
|
286
|
+
#
|
287
|
+
# J(n,m) has parameters v = m(m – 1)/2, k = 2(m – 2), λ = m – 2, μ = 4.
|
288
|
+
m = l + 2
|
289
|
+
if (mu == 4 and
|
290
|
+
k == 2*(m - 2) and
|
291
|
+
v == m*(m - 1)//2):
|
292
|
+
from sage.graphs.generators.families import JohnsonGraph
|
293
|
+
return (lambda m: JohnsonGraph(m, 2), m)
|
294
|
+
|
295
|
+
|
296
|
+
@cached_function
|
297
|
+
def is_steiner(int v, int k, int l, int mu):
|
298
|
+
r"""
|
299
|
+
Test whether some Steiner graph is `(v,k,\lambda,\mu)`-strongly regular.
|
300
|
+
|
301
|
+
A Steiner graph is the intersection graph of a Steiner set system. For more
|
302
|
+
information, see https://www.win.tue.nl/~aeb/graphs/S.html.
|
303
|
+
|
304
|
+
INPUT:
|
305
|
+
|
306
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
307
|
+
|
308
|
+
OUTPUT:
|
309
|
+
|
310
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
311
|
+
exists, and ``None`` otherwise.
|
312
|
+
|
313
|
+
EXAMPLES::
|
314
|
+
|
315
|
+
sage: from sage.graphs.strongly_regular_db import is_steiner
|
316
|
+
sage: t = is_steiner(26,15,8,9); t
|
317
|
+
(..., 13, 3)
|
318
|
+
sage: g = t[0](*t[1:]); g
|
319
|
+
Intersection Graph: Graph on 26 vertices
|
320
|
+
sage: g.is_strongly_regular(parameters=True)
|
321
|
+
(26, 15, 8, 9)
|
322
|
+
|
323
|
+
sage: t = is_steiner(5,5,5,5); t
|
324
|
+
"""
|
325
|
+
# Using notations from https://www.win.tue.nl/~aeb/graphs/S.html
|
326
|
+
#
|
327
|
+
# The block graph of a Steiner 2-design S(2,m,n) has parameters:
|
328
|
+
# v = n(n-1)/m(m-1), k = m(n-m)/(m-1), λ = (m-1)^2 + (n-1)/(m–1)–2, μ = m^2.
|
329
|
+
if mu <= 1 or not is_square(mu):
|
330
|
+
return
|
331
|
+
m = int(sqrt(mu))
|
332
|
+
n = (k*(m - 1))//m + m
|
333
|
+
|
334
|
+
if (v == (n*(n - 1))/(m*(m - 1)) and
|
335
|
+
k == m*(n - m)/(m - 1) and
|
336
|
+
l == (m - 1)**2 + (n - 1)/(m - 1) - 2 and
|
337
|
+
balanced_incomplete_block_design(n, m, existence=True) is True):
|
338
|
+
from sage.graphs.generators.intersection import IntersectionGraph
|
339
|
+
return (lambda n, m: IntersectionGraph([frozenset(b) for b in balanced_incomplete_block_design(n, m)]), n, m)
|
340
|
+
|
341
|
+
|
342
|
+
@cached_function
|
343
|
+
def is_affine_polar(int v, int k, int l, int mu):
|
344
|
+
r"""
|
345
|
+
Test whether some Affine Polar graph is `(v,k,\lambda,\mu)`-strongly regular.
|
346
|
+
|
347
|
+
For more information, see https://www.win.tue.nl/~aeb/graphs/VO.html.
|
348
|
+
|
349
|
+
INPUT:
|
350
|
+
|
351
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
352
|
+
|
353
|
+
OUTPUT:
|
354
|
+
|
355
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
356
|
+
exists, and ``None`` otherwise.
|
357
|
+
|
358
|
+
EXAMPLES::
|
359
|
+
|
360
|
+
sage: from sage.graphs.strongly_regular_db import is_affine_polar
|
361
|
+
sage: t = is_affine_polar(81,32,13,12); t # needs sage.rings.finite_rings
|
362
|
+
(..., 4, 3)
|
363
|
+
sage: g = t[0](*t[1:]); g # needs sage.libs.gap sage.rings.finite_rings
|
364
|
+
Affine Polar Graph VO^+(4,3): Graph on 81 vertices
|
365
|
+
sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap sage.rings.finite_rings
|
366
|
+
(81, 32, 13, 12)
|
367
|
+
|
368
|
+
sage: t = is_affine_polar(5,5,5,5); t
|
369
|
+
"""
|
370
|
+
# Using notations from https://www.win.tue.nl/~aeb/graphs/VO.html
|
371
|
+
#
|
372
|
+
# VO+(2e,q) has parameters: v = q^(2e), k = (q^(e−1) + 1)(q^e − 1), λ =
|
373
|
+
# q(q^(e−2) + 1)(q^(e−1) − 1) + q − 2, μ = q^(e−1)(q^(e−1) + 1)
|
374
|
+
#
|
375
|
+
# VO−(2e,q) has parameters v = q^(2e), k = (q^(e−1) - 1)(q^e + 1), λ =
|
376
|
+
# q(q^(e−2) - 1)(q^(e−1) + 1) + q − 2, μ = q^(e−1)(q^(e−1) - 1)
|
377
|
+
if not is_square(v) or not is_prime_power(v):
|
378
|
+
return
|
379
|
+
prime, power = is_prime_power(v, get_data=True)
|
380
|
+
if power % 2:
|
381
|
+
return
|
382
|
+
for e in divisors(power/2):
|
383
|
+
q = prime**(power//(2*e))
|
384
|
+
assert v == q**(2*e)
|
385
|
+
if (k == (q**(e - 1) + 1)*(q**e - 1) and
|
386
|
+
l == q*(q**(e - 2) + 1)*(q**(e - 1) - 1) + q - 2 and
|
387
|
+
mu == q**(e - 1)*(q**(e - 1) + 1)):
|
388
|
+
from sage.graphs.generators.classical_geometries import AffineOrthogonalPolarGraph
|
389
|
+
return (lambda d, q: AffineOrthogonalPolarGraph(d, q, sign='+'), 2*e, q)
|
390
|
+
if (k == (q**(e - 1) - 1)*(q**e + 1) and
|
391
|
+
l == q*(q**(e - 2) - 1)*(q**(e - 1) + 1) + q - 2 and
|
392
|
+
mu == q**(e - 1)*(q**(e - 1) - 1)):
|
393
|
+
from sage.graphs.generators.classical_geometries import AffineOrthogonalPolarGraph
|
394
|
+
return (lambda d, q: AffineOrthogonalPolarGraph(d, q, sign='-'), 2*e, q)
|
395
|
+
|
396
|
+
|
397
|
+
@cached_function
|
398
|
+
def is_orthogonal_polar(int v, int k, int l, int mu):
|
399
|
+
r"""
|
400
|
+
Test whether some Orthogonal Polar graph is `(v,k,\lambda,\mu)`-strongly regular.
|
401
|
+
|
402
|
+
For more information, see https://www.win.tue.nl/~aeb/graphs/srghub.html.
|
403
|
+
|
404
|
+
INPUT:
|
405
|
+
|
406
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
407
|
+
|
408
|
+
OUTPUT:
|
409
|
+
|
410
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
411
|
+
exists, and ``None`` otherwise.
|
412
|
+
|
413
|
+
EXAMPLES::
|
414
|
+
|
415
|
+
sage: from sage.graphs.strongly_regular_db import is_orthogonal_polar
|
416
|
+
sage: t = is_orthogonal_polar(85, 20, 3, 5); t
|
417
|
+
(<function OrthogonalPolarGraph at ...>, 5, 4, '')
|
418
|
+
sage: g = t[0](*t[1:]); g # needs sage.libs.gap sage.rings.finite_rings
|
419
|
+
Orthogonal Polar Graph O(5, 4): Graph on 85 vertices
|
420
|
+
sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap sage.rings.finite_rings
|
421
|
+
(85, 20, 3, 5)
|
422
|
+
|
423
|
+
sage: t = is_orthogonal_polar(5,5,5,5); t # needs sage.rings.finite_rings
|
424
|
+
|
425
|
+
TESTS:
|
426
|
+
|
427
|
+
All of ``O(2m+1,q)``, ``O^+(2m,q)`` and ``O^-(2m,q)`` appear::
|
428
|
+
|
429
|
+
sage: is_orthogonal_polar(85, 20, 3, 5)
|
430
|
+
(<function OrthogonalPolarGraph at ...>, 5, 4, '')
|
431
|
+
sage: is_orthogonal_polar(119,54,21,27)
|
432
|
+
(<function OrthogonalPolarGraph at ...>, 8, 2, '-')
|
433
|
+
sage: is_orthogonal_polar(130,48,20,16) # needs sage.rings.finite_rings
|
434
|
+
(<function OrthogonalPolarGraph at ...>, 6, 3, '+')
|
435
|
+
"""
|
436
|
+
r, s = eigenvalues(v, k, l, mu)
|
437
|
+
if r is None:
|
438
|
+
return
|
439
|
+
q_pow_m_minus_one = -s-1 if abs(s) > r else r+1
|
440
|
+
|
441
|
+
if is_prime_power(q_pow_m_minus_one):
|
442
|
+
prime, power = is_prime_power(q_pow_m_minus_one, get_data=True)
|
443
|
+
for d in divisors(power):
|
444
|
+
q = prime**d
|
445
|
+
m = (power//d) + 1
|
446
|
+
|
447
|
+
# O(2m+1,q)
|
448
|
+
if (v == (q**(2*m) - 1)//(q - 1) and
|
449
|
+
k == q*(q**(2*m - 2) - 1)//(q - 1) and
|
450
|
+
l == q**2*(q**(2*m - 4) - 1)//(q - 1) + q - 1 and
|
451
|
+
mu == (q**(2*m - 2) - 1)//(q - 1)):
|
452
|
+
from sage.graphs.generators.classical_geometries import OrthogonalPolarGraph
|
453
|
+
return (OrthogonalPolarGraph, 2*m+1, q, "")
|
454
|
+
|
455
|
+
# O^+(2m,q)
|
456
|
+
if (v == (q**(2*m - 1) - 1)//(q - 1) + q**(m - 1) and
|
457
|
+
k == q*(q**(2*m - 3) - 1)//(q - 1) + q**(m - 1) and
|
458
|
+
k == q**(2*m - 3) + l + 1 and
|
459
|
+
mu == k//q):
|
460
|
+
from sage.graphs.generators.classical_geometries import OrthogonalPolarGraph
|
461
|
+
return (OrthogonalPolarGraph, 2*m, q, "+")
|
462
|
+
|
463
|
+
# O^+(2m+1,q)
|
464
|
+
if (v == (q**(2*m - 1) - 1)//(q - 1) - q**(m - 1) and
|
465
|
+
k == q*(q**(2*m - 3) - 1)//(q - 1) - q**(m - 1) and
|
466
|
+
k == q**(2*m - 3) + l + 1 and
|
467
|
+
mu == k//q):
|
468
|
+
from sage.graphs.generators.classical_geometries import OrthogonalPolarGraph
|
469
|
+
return (OrthogonalPolarGraph, 2*m, q, "-")
|
470
|
+
|
471
|
+
|
472
|
+
@cached_function
|
473
|
+
def is_goethals_seidel(int v, int k, int l, int mu):
|
474
|
+
r"""
|
475
|
+
Test whether some
|
476
|
+
:func:`~sage.graphs.graph_generators.GraphGenerators.GoethalsSeidelGraph` graph is
|
477
|
+
`(v,k,\lambda,\mu)`-strongly regular.
|
478
|
+
|
479
|
+
INPUT:
|
480
|
+
|
481
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
482
|
+
|
483
|
+
OUTPUT:
|
484
|
+
|
485
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
486
|
+
exists, and ``None`` otherwise.
|
487
|
+
|
488
|
+
EXAMPLES::
|
489
|
+
|
490
|
+
sage: from sage.graphs.strongly_regular_db import is_goethals_seidel
|
491
|
+
sage: t = is_goethals_seidel(28, 15, 6, 10); t # needs sage.combinat sage.modules
|
492
|
+
[<function GoethalsSeidelGraph at ...>, 3, 3]
|
493
|
+
sage: g = t[0](*t[1:]); g # needs sage.combinat sage.modules
|
494
|
+
Graph on 28 vertices
|
495
|
+
sage: g.is_strongly_regular(parameters=True) # needs sage.combinat sage.modules
|
496
|
+
(28, 15, 6, 10)
|
497
|
+
|
498
|
+
sage: t = is_goethals_seidel(256, 135, 70, 72); t # needs sage.combinat sage.modules
|
499
|
+
[<function GoethalsSeidelGraph at ...>, 2, 15]
|
500
|
+
sage: g = t[0](*t[1:]); g # needs sage.combinat sage.modules
|
501
|
+
Graph on 256 vertices
|
502
|
+
sage: g.is_strongly_regular(parameters=True) # needs sage.combinat sage.modules
|
503
|
+
(256, 135, 70, 72)
|
504
|
+
|
505
|
+
sage: t = is_goethals_seidel(5,5,5,5); t # needs sage.combinat sage.modules
|
506
|
+
|
507
|
+
TESTS::
|
508
|
+
|
509
|
+
sage: for p in [(16, 9, 4, 6), (28, 15, 6, 10), # needs sage.combinat sage.modules
|
510
|
+
....: (64, 35, 18, 20), (120, 63, 30, 36),
|
511
|
+
....: (144, 77, 40, 42), (256, 135, 70, 72), (400, 209, 108, 110),
|
512
|
+
....: (496, 255, 126, 136), (540, 275, 130, 150), (576, 299, 154, 156),
|
513
|
+
....: (780, 399, 198, 210), (784, 405, 208, 210), (976, 495, 238, 264)]:
|
514
|
+
....: print(is_goethals_seidel(*p))
|
515
|
+
[<function GoethalsSeidelGraph at ...>, 2, 3]
|
516
|
+
[<function GoethalsSeidelGraph at ...>, 3, 3]
|
517
|
+
[<function GoethalsSeidelGraph at ...>, 2, 7]
|
518
|
+
[<function GoethalsSeidelGraph at ...>, 3, 7]
|
519
|
+
[<function GoethalsSeidelGraph at ...>, 2, 11]
|
520
|
+
[<function GoethalsSeidelGraph at ...>, 2, 15]
|
521
|
+
[<function GoethalsSeidelGraph at ...>, 2, 19]
|
522
|
+
[<function GoethalsSeidelGraph at ...>, 3, 15]
|
523
|
+
[<function GoethalsSeidelGraph at ...>, 5, 11]
|
524
|
+
[<function GoethalsSeidelGraph at ...>, 2, 23]
|
525
|
+
[<function GoethalsSeidelGraph at ...>, 3, 19]
|
526
|
+
[<function GoethalsSeidelGraph at ...>, 2, 27]
|
527
|
+
[<function GoethalsSeidelGraph at ...>, 5, 15]
|
528
|
+
"""
|
529
|
+
from sage.combinat.designs.bibd import balanced_incomplete_block_design
|
530
|
+
from sage.combinat.matrices.hadamard_matrix import hadamard_matrix
|
531
|
+
|
532
|
+
# here we guess the parameters v_bibd,k_bibd and r_bibd of the block design
|
533
|
+
#
|
534
|
+
# - the number of vertices v is equal to v_bibd*(r_bibd+1)
|
535
|
+
# - the degree k of the graph is equal to k=(v+r_bibd-1)/2
|
536
|
+
|
537
|
+
r_bibd = k - (v - 1 - k)
|
538
|
+
v_bibd = v//(r_bibd + 1)
|
539
|
+
k_bibd = (v_bibd - 1)//r_bibd + 1 if r_bibd > 0 else -1
|
540
|
+
|
541
|
+
if (v == v_bibd*(r_bibd + 1) and
|
542
|
+
2*k == v + r_bibd - 1 and
|
543
|
+
4*l == -2*v + 6*k - v_bibd - k_bibd and
|
544
|
+
hadamard_matrix(r_bibd + 1, existence=True) is True and
|
545
|
+
balanced_incomplete_block_design(v_bibd, k_bibd, existence=True) is True):
|
546
|
+
from sage.graphs.generators.families import GoethalsSeidelGraph
|
547
|
+
return [GoethalsSeidelGraph, k_bibd, r_bibd]
|
548
|
+
|
549
|
+
|
550
|
+
@cached_function
|
551
|
+
def is_NOodd(int v, int k, int l, int mu):
|
552
|
+
r"""
|
553
|
+
Test whether some NO^e(2n+1,q) graph is `(v,k,\lambda,\mu)`-strongly regular.
|
554
|
+
|
555
|
+
Here `q>2`, for in the case `q=2` this graph is complete. For more
|
556
|
+
information, see
|
557
|
+
:func:`sage.graphs.graph_generators.GraphGenerators.NonisotropicOrthogonalPolarGraph`
|
558
|
+
and Sect. 7.C of [BL1984]_.
|
559
|
+
|
560
|
+
INPUT:
|
561
|
+
|
562
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
563
|
+
|
564
|
+
OUTPUT:
|
565
|
+
|
566
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
567
|
+
exists, and ``None`` otherwise.
|
568
|
+
|
569
|
+
EXAMPLES::
|
570
|
+
|
571
|
+
sage: from sage.graphs.strongly_regular_db import is_NOodd
|
572
|
+
sage: t = is_NOodd(120, 51, 18, 24); t # needs sage.libs.pari
|
573
|
+
(<function NonisotropicOrthogonalPolarGraph at ...>, 5, 4, '-')
|
574
|
+
sage: g = t[0](*t[1:]); g # needs sage.libs.gap sage.libs.pari
|
575
|
+
NO^-(5, 4): Graph on 120 vertices
|
576
|
+
sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap sage.libs.pari
|
577
|
+
(120, 51, 18, 24)
|
578
|
+
|
579
|
+
TESTS:
|
580
|
+
|
581
|
+
All of ``NO^+(2m+1,q)`` and ``NO^-(2m+1,q)`` appear::
|
582
|
+
|
583
|
+
sage: # needs sage.libs.pari
|
584
|
+
sage: t = is_NOodd(120, 51, 18, 24); t
|
585
|
+
(<function NonisotropicOrthogonalPolarGraph at ...>, 5, 4, '-')
|
586
|
+
sage: t = is_NOodd(136, 75, 42, 40); t
|
587
|
+
(<function NonisotropicOrthogonalPolarGraph at ...>, 5, 4, '+')
|
588
|
+
sage: t = is_NOodd(378, 260, 178, 180); t
|
589
|
+
(<function NonisotropicOrthogonalPolarGraph at ...>, 7, 3, '+')
|
590
|
+
sage: t = is_NOodd(45, 32, 22, 24); t
|
591
|
+
(<function NonisotropicOrthogonalPolarGraph at ...>, 5, 3, '+')
|
592
|
+
sage: t = is_NOodd(351, 224, 142, 144); t
|
593
|
+
(<function NonisotropicOrthogonalPolarGraph at ...>, 7, 3, '-')
|
594
|
+
sage: t = is_NOodd(325, 144, 68, 60); t
|
595
|
+
(<function NonisotropicOrthogonalPolarGraph at ...>, 5, 5, '+')
|
596
|
+
sage: t = is_NOodd(300, 104, 28, 40); t
|
597
|
+
(<function NonisotropicOrthogonalPolarGraph at ...>, 5, 5, '-')
|
598
|
+
sage: t = is_NOodd(5,5,5,5); t
|
599
|
+
"""
|
600
|
+
cdef int n, q
|
601
|
+
r, s = eigenvalues(v, k, l, mu) # -eq^(n-1)-1 and eq^(n-1)(q-2)-1; q=3 is special case
|
602
|
+
if r is None:
|
603
|
+
return
|
604
|
+
r += 1
|
605
|
+
s += 1
|
606
|
+
if abs(r) > abs(s):
|
607
|
+
(r, s) = (s, r) # r=-eq^(n-1) s= eq^(n-1)(q-2)
|
608
|
+
q = 2 - s//r
|
609
|
+
p, t = is_prime_power(q, get_data=True)
|
610
|
+
pp, kk = is_prime_power(abs(r), get_data=True)
|
611
|
+
if p == pp and t:
|
612
|
+
n = kk//t + 1
|
613
|
+
e = 1 if v == (q**n)*(q**n + 1)//2 else -1
|
614
|
+
if (v == (q**n)*(q**n + e)//2 and
|
615
|
+
k == (q**n - e)*(q**(n - 1) + e) and
|
616
|
+
l == 2*(q**(2*n - 2) - 1) + e*q**(n - 1)*(q - 1) and
|
617
|
+
mu == 2*q**(n - 1)*(q**(n - 1) + e)):
|
618
|
+
from sage.graphs.generators.classical_geometries import NonisotropicOrthogonalPolarGraph
|
619
|
+
return (NonisotropicOrthogonalPolarGraph, 2*n + 1, q, '+' if e == 1 else '-')
|
620
|
+
|
621
|
+
|
622
|
+
@cached_function
|
623
|
+
def is_NOperp_F5(int v, int k, int l, int mu):
|
624
|
+
r"""
|
625
|
+
Test whether some NO^e,perp(2n+1,5) graph is `(v,k,\lambda,\mu)`-strongly regular.
|
626
|
+
|
627
|
+
For more information, see
|
628
|
+
:func:`sage.graphs.graph_generators.GraphGenerators.NonisotropicOrthogonalPolarGraph`
|
629
|
+
and Sect. 7.D of [BL1984]_.
|
630
|
+
|
631
|
+
INPUT:
|
632
|
+
|
633
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
634
|
+
|
635
|
+
OUTPUT:
|
636
|
+
|
637
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
638
|
+
exists, and ``None`` otherwise.
|
639
|
+
|
640
|
+
EXAMPLES::
|
641
|
+
|
642
|
+
sage: from sage.graphs.strongly_regular_db import is_NOperp_F5
|
643
|
+
sage: t = is_NOperp_F5(10, 3, 0, 1); t # needs sage.libs.pari
|
644
|
+
(<function NonisotropicOrthogonalPolarGraph at ...>, 3, 5, '-', 1)
|
645
|
+
sage: g = t[0](*t[1:]); g # needs sage.libs.gap sage.libs.pari
|
646
|
+
NO^-,perp(3, 5): Graph on 10 vertices
|
647
|
+
sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap sage.libs.pari
|
648
|
+
(10, 3, 0, 1)
|
649
|
+
|
650
|
+
TESTS:
|
651
|
+
|
652
|
+
All of ``NO^+,perp(2m+1,5)`` and ``NO^-,perp(2m+1,5)`` appear::
|
653
|
+
|
654
|
+
sage: t = is_NOperp_F5(325, 60, 15, 10); t # needs sage.libs.pari
|
655
|
+
(<function NonisotropicOrthogonalPolarGraph at ...>, 5, 5, '+', 1)
|
656
|
+
sage: t = is_NOperp_F5(300, 65, 10, 15); t # needs sage.libs.pari
|
657
|
+
(<function NonisotropicOrthogonalPolarGraph at ...>, 5, 5, '-', 1)
|
658
|
+
sage: t = is_NOperp_F5(5,5,5,5); t # needs sage.libs.pari
|
659
|
+
"""
|
660
|
+
cdef int n
|
661
|
+
r, s = eigenvalues(v, k, l, mu) # 2*e*5**(n-1), -e*5**(n-1); note exceptional case n=1
|
662
|
+
if r is None:
|
663
|
+
return
|
664
|
+
if abs(r) < abs(s):
|
665
|
+
(r, s) = (s, r)
|
666
|
+
e = 1 if s < 0 else -1
|
667
|
+
p, n = is_prime_power(abs(s), get_data=True)
|
668
|
+
if (5 == p and n) or (abs(r) == 2 and abs(s) == 1):
|
669
|
+
n += 1
|
670
|
+
if (v == (5**n)*(5**n + e)//2 and
|
671
|
+
k == (5**n - e)*5**(n - 1)//2 and
|
672
|
+
l == 5**(n - 1)*(5**(n - 1) + e)//2 and
|
673
|
+
mu == 5**(n - 1)*(5**(n - 1) - e)//2):
|
674
|
+
from sage.graphs.generators.classical_geometries import NonisotropicOrthogonalPolarGraph
|
675
|
+
return (NonisotropicOrthogonalPolarGraph, 2*n + 1, 5, '+' if e == 1 else '-', 1)
|
676
|
+
|
677
|
+
|
678
|
+
@cached_function
|
679
|
+
def is_NO_F2(int v, int k, int l, int mu):
|
680
|
+
r"""
|
681
|
+
Test whether some NO^e,perp(2n,2) graph is `(v,k,\lambda,\mu)`-strongly regular.
|
682
|
+
|
683
|
+
For more information, see
|
684
|
+
:func:`sage.graphs.graph_generators.GraphGenerators.NonisotropicOrthogonalPolarGraph`.
|
685
|
+
|
686
|
+
INPUT:
|
687
|
+
|
688
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
689
|
+
|
690
|
+
OUTPUT:
|
691
|
+
|
692
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
693
|
+
exists, and ``None`` otherwise.
|
694
|
+
|
695
|
+
EXAMPLES::
|
696
|
+
|
697
|
+
sage: from sage.graphs.strongly_regular_db import is_NO_F2
|
698
|
+
sage: t = is_NO_F2(10, 3, 0, 1); t # needs sage.libs.pari
|
699
|
+
(<function NonisotropicOrthogonalPolarGraph at ...>, 4, 2, '-')
|
700
|
+
sage: g = t[0](*t[1:]); g # needs sage.libs.gap sage.libs.pari
|
701
|
+
NO^-(4, 2): Graph on 10 vertices
|
702
|
+
sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap sage.libs.pari
|
703
|
+
(10, 3, 0, 1)
|
704
|
+
|
705
|
+
TESTS:
|
706
|
+
|
707
|
+
All of ``NO^+(2m,2)`` and ``NO^-(2m,2)`` appear::
|
708
|
+
|
709
|
+
sage: t = is_NO_F2(36, 15, 6, 6); t # needs sage.libs.pari
|
710
|
+
(<function NonisotropicOrthogonalPolarGraph at ...>, 6, 2, '-')
|
711
|
+
sage: t = is_NO_F2(28, 15, 6, 10); t # needs sage.libs.pari
|
712
|
+
(<function NonisotropicOrthogonalPolarGraph at ...>, 6, 2, '+')
|
713
|
+
sage: t = is_NO_F2(5,5,5,5); t # needs sage.libs.pari
|
714
|
+
"""
|
715
|
+
cdef int n, e, p
|
716
|
+
p, n = is_prime_power(k+1, get_data=True) # k+1==2**(2*n-2)
|
717
|
+
if 2 == p and n and not n % 2:
|
718
|
+
n = (n+2)//2
|
719
|
+
e = (2**(2*n-1)-v)//2**(n-1)
|
720
|
+
if (abs(e) == 1 and
|
721
|
+
v == 2**(2*n - 1) - e*2**(n - 1) and
|
722
|
+
k == 2**(2*n - 2) - 1 and
|
723
|
+
l == 2**(2*n - 3) - 2 and
|
724
|
+
mu == 2**(2*n - 3) + e*2**(n - 2)):
|
725
|
+
from sage.graphs.generators.classical_geometries import NonisotropicOrthogonalPolarGraph
|
726
|
+
return (NonisotropicOrthogonalPolarGraph, 2*n, 2, '+' if e == 1 else '-')
|
727
|
+
|
728
|
+
|
729
|
+
@cached_function
|
730
|
+
def is_NO_F3(int v, int k, int l, int mu):
|
731
|
+
r"""
|
732
|
+
Test whether some NO^e,perp(2n,3) graph is `(v,k,\lambda,\mu)`-strongly regular.
|
733
|
+
|
734
|
+
For more information, see
|
735
|
+
:func:`sage.graphs.graph_generators.GraphGenerators.NonisotropicOrthogonalPolarGraph`.
|
736
|
+
|
737
|
+
INPUT:
|
738
|
+
|
739
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
740
|
+
|
741
|
+
OUTPUT:
|
742
|
+
|
743
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
744
|
+
exists, and ``None`` otherwise.
|
745
|
+
|
746
|
+
EXAMPLES::
|
747
|
+
|
748
|
+
sage: from sage.graphs.strongly_regular_db import is_NO_F3
|
749
|
+
sage: t = is_NO_F3(15, 6, 1, 3); t # needs sage.libs.pari
|
750
|
+
(<function NonisotropicOrthogonalPolarGraph at ...>, 4, 3, '-')
|
751
|
+
sage: g = t[0](*t[1:]); g # needs sage.libs.gap sage.libs.pari
|
752
|
+
NO^-(4, 3): Graph on 15 vertices
|
753
|
+
sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap sage.libs.pari
|
754
|
+
(15, 6, 1, 3)
|
755
|
+
|
756
|
+
TESTS:
|
757
|
+
|
758
|
+
All of ``NO^+(2m,3)`` and ``NO^-(2m,3)`` appear::
|
759
|
+
|
760
|
+
sage: t = is_NO_F3(126, 45, 12, 18); t # needs sage.libs.pari
|
761
|
+
(<function NonisotropicOrthogonalPolarGraph at ...>, 6, 3, '-')
|
762
|
+
sage: t = is_NO_F3(117, 36, 15, 9); t # needs sage.libs.pari
|
763
|
+
(<function NonisotropicOrthogonalPolarGraph at ...>, 6, 3, '+')
|
764
|
+
sage: t = is_NO_F3(5,5,5,5); t # needs sage.libs.pari
|
765
|
+
"""
|
766
|
+
cdef int n, e, p
|
767
|
+
r, s = eigenvalues(v, k, l, mu) # e*3**(n-1), -e*3**(n-2)
|
768
|
+
if r is None:
|
769
|
+
return
|
770
|
+
if abs(r) < abs(s):
|
771
|
+
(r, s) = (s, r)
|
772
|
+
e = 1 if r > 0 else -1
|
773
|
+
p, n = is_prime_power(abs(r), get_data=True)
|
774
|
+
if 3 == p and n:
|
775
|
+
n += 1
|
776
|
+
if (v == 3**(n - 1)*(3**n - e)//2 and
|
777
|
+
k == 3**(n - 1)*(3**(n - 1) - e)//2 and
|
778
|
+
l == 3**(n - 2)*(3**(n - 1) + e)//2 and
|
779
|
+
mu == 3**(n - 1)*(3**(n - 2) - e)//2):
|
780
|
+
from sage.graphs.generators.classical_geometries import NonisotropicOrthogonalPolarGraph
|
781
|
+
return (NonisotropicOrthogonalPolarGraph, 2*n, 3, '+' if e == 1 else '-')
|
782
|
+
|
783
|
+
|
784
|
+
@cached_function
|
785
|
+
def is_NU(int v, int k, int l, int mu):
|
786
|
+
r"""
|
787
|
+
Test whether some NU(n,q)-graph, is `(v,k,\lambda,\mu)`-strongly regular.
|
788
|
+
|
789
|
+
Note that n>2; for n=2 there is no s.r.g. For more information, see
|
790
|
+
:func:`sage.graphs.graph_generators.GraphGenerators.NonisotropicUnitaryPolarGraph`
|
791
|
+
and series C14 in [Hub1975]_.
|
792
|
+
|
793
|
+
INPUT:
|
794
|
+
|
795
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
796
|
+
|
797
|
+
OUTPUT:
|
798
|
+
|
799
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
800
|
+
exists, and ``None`` otherwise.
|
801
|
+
|
802
|
+
EXAMPLES::
|
803
|
+
|
804
|
+
sage: from sage.graphs.strongly_regular_db import is_NU
|
805
|
+
sage: t = is_NU(40, 27, 18, 18); t # needs sage.libs.pari
|
806
|
+
(<function NonisotropicUnitaryPolarGraph at ...>, 4, 2)
|
807
|
+
sage: g = t[0](*t[1:]); g # needs sage.libs.gap sage.libs.pari
|
808
|
+
NU(4, 2): Graph on 40 vertices
|
809
|
+
sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap sage.libs.pari
|
810
|
+
(40, 27, 18, 18)
|
811
|
+
|
812
|
+
TESTS::
|
813
|
+
|
814
|
+
sage: # needs sage.libs.pari
|
815
|
+
sage: t = is_NU(176, 135, 102, 108); t
|
816
|
+
(<function NonisotropicUnitaryPolarGraph at ...>, 5, 2)
|
817
|
+
sage: t = is_NU(540, 224, 88, 96); t
|
818
|
+
(<function NonisotropicUnitaryPolarGraph at ...>, 4, 3)
|
819
|
+
sage: t = is_NU(208, 75, 30, 25); t
|
820
|
+
(<function NonisotropicUnitaryPolarGraph at ...>, 3, 4)
|
821
|
+
sage: t = is_NU(5,5,5,5); t
|
822
|
+
"""
|
823
|
+
cdef int n, q, e # special cases: n=3 or q=2
|
824
|
+
r, s = eigenvalues(v, k, l, mu) # r,s = eq^{n-2} - 1, -e(q^2-q-1)q^{n-3} - 1, e=(-1)^n
|
825
|
+
if r is None:
|
826
|
+
return
|
827
|
+
r += 1
|
828
|
+
s += 1
|
829
|
+
if abs(r) > abs(s):
|
830
|
+
(r, s) = (s, r)
|
831
|
+
p, t = is_prime_power(abs(r), get_data=True)
|
832
|
+
if p == 2: # it can be that q=2, then we'd have r>s now
|
833
|
+
pp, kk = is_prime_power(abs(s), get_data=True)
|
834
|
+
if pp == 2 and kk > 0:
|
835
|
+
(r, s) = (s, r)
|
836
|
+
p, t = is_prime_power(abs(r), get_data=True)
|
837
|
+
if r == 1:
|
838
|
+
return
|
839
|
+
kr = k//(r-1) # eq^{n-1}+1
|
840
|
+
e = 1 if kr > 0 else -1
|
841
|
+
q = (kr-1)//r
|
842
|
+
pp, kk = is_prime_power(q, get_data=True)
|
843
|
+
if p == pp and kk:
|
844
|
+
n = t//kk + 2
|
845
|
+
if (v == q**(n - 1)*(q**n - e)//(q + 1) and
|
846
|
+
k == (q**(n - 1) + e)*(q**(n - 2) - e) and
|
847
|
+
l == q**(2*n - 5)*(q + 1) - e*q**(n - 2)*(q - 1) - 2 and
|
848
|
+
mu == q**(n - 3)*(q + 1)*(q**(n - 2) - e)):
|
849
|
+
from sage.graphs.generators.classical_geometries import NonisotropicUnitaryPolarGraph
|
850
|
+
return (NonisotropicUnitaryPolarGraph, n, q)
|
851
|
+
|
852
|
+
|
853
|
+
@cached_function
|
854
|
+
def is_haemers(int v, int k, int l, int mu):
|
855
|
+
r"""
|
856
|
+
Test whether some HaemersGraph graph is `(v,k,\lambda,\mu)`-strongly regular.
|
857
|
+
|
858
|
+
For more information, see
|
859
|
+
:func:`~sage.graphs.graph_generators.GraphGenerators.HaemersGraph`.
|
860
|
+
|
861
|
+
INPUT:
|
862
|
+
|
863
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
864
|
+
|
865
|
+
OUTPUT:
|
866
|
+
|
867
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
868
|
+
exists, and ``None`` otherwise.
|
869
|
+
|
870
|
+
EXAMPLES::
|
871
|
+
|
872
|
+
sage: from sage.graphs.strongly_regular_db import is_haemers
|
873
|
+
sage: t = is_haemers(96, 19, 2, 4); t # needs sage.libs.pari
|
874
|
+
(<function HaemersGraph at ...>, 4)
|
875
|
+
sage: g = t[0](*t[1:]); g # needs sage.libs.pari
|
876
|
+
Haemers(4): Graph on 96 vertices
|
877
|
+
sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari
|
878
|
+
(96, 19, 2, 4)
|
879
|
+
|
880
|
+
TESTS::
|
881
|
+
|
882
|
+
sage: t = is_haemers(5,5,5,5); t # needs sage.libs.pari
|
883
|
+
"""
|
884
|
+
cdef int q, n, p
|
885
|
+
p, n = is_prime_power(mu, get_data=True)
|
886
|
+
q = mu
|
887
|
+
if 2 == p and n:
|
888
|
+
if (v == q**2*(q + 2) and
|
889
|
+
k == q*(q + 1) - 1 and
|
890
|
+
l == q - 2):
|
891
|
+
from sage.graphs.generators.classical_geometries import HaemersGraph
|
892
|
+
return (HaemersGraph, q)
|
893
|
+
|
894
|
+
|
895
|
+
@cached_function
|
896
|
+
def is_cossidente_penttila(int v, int k, int l, int mu):
|
897
|
+
r"""
|
898
|
+
Test whether some CossidentePenttilaGraph graph is `(v,k,\lambda,\mu)`-strongly regular.
|
899
|
+
|
900
|
+
For more information, see
|
901
|
+
:func:`~sage.graphs.graph_generators.GraphGenerators.CossidentePenttilaGraph`.
|
902
|
+
|
903
|
+
INPUT:
|
904
|
+
|
905
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
906
|
+
|
907
|
+
OUTPUT:
|
908
|
+
|
909
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
910
|
+
exists, and ``None`` otherwise.
|
911
|
+
|
912
|
+
EXAMPLES::
|
913
|
+
|
914
|
+
sage: from sage.graphs.strongly_regular_db import is_cossidente_penttila
|
915
|
+
sage: t = is_cossidente_penttila(378, 52, 1, 8); t # needs sage.libs.pari
|
916
|
+
(<function CossidentePenttilaGraph at ...>, 5)
|
917
|
+
sage: g = t[0](*t[1:]); g # optional - gap_package_design, needs sage.libs.pari
|
918
|
+
CossidentePenttila(5): Graph on 378 vertices
|
919
|
+
sage: g.is_strongly_regular(parameters=True) # optional - gap_package_design, needs sage.libs.pari
|
920
|
+
(378, 52, 1, 8)
|
921
|
+
|
922
|
+
TESTS::
|
923
|
+
|
924
|
+
sage: t = is_cossidente_penttila(56,10,0,2); t # needs sage.libs.pari
|
925
|
+
(<function CossidentePenttilaGraph at ...>, 3)
|
926
|
+
sage: t = is_cossidente_penttila(1376,150,2,18); t # needs sage.libs.pari
|
927
|
+
(<function CossidentePenttilaGraph at ...>, 7)
|
928
|
+
sage: t = is_cossidente_penttila(5,5,5,5); t # needs sage.libs.pari
|
929
|
+
"""
|
930
|
+
cdef int q, n, p
|
931
|
+
q = 2*l + 3
|
932
|
+
p, n = is_prime_power(q, get_data=True)
|
933
|
+
if 2 < p and n:
|
934
|
+
if (v == (q**3 + 1)*(q + 1)//2 and
|
935
|
+
k == (q**2 + 1)*(q - 1)//2 and
|
936
|
+
mu == (q - 1)**2//2):
|
937
|
+
from sage.graphs.generators.classical_geometries import CossidentePenttilaGraph
|
938
|
+
return (CossidentePenttilaGraph, q)
|
939
|
+
|
940
|
+
|
941
|
+
@cached_function
|
942
|
+
def is_complete_multipartite(int v, int k, int l, int mu):
|
943
|
+
r"""
|
944
|
+
Test whether some complete multipartite graph is `(v,k,\lambda,\mu)`-strongly regular.
|
945
|
+
|
946
|
+
Any complete multipartite graph with parts of the same size is strongly regular.
|
947
|
+
|
948
|
+
INPUT:
|
949
|
+
|
950
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
951
|
+
|
952
|
+
OUTPUT:
|
953
|
+
|
954
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
955
|
+
exists, and ``None`` otherwise.
|
956
|
+
|
957
|
+
EXAMPLES::
|
958
|
+
|
959
|
+
sage: from sage.graphs.strongly_regular_db import is_complete_multipartite
|
960
|
+
sage: t = is_complete_multipartite(12,8,4,8); t
|
961
|
+
(<...CompleteMultipartiteSRG...>,
|
962
|
+
3,
|
963
|
+
4)
|
964
|
+
sage: g = t[0](*t[1:]); g
|
965
|
+
Multipartite Graph with set sizes [4, 4, 4]: Graph on 12 vertices
|
966
|
+
sage: g.is_strongly_regular(parameters=True)
|
967
|
+
(12, 8, 4, 8)
|
968
|
+
|
969
|
+
TESTS::
|
970
|
+
|
971
|
+
sage: t = is_complete_multipartite(5,5,5,5); t
|
972
|
+
sage: t = is_complete_multipartite(11,8,4,8); t
|
973
|
+
sage: t = is_complete_multipartite(20,16,12,16)
|
974
|
+
sage: g = t[0](*t[1:]); g
|
975
|
+
Multipartite Graph with set sizes [4, 4, 4, 4, 4]: Graph on 20 vertices
|
976
|
+
sage: g.is_strongly_regular(parameters=True)
|
977
|
+
(20, 16, 12, 16)
|
978
|
+
"""
|
979
|
+
if v > k:
|
980
|
+
r = v//(v - k) # number of parts (of size v-k each)
|
981
|
+
if l == (v - k)*(r - 2) and k == mu and v == r*(v - k):
|
982
|
+
from sage.graphs.generators.basic import CompleteMultipartiteGraph
|
983
|
+
|
984
|
+
def CompleteMultipartiteSRG(nparts, partsize):
|
985
|
+
return CompleteMultipartiteGraph([partsize] * nparts)
|
986
|
+
return (CompleteMultipartiteSRG, r, v - k)
|
987
|
+
|
988
|
+
|
989
|
+
@cached_function
|
990
|
+
def is_polhill(int v, int k, int l, int mu):
|
991
|
+
r"""
|
992
|
+
Test whether some graph from [Pol2009]_ is `(1024,k,\lambda,\mu)`-strongly
|
993
|
+
regular.
|
994
|
+
|
995
|
+
.. NOTE::
|
996
|
+
|
997
|
+
This function does not actually explore *all* strongly regular graphs
|
998
|
+
produced in [Pol2009]_, but only those on 1024 vertices.
|
999
|
+
|
1000
|
+
John Polhill offered his help if we attempt to write a code to guess,
|
1001
|
+
given `(v,k,\lambda,\mu)`, which of his construction must be applied to
|
1002
|
+
find the graph.
|
1003
|
+
|
1004
|
+
INPUT:
|
1005
|
+
|
1006
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
1007
|
+
|
1008
|
+
OUTPUT:
|
1009
|
+
|
1010
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if the
|
1011
|
+
parameters match, and ``None`` otherwise.
|
1012
|
+
|
1013
|
+
EXAMPLES::
|
1014
|
+
|
1015
|
+
sage: # needs sage.rings.finite_rings
|
1016
|
+
sage: from sage.graphs.strongly_regular_db import is_polhill
|
1017
|
+
sage: t = is_polhill(1024, 231, 38, 56); t
|
1018
|
+
[<cyfunction is_polhill.<locals>.<lambda> at ...>]
|
1019
|
+
sage: g = t[0](*t[1:]); g # not tested (too long)
|
1020
|
+
Graph on 1024 vertices
|
1021
|
+
sage: g.is_strongly_regular(parameters=True) # not tested (too long)
|
1022
|
+
(1024, 231, 38, 56)
|
1023
|
+
sage: t = is_polhill(1024, 264, 56, 72); t
|
1024
|
+
[<cyfunction is_polhill.<locals>.<lambda> at ...>]
|
1025
|
+
sage: t = is_polhill(1024, 297, 76, 90); t
|
1026
|
+
[<cyfunction is_polhill.<locals>.<lambda> at ...>]
|
1027
|
+
sage: t = is_polhill(1024, 330, 98, 110); t
|
1028
|
+
[<cyfunction is_polhill.<locals>.<lambda> at ...>]
|
1029
|
+
sage: t = is_polhill(1024, 462, 206, 210); t
|
1030
|
+
[<cyfunction is_polhill.<locals>.<lambda> at ...>]
|
1031
|
+
"""
|
1032
|
+
if (v, k, l, mu) not in [(1024, 231, 38, 56),
|
1033
|
+
(1024, 264, 56, 72),
|
1034
|
+
(1024, 297, 76, 90),
|
1035
|
+
(1024, 330, 98, 110),
|
1036
|
+
(1024, 462, 206, 210)]:
|
1037
|
+
return
|
1038
|
+
|
1039
|
+
from itertools import product
|
1040
|
+
from sage.categories.cartesian_product import cartesian_product
|
1041
|
+
from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
|
1042
|
+
from copy import copy
|
1043
|
+
|
1044
|
+
def additive_cayley(vertices):
|
1045
|
+
g = Graph()
|
1046
|
+
g.add_vertices(vertices[0].parent())
|
1047
|
+
edges = [(x, x + vv)
|
1048
|
+
for vv in set(vertices)
|
1049
|
+
for x in g]
|
1050
|
+
g.add_edges(edges)
|
1051
|
+
g.relabel()
|
1052
|
+
return g
|
1053
|
+
|
1054
|
+
# D is a Partial Difference Set of (Z4)^2, see section 2.
|
1055
|
+
G = cartesian_product([IntegerModRing(4), IntegerModRing(4)])
|
1056
|
+
D = [[(2, 0), (0, 1), (0, 3), (1, 1), (3, 3)],
|
1057
|
+
[(1, 0), (3, 0), (0, 2), (1, 3), (3, 1)],
|
1058
|
+
[(1, 2), (3, 2), (2, 1), (2, 3), (2, 2)]]
|
1059
|
+
D = [[G(e) for e in x] for x in D]
|
1060
|
+
|
1061
|
+
# The K_i are hyperplanes partitioning the nonzero elements of
|
1062
|
+
# GF(2^s)^2. See section 6.
|
1063
|
+
s = 3
|
1064
|
+
G1 = GF(2**s,'x')
|
1065
|
+
Gp = cartesian_product([G1, G1])
|
1066
|
+
K = [Gp((x, 1)) for x in G1] + [Gp((1, 0))]
|
1067
|
+
K = [[x for x in Gp if x[0]*uu + x[1]*vv == 0] for (uu, vv) in K]
|
1068
|
+
|
1069
|
+
# We now define the P_{i,j}. see section 6.
|
1070
|
+
|
1071
|
+
P = {}
|
1072
|
+
P[0, 1] = list(range((-1) + 1, 2**(s-2)+1))
|
1073
|
+
P[1, 1] = list(range((-1) + 2**(s-2)+2, 2**(s-1)+1))
|
1074
|
+
P[2, 1] = list(range((-1) + 2**(s-1)+2, 2**(s-1)+2**(s-2)+1))
|
1075
|
+
P[3, 1] = list(range((-1) + 2**(s-1)+2**(s-2)+2, 2**(s)+1))
|
1076
|
+
|
1077
|
+
P[0, 2] = list(range((-1) + 2**(s-2)+2, 2**(s-1)+2))
|
1078
|
+
P[1, 2] = list(range((-1) + 2**(s-1)+3, 2**(s-1)+2**(s-2)+2))
|
1079
|
+
P[2, 2] = list(range((-1) + 2**(s-1)+2**(s-2)+3, 2**(s)+1)) + [0]
|
1080
|
+
P[3, 2] = list(range((-1) + 2, 2**(s-2)+1))
|
1081
|
+
|
1082
|
+
P[0, 3] = list(range((-1) + 2**(s-1)+3, 2**(s-1)+2**(s-2)+3))
|
1083
|
+
P[1, 3] = list(range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1)) + [0,1]
|
1084
|
+
P[2, 3] = list(range((-1) + 3, 2**(s-2)+2))
|
1085
|
+
P[3, 3] = list(range((-1) + 2**(s-2)+3, 2**(s-1)+2))
|
1086
|
+
|
1087
|
+
P[0, 4] = list(range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1))
|
1088
|
+
P[1, 4] = list(range((-1) + 3, 2**(s-2)+1)) + [2**(s-1)+1,2**(s-1)+2**(s-2)+2]
|
1089
|
+
P[2, 4] = list(range((-1) + 2**(s-2)+3, 2**(s-1)+1)) + [2**(s-1)+2**(s-2)+1,1]
|
1090
|
+
P[3, 4] = list(range((-1) + 2**(s-1)+3, 2**(s-1)+2**(s-2)+1)) + [2**(s-2)+1,0]
|
1091
|
+
|
1092
|
+
R = {x: copy(P[x]) for x in P}
|
1093
|
+
|
1094
|
+
for x in P:
|
1095
|
+
P[x] = [K[i] for i in P[x]]
|
1096
|
+
P[x] = set(sum(P[x], [])).difference([Gp((0, 0))])
|
1097
|
+
|
1098
|
+
P[1, 4].add(Gp((0, 0)))
|
1099
|
+
P[2, 4].add(Gp((0, 0)))
|
1100
|
+
P[3, 4].add(Gp((0, 0)))
|
1101
|
+
|
1102
|
+
# We now define the R_{i,j}. see *end* of section 6.
|
1103
|
+
|
1104
|
+
R[0, 3] = list(range((-1) + 2**(s-1)+3, 2**(s-1)+2**(s-2)+2))
|
1105
|
+
R[1, 3] = list(range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1)) + [0,1,2**(s-1)+2**(s-2)+2]
|
1106
|
+
R[0, 4] = list(range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1)) + [2**(s-1)+2**(s-2)+2]
|
1107
|
+
R[1, 4] = list(range((-1) + 3, 2**(s-2)+1)) + [2**(s-1)+1]
|
1108
|
+
|
1109
|
+
for x in R:
|
1110
|
+
R[x] = [K[i] for i in R[x]]
|
1111
|
+
R[x] = set(sum(R[x], [])).difference([Gp((0, 0))])
|
1112
|
+
|
1113
|
+
R[1, 3].add(Gp((0, 0)))
|
1114
|
+
R[2, 4].add(Gp((0, 0)))
|
1115
|
+
R[3, 4].add(Gp((0, 0)))
|
1116
|
+
|
1117
|
+
# Dabcd = Da, Db, Dc, Dd (cf. p273)
|
1118
|
+
# D1234 = D1, D2, D3, D4 (cf. p276)
|
1119
|
+
Dabcd = []
|
1120
|
+
D1234 = []
|
1121
|
+
|
1122
|
+
Gprod = cartesian_product([G, Gp])
|
1123
|
+
for DD,PQ in [(Dabcd, P), (D1234, R)]:
|
1124
|
+
for i in range(1, 5):
|
1125
|
+
Dtmp = [product([G.zero()], PQ[0, i]),
|
1126
|
+
product(D[0], PQ[1, i]),
|
1127
|
+
product(D[1], PQ[2, i]),
|
1128
|
+
product(D[2], PQ[3, i])]
|
1129
|
+
Dtmp = map(set, Dtmp)
|
1130
|
+
Dtmp = [Gprod(e) for e in sum(map(list, Dtmp), [])]
|
1131
|
+
DD.append(Dtmp)
|
1132
|
+
|
1133
|
+
# Now that we have the data, we can return the graphs.
|
1134
|
+
if k == 231:
|
1135
|
+
return [lambda: additive_cayley(Dabcd[0])]
|
1136
|
+
if k == 264:
|
1137
|
+
return [lambda: additive_cayley(D1234[2])]
|
1138
|
+
if k == 297:
|
1139
|
+
return [lambda: additive_cayley(D1234[0] + D1234[1] + D1234[2]).complement()]
|
1140
|
+
if k == 330:
|
1141
|
+
return [lambda: additive_cayley(Dabcd[0] + Dabcd[1] + Dabcd[2]).complement()]
|
1142
|
+
if k == 462:
|
1143
|
+
return [lambda: additive_cayley(Dabcd[0] + Dabcd[1])]
|
1144
|
+
|
1145
|
+
|
1146
|
+
def is_RSHCD(int v, int k, int l, int mu):
|
1147
|
+
r"""
|
1148
|
+
Test whether some RSHCD graph is `(v,k,\lambda,\mu)`-strongly regular.
|
1149
|
+
|
1150
|
+
For more information, see :func:`SRG_from_RSHCD`.
|
1151
|
+
|
1152
|
+
INPUT:
|
1153
|
+
|
1154
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
1155
|
+
|
1156
|
+
OUTPUT:
|
1157
|
+
|
1158
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
1159
|
+
exists, and ``None`` otherwise.
|
1160
|
+
|
1161
|
+
EXAMPLES::
|
1162
|
+
|
1163
|
+
sage: from sage.graphs.strongly_regular_db import is_RSHCD
|
1164
|
+
sage: t = is_RSHCD(64,27,10,12); t # needs sage.combinat sage.modules
|
1165
|
+
[<built-in function SRG_from_RSHCD>, 64, 27, 10, 12]
|
1166
|
+
sage: g = t[0](*t[1:]); g # needs sage.combinat sage.modules
|
1167
|
+
Graph on 64 vertices
|
1168
|
+
sage: g.is_strongly_regular(parameters=True) # needs sage.combinat sage.modules
|
1169
|
+
(64, 27, 10, 12)
|
1170
|
+
"""
|
1171
|
+
if SRG_from_RSHCD(v, k, l, mu, existence=True) is True:
|
1172
|
+
return [SRG_from_RSHCD, v, k, l, mu]
|
1173
|
+
|
1174
|
+
|
1175
|
+
def SRG_from_RSHCD(v, k, l, mu, existence=False, check=True):
|
1176
|
+
r"""
|
1177
|
+
Return a `(v,k,l,mu)`-strongly regular graph from a RSHCD.
|
1178
|
+
|
1179
|
+
This construction appears in 8.D of [BL1984]_. For more information, see
|
1180
|
+
:func:`~sage.combinat.matrices.hadamard_matrix.regular_symmetric_hadamard_matrix_with_constant_diagonal`.
|
1181
|
+
|
1182
|
+
INPUT:
|
1183
|
+
|
1184
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
1185
|
+
|
1186
|
+
- ``existence`` -- boolean; whether to return a graph or to test if Sage
|
1187
|
+
can build such a graph
|
1188
|
+
|
1189
|
+
- ``check`` -- boolean (default: ``True``); whether to check that output is
|
1190
|
+
correct before returning it. As this is expected to be useless, you may
|
1191
|
+
want to disable it whenever you want speed.
|
1192
|
+
|
1193
|
+
EXAMPLES:
|
1194
|
+
|
1195
|
+
some graphs ::
|
1196
|
+
|
1197
|
+
sage: from sage.graphs.strongly_regular_db import SRG_from_RSHCD
|
1198
|
+
sage: SRG_from_RSHCD(784, 0, 14, 38, existence=True) # needs sage.combinat sage.modules
|
1199
|
+
False
|
1200
|
+
sage: SRG_from_RSHCD(784, 377, 180, 182, existence=True) # needs sage.combinat sage.modules
|
1201
|
+
True
|
1202
|
+
sage: SRG_from_RSHCD(144, 65, 28, 30) # needs sage.combinat sage.modules
|
1203
|
+
Graph on 144 vertices
|
1204
|
+
|
1205
|
+
an example with vertex-transitive automorphism group, found during the
|
1206
|
+
implementation of the case `v=324` ::
|
1207
|
+
|
1208
|
+
sage: # long time, needs sage.combinat sage.modules
|
1209
|
+
sage: G = SRG_from_RSHCD(324,152,70,72)
|
1210
|
+
sage: a = G.automorphism_group()
|
1211
|
+
sage: a.order()
|
1212
|
+
2592
|
1213
|
+
sage: len(a.orbits())
|
1214
|
+
1
|
1215
|
+
|
1216
|
+
TESTS::
|
1217
|
+
|
1218
|
+
sage: SRG_from_RSHCD(784, 0, 14, 38) # needs sage.combinat sage.modules
|
1219
|
+
Traceback (most recent call last):
|
1220
|
+
...
|
1221
|
+
ValueError: I do not know how to build a (784, 0, 14, 38)-SRG from a RSHCD
|
1222
|
+
"""
|
1223
|
+
from sage.combinat.matrices.hadamard_matrix import regular_symmetric_hadamard_matrix_with_constant_diagonal
|
1224
|
+
|
1225
|
+
def sgn(x):
|
1226
|
+
return 1 if x >= 0 else -1
|
1227
|
+
n = v
|
1228
|
+
a = (n-4*mu)//2
|
1229
|
+
e = 2*k - n + 1 + a
|
1230
|
+
|
1231
|
+
if (e**2 == 1 and
|
1232
|
+
k == (n-1-a+e)/2 and
|
1233
|
+
l == (n-2*a)/4 - (1-e) and
|
1234
|
+
mu == (n-2*a)/4 and
|
1235
|
+
regular_symmetric_hadamard_matrix_with_constant_diagonal(n, sgn(a)*e, existence=True) is True):
|
1236
|
+
if existence:
|
1237
|
+
return True
|
1238
|
+
from sage.matrix.constructor import identity_matrix as I
|
1239
|
+
from sage.matrix.constructor import ones_matrix as J
|
1240
|
+
|
1241
|
+
H = regular_symmetric_hadamard_matrix_with_constant_diagonal(n, sgn(a)*e)
|
1242
|
+
if list(H.column(0)[1:]).count(1) == k:
|
1243
|
+
H = -H
|
1244
|
+
G = Graph((J(n) - I(n) - H + H[0, 0]*I(n)) / 2,
|
1245
|
+
loops=False, multiedges=False, format='adjacency_matrix')
|
1246
|
+
if check:
|
1247
|
+
assert G.is_strongly_regular(parameters=True) == (v, k, l, mu)
|
1248
|
+
return G
|
1249
|
+
|
1250
|
+
if existence:
|
1251
|
+
return False
|
1252
|
+
raise ValueError("I do not know how to build a {}-SRG from a RSHCD".format((v, k, l, mu)))
|
1253
|
+
|
1254
|
+
|
1255
|
+
@cached_function
|
1256
|
+
def is_unitary_polar(int v, int k, int l, int mu):
|
1257
|
+
r"""
|
1258
|
+
Test whether some Unitary Polar graph is `(v,k,\lambda,\mu)`-strongly regular.
|
1259
|
+
|
1260
|
+
For more information, see https://www.win.tue.nl/~aeb/graphs/srghub.html.
|
1261
|
+
|
1262
|
+
INPUT:
|
1263
|
+
|
1264
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
1265
|
+
|
1266
|
+
OUTPUT:
|
1267
|
+
|
1268
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
1269
|
+
exists, and ``None`` otherwise.
|
1270
|
+
|
1271
|
+
EXAMPLES::
|
1272
|
+
|
1273
|
+
sage: from sage.graphs.strongly_regular_db import is_unitary_polar
|
1274
|
+
sage: t = is_unitary_polar(45, 12, 3, 3); t # needs sage.libs.pari
|
1275
|
+
(<function UnitaryPolarGraph at ...>, 4, 2)
|
1276
|
+
sage: g = t[0](*t[1:]); g # needs sage.libs.gap sage.libs.pari
|
1277
|
+
Unitary Polar Graph U(4, 2); GQ(4, 2): Graph on 45 vertices
|
1278
|
+
sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap sage.libs.pari
|
1279
|
+
(45, 12, 3, 3)
|
1280
|
+
|
1281
|
+
sage: t = is_unitary_polar(5,5,5,5); t # needs sage.libs.pari
|
1282
|
+
|
1283
|
+
TESTS:
|
1284
|
+
|
1285
|
+
All the ``U(n,q)`` appear::
|
1286
|
+
|
1287
|
+
sage: # needs sage.libs.pari
|
1288
|
+
sage: t = is_unitary_polar(45, 12, 3, 3); t
|
1289
|
+
(<function UnitaryPolarGraph at ...>, 4, 2)
|
1290
|
+
sage: t = is_unitary_polar(165, 36, 3, 9); t
|
1291
|
+
(<function UnitaryPolarGraph at ...>, 5, 2)
|
1292
|
+
sage: t = is_unitary_polar(693, 180, 51, 45); t
|
1293
|
+
(<function UnitaryPolarGraph at ...>, 6, 2)
|
1294
|
+
sage: t = is_unitary_polar(1105, 80, 15, 5); t
|
1295
|
+
(<function UnitaryPolarGraph at ...>, 4, 4)
|
1296
|
+
"""
|
1297
|
+
r, s = eigenvalues(v, k, l, mu)
|
1298
|
+
if r is None:
|
1299
|
+
return
|
1300
|
+
q = k//mu
|
1301
|
+
if q*mu != k or q < 2:
|
1302
|
+
return
|
1303
|
+
p, t = is_prime_power(q, get_data=True)
|
1304
|
+
if p**t != q or t % 2:
|
1305
|
+
return
|
1306
|
+
# at this point we know that we should have U(n,q) for some n and q=p^t, t even
|
1307
|
+
if r > 0:
|
1308
|
+
q_pow_d_minus_one = r+1
|
1309
|
+
else:
|
1310
|
+
q_pow_d_minus_one = -s-1
|
1311
|
+
ppp, ttt = is_prime_power(q_pow_d_minus_one, get_data=True)
|
1312
|
+
d = ttt//t + 1
|
1313
|
+
if ppp != p or (d-1)*t != ttt:
|
1314
|
+
return
|
1315
|
+
t //= 2
|
1316
|
+
# U(2d+1,q); write q^(1/2) as p^t
|
1317
|
+
if (v == (q**d - 1)*((q**d)*p**t + 1)//(q - 1) and
|
1318
|
+
k == q*(q**(d-1) - 1)*((q**d)//(p**t) + 1)//(q - 1) and
|
1319
|
+
l == q*q*(q**(d-2)-1)*((q**(d-1))//(p**t) + 1)//(q - 1) + q - 1):
|
1320
|
+
from sage.graphs.generators.classical_geometries import UnitaryPolarGraph
|
1321
|
+
return (UnitaryPolarGraph, 2*d+1, p**t)
|
1322
|
+
|
1323
|
+
# U(2d,q);
|
1324
|
+
if (v == (q**d - 1)*((q**d)//(p**t) + 1)//(q - 1) and
|
1325
|
+
k == q*(q**(d-1) - 1)*((q**(d-1))//(p**t) + 1)//(q - 1) and
|
1326
|
+
l == q*q*(q**(d-2)-1)*((q**(d-2))//(p**t) + 1)//(q - 1) + q - 1):
|
1327
|
+
from sage.graphs.generators.classical_geometries import UnitaryPolarGraph
|
1328
|
+
return (UnitaryPolarGraph, 2*d, p**t)
|
1329
|
+
|
1330
|
+
|
1331
|
+
@cached_function
|
1332
|
+
def is_unitary_dual_polar(int v, int k, int l, int mu):
|
1333
|
+
r"""
|
1334
|
+
Test whether some Unitary Dual Polar graph is `(v,k,\lambda,\mu)`-strongly regular.
|
1335
|
+
|
1336
|
+
This must be the U_5(q) on totally isotropic lines.
|
1337
|
+
For more information, see https://www.win.tue.nl/~aeb/graphs/srghub.html.
|
1338
|
+
|
1339
|
+
INPUT:
|
1340
|
+
|
1341
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
1342
|
+
|
1343
|
+
OUTPUT:
|
1344
|
+
|
1345
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
1346
|
+
exists, and ``None`` otherwise.
|
1347
|
+
|
1348
|
+
EXAMPLES::
|
1349
|
+
|
1350
|
+
sage: # needs sage.libs.pari
|
1351
|
+
sage: from sage.graphs.strongly_regular_db import is_unitary_dual_polar
|
1352
|
+
sage: t = is_unitary_dual_polar(297, 40, 7, 5); t
|
1353
|
+
(<function UnitaryDualPolarGraph at ...>, 5, 2)
|
1354
|
+
sage: g = t[0](*t[1:]); g # needs sage.libs.gap
|
1355
|
+
Unitary Dual Polar Graph DU(5, 2); GQ(8, 4): Graph on 297 vertices
|
1356
|
+
sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap
|
1357
|
+
(297, 40, 7, 5)
|
1358
|
+
sage: t = is_unitary_dual_polar(5,5,5,5); t
|
1359
|
+
|
1360
|
+
TESTS::
|
1361
|
+
|
1362
|
+
sage: is_unitary_dual_polar(6832, 270, 26, 10) # needs sage.libs.pari
|
1363
|
+
(<function UnitaryDualPolarGraph at ...>, 5, 3)
|
1364
|
+
"""
|
1365
|
+
r, s = eigenvalues(v, k, l, mu)
|
1366
|
+
if r is None:
|
1367
|
+
return
|
1368
|
+
q = mu - 1
|
1369
|
+
if q < 2:
|
1370
|
+
return
|
1371
|
+
p, t = is_prime_power(q, get_data=True)
|
1372
|
+
if p**t != q or t % 2:
|
1373
|
+
return
|
1374
|
+
if (r < 0 and q != -r - 1) or (s < 0 and q != -s - 1):
|
1375
|
+
return
|
1376
|
+
t //= 2
|
1377
|
+
# we have correct mu, negative eigenvalue, and q=p^(2t)
|
1378
|
+
if (v == (q**2*p**t + 1)*(q*p**t + 1) and
|
1379
|
+
k == q*p**t*(q + 1) and
|
1380
|
+
l == k - 1 - q**2*p**t):
|
1381
|
+
from sage.graphs.generators.classical_geometries import UnitaryDualPolarGraph
|
1382
|
+
return (UnitaryDualPolarGraph, 5, p**t)
|
1383
|
+
|
1384
|
+
|
1385
|
+
@cached_function
|
1386
|
+
def is_GQqmqp(int v, int k, int l, int mu):
|
1387
|
+
r"""
|
1388
|
+
Test whether some `GQ(q-1,q+1)` or `GQ(q+1,q-1)`-graph is `(v,k,\lambda,\mu)`-srg.
|
1389
|
+
|
1390
|
+
INPUT:
|
1391
|
+
|
1392
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
1393
|
+
|
1394
|
+
OUTPUT:
|
1395
|
+
|
1396
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
1397
|
+
exists, and ``None`` otherwise.
|
1398
|
+
|
1399
|
+
EXAMPLES::
|
1400
|
+
|
1401
|
+
sage: # needs sage.libs.pari
|
1402
|
+
sage: from sage.graphs.strongly_regular_db import is_GQqmqp
|
1403
|
+
sage: t = is_GQqmqp(27,10,1,5); t
|
1404
|
+
(<function AhrensSzekeresGeneralizedQuadrangleGraph at ...>, 3, False)
|
1405
|
+
sage: g = t[0](*t[1:]); g
|
1406
|
+
AS(3); GQ(2, 4): Graph on 27 vertices
|
1407
|
+
sage: t = is_GQqmqp(45,12,3,3); t
|
1408
|
+
(<function AhrensSzekeresGeneralizedQuadrangleGraph at ...>, 3, True)
|
1409
|
+
sage: g = t[0](*t[1:]); g
|
1410
|
+
AS(3)*; GQ(4, 2): Graph on 45 vertices
|
1411
|
+
sage: g.is_strongly_regular(parameters=True)
|
1412
|
+
(45, 12, 3, 3)
|
1413
|
+
sage: t = is_GQqmqp(16,6,2,2); t
|
1414
|
+
(<function T2starGeneralizedQuadrangleGraph at ...>, 2, True)
|
1415
|
+
sage: g = t[0](*t[1:]); g
|
1416
|
+
T2*(O,2)*; GQ(3, 1): Graph on 16 vertices
|
1417
|
+
sage: g.is_strongly_regular(parameters=True)
|
1418
|
+
(16, 6, 2, 2)
|
1419
|
+
sage: t = is_GQqmqp(64,18,2,6); t
|
1420
|
+
(<function T2starGeneralizedQuadrangleGraph at ...>, 4, False)
|
1421
|
+
sage: g = t[0](*t[1:]); g
|
1422
|
+
T2*(O,4); GQ(3, 5): Graph on 64 vertices
|
1423
|
+
sage: g.is_strongly_regular(parameters=True)
|
1424
|
+
(64, 18, 2, 6)
|
1425
|
+
|
1426
|
+
TESTS::
|
1427
|
+
|
1428
|
+
sage: # needs sage.libs.pari
|
1429
|
+
sage: (S,T) = (127,129)
|
1430
|
+
sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t
|
1431
|
+
(<function T2starGeneralizedQuadrangleGraph at ...>, 128, False)
|
1432
|
+
sage: (S,T) = (129,127)
|
1433
|
+
sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t
|
1434
|
+
(<function T2starGeneralizedQuadrangleGraph at ...>, 128, True)
|
1435
|
+
sage: (S,T) = (124,126)
|
1436
|
+
sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t
|
1437
|
+
(<function AhrensSzekeresGeneralizedQuadrangleGraph at ...>, 125, False)
|
1438
|
+
sage: (S,T) = (126,124)
|
1439
|
+
sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t
|
1440
|
+
(<function AhrensSzekeresGeneralizedQuadrangleGraph at ...>, 125, True)
|
1441
|
+
sage: t = is_GQqmqp(5,5,5,5); t
|
1442
|
+
"""
|
1443
|
+
# do we have GQ(s,t)? we must have mu=t+1, s=l+1,
|
1444
|
+
# v=(s+1)(st+1), k=s(t+1)
|
1445
|
+
S = l + 1
|
1446
|
+
T = mu - 1
|
1447
|
+
q = (S+T)//2
|
1448
|
+
p, w = is_prime_power(q, get_data=True)
|
1449
|
+
if (v == (S+1)*(S*T+1) and
|
1450
|
+
k == S*(T+1) and
|
1451
|
+
q == p**w and
|
1452
|
+
(S+T)//2 == q):
|
1453
|
+
if p % 2 == 0:
|
1454
|
+
from sage.graphs.generators.classical_geometries\
|
1455
|
+
import T2starGeneralizedQuadrangleGraph as F
|
1456
|
+
else:
|
1457
|
+
from sage.graphs.generators.classical_geometries\
|
1458
|
+
import AhrensSzekeresGeneralizedQuadrangleGraph as F
|
1459
|
+
if (S, T) == (q-1, q+1):
|
1460
|
+
return (F, q, False)
|
1461
|
+
elif (S, T) == (q+1, q-1):
|
1462
|
+
return (F, q, True)
|
1463
|
+
|
1464
|
+
|
1465
|
+
@cached_function
|
1466
|
+
def is_twograph_descendant_of_srg(int v, int k0, int l, int mu):
|
1467
|
+
r"""
|
1468
|
+
Test whether some descendant graph of a s.r.g. is `(v,k_0,\lambda,\mu)`-s.r.g.
|
1469
|
+
|
1470
|
+
We check whether there can exist `(v+1,k,\lambda^*,\mu^*)`-s.r.g. `G` so
|
1471
|
+
that ``self`` is a descendant graph of the regular two-graph specified
|
1472
|
+
by `G`.
|
1473
|
+
Specifically, we must have that `v+1=2(2k-\lambda^*-\mu^*)`, and
|
1474
|
+
`k_0=2(k-\mu^*)`, `\lambda=k+\lambda^*-2\mu^*`, `\mu=k-\mu^*`, which give 2
|
1475
|
+
independent linear conditions, say `k-\mu^*=\mu` and
|
1476
|
+
`\lambda^*-\mu^*=\lambda-\mu`. Further, there is a quadratic relation
|
1477
|
+
`2 k^2-(v+1+4 \mu) k+ 2 v \mu=0`.
|
1478
|
+
|
1479
|
+
If we can construct such `G` then we return a function to build a
|
1480
|
+
`(v,k_0,\lambda,\mu)`-s.r.g. For more information,
|
1481
|
+
see 10.3 in https://www.win.tue.nl/~aeb/2WF02/spectra.pdf
|
1482
|
+
|
1483
|
+
INPUT:
|
1484
|
+
|
1485
|
+
- ``v``, ``k0``, ``l``, ``mu`` -- integers
|
1486
|
+
|
1487
|
+
OUTPUT:
|
1488
|
+
|
1489
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if one
|
1490
|
+
exists and is known, and ``None`` otherwise.
|
1491
|
+
|
1492
|
+
EXAMPLES::
|
1493
|
+
|
1494
|
+
sage: from sage.graphs.strongly_regular_db import is_twograph_descendant_of_srg
|
1495
|
+
sage: t = is_twograph_descendant_of_srg(27, 10, 1, 5); t # needs database_graphs sage.rings.finite_rings
|
1496
|
+
(<...is_twograph_descendant_of_srg...>, (8,))
|
1497
|
+
sage: g = t[0](*t[1:]); g # needs database_graphs sage.rings.finite_rings
|
1498
|
+
descendant of complement(Johnson graph with parameters 8,2) at {0, 1}: Graph on 27 vertices
|
1499
|
+
sage: g.is_strongly_regular(parameters=True) # needs database_graphs sage.rings.finite_rings
|
1500
|
+
(27, 10, 1, 5)
|
1501
|
+
sage: t = is_twograph_descendant_of_srg(5,5,5,5); t
|
1502
|
+
|
1503
|
+
TESTS::
|
1504
|
+
|
1505
|
+
sage: graphs.strongly_regular_graph(279, 150, 85, 75, existence=True) # needs sage.combinat
|
1506
|
+
True
|
1507
|
+
sage: graphs.strongly_regular_graph(279, 150, 85, 75).is_strongly_regular(parameters=True) # optional - gap_package_design internet
|
1508
|
+
(279, 150, 85, 75)
|
1509
|
+
"""
|
1510
|
+
cdef int b, k
|
1511
|
+
if k0 != 2*mu or not v % 2:
|
1512
|
+
return
|
1513
|
+
b = v+1+4*mu
|
1514
|
+
D = sqrt(b**2-16*v*mu)
|
1515
|
+
if int(D) == D:
|
1516
|
+
for kf in [(-D+b)//4, (D+b)//4]:
|
1517
|
+
k = int(kf)
|
1518
|
+
if (k == kf and
|
1519
|
+
strongly_regular_graph(v+1, k, l - 2*mu + k, k - mu, existence=True) is True):
|
1520
|
+
try:
|
1521
|
+
g = strongly_regular_graph_lazy(v+1, k, l - 2*mu + k) # Sage might not know how to build g
|
1522
|
+
|
1523
|
+
def la(*gr):
|
1524
|
+
from sage.combinat.designs.twographs import twograph_descendant
|
1525
|
+
gg = g[0](*gr)
|
1526
|
+
if (gg.name() is None) or (gg.name() == ''):
|
1527
|
+
gg = Graph(gg, name=str((v+1, k, l - 2*mu + k, k - mu))+"-strongly regular graph")
|
1528
|
+
return twograph_descendant(gg, next(gg.vertex_iterator()),
|
1529
|
+
name=True)
|
1530
|
+
return (la, *g[1:])
|
1531
|
+
except RuntimeError:
|
1532
|
+
pass
|
1533
|
+
return
|
1534
|
+
|
1535
|
+
|
1536
|
+
@cached_function
|
1537
|
+
def is_taylor_twograph_srg(int v, int k, int l, int mu):
|
1538
|
+
r"""
|
1539
|
+
Test whether some Taylor two-graph SRG is `(v,k,\lambda,\mu)`-strongly regular.
|
1540
|
+
|
1541
|
+
For more information, see §7E of [BL1984]_.
|
1542
|
+
|
1543
|
+
INPUT:
|
1544
|
+
|
1545
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
1546
|
+
|
1547
|
+
OUTPUT:
|
1548
|
+
|
1549
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph
|
1550
|
+
:func:`TaylorTwographSRG
|
1551
|
+
<sage.graphs.graph_generators.GraphGenerators.TaylorTwographSRG>` if the
|
1552
|
+
parameters match, and ``None`` otherwise.
|
1553
|
+
|
1554
|
+
EXAMPLES::
|
1555
|
+
|
1556
|
+
sage: # needs sage.libs.pari
|
1557
|
+
sage: from sage.graphs.strongly_regular_db import is_taylor_twograph_srg
|
1558
|
+
sage: t = is_taylor_twograph_srg(28, 15, 6, 10); t
|
1559
|
+
(<function TaylorTwographSRG at ...>, 3)
|
1560
|
+
sage: g = t[0](*t[1:]); g
|
1561
|
+
Taylor two-graph SRG: Graph on 28 vertices
|
1562
|
+
sage: g.is_strongly_regular(parameters=True)
|
1563
|
+
(28, 15, 6, 10)
|
1564
|
+
sage: t = is_taylor_twograph_srg(5,5,5,5); t
|
1565
|
+
|
1566
|
+
TESTS::
|
1567
|
+
|
1568
|
+
sage: is_taylor_twograph_srg(730, 369, 168, 205) # needs sage.libs.pari
|
1569
|
+
(<function TaylorTwographSRG at ...>, 9)
|
1570
|
+
"""
|
1571
|
+
r, _ = eigenvalues(v, k, l, mu)
|
1572
|
+
if r is None:
|
1573
|
+
return
|
1574
|
+
p, t = is_prime_power(v-1, get_data=True)
|
1575
|
+
if p**t+1 != v or t % 3 != 0 or p % 2 == 0:
|
1576
|
+
return
|
1577
|
+
q = p**(t//3)
|
1578
|
+
if (k, l, mu) == (q*(q**2+1)//2, (q**2+3)*(q-1)//4, (q**2+1)*(q+1)//4):
|
1579
|
+
from sage.graphs.generators.classical_geometries import TaylorTwographSRG
|
1580
|
+
return (TaylorTwographSRG, q)
|
1581
|
+
return
|
1582
|
+
|
1583
|
+
|
1584
|
+
def is_switch_skewhad(int v, int k, int l, int mu):
|
1585
|
+
r"""
|
1586
|
+
Test whether some ``switch skewhad^2+*`` is `(v,k,\lambda,\mu)`-strongly regular.
|
1587
|
+
|
1588
|
+
The ``switch skewhad^2+*`` graphs appear on `Andries Brouwer's database
|
1589
|
+
<https://www.win.tue.nl/~aeb/graphs/srg/srgtab.html>`__ and are built by
|
1590
|
+
adding an isolated vertex to the complement of
|
1591
|
+
:func:`~sage.graphs.graph_generators.GraphGenerators.SquaredSkewHadamardMatrixGraph`,
|
1592
|
+
and a :meth:`Seidel switching <Graph.seidel_switching>` a set of disjoint
|
1593
|
+
`n`-cocliques.
|
1594
|
+
|
1595
|
+
INPUT:
|
1596
|
+
|
1597
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
1598
|
+
|
1599
|
+
OUTPUT:
|
1600
|
+
|
1601
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if the
|
1602
|
+
parameters match, and ``None`` otherwise.
|
1603
|
+
|
1604
|
+
EXAMPLES::
|
1605
|
+
|
1606
|
+
sage: graphs.strongly_regular_graph(226, 105, 48, 49) # needs sage.combinat sage.modules
|
1607
|
+
switch skewhad^2+*_4: Graph on 226 vertices
|
1608
|
+
|
1609
|
+
TESTS::
|
1610
|
+
|
1611
|
+
sage: from sage.graphs.strongly_regular_db import is_switch_skewhad
|
1612
|
+
sage: t = is_switch_skewhad(5,5,5,5); t # needs sage.combinat sage.modules
|
1613
|
+
"""
|
1614
|
+
from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix
|
1615
|
+
from sage.graphs.generators.families import SwitchedSquaredSkewHadamardMatrixGraph
|
1616
|
+
cdef int n
|
1617
|
+
r, s = eigenvalues(v, k, l, mu)
|
1618
|
+
if r is None:
|
1619
|
+
return
|
1620
|
+
if r < s:
|
1621
|
+
r, s = s, r
|
1622
|
+
n = -s // 2
|
1623
|
+
if (int(r) == 2*n-1 and
|
1624
|
+
v == (4*n-1)**2 + 1 and
|
1625
|
+
k == (4*n-1)*(2*n-1) and
|
1626
|
+
skew_hadamard_matrix(4*n, existence=True) is True):
|
1627
|
+
return (SwitchedSquaredSkewHadamardMatrixGraph, n)
|
1628
|
+
|
1629
|
+
|
1630
|
+
def is_switch_OA_srg(int v, int k, int l, int mu):
|
1631
|
+
r"""
|
1632
|
+
Test whether some *switch* `OA(k,n)+*` is `(v,k,\lambda,\mu)`-strongly regular.
|
1633
|
+
|
1634
|
+
The "switch* `OA(k,n)+*` graphs appear on `Andries Brouwer's database
|
1635
|
+
<https://www.win.tue.nl/~aeb/graphs/srg/srgtab.html>`__ and are built by
|
1636
|
+
adding an isolated vertex to a
|
1637
|
+
:meth:`~sage.graphs.graph_generators.GraphGenerators.OrthogonalArrayBlockGraph`,
|
1638
|
+
and a :meth:`Seidel switching <Graph.seidel_switching>` a set of disjoint
|
1639
|
+
`n`-cocliques.
|
1640
|
+
|
1641
|
+
INPUT:
|
1642
|
+
|
1643
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
1644
|
+
|
1645
|
+
OUTPUT:
|
1646
|
+
|
1647
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if the
|
1648
|
+
parameters match, and ``None`` otherwise.
|
1649
|
+
|
1650
|
+
EXAMPLES::
|
1651
|
+
|
1652
|
+
sage: graphs.strongly_regular_graph(170, 78, 35, 36) # indirect doctest # needs sage.combinat sage.modules
|
1653
|
+
Graph on 170 vertices
|
1654
|
+
|
1655
|
+
TESTS::
|
1656
|
+
|
1657
|
+
sage: from sage.graphs.strongly_regular_db import is_switch_OA_srg
|
1658
|
+
sage: t = is_switch_OA_srg(5,5,5,5); t
|
1659
|
+
sage: t = is_switch_OA_srg(170, 78, 35, 36) # needs sage.schemes
|
1660
|
+
sage: t[0](*t[1:]).is_strongly_regular(parameters=True) # needs sage.schemes
|
1661
|
+
(170, 78, 35, 36)
|
1662
|
+
sage: t = is_switch_OA_srg(290, 136, 63, 64) # needs sage.schemes
|
1663
|
+
sage: t[0](*t[1:]).is_strongly_regular(parameters=True) # needs sage.schemes
|
1664
|
+
(290, 136, 63, 64)
|
1665
|
+
sage: is_switch_OA_srg(626, 300, 143, 144) # needs sage.schemes
|
1666
|
+
(<...switch_OA_srg..., 12, 25)
|
1667
|
+
sage: is_switch_OA_srg(842, 406, 195, 196) # needs sage.schemes
|
1668
|
+
(<...switch_OA_srg..., 14, 29)
|
1669
|
+
"""
|
1670
|
+
cdef int n_2_p_1 = v
|
1671
|
+
cdef int n = <int> floor(sqrt(n_2_p_1 - 1))
|
1672
|
+
|
1673
|
+
if n*n != n_2_p_1 - 1: # is it a square?
|
1674
|
+
return None
|
1675
|
+
|
1676
|
+
cdef int c = k//n
|
1677
|
+
if (k % n or l != c*c-1 or k != 1+(c-1)*(c+1)+(n-c)*(n-c-1) or
|
1678
|
+
orthogonal_array(c+1, n, existence=True, resolvable=True) is not True):
|
1679
|
+
return None
|
1680
|
+
|
1681
|
+
def switch_OA_srg(c, n):
|
1682
|
+
OA = [tuple(x) for x in orthogonal_array(c+1, n, resolvable=True)]
|
1683
|
+
g = Graph([OA, lambda x, y: any(xx == yy for xx, yy in zip(x, y))],
|
1684
|
+
loops=False)
|
1685
|
+
g.add_vertex(0)
|
1686
|
+
g.seidel_switching(OA[:c*n])
|
1687
|
+
return g
|
1688
|
+
|
1689
|
+
return (switch_OA_srg, c, n)
|
1690
|
+
|
1691
|
+
|
1692
|
+
def is_nowhere0_twoweight(int v, int k, int l, int mu):
|
1693
|
+
r"""
|
1694
|
+
Test whether some graph of nowhere 0 words is `(v,k,\lambda,\mu)`-strongly regular.
|
1695
|
+
|
1696
|
+
Test whether a :meth:`~sage.graphs.graph_generators.GraphGenerators.Nowhere0WordsTwoWeightCodeGraph`
|
1697
|
+
is `(v,k,\lambda,\mu)`-strongly regular.
|
1698
|
+
|
1699
|
+
INPUT:
|
1700
|
+
|
1701
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
1702
|
+
|
1703
|
+
OUTPUT:
|
1704
|
+
|
1705
|
+
A tuple ``t`` such that ``t[0](*t[1:])`` builds the requested graph if the
|
1706
|
+
parameters match, and ``None`` otherwise.
|
1707
|
+
|
1708
|
+
EXAMPLES::
|
1709
|
+
|
1710
|
+
sage: graphs.strongly_regular_graph(196, 60, 14, 20) # needs sage.combinat sage.modules
|
1711
|
+
Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices
|
1712
|
+
|
1713
|
+
TESTS::
|
1714
|
+
|
1715
|
+
sage: from sage.graphs.strongly_regular_db import is_nowhere0_twoweight
|
1716
|
+
sage: t = is_nowhere0_twoweight(1800, 728, 268, 312); t # needs sage.libs.pari
|
1717
|
+
(<function Nowhere0WordsTwoWeightCodeGraph at ...>, 16)
|
1718
|
+
sage: t = is_nowhere0_twoweight(5,5,5,5); t # needs sage.libs.pari
|
1719
|
+
"""
|
1720
|
+
from sage.graphs.generators.classical_geometries import Nowhere0WordsTwoWeightCodeGraph
|
1721
|
+
cdef int q
|
1722
|
+
r, s = eigenvalues(v, k, l, mu)
|
1723
|
+
if r is None:
|
1724
|
+
return
|
1725
|
+
if r < s:
|
1726
|
+
r, s = s, r
|
1727
|
+
q = r*2
|
1728
|
+
if (q > 4 and is_prime_power(q) and not r % 2 and
|
1729
|
+
v == r*(q-1)**2 and
|
1730
|
+
4*k == q*(q-2)*(q-3) and
|
1731
|
+
8*mu == q*(q-3)*(q-4)):
|
1732
|
+
return (Nowhere0WordsTwoWeightCodeGraph, q)
|
1733
|
+
|
1734
|
+
|
1735
|
+
cdef eigenvalues(int v, int k, int l, int mu):
|
1736
|
+
r"""
|
1737
|
+
Return the eigenvalues of a (v,k,l,mu)-strongly regular graph.
|
1738
|
+
|
1739
|
+
If the set of parameters is not feasible, or if they correspond to a
|
1740
|
+
conference graph, the function returns ``(None,None)``. Otherwise
|
1741
|
+
it returns the pair [r,s] of eigenvalues, satisfying r>s.
|
1742
|
+
|
1743
|
+
INPUT:
|
1744
|
+
|
1745
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
1746
|
+
"""
|
1747
|
+
# See 1.3.1 of [Distance-regular graphs]
|
1748
|
+
b = (mu-l)
|
1749
|
+
c = (mu-k)
|
1750
|
+
D = b**2-4*c
|
1751
|
+
if not is_square(D):
|
1752
|
+
return [None, None]
|
1753
|
+
return [(-b+sqrt(D))/2.0,
|
1754
|
+
(-b-sqrt(D))/2.0]
|
1755
|
+
|
1756
|
+
|
1757
|
+
def eigenmatrix(int v, int k, int l, int mu):
|
1758
|
+
r"""
|
1759
|
+
Return the first eigenmatrix of a `(v,k,l,mu)`-strongly regular graph.
|
1760
|
+
|
1761
|
+
The adjacency matrix `A` of an s.r.g. commutes with the adjacency matrix
|
1762
|
+
`A'=J-A-I` of its complement (here `J` is all-1 matrix, and `I` the identity
|
1763
|
+
matrix). Thus, they can be simultaneously diagonalized and so `A` and `A'`
|
1764
|
+
share eigenspaces.
|
1765
|
+
|
1766
|
+
The eigenvalues of `J` are `v` with multiplicity 1, and 0 with multiplicity
|
1767
|
+
`v-1`. Thus the eigenvalue of `A'` corresponding to the 1-dimension
|
1768
|
+
`k`-eigenspace of `A` is `v-k-1`. Respectively, the eigenvalues of `A'`
|
1769
|
+
corresponding to `t`-eigenspace of `A`, with `t` unequal to `k`, equals
|
1770
|
+
`-t-1`. The 1st eigenmatrix `P` of the C-algebra `C[A]` generated by `A`
|
1771
|
+
encodes this eigenvalue information in its three columns;
|
1772
|
+
the 2nd (resp. 3rd)
|
1773
|
+
column contains distinct eigenvalues of `A` (resp. of `A'`), and the 1st
|
1774
|
+
column contains the corresponding eigenvalues of `I`. The matrix `vP^{-1}`
|
1775
|
+
is called the 2nd eigenvalue matrix of `C[A]`.
|
1776
|
+
|
1777
|
+
The most interesting feature of `vP^{-1}` is that it is the 1st eigenmatrix
|
1778
|
+
of the dual of `C[A]` if the dual is generated by the adjacency matrix of a
|
1779
|
+
strongly regular graph. See [BH2012]_ and [BI1984]_ for details.
|
1780
|
+
|
1781
|
+
If the set of parameters is not feasible, or if they correspond to a
|
1782
|
+
conference graph, the function returns ``None``. Its output is stable, assuming
|
1783
|
+
that the eigenvalues r,s used satisfy r>s; this holds for the current
|
1784
|
+
implementation of eigenvalues().
|
1785
|
+
|
1786
|
+
INPUT:
|
1787
|
+
|
1788
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
1789
|
+
|
1790
|
+
EXAMPLES:
|
1791
|
+
|
1792
|
+
Petersen's graph's C-algebra does not have a dual coming from an s.r.g.::
|
1793
|
+
|
1794
|
+
sage: from sage.graphs.strongly_regular_db import eigenmatrix
|
1795
|
+
sage: P = eigenmatrix(10,3,0,1); P # needs sage.modules
|
1796
|
+
[ 1 3 6]
|
1797
|
+
[ 1 1 -2]
|
1798
|
+
[ 1 -2 1]
|
1799
|
+
sage: 10*P^-1 # needs sage.modules
|
1800
|
+
[ 1 5 4]
|
1801
|
+
[ 1 5/3 -8/3]
|
1802
|
+
[ 1 -5/3 2/3]
|
1803
|
+
|
1804
|
+
The line graph of `K_{3,3}` is self-dual::
|
1805
|
+
|
1806
|
+
sage: P = eigenmatrix(9,4,1,2); P # needs sage.modules
|
1807
|
+
[ 1 4 4]
|
1808
|
+
[ 1 1 -2]
|
1809
|
+
[ 1 -2 1]
|
1810
|
+
sage: 9*P^-1 # needs sage.modules
|
1811
|
+
[ 1 4 4]
|
1812
|
+
[ 1 1 -2]
|
1813
|
+
[ 1 -2 1]
|
1814
|
+
|
1815
|
+
A strongly regular graph with a non-isomorphic dual coming from another
|
1816
|
+
strongly regular graph::
|
1817
|
+
|
1818
|
+
sage: # needs sage.modules
|
1819
|
+
sage: graphs.strongly_regular_graph(243,220,199,200, existence=True) # needs sage.combinat
|
1820
|
+
True
|
1821
|
+
sage: graphs.strongly_regular_graph(243,110,37,60, existence=True) # needs sage.combinat
|
1822
|
+
True
|
1823
|
+
sage: P = eigenmatrix(243,220,199,200); P
|
1824
|
+
[ 1 220 22]
|
1825
|
+
[ 1 4 -5]
|
1826
|
+
[ 1 -5 4]
|
1827
|
+
sage: 243*P^-1
|
1828
|
+
[ 1 110 132]
|
1829
|
+
[ 1 2 -3]
|
1830
|
+
[ 1 -25 24]
|
1831
|
+
sage: 243*P^-1==eigenmatrix(243,110,37,60)
|
1832
|
+
True
|
1833
|
+
|
1834
|
+
TESTS::
|
1835
|
+
|
1836
|
+
sage: eigenmatrix(5,5,5,-5)
|
1837
|
+
"""
|
1838
|
+
from sage.rings.integer_ring import ZZ
|
1839
|
+
r, s = eigenvalues(v, k, l, mu)
|
1840
|
+
if r is not None:
|
1841
|
+
return Matrix(ZZ, [[1, k, v-k-1], [1, r, -r-1], [1, s, -s-1]])
|
1842
|
+
|
1843
|
+
|
1844
|
+
cpdef latin_squares_graph_parameters(int v, int k, int l, int mu):
|
1845
|
+
r"""
|
1846
|
+
Check whether (v,k,l,mu)-strongly regular graph has parameters of an `L_g(n)` s.r.g.
|
1847
|
+
|
1848
|
+
Also known as pseudo-OA(n,g) case, i.e. s.r.g. with parameters of an OA(n,g)-graph.
|
1849
|
+
Return g and n, if they exist. See Sect. 9.1 of [BH2012]_ for details.
|
1850
|
+
|
1851
|
+
INPUT:
|
1852
|
+
|
1853
|
+
- ``v``, ``k``, ``l``, ``mu`` -- - (integrs) parameters of the graph
|
1854
|
+
|
1855
|
+
OUTPUT:
|
1856
|
+
|
1857
|
+
- ``(g, n)`` -- parameters of an `L_g(n)` graph, or ``None``
|
1858
|
+
|
1859
|
+
TESTS::
|
1860
|
+
|
1861
|
+
sage: from sage.graphs.strongly_regular_db import latin_squares_graph_parameters
|
1862
|
+
sage: latin_squares_graph_parameters(9,4,1,2)
|
1863
|
+
(2, 3)
|
1864
|
+
sage: latin_squares_graph_parameters(5,4,1,2)
|
1865
|
+
"""
|
1866
|
+
cdef int g, n
|
1867
|
+
r, s = eigenvalues(v, k, l, mu)
|
1868
|
+
if r is None:
|
1869
|
+
return
|
1870
|
+
if r < s:
|
1871
|
+
r, s = s, r
|
1872
|
+
g = -s
|
1873
|
+
n = r+g
|
1874
|
+
if v == n**2 and k == g*(n-1) and l == (g-1)*(g-2)+n-2 and mu == g*(g-1):
|
1875
|
+
return g, n
|
1876
|
+
return
|
1877
|
+
|
1878
|
+
|
1879
|
+
def _H_3_cayley_graph(L):
|
1880
|
+
r"""
|
1881
|
+
Return the `L`-Cayley graph of the group `H_3` from Prop. 12 in [JK2003]_.
|
1882
|
+
|
1883
|
+
INPUT:
|
1884
|
+
|
1885
|
+
- the list of words for the generating set in the format ["abc",...,"xyz"] for
|
1886
|
+
a,b,...,z being integers between 0 and 4.
|
1887
|
+
|
1888
|
+
TESTS::
|
1889
|
+
|
1890
|
+
sage: from sage.graphs.strongly_regular_db import _H_3_cayley_graph
|
1891
|
+
sage: _H_3_cayley_graph(["100","110","130","140","200","230","240","300"]) # needs sage.groups
|
1892
|
+
Graph on 100 vertices
|
1893
|
+
"""
|
1894
|
+
from sage.groups.free_group import FreeGroup
|
1895
|
+
from sage.groups.finitely_presented import FinitelyPresentedGroup
|
1896
|
+
G = FreeGroup('x,y,z')
|
1897
|
+
x, y, z = G.gens()
|
1898
|
+
rels = (x**5, y**5, z**4, x*y*x**(-1)*y**(-1), z*x*z**(-1)*x**(-2), z*y*z**(-1)*y**(-2))
|
1899
|
+
G = FinitelyPresentedGroup(G, rels)
|
1900
|
+
x, y, z = G.gens()
|
1901
|
+
H = G.as_permutation_group()
|
1902
|
+
L = [[int(u) for u in x] for x in L]
|
1903
|
+
x, y, z = (H.gen(0), H.gen(1), H.gen(2))
|
1904
|
+
L = [H(x**xx*y**yy*z**zz) for xx, yy, zz in L]
|
1905
|
+
return Graph(H.cayley_graph(generators=L, simple=True))
|
1906
|
+
|
1907
|
+
|
1908
|
+
def SRG_100_44_18_20():
|
1909
|
+
r"""
|
1910
|
+
Return a `(100, 44, 18, 20)`-strongly regular graph.
|
1911
|
+
|
1912
|
+
This graph is built as a Cayley graph, using the construction for `\Delta_1`
|
1913
|
+
with group `H_3` presented in Table 8.1 of [JK2003]_
|
1914
|
+
|
1915
|
+
EXAMPLES::
|
1916
|
+
|
1917
|
+
sage: from sage.graphs.strongly_regular_db import SRG_100_44_18_20
|
1918
|
+
sage: G = SRG_100_44_18_20() # long time # needs sage.groups
|
1919
|
+
sage: G.is_strongly_regular(parameters=True) # long time # needs sage.groups
|
1920
|
+
(100, 44, 18, 20)
|
1921
|
+
"""
|
1922
|
+
L = ['100', '110', '130', '140', '200', '230', '240', '300', '310', '320',
|
1923
|
+
'400', '410', '420', '440', '041', '111', '221', '231', '241', '321',
|
1924
|
+
'331', '401', '421', '441', '002', '042', '112', '122', '142', '212',
|
1925
|
+
'232', '242', '322', '342', '033', '113', '143', '223', '303', '333',
|
1926
|
+
'343', '413', '433', '443']
|
1927
|
+
return _H_3_cayley_graph(L)
|
1928
|
+
|
1929
|
+
|
1930
|
+
def SRG_100_45_20_20():
|
1931
|
+
r"""
|
1932
|
+
Return a `(100, 45, 20, 20)`-strongly regular graph.
|
1933
|
+
|
1934
|
+
This graph is built as a Cayley graph, using the construction for `\Gamma_3`
|
1935
|
+
with group `H_3` presented in Table 8.1 of [JK2003]_.
|
1936
|
+
|
1937
|
+
EXAMPLES::
|
1938
|
+
|
1939
|
+
sage: from sage.graphs.strongly_regular_db import SRG_100_45_20_20
|
1940
|
+
sage: G = SRG_100_45_20_20() # long time # needs sage.groups
|
1941
|
+
sage: G.is_strongly_regular(parameters=True) # long time # needs sage.groups
|
1942
|
+
(100, 45, 20, 20)
|
1943
|
+
"""
|
1944
|
+
L = ['120', '140', '200', '210', '201', '401', '411', '321', '002', '012',
|
1945
|
+
'022', '042', '303', '403', '013', '413', '240', '031', '102', '323',
|
1946
|
+
'300', '231', '132', '133', '310', '141', '142', '233', '340', '241',
|
1947
|
+
'202', '333', '410', '341', '222', '433', '430', '441', '242', '302',
|
1948
|
+
'312', '322', '332', '442', '143']
|
1949
|
+
return _H_3_cayley_graph(L)
|
1950
|
+
|
1951
|
+
|
1952
|
+
def SRG_105_32_4_12():
|
1953
|
+
r"""
|
1954
|
+
Return a `(105, 32, 4, 12)`-strongly regular graph.
|
1955
|
+
|
1956
|
+
The vertices are the flags of the projective plane of order 4. Two flags
|
1957
|
+
`(a,A)` and `(b,B)` are adjacent if the point `a` is on the line `B` or
|
1958
|
+
the point `b` is on the line `A`, and `a \neq b`, `A \neq B`. See
|
1959
|
+
Theorem 2.7 in [GS1970]_, and [Coo2006]_.
|
1960
|
+
|
1961
|
+
EXAMPLES::
|
1962
|
+
|
1963
|
+
sage: from sage.graphs.strongly_regular_db import SRG_105_32_4_12
|
1964
|
+
sage: G = SRG_105_32_4_12(); G # needs sage.groups sage.rings.finite_rings
|
1965
|
+
Aut L(3,4) on flags: Graph on 105 vertices
|
1966
|
+
sage: G.is_strongly_regular(parameters=True) # needs sage.groups sage.rings.finite_rings
|
1967
|
+
(105, 32, 4, 12)
|
1968
|
+
"""
|
1969
|
+
from sage.combinat.designs.block_design import ProjectiveGeometryDesign
|
1970
|
+
P = ProjectiveGeometryDesign(2, 1, GF(4, 'a'))
|
1971
|
+
IG = P.incidence_graph().line_graph()
|
1972
|
+
a = IG.automorphism_group()
|
1973
|
+
h = a.stabilizer(a.domain()[0])
|
1974
|
+
o = next(x for x in h.orbits() if len(x) == 32)[0]
|
1975
|
+
e = a.orbit((a.domain()[0], o), action='OnSets')
|
1976
|
+
G = Graph()
|
1977
|
+
G.add_edges(e)
|
1978
|
+
G.name('Aut L(3,4) on flags')
|
1979
|
+
return G
|
1980
|
+
|
1981
|
+
|
1982
|
+
def SRG_120_77_52_44():
|
1983
|
+
r"""
|
1984
|
+
Return a `(120,77,52,44)`-strongly regular graph.
|
1985
|
+
|
1986
|
+
To build this graph, we first build a `2-(21,7,12)` design, by removing two
|
1987
|
+
points from the :func:`~sage.combinat.designs.block_design.WittDesign` on 23
|
1988
|
+
points. We then build the intersection graph of blocks with intersection
|
1989
|
+
size 3.
|
1990
|
+
|
1991
|
+
EXAMPLES::
|
1992
|
+
|
1993
|
+
sage: from sage.graphs.strongly_regular_db import SRG_120_77_52_44
|
1994
|
+
sage: G = SRG_120_77_52_44() # optional - gap_package_design
|
1995
|
+
sage: G.is_strongly_regular(parameters=True) # optional - gap_package_design
|
1996
|
+
(120, 77, 52, 44)
|
1997
|
+
"""
|
1998
|
+
from sage.combinat.designs.block_design import WittDesign
|
1999
|
+
from sage.combinat.designs.incidence_structures import IncidenceStructure
|
2000
|
+
W = WittDesign(23)
|
2001
|
+
H = IncidenceStructure([x for x in W if 22 not in x and 21 not in x])
|
2002
|
+
g = H.intersection_graph(3)
|
2003
|
+
g.name('PG(2,2)s in PG(2,4)')
|
2004
|
+
return g
|
2005
|
+
|
2006
|
+
|
2007
|
+
def SRG_144_39_6_12():
|
2008
|
+
r"""
|
2009
|
+
Return a `(144,39,6,12)`-strongly regular graph.
|
2010
|
+
|
2011
|
+
This graph is obtained as an orbit of length 2808 on sets of cardinality 2
|
2012
|
+
(among 2 such orbits) of the group `PGL_3(3)` acting on the (right) cosets of
|
2013
|
+
a subgroup of order 39.
|
2014
|
+
|
2015
|
+
EXAMPLES::
|
2016
|
+
|
2017
|
+
sage: from sage.graphs.strongly_regular_db import SRG_144_39_6_12
|
2018
|
+
sage: G = SRG_144_39_6_12() # needs sage.libs.gap
|
2019
|
+
sage: G.is_strongly_regular(parameters=True) # needs sage.libs.gap
|
2020
|
+
(144, 39, 6, 12)
|
2021
|
+
"""
|
2022
|
+
from sage.libs.gap.libgap import libgap
|
2023
|
+
g = libgap.ProjectiveGeneralLinearGroup(3, 3)
|
2024
|
+
ns = g.Normalizer(g.SylowSubgroup(13))
|
2025
|
+
G = g.Action(g.RightCosets(ns), libgap.OnRight)
|
2026
|
+
H = G.Stabilizer(1)
|
2027
|
+
for o in H.Orbits():
|
2028
|
+
if len(o) != 39:
|
2029
|
+
continue
|
2030
|
+
h = Graph()
|
2031
|
+
h.add_edges(G.Orbit([1, o[0]], libgap.OnSets))
|
2032
|
+
if h.is_strongly_regular():
|
2033
|
+
h.relabel()
|
2034
|
+
h.name('PGL_3(3) on cosets of 13:3')
|
2035
|
+
return h
|
2036
|
+
|
2037
|
+
|
2038
|
+
def SRG_176_49_12_14():
|
2039
|
+
r"""
|
2040
|
+
Return a `(176,49,12,14)`-strongly regular graph.
|
2041
|
+
|
2042
|
+
This graph is built from the symmetric Higman-Sims design. In
|
2043
|
+
[Bro1982]_, it is explained that there exists an involution
|
2044
|
+
`\sigma` exchanging the points and blocks of the Higman-Sims design, such
|
2045
|
+
that each point is mapped on a block that contains it (i.e. `\sigma` is a
|
2046
|
+
'polarity with all universal points'). The graph is then built by making two
|
2047
|
+
vertices `u,v` adjacent whenever `v\in \sigma(u)`.
|
2048
|
+
|
2049
|
+
EXAMPLES::
|
2050
|
+
|
2051
|
+
sage: from sage.graphs.strongly_regular_db import SRG_176_49_12_14
|
2052
|
+
sage: G = SRG_176_49_12_14() # long time, optional - gap_package_design
|
2053
|
+
sage: G.is_strongly_regular(parameters=True) # long time, optional - gap_package_design
|
2054
|
+
(176, 49, 12, 14)
|
2055
|
+
"""
|
2056
|
+
from sage.combinat.designs.database import HigmanSimsDesign
|
2057
|
+
d = HigmanSimsDesign()
|
2058
|
+
g = d.incidence_graph(labels=True)
|
2059
|
+
ag = g.automorphism_group().conjugacy_classes_representatives()
|
2060
|
+
|
2061
|
+
# Looking for an involution that maps a point of the design to one of the
|
2062
|
+
# blocks that contains it. It is called a polarity with only absolute
|
2063
|
+
# points.
|
2064
|
+
for aut in ag:
|
2065
|
+
try:
|
2066
|
+
0 in aut(0)
|
2067
|
+
except TypeError:
|
2068
|
+
continue
|
2069
|
+
if (aut.order() == 2 and
|
2070
|
+
all(i in aut(i) for i in d.ground_set())):
|
2071
|
+
g = Graph()
|
2072
|
+
g.add_edges(((u, v) for u in d.ground_set() for v in aut(u)), loops=False)
|
2073
|
+
g.name('Higman symmetric 2-design')
|
2074
|
+
return g
|
2075
|
+
|
2076
|
+
|
2077
|
+
def SRG_176_105_68_54():
|
2078
|
+
r"""
|
2079
|
+
Return a `(176, 105, 68, 54)`-strongly regular graph.
|
2080
|
+
|
2081
|
+
To build this graph, we first build a `2-(22,7,16)` design, by removing one
|
2082
|
+
point from the :func:`~sage.combinat.designs.block_design.WittDesign` on 23
|
2083
|
+
points. We then build the intersection graph of blocks with intersection
|
2084
|
+
size 3. Known as S.7 in [Hub1975]_.
|
2085
|
+
|
2086
|
+
EXAMPLES::
|
2087
|
+
|
2088
|
+
sage: from sage.graphs.strongly_regular_db import SRG_176_105_68_54
|
2089
|
+
sage: G = SRG_176_105_68_54() # optional - gap_package_design
|
2090
|
+
sage: G.is_strongly_regular(parameters=True) # optional - gap_package_design
|
2091
|
+
(176, 105, 68, 54)
|
2092
|
+
"""
|
2093
|
+
from sage.combinat.designs.block_design import WittDesign
|
2094
|
+
from sage.combinat.designs.incidence_structures import IncidenceStructure
|
2095
|
+
W = WittDesign(23)
|
2096
|
+
H = IncidenceStructure([x for x in W if 22 not in x])
|
2097
|
+
g = H.intersection_graph(3)
|
2098
|
+
g.name('Witt 3-(22,7,4)')
|
2099
|
+
return g
|
2100
|
+
|
2101
|
+
|
2102
|
+
def SRG_210_99_48_45():
|
2103
|
+
r"""
|
2104
|
+
Return a strongly regular graph with parameters `(210, 99, 48, 45)`.
|
2105
|
+
|
2106
|
+
This graph is from Example 4.2 in [KPRWZ2010]_. One considers the action of
|
2107
|
+
the symmetric group `S_7` on the 210 digraphs isomorphic to the
|
2108
|
+
disjoint union of `K_1` and the circulant 6-vertex digraph
|
2109
|
+
``digraphs.Circulant(6,[1,4])``. It has 16 orbitals; the package [FK1991]_
|
2110
|
+
found a megring of them, explicitly described in [KPRWZ2010]_, resulting in
|
2111
|
+
this graph.
|
2112
|
+
|
2113
|
+
EXAMPLES::
|
2114
|
+
|
2115
|
+
sage: from sage.graphs.strongly_regular_db import SRG_210_99_48_45
|
2116
|
+
sage: g = SRG_210_99_48_45() # needs sage.libs.gap
|
2117
|
+
sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap
|
2118
|
+
(210, 99, 48, 45)
|
2119
|
+
"""
|
2120
|
+
from sage.libs.gap.libgap import libgap
|
2121
|
+
from sage.combinat.permutation import Permutation
|
2122
|
+
|
2123
|
+
def ekg(g0):
|
2124
|
+
# return arcs of the Cayley digraph of <g> on {g,g^4}
|
2125
|
+
g = Permutation(g0)
|
2126
|
+
return libgap.Set([(x, g(x)) for x in range(1, 8)] +
|
2127
|
+
[(x, g(g(g(g(x))))) for x in range(1, 8)])
|
2128
|
+
|
2129
|
+
kd = list(map(ekg,
|
2130
|
+
[(7, 1, 2, 3, 4, 5), (7, 1, 3, 4, 5, 6),
|
2131
|
+
(7, 3, 4, 5, 6, 2), (7, 1, 4, 3, 5, 6),
|
2132
|
+
(7, 3, 1, 4, 5, 6), (7, 2, 4, 3, 5, 6),
|
2133
|
+
(7, 3, 2, 4, 5, 1), (7, 2, 4, 3, 5, 1)]))
|
2134
|
+
s = libgap.SymmetricGroup(7)
|
2135
|
+
O = s.Orbit(kd[0], libgap.OnSetsTuples)
|
2136
|
+
sa = s.Action(O, libgap.OnSetsTuples)
|
2137
|
+
G = Graph()
|
2138
|
+
for g in kd[1:]:
|
2139
|
+
G.add_edges(libgap.Orbit(sa, [libgap.Position(O, kd[0]),
|
2140
|
+
libgap.Position(O, g)], libgap.OnSets))
|
2141
|
+
G.name('merging of S_7 on Circulant(6,[1,4])s')
|
2142
|
+
return G
|
2143
|
+
|
2144
|
+
|
2145
|
+
def SRG_243_110_37_60():
|
2146
|
+
r"""
|
2147
|
+
Return a `(243, 110, 37, 60)`-strongly regular graph.
|
2148
|
+
|
2149
|
+
Consider the orthogonal complement of the
|
2150
|
+
:func:`~sage.coding.code_constructions.TernaryGolayCode`, which has 243
|
2151
|
+
words. On them we define a graph, in which two words are adjacent
|
2152
|
+
whenever their Hamming distance is 9. This construction appears in
|
2153
|
+
[GS1975]_.
|
2154
|
+
|
2155
|
+
.. NOTE::
|
2156
|
+
|
2157
|
+
A strongly regular graph with the same parameters is also obtained from
|
2158
|
+
the database of 2-weight codes.
|
2159
|
+
|
2160
|
+
EXAMPLES::
|
2161
|
+
|
2162
|
+
sage: from sage.graphs.strongly_regular_db import SRG_243_110_37_60
|
2163
|
+
sage: G = SRG_243_110_37_60() # needs sage.modules sage.rings.finite_rings
|
2164
|
+
sage: G.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings
|
2165
|
+
(243, 110, 37, 60)
|
2166
|
+
"""
|
2167
|
+
from sage.coding.golay_code import GolayCode
|
2168
|
+
M = GolayCode(GF(3), False).generator_matrix()
|
2169
|
+
V = list(M.right_kernel())
|
2170
|
+
g = Graph([list(range(len(V))), lambda x, y: (V[x] - V[y]).hamming_weight() == 9])
|
2171
|
+
g.name('Ternary Golay code')
|
2172
|
+
return g
|
2173
|
+
|
2174
|
+
|
2175
|
+
def SRG_253_140_87_65():
|
2176
|
+
r"""
|
2177
|
+
Return a `(253, 140, 87, 65)`-strongly regular graph.
|
2178
|
+
|
2179
|
+
To build this graph, we first build the
|
2180
|
+
:func:`~sage.combinat.designs.block_design.WittDesign` on 23 points which is
|
2181
|
+
a `2-(23,7,21)` design. We then build the intersection graph of blocks with
|
2182
|
+
intersection size 3. Known as S.6 in [Hub1975]_.
|
2183
|
+
|
2184
|
+
EXAMPLES::
|
2185
|
+
|
2186
|
+
sage: from sage.graphs.strongly_regular_db import SRG_253_140_87_65
|
2187
|
+
sage: G = SRG_253_140_87_65() # optional - gap_package_design
|
2188
|
+
sage: G.is_strongly_regular(parameters=True) # optional - gap_package_design
|
2189
|
+
(253, 140, 87, 65)
|
2190
|
+
"""
|
2191
|
+
from sage.combinat.designs.block_design import WittDesign
|
2192
|
+
from sage.combinat.designs.incidence_structures import IncidenceStructure
|
2193
|
+
W = WittDesign(23)
|
2194
|
+
g = W.intersection_graph(3)
|
2195
|
+
g.name('Witt 4-(23,7,1)')
|
2196
|
+
return g
|
2197
|
+
|
2198
|
+
|
2199
|
+
def SRG_196_91_42_42():
|
2200
|
+
r"""
|
2201
|
+
Return a `(196,91,42,42)`-strongly regular graph.
|
2202
|
+
|
2203
|
+
This strongly regular graph is built following the construction provided in
|
2204
|
+
Corollary 8.2.27 of [IS2006]_.
|
2205
|
+
|
2206
|
+
EXAMPLES::
|
2207
|
+
|
2208
|
+
sage: from sage.graphs.strongly_regular_db import SRG_196_91_42_42
|
2209
|
+
sage: G = SRG_196_91_42_42()
|
2210
|
+
sage: G.is_strongly_regular(parameters=True)
|
2211
|
+
(196, 91, 42, 42)
|
2212
|
+
"""
|
2213
|
+
from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
|
2214
|
+
from sage.graphs.generators.intersection import IntersectionGraph
|
2215
|
+
k = 7
|
2216
|
+
R = IntegerModRing(91)
|
2217
|
+
A = list(map(R, [0, 10, 27, 28, 31, 43, 50]))
|
2218
|
+
B = list(map(R, [0, 11, 20, 25, 49, 55, 57]))
|
2219
|
+
H = list(map(R, [13 * i for i in range(k)]))
|
2220
|
+
U = list(map(frozenset, [[x + z for x in A] for z in R]))
|
2221
|
+
V = list(map(frozenset, [[x + z for x in B] for z in R]))
|
2222
|
+
W = list(map(frozenset, [[x + z for x in H] for z in R]))
|
2223
|
+
G = IntersectionGraph(U + V + W)
|
2224
|
+
|
2225
|
+
G.seidel_switching(U)
|
2226
|
+
|
2227
|
+
G.add_edges((-1, x) for x in U)
|
2228
|
+
G.relabel(perm={u: i for i, u in enumerate(G)})
|
2229
|
+
G.name('RSHCD+')
|
2230
|
+
return G
|
2231
|
+
|
2232
|
+
|
2233
|
+
def SRG_220_84_38_28():
|
2234
|
+
r"""
|
2235
|
+
Return a `(220, 84, 38, 28)`-strongly regular graph.
|
2236
|
+
|
2237
|
+
This graph is obtained from the
|
2238
|
+
:meth:`~IncidenceStructure.intersection_graph` of a
|
2239
|
+
:func:`~sage.combinat.designs.database.BIBD_45_9_8`. This construction
|
2240
|
+
appears in VII.11.2 from [DesignHandbook]_
|
2241
|
+
|
2242
|
+
EXAMPLES::
|
2243
|
+
|
2244
|
+
sage: from sage.graphs.strongly_regular_db import SRG_220_84_38_28
|
2245
|
+
sage: g = SRG_220_84_38_28()
|
2246
|
+
sage: g.is_strongly_regular(parameters=True)
|
2247
|
+
(220, 84, 38, 28)
|
2248
|
+
"""
|
2249
|
+
from sage.combinat.designs.database import BIBD_45_9_8
|
2250
|
+
from sage.combinat.designs.incidence_structures import IncidenceStructure
|
2251
|
+
G = IncidenceStructure(BIBD_45_9_8()).intersection_graph(3)
|
2252
|
+
G.relabel()
|
2253
|
+
G.name('Tonchev: quasisymmetric 2-(45,9,8)')
|
2254
|
+
return G
|
2255
|
+
|
2256
|
+
|
2257
|
+
def SRG_276_140_58_84():
|
2258
|
+
r"""
|
2259
|
+
Return a `(276, 140, 58, 84)`-strongly regular graph.
|
2260
|
+
|
2261
|
+
The graph is built from
|
2262
|
+
:meth:`~sage.graphs.graph_generators.GraphGenerators.McLaughlinGraph`, with
|
2263
|
+
an added isolated vertex. We then perform a
|
2264
|
+
:meth:`~Graph.seidel_switching` on a set of 28 disjoint 5-cliques, which
|
2265
|
+
exist by cf. [HT1996]_.
|
2266
|
+
|
2267
|
+
EXAMPLES::
|
2268
|
+
|
2269
|
+
sage: from sage.graphs.strongly_regular_db import SRG_276_140_58_84
|
2270
|
+
sage: g = SRG_276_140_58_84() # long time, optional - gap_package_design
|
2271
|
+
sage: g.is_strongly_regular(parameters=True) # long time, optional - gap_package_design
|
2272
|
+
(276, 140, 58, 84)
|
2273
|
+
"""
|
2274
|
+
from sage.graphs.generators.smallgraphs import McLaughlinGraph
|
2275
|
+
g = McLaughlinGraph()
|
2276
|
+
C = [[ 0, 72, 87, 131, 136], [ 1, 35, 61, 102, 168], [ 2, 32, 97, 125, 197], [ 3, 22, 96, 103, 202],
|
2277
|
+
[ 4, 46, 74, 158, 229], [ 5, 83, 93, 242, 261], [ 6, 26, 81, 147, 176], [ 7, 42, 63, 119, 263],
|
2278
|
+
[ 8, 49, 64, 165, 227], [ 9, 70, 85, 208, 273], [10, 73, 92, 230, 268], [11, 54, 95, 184, 269],
|
2279
|
+
[12, 55, 62, 185, 205], [13, 51, 65, 162, 254], [14, 78, 88, 231, 274], [15, 40, 59, 117, 252],
|
2280
|
+
[16, 24, 71, 137, 171], [17, 39, 43, 132, 163], [18, 57, 79, 175, 271], [19, 68, 80, 217, 244],
|
2281
|
+
[20, 75, 98, 239, 267], [21, 33, 56, 113, 240], [23, 127, 152, 164, 172], [25, 101, 128, 183, 264],
|
2282
|
+
[27, 129, 154, 160, 201], [28, 126, 144, 161, 228], [29, 100, 133, 204, 266], [30, 108, 146, 200, 219]]
|
2283
|
+
g.add_vertex(-1)
|
2284
|
+
g.seidel_switching(sum(C, []))
|
2285
|
+
g.relabel()
|
2286
|
+
g.name('Haemers-Tonchev')
|
2287
|
+
return g
|
2288
|
+
|
2289
|
+
|
2290
|
+
def SRG_280_135_70_60():
|
2291
|
+
r"""
|
2292
|
+
Return a strongly regular graph with parameters `(280, 135, 70, 60)`.
|
2293
|
+
|
2294
|
+
This graph is built from the action of `J_2` on the cosets of a `3.PGL(2,9)`-subgroup.
|
2295
|
+
|
2296
|
+
EXAMPLES::
|
2297
|
+
|
2298
|
+
sage: from sage.graphs.strongly_regular_db import SRG_280_135_70_60
|
2299
|
+
sage: g=SRG_280_135_70_60() # long time, optional - internet
|
2300
|
+
sage: g.is_strongly_regular(parameters=True) # long time, optional - internet
|
2301
|
+
(280, 135, 70, 60)
|
2302
|
+
"""
|
2303
|
+
from sage.libs.gap.libgap import libgap
|
2304
|
+
from sage.graphs.graph import Graph
|
2305
|
+
|
2306
|
+
libgap.load_package("AtlasRep")
|
2307
|
+
# A representation of J2 acting on a 3.PGL(2,9) it contains.
|
2308
|
+
J2 = libgap.AtlasGroup("J2", libgap.NrMovedPoints, 280)
|
2309
|
+
edges = J2.Orbit([1, 2], libgap.OnSets)
|
2310
|
+
g = Graph()
|
2311
|
+
g.add_edges(edges)
|
2312
|
+
g.relabel()
|
2313
|
+
g.name('J_2 on cosets of 3.PGL(2,9)')
|
2314
|
+
return g
|
2315
|
+
|
2316
|
+
|
2317
|
+
def SRG_280_117_44_52():
|
2318
|
+
r"""
|
2319
|
+
Return a strongly regular graph with parameters `(280, 117, 44, 52)`.
|
2320
|
+
|
2321
|
+
This graph is built according to a very pretty construction of Mathon and
|
2322
|
+
Rosa [MR1985]_:
|
2323
|
+
|
2324
|
+
The vertices of the graph `G` are all partitions of a set of 9 elements
|
2325
|
+
into `\{\{a,b,c\},\{d,e,f\},\{g,h,i\}\}`. The cross-intersection of two
|
2326
|
+
such partitions `P=\{P_1,P_2,P_3\}` and `P'=\{P'_1,P'_2,P'_3\}` being
|
2327
|
+
defined as `\{P_i \cap P'_j: 1\leq i,j\leq 3\}`, two vertices of `G` are
|
2328
|
+
set to be adjacent if the cross-intersection of their respective
|
2329
|
+
partitions does not contain exactly 7 nonempty sets.
|
2330
|
+
|
2331
|
+
EXAMPLES::
|
2332
|
+
|
2333
|
+
sage: from sage.graphs.strongly_regular_db import SRG_280_117_44_52
|
2334
|
+
sage: g=SRG_280_117_44_52()
|
2335
|
+
sage: g.is_strongly_regular(parameters=True)
|
2336
|
+
(280, 117, 44, 52)
|
2337
|
+
"""
|
2338
|
+
from sage.graphs.hypergraph_generators import hypergraphs
|
2339
|
+
|
2340
|
+
# V is the set of partitions {{a,b,c},{d,e,f},{g,h,i}} of {0,...,8}
|
2341
|
+
H = hypergraphs.CompleteUniform(9, 3)
|
2342
|
+
g = H.intersection_graph()
|
2343
|
+
V = g.complement().cliques_maximal()
|
2344
|
+
V = [frozenset(u) for u in V]
|
2345
|
+
|
2346
|
+
# G is the graph defined on V in which two vertices are adjacent when they
|
2347
|
+
# corresponding partitions cross-intersect on 7 nonempty sets
|
2348
|
+
G = Graph([V, lambda x, y:
|
2349
|
+
sum(any(xxx in yy for xxx in xx) for xx in x for yy in y) != 7],
|
2350
|
+
loops=False)
|
2351
|
+
G.name('Mathon-Rosa')
|
2352
|
+
return G
|
2353
|
+
|
2354
|
+
|
2355
|
+
def strongly_regular_from_two_weight_code(L):
|
2356
|
+
r"""
|
2357
|
+
Return a strongly regular graph from a two-weight code.
|
2358
|
+
|
2359
|
+
A code is said to be a *two-weight* code the weight of its nonzero codewords
|
2360
|
+
(i.e. their number of nonzero coordinates) can only be one of two integer
|
2361
|
+
values `w_1,w_2`. It is said to be *projective* if the minimum weight of the
|
2362
|
+
dual code is `\geq 3`. A strongly regular graph can be built from a
|
2363
|
+
two-weight projective code with weights `w_1,w_2` (assuming `w_1<w_2`) by
|
2364
|
+
adding an edge between any two codewords whose difference has weight
|
2365
|
+
`w_1`. For more information, see [LS1981]_ or [Del1972]_.
|
2366
|
+
|
2367
|
+
INPUT:
|
2368
|
+
|
2369
|
+
- ``L`` -- a two-weight linear code, or its generating matrix
|
2370
|
+
|
2371
|
+
EXAMPLES::
|
2372
|
+
|
2373
|
+
sage: from sage.graphs.strongly_regular_db import strongly_regular_from_two_weight_code
|
2374
|
+
sage: x = ("100022021001111",
|
2375
|
+
....: "010011211122000",
|
2376
|
+
....: "001021112100011",
|
2377
|
+
....: "000110120222220")
|
2378
|
+
sage: M = Matrix(GF(3),[list(l) for l in x]) # needs sage.modules sage.rings.finite_rings
|
2379
|
+
sage: G = strongly_regular_from_two_weight_code(LinearCode(M)) # needs sage.modules sage.rings.finite_rings
|
2380
|
+
sage: G.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings
|
2381
|
+
(81, 50, 31, 30)
|
2382
|
+
"""
|
2383
|
+
from sage.structure.element import Matrix
|
2384
|
+
if isinstance(L, Matrix):
|
2385
|
+
L = LinearCode(L)
|
2386
|
+
V = [tuple(l) for l in L]
|
2387
|
+
w1, _ = sorted(set(sum(map(bool, x)) for x in V).difference([0]))
|
2388
|
+
G = Graph([V, lambda u, v: sum(uu != vv for uu, vv in zip(u, v)) == w1])
|
2389
|
+
G.relabel()
|
2390
|
+
G.name('two-weight code: '+str(L))
|
2391
|
+
return G
|
2392
|
+
|
2393
|
+
|
2394
|
+
def SRG_416_100_36_20():
|
2395
|
+
r"""
|
2396
|
+
Return a `(416,100,36,20)`-strongly regular graph.
|
2397
|
+
|
2398
|
+
This graph is obtained as an orbit on sets of cardinality 2
|
2399
|
+
(among 2 that exists) of the group `G_2(4)`.
|
2400
|
+
This graph is isomorphic to the subgraph of the from :meth:`Suzuki Graph
|
2401
|
+
<sage.graphs.graph_generators.GraphGenerators.SuzukiGraph>` induced on
|
2402
|
+
the neighbors of a vertex. Known as S.14 in [Hub1975]_.
|
2403
|
+
|
2404
|
+
EXAMPLES::
|
2405
|
+
|
2406
|
+
sage: from sage.graphs.strongly_regular_db import SRG_416_100_36_20
|
2407
|
+
sage: g = SRG_416_100_36_20() # long time, optional - internet, needs sage.libs.gap
|
2408
|
+
sage: g.is_strongly_regular(parameters=True) # long time, optional - internet, needs sage.libs.gap
|
2409
|
+
(416, 100, 36, 20)
|
2410
|
+
"""
|
2411
|
+
from sage.libs.gap.libgap import libgap
|
2412
|
+
libgap.load_package("AtlasRep")
|
2413
|
+
g = libgap.AtlasGroup("G2(4)", libgap.NrMovedPoints, 416)
|
2414
|
+
h = Graph()
|
2415
|
+
h.add_edges(g.Orbit([1, 5],libgap.OnSets))
|
2416
|
+
h.relabel()
|
2417
|
+
h.name('G_2(4) on cosets of HS')
|
2418
|
+
return h
|
2419
|
+
|
2420
|
+
|
2421
|
+
def SRG_560_208_72_80():
|
2422
|
+
r"""
|
2423
|
+
Return a `(560,208,72,80)`-strongly regular graph.
|
2424
|
+
|
2425
|
+
This graph is obtained as the union of 4 orbits of sets of cardinality 2
|
2426
|
+
(among the 13 that exist) of the group `Sz(8)`.
|
2427
|
+
|
2428
|
+
EXAMPLES::
|
2429
|
+
|
2430
|
+
sage: from sage.graphs.strongly_regular_db import SRG_560_208_72_80
|
2431
|
+
sage: g = SRG_560_208_72_80() # not tested (~2s) # needs sage.libs.gap
|
2432
|
+
sage: g.is_strongly_regular(parameters=True) # not tested (~2s) # needs sage.libs.gap
|
2433
|
+
(560, 208, 72, 80)
|
2434
|
+
"""
|
2435
|
+
from sage.libs.gap.libgap import libgap
|
2436
|
+
libgap.load_package("AtlasRep")
|
2437
|
+
g = libgap.AtlasGroup("Sz8", libgap.NrMovedPoints, 560)
|
2438
|
+
|
2439
|
+
h = Graph()
|
2440
|
+
h.add_edges(g.Orbit([1, 2],libgap.OnSets))
|
2441
|
+
h.add_edges(g.Orbit([1, 4],libgap.OnSets))
|
2442
|
+
h.add_edges(g.Orbit([1, 8],libgap.OnSets))
|
2443
|
+
h.add_edges(g.Orbit([1, 27],libgap.OnSets))
|
2444
|
+
h.relabel()
|
2445
|
+
h.name('Sz(8)-graph')
|
2446
|
+
return h
|
2447
|
+
|
2448
|
+
|
2449
|
+
def strongly_regular_from_two_intersection_set(M):
|
2450
|
+
r"""
|
2451
|
+
Return a strongly regular graph from a 2-intersection set.
|
2452
|
+
|
2453
|
+
A set of points in the projective geometry `PG(k,q)` is said to be a
|
2454
|
+
2-intersection set if it intersects every hyperplane in either `h_1` or
|
2455
|
+
`h_2` points, where `h_1,h_2\in \\NN`.
|
2456
|
+
|
2457
|
+
From a 2-intersection set `S` can be defined a strongly-regular graph in the
|
2458
|
+
following way:
|
2459
|
+
|
2460
|
+
- Place the points of `S` on a hyperplane `H` in `PG(k+1,q)`
|
2461
|
+
|
2462
|
+
- Define the graph `G` on all points of `PG(k+1,q)\backslash H`
|
2463
|
+
|
2464
|
+
- Make two points of `V(G)=PG(k+1,q)\backslash H` adjacent if the line going
|
2465
|
+
through them intersects `S`
|
2466
|
+
|
2467
|
+
For more information, see e.g. [CD2013]_ where this explanation has been
|
2468
|
+
taken from.
|
2469
|
+
|
2470
|
+
INPUT:
|
2471
|
+
|
2472
|
+
- ``M`` -- a `|S| \times k` matrix with entries in `F_q` representing the points of
|
2473
|
+
the 2-intersection set. We assume that the first nonzero entry of each row is
|
2474
|
+
equal to `1`, that is, they give points in homogeneous coordinates.
|
2475
|
+
|
2476
|
+
The implementation does not check that `S` is actually a 2-intersection set.
|
2477
|
+
|
2478
|
+
EXAMPLES::
|
2479
|
+
|
2480
|
+
sage: from sage.graphs.strongly_regular_db import strongly_regular_from_two_intersection_set
|
2481
|
+
sage: S = Matrix([(0,0,1),(0,1,0)] + [(1,x^2,x) for x in GF(4,'b')]) # needs sage.modules sage.rings.finite_rings
|
2482
|
+
sage: g = strongly_regular_from_two_intersection_set(S); g # needs sage.modules sage.rings.finite_rings
|
2483
|
+
two-intersection set in PG(3,4): Graph on 64 vertices
|
2484
|
+
sage: g.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings
|
2485
|
+
(64, 18, 2, 6)
|
2486
|
+
"""
|
2487
|
+
from itertools import product
|
2488
|
+
from sage.rings.rational_field import QQ
|
2489
|
+
K = M.base_ring()
|
2490
|
+
k = M.ncols()
|
2491
|
+
g = Graph()
|
2492
|
+
|
2493
|
+
M = [list(p) for p in M]
|
2494
|
+
|
2495
|
+
# For every point in F_q^{k+1} not on the hyperplane of M
|
2496
|
+
for u in [tuple(x) for x in product(K,repeat=k)]:
|
2497
|
+
# For every v point of M
|
2498
|
+
for v in M:
|
2499
|
+
# u is adjacent with all vertices on a uv line.
|
2500
|
+
g.add_edges([[u, tuple([u[i] + qq*v[i] for i in range(k)])]
|
2501
|
+
for qq in K if not qq == K.zero()])
|
2502
|
+
g.relabel()
|
2503
|
+
e = QQ((1,k))
|
2504
|
+
qq = g.num_verts()**e
|
2505
|
+
g.name('two-intersection set in PG('+str(k)+','+str(qq)+')')
|
2506
|
+
return g
|
2507
|
+
|
2508
|
+
|
2509
|
+
def SRG_120_63_30_36():
|
2510
|
+
r"""
|
2511
|
+
Return a `(120,63,30,36)`-strongly regular graph.
|
2512
|
+
|
2513
|
+
It is the distance-2 graph of :meth:`JohnsonGraph(10,3)
|
2514
|
+
<sage.graphs.graph_generators.GraphGenerators.JohnsonGraph>`.
|
2515
|
+
|
2516
|
+
EXAMPLES::
|
2517
|
+
|
2518
|
+
sage: from sage.graphs.strongly_regular_db import SRG_120_63_30_36
|
2519
|
+
sage: G = SRG_120_63_30_36()
|
2520
|
+
sage: G.is_strongly_regular(parameters=True)
|
2521
|
+
(120, 63, 30, 36)
|
2522
|
+
"""
|
2523
|
+
from sage.graphs.generators.families import JohnsonGraph
|
2524
|
+
return JohnsonGraph(10, 3).distance_graph([2])
|
2525
|
+
|
2526
|
+
|
2527
|
+
def SRG_126_25_8_4():
|
2528
|
+
r"""
|
2529
|
+
Return a `(126,25,8,4)`-strongly regular graph.
|
2530
|
+
|
2531
|
+
It is the distance-(1 or 4) graph of :meth:`JohnsonGraph(9,4)
|
2532
|
+
<sage.graphs.graph_generators.GraphGenerators.JohnsonGraph>`.
|
2533
|
+
|
2534
|
+
EXAMPLES::
|
2535
|
+
|
2536
|
+
sage: from sage.graphs.strongly_regular_db import SRG_126_25_8_4
|
2537
|
+
sage: G = SRG_126_25_8_4()
|
2538
|
+
sage: G.is_strongly_regular(parameters=True)
|
2539
|
+
(126, 25, 8, 4)
|
2540
|
+
"""
|
2541
|
+
from sage.graphs.generators.families import JohnsonGraph
|
2542
|
+
return JohnsonGraph(9, 4).distance_graph([1, 4])
|
2543
|
+
|
2544
|
+
|
2545
|
+
def SRG_175_72_20_36():
|
2546
|
+
r"""
|
2547
|
+
Return a `(175,72,20,36)`-strongly regular graph.
|
2548
|
+
|
2549
|
+
This graph is obtained from the line graph of
|
2550
|
+
:meth:`~sage.graphs.graph_generators.GraphGenerators.HoffmanSingletonGraph`. Setting
|
2551
|
+
two vertices to be adjacent if their distance in the line graph is exactly
|
2552
|
+
2 yields the graph. For more information, see 10.B.(iv) in [BL1984]_ and
|
2553
|
+
https://www.win.tue.nl/~aeb/graphs/McL.html.
|
2554
|
+
|
2555
|
+
EXAMPLES::
|
2556
|
+
|
2557
|
+
sage: from sage.graphs.strongly_regular_db import SRG_175_72_20_36
|
2558
|
+
sage: G = SRG_175_72_20_36()
|
2559
|
+
sage: G.is_strongly_regular(parameters=True)
|
2560
|
+
(175, 72, 20, 36)
|
2561
|
+
"""
|
2562
|
+
from sage.graphs.generators.smallgraphs import HoffmanSingletonGraph
|
2563
|
+
return HoffmanSingletonGraph().line_graph().distance_graph([2])
|
2564
|
+
|
2565
|
+
|
2566
|
+
def SRG_176_90_38_54():
|
2567
|
+
r"""
|
2568
|
+
Return a `(176,90,38,54)`-strongly regular graph.
|
2569
|
+
|
2570
|
+
This graph is obtained from
|
2571
|
+
:func:`~sage.graphs.strongly_regular_db.SRG_175_72_20_36`
|
2572
|
+
by attaching a isolated vertex and doing Seidel switching
|
2573
|
+
with respect to disjoint union of 18 maximum cliques, following
|
2574
|
+
a construction by W.Haemers given in Sect.10.B.(vi) of [BL1984]_.
|
2575
|
+
|
2576
|
+
EXAMPLES::
|
2577
|
+
|
2578
|
+
sage: from sage.graphs.strongly_regular_db import SRG_176_90_38_54
|
2579
|
+
sage: G = SRG_176_90_38_54(); G
|
2580
|
+
a Seidel switching of Distance graph for distance 2 in : Graph on 176 vertices
|
2581
|
+
sage: G.is_strongly_regular(parameters=True)
|
2582
|
+
(176, 90, 38, 54)
|
2583
|
+
"""
|
2584
|
+
g = SRG_175_72_20_36()
|
2585
|
+
g.relabel(range(175))
|
2586
|
+
# c=filter(lambda x: len(x)==5, g.cliques_maximal())
|
2587
|
+
# r=flatten(Hypergraph(c).packing()[:18]) # takes 3s, so we put the answer here
|
2588
|
+
r = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
2589
|
+
20, 21, 22, 23, 24, 25, 28, 29, 32, 38, 39, 41, 42, 43, 47, 49, 50, 51,
|
2590
|
+
52, 53, 55, 57, 61, 63, 65, 67, 69, 72, 75, 77, 79, 81, 84, 87, 88, 89,
|
2591
|
+
92, 95, 96, 97, 99, 101, 102, 104, 105, 107, 112, 114, 117, 118, 123,
|
2592
|
+
125, 129, 132, 139, 140, 141, 144, 146, 147, 153, 154, 162, 165, 166,
|
2593
|
+
167, 170, 172, 173, 174]
|
2594
|
+
g.add_vertex()
|
2595
|
+
g.seidel_switching(r)
|
2596
|
+
g.name('a Seidel switching of ' + g.name())
|
2597
|
+
return g
|
2598
|
+
|
2599
|
+
|
2600
|
+
def SRG_630_85_20_10():
|
2601
|
+
r"""
|
2602
|
+
Return a `(630,85,20,10)`-strongly regular graph.
|
2603
|
+
|
2604
|
+
This graph is the line graph of `pg(5,18,2)`; its point graph is
|
2605
|
+
:func:`~sage.graphs.strongly_regular_db.SRG_175_72_20_36`.
|
2606
|
+
One selects a subset of 630 maximum cliques in the latter following
|
2607
|
+
a construction by W.Haemers given in Sect.10.B.(v) of [BL1984]_.
|
2608
|
+
|
2609
|
+
EXAMPLES::
|
2610
|
+
|
2611
|
+
sage: from sage.graphs.strongly_regular_db import SRG_630_85_20_10
|
2612
|
+
sage: G = SRG_630_85_20_10() # long time # needs sage.groups
|
2613
|
+
sage: G.is_strongly_regular(parameters=True) # long time # needs sage.groups
|
2614
|
+
(630, 85, 20, 10)
|
2615
|
+
"""
|
2616
|
+
from sage.graphs.generators.intersection import IntersectionGraph
|
2617
|
+
from sage.graphs.generators.smallgraphs import HoffmanSingletonGraph
|
2618
|
+
hs = HoffmanSingletonGraph()
|
2619
|
+
P = list(range(5)) + list(range(30, 35)) # a Petersen in hs
|
2620
|
+
mc = [0, 1, 5, 6, 12, 13, 16, 17, 22, 23, 29, 33, 39, 42, 47]
|
2621
|
+
assert hs.subgraph(mc).is_regular(k=0) # a maximum coclique
|
2622
|
+
assert hs.subgraph(P).is_regular(k=3)
|
2623
|
+
h = hs.automorphism_group().stabilizer(mc, action='OnSets')
|
2624
|
+
l = h.orbit(tuple((x[0], x[1]) for x in hs.subgraph(P).matching()),
|
2625
|
+
"OnSetsSets")
|
2626
|
+
return IntersectionGraph(l)
|
2627
|
+
|
2628
|
+
|
2629
|
+
def SRG_126_50_13_24():
|
2630
|
+
r"""
|
2631
|
+
Return a `(126,50,13,24)`-strongly regular graph.
|
2632
|
+
|
2633
|
+
This graph is a subgraph of
|
2634
|
+
:meth:`~sage.graphs.strongly_regular_db.SRG_175_72_20_36`.
|
2635
|
+
This construction, due to Goethals, is given in §10B.(vii) of [BL1984]_.
|
2636
|
+
|
2637
|
+
EXAMPLES::
|
2638
|
+
|
2639
|
+
sage: from sage.graphs.strongly_regular_db import SRG_126_50_13_24
|
2640
|
+
sage: G = SRG_126_50_13_24(); G
|
2641
|
+
Goethals graph: Graph on 126 vertices
|
2642
|
+
sage: G.is_strongly_regular(parameters=True)
|
2643
|
+
(126, 50, 13, 24)
|
2644
|
+
"""
|
2645
|
+
from sage.graphs.generators.smallgraphs import HoffmanSingletonGraph
|
2646
|
+
hs = HoffmanSingletonGraph()
|
2647
|
+
s = set(hs.vertices(sort=False)).difference(hs.neighbors(0) + [0])
|
2648
|
+
g = SRG_175_72_20_36().subgraph(hs.edge_boundary(s, s))
|
2649
|
+
g.name('Goethals graph')
|
2650
|
+
return g
|
2651
|
+
|
2652
|
+
|
2653
|
+
def SRG_1288_792_476_504():
|
2654
|
+
r"""
|
2655
|
+
Return a `(1288, 792, 476, 504)`-strongly regular graph.
|
2656
|
+
|
2657
|
+
This graph is built on the words of weight 12 in the
|
2658
|
+
:func:`~sage.coding.code_constructions.BinaryGolayCode`. Two of them are
|
2659
|
+
then made adjacent if their symmetric difference has weight 12 (cf
|
2660
|
+
[BE1992]_).
|
2661
|
+
|
2662
|
+
.. SEEALSO::
|
2663
|
+
|
2664
|
+
:func:`strongly_regular_from_two_weight_code` -- build a strongly regular graph from
|
2665
|
+
a two-weight code.
|
2666
|
+
|
2667
|
+
EXAMPLES::
|
2668
|
+
|
2669
|
+
sage: from sage.graphs.strongly_regular_db import SRG_1288_792_476_504
|
2670
|
+
sage: G = SRG_1288_792_476_504() # long time # needs sage.rings.finite_rings
|
2671
|
+
sage: G.is_strongly_regular(parameters=True) # long time # needs sage.rings.finite_rings
|
2672
|
+
(1288, 792, 476, 504)
|
2673
|
+
"""
|
2674
|
+
from sage.coding.golay_code import GolayCode
|
2675
|
+
C = GolayCode(GF(2), False)
|
2676
|
+
C = [[i for i,v in enumerate(c) if v]
|
2677
|
+
for c in C]
|
2678
|
+
C = [s for s in C if len(s) == 12]
|
2679
|
+
G = Graph([[frozenset(c) for c in C],
|
2680
|
+
lambda x, y: len(x.symmetric_difference(y)) == 12])
|
2681
|
+
G.relabel()
|
2682
|
+
G.name('binary Golay code')
|
2683
|
+
return G
|
2684
|
+
|
2685
|
+
|
2686
|
+
cdef bint seems_feasible(int v, int k, int l, int mu) noexcept:
|
2687
|
+
r"""
|
2688
|
+
Check if the set of parameters seems feasible.
|
2689
|
+
|
2690
|
+
INPUT:
|
2691
|
+
|
2692
|
+
- ``v``, ``k``, ``l``, ``mu`` -- integers
|
2693
|
+
|
2694
|
+
TESTS:
|
2695
|
+
|
2696
|
+
:issue:`32306` is fixed::
|
2697
|
+
|
2698
|
+
sage: from sage.graphs.strongly_regular_db import strongly_regular_graph
|
2699
|
+
sage: strongly_regular_graph(16384, 8256, 4160, 4160, existence=True) # needs sage.combinat sage.modules
|
2700
|
+
True
|
2701
|
+
"""
|
2702
|
+
cdef uint_fast32_t tmp[2]
|
2703
|
+
|
2704
|
+
if (v < 0 or k <= 0 or l < 0 or mu < 0 or
|
2705
|
+
k >= v - 1 or l >= k or mu > k or
|
2706
|
+
v - 2*k + mu - 2 < 0 or # lambda of complement graph >=0
|
2707
|
+
v - 2*k + l < 0 or # μ of complement graph >= 0
|
2708
|
+
mu*(v - k - 1) != k*(k - l - 1)):
|
2709
|
+
return False
|
2710
|
+
|
2711
|
+
if mu == k: # complete multipartite graph
|
2712
|
+
r = v//(v-k) # number of parts (of size v-k each)
|
2713
|
+
return (l == (v-k)*(r-2) and v == r*(v-k))
|
2714
|
+
|
2715
|
+
if mu == 0: # the complement of a complete multipartite graph
|
2716
|
+
r = v//(k+1) # number of parts (of size k+1 each)
|
2717
|
+
return (l == k-1 and v == r*(k+1))
|
2718
|
+
|
2719
|
+
# Conference graphs. Only possible if 'v' is a sum of two squares (3.A of
|
2720
|
+
# [BL1984]_)
|
2721
|
+
if (v-1)*(mu-l)-2*k == 0:
|
2722
|
+
return two_squares_c(v, tmp)
|
2723
|
+
|
2724
|
+
rr, ss = eigenvalues(v, k, l, mu)
|
2725
|
+
if rr is None:
|
2726
|
+
return False
|
2727
|
+
r, s = rr, ss
|
2728
|
+
|
2729
|
+
# p.87 of [BL1984]_
|
2730
|
+
# "Integrality condition"
|
2731
|
+
if ((s+1)*(k-s)*k) % (mu*(s-r)) or ((r+1)*(k-r)*k) % (mu*(s-r)):
|
2732
|
+
return False
|
2733
|
+
|
2734
|
+
# Theorem 21.3 of [WilsonACourse] or
|
2735
|
+
# 3.B of [BL1984]_
|
2736
|
+
# (Krein conditions)
|
2737
|
+
if (r+1)*(k+r+2*r*s) > (k+r)*(s+1)**2 or (s+1)*(k+s+2*r*s) > (k+s)*(r+1)**2:
|
2738
|
+
return False
|
2739
|
+
|
2740
|
+
# multiplicity of eigenvalues 'r,s' (f=lambda_r, g=lambda_s)
|
2741
|
+
#
|
2742
|
+
# They are integers (checked by the 'integrality condition').
|
2743
|
+
f = -k*(s+1)*(k-s)//(mu*(r-s))
|
2744
|
+
g = k*(r+1)*(k-r)//(mu*(r-s))
|
2745
|
+
if 1 + f + g != v: # the only other eigenvalue, k, has multiplicity 1
|
2746
|
+
return False
|
2747
|
+
|
2748
|
+
# 3.C of [BL1984]_
|
2749
|
+
# (Absolute bound)
|
2750
|
+
if 2*v > f*(f+3) or 2*v > g*(g+3):
|
2751
|
+
return False
|
2752
|
+
|
2753
|
+
# 3.D of [BL1984]_
|
2754
|
+
# (Claw bound)
|
2755
|
+
if (mu != s**2 and
|
2756
|
+
mu != s*(s+1) and
|
2757
|
+
2*(r+1) > s*(s+1)*(mu+1)):
|
2758
|
+
return False
|
2759
|
+
|
2760
|
+
# 3.E of [BL1984]_
|
2761
|
+
# (the Case μ=1)
|
2762
|
+
if mu == 1:
|
2763
|
+
if k % (l+1) or (v*k) % ((l+1)*(l+2)):
|
2764
|
+
return False
|
2765
|
+
|
2766
|
+
# 3.F of [BL1984]_
|
2767
|
+
# (the Case μ=2)
|
2768
|
+
if mu == 2 and 2*k < l*(l + 3) and k % (l + 1):
|
2769
|
+
return False
|
2770
|
+
|
2771
|
+
return True
|
2772
|
+
|
2773
|
+
|
2774
|
+
def strongly_regular_graph(int v, int k, int l, int mu=-1, bint existence=False, bint check=True):
|
2775
|
+
r"""
|
2776
|
+
Return a `(v,k,\lambda,\mu)`-strongly regular graph.
|
2777
|
+
|
2778
|
+
This function relies partly on Andries Brouwer's `database of strongly
|
2779
|
+
regular graphs <https://www.win.tue.nl/~aeb/graphs/srg/srgtab.html>`__. See
|
2780
|
+
the documentation of :mod:`sage.graphs.strongly_regular_db` for more
|
2781
|
+
information.
|
2782
|
+
|
2783
|
+
INPUT:
|
2784
|
+
|
2785
|
+
- ``v``, ``k``, ``l``, ``mu`` -- ``integers`` -- note that ``mu``, if unspecified, is
|
2786
|
+
automatically determined from ``v``, ``k``, ``l``
|
2787
|
+
|
2788
|
+
- ``existence`` -- boolean (default: ``False``); instead of building the graph,
|
2789
|
+
return:
|
2790
|
+
|
2791
|
+
- ``True`` -- meaning that a `(v,k,\lambda,\mu)`-strongly regular graph
|
2792
|
+
exists
|
2793
|
+
|
2794
|
+
- ``Unknown`` -- meaning that Sage does not know if such a strongly
|
2795
|
+
regular graph exists (see :mod:`sage.misc.unknown`)
|
2796
|
+
|
2797
|
+
- ``False`` -- meaning that no such strongly regular graph exists
|
2798
|
+
|
2799
|
+
- ``check`` -- boolean (default: ``True``); whether to check that output is
|
2800
|
+
correct before returning it. As this is expected to be useless, you may
|
2801
|
+
want to disable it whenever you want speed.
|
2802
|
+
|
2803
|
+
EXAMPLES:
|
2804
|
+
|
2805
|
+
Petersen's graph from its set of parameters::
|
2806
|
+
|
2807
|
+
sage: graphs.strongly_regular_graph(10,3,0,1, existence=True) # needs database_graphs sage.libs.pari
|
2808
|
+
True
|
2809
|
+
sage: graphs.strongly_regular_graph(10,3,0,1) # needs database_graphs
|
2810
|
+
complement(Johnson graph with parameters 5,2): Graph on 10 vertices
|
2811
|
+
|
2812
|
+
Now without specifying `\mu`::
|
2813
|
+
|
2814
|
+
sage: graphs.strongly_regular_graph(10,3,0) # needs database_graphs
|
2815
|
+
complement(Johnson graph with parameters 5,2): Graph on 10 vertices
|
2816
|
+
|
2817
|
+
An obviously infeasible set of parameters::
|
2818
|
+
|
2819
|
+
sage: graphs.strongly_regular_graph(5,5,5,5, existence=True) # needs database_graphs
|
2820
|
+
False
|
2821
|
+
sage: graphs.strongly_regular_graph(5,5,5,5) # needs database_graphs
|
2822
|
+
Traceback (most recent call last):
|
2823
|
+
...
|
2824
|
+
ValueError: There exists no (5, 5, 5, 5)-strongly regular graph
|
2825
|
+
|
2826
|
+
A set of parameters proved in a paper to be infeasible::
|
2827
|
+
|
2828
|
+
sage: graphs.strongly_regular_graph(324,57,0,12,existence=True) # needs sage.combinat sage.modules
|
2829
|
+
False
|
2830
|
+
sage: graphs.strongly_regular_graph(324,57,0,12) # needs sage.combinat sage.modules
|
2831
|
+
Traceback (most recent call last):
|
2832
|
+
...
|
2833
|
+
EmptySetError: Andries Brouwer's database reports that no (324, 57, 0,
|
2834
|
+
12)-strongly regular graph exists. Comments: <a
|
2835
|
+
href="srgtabrefs.html#GavrilyukMakhnev05">Gavrilyuk & Makhnev</a> ...
|
2836
|
+
|
2837
|
+
A set of parameters unknown to be realizable in Andries Brouwer's database::
|
2838
|
+
|
2839
|
+
sage: graphs.strongly_regular_graph(324,95,22,30,existence=True) # needs sage.combinat
|
2840
|
+
Unknown
|
2841
|
+
sage: graphs.strongly_regular_graph(324,95,22,30) # needs sage.combinat
|
2842
|
+
Traceback (most recent call last):
|
2843
|
+
...
|
2844
|
+
RuntimeError: Andries Brouwer's database reports that no
|
2845
|
+
(324, 95, 22, 30)-strongly regular graph is known to exist.
|
2846
|
+
Comments:
|
2847
|
+
|
2848
|
+
A large unknown set of parameters (not in Andries Brouwer's database)::
|
2849
|
+
|
2850
|
+
sage: graphs.strongly_regular_graph(1394,175,0,25,existence=True) # needs sage.combinat
|
2851
|
+
Unknown
|
2852
|
+
sage: graphs.strongly_regular_graph(1394,175,0,25) # needs sage.combinat
|
2853
|
+
Traceback (most recent call last):
|
2854
|
+
...
|
2855
|
+
RuntimeError: Sage cannot figure out if a (1394, 175, 0, 25)-strongly
|
2856
|
+
regular graph exists.
|
2857
|
+
|
2858
|
+
Test the Claw bound (see 3.D of [BL1984]_)::
|
2859
|
+
|
2860
|
+
sage: graphs.strongly_regular_graph(2058, 242, 91, 20, existence=True) # needs database_graphs
|
2861
|
+
False
|
2862
|
+
|
2863
|
+
TESTS:
|
2864
|
+
|
2865
|
+
Check that :issue:`26513` is fixed::
|
2866
|
+
|
2867
|
+
sage: graphs.strongly_regular_graph(539, 288, 162, 144) # needs sage.combinat
|
2868
|
+
descendant of (540, 264, 138, 120)-strongly regular graph at ... 539 vertices
|
2869
|
+
sage: graphs.strongly_regular_graph(539, 250, 105, 125) # needs sage.combinat
|
2870
|
+
descendant of (540, 275, 130, 150)-strongly regular graph at ... 539 vertices
|
2871
|
+
sage: graphs.strongly_regular_graph(209, 100, 45, 50) # needs database_graphs sage.libs.pari
|
2872
|
+
descendant of complement(merging of S_7 on Circulant(6,[1,4])s) at ... 209 vertices
|
2873
|
+
|
2874
|
+
|
2875
|
+
Check that all of our constructions are correct - you will need gap_packages spkg installed::
|
2876
|
+
|
2877
|
+
sage: from sage.graphs.strongly_regular_db import apparently_feasible_parameters
|
2878
|
+
sage: for p in sorted(apparently_feasible_parameters(1300)): # not tested, optional gap_package_design
|
2879
|
+
....: if graphs.strongly_regular_graph(*p,existence=True) is True:
|
2880
|
+
....: try:
|
2881
|
+
....: _ = graphs.strongly_regular_graph(*p)
|
2882
|
+
....: print(p, "built successfully")
|
2883
|
+
....: except RuntimeError as e:
|
2884
|
+
....: if 'Brouwer' not in str(e):
|
2885
|
+
....: raise
|
2886
|
+
|
2887
|
+
`\mu=0` behaves correctly (:issue:`19712`)::
|
2888
|
+
|
2889
|
+
sage: # needs database_graphs
|
2890
|
+
sage: graphs.strongly_regular_graph(10,2,1)
|
2891
|
+
Traceback (most recent call last):
|
2892
|
+
...
|
2893
|
+
ValueError: There exists no (10, 2, 1, 0)-strongly regular graph
|
2894
|
+
sage: graphs.strongly_regular_graph(12,3,2)
|
2895
|
+
complement(Multipartite Graph with set sizes [4, 4, 4]): Graph on 12 vertices
|
2896
|
+
sage: graphs.strongly_regular_graph(6,3,0)
|
2897
|
+
Multipartite Graph with set sizes [3, 3]: Graph on 6 vertices
|
2898
|
+
"""
|
2899
|
+
if mu == -1:
|
2900
|
+
mu = k*(k - l - 1)//(v - k - 1)
|
2901
|
+
g = strongly_regular_graph_lazy(v, k, l, mu=mu, existence=existence)
|
2902
|
+
if existence is True:
|
2903
|
+
return g
|
2904
|
+
G = g[0](*g[1:])
|
2905
|
+
if check and (v, k, l, mu) != G.is_strongly_regular(parameters=True):
|
2906
|
+
params = (v, k, l, mu)
|
2907
|
+
raise RuntimeError(f"Sage built an incorrect {params}-SRG.")
|
2908
|
+
return G
|
2909
|
+
|
2910
|
+
|
2911
|
+
def strongly_regular_graph_lazy(int v, int k, int l, int mu=-1, bint existence=False):
|
2912
|
+
r"""
|
2913
|
+
Return a promise to build an `(v,k,l,mu)`-srg.
|
2914
|
+
|
2915
|
+
Return a promise to build an `(v,k,l,mu)`-srg as a tuple `t`, with `t[0]` a
|
2916
|
+
function to evaluate on `*t[1:]`.
|
2917
|
+
|
2918
|
+
Input as in :func:`~sage.graphs.strongly_regular_graphs_db.strongly_regular_graph`,
|
2919
|
+
although without `check`.
|
2920
|
+
|
2921
|
+
TESTS::
|
2922
|
+
|
2923
|
+
sage: # needs database_graphs
|
2924
|
+
sage: from sage.graphs.strongly_regular_db import strongly_regular_graph_lazy
|
2925
|
+
sage: g,p=strongly_regular_graph_lazy(10,6,3); g,p
|
2926
|
+
(<...is_johnson...>, 5)
|
2927
|
+
sage: g(p)
|
2928
|
+
Johnson graph with parameters 5,2: Graph on 10 vertices
|
2929
|
+
sage: g,p=strongly_regular_graph_lazy(10,3,0,1); g,p
|
2930
|
+
(<...strongly_regular_graph_lazy...>,
|
2931
|
+
(5,))
|
2932
|
+
sage: g(p)
|
2933
|
+
complement(Johnson graph with parameters 5,2): Graph on 10 vertices
|
2934
|
+
sage: g,p=strongly_regular_graph_lazy(12,3,2); g,p
|
2935
|
+
(<...strongly_regular_graph_lazy...>,
|
2936
|
+
(3, 4))
|
2937
|
+
sage: g(p)
|
2938
|
+
complement(Multipartite Graph with set sizes [4, 4, 4]): Graph on 12 vertices
|
2939
|
+
sage: g = strongly_regular_graph_lazy(539,250,105); g # needs sage.combinat sage.modules
|
2940
|
+
(<...is_twograph_descendant_of_srg...>,
|
2941
|
+
5,
|
2942
|
+
11)
|
2943
|
+
sage: g[0](*g[1:]) # needs sage.combinat sage.modules
|
2944
|
+
descendant of (540, 275, 130, 150)-strongly regular graph at 0: Graph on 539 vertices
|
2945
|
+
"""
|
2946
|
+
load_brouwer_database()
|
2947
|
+
if mu == -1:
|
2948
|
+
mu = k*(k - l - 1)//(v - k - 1)
|
2949
|
+
|
2950
|
+
params = (v, k, l, mu)
|
2951
|
+
params_complement = (v, v - k - 1, v - 2*k + mu - 2, v - 2*k + l)
|
2952
|
+
|
2953
|
+
if not seems_feasible(v, k, l, mu):
|
2954
|
+
if existence:
|
2955
|
+
return False
|
2956
|
+
raise ValueError(f"There exists no {params}-strongly regular graph")
|
2957
|
+
|
2958
|
+
if _small_srg_database is None:
|
2959
|
+
_build_small_srg_database()
|
2960
|
+
|
2961
|
+
if params in _small_srg_database:
|
2962
|
+
val = _small_srg_database[params]
|
2963
|
+
return True if existence else (val[0], *val[1:])
|
2964
|
+
if params_complement in _small_srg_database:
|
2965
|
+
val = _small_srg_database[params_complement]
|
2966
|
+
return True if existence else (lambda *t: val[0](*t).complement(), *val[1:])
|
2967
|
+
|
2968
|
+
test_functions = [is_complete_multipartite, # must be 1st, to prevent 0-divisions
|
2969
|
+
is_paley, is_johnson,
|
2970
|
+
is_orthogonal_array_block_graph,
|
2971
|
+
is_steiner, is_affine_polar,
|
2972
|
+
is_goethals_seidel,
|
2973
|
+
is_orthogonal_polar,
|
2974
|
+
is_NOodd, is_NOperp_F5, is_NO_F2, is_NO_F3, is_NU,
|
2975
|
+
is_unitary_polar, is_unitary_dual_polar, is_GQqmqp,
|
2976
|
+
is_RSHCD,
|
2977
|
+
is_twograph_descendant_of_srg,
|
2978
|
+
is_taylor_twograph_srg,
|
2979
|
+
is_switch_OA_srg,
|
2980
|
+
is_polhill,
|
2981
|
+
is_haemers,
|
2982
|
+
is_cossidente_penttila,
|
2983
|
+
is_mathon_PC_srg,
|
2984
|
+
is_muzychuk_S6,
|
2985
|
+
is_nowhere0_twoweight,
|
2986
|
+
is_switch_skewhad]
|
2987
|
+
|
2988
|
+
# Going through all test functions, for the set of parameters and its
|
2989
|
+
# complement.
|
2990
|
+
for f in test_functions:
|
2991
|
+
if f(*params):
|
2992
|
+
if existence:
|
2993
|
+
return True
|
2994
|
+
ans = f(*params)
|
2995
|
+
return (ans[0], *ans[1:])
|
2996
|
+
if f(*params_complement):
|
2997
|
+
if existence:
|
2998
|
+
return True
|
2999
|
+
ans = f(*params_complement)
|
3000
|
+
return (lambda t: ans[0](*t).complement(), ans[1:])
|
3001
|
+
|
3002
|
+
# From now on, we have no idea how to build the graph.
|
3003
|
+
#
|
3004
|
+
# We try to return the most appropriate error message.
|
3005
|
+
|
3006
|
+
global _brouwer_database
|
3007
|
+
brouwer_data = _brouwer_database.get(params, None)
|
3008
|
+
|
3009
|
+
if brouwer_data is not None:
|
3010
|
+
comments = brouwer_data['comments']
|
3011
|
+
if brouwer_data['status'] == 'impossible':
|
3012
|
+
if existence:
|
3013
|
+
return False
|
3014
|
+
raise EmptySetError(
|
3015
|
+
f"Andries Brouwer's database reports that no "
|
3016
|
+
f"{params}-strongly regular graph exists. Comments: {comments}")
|
3017
|
+
|
3018
|
+
if brouwer_data['status'] == 'open':
|
3019
|
+
if existence:
|
3020
|
+
return Unknown
|
3021
|
+
raise RuntimeError(
|
3022
|
+
f"Andries Brouwer's database reports that no "
|
3023
|
+
f"{params}-strongly regular graph is known to exist.\n"
|
3024
|
+
f"Comments: {comments}")
|
3025
|
+
|
3026
|
+
if brouwer_data['status'] == 'exists':
|
3027
|
+
if existence:
|
3028
|
+
return True
|
3029
|
+
raise RuntimeError(
|
3030
|
+
f"Andries Brouwer's database claims that such a "
|
3031
|
+
f"{params}-strongly regular graph exists, but Sage does not "
|
3032
|
+
f"know how to build it. If *you* do, please get in touch "
|
3033
|
+
f"with us on sage-devel!\n"
|
3034
|
+
f"Comments: {comments}")
|
3035
|
+
if existence:
|
3036
|
+
return Unknown
|
3037
|
+
raise RuntimeError(
|
3038
|
+
f"Sage cannot figure out if a {params}-strongly "
|
3039
|
+
f"regular graph exists.")
|
3040
|
+
|
3041
|
+
|
3042
|
+
def apparently_feasible_parameters(int n):
|
3043
|
+
r"""
|
3044
|
+
Return a list of a priori feasible parameters `(v,k,\lambda,\mu)`, with `0<\mu<k`.
|
3045
|
+
|
3046
|
+
Note that some of those that it returns may also be infeasible for more
|
3047
|
+
involved reasons. The condition `0<\mu<k` makes sure we skip trivial cases of
|
3048
|
+
complete multipartite graphs and their complements.
|
3049
|
+
|
3050
|
+
INPUT:
|
3051
|
+
|
3052
|
+
- ``n`` -- integer; return all a-priori feasible tuples `(v,k,\lambda,\mu)`
|
3053
|
+
for `v<n`
|
3054
|
+
|
3055
|
+
EXAMPLES:
|
3056
|
+
|
3057
|
+
All sets of parameters with `v<20` which pass basic arithmetic tests are
|
3058
|
+
feasible::
|
3059
|
+
|
3060
|
+
sage: from sage.graphs.strongly_regular_db import apparently_feasible_parameters
|
3061
|
+
sage: small_feasible = apparently_feasible_parameters(20); small_feasible
|
3062
|
+
{(5, 2, 0, 1),
|
3063
|
+
(9, 4, 1, 2),
|
3064
|
+
(10, 3, 0, 1),
|
3065
|
+
(10, 6, 3, 4),
|
3066
|
+
(13, 6, 2, 3),
|
3067
|
+
(15, 6, 1, 3),
|
3068
|
+
(15, 8, 4, 4),
|
3069
|
+
(16, 5, 0, 2),
|
3070
|
+
(16, 6, 2, 2),
|
3071
|
+
(16, 9, 4, 6),
|
3072
|
+
(16, 10, 6, 6),
|
3073
|
+
(17, 8, 3, 4)}
|
3074
|
+
sage: all(graphs.strongly_regular_graph(*x,existence=True) is True # needs database_graphs sage.libs.pari
|
3075
|
+
....: for x in small_feasible)
|
3076
|
+
True
|
3077
|
+
|
3078
|
+
But that becomes wrong for `v<60` (because of the non-existence of a
|
3079
|
+
`(49,16,3,6)`-strongly regular graph)::
|
3080
|
+
|
3081
|
+
sage: small_feasible = apparently_feasible_parameters(60)
|
3082
|
+
sage: all(graphs.strongly_regular_graph(*x,existence=True) is True # needs database_graphs sage.libs.pari
|
3083
|
+
....: for x in small_feasible)
|
3084
|
+
False
|
3085
|
+
"""
|
3086
|
+
cdef int v, k, l, mu
|
3087
|
+
feasible = set()
|
3088
|
+
for v in range(n):
|
3089
|
+
for k in range(1, v - 1):
|
3090
|
+
for l in range(k - 1):
|
3091
|
+
mu = k*(k - l - 1)//(v - k - 1)
|
3092
|
+
if mu > 0 and mu < k and seems_feasible(v, k, l, mu):
|
3093
|
+
feasible.add((v, k, l, mu))
|
3094
|
+
return feasible
|
3095
|
+
|
3096
|
+
|
3097
|
+
def _build_small_srg_database():
|
3098
|
+
r"""
|
3099
|
+
Build the database of small strongly regular graphs.
|
3100
|
+
|
3101
|
+
This data is stored in the module-level variable ``_small_srg_database``.
|
3102
|
+
We use formulas from Cor.3.7 of [CK1986]_ to compute parameters of the
|
3103
|
+
graph of the projective 2-intersection set associated with a 2-weight code `C`,
|
3104
|
+
and the usual theory of duality in association schemes to compute the
|
3105
|
+
parameters of the graph of words of `C`. Another relevant reference is
|
3106
|
+
Sect.9.8.3 of [BH2012]_.
|
3107
|
+
|
3108
|
+
EXAMPLES::
|
3109
|
+
|
3110
|
+
sage: from sage.graphs.strongly_regular_db import _build_small_srg_database
|
3111
|
+
sage: _build_small_srg_database() # needs sage.modules sage.rings.finite_rings
|
3112
|
+
|
3113
|
+
TESTS:
|
3114
|
+
|
3115
|
+
Make sure that all two-weight codes yield the strongly regular graphs we
|
3116
|
+
expect::
|
3117
|
+
|
3118
|
+
sage: # needs database_graphs
|
3119
|
+
sage: graphs.strongly_regular_graph(81, 50, 31, 30) # needs sage.libs.pari
|
3120
|
+
complement(two-intersection set in PG(4,3)): Graph on 81 vertices
|
3121
|
+
sage: graphs.strongly_regular_graph(243, 220, 199, 200) # long time, needs sage.rings.finite_rings
|
3122
|
+
two-weight code: [55, 5] linear code over GF(3): Graph on 243 vertices
|
3123
|
+
sage: graphs.strongly_regular_graph(256, 153, 92, 90) # needs sage.combinat
|
3124
|
+
complement(two-intersection set in PG(4,4)): Graph on 256 vertices
|
3125
|
+
sage: graphs.strongly_regular_graph(256, 170, 114, 110) # needs sage.combinat
|
3126
|
+
complement(two-intersection set in PG(8,2)): Graph on 256 vertices
|
3127
|
+
sage: graphs.strongly_regular_graph(256, 187, 138, 132) # needs sage.combinat
|
3128
|
+
complement(two-intersection set in PG(8,2)): Graph on 256 vertices
|
3129
|
+
sage: graphs.strongly_regular_graph(512, 73, 12, 10) # not tested (too long), needs sage.rings.finite_rings
|
3130
|
+
two-weight code: [219, 9] linear code over GF(2): Graph on 512 vertices
|
3131
|
+
sage: graphs.strongly_regular_graph(512, 219, 106, 84) # long time, needs sage.combinat
|
3132
|
+
two-intersection set in PG(9,2): Graph on 512 vertices
|
3133
|
+
sage: graphs.strongly_regular_graph(512, 315, 202, 180) # not tested (too long), needs sage.rings.finite_rings
|
3134
|
+
two-weight code: [70, 9] linear code over GF(2): Graph on 512 vertices
|
3135
|
+
sage: graphs.strongly_regular_graph(625, 364, 213, 210) # long time, needs sage.libs.pari
|
3136
|
+
complement(two-intersection set in PG(4,5)): Graph on 625 vertices
|
3137
|
+
sage: graphs.strongly_regular_graph(625, 416, 279, 272) # long time, needs sage.libs.pari
|
3138
|
+
complement(two-intersection set in PG(4,5)): Graph on 625 vertices
|
3139
|
+
sage: graphs.strongly_regular_graph(625, 468, 353, 342) # long time, needs sage.libs.pari
|
3140
|
+
complement(two-intersection set in PG(4,5)): Graph on 625 vertices
|
3141
|
+
sage: graphs.strongly_regular_graph(729, 336, 153,156) # not tested (too long)
|
3142
|
+
two-intersection set in PG(6,3): Graph on 729 vertices
|
3143
|
+
sage: graphs.strongly_regular_graph(729, 420, 243, 240) # not tested (too long)
|
3144
|
+
complement(two-intersection set in PG(6,3)): Graph on 729 vertices
|
3145
|
+
sage: graphs.strongly_regular_graph(729, 448, 277, 272) # not tested (too long)
|
3146
|
+
complement(two-intersection set in PG(6,3)): Graph on 729 vertices
|
3147
|
+
sage: graphs.strongly_regular_graph(729, 476, 313, 306) # not tested (too long)
|
3148
|
+
complement(two-intersection set in PG(6,3)): Graph on 729 vertices
|
3149
|
+
sage: graphs.strongly_regular_graph(729, 532, 391, 380) # not tested (too long)
|
3150
|
+
complement(two-intersection set in PG(6,3)): Graph on 729 vertices
|
3151
|
+
sage: graphs.strongly_regular_graph(729, 560, 433, 420) # not tested (too long)
|
3152
|
+
complement(two-intersection set in PG(6,3)): Graph on 729 vertices
|
3153
|
+
Graph on 729 vertices
|
3154
|
+
sage: graphs.strongly_regular_graph(729, 616, 523, 506) # not tested (too long)
|
3155
|
+
complement(two-intersection set in PG(6,3)): Graph on 729 vertices
|
3156
|
+
sage: graphs.strongly_regular_graph(1024, 363, 122, 132) # not tested (too long)
|
3157
|
+
two-intersection set in PG(5,4): Graph on 1024 vertices
|
3158
|
+
sage: graphs.strongly_regular_graph(1024, 396, 148, 156) # not tested (too long)
|
3159
|
+
two-intersection set in PG(5,4): Graph on 1024 vertices
|
3160
|
+
sage: graphs.strongly_regular_graph(1024, 429, 176, 182) # not tested (too long)
|
3161
|
+
two-intersection set in PG(5,4): Graph on 1024 vertices
|
3162
|
+
sage: graphs.strongly_regular_graph(1024, 825, 668, 650) # not tested (too long)
|
3163
|
+
complement(two-intersection set in PG(10,2)): Graph on 1024 vertices
|
3164
|
+
"""
|
3165
|
+
from sage.graphs.generators.smallgraphs import McLaughlinGraph
|
3166
|
+
from sage.graphs.generators.smallgraphs import CameronGraph
|
3167
|
+
from sage.graphs.generators.smallgraphs import GritsenkoGraph
|
3168
|
+
from sage.graphs.generators.smallgraphs import M22Graph
|
3169
|
+
from sage.graphs.generators.smallgraphs import SimsGewirtzGraph
|
3170
|
+
from sage.graphs.generators.smallgraphs import HoffmanSingletonGraph
|
3171
|
+
from sage.graphs.generators.smallgraphs import HigmanSimsGraph
|
3172
|
+
from sage.graphs.generators.smallgraphs import IoninKharaghani765Graph
|
3173
|
+
from sage.graphs.generators.smallgraphs import JankoKharaghaniGraph
|
3174
|
+
from sage.graphs.generators.smallgraphs import LocalMcLaughlinGraph
|
3175
|
+
from sage.graphs.generators.smallgraphs import SuzukiGraph
|
3176
|
+
from sage.graphs.generators.smallgraphs import MathonStronglyRegularGraph
|
3177
|
+
from sage.graphs.generators.smallgraphs import U42Graph216
|
3178
|
+
from sage.graphs.generators.smallgraphs import U42Graph540
|
3179
|
+
|
3180
|
+
global _small_srg_database
|
3181
|
+
_small_srg_database = {
|
3182
|
+
( 36, 14, 4, 6): [Graph, ('c~rLDEOcKTPO`U`HOIj@MWFLQFAaRIT`HIWqPsQQJ'
|
3183
|
+
'DXGLqYM@gRLAWLdkEW@RQYQIErcgesClhKefC_ygS'
|
3184
|
+
'GkZ`OyHETdK[?lWStCapVgKK')],
|
3185
|
+
( 50, 7, 0, 1): [HoffmanSingletonGraph],
|
3186
|
+
( 56, 10, 0, 2): [SimsGewirtzGraph],
|
3187
|
+
( 65, 32, 15, 16): [GritsenkoGraph],
|
3188
|
+
( 77, 16, 0, 4): [M22Graph],
|
3189
|
+
(100, 22, 0, 6): [HigmanSimsGraph],
|
3190
|
+
(100, 44, 18, 20): [SRG_100_44_18_20],
|
3191
|
+
(100, 45, 20, 20): [SRG_100_45_20_20],
|
3192
|
+
(105, 32, 4, 12): [SRG_105_32_4_12],
|
3193
|
+
(120, 63, 30, 36): [SRG_120_63_30_36],
|
3194
|
+
(120, 77, 52, 44): [SRG_120_77_52_44],
|
3195
|
+
(126, 25, 8, 4): [SRG_126_25_8_4],
|
3196
|
+
(126, 50, 13, 24): [SRG_126_50_13_24],
|
3197
|
+
(144, 39, 6, 12): [SRG_144_39_6_12],
|
3198
|
+
(162, 56, 10, 24): [LocalMcLaughlinGraph],
|
3199
|
+
(175, 72, 20, 36): [SRG_175_72_20_36],
|
3200
|
+
(176, 49, 12, 14): [SRG_176_49_12_14],
|
3201
|
+
(176, 90, 38, 54): [SRG_176_90_38_54],
|
3202
|
+
(176, 105, 68, 54): [SRG_176_105_68_54],
|
3203
|
+
(196, 91, 42, 42): [SRG_196_91_42_42],
|
3204
|
+
(210, 99, 48, 45): [SRG_210_99_48_45],
|
3205
|
+
(216, 40, 4, 8): [U42Graph216],
|
3206
|
+
(220, 84, 38, 28): [SRG_220_84_38_28],
|
3207
|
+
(231, 30, 9, 3): [CameronGraph],
|
3208
|
+
(243, 110, 37, 60): [SRG_243_110_37_60],
|
3209
|
+
(253, 140, 87, 65): [SRG_253_140_87_65],
|
3210
|
+
(275, 112, 30, 56): [McLaughlinGraph],
|
3211
|
+
(276, 140, 58, 84): [SRG_276_140_58_84],
|
3212
|
+
(280, 117, 44, 52): [SRG_280_117_44_52],
|
3213
|
+
(280, 135, 70, 60): [SRG_280_135_70_60],
|
3214
|
+
(416, 100, 36, 20): [SRG_416_100_36_20],
|
3215
|
+
(540, 187, 58, 68): [U42Graph540],
|
3216
|
+
(560, 208, 72, 80): [SRG_560_208_72_80],
|
3217
|
+
(630, 85, 20, 10): [SRG_630_85_20_10],
|
3218
|
+
(765, 192, 48, 48): [IoninKharaghani765Graph],
|
3219
|
+
(784, 243, 82, 72): [MathonStronglyRegularGraph, 0],
|
3220
|
+
(784, 270, 98, 90): [MathonStronglyRegularGraph, 1],
|
3221
|
+
(784, 297, 116, 110):[MathonStronglyRegularGraph, 2],
|
3222
|
+
(936, 375, 150,150): [JankoKharaghaniGraph, 936],
|
3223
|
+
(1288,792, 476,504): [SRG_1288_792_476_504],
|
3224
|
+
(1782,416, 100, 96): [SuzukiGraph],
|
3225
|
+
(1800,1029,588,588): [JankoKharaghaniGraph, 1800],
|
3226
|
+
}
|
3227
|
+
|
3228
|
+
# Turns the known two-weight codes into SRG constructors
|
3229
|
+
#
|
3230
|
+
cdef int n, q, k, w1, w2, K, N, l, m, K_O, l_O, m_O
|
3231
|
+
import sage.coding.two_weight_db
|
3232
|
+
from sage.matrix.constructor import matrix
|
3233
|
+
from sage.rings.integer_ring import ZZ
|
3234
|
+
cinv = matrix(ZZ, [[1, 0, 0], [0, 0, 1], [0, 1, 0]])
|
3235
|
+
for code in sage.coding.two_weight_db.data:
|
3236
|
+
n, q, k, w1, w2 = code['n'], code['K'].cardinality(), code['k'], code['w1'], code['w2']
|
3237
|
+
N = q**k
|
3238
|
+
K_O = n*(q - 1)
|
3239
|
+
l_O = K_O**2 + 3*K_O - q*(w1 + w2) - K_O*q*(w1 + w2) + w1*w2*q**2
|
3240
|
+
m_O = (w1*w2*q**2)//N
|
3241
|
+
|
3242
|
+
em = eigenmatrix(N, K_O, l_O, m_O) # 1st eigenmatrix
|
3243
|
+
assert((em is not None) and (em.det() != 0))
|
3244
|
+
emi = N*em.inverse() # 2nd eigenmatrix
|
3245
|
+
# 1st and 2nd eigenmatrices equal up to renumbering graphs?
|
3246
|
+
selfdual = em == cinv*emi*cinv
|
3247
|
+
_small_srg_database[N, K_O, l_O, m_O] = \
|
3248
|
+
[lambda x: strongly_regular_from_two_intersection_set(x.transpose()), code['M']]
|
3249
|
+
if not selfdual: # we can build two graphs (not complements to each other!)
|
3250
|
+
K, s, r = emi[0, 1], emi[1, 1], emi[2, 1] # by Thm 5.7 in [CK1986]_.
|
3251
|
+
l = K + r*s + r + s
|
3252
|
+
m = K + r*s
|
3253
|
+
_small_srg_database[N, K, l, m] = [strongly_regular_from_two_weight_code, code['M']]
|
3254
|
+
|
3255
|
+
|
3256
|
+
cdef load_brouwer_database():
|
3257
|
+
r"""
|
3258
|
+
Loads Andries Brouwer's database into _brouwer_database.
|
3259
|
+
"""
|
3260
|
+
global _brouwer_database
|
3261
|
+
if _brouwer_database is not None:
|
3262
|
+
return
|
3263
|
+
|
3264
|
+
from sage.features.databases import DatabaseGraphs
|
3265
|
+
data_dir = os.path.dirname(DatabaseGraphs().absolute_filename())
|
3266
|
+
filename = os.path.join(data_dir, 'brouwer_srg_database.json')
|
3267
|
+
with open(filename) as fobj:
|
3268
|
+
database = json.load(fobj)
|
3269
|
+
|
3270
|
+
_brouwer_database = {
|
3271
|
+
(v, k, l, mu): {'status': status, 'comments': comments}
|
3272
|
+
for (v, k, l, mu, status, comments) in database
|
3273
|
+
}
|
3274
|
+
|
3275
|
+
|
3276
|
+
def _check_database():
|
3277
|
+
r"""
|
3278
|
+
Check the coherence of Andries Brouwer's database with Sage.
|
3279
|
+
|
3280
|
+
The function also outputs some statistics on the database.
|
3281
|
+
|
3282
|
+
EXAMPLES::
|
3283
|
+
|
3284
|
+
sage: from sage.graphs.strongly_regular_db import _check_database
|
3285
|
+
sage: _check_database() # long time # needs sage.libs.pari
|
3286
|
+
Sage cannot build a (512 133 24 38 ) that exists. Comment ...
|
3287
|
+
...
|
3288
|
+
In Andries Brouwer's database:
|
3289
|
+
- 462 impossible entries
|
3290
|
+
- 2911 undecided entries
|
3291
|
+
- 1165 realizable entries (Sage misses ... of them)
|
3292
|
+
"""
|
3293
|
+
global _brouwer_database
|
3294
|
+
load_brouwer_database()
|
3295
|
+
|
3296
|
+
# Check that all parameters detected as infeasible are actually infeasible
|
3297
|
+
# in Brouwer's database, for a test that was implemented.
|
3298
|
+
for params in set(_brouwer_database).difference(apparently_feasible_parameters(1301)):
|
3299
|
+
if _brouwer_database[params]['status'] != "impossible":
|
3300
|
+
raise RuntimeError("Brouwer's db does not seem to know that {} in unfeasible".format(params))
|
3301
|
+
comment = _brouwer_database[params]['comments']
|
3302
|
+
if ('Krein' in comment or
|
3303
|
+
'Absolute' in comment or
|
3304
|
+
'Conf' in comment or
|
3305
|
+
'mu=1' in comment or
|
3306
|
+
'μ=2' in comment):
|
3307
|
+
continue
|
3308
|
+
raise RuntimeError("We detected that {} was unfeasible, but maybe we should not have".format(params))
|
3309
|
+
|
3310
|
+
# We empty the global database, to be sure that strongly_regular_graph does
|
3311
|
+
# not use its data to answer.
|
3312
|
+
_brouwer_database, saved_database = {}, _brouwer_database
|
3313
|
+
|
3314
|
+
cdef int missed = 0
|
3315
|
+
for params, dic in sorted(saved_database.items()):
|
3316
|
+
sage_answer = strongly_regular_graph(*params, existence=True)
|
3317
|
+
if dic['status'] == 'open':
|
3318
|
+
if sage_answer is True:
|
3319
|
+
print("Sage can build a {}, Brouwer's database cannot".format(params))
|
3320
|
+
assert sage_answer is not False
|
3321
|
+
elif dic['status'] == 'exists':
|
3322
|
+
if sage_answer is not True:
|
3323
|
+
print(("Sage cannot build a ({:<4} {:<4} {:<4} {:<4}) that exists. " +
|
3324
|
+
"Comment from Brouwer's database: ").format(*params)
|
3325
|
+
+ dic['comments'])
|
3326
|
+
missed += 1
|
3327
|
+
assert sage_answer is not False
|
3328
|
+
elif dic['status'] == 'impossible':
|
3329
|
+
assert sage_answer is not True
|
3330
|
+
else:
|
3331
|
+
assert False # must not happen
|
3332
|
+
|
3333
|
+
status = [x['status'] for x in saved_database.values()]
|
3334
|
+
print("\nIn Andries Brouwer's database:")
|
3335
|
+
print("- {} impossible entries".format(status.count('impossible')))
|
3336
|
+
print("- {} undecided entries".format(status.count('open')))
|
3337
|
+
print("- {} realizable entries (Sage misses {} of them)".format(status.count('exists'), missed))
|
3338
|
+
|
3339
|
+
# Reassign its value to the global database
|
3340
|
+
_brouwer_database = saved_database
|