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,993 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ r"""
3
+ Cython functions for combinatorial designs
4
+
5
+ This module implements the design methods that need to be somewhat efficient.
6
+
7
+ Functions
8
+ ---------
9
+ """
10
+
11
+ from sage.data_structures.bitset_base cimport *
12
+
13
+ from libc.string cimport memset
14
+
15
+ from cysignals.memory cimport sig_malloc, sig_realloc, sig_free
16
+ from memory_allocator cimport MemoryAllocator
17
+
18
+ from sage.misc.unknown import Unknown
19
+
20
+
21
+ def is_covering_array(array, strength=None, levels=None, verbose=False, parameters=False):
22
+ r"""
23
+ Check if the input is a covering array with given strength.
24
+
25
+ See :mod:`sage.combinat.designs.covering_array` for a definition.
26
+
27
+ INPUT:
28
+
29
+ - ``array`` -- the Covering Array to be tested
30
+
31
+ - ``strength`` -- integer; the parameter `t` of the covering array,
32
+ such that in any selection of `t` columns of the array, every `t`
33
+ -tuple appears at least once. If set to None then all t > 0 are
34
+ tested to and the maximal strength is used.
35
+
36
+ - ``levels`` -- the number of symbols that appear in ``array``
37
+ If set to None, then each unique entry in ``array`` is counted
38
+
39
+ - ``verbose`` -- boolean; whether to display some information about
40
+ the covering array
41
+
42
+ - ``parameters`` -- boolean; whether to return the parameters of
43
+ the Covering Array. If set to ``True``, the function returns a
44
+ pair ``(boolean_answer,(N,t,k,v))``.
45
+
46
+ EXAMPLES::
47
+
48
+ sage: from sage.combinat.designs.designs_pyx import is_covering_array
49
+ sage: C = [[1, 1, 1, 0],
50
+ ....: [1, 1, 0, 0],
51
+ ....: [0, 0, 0]]
52
+ sage: is_covering_array(C)
53
+ Traceback (most recent call last):
54
+ ...
55
+ ValueError: Not all rows are the same length, row 2 is not the same length as row 0
56
+
57
+ sage: C = [[0, 1, 1],
58
+ ....: [1, 1, 0],
59
+ ....: [1, 0, 1],
60
+ ....: [0, 0, 0,]]
61
+ sage: is_covering_array(C,strength=4)
62
+ Traceback (most recent call last):
63
+ ...
64
+ ValueError: Strength must be equal or less than number of columns
65
+
66
+ sage: C = [[0, 1, 1],
67
+ ....: [1, 1, 1],
68
+ ....: [1, 0, 1]]
69
+ sage: is_covering_array(C,verbose=True)
70
+ A 3 by 3 Covering Array with strength 0 with entries from a symbol set of size 2
71
+ True
72
+
73
+ sage: C = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
74
+ ....: [0, 0, 0, 0, 1, 1, 1, 1, 1, 1],
75
+ ....: [0, 1, 1, 1, 0, 0, 0, 1, 1, 1],
76
+ ....: [1, 0, 1, 1, 0, 1, 1, 0, 0, 1],
77
+ ....: [1, 1, 0, 1, 1, 0, 1, 0, 1, 0],
78
+ ....: [1, 1, 1, 0, 1, 1, 0, 1, 2, 0]]
79
+ sage: is_covering_array(C,levels=2)
80
+ Traceback (most recent call last):
81
+ ...
82
+ ValueError: Array should contain integer symbols from 0 to 1
83
+
84
+ sage: C = [[1, 0, 0, 2, 0, 2, 1, 2, 2, 1, 0, 2, 2],
85
+ ....: [1, 1, 0, 0, 2, 0, 2, 1, 2, 2, 1, 0, 2],
86
+ ....: [1, 1, 1, 0, 0, 2, 0, 2, 1, 2, 2, 1, 0],
87
+ ....: [0, 1, 1, 1, 0, 0, 2, 0, 2, 1, 2, 2, 1],
88
+ ....: [2, 0, 1, 1, 1, 0, 0, 2, 0, 2, 1, 2, 2],
89
+ ....: [1, 2, 0, 1, 1, 1, 0, 0, 2, 0, 2, 1, 2],
90
+ ....: [1, 1, 2, 0, 1, 1, 1, 0, 0, 2, 0, 2, 1],
91
+ ....: [2, 1, 1, 2, 0, 1, 1, 1, 0, 0, 2, 0, 2],
92
+ ....: [1, 2, 1, 1, 2, 0, 1, 1, 1, 0, 0, 2, 0],
93
+ ....: [0, 1, 2, 1, 1, 2, 0, 1, 1, 1, 0, 0, 2],
94
+ ....: [1, 0, 1, 2, 1, 1, 2, 0, 1, 1, 1, 0, 0],
95
+ ....: [0, 1, 0, 1, 2, 1, 1, 2, 0, 1, 1, 1, 0],
96
+ ....: [0, 0, 1, 0, 1, 2, 1, 1, 2, 0, 1, 1, 1],
97
+ ....: [2, 0, 0, 1, 0, 1, 2, 1, 1, 2, 0, 1, 1],
98
+ ....: [2, 2, 0, 0, 1, 0, 1, 2, 1, 1, 2, 0, 1],
99
+ ....: [2, 2, 2, 0, 0, 1, 0, 1, 2, 1, 1, 2, 0],
100
+ ....: [0, 2, 2, 2, 0, 0, 1, 0, 1, 2, 1, 1, 2],
101
+ ....: [1, 0, 2, 2, 2, 0, 0, 1, 0, 1, 2, 1, 1],
102
+ ....: [2, 1, 0, 2, 2, 2, 0, 0, 1, 0, 1, 2, 1],
103
+ ....: [2, 2, 1, 0, 2, 2, 2, 0, 0, 1, 0, 1, 2],
104
+ ....: [1, 2, 2, 1, 0, 2, 2, 2, 0, 0, 1, 0, 1],
105
+ ....: [2, 1, 2, 2, 1, 0, 2, 2, 2, 0, 0, 1, 0],
106
+ ....: [0, 2, 1, 2, 2, 1, 0, 2, 2, 2, 0, 0, 1],
107
+ ....: [2, 0, 2, 1, 2, 2, 1, 0, 2, 2, 2, 0, 0],
108
+ ....: [0, 2, 0, 2, 1, 2, 2, 1, 0, 2, 2, 2, 0],
109
+ ....: [0, 0, 2, 0, 2, 1, 2, 2, 1, 0, 2, 2, 2],
110
+ ....: [1, 1, 0, 2, 1, 1, 2, 1, 0, 1, 0, 0, 2],
111
+ ....: [1, 1, 1, 0, 2, 1, 1, 2, 1, 0, 1, 0, 0],
112
+ ....: [0, 1, 1, 1, 0, 2, 1, 1, 2, 1, 0, 1, 0],
113
+ ....: [0, 0, 1, 1, 1, 0, 2, 1, 1, 2, 1, 0, 1],
114
+ ....: [2, 0, 0, 1, 1, 1, 0, 2, 1, 1, 2, 1, 0],
115
+ ....: [0, 2, 0, 0, 1, 1, 1, 0, 2, 1, 1, 2, 1],
116
+ ....: [2, 0, 2, 0, 0, 1, 1, 1, 0, 2, 1, 1, 2],
117
+ ....: [1, 2, 0, 2, 0, 0, 1, 1, 1, 0, 2, 1, 1],
118
+ ....: [2, 1, 2, 0, 2, 0, 0, 1, 1, 1, 0, 2, 1],
119
+ ....: [2, 2, 1, 2, 0, 2, 0, 0, 1, 1, 1, 0, 2],
120
+ ....: [1, 2, 2, 1, 2, 0, 2, 0, 0, 1, 1, 1, 0],
121
+ ....: [0, 1, 2, 2, 1, 2, 0, 2, 0, 0, 1, 1, 1],
122
+ ....: [2, 0, 1, 2, 2, 1, 2, 0, 2, 0, 0, 1, 1],
123
+ ....: [2, 2, 0, 1, 2, 2, 1, 2, 0, 2, 0, 0, 1],
124
+ ....: [2, 2, 2, 0, 1, 2, 2, 1, 2, 0, 2, 0, 0],
125
+ ....: [0, 2, 2, 2, 0, 1, 2, 2, 1, 2, 0, 2, 0],
126
+ ....: [0, 0, 2, 2, 2, 0, 1, 2, 2, 1, 2, 0, 2],
127
+ ....: [1, 0, 0, 2, 2, 2, 0, 1, 2, 2, 1, 2, 0],
128
+ ....: [0, 1, 0, 0, 2, 2, 2, 0, 1, 2, 2, 1, 2],
129
+ ....: [1, 0, 1, 0, 0, 2, 2, 2, 0, 1, 2, 2, 1],
130
+ ....: [2, 1, 0, 1, 0, 0, 2, 2, 2, 0, 1, 2, 2],
131
+ ....: [1, 2, 1, 0, 1, 0, 0, 2, 2, 2, 0, 1, 2],
132
+ ....: [1, 1, 2, 1, 0, 1, 0, 0, 2, 2, 2, 0, 1],
133
+ ....: [2, 1, 1, 2, 1, 0, 1, 0, 0, 2, 2, 2, 0],
134
+ ....: [0, 2, 1, 1, 2, 1, 0, 1, 0, 0, 2, 2, 2],
135
+ ....: [1, 0, 2, 1, 1, 2, 1, 0, 1, 0, 0, 2, 2],
136
+ ....: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
137
+ sage: is_covering_array(C,parameters=True)
138
+ (True, (53, 3, 13, 3))
139
+
140
+ sage: C = [[1, 0, 1, 1, 2, 0, 2, 2],
141
+ ....: [2, 1, 0, 1, 1, 2, 0, 2],
142
+ ....: [2, 2, 1, 0, 1, 1, 2, 0],
143
+ ....: [0, 2, 2, 1, 0, 1, 1, 2],
144
+ ....: [2, 0, 2, 2, 1, 0, 1, 1],
145
+ ....: [1, 2, 0, 2, 2, 1, 0, 1],
146
+ ....: [1, 1, 2, 0, 2, 2, 1, 0],
147
+ ....: [0, 1, 1, 2, 0, 2, 2, 1]]
148
+ sage: is_covering_array(C,strength=2,parameters=True)
149
+ (False, (8, 0, 8, 3))
150
+ """
151
+ from itertools import product, combinations
152
+
153
+ if levels is None:
154
+ symbol_list = list({x for l in array for x in l})
155
+ levels = len(symbol_list)
156
+ else:
157
+ symbol_list = range(levels)
158
+
159
+ number_rows = len(array)
160
+ number_columns = len(array[0])
161
+
162
+ for row in array:
163
+ if len(row) != number_columns:
164
+ raise ValueError("Not all rows are the same length, row {} is not the same length as row 0".format(array.index(row)))
165
+ else:
166
+ for entry in row:
167
+ if int(entry) != entry or entry < -1 or entry >= levels:
168
+ raise ValueError("Array should contain integer symbols from 0 to {}".format(levels-1))
169
+
170
+ result = True
171
+
172
+ # If strength t is inputted, check that for every selection of t
173
+ # columns, each v^t t-tuple is found in some row.
174
+ if strength:
175
+ if strength > number_columns:
176
+ raise ValueError("Strength must be equal or less than number of columns")
177
+ wstrength = strength
178
+ for comb in combinations(range(number_columns), wstrength):
179
+ existing_ttuples = set(tuple([row[ti] for ti in comb]) for row in array)
180
+ if len(existing_ttuples) != levels ** wstrength:
181
+ wstrength = 0
182
+ result = False
183
+ break
184
+
185
+ # If no strength t is inputted, starting at t=1 check all t until
186
+ # one of the v^t t-tuples does not appear.
187
+ else:
188
+ wstrength = 1
189
+ finished = False
190
+ do_iterate = True
191
+ while finished is False:
192
+ for comb in combinations(range(number_columns), wstrength):
193
+ tuple_dictionary = {item: 0 for item in product(symbol_list, repeat=wstrength)}
194
+ for row in array:
195
+ tuple_dictionary[tuple([row[ti] for ti in comb])] += 1
196
+ if 0 in tuple_dictionary.values():
197
+ wstrength -= 1
198
+ finished = True
199
+ break
200
+ elif do_iterate and any(value < levels for value in tuple_dictionary.values()):
201
+ do_iterate = False
202
+ finished = True
203
+ if finished is False and wstrength < number_columns and do_iterate:
204
+ wstrength += 1
205
+
206
+ if verbose:
207
+ print('A {} by {} Covering Array with strength {} with entries from a symbol set of size {}'.format(number_rows, number_columns, wstrength, levels))
208
+
209
+ if parameters:
210
+ return (result, (number_rows, wstrength, number_columns, levels))
211
+ else:
212
+ return result
213
+
214
+
215
+ def is_orthogonal_array(OA, int k, int n, int t=2, verbose=False, terminology='OA'):
216
+ r"""
217
+ Check that the integer matrix `OA` is an `OA(k,n,t)`.
218
+
219
+ See :func:`~sage.combinat.designs.orthogonal_arrays.orthogonal_array`
220
+ for a definition.
221
+
222
+ INPUT:
223
+
224
+ - ``OA`` -- the Orthogonal Array to be tested
225
+
226
+ - ``k``, ``n``, ``t`` -- integers; only implemented for `t=2`
227
+
228
+ - ``verbose`` -- boolean; whether to display some information when ``OA``
229
+ is not an orthogonal array `OA(k,n)`
230
+
231
+ - ``terminology`` -- string; how to phrase the information when ``verbose =
232
+ True``. Possible values are `"OA"`, `"MOLS"`
233
+
234
+ EXAMPLES::
235
+
236
+ sage: # needs sage.schemes
237
+ sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array
238
+ sage: OA = designs.orthogonal_arrays.build(8,9)
239
+ sage: is_orthogonal_array(OA,8,9)
240
+ True
241
+ sage: is_orthogonal_array(OA,8,10)
242
+ False
243
+ sage: OA[4][3] = 1
244
+ sage: is_orthogonal_array(OA,8,9)
245
+ False
246
+ sage: is_orthogonal_array(OA,8,9,verbose=True)
247
+ Columns 0 and 3 are not orthogonal
248
+ False
249
+ sage: is_orthogonal_array(OA,8,9, verbose=True, terminology='MOLS')
250
+ Squares 0 and 3 are not orthogonal
251
+ False
252
+
253
+ TESTS::
254
+
255
+ sage: # needs sage.schemes
256
+ sage: is_orthogonal_array(OA,8,9, t=3)
257
+ Traceback (most recent call last):
258
+ ...
259
+ NotImplementedError: only implemented for t=2
260
+ sage: is_orthogonal_array([[3]*8],8,9, verbose=True)
261
+ The number of rows is 1 instead of 9^2=81
262
+ False
263
+ sage: is_orthogonal_array([[3]*8],8,9, verbose=True, terminology='MOLS')
264
+ All squares do not have dimension n^2=9^2
265
+ False
266
+ sage: is_orthogonal_array([[3]*7],8,9, verbose=True)
267
+ Some row does not have length 8
268
+ False
269
+ sage: is_orthogonal_array([[3]*7],8,9, verbose=True, terminology='MOLS')
270
+ The number of squares is not 6
271
+ False
272
+
273
+ Up to relabelling, there is a unique `OA(3,2)`. So their number is just the
274
+ cardinality of the relabeling group which is `S_2^3 \times S_3` and has
275
+ cardinality `48`::
276
+
277
+ sage: from itertools import product
278
+ sage: n = 0
279
+ sage: for a in product(product((0,1), repeat=3), repeat=4): # needs sage.schemes
280
+ ....: if is_orthogonal_array(a,3,2):
281
+ ....: n += 1
282
+ sage: n # needs sage.schemes
283
+ 48
284
+ """
285
+ cdef int n2 = n*n
286
+ cdef int x
287
+
288
+ if t != 2:
289
+ raise NotImplementedError("only implemented for t=2")
290
+
291
+ for R in OA:
292
+ if len(R) != k:
293
+ if verbose:
294
+ print({"OA": "Some row does not have length "+str(k),
295
+ "MOLS": "The number of squares is not "+str(k-2)}[terminology])
296
+ return False
297
+
298
+ if len(OA) != n2:
299
+ if verbose:
300
+ print({"OA": "The number of rows is {} instead of {}^2={}".format(len(OA),n,n2),
301
+ "MOLS": "All squares do not have dimension n^2={}^2".format(n)}[terminology])
302
+ return False
303
+
304
+ if n == 0:
305
+ return True
306
+
307
+ cdef int i,j,l
308
+
309
+ # A copy of OA
310
+ cdef MemoryAllocator mem = MemoryAllocator()
311
+ cdef unsigned short * OAc = <unsigned short *> mem.malloc(k*n2*sizeof(unsigned short))
312
+
313
+ cdef unsigned short * C1
314
+ cdef unsigned short * C2
315
+
316
+ # failed malloc ?
317
+ if OAc is NULL:
318
+ raise MemoryError
319
+
320
+ # Filling OAc
321
+ for i,R in enumerate(OA):
322
+ for j,x in enumerate(R):
323
+ if x < 0 or x >= n:
324
+ if verbose:
325
+ print({"OA": "{} is not in the interval [0..{}]".format(x,n-1),
326
+ "MOLS": "Entry {} was expected to be in the interval [0..{}]".format(x,n-1)}[terminology])
327
+ return False
328
+ OAc[j*n2+i] = x
329
+
330
+ # A bitset to keep track of pairs of values
331
+ cdef bitset_t seen
332
+ bitset_init(seen, n2)
333
+
334
+ for i in range(k): # For any column C1
335
+ C1 = OAc+i*n2
336
+ for j in range(i+1,k): # For any column C2 > C1
337
+ C2 = OAc+j*n2
338
+ bitset_set_first_n(seen, 0) # No pair has been seen yet
339
+ for l in range(n2):
340
+ bitset_add(seen,n*C1[l]+C2[l])
341
+
342
+ if bitset_len(seen) != n2: # Have we seen all pairs ?
343
+ bitset_free(seen)
344
+ if verbose:
345
+ print({"OA": "Columns {} and {} are not orthogonal".format(i,j),
346
+ "MOLS": "Squares {} and {} are not orthogonal".format(i,j)}[terminology])
347
+ return False
348
+
349
+ bitset_free(seen)
350
+ return True
351
+
352
+
353
+ def is_group_divisible_design(groups, blocks, v, G=None, K=None, lambd=1, verbose=False):
354
+ r"""
355
+ Check that input is a Group Divisible Design on `\{0, \ldots, v-1\}`.
356
+
357
+ For more information on Group Divisible Designs, see
358
+ :class:`~sage.combinat.designs.group_divisible_designs.GroupDivisibleDesign`.
359
+
360
+ INPUT:
361
+
362
+ - ``groups`` -- a partition of `X`. If set to ``None`` the groups are
363
+ guessed automatically, and the function returns ``(True, guessed_groups)``
364
+ instead of ``True``
365
+
366
+ - ``blocks`` -- collection of blocks
367
+
368
+ - ``v`` -- integers; size of the ground set assumed to be `X=\{0,...,v-1\}`
369
+
370
+ - ``G`` -- list of integers of which the sizes of the groups must be
371
+ elements. Set to ``None`` (automatic guess) by default
372
+
373
+ - ``K`` -- list of integers of which the sizes of the blocks must be
374
+ elements. Set to ``None`` (automatic guess) by default
375
+
376
+ - ``lambd`` -- value of `\lambda`. Set to `1` by default
377
+
378
+ - ``verbose`` -- boolean; whether to display some information when the
379
+ design is not a GDD
380
+
381
+ EXAMPLES::
382
+
383
+ sage: from sage.combinat.designs.designs_pyx import is_group_divisible_design
384
+ sage: TD = designs.transversal_design(4,10) # needs sage.modules
385
+ sage: groups = [list(range(i*10,(i+1)*10)) for i in range(4)]
386
+ sage: is_group_divisible_design(groups,TD,40,lambd=1) # needs sage.modules
387
+ True
388
+
389
+ TESTS::
390
+
391
+ sage: TD = designs.transversal_design(4,10) # needs sage.modules
392
+ sage: groups = [list(range(i*10,(i+1)*10)) for i in range(4)]
393
+ sage: is_group_divisible_design(groups, TD, 40, lambd=2, verbose=True) # needs sage.modules
394
+ the pair (0,10) has been seen 1 times but lambda=2
395
+ False
396
+ sage: is_group_divisible_design([[1,2],[3,4]],[[1,2]],40,lambd=1,verbose=True)
397
+ groups is not a partition of [0,...,39]
398
+ False
399
+ sage: is_group_divisible_design([list(range(40))],[[1,2]],40,lambd=1,verbose=True)
400
+ the pair (1,2) belongs to a group but appears in some block
401
+ False
402
+ sage: is_group_divisible_design([list(range(40))],[[2,2]],40,lambd=1,verbose=True)
403
+ The following block has repeated elements: [2, 2]
404
+ False
405
+ sage: is_group_divisible_design([list(range(40))],[["e",2]],40,lambd=1,verbose=True)
406
+ e does not belong to [0,...,39]
407
+ False
408
+ sage: is_group_divisible_design([list(range(40))],[list(range(40))],40,G=[5],lambd=1,verbose=True)
409
+ a group has size 40 while G=[5]
410
+ False
411
+ sage: is_group_divisible_design([list(range(40))],[["e",2]],40,K=[1],lambd=1,verbose=True)
412
+ a block has size 2 while K=[1]
413
+ False
414
+
415
+ sage: # needs sage.schemes
416
+ sage: p = designs.projective_plane(3)
417
+ sage: is_group_divisible_design(None, p.blocks(), 13)
418
+ (True, [[0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12]])
419
+ sage: is_group_divisible_design(None, p.blocks()*2, 13, verbose=True)
420
+ the pair (0,1) has been seen 2 times but lambda=1
421
+ False
422
+ sage: is_group_divisible_design(None, p.blocks()*2, 13, lambd=2)
423
+ (True, [[0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12]])
424
+ """
425
+ cdef int n = v
426
+ cdef int i,ii,j,jj,s
427
+ cdef int l = lambd
428
+ cdef bint guess_groups = groups is None
429
+
430
+ if v < 0 or lambd < 0:
431
+ if verbose:
432
+ print("v={} and lambda={} must be nonnegative integers".format(v,l))
433
+ return False
434
+
435
+ # Block sizes are element of K
436
+ if K is not None:
437
+ K = set(K)
438
+ for b in blocks:
439
+ if not len(b) in K:
440
+ if verbose:
441
+ print("a block has size {} while K={}".format(len(b),list(K)))
442
+ return False
443
+
444
+ # Check that "groups" consists of disjoint sets whose union has length n
445
+ if (groups is not None and
446
+ (sum(len(g) for g in groups) != n or
447
+ len(set().union(*groups)) != n)):
448
+ if verbose:
449
+ print("groups is not a partition of [0,...,{}]".format(n-1))
450
+ return False
451
+
452
+ # Checks that the blocks are indeed sets and do not repeat elements
453
+ for b in blocks:
454
+ if len(b) != len(set(b)):
455
+ if verbose:
456
+ print("The following block has repeated elements: {}".format(b))
457
+ return False
458
+
459
+ # Check that the groups/blocks belong to [0,...,n-1]
460
+ from itertools import chain
461
+ for b in chain(groups if groups is not None else [],blocks):
462
+ for x in b:
463
+ try:
464
+ i = x
465
+ except TypeError:
466
+ i = -1
467
+ if i < 0 or i >= n:
468
+ if verbose:
469
+ print("{} does not belong to [0,...,{}]".format(x, n-1))
470
+ return False
471
+
472
+ cdef MemoryAllocator mem = MemoryAllocator()
473
+ cdef unsigned short * matrix = <unsigned short *> mem.calloc(n*n, sizeof(unsigned short))
474
+
475
+ # Counts the number of occurrences of each pair of points
476
+ for b in blocks:
477
+ s = len(b)
478
+ for i in range(s):
479
+ ii = b[i]
480
+ for j in range(i+1,s):
481
+ jj = b[j]
482
+ matrix[ii*n+jj] += 1
483
+ matrix[jj*n+ii] += 1
484
+
485
+ # Guess the groups (if necessary)
486
+ if groups is None:
487
+ from sage.sets.disjoint_set import DisjointSet_of_integers
488
+ groups = DisjointSet_of_integers(n)
489
+ for i in range(n):
490
+ for j in range(i + 1, n):
491
+ if matrix[i * n + j] == 0:
492
+ groups.union(i, j)
493
+ groups = list(groups.root_to_elements_dict().values())
494
+
495
+ # Group sizes are element of G
496
+ if G is not None:
497
+ G = set(G)
498
+ for g in groups:
499
+ if not len(g) in G:
500
+ if verbose:
501
+ print("a group has size {} while G={}".format(len(g),list(G)))
502
+ return False
503
+
504
+ # Checks that two points of the same group were never covered
505
+ for g in groups:
506
+ s = len(g)
507
+ for i in range(s):
508
+ ii = g[i]
509
+ for j in range(i+1,s):
510
+ jj = g[j]
511
+ if matrix[ii*n+jj] != 0:
512
+ if verbose:
513
+ print("the pair ({},{}) belongs to a group but appears in some block".format(ii, jj))
514
+ return False
515
+
516
+ # We fill the entries with what is expected by the next loop
517
+ matrix[ii*n+jj] = l
518
+ matrix[jj*n+ii] = l
519
+
520
+ # Checking that what should be equal to lambda IS equal to lambda
521
+ for i in range(n):
522
+ for j in range(i+1,n):
523
+ if matrix[i*n+j] != l:
524
+ if verbose:
525
+ print("the pair ({},{}) has been seen {} times but lambda={}".format(i,j,matrix[i*n+j],l))
526
+ return False
527
+
528
+ return True if not guess_groups else (True, groups)
529
+
530
+
531
+ def is_pairwise_balanced_design(blocks, v, K=None, lambd=1, verbose=False):
532
+ r"""
533
+ Check that input is a Pairwise Balanced Design (PBD) on `\{0, \ldots, v-1\}`.
534
+
535
+ For more information on Pairwise Balanced Designs (PBD), see
536
+ :class:`~sage.combinat.designs.bibd.PairwiseBalancedDesign`.
537
+
538
+ INPUT:
539
+
540
+ - ``blocks`` -- collection of blocks
541
+
542
+ - ``v`` -- integers; size of the ground set assumed to be `X=\{0,...,v-1\}`
543
+
544
+ - ``K`` -- list of integers of which the sizes of the blocks must be
545
+ elements; set to ``None`` (automatic guess) by default
546
+
547
+ - ``lambd`` -- value of `\lambda` (default: `1`)
548
+
549
+ - ``verbose`` -- boolean; whether to display some information when the
550
+ design is not a PBD
551
+
552
+ EXAMPLES::
553
+
554
+ sage: from sage.combinat.designs.designs_pyx import is_pairwise_balanced_design
555
+ sage: sts = designs.steiner_triple_system(9)
556
+ sage: is_pairwise_balanced_design(sts,9,[3],1)
557
+ True
558
+ sage: TD = designs.transversal_design(4,10).blocks() # needs sage.modules
559
+ sage: groups = [list(range(i*10,(i+1)*10)) for i in range(4)]
560
+ sage: is_pairwise_balanced_design(TD + groups, 40, [4,10], 1, verbose=True) # needs sage.modules
561
+ True
562
+
563
+ TESTS::
564
+
565
+ sage: from sage.combinat.designs.designs_pyx import is_pairwise_balanced_design
566
+ sage: is_pairwise_balanced_design(TD + groups, 40, [4,10], 2, verbose=True) # needs sage.modules
567
+ the pair (0,1) has been seen 1 times but lambda=2
568
+ False
569
+ sage: is_pairwise_balanced_design(TD + groups, 40, [10], 1, verbose=True) # needs sage.modules
570
+ a block has size 4 while K=[10]
571
+ False
572
+ sage: is_pairwise_balanced_design([[2,2]], 40, [2], 1, verbose=True)
573
+ The following block has repeated elements: [2, 2]
574
+ False
575
+ sage: is_pairwise_balanced_design([["e",2]], 40, [2], 1, verbose=True)
576
+ e does not belong to [0,...,39]
577
+ False
578
+ """
579
+ return is_group_divisible_design([[i] for i in range(v)],
580
+ blocks,
581
+ v,
582
+ K=K,
583
+ lambd=lambd,
584
+ verbose=verbose)
585
+
586
+
587
+ def is_projective_plane(blocks, verbose=False):
588
+ r"""
589
+ Test whether the blocks form a projective plane on `\{0,...,v-1\}`.
590
+
591
+ A *projective plane* is an incidence structure that has the following properties:
592
+
593
+ 1. Given any two distinct points, there is exactly one line incident with both of them.
594
+ 2. Given any two distinct lines, there is exactly one point incident with both of them.
595
+ 3. There are four points such that no line is incident with more than two of them.
596
+
597
+ For more informations, see :wikipedia:`Projective_plane`.
598
+
599
+ :meth:`~IncidenceStructure.is_t_design` can also check if an incidence structure is a projective plane
600
+ with the parameters `v=k^2+k+1`, `t=2` and `l=1`.
601
+
602
+ INPUT:
603
+
604
+ - ``blocks`` -- collection of blocks
605
+
606
+ - ``verbose`` -- whether to print additional information
607
+
608
+ EXAMPLES::
609
+
610
+ sage: from sage.combinat.designs.designs_pyx import is_projective_plane
611
+ sage: p = designs.projective_plane(4) # needs sage.schemes
612
+ sage: b = p.blocks() # needs sage.schemes
613
+ sage: is_projective_plane(b, verbose=True) # needs sage.schemes
614
+ True
615
+
616
+ sage: # needs sage.schemes
617
+ sage: p = designs.projective_plane(2)
618
+ sage: b = p.blocks()
619
+ sage: is_projective_plane(b)
620
+ True
621
+ sage: b[0][2] = 5
622
+ sage: is_projective_plane(b, verbose=True)
623
+ the pair (0,5) has been seen 2 times but lambda=1
624
+ False
625
+
626
+ sage: is_projective_plane([[0,1,2],[1,2,4]], verbose=True)
627
+ the pair (0,3) has been seen 0 times but lambda=1
628
+ False
629
+
630
+ sage: is_projective_plane([[1]], verbose=True)
631
+ First block has less than 3 points.
632
+ False
633
+
634
+ sage: # needs sage.schemes
635
+ sage: p = designs.projective_plane(2)
636
+ sage: b = p.blocks()
637
+ sage: b[2].append(4)
638
+ sage: is_projective_plane(b, verbose=True)
639
+ a block has size 4 while K=[3]
640
+ False
641
+ """
642
+ if not blocks:
643
+ if verbose:
644
+ print('There is no block.')
645
+ return False
646
+ k = len(blocks[0])-1
647
+ if k < 2:
648
+ if verbose:
649
+ print('First block has less than 3 points.')
650
+ return False
651
+ v = k**2 + k + 1
652
+ return is_group_divisible_design([[i] for i in range(v)],
653
+ blocks,
654
+ v,
655
+ K=[k+1],
656
+ lambd=1,
657
+ verbose=verbose)
658
+
659
+
660
+ def is_difference_matrix(M, G, k, lmbda=1, verbose=False):
661
+ r"""
662
+ Test if `M` is a `(G,k,\lambda)`-difference matrix.
663
+
664
+ A matrix `M` is a `(G,k,\lambda)`-difference matrix if its entries are
665
+ element of `G`, and if for any two rows `R,R'` of `M` and `x\in G` there
666
+ are exactly `\lambda` values `i` such that `R_i-R'_i=x`.
667
+
668
+ INPUT:
669
+
670
+ - ``M`` -- a matrix with entries from ``G``
671
+
672
+ - ``G`` -- a group
673
+
674
+ - ``k`` -- integer
675
+
676
+ - ``lmbda`` -- integer (default: `1`)
677
+
678
+ - ``verbose`` -- boolean; whether to print some information when the answer
679
+ is ``False``
680
+
681
+ EXAMPLES::
682
+
683
+ sage: from sage.combinat.designs.designs_pyx import is_difference_matrix
684
+ sage: q = 3**3
685
+ sage: F = GF(q,'x') # needs sage.rings.finite_rings
686
+ sage: M = [[x*y for y in F] for x in F] # needs sage.rings.finite_rings
687
+ sage: is_difference_matrix(M,F,q,verbose=1) # needs sage.rings.finite_rings
688
+ True
689
+
690
+ sage: B = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
691
+ ....: [0, 1, 2, 3, 4, 2, 3, 4, 0, 1],
692
+ ....: [0, 2, 4, 1, 3, 3, 0, 2, 4, 1]]
693
+ sage: G = GF(5)
694
+ sage: B = [[G(b) for b in R] for R in B]
695
+ sage: is_difference_matrix(list(zip(*B)),G,3,2)
696
+ True
697
+
698
+ Bad input::
699
+
700
+ sage: # needs sage.rings.finite_rings
701
+ sage: for R in M: R.append(None)
702
+ sage: is_difference_matrix(M,F,q,verbose=1)
703
+ The matrix has 28 columns but k=27
704
+ False
705
+ sage: for R in M: _=R.pop(-1)
706
+ sage: M.append([None]*3**3)
707
+ sage: is_difference_matrix(M,F,q,verbose=1)
708
+ The matrix has 28 rows instead of lambda(|G|-1+2u)+mu=1(27-1+2.0)+1=27
709
+ False
710
+ sage: _= M.pop(-1)
711
+ sage: for R in M: R[-1] = 0
712
+ sage: is_difference_matrix(M,F,q,verbose=1)
713
+ Columns 0 and 26 generate 0 exactly 27 times instead of the expected mu(=1)
714
+ False
715
+ sage: for R in M: R[-1] = 1
716
+ sage: M[-1][-1] = 0
717
+ sage: is_difference_matrix(M,F,q,verbose=1)
718
+ Columns 0 and 26 do not generate all elements of G exactly lambda(=1) times.
719
+ The element x appeared 0 times as a difference.
720
+ False
721
+ """
722
+ return is_quasi_difference_matrix(M,G,k,lmbda=lmbda,mu=lmbda,u=0,verbose=verbose)
723
+
724
+
725
+ def is_quasi_difference_matrix(M, G, int k, int lmbda, int mu, int u, verbose=False):
726
+ r"""
727
+ Test if the matrix is a `(G,k;\lambda,\mu;u)`-quasi-difference matrix.
728
+
729
+ Let `G` be an abelian group of order `n`. A
730
+ `(n,k;\lambda,\mu;u)`-quasi-difference matrix (QDM) is a matrix `Q_{ij}`
731
+ with `\lambda(n-1+2u)+\mu` rows and `k` columns, with each entry either
732
+ equal to ``None`` (i.e. the 'missing entries') or to an element of `G`. Each
733
+ column contains exactly `\lambda u` empty entries, and each row contains at
734
+ most one ``None``. Furthermore, for each `1\leq i<j\leq k`, the multiset
735
+
736
+ .. MATH::
737
+
738
+ \{q_{li}-q_{lj}:1\leq l\leq \lambda (n-1+2u)+\mu, \text{ with } q_{li}\text{ and }q_{lj}\text{ not empty}\}
739
+
740
+ contains `\lambda` times every nonzero element of `G` and contains `\mu`
741
+ times `0`.
742
+
743
+ INPUT:
744
+
745
+ - ``M`` -- a matrix with entries from ``G`` (or equal to ``None`` for
746
+ missing entries)
747
+
748
+ - ``G`` -- a group
749
+
750
+ - ``k``, ``lmbda``, ``mu``, ``u`` -- integers
751
+
752
+ - ``verbose`` -- boolean; whether to print some information when the answer
753
+ is ``False``
754
+
755
+ EXAMPLES:
756
+
757
+ Differences matrices::
758
+
759
+ sage: from sage.combinat.designs.designs_pyx import is_quasi_difference_matrix
760
+ sage: q = 3**3
761
+ sage: F = GF(q,'x') # needs sage.rings.finite_rings
762
+ sage: M = [[x*y for y in F] for x in F] # needs sage.rings.finite_rings
763
+ sage: is_quasi_difference_matrix(M,F,q,1,1,0,verbose=1) # needs sage.rings.finite_rings
764
+ True
765
+
766
+ sage: B = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
767
+ ....: [0, 1, 2, 3, 4, 2, 3, 4, 0, 1],
768
+ ....: [0, 2, 4, 1, 3, 3, 0, 2, 4, 1]]
769
+ sage: G = GF(5)
770
+ sage: B = [[G(b) for b in R] for R in B]
771
+ sage: is_quasi_difference_matrix(list(zip(*B)),G,3,2,2,0)
772
+ True
773
+
774
+ A quasi-difference matrix from the database::
775
+
776
+ sage: from sage.combinat.designs.database import QDM
777
+ sage: G,M = QDM[38,1][37,1,1,1][1]()
778
+ sage: is_quasi_difference_matrix(M,G,k=6,lmbda=1,mu=1,u=1)
779
+ True
780
+
781
+ Bad input::
782
+
783
+ sage: is_quasi_difference_matrix(M,G,k=6,lmbda=1,mu=1,u=3,verbose=1)
784
+ The matrix has 39 rows instead of lambda(|G|-1+2u)+mu=1(37-1+2.3)+1=43
785
+ False
786
+ sage: is_quasi_difference_matrix(M,G,k=6,lmbda=1,mu=2,u=1,verbose=1)
787
+ The matrix has 39 rows instead of lambda(|G|-1+2u)+mu=1(37-1+2.1)+2=40
788
+ False
789
+ sage: M[3][1] = None
790
+ sage: is_quasi_difference_matrix(M,G,k=6,lmbda=1,mu=1,u=1,verbose=1)
791
+ Row 3 contains more than one empty entry
792
+ False
793
+ sage: M[3][1] = 1
794
+ sage: M[6][1] = None
795
+ sage: is_quasi_difference_matrix(M,G,k=6,lmbda=1,mu=1,u=1,verbose=1)
796
+ Column 1 contains 2 empty entries instead of the expected lambda.u=1.1=1
797
+ False
798
+ """
799
+ from sage.combinat.designs.difference_family import group_law
800
+
801
+ assert k>=2
802
+ assert lmbda >=1
803
+ assert mu>=0
804
+ assert u>=0
805
+
806
+ cdef int n = G.cardinality()
807
+ cdef int M_nrows = len(M)
808
+ cdef int i,j,ii
809
+ cdef bint bit
810
+
811
+ # Height of the matrix
812
+ if lmbda*(n-1+2*u)+mu != M_nrows:
813
+ if verbose:
814
+ print("The matrix has {} rows instead of lambda(|G|-1+2u)+mu={}({}-1+2.{})+{}={}".format(M_nrows,lmbda,n,u,mu,lmbda*(n-1+2*u)+mu))
815
+ return False
816
+
817
+ # Width of the matrix
818
+ for R in M:
819
+ if len(R) != k:
820
+ if verbose:
821
+ print("The matrix has {} columns but k={}".format(len(R), k))
822
+ return False
823
+
824
+ # When |G|=0
825
+ if M_nrows == 0:
826
+ return True
827
+
828
+ # Map group element with integers
829
+ cdef list int_to_group = list(G)
830
+ cdef dict group_to_int = {v:i for i,v in enumerate(int_to_group)}
831
+
832
+ # Allocations
833
+ cdef MemoryAllocator mem = MemoryAllocator()
834
+ cdef int ** x_minus_y = <int **> mem.malloc((n+1)*sizeof(int *))
835
+ cdef int * x_minus_y_data = <int *> mem.malloc((n+1)*(n+1)*sizeof(int))
836
+ cdef int * M_c = <int *> mem.malloc(k*M_nrows*sizeof(int))
837
+ cdef int * G_seen = <int *> mem.malloc((n+1)*sizeof(int))
838
+
839
+ # The "x-y" table. If g_i, g_j \in G, then x_minus_y[i][j] is equal to
840
+ # group_to_int[g_i-g_j].
841
+ #
842
+ # In order to handle empty values represented by n, we have
843
+ # x_minus_y[?][n]=x_minus_y[n][?]=n
844
+ zero, op, inv = group_law(G)
845
+ x_minus_y[0] = x_minus_y_data
846
+ for i in range(1,n+1):
847
+ x_minus_y[i] = x_minus_y[i-1] + n+1
848
+
849
+ # Elements of G
850
+ for j,Gj in enumerate(int_to_group):
851
+ minus_Gj = inv(Gj)
852
+ assert op(Gj, minus_Gj) == zero
853
+ for i,Gi in enumerate(int_to_group):
854
+ x_minus_y[i][j] = group_to_int[op(Gi,minus_Gj)]
855
+
856
+ # Empty values
857
+ for i in range(n+1):
858
+ x_minus_y[n][i]=n
859
+ x_minus_y[i][n]=n
860
+
861
+ # A copy of the matrix
862
+ for i,R in enumerate(M):
863
+ for j,x in enumerate(R):
864
+ M_c[i*k+j] = group_to_int[G(x)] if x is not None else n
865
+
866
+ # Each row contains at most one empty entry
867
+ if u:
868
+ for i in range(M_nrows):
869
+ bit = False
870
+ for j in range(k):
871
+ if M_c[i*k+j] == n:
872
+ if bit:
873
+ if verbose:
874
+ print("Row {} contains more than one empty entry".format(i))
875
+ return False
876
+ bit = True
877
+
878
+ # Each column contains lmbda*u empty entries
879
+ for j in range(k):
880
+ ii = 0
881
+ for i in range(M_nrows):
882
+ if M_c[i*k+j] == n:
883
+ ii += 1
884
+ if ii!=lmbda*u:
885
+ if verbose:
886
+ print("Column {} contains {} empty entries instead of the expected "
887
+ "lambda.u={}.{}={}".format(j, ii, lmbda, u, lmbda*u))
888
+ return False
889
+
890
+ # We are now ready to test every pair of columns
891
+ for i in range(k):
892
+ for j in range(i+1,k):
893
+ memset(G_seen, 0, (n+1)*sizeof(int))
894
+ for ii in range(M_nrows):
895
+ G_seen[x_minus_y[M_c[ii*k+i]][M_c[ii*k+j]]] += 1
896
+
897
+ if G_seen[0] != mu: # Bad number of 0
898
+ if verbose:
899
+ print("Columns {} and {} generate 0 exactly {} times "
900
+ "instead of the expected mu(={})".format(i,j,G_seen[0],mu))
901
+ return False
902
+
903
+ for ii in range(1,n): # bad number of g_ii\in G
904
+ if G_seen[ii] != lmbda:
905
+ if verbose:
906
+ print("Columns {} and {} do not generate all elements of G "
907
+ "exactly lambda(={}) times. The element {} appeared {} "
908
+ "times as a difference.".format(i,j,lmbda,int_to_group[ii],G_seen[ii]))
909
+ return False
910
+
911
+ return True
912
+
913
+
914
+ # Cached information for OA constructions (see .pxd file for more info)
915
+
916
+ _OA_cache = <cache_entry *> sig_malloc(2*sizeof(cache_entry))
917
+ if (_OA_cache == NULL):
918
+ sig_free(_OA_cache)
919
+ raise MemoryError
920
+ _OA_cache[0].max_true = -1
921
+ _OA_cache[1].max_true = -1
922
+ _OA_cache_size = 2
923
+
924
+ cpdef _OA_cache_set(int k, int n, truth_value):
925
+ r"""
926
+ Set a value in the OA cache of existence results.
927
+
928
+ INPUT:
929
+
930
+ - ``k``, ``n`` -- integers
931
+
932
+ - ``truth_value`` -- one of ``True``, ``False``, ``Unknown``
933
+ """
934
+ global _OA_cache, _OA_cache_size
935
+ cdef int i
936
+ if _OA_cache_size <= n:
937
+ new_cache_size = n+100
938
+ _OA_cache = <cache_entry *> sig_realloc(_OA_cache,new_cache_size*sizeof(cache_entry))
939
+ if _OA_cache == NULL:
940
+ sig_free(_OA_cache)
941
+ raise MemoryError
942
+
943
+ for i in range(_OA_cache_size,new_cache_size):
944
+ _OA_cache[i].max_true = 0
945
+ _OA_cache[i].min_unknown = -1
946
+ _OA_cache[i].max_unknown = 0
947
+ _OA_cache[i].min_false = -1
948
+
949
+ _OA_cache_size = new_cache_size
950
+
951
+ if truth_value is True:
952
+ _OA_cache[n].max_true = k if k>_OA_cache[n].max_true else _OA_cache[n].max_true
953
+ elif truth_value is Unknown:
954
+ _OA_cache[n].min_unknown = k if k<_OA_cache[n].min_unknown else _OA_cache[n].min_unknown
955
+ _OA_cache[n].max_unknown = k if k>_OA_cache[n].max_unknown else _OA_cache[n].max_unknown
956
+ else:
957
+ _OA_cache[n].min_false = k if k<_OA_cache[n].min_false else _OA_cache[n].min_false
958
+
959
+ cpdef _OA_cache_get(int k, int n):
960
+ r"""
961
+ Get a value from the OA cache of existence results.
962
+
963
+ INPUT:
964
+
965
+ - ``k``, ``n`` -- integers
966
+ """
967
+ if n>=_OA_cache_size:
968
+ return None
969
+ if k <= _OA_cache[n].max_true:
970
+ return True
971
+ elif (k >= _OA_cache[n].min_unknown and k <= _OA_cache[n].max_unknown):
972
+ return Unknown
973
+ elif k >= _OA_cache[n].min_false:
974
+ return False
975
+
976
+ return None
977
+
978
+ cpdef _OA_cache_construction_available(int k, int n):
979
+ r"""
980
+ Test if a construction is implemented using the cache's information.
981
+
982
+ INPUT:
983
+
984
+ - ``k``, ``n`` -- integers
985
+ """
986
+ if n>=_OA_cache_size:
987
+ return Unknown
988
+ if k <= _OA_cache[n].max_true:
989
+ return True
990
+ if k >= _OA_cache[n].min_unknown:
991
+ return False
992
+ else:
993
+ return Unknown