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.
Files changed (260) hide show
  1. passagemath_graphs-10.6.1rc1.dist-info/METADATA +292 -0
  2. passagemath_graphs-10.6.1rc1.dist-info/RECORD +260 -0
  3. passagemath_graphs-10.6.1rc1.dist-info/WHEEL +5 -0
  4. passagemath_graphs-10.6.1rc1.dist-info/top_level.txt +2 -0
  5. passagemath_graphs.libs/libgcc_s-69c45f16.so.1 +0 -0
  6. passagemath_graphs.libs/libgmp-8e78bd9b.so.10.5.0 +0 -0
  7. passagemath_graphs.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
  8. sage/all__sagemath_graphs.py +39 -0
  9. sage/combinat/abstract_tree.py +2723 -0
  10. sage/combinat/all__sagemath_graphs.py +34 -0
  11. sage/combinat/binary_tree.py +5306 -0
  12. sage/combinat/cluster_algebra_quiver/all.py +22 -0
  13. sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
  14. sage/combinat/cluster_algebra_quiver/interact.py +124 -0
  15. sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
  16. sage/combinat/cluster_algebra_quiver/mutation_type.py +1555 -0
  17. sage/combinat/cluster_algebra_quiver/quiver.py +2290 -0
  18. sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
  19. sage/combinat/designs/MOLS_handbook_data.py +570 -0
  20. sage/combinat/designs/all.py +58 -0
  21. sage/combinat/designs/bibd.py +1655 -0
  22. sage/combinat/designs/block_design.py +1071 -0
  23. sage/combinat/designs/covering_array.py +269 -0
  24. sage/combinat/designs/covering_design.py +530 -0
  25. sage/combinat/designs/database.py +5615 -0
  26. sage/combinat/designs/design_catalog.py +122 -0
  27. sage/combinat/designs/designs_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  28. sage/combinat/designs/designs_pyx.pxd +21 -0
  29. sage/combinat/designs/designs_pyx.pyx +993 -0
  30. sage/combinat/designs/difference_family.py +3951 -0
  31. sage/combinat/designs/difference_matrices.py +279 -0
  32. sage/combinat/designs/evenly_distributed_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  33. sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
  34. sage/combinat/designs/ext_rep.py +1064 -0
  35. sage/combinat/designs/gen_quadrangles_with_spread.cpython-310-aarch64-linux-gnu.so +0 -0
  36. sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
  37. sage/combinat/designs/group_divisible_designs.py +361 -0
  38. sage/combinat/designs/incidence_structures.py +2357 -0
  39. sage/combinat/designs/latin_squares.py +581 -0
  40. sage/combinat/designs/orthogonal_arrays.py +2244 -0
  41. sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
  42. sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-310-aarch64-linux-gnu.so +0 -0
  43. sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +967 -0
  44. sage/combinat/designs/resolvable_bibd.py +815 -0
  45. sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
  46. sage/combinat/designs/subhypergraph_search.cpython-310-aarch64-linux-gnu.so +0 -0
  47. sage/combinat/designs/subhypergraph_search.pyx +530 -0
  48. sage/combinat/designs/twographs.py +306 -0
  49. sage/combinat/finite_state_machine.py +14874 -0
  50. sage/combinat/finite_state_machine_generators.py +2006 -0
  51. sage/combinat/graph_path.py +448 -0
  52. sage/combinat/interval_posets.py +3908 -0
  53. sage/combinat/nu_tamari_lattice.py +269 -0
  54. sage/combinat/ordered_tree.py +1446 -0
  55. sage/combinat/posets/all.py +46 -0
  56. sage/combinat/posets/bubble_shuffle.py +247 -0
  57. sage/combinat/posets/cartesian_product.py +493 -0
  58. sage/combinat/posets/d_complete.py +182 -0
  59. sage/combinat/posets/elements.py +273 -0
  60. sage/combinat/posets/forest.py +30 -0
  61. sage/combinat/posets/hasse_cython.cpython-310-aarch64-linux-gnu.so +0 -0
  62. sage/combinat/posets/hasse_cython.pyx +174 -0
  63. sage/combinat/posets/hasse_diagram.py +3672 -0
  64. sage/combinat/posets/hochschild_lattice.py +158 -0
  65. sage/combinat/posets/incidence_algebras.py +794 -0
  66. sage/combinat/posets/lattices.py +5117 -0
  67. sage/combinat/posets/linear_extension_iterator.cpython-310-aarch64-linux-gnu.so +0 -0
  68. sage/combinat/posets/linear_extension_iterator.pyx +292 -0
  69. sage/combinat/posets/linear_extensions.py +1037 -0
  70. sage/combinat/posets/mobile.py +275 -0
  71. sage/combinat/posets/moebius_algebra.py +776 -0
  72. sage/combinat/posets/poset_examples.py +2178 -0
  73. sage/combinat/posets/posets.py +9360 -0
  74. sage/combinat/rooted_tree.py +1070 -0
  75. sage/combinat/shard_order.py +239 -0
  76. sage/combinat/tamari_lattices.py +384 -0
  77. sage/combinat/yang_baxter_graph.py +923 -0
  78. sage/databases/all__sagemath_graphs.py +1 -0
  79. sage/databases/knotinfo_db.py +1231 -0
  80. sage/ext_data/all__sagemath_graphs.py +1 -0
  81. sage/ext_data/graphs/graph_plot_js.html +330 -0
  82. sage/ext_data/kenzo/CP2.txt +45 -0
  83. sage/ext_data/kenzo/CP3.txt +349 -0
  84. sage/ext_data/kenzo/CP4.txt +4774 -0
  85. sage/ext_data/kenzo/README.txt +49 -0
  86. sage/ext_data/kenzo/S4.txt +20 -0
  87. sage/graphs/all.py +42 -0
  88. sage/graphs/asteroidal_triples.cpython-310-aarch64-linux-gnu.so +0 -0
  89. sage/graphs/asteroidal_triples.pyx +320 -0
  90. sage/graphs/base/all.py +1 -0
  91. sage/graphs/base/boost_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  92. sage/graphs/base/boost_graph.pxd +106 -0
  93. sage/graphs/base/boost_graph.pyx +3045 -0
  94. sage/graphs/base/c_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  95. sage/graphs/base/c_graph.pxd +106 -0
  96. sage/graphs/base/c_graph.pyx +5096 -0
  97. sage/graphs/base/dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  98. sage/graphs/base/dense_graph.pxd +28 -0
  99. sage/graphs/base/dense_graph.pyx +801 -0
  100. sage/graphs/base/graph_backends.cpython-310-aarch64-linux-gnu.so +0 -0
  101. sage/graphs/base/graph_backends.pxd +5 -0
  102. sage/graphs/base/graph_backends.pyx +797 -0
  103. sage/graphs/base/overview.py +85 -0
  104. sage/graphs/base/sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  105. sage/graphs/base/sparse_graph.pxd +90 -0
  106. sage/graphs/base/sparse_graph.pyx +1653 -0
  107. sage/graphs/base/static_dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  108. sage/graphs/base/static_dense_graph.pxd +5 -0
  109. sage/graphs/base/static_dense_graph.pyx +1032 -0
  110. sage/graphs/base/static_sparse_backend.cpython-310-aarch64-linux-gnu.so +0 -0
  111. sage/graphs/base/static_sparse_backend.pxd +27 -0
  112. sage/graphs/base/static_sparse_backend.pyx +1583 -0
  113. sage/graphs/base/static_sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  114. sage/graphs/base/static_sparse_graph.pxd +37 -0
  115. sage/graphs/base/static_sparse_graph.pyx +1375 -0
  116. sage/graphs/bipartite_graph.py +2732 -0
  117. sage/graphs/centrality.cpython-310-aarch64-linux-gnu.so +0 -0
  118. sage/graphs/centrality.pyx +1038 -0
  119. sage/graphs/cographs.py +519 -0
  120. sage/graphs/comparability.cpython-310-aarch64-linux-gnu.so +0 -0
  121. sage/graphs/comparability.pyx +851 -0
  122. sage/graphs/connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  123. sage/graphs/connectivity.pxd +157 -0
  124. sage/graphs/connectivity.pyx +4813 -0
  125. sage/graphs/convexity_properties.cpython-310-aarch64-linux-gnu.so +0 -0
  126. sage/graphs/convexity_properties.pxd +16 -0
  127. sage/graphs/convexity_properties.pyx +870 -0
  128. sage/graphs/digraph.py +4754 -0
  129. sage/graphs/digraph_generators.py +1993 -0
  130. sage/graphs/distances_all_pairs.cpython-310-aarch64-linux-gnu.so +0 -0
  131. sage/graphs/distances_all_pairs.pxd +12 -0
  132. sage/graphs/distances_all_pairs.pyx +2938 -0
  133. sage/graphs/domination.py +1363 -0
  134. sage/graphs/dot2tex_utils.py +100 -0
  135. sage/graphs/edge_connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  136. sage/graphs/edge_connectivity.pyx +1215 -0
  137. sage/graphs/generators/all.py +1 -0
  138. sage/graphs/generators/basic.py +1769 -0
  139. sage/graphs/generators/chessboard.py +538 -0
  140. sage/graphs/generators/classical_geometries.py +1611 -0
  141. sage/graphs/generators/degree_sequence.py +235 -0
  142. sage/graphs/generators/distance_regular.cpython-310-aarch64-linux-gnu.so +0 -0
  143. sage/graphs/generators/distance_regular.pyx +2846 -0
  144. sage/graphs/generators/families.py +4759 -0
  145. sage/graphs/generators/intersection.py +565 -0
  146. sage/graphs/generators/platonic_solids.py +262 -0
  147. sage/graphs/generators/random.py +2623 -0
  148. sage/graphs/generators/smallgraphs.py +5741 -0
  149. sage/graphs/generators/world_map.py +724 -0
  150. sage/graphs/generic_graph.py +26867 -0
  151. sage/graphs/generic_graph_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  152. sage/graphs/generic_graph_pyx.pxd +34 -0
  153. sage/graphs/generic_graph_pyx.pyx +1673 -0
  154. sage/graphs/genus.cpython-310-aarch64-linux-gnu.so +0 -0
  155. sage/graphs/genus.pyx +622 -0
  156. sage/graphs/graph.py +9645 -0
  157. sage/graphs/graph_coloring.cpython-310-aarch64-linux-gnu.so +0 -0
  158. sage/graphs/graph_coloring.pyx +2284 -0
  159. sage/graphs/graph_database.py +1177 -0
  160. sage/graphs/graph_decompositions/all.py +1 -0
  161. sage/graphs/graph_decompositions/bandwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  162. sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
  163. sage/graphs/graph_decompositions/clique_separators.cpython-310-aarch64-linux-gnu.so +0 -0
  164. sage/graphs/graph_decompositions/clique_separators.pyx +616 -0
  165. sage/graphs/graph_decompositions/cutwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  166. sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
  167. sage/graphs/graph_decompositions/fast_digraph.cpython-310-aarch64-linux-gnu.so +0 -0
  168. sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
  169. sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
  170. sage/graphs/graph_decompositions/graph_products.cpython-310-aarch64-linux-gnu.so +0 -0
  171. sage/graphs/graph_decompositions/graph_products.pyx +508 -0
  172. sage/graphs/graph_decompositions/modular_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  173. sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
  174. sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
  175. sage/graphs/graph_decompositions/slice_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  176. sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
  177. sage/graphs/graph_decompositions/slice_decomposition.pyx +1106 -0
  178. sage/graphs/graph_decompositions/tree_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  179. sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
  180. sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
  181. sage/graphs/graph_decompositions/vertex_separation.cpython-310-aarch64-linux-gnu.so +0 -0
  182. sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
  183. sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
  184. sage/graphs/graph_editor.py +82 -0
  185. sage/graphs/graph_generators.py +3314 -0
  186. sage/graphs/graph_generators_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  187. sage/graphs/graph_generators_pyx.pyx +95 -0
  188. sage/graphs/graph_input.py +812 -0
  189. sage/graphs/graph_latex.py +2064 -0
  190. sage/graphs/graph_list.py +410 -0
  191. sage/graphs/graph_plot.py +1756 -0
  192. sage/graphs/graph_plot_js.py +338 -0
  193. sage/graphs/hyperbolicity.cpython-310-aarch64-linux-gnu.so +0 -0
  194. sage/graphs/hyperbolicity.pyx +1704 -0
  195. sage/graphs/hypergraph_generators.py +364 -0
  196. sage/graphs/independent_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  197. sage/graphs/independent_sets.pxd +13 -0
  198. sage/graphs/independent_sets.pyx +402 -0
  199. sage/graphs/isgci.py +1033 -0
  200. sage/graphs/isoperimetric_inequalities.cpython-310-aarch64-linux-gnu.so +0 -0
  201. sage/graphs/isoperimetric_inequalities.pyx +489 -0
  202. sage/graphs/line_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  203. sage/graphs/line_graph.pyx +743 -0
  204. sage/graphs/lovasz_theta.py +77 -0
  205. sage/graphs/matching.py +1633 -0
  206. sage/graphs/matching_covered_graph.py +3590 -0
  207. sage/graphs/orientations.py +1489 -0
  208. sage/graphs/partial_cube.py +459 -0
  209. sage/graphs/path_enumeration.cpython-310-aarch64-linux-gnu.so +0 -0
  210. sage/graphs/path_enumeration.pyx +2040 -0
  211. sage/graphs/pq_trees.py +1129 -0
  212. sage/graphs/print_graphs.py +201 -0
  213. sage/graphs/schnyder.py +865 -0
  214. sage/graphs/spanning_tree.cpython-310-aarch64-linux-gnu.so +0 -0
  215. sage/graphs/spanning_tree.pyx +1457 -0
  216. sage/graphs/strongly_regular_db.cpython-310-aarch64-linux-gnu.so +0 -0
  217. sage/graphs/strongly_regular_db.pyx +3340 -0
  218. sage/graphs/traversals.cpython-310-aarch64-linux-gnu.so +0 -0
  219. sage/graphs/traversals.pxd +9 -0
  220. sage/graphs/traversals.pyx +1872 -0
  221. sage/graphs/trees.cpython-310-aarch64-linux-gnu.so +0 -0
  222. sage/graphs/trees.pxd +15 -0
  223. sage/graphs/trees.pyx +310 -0
  224. sage/graphs/tutte_polynomial.py +713 -0
  225. sage/graphs/views.cpython-310-aarch64-linux-gnu.so +0 -0
  226. sage/graphs/views.pyx +794 -0
  227. sage/graphs/weakly_chordal.cpython-310-aarch64-linux-gnu.so +0 -0
  228. sage/graphs/weakly_chordal.pyx +604 -0
  229. sage/groups/all__sagemath_graphs.py +1 -0
  230. sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
  231. sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
  232. sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-310-aarch64-linux-gnu.so +0 -0
  233. sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
  234. sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
  235. sage/knots/all.py +6 -0
  236. sage/knots/free_knotinfo_monoid.py +507 -0
  237. sage/knots/gauss_code.py +291 -0
  238. sage/knots/knot.py +682 -0
  239. sage/knots/knot_table.py +284 -0
  240. sage/knots/knotinfo.py +2900 -0
  241. sage/knots/link.py +4715 -0
  242. sage/sandpiles/all.py +13 -0
  243. sage/sandpiles/examples.py +225 -0
  244. sage/sandpiles/sandpile.py +6365 -0
  245. sage/topology/all.py +22 -0
  246. sage/topology/cell_complex.py +1214 -0
  247. sage/topology/cubical_complex.py +1976 -0
  248. sage/topology/delta_complex.py +1806 -0
  249. sage/topology/filtered_simplicial_complex.py +744 -0
  250. sage/topology/moment_angle_complex.py +823 -0
  251. sage/topology/simplicial_complex.py +5160 -0
  252. sage/topology/simplicial_complex_catalog.py +92 -0
  253. sage/topology/simplicial_complex_examples.py +1680 -0
  254. sage/topology/simplicial_complex_homset.py +205 -0
  255. sage/topology/simplicial_complex_morphism.py +836 -0
  256. sage/topology/simplicial_set.py +4102 -0
  257. sage/topology/simplicial_set_catalog.py +55 -0
  258. sage/topology/simplicial_set_constructions.py +2954 -0
  259. sage/topology/simplicial_set_examples.py +865 -0
  260. sage/topology/simplicial_set_morphism.py +1464 -0
@@ -0,0 +1,1071 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ # sage.doctest: needs sage.rings.finite_rings
3
+ r"""
4
+ Block designs
5
+
6
+ A *block design* is a set together with a family of subsets (repeated subsets
7
+ are allowed) whose members are chosen to satisfy some set of properties that are
8
+ deemed useful for a particular application. See :wikipedia:`Block_design`.
9
+
10
+ REFERENCES:
11
+
12
+ - Block design from wikipedia: :wikipedia:`Block_design`
13
+
14
+ - What is a block design?,
15
+ http://designtheory.org/library/extrep/extrep-1.1-html/node4.html (in 'The
16
+ External Representation of Block Designs' by Peter J. Cameron, Peter
17
+ Dobcsanyi, John P. Morgan, Leonard H. Soicher)
18
+
19
+ .. [Hu57] Daniel R. Hughes, "A class of non-Desarguesian projective planes",
20
+ The Canadian Journal of Mathematics (1957), http://cms.math.ca/cjm/v9/p378
21
+
22
+ .. [We07] Charles Weibel, "Survey of Non-Desarguesian planes" (2007), notices of
23
+ the AMS, vol. 54 num. 10, pages 1294--1303
24
+
25
+ AUTHORS:
26
+
27
+ - Quentin Honoré (2015): construction of Hughes plane :issue:`18527`
28
+
29
+ - Vincent Delecroix (2014): rewrite the part on projective planes :issue:`16281`
30
+
31
+ - Peter Dobcsanyi and David Joyner (2007-2008)
32
+
33
+ This is a significantly modified form of the module block_design.py (version
34
+ 0.6) written by Peter Dobcsanyi peter@designtheory.org. Thanks go to Robert
35
+ Miller for lots of good design suggestions.
36
+
37
+ .. TODO::
38
+
39
+ Implement more finite non-Desarguesian plane as in [We07]_ and
40
+ :wikipedia:`Non-Desarguesian_plane`.
41
+
42
+ Functions and methods
43
+ ---------------------
44
+ """
45
+
46
+ # ****************************************************************************
47
+ # Copyright (C) 2007 Peter Dobcsanyi <peter@designtheory.org>
48
+ # Copyright (C) 2007 David Joyner <wdjoyner@gmail.com>
49
+ #
50
+ # This program is free software: you can redistribute it and/or modify
51
+ # it under the terms of the GNU General Public License as published by
52
+ # the Free Software Foundation, either version 2 of the License, or
53
+ # (at your option) any later version.
54
+ # https://www.gnu.org/licenses/
55
+ # ****************************************************************************
56
+ from sage.arith.misc import binomial, integer_floor, is_prime_power
57
+ from sage.categories.sets_cat import EmptySetError
58
+ from sage.misc.lazy_import import lazy_import
59
+ from sage.misc.unknown import Unknown
60
+ from sage.rings.integer import Integer
61
+ from sage.rings.integer_ring import ZZ
62
+
63
+ from .incidence_structures import IncidenceStructure
64
+
65
+ lazy_import('sage.libs.gap.libgap', 'libgap')
66
+ lazy_import('sage.matrix.matrix_space', 'MatrixSpace')
67
+ lazy_import('sage.modules.free_module', 'VectorSpace')
68
+ lazy_import('sage.rings.finite_rings.finite_field_constructor', 'FiniteField')
69
+
70
+
71
+ BlockDesign = IncidenceStructure
72
+
73
+ # utility functions -----------------------------------------------------
74
+
75
+
76
+ def tdesign_params(t, v, k, L):
77
+ """
78
+ Return the design's parameters: `(t, v, b, r , k, L)`. Note that `t` must be
79
+ given.
80
+
81
+ EXAMPLES::
82
+
83
+ sage: BD = BlockDesign(7, [[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
84
+ sage: from sage.combinat.designs.block_design import tdesign_params
85
+ sage: tdesign_params(2,7,3,1)
86
+ (2, 7, 7, 3, 3, 1)
87
+ """
88
+ x = binomial(v, t)
89
+ y = binomial(k, t)
90
+ b = divmod(L * x, y)[0]
91
+ x = binomial(v-1, t-1)
92
+ y = binomial(k-1, t-1)
93
+ r = integer_floor(L * x/y)
94
+ return (t, v, b, r, k, L)
95
+
96
+
97
+ def are_hyperplanes_in_projective_geometry_parameters(v, k, lmbda, return_parameters=False):
98
+ r"""
99
+ Return ``True`` if the parameters ``(v,k,lmbda)`` are the one of hyperplanes in
100
+ a (finite Desarguesian) projective space.
101
+
102
+ In other words, test whether there exists a prime power ``q`` and an integer
103
+ ``d`` greater than two such that:
104
+
105
+ - `v = (q^{d+1}-1)/(q-1) = q^d + q^{d-1} + ... + 1`
106
+ - `k = (q^d - 1)/(q-1) = q^{d-1} + q^{d-2} + ... + 1`
107
+ - `lmbda = (q^{d-1}-1)/(q-1) = q^{d-2} + q^{d-3} + ... + 1`
108
+
109
+ If it exists, such a pair ``(q,d)`` is unique.
110
+
111
+ INPUT:
112
+
113
+ - ``v``, ``k``, ``lmbda`` -- integers
114
+
115
+ OUTPUT:
116
+
117
+ - a boolean or, if ``return_parameters`` is set to ``True`` a pair
118
+ ``(True, (q,d))`` or ``(False, (None,None))``.
119
+
120
+ EXAMPLES::
121
+
122
+ sage: from sage.combinat.designs.block_design import are_hyperplanes_in_projective_geometry_parameters
123
+ sage: are_hyperplanes_in_projective_geometry_parameters(40, 13, 4)
124
+ True
125
+ sage: are_hyperplanes_in_projective_geometry_parameters(40, 13, 4,
126
+ ....: return_parameters=True)
127
+ (True, (3, 3))
128
+ sage: PG = designs.ProjectiveGeometryDesign(3, 2, GF(3)) # needs sage.combinat
129
+ sage: PG.is_t_design(return_parameters=True) # needs sage.combinat
130
+ (True, (2, 40, 13, 4))
131
+
132
+ sage: are_hyperplanes_in_projective_geometry_parameters(15, 3, 1)
133
+ False
134
+ sage: are_hyperplanes_in_projective_geometry_parameters(15, 3, 1,
135
+ ....: return_parameters=True)
136
+ (False, (None, None))
137
+
138
+ TESTS::
139
+
140
+ sage: sgp = lambda q,d: ((q**(d+1)-1)//(q-1), (q**d-1)//(q-1), (q**(d-1)-1)//(q-1))
141
+ sage: for q in [3,4,5,7,8,9,11]:
142
+ ....: for d in [2,3,4,5]:
143
+ ....: v,k,l = sgp(q,d)
144
+ ....: assert are_hyperplanes_in_projective_geometry_parameters(v,k,l,True) == (True, (q,d))
145
+ ....: assert are_hyperplanes_in_projective_geometry_parameters(v+1,k,l) is False
146
+ ....: assert are_hyperplanes_in_projective_geometry_parameters(v-1,k,l) is False
147
+ ....: assert are_hyperplanes_in_projective_geometry_parameters(v,k+1,l) is False
148
+ ....: assert are_hyperplanes_in_projective_geometry_parameters(v,k-1,l) is False
149
+ ....: assert are_hyperplanes_in_projective_geometry_parameters(v,k,l+1) is False
150
+ ....: assert are_hyperplanes_in_projective_geometry_parameters(v,k,l-1) is False
151
+ """
152
+ import sage.arith.all as arith
153
+
154
+ q1 = Integer(v - k)
155
+ q2 = Integer(k - lmbda)
156
+
157
+ if (lmbda <= 0 or q1 < 4 or q2 < 2 or
158
+ not q1.is_prime_power() or
159
+ not q2.is_prime_power()):
160
+ return (False,(None,None)) if return_parameters else False
161
+
162
+ p1,e1 = q1.factor()[0]
163
+ p2,e2 = q2.factor()[0]
164
+
165
+ k = arith.gcd(e1,e2)
166
+ d = e1//k
167
+ q = p1**k
168
+ if e2//k != d-1 or lmbda != (q**(d-1)-1)//(q-1):
169
+ return (False,(None,None)) if return_parameters else False
170
+
171
+ return (True, (q,d)) if return_parameters else True
172
+
173
+
174
+ def ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=True, check=True):
175
+ r"""
176
+ Return a projective geometry design.
177
+
178
+ The projective geometry design `PG_d(n,q)` has for points the lines of
179
+ `\GF{q}^{n+1}`, and for blocks the `(d+1)`-dimensional subspaces of
180
+ `\GF{q}^{n+1}`, each of which contains `\frac {|\GF{q}|^{d+1}-1} {|\GF{q}|-1}` lines.
181
+ It is a `2`-design with parameters
182
+
183
+ .. MATH::
184
+
185
+ v = \binom{n+1}{1}_q,\ k = \binom{d+1}{1}_q,\ \lambda =
186
+ \binom{n-1}{d-1}_q
187
+
188
+ where the `q`-binomial coefficient `\binom{m}{r}_q` is defined by
189
+
190
+ .. MATH::
191
+
192
+ \binom{m}{r}_q = \frac{(q^m - 1)(q^{m-1} - 1) \cdots (q^{m-r+1}-1)}
193
+ {(q^r-1)(q^{r-1}-1)\cdots (q-1)}
194
+
195
+ .. SEEALSO::
196
+
197
+ :func:`AffineGeometryDesign`
198
+
199
+ INPUT:
200
+
201
+ - ``n`` -- the projective dimension
202
+
203
+ - ``d`` -- the dimension of the subspaces which make up the blocks
204
+
205
+ - ``F`` -- a finite field or a prime power
206
+
207
+ - ``algorithm`` -- set to ``None`` by default, which results in using Sage's
208
+ own implementation. In order to use GAP's implementation instead (i.e. its
209
+ ``PGPointFlatBlockDesign`` function) set ``algorithm="gap"``. Note that
210
+ GAP's "design" package must be available in this case, and that it can be
211
+ installed with the ``gap_packages`` spkg.
212
+
213
+ - ``point_coordinates`` -- ``True`` by default. Ignored and assumed to be ``False`` if
214
+ ``algorithm="gap"``. If ``True``, the ground set is indexed by coordinates
215
+ in `\GF{q}^{n+1}`. Otherwise the ground set is indexed by integers.
216
+
217
+ - ``check`` -- boolean (default: ``True``); whether to check the output
218
+
219
+ EXAMPLES:
220
+
221
+ The set of `d`-dimensional subspaces in a `n`-dimensional projective space
222
+ forms `2`-designs (or balanced incomplete block designs)::
223
+
224
+ sage: PG = designs.ProjectiveGeometryDesign(4, 2, GF(2)); PG # needs sage.combinat
225
+ Incidence structure with 31 points and 155 blocks
226
+ sage: PG.is_t_design(return_parameters=True) # needs sage.combinat
227
+ (True, (2, 31, 7, 7))
228
+
229
+ sage: PG = designs.ProjectiveGeometryDesign(3, 1, GF(4)) # needs sage.combinat
230
+ sage: PG.is_t_design(return_parameters=True) # needs sage.combinat
231
+ (True, (2, 85, 5, 1))
232
+
233
+ Check with ``F`` being a prime power::
234
+
235
+ sage: PG = designs.ProjectiveGeometryDesign(3, 2, 4); PG
236
+ Incidence structure with 85 points and 85 blocks
237
+
238
+ Use coordinates::
239
+
240
+ sage: PG = designs.ProjectiveGeometryDesign(2, 1, GF(3))
241
+ sage: PG.blocks()[0]
242
+ [(1, 0, 0), (1, 0, 1), (1, 0, 2), (0, 0, 1)]
243
+
244
+ Use indexing by integers::
245
+
246
+ sage: PG = designs.ProjectiveGeometryDesign(2, 1, GF(3), point_coordinates=0)
247
+ sage: PG.blocks()[0]
248
+ [0, 1, 2, 12]
249
+
250
+ Check that the constructor using gap also works::
251
+
252
+ sage: BD = designs.ProjectiveGeometryDesign(2, 1, GF(2), algorithm='gap') # optional - gap_package_design
253
+ sage: BD.is_t_design(return_parameters=True) # optional - gap_package_design
254
+ (True, (2, 7, 3, 1))
255
+ """
256
+ try:
257
+ q = int(F)
258
+ except TypeError:
259
+ q = F.cardinality()
260
+ else:
261
+ from sage.rings.finite_rings.finite_field_constructor import GF
262
+ F = GF(q)
263
+
264
+ if algorithm is None:
265
+ from sage.matrix.echelon_matrix import reduced_echelon_matrix_iterator
266
+
267
+ points = {p:i for i,p in enumerate(reduced_echelon_matrix_iterator(F,1,n+1,copy=True,set_immutable=True))}
268
+ blocks = []
269
+ for m1 in reduced_echelon_matrix_iterator(F,d+1,n+1,copy=False):
270
+ b = []
271
+ for m2 in reduced_echelon_matrix_iterator(F,1,d+1,copy=False):
272
+ m = m2*m1
273
+ m.echelonize()
274
+ m.set_immutable()
275
+ b.append(points[m])
276
+ blocks.append(b)
277
+ B = BlockDesign(len(points), blocks, name='ProjectiveGeometryDesign', check=check)
278
+ if point_coordinates:
279
+ B.relabel({i:p[0] for p,i in points.items()})
280
+
281
+ elif algorithm == "gap": # Requires GAP's Design
282
+ libgap.load_package("design")
283
+ D = libgap.PGPointFlatBlockDesign(n, F.order(), d)
284
+ v = D['v'].sage()
285
+ gblcks = D['blocks'].sage()
286
+ gB = []
287
+ for b in gblcks:
288
+ gB.append([x - 1 for x in b])
289
+ B = BlockDesign(v, gB, name='ProjectiveGeometryDesign', check=check)
290
+
291
+ if check:
292
+ from sage.combinat.q_analogues import q_binomial
293
+ q = F.cardinality()
294
+ if not B.is_t_design(t=2, v=q_binomial(n+1,1,q),
295
+ k=q_binomial(d+1,1,q),
296
+ l=q_binomial(n-1, d-1, q)):
297
+ raise RuntimeError("error in ProjectiveGeometryDesign "
298
+ "construction. Please e-mail sage-devel@googlegroups.com")
299
+ return B
300
+
301
+
302
+ def DesarguesianProjectivePlaneDesign(n, point_coordinates=True, check=True):
303
+ r"""
304
+ Return the Desarguesian projective plane of order ``n`` as a 2-design.
305
+
306
+ The Desarguesian projective plane of order `n` can also be defined as the
307
+ projective plane over a field of order `n`. For more information, have a
308
+ look at :wikipedia:`Projective_plane`.
309
+
310
+ INPUT:
311
+
312
+ - ``n`` -- integer which must be a power of a prime number
313
+
314
+ - ``point_coordinates`` -- boolean (default: ``True``); whether to label the
315
+ points with their homogeneous coordinates (default) or with integers
316
+
317
+ - ``check`` -- boolean (default: ``True``); whether to check that output is
318
+ correct before returning it. As this is expected to be useless, you may
319
+ want to disable it whenever you want speed.
320
+
321
+ .. SEEALSO::
322
+
323
+ :func:`ProjectiveGeometryDesign`
324
+
325
+ EXAMPLES::
326
+
327
+ sage: designs.DesarguesianProjectivePlaneDesign(2)
328
+ (7,3,1)-Balanced Incomplete Block Design
329
+ sage: designs.DesarguesianProjectivePlaneDesign(3)
330
+ (13,4,1)-Balanced Incomplete Block Design
331
+ sage: designs.DesarguesianProjectivePlaneDesign(4)
332
+ (21,5,1)-Balanced Incomplete Block Design
333
+ sage: designs.DesarguesianProjectivePlaneDesign(5)
334
+ (31,6,1)-Balanced Incomplete Block Design
335
+ sage: designs.DesarguesianProjectivePlaneDesign(6)
336
+ Traceback (most recent call last):
337
+ ...
338
+ ValueError: the order of a finite field must be a prime power
339
+ """
340
+ K = FiniteField(n, 'a')
341
+ n2 = n**2
342
+ relabel = {x: i for i, x in enumerate(K)}
343
+ Kiter = relabel
344
+ # it is much faster to iterate through a dict than through
345
+ # the finite field K
346
+
347
+ # we decompose the (equivalence class) of points [x:y:z] of the projective
348
+ # plane into an affine plane, an affine line and a point. At the same time,
349
+ # we relabel the points with the integers from 0 to n^2 + n as follows:
350
+ # - the affine plane is the set of points [x:y:1] (i.e. the third coordinate
351
+ # is nonzero) and gets relabeled from 0 to n^2-1
352
+ affine_plane = lambda x,y: relabel[x] + n * relabel[y]
353
+
354
+ # - the affine line is the set of points [x:1:0] (i.e. the third coordinate is
355
+ # zero but not the second one) and gets relabeled from n^2 to n^2 + n - 1
356
+ line_infinity = lambda x: n2 + relabel[x]
357
+
358
+ # - the point is [1:0:0] and gets relabeled n^2 + n
359
+ point_infinity = n2 + n
360
+
361
+ blcks = []
362
+
363
+ # the n^2 lines of the form "x = sy + az"
364
+ for s in Kiter:
365
+ for a in Kiter:
366
+ # points in the affine plane
367
+ blcks.append([affine_plane(s*y+a, y) for y in Kiter])
368
+ # point at infinity
369
+ blcks[-1].append(line_infinity(s))
370
+
371
+ # the n horizontals of the form "y = az"
372
+ for a in Kiter:
373
+ # points in the affine plane
374
+ blcks.append([affine_plane(x,a) for x in Kiter])
375
+ # point at infinity
376
+ blcks[-1].append(point_infinity)
377
+
378
+ # the line at infinity "z = 0"
379
+ blcks.append(range(n2,n2+n+1))
380
+ if check:
381
+ from .designs_pyx import is_projective_plane
382
+ if not is_projective_plane(blcks):
383
+ raise RuntimeError('There is a problem in the function DesarguesianProjectivePlane')
384
+ from .bibd import BalancedIncompleteBlockDesign
385
+ B = BalancedIncompleteBlockDesign(n2+n+1, blcks, check=check)
386
+
387
+ if point_coordinates:
388
+ zero = K.zero()
389
+ one = K.one()
390
+ d = {affine_plane(x,y): (x,y,one)
391
+ for x in Kiter
392
+ for y in Kiter}
393
+ d.update({line_infinity(x): (x,one,zero)
394
+ for x in Kiter})
395
+ d[n2+n] = (one,zero,zero)
396
+ B.relabel(d)
397
+
398
+ return B
399
+
400
+
401
+ def q3_minus_one_matrix(K):
402
+ r"""
403
+ Return a companion matrix in `GL(3, K)` whose multiplicative order is `q^3 - 1`.
404
+
405
+ This function is used in :func:`HughesPlane`.
406
+
407
+ EXAMPLES::
408
+
409
+ sage: from sage.combinat.designs.block_design import q3_minus_one_matrix
410
+ sage: m = q3_minus_one_matrix(GF(3))
411
+ sage: m.multiplicative_order() == 3**3 - 1
412
+ True
413
+
414
+ sage: m = q3_minus_one_matrix(GF(4, 'a'))
415
+ sage: m.multiplicative_order() == 4**3 - 1
416
+ True
417
+
418
+ sage: m = q3_minus_one_matrix(GF(5))
419
+ sage: m.multiplicative_order() == 5**3 - 1
420
+ True
421
+
422
+ sage: m = q3_minus_one_matrix(GF(9, 'a'))
423
+ sage: m.multiplicative_order() == 9**3 - 1
424
+ True
425
+ """
426
+ q = K.cardinality()
427
+ M = MatrixSpace(K, 3)
428
+
429
+ if q.is_prime():
430
+ from sage.rings.finite_rings.conway_polynomials import conway_polynomial
431
+ try:
432
+ a,b,c,_ = conway_polynomial(q, 3)
433
+ except RuntimeError: # the polynomial is not in the database
434
+ pass
435
+ else:
436
+ return M([0,0,-a,1,0,-b,0,1,-c])
437
+
438
+ m = M()
439
+ m[1,0] = m[2,1] = K.one()
440
+ while True:
441
+ m[0,2] = K._random_nonzero_element()
442
+ m[1,2] = K.random_element()
443
+ m[2,2] = K.random_element()
444
+ if m.multiplicative_order() == q**3 - 1:
445
+ return m
446
+
447
+
448
+ def normalize_hughes_plane_point(p, q):
449
+ r"""
450
+ Return the normalized form of point ``p`` as a 3-tuple.
451
+
452
+ In the Hughes projective plane over the finite field `K`, all triples `(xk,
453
+ yk, zk)` with `k \in K` represent the same point (where the multiplication
454
+ is over the nearfield built from `K`). This function chooses a canonical
455
+ representative among them.
456
+
457
+ This function is used in :func:`HughesPlane`.
458
+
459
+ INPUT:
460
+
461
+ - ``p`` -- point with the coordinates `(x,y,z)` (a list, a vector, a tuple...)
462
+
463
+ - ``q`` -- cardinality of the underlying finite field
464
+
465
+ EXAMPLES::
466
+
467
+ sage: from sage.combinat.designs.block_design import normalize_hughes_plane_point
468
+ sage: K = FiniteField(9,'x')
469
+ sage: x = K.gen()
470
+ sage: normalize_hughes_plane_point((x, x + 1, x), 9)
471
+ (1, x, 1)
472
+ sage: normalize_hughes_plane_point(vector((x,x,x)), 9)
473
+ (1, 1, 1)
474
+ sage: zero = K.zero()
475
+ sage: normalize_hughes_plane_point((2*x + 2, zero, zero), 9)
476
+ (1, 0, 0)
477
+ sage: one = K.one()
478
+ sage: normalize_hughes_plane_point((2*x, one, zero), 9)
479
+ (2*x, 1, 0)
480
+ """
481
+ for i in [2,1,0]:
482
+ if p[i].is_one():
483
+ return tuple(p)
484
+ elif not p[i].is_zero():
485
+ k = ~p[i]
486
+ if k.is_square():
487
+ return (p[0] * k,p[1] * k,p[2] * k)
488
+ else:
489
+ return ((p[0] * k)**q,(p[1]*k)**q,(p[2]*k)**q)
490
+
491
+
492
+ def HughesPlane(q2, check=True):
493
+ r"""
494
+ Return the Hughes projective plane of order ``q2``.
495
+
496
+ Let `q` be an odd prime, the Hughes plane of order `q^2` is a finite
497
+ projective plane of order `q^2` introduced by D. Hughes in [Hu57]_. Its
498
+ construction is as follows.
499
+
500
+ Let `K = GF(q^2)` be a finite field with `q^2` elements and `F = GF(q)
501
+ \subset K` be its unique subfield with `q` elements. We define a twisted
502
+ multiplication on `K` as
503
+
504
+ .. MATH::
505
+
506
+ x \circ y =
507
+ \begin{cases}
508
+ x\ y & \text{if y is a square in K}\\
509
+ x^q\ y & \text{otherwise}
510
+ \end{cases}
511
+
512
+ The points of the Hughes plane are the triples `(x, y, z)` of points in `K^3
513
+ \backslash \{0,0,0\}` up to the equivalence relation `(x,y,z) \sim (x \circ
514
+ k, y \circ k, z \circ k)` where `k \in K`.
515
+
516
+ For `a = 1` or `a \in (K \backslash F)` we define a block `L(a)` as the set of
517
+ triples `(x,y,z)` so that `x + a \circ y + z = 0`. The rest of the blocks
518
+ are obtained by letting act the group `GL(3, F)` by its standard action.
519
+
520
+ For more information, see :wikipedia:`Hughes_plane` and [We07].
521
+
522
+ .. SEEALSO::
523
+
524
+ :func:`DesarguesianProjectivePlaneDesign` to build the Desarguesian
525
+ projective planes
526
+
527
+ INPUT:
528
+
529
+ - ``q2`` -- an even power of an odd prime number
530
+
531
+ - ``check`` -- boolean (default: ``True``); whether to check that output is
532
+ correct before returning it. As this is expected to be useless, you may
533
+ want to disable it whenever you want speed.
534
+
535
+ EXAMPLES::
536
+
537
+ sage: H = designs.HughesPlane(9); H
538
+ (91,10,1)-Balanced Incomplete Block Design
539
+
540
+ We prove in the following computations that the Desarguesian plane ``H`` is
541
+ not Desarguesian. Let us consider the two triangles `(0,1,10)` and `(57, 70,
542
+ 59)`. We show that the intersection points `D_{0,1} \cap D_{57,70}`,
543
+ `D_{1,10} \cap D_{70,59}` and `D_{10,0} \cap D_{59,57}` are on the same line
544
+ while `D_{0,70}`, `D_{1,59}` and `D_{10,57}` are not concurrent::
545
+
546
+ sage: blocks = H.blocks()
547
+ sage: line = lambda p,q: next(b for b in blocks if p in b and q in b)
548
+
549
+ sage: b_0_1 = line(0, 1)
550
+ sage: b_1_10 = line(1, 10)
551
+ sage: b_10_0 = line(10, 0)
552
+ sage: b_57_70 = line(57, 70)
553
+ sage: b_70_59 = line(70, 59)
554
+ sage: b_59_57 = line(59, 57)
555
+
556
+ sage: set(b_0_1).intersection(b_57_70)
557
+ {2}
558
+ sage: set(b_1_10).intersection(b_70_59)
559
+ {73}
560
+ sage: set(b_10_0).intersection(b_59_57)
561
+ {60}
562
+
563
+ sage: line(2, 73) == line(73, 60)
564
+ True
565
+
566
+ sage: b_0_57 = line(0, 57)
567
+ sage: b_1_70 = line(1, 70)
568
+ sage: b_10_59 = line(10, 59)
569
+
570
+ sage: p = set(b_0_57).intersection(b_1_70)
571
+ sage: q = set(b_1_70).intersection(b_10_59)
572
+ sage: p == q
573
+ False
574
+
575
+ TESTS:
576
+
577
+ Some wrong input::
578
+
579
+ sage: designs.HughesPlane(5)
580
+ Traceback (most recent call last):
581
+ ...
582
+ EmptySetError: No Hughes plane of non-square order exists.
583
+
584
+ sage: designs.HughesPlane(16)
585
+ Traceback (most recent call last):
586
+ ...
587
+ EmptySetError: No Hughes plane of even order exists.
588
+
589
+ Check that it works for non-prime `q`::
590
+
591
+ sage: designs.HughesPlane(3**4) # not tested - 10 secs
592
+ (6643,82,1)-Balanced Incomplete Block Design
593
+ """
594
+ if not q2.is_square():
595
+ raise EmptySetError("No Hughes plane of non-square order exists.")
596
+ if q2 % 2 == 0:
597
+ raise EmptySetError("No Hughes plane of even order exists.")
598
+ q = q2.sqrt()
599
+ K = FiniteField(q2, prefix='x')
600
+ F = FiniteField(q, prefix='y')
601
+ A = q3_minus_one_matrix(F)
602
+ A = A.change_ring(K)
603
+ m = K.list()
604
+ V = VectorSpace(K, 3)
605
+ zero = K.zero()
606
+ one = K.one()
607
+ points = [(x, y, one) for x in m for y in m] + \
608
+ [(x, one, zero) for x in m] + \
609
+ [(one, zero, zero)]
610
+ relabel = {tuple(p):i for i,p in enumerate(points)}
611
+ blcks = []
612
+ for a in m:
613
+ if a not in F or a == 1:
614
+ # build L(a)
615
+ aa = ~a
616
+ l = []
617
+ l.append(V((-a, one, zero)))
618
+ for x in m:
619
+ y = - aa * (x+one)
620
+ if not y.is_square():
621
+ y *= aa**(q-1)
622
+ l.append(V((x, y, one)))
623
+ # compute the orbit of L(a)
624
+ blcks.append([relabel[normalize_hughes_plane_point(p,q)] for p in l])
625
+ for i in range(q2 + q):
626
+ l = [A*j for j in l]
627
+ blcks.append([relabel[normalize_hughes_plane_point(p,q)] for p in l])
628
+ from .bibd import BalancedIncompleteBlockDesign
629
+ return BalancedIncompleteBlockDesign(q2**2+q2+1, blcks, check=check)
630
+
631
+
632
+ def projective_plane_to_OA(pplane, pt=None, check=True):
633
+ r"""
634
+ Return the orthogonal array built from the projective plane ``pplane``.
635
+
636
+ The orthogonal array `OA(n+1,n,2)` is obtained from the projective plane
637
+ ``pplane`` by removing the point ``pt`` and the `n+1` lines that pass
638
+ through it`. These `n+1` lines form the `n+1` groups while the remaining
639
+ `n^2+n` lines form the transversals.
640
+
641
+ INPUT:
642
+
643
+ - ``pplane`` -- a projective plane as a 2-design
644
+
645
+ - ``pt`` -- a point in the projective plane ``pplane``; if it is not provided,
646
+ then it is set to `n^2 + n`
647
+
648
+ - ``check`` -- boolean (default: ``True``); whether to check that output is
649
+ correct before returning it. As this is expected to be useless, you may
650
+ want to disable it whenever you want speed.
651
+
652
+ EXAMPLES::
653
+
654
+ sage: from sage.combinat.designs.block_design import projective_plane_to_OA
655
+ sage: p2 = designs.DesarguesianProjectivePlaneDesign(2, point_coordinates=False)
656
+ sage: projective_plane_to_OA(p2)
657
+ [[0, 0, 0], [0, 1, 1], [1, 0, 1], [1, 1, 0]]
658
+ sage: p3 = designs.DesarguesianProjectivePlaneDesign(3, point_coordinates=False)
659
+ sage: projective_plane_to_OA(p3)
660
+ [[0, 0, 0, 0],
661
+ [0, 1, 2, 1],
662
+ [0, 2, 1, 2],
663
+ [1, 0, 2, 2],
664
+ [1, 1, 1, 0],
665
+ [1, 2, 0, 1],
666
+ [2, 0, 1, 1],
667
+ [2, 1, 0, 2],
668
+ [2, 2, 2, 0]]
669
+
670
+ sage: pp = designs.DesarguesianProjectivePlaneDesign(16, point_coordinates=False)
671
+ sage: _ = projective_plane_to_OA(pp, pt=0)
672
+ sage: _ = projective_plane_to_OA(pp, pt=3)
673
+ sage: _ = projective_plane_to_OA(pp, pt=7)
674
+ """
675
+ from .bibd import _relabel_bibd
676
+ pplane = pplane.blocks()
677
+ n = len(pplane[0]) - 1
678
+
679
+ if pt is None:
680
+ pt = n**2+n
681
+
682
+ assert len(pplane) == n**2+n+1, "pplane is not a projective plane"
683
+ assert all(len(B) == n+1 for B in pplane), "pplane is not a projective plane"
684
+
685
+ pplane = _relabel_bibd(pplane,n**2+n+1,p=n**2+n)
686
+ OA = [[x % n for x in sorted(X)] for X in pplane if n**2+n not in X]
687
+
688
+ assert len(OA) == n**2, "pplane is not a projective plane"
689
+
690
+ if check:
691
+ from .designs_pyx import is_orthogonal_array
692
+ is_orthogonal_array(OA,n+1,n,2)
693
+
694
+ return OA
695
+
696
+
697
+ def projective_plane(n, check=True, existence=False):
698
+ r"""
699
+ Return a projective plane of order ``n`` as a 2-design.
700
+
701
+ A finite projective plane is a 2-design with `n^2+n+1` lines (or blocks) and
702
+ `n^2+n+1` points. For more information on finite projective planes, see the
703
+ :wikipedia:`Projective_plane#Finite_projective_planes`.
704
+
705
+ If no construction is possible, then the function raises a :exc:`EmptySetError`,
706
+ whereas if no construction is available, the function raises a
707
+ :exc:`NotImplementedError`.
708
+
709
+ INPUT:
710
+
711
+ - ``n`` -- the finite projective plane's order
712
+
713
+ EXAMPLES::
714
+
715
+ sage: # needs sage.schemes
716
+ sage: designs.projective_plane(2)
717
+ (7,3,1)-Balanced Incomplete Block Design
718
+ sage: designs.projective_plane(3)
719
+ (13,4,1)-Balanced Incomplete Block Design
720
+ sage: designs.projective_plane(4)
721
+ (21,5,1)-Balanced Incomplete Block Design
722
+ sage: designs.projective_plane(5)
723
+ (31,6,1)-Balanced Incomplete Block Design
724
+ sage: designs.projective_plane(6)
725
+ Traceback (most recent call last):
726
+ ...
727
+ EmptySetError: By the Bruck-Ryser theorem, no projective plane of order 6 exists.
728
+ sage: designs.projective_plane(10)
729
+ Traceback (most recent call last):
730
+ ...
731
+ EmptySetError: No projective plane of order 10 exists by
732
+ C. Lam, L. Thiel and S. Swiercz "The nonexistence of finite
733
+ projective planes of order 10" (1989), Canad. J. Math.
734
+ sage: designs.projective_plane(12)
735
+ Traceback (most recent call last):
736
+ ...
737
+ NotImplementedError: If such a projective plane exists,
738
+ we do not know how to build it.
739
+ sage: designs.projective_plane(14)
740
+ Traceback (most recent call last):
741
+ ...
742
+ EmptySetError: By the Bruck-Ryser theorem, no projective plane of order 14 exists.
743
+
744
+ TESTS::
745
+
746
+ sage: # needs sage.schemes
747
+ sage: designs.projective_plane(2197, existence=True)
748
+ True
749
+ sage: designs.projective_plane(6, existence=True)
750
+ False
751
+ sage: designs.projective_plane(10, existence=True)
752
+ False
753
+ sage: designs.projective_plane(12, existence=True)
754
+ Unknown
755
+ """
756
+ from sage.combinat.designs.bibd import BruckRyserChowla_check
757
+
758
+ if n <= 1:
759
+ if existence:
760
+ return False
761
+ raise EmptySetError("There is no projective plane of order <= 1")
762
+
763
+ if n == 10:
764
+ if existence:
765
+ return False
766
+ ref = ("C. Lam, L. Thiel and S. Swiercz \"The nonexistence of finite "
767
+ "projective planes of order 10\" (1989), Canad. J. Math.")
768
+ raise EmptySetError("No projective plane of order 10 exists by %s" % ref)
769
+
770
+ if BruckRyserChowla_check(n*n+n+1, n+1, 1) is False:
771
+ if existence:
772
+ return False
773
+ raise EmptySetError("By the Bruck-Ryser theorem, no projective"
774
+ " plane of order {} exists.".format(n))
775
+
776
+ if not is_prime_power(n):
777
+ if existence:
778
+ return Unknown
779
+ raise NotImplementedError("If such a projective plane exists, we do "
780
+ "not know how to build it.")
781
+
782
+ if existence:
783
+ return True
784
+ else:
785
+ return DesarguesianProjectivePlaneDesign(n, point_coordinates=False, check=check)
786
+
787
+
788
+ def AffineGeometryDesign(n, d, F, point_coordinates=True, check=True):
789
+ r"""
790
+ Return an affine geometry design.
791
+
792
+ The affine geometry design `AG_d(n,q)` is the 2-design whose blocks are the
793
+ `d`-vector subspaces in `\GF{q}^n`. It has parameters
794
+
795
+ .. MATH::
796
+
797
+ v = q^n,\ k = q^d,\ \lambda = \binom{n-1}{d-1}_q
798
+
799
+ where the `q`-binomial coefficient `\binom{m}{r}_q` is defined by
800
+
801
+ .. MATH::
802
+
803
+ \binom{m}{r}_q = \frac{(q^m - 1)(q^{m-1} - 1) \cdots (q^{m-r+1}-1)}
804
+ {(q^r-1)(q^{r-1}-1)\cdots (q-1)}
805
+
806
+ .. SEEALSO::
807
+
808
+ :func:`ProjectiveGeometryDesign`
809
+
810
+ INPUT:
811
+
812
+ - ``n`` -- integer; the Euclidean dimension. The number of points of the
813
+ design is `v=|\GF{q}^n|`
814
+
815
+ - ``d`` -- integer; the dimension of the (affine) subspaces of `\GF{q}^n`
816
+ which make up the blocks
817
+
818
+ - ``F`` -- a finite field or a prime power
819
+
820
+ - ``point_coordinates`` -- boolean (default: ``True``); whether we use
821
+ coordinates in `\GF{q}^n` or plain integers for the points of the design
822
+
823
+ - ``check`` -- boolean (default: ``True``); whether to check the output
824
+
825
+ EXAMPLES::
826
+
827
+ sage: # needs sage.combinat
828
+ sage: BD = designs.AffineGeometryDesign(3, 1, GF(2))
829
+ sage: BD.is_t_design(return_parameters=True)
830
+ (True, (2, 8, 2, 1))
831
+ sage: BD = designs.AffineGeometryDesign(3, 2, GF(4))
832
+ sage: BD.is_t_design(return_parameters=True)
833
+ (True, (2, 64, 16, 5))
834
+ sage: BD = designs.AffineGeometryDesign(4, 2, GF(3))
835
+ sage: BD.is_t_design(return_parameters=True)
836
+ (True, (2, 81, 9, 13))
837
+
838
+ With ``F`` an integer instead of a finite field::
839
+
840
+ sage: BD = designs.AffineGeometryDesign(3, 2, 4)
841
+ sage: BD.is_t_design(return_parameters=True)
842
+ (True, (2, 64, 16, 5))
843
+
844
+ Testing the option ``point_coordinates``::
845
+
846
+ sage: designs.AffineGeometryDesign(3, 1, GF(2),
847
+ ....: point_coordinates=True).blocks()[0]
848
+ [(0, 0, 0), (0, 0, 1)]
849
+ sage: designs.AffineGeometryDesign(3, 1, GF(2),
850
+ ....: point_coordinates=False).blocks()[0]
851
+ [0, 1]
852
+ """
853
+ try:
854
+ q = int(F)
855
+ except TypeError:
856
+ q = F.cardinality()
857
+ else:
858
+ from sage.rings.finite_rings.finite_field_constructor import GF
859
+ F = GF(q)
860
+
861
+ n = int(n)
862
+ d = int(d)
863
+
864
+ from itertools import islice
865
+ from sage.combinat.q_analogues import q_binomial
866
+ from sage.matrix.echelon_matrix import reduced_echelon_matrix_iterator
867
+
868
+ points = {p:i for i,p in enumerate(reduced_echelon_matrix_iterator(F,1,n+1,copy=True,set_immutable=True)) if p[0,0]}
869
+
870
+ blocks = []
871
+ l1 = int(q_binomial(n+1, d+1, q) - q_binomial(n, d+1, q))
872
+ l2 = q**d
873
+ for m1 in islice(reduced_echelon_matrix_iterator(F,d+1,n+1,copy=False),
874
+ int(l1)):
875
+ b = []
876
+ for m2 in islice(reduced_echelon_matrix_iterator(F,1,d+1,copy=False),
877
+ int(l2)):
878
+ m = m2*m1
879
+ m.echelonize()
880
+ m.set_immutable()
881
+ b.append(points[m])
882
+ blocks.append(b)
883
+
884
+ B = BlockDesign(len(points), blocks, name='AffineGeometryDesign', check=check)
885
+
886
+ if point_coordinates:
887
+ rd = {i: p[0][1:] for p, i in points.items()}
888
+ for v in rd.values():
889
+ v.set_immutable()
890
+ B.relabel(rd)
891
+
892
+ if check:
893
+ if not B.is_t_design(t=2, v=q**n, k=q**d, l=q_binomial(n-1, d-1, q)):
894
+ raise RuntimeError("error in AffineGeometryDesign "
895
+ "construction. Please e-mail sage-devel@googlegroups.com")
896
+ return B
897
+
898
+
899
+ def CremonaRichmondConfiguration():
900
+ r"""
901
+ Return the Cremona-Richmond configuration.
902
+
903
+ The Cremona-Richmond configuration is a set system whose incidence graph
904
+ is equal to the
905
+ :meth:`~sage.graphs.graph_generators.GraphGenerators.TutteCoxeterGraph`. It
906
+ is a generalized quadrangle of parameters `(2,2)`.
907
+
908
+ For more information, see the
909
+ :wikipedia:`Cremona-Richmond_configuration`.
910
+
911
+ EXAMPLES::
912
+
913
+ sage: H = designs.CremonaRichmondConfiguration(); H # needs networkx
914
+ Incidence structure with 15 points and 15 blocks
915
+ sage: g = graphs.TutteCoxeterGraph() # needs networkx
916
+ sage: H.incidence_graph().is_isomorphic(g) # needs networkx
917
+ True
918
+ """
919
+ from sage.graphs.generators.smallgraphs import TutteCoxeterGraph
920
+ from sage.combinat.designs.incidence_structures import IncidenceStructure
921
+ g = TutteCoxeterGraph()
922
+ H = IncidenceStructure([g.neighbors(v)
923
+ for v in g.bipartite_sets()[0]])
924
+ H.relabel()
925
+ return H
926
+
927
+
928
+ def WittDesign(n):
929
+ """
930
+ INPUT:
931
+
932
+ - ``n`` -- integer in `9,10,11,12,21,22,23,24`
933
+
934
+ Wraps GAP Design's WittDesign. If ``n=24`` then this function returns the
935
+ large Witt design `W_{24}`, the unique (up to isomorphism) `5-(24,8,1)`
936
+ design. If ``n=12`` then this function returns the small Witt design
937
+ `W_{12}`, the unique (up to isomorphism) `5-(12,6,1)` design. The other
938
+ values of `n` return a block design derived from these.
939
+
940
+ .. NOTE::
941
+
942
+ Requires GAP's Design package (included in the gap_packages Sage spkg).
943
+
944
+ EXAMPLES::
945
+
946
+ sage: # optional - gap_package_design
947
+ sage: BD = designs.WittDesign(9)
948
+ sage: BD.is_t_design(return_parameters=True)
949
+ (True, (2, 9, 3, 1))
950
+ sage: BD
951
+ Incidence structure with 9 points and 12 blocks
952
+ sage: print(BD)
953
+ Incidence structure with 9 points and 12 blocks
954
+ """
955
+ libgap.load_package("design")
956
+ B = libgap.WittDesign(n)
957
+ v = B['v'].sage()
958
+ gB = [[x - 1 for x in b] for b in B['blocks'].sage()]
959
+ return BlockDesign(v, gB, name='WittDesign', check=True)
960
+
961
+
962
+ def HadamardDesign(n):
963
+ """
964
+ As described in Section 1, p. 10, in [CvL]_. The input n must have the
965
+ property that there is a Hadamard matrix of order `n+1` (and that a
966
+ construction of that Hadamard matrix has been implemented...).
967
+
968
+ EXAMPLES::
969
+
970
+ sage: # needs sage.combinat sage.modules
971
+ sage: designs.HadamardDesign(7)
972
+ Incidence structure with 7 points and 7 blocks
973
+ sage: print(designs.HadamardDesign(7))
974
+ Incidence structure with 7 points and 7 blocks
975
+
976
+ For example, the Hadamard 2-design with `n = 11` is a design whose parameters are `2-(11, 5, 2)`.
977
+ We verify that `NJ = 5J` for this design. ::
978
+
979
+ sage: # needs sage.combinat sage.modules
980
+ sage: D = designs.HadamardDesign(11); N = D.incidence_matrix()
981
+ sage: J = matrix(ZZ, 11, 11, [1]*11*11); N*J
982
+ [5 5 5 5 5 5 5 5 5 5 5]
983
+ [5 5 5 5 5 5 5 5 5 5 5]
984
+ [5 5 5 5 5 5 5 5 5 5 5]
985
+ [5 5 5 5 5 5 5 5 5 5 5]
986
+ [5 5 5 5 5 5 5 5 5 5 5]
987
+ [5 5 5 5 5 5 5 5 5 5 5]
988
+ [5 5 5 5 5 5 5 5 5 5 5]
989
+ [5 5 5 5 5 5 5 5 5 5 5]
990
+ [5 5 5 5 5 5 5 5 5 5 5]
991
+ [5 5 5 5 5 5 5 5 5 5 5]
992
+ [5 5 5 5 5 5 5 5 5 5 5]
993
+
994
+ REFERENCES:
995
+
996
+ - [CvL] P. Cameron, J. H. van Lint, Designs, graphs, codes and
997
+ their links, London Math. Soc., 1991.
998
+ """
999
+ from sage.combinat.matrices.hadamard_matrix import hadamard_matrix
1000
+ from sage.matrix.constructor import matrix
1001
+ H = hadamard_matrix(n + 1) # assumed to be normalised.
1002
+ H1 = H.matrix_from_columns(range(1,n+1))
1003
+ H2 = H1.matrix_from_rows(range(1,n+1))
1004
+ J = matrix(ZZ,n,n,[1]*n*n)
1005
+ MS = J.parent()
1006
+ A = MS((H2+J)/2) # convert -1's to 0's; coerce entries to ZZ
1007
+ # A is the incidence matrix of the block design
1008
+ return IncidenceStructure(incidence_matrix=A, name='HadamardDesign')
1009
+
1010
+
1011
+ def Hadamard3Design(n):
1012
+ r"""
1013
+ Return the Hadamard 3-design with parameters `3-(n, \frac n 2, \frac n 4 - 1)`.
1014
+
1015
+ This is the unique extension of the Hadamard `2`-design (see
1016
+ :meth:`HadamardDesign`). We implement the description from pp. 12 in
1017
+ [CvL]_.
1018
+
1019
+ INPUT:
1020
+
1021
+ - ``n`` -- integer; a multiple of 4 such that `n>4`
1022
+
1023
+ EXAMPLES::
1024
+
1025
+ sage: # needs sage.combinat sage.modules
1026
+ sage: designs.Hadamard3Design(12)
1027
+ Incidence structure with 12 points and 22 blocks
1028
+
1029
+ We verify that any two blocks of the Hadamard `3`-design `3-(8, 4, 1)`
1030
+ design meet in `0` or `2` points. More generally, it is true that any two
1031
+ blocks of a Hadamard `3`-design meet in `0` or `\frac{n}{4}` points (for `n
1032
+ > 4`).
1033
+
1034
+ ::
1035
+
1036
+ sage: # needs sage.combinat sage.modules
1037
+ sage: D = designs.Hadamard3Design(8)
1038
+ sage: N = D.incidence_matrix()
1039
+ sage: N.transpose()*N
1040
+ [4 2 2 2 2 2 2 2 2 2 2 2 2 0]
1041
+ [2 4 2 2 2 2 2 2 2 2 2 2 0 2]
1042
+ [2 2 4 2 2 2 2 2 2 2 2 0 2 2]
1043
+ [2 2 2 4 2 2 2 2 2 2 0 2 2 2]
1044
+ [2 2 2 2 4 2 2 2 2 0 2 2 2 2]
1045
+ [2 2 2 2 2 4 2 2 0 2 2 2 2 2]
1046
+ [2 2 2 2 2 2 4 0 2 2 2 2 2 2]
1047
+ [2 2 2 2 2 2 0 4 2 2 2 2 2 2]
1048
+ [2 2 2 2 2 0 2 2 4 2 2 2 2 2]
1049
+ [2 2 2 2 0 2 2 2 2 4 2 2 2 2]
1050
+ [2 2 2 0 2 2 2 2 2 2 4 2 2 2]
1051
+ [2 2 0 2 2 2 2 2 2 2 2 4 2 2]
1052
+ [2 0 2 2 2 2 2 2 2 2 2 2 4 2]
1053
+ [0 2 2 2 2 2 2 2 2 2 2 2 2 4]
1054
+
1055
+
1056
+ REFERENCES:
1057
+
1058
+ .. [CvL] \P. Cameron, J. H. van Lint, Designs, graphs, codes and
1059
+ their links, London Math. Soc., 1991.
1060
+ """
1061
+ if n == 1 or n == 4:
1062
+ raise ValueError("The Hadamard design with n = %s does not extend to a three design." % n)
1063
+ from sage.combinat.matrices.hadamard_matrix import hadamard_matrix
1064
+ from sage.matrix.constructor import matrix, block_matrix
1065
+ H = hadamard_matrix(n) # assumed to be normalised.
1066
+ H1 = H.matrix_from_columns(range(1, n))
1067
+ J = matrix(ZZ, n, n-1, [1]*(n-1)*n)
1068
+ A1 = (H1 + J) / 2
1069
+ A2 = (J - H1) / 2
1070
+ A = block_matrix(1, 2, [A1, A2]) # the incidence matrix of the design.
1071
+ return IncidenceStructure(incidence_matrix=A, name='HadamardThreeDesign')