passagemath-graphs 10.5.43__cp39-cp39-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 (258) hide show
  1. passagemath_graphs-10.5.43.dist-info/METADATA +293 -0
  2. passagemath_graphs-10.5.43.dist-info/RECORD +258 -0
  3. passagemath_graphs-10.5.43.dist-info/WHEEL +5 -0
  4. passagemath_graphs-10.5.43.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 +2552 -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 +125 -0
  15. sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
  16. sage/combinat/cluster_algebra_quiver/mutation_type.py +1556 -0
  17. sage/combinat/cluster_algebra_quiver/quiver.py +2262 -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 +534 -0
  25. sage/combinat/designs/database.py +5614 -0
  26. sage/combinat/designs/design_catalog.py +122 -0
  27. sage/combinat/designs/designs_pyx.cpython-39-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-39-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-39-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 +548 -0
  40. sage/combinat/designs/orthogonal_arrays.py +2243 -0
  41. sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
  42. sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-39-aarch64-linux-gnu.so +0 -0
  43. sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +966 -0
  44. sage/combinat/designs/resolvable_bibd.py +781 -0
  45. sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
  46. sage/combinat/designs/subhypergraph_search.cpython-39-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/cartesian_product.py +493 -0
  57. sage/combinat/posets/d_complete.py +182 -0
  58. sage/combinat/posets/elements.py +273 -0
  59. sage/combinat/posets/forest.py +30 -0
  60. sage/combinat/posets/hasse_cython.cpython-39-aarch64-linux-gnu.so +0 -0
  61. sage/combinat/posets/hasse_cython.pyx +174 -0
  62. sage/combinat/posets/hasse_diagram.py +3678 -0
  63. sage/combinat/posets/incidence_algebras.py +796 -0
  64. sage/combinat/posets/lattices.py +5119 -0
  65. sage/combinat/posets/linear_extension_iterator.cpython-39-aarch64-linux-gnu.so +0 -0
  66. sage/combinat/posets/linear_extension_iterator.pyx +292 -0
  67. sage/combinat/posets/linear_extensions.py +1039 -0
  68. sage/combinat/posets/mobile.py +275 -0
  69. sage/combinat/posets/moebius_algebra.py +776 -0
  70. sage/combinat/posets/poset_examples.py +2131 -0
  71. sage/combinat/posets/posets.py +9169 -0
  72. sage/combinat/rooted_tree.py +1070 -0
  73. sage/combinat/shard_order.py +239 -0
  74. sage/combinat/tamari_lattices.py +384 -0
  75. sage/combinat/yang_baxter_graph.py +923 -0
  76. sage/databases/all__sagemath_graphs.py +1 -0
  77. sage/databases/knotinfo_db.py +1230 -0
  78. sage/ext_data/all__sagemath_graphs.py +1 -0
  79. sage/ext_data/graphs/graph_plot_js.html +330 -0
  80. sage/ext_data/kenzo/CP2.txt +45 -0
  81. sage/ext_data/kenzo/CP3.txt +349 -0
  82. sage/ext_data/kenzo/CP4.txt +4774 -0
  83. sage/ext_data/kenzo/README.txt +49 -0
  84. sage/ext_data/kenzo/S4.txt +20 -0
  85. sage/graphs/all.py +42 -0
  86. sage/graphs/asteroidal_triples.cpython-39-aarch64-linux-gnu.so +0 -0
  87. sage/graphs/asteroidal_triples.pyx +299 -0
  88. sage/graphs/base/all.py +1 -0
  89. sage/graphs/base/boost_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  90. sage/graphs/base/boost_graph.pxd +106 -0
  91. sage/graphs/base/boost_graph.pyx +3045 -0
  92. sage/graphs/base/c_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  93. sage/graphs/base/c_graph.pxd +106 -0
  94. sage/graphs/base/c_graph.pyx +5096 -0
  95. sage/graphs/base/dense_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  96. sage/graphs/base/dense_graph.pxd +26 -0
  97. sage/graphs/base/dense_graph.pyx +757 -0
  98. sage/graphs/base/graph_backends.cpython-39-aarch64-linux-gnu.so +0 -0
  99. sage/graphs/base/graph_backends.pxd +5 -0
  100. sage/graphs/base/graph_backends.pyx +797 -0
  101. sage/graphs/base/overview.py +85 -0
  102. sage/graphs/base/sparse_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  103. sage/graphs/base/sparse_graph.pxd +90 -0
  104. sage/graphs/base/sparse_graph.pyx +1653 -0
  105. sage/graphs/base/static_dense_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  106. sage/graphs/base/static_dense_graph.pxd +5 -0
  107. sage/graphs/base/static_dense_graph.pyx +1032 -0
  108. sage/graphs/base/static_sparse_backend.cpython-39-aarch64-linux-gnu.so +0 -0
  109. sage/graphs/base/static_sparse_backend.pxd +27 -0
  110. sage/graphs/base/static_sparse_backend.pyx +1580 -0
  111. sage/graphs/base/static_sparse_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  112. sage/graphs/base/static_sparse_graph.pxd +37 -0
  113. sage/graphs/base/static_sparse_graph.pyx +1304 -0
  114. sage/graphs/bipartite_graph.py +2709 -0
  115. sage/graphs/centrality.cpython-39-aarch64-linux-gnu.so +0 -0
  116. sage/graphs/centrality.pyx +965 -0
  117. sage/graphs/cographs.py +519 -0
  118. sage/graphs/comparability.cpython-39-aarch64-linux-gnu.so +0 -0
  119. sage/graphs/comparability.pyx +813 -0
  120. sage/graphs/connectivity.cpython-39-aarch64-linux-gnu.so +0 -0
  121. sage/graphs/connectivity.pxd +157 -0
  122. sage/graphs/connectivity.pyx +4813 -0
  123. sage/graphs/convexity_properties.cpython-39-aarch64-linux-gnu.so +0 -0
  124. sage/graphs/convexity_properties.pxd +16 -0
  125. sage/graphs/convexity_properties.pyx +827 -0
  126. sage/graphs/digraph.py +4410 -0
  127. sage/graphs/digraph_generators.py +1921 -0
  128. sage/graphs/distances_all_pairs.cpython-39-aarch64-linux-gnu.so +0 -0
  129. sage/graphs/distances_all_pairs.pxd +12 -0
  130. sage/graphs/distances_all_pairs.pyx +2938 -0
  131. sage/graphs/domination.py +1363 -0
  132. sage/graphs/dot2tex_utils.py +100 -0
  133. sage/graphs/edge_connectivity.cpython-39-aarch64-linux-gnu.so +0 -0
  134. sage/graphs/edge_connectivity.pyx +1215 -0
  135. sage/graphs/generators/all.py +1 -0
  136. sage/graphs/generators/basic.py +1769 -0
  137. sage/graphs/generators/chessboard.py +538 -0
  138. sage/graphs/generators/classical_geometries.py +1611 -0
  139. sage/graphs/generators/degree_sequence.py +235 -0
  140. sage/graphs/generators/distance_regular.cpython-39-aarch64-linux-gnu.so +0 -0
  141. sage/graphs/generators/distance_regular.pyx +2846 -0
  142. sage/graphs/generators/families.py +4749 -0
  143. sage/graphs/generators/intersection.py +565 -0
  144. sage/graphs/generators/platonic_solids.py +262 -0
  145. sage/graphs/generators/random.py +2623 -0
  146. sage/graphs/generators/smallgraphs.py +5741 -0
  147. sage/graphs/generators/world_map.py +724 -0
  148. sage/graphs/generic_graph.py +26395 -0
  149. sage/graphs/generic_graph_pyx.cpython-39-aarch64-linux-gnu.so +0 -0
  150. sage/graphs/generic_graph_pyx.pxd +34 -0
  151. sage/graphs/generic_graph_pyx.pyx +1626 -0
  152. sage/graphs/genus.cpython-39-aarch64-linux-gnu.so +0 -0
  153. sage/graphs/genus.pyx +623 -0
  154. sage/graphs/graph.py +9362 -0
  155. sage/graphs/graph_coloring.cpython-39-aarch64-linux-gnu.so +0 -0
  156. sage/graphs/graph_coloring.pyx +2284 -0
  157. sage/graphs/graph_database.py +1122 -0
  158. sage/graphs/graph_decompositions/all.py +1 -0
  159. sage/graphs/graph_decompositions/bandwidth.cpython-39-aarch64-linux-gnu.so +0 -0
  160. sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
  161. sage/graphs/graph_decompositions/clique_separators.cpython-39-aarch64-linux-gnu.so +0 -0
  162. sage/graphs/graph_decompositions/clique_separators.pyx +595 -0
  163. sage/graphs/graph_decompositions/cutwidth.cpython-39-aarch64-linux-gnu.so +0 -0
  164. sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
  165. sage/graphs/graph_decompositions/fast_digraph.cpython-39-aarch64-linux-gnu.so +0 -0
  166. sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
  167. sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
  168. sage/graphs/graph_decompositions/graph_products.cpython-39-aarch64-linux-gnu.so +0 -0
  169. sage/graphs/graph_decompositions/graph_products.pyx +462 -0
  170. sage/graphs/graph_decompositions/modular_decomposition.cpython-39-aarch64-linux-gnu.so +0 -0
  171. sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
  172. sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
  173. sage/graphs/graph_decompositions/slice_decomposition.cpython-39-aarch64-linux-gnu.so +0 -0
  174. sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
  175. sage/graphs/graph_decompositions/slice_decomposition.pyx +1080 -0
  176. sage/graphs/graph_decompositions/tree_decomposition.cpython-39-aarch64-linux-gnu.so +0 -0
  177. sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
  178. sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
  179. sage/graphs/graph_decompositions/vertex_separation.cpython-39-aarch64-linux-gnu.so +0 -0
  180. sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
  181. sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
  182. sage/graphs/graph_editor.py +82 -0
  183. sage/graphs/graph_generators.py +3301 -0
  184. sage/graphs/graph_generators_pyx.cpython-39-aarch64-linux-gnu.so +0 -0
  185. sage/graphs/graph_generators_pyx.pyx +95 -0
  186. sage/graphs/graph_input.py +812 -0
  187. sage/graphs/graph_latex.py +2064 -0
  188. sage/graphs/graph_list.py +367 -0
  189. sage/graphs/graph_plot.py +1749 -0
  190. sage/graphs/graph_plot_js.py +338 -0
  191. sage/graphs/hyperbolicity.cpython-39-aarch64-linux-gnu.so +0 -0
  192. sage/graphs/hyperbolicity.pyx +1702 -0
  193. sage/graphs/hypergraph_generators.py +364 -0
  194. sage/graphs/independent_sets.cpython-39-aarch64-linux-gnu.so +0 -0
  195. sage/graphs/independent_sets.pxd +13 -0
  196. sage/graphs/independent_sets.pyx +402 -0
  197. sage/graphs/isgci.py +1033 -0
  198. sage/graphs/isoperimetric_inequalities.cpython-39-aarch64-linux-gnu.so +0 -0
  199. sage/graphs/isoperimetric_inequalities.pyx +453 -0
  200. sage/graphs/line_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  201. sage/graphs/line_graph.pyx +627 -0
  202. sage/graphs/lovasz_theta.py +77 -0
  203. sage/graphs/matching.py +1633 -0
  204. sage/graphs/matching_covered_graph.py +3566 -0
  205. sage/graphs/orientations.py +1504 -0
  206. sage/graphs/partial_cube.py +459 -0
  207. sage/graphs/path_enumeration.cpython-39-aarch64-linux-gnu.so +0 -0
  208. sage/graphs/path_enumeration.pyx +2040 -0
  209. sage/graphs/pq_trees.py +1129 -0
  210. sage/graphs/print_graphs.py +201 -0
  211. sage/graphs/schnyder.py +865 -0
  212. sage/graphs/spanning_tree.cpython-39-aarch64-linux-gnu.so +0 -0
  213. sage/graphs/spanning_tree.pyx +1457 -0
  214. sage/graphs/strongly_regular_db.cpython-39-aarch64-linux-gnu.so +0 -0
  215. sage/graphs/strongly_regular_db.pyx +3340 -0
  216. sage/graphs/traversals.cpython-39-aarch64-linux-gnu.so +0 -0
  217. sage/graphs/traversals.pxd +9 -0
  218. sage/graphs/traversals.pyx +1871 -0
  219. sage/graphs/trees.cpython-39-aarch64-linux-gnu.so +0 -0
  220. sage/graphs/trees.pxd +15 -0
  221. sage/graphs/trees.pyx +310 -0
  222. sage/graphs/tutte_polynomial.py +713 -0
  223. sage/graphs/views.cpython-39-aarch64-linux-gnu.so +0 -0
  224. sage/graphs/views.pyx +794 -0
  225. sage/graphs/weakly_chordal.cpython-39-aarch64-linux-gnu.so +0 -0
  226. sage/graphs/weakly_chordal.pyx +562 -0
  227. sage/groups/all__sagemath_graphs.py +1 -0
  228. sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
  229. sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
  230. sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-39-aarch64-linux-gnu.so +0 -0
  231. sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
  232. sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
  233. sage/knots/all.py +6 -0
  234. sage/knots/free_knotinfo_monoid.py +507 -0
  235. sage/knots/gauss_code.py +291 -0
  236. sage/knots/knot.py +682 -0
  237. sage/knots/knot_table.py +284 -0
  238. sage/knots/knotinfo.py +2880 -0
  239. sage/knots/link.py +4682 -0
  240. sage/sandpiles/all.py +13 -0
  241. sage/sandpiles/examples.py +225 -0
  242. sage/sandpiles/sandpile.py +6365 -0
  243. sage/topology/all.py +22 -0
  244. sage/topology/cell_complex.py +1214 -0
  245. sage/topology/cubical_complex.py +1977 -0
  246. sage/topology/delta_complex.py +1806 -0
  247. sage/topology/filtered_simplicial_complex.py +744 -0
  248. sage/topology/moment_angle_complex.py +823 -0
  249. sage/topology/simplicial_complex.py +5161 -0
  250. sage/topology/simplicial_complex_catalog.py +86 -0
  251. sage/topology/simplicial_complex_examples.py +1692 -0
  252. sage/topology/simplicial_complex_homset.py +205 -0
  253. sage/topology/simplicial_complex_morphism.py +836 -0
  254. sage/topology/simplicial_set.py +4102 -0
  255. sage/topology/simplicial_set_catalog.py +55 -0
  256. sage/topology/simplicial_set_constructions.py +2954 -0
  257. sage/topology/simplicial_set_examples.py +865 -0
  258. sage/topology/simplicial_set_morphism.py +1464 -0
@@ -0,0 +1,781 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ # sage.doctest: needs sage.rings.finite_rings
3
+ r"""
4
+ Resolvable balanced incomplete block design (RBIBD)
5
+
6
+ This module contains everything related to resolvable Balanced Incomplete Block
7
+ Designs. The constructions implemented here can be obtained through the
8
+ ``designs.<tab>`` object::
9
+
10
+ designs.resolvable_balanced_incomplete_block_design(15,3)
11
+
12
+ For Balanced Incomplete Block Design (BIBD) see the module :mod:`bibd
13
+ <sage.combinat.designs.bibd>`. A BIBD
14
+ is said to be *resolvable* if its blocks can be partitionned into parallel
15
+ classes, i.e. partitions of its ground set.
16
+
17
+ The main function of this module is
18
+ :func:`resolvable_balanced_incomplete_block_design`, which calls all others.
19
+
20
+ .. csv-table::
21
+ :class: contentstable
22
+ :widths: 30, 70
23
+ :delim: |
24
+
25
+ :func:`resolvable_balanced_incomplete_block_design` | Return a resolvable BIBD of parameters `v,k`.
26
+ :func:`kirkman_triple_system` | Return a Kirkman Triple System on `v` points.
27
+ :func:`v_4_1_rbibd` | Return a `(v,4,1)`-RBIBD
28
+ :func:`PBD_4_7` | Return a `(v,\{4,7\})`-PBD
29
+ :func:`PBD_4_7_from_Y` | Return a `(3v+1,\{4,7\})`-PBD from a `(v,\{4,5,7\},\NN-\{3,6,10\})`-GDD.
30
+
31
+ References:
32
+
33
+ .. [Stinson91] \D.R. Stinson,
34
+ A survey of Kirkman triple systems and related designs,
35
+ Volume 92, Issues 1-3, 17 November 1991, Pages 371-393,
36
+ Discrete Mathematics,
37
+ :doi:`10.1016/0012-365X(91)90294-C`
38
+
39
+ .. [RCW71] \D. K. Ray-Chaudhuri, R. M. Wilson,
40
+ Solution of Kirkman's schoolgirl problem,
41
+ Volume 19, Pages 187-203,
42
+ Proceedings of Symposia in Pure Mathematics
43
+
44
+ .. [BJL99] \T. Beth, D. Jungnickel, H. Lenz,
45
+ Design Theory 2ed.
46
+ Cambridge University Press
47
+ 1999
48
+
49
+ Functions
50
+ ---------
51
+ """
52
+ from itertools import repeat
53
+ from sage.arith.misc import is_prime_power
54
+ from sage.combinat.designs.bibd import BalancedIncompleteBlockDesign
55
+ from sage.categories.sets_cat import EmptySetError
56
+ from .bibd import balanced_incomplete_block_design
57
+ from sage.misc.unknown import Unknown
58
+
59
+
60
+ def resolvable_balanced_incomplete_block_design(v, k, existence=False):
61
+ r"""
62
+ Return a resolvable BIBD of parameters `v,k`.
63
+
64
+ A BIBD is said to be *resolvable* if its blocks can be partitionned into
65
+ parallel classes, i.e. partitions of the ground set.
66
+
67
+ INPUT:
68
+
69
+ - ``v``, ``k`` -- integers
70
+
71
+ - ``existence`` -- boolean; instead of building the design, return:
72
+
73
+ - ``True`` -- meaning that Sage knows how to build the design
74
+
75
+ - ``Unknown`` -- meaning that Sage does not know how to build the
76
+ design, but that the design may exist (see :mod:`sage.misc.unknown`)
77
+
78
+ - ``False`` -- meaning that the design does not exist
79
+
80
+ .. SEEALSO::
81
+
82
+ - :meth:`IncidenceStructure.is_resolvable`
83
+ - :func:`~sage.combinat.designs.bibd.balanced_incomplete_block_design`
84
+
85
+ EXAMPLES::
86
+
87
+ sage: KTS15 = designs.resolvable_balanced_incomplete_block_design(15,3); KTS15
88
+ (15,3,1)-Balanced Incomplete Block Design
89
+ sage: KTS15.is_resolvable()
90
+ True
91
+
92
+ TESTS::
93
+
94
+ sage: for v in range(40):
95
+ ....: for k in range(v):
96
+ ....: if designs.resolvable_balanced_incomplete_block_design(v,k,existence=True) is True:
97
+ ....: _ = designs.resolvable_balanced_incomplete_block_design(v,k)
98
+ """
99
+ # Trivial cases
100
+ if v == 1 or k == v:
101
+ return balanced_incomplete_block_design(v,k,existence=existence)
102
+
103
+ # Non-existence of resolvable BIBD
104
+ if (v < k or
105
+ k < 2 or
106
+ v % k != 0 or
107
+ (v-1) % (k-1) != 0 or
108
+ (v*(v-1)) % (k*(k-1)) != 0 or
109
+ # From the Handbook of combinatorial designs:
110
+ #
111
+ # With lambda>1 the other exceptions is
112
+ # (15,5,2)
113
+ (k == 6 and v == 36) or
114
+ # Fisher's inequality
115
+ (v*(v-1))/(k*(k-1)) < v):
116
+ if existence:
117
+ return False
118
+ raise EmptySetError("There exists no ({},{},{})-RBIBD".format(v,k,1))
119
+
120
+ if k == 2:
121
+ if existence:
122
+ return True
123
+ classes = [[[(c+i) % (v-1),(c+v-i) % (v-1)] for i in range(1, v//2)]
124
+ for c in range(v-1)]
125
+ for i,classs in enumerate(classes):
126
+ classs.append([v-1,i])
127
+
128
+ B = BalancedIncompleteBlockDesign(v,
129
+ sum(classes,[]),
130
+ k=k,
131
+ check=True,
132
+ copy=False)
133
+ B._classes = classes
134
+ return B
135
+ elif k == 3:
136
+ return kirkman_triple_system(v,existence=existence)
137
+ elif k == 4:
138
+ return v_4_1_rbibd(v,existence=existence)
139
+ else:
140
+ if existence:
141
+ return Unknown
142
+ raise NotImplementedError("I don't know how to build a ({},{},1)-RBIBD!".format(v,3))
143
+
144
+
145
+ def kirkman_triple_system(v, existence=False):
146
+ r"""
147
+ Return a Kirkman Triple System on `v` points.
148
+
149
+ A Kirkman Triple System `KTS(v)` is a resolvable Steiner Triple System. It
150
+ exists if and only if `v\equiv 3\pmod{6}`.
151
+
152
+ INPUT:
153
+
154
+ - ``n`` -- integer
155
+
156
+ - ``existence`` -- boolean (default: ``False``); whether to build the
157
+ `KTS(n)` or only answer whether it exists
158
+
159
+ .. SEEALSO::
160
+
161
+ :meth:`IncidenceStructure.is_resolvable`
162
+
163
+ EXAMPLES:
164
+
165
+ A solution to Kirkmman's original problem::
166
+
167
+ sage: kts = designs.kirkman_triple_system(15)
168
+ sage: classes = kts.is_resolvable(1)[1]
169
+ sage: names = '0123456789abcde'
170
+ sage: def to_name(r_s_t):
171
+ ....: r, s, t = r_s_t
172
+ ....: return ' ' + names[r] + names[s] + names[t] + ' '
173
+ sage: rows = [' '.join(('Day {}'.format(i) for i in range(1,8)))]
174
+ sage: rows.extend(' '.join(map(to_name,row)) for row in zip(*classes))
175
+ sage: print('\n'.join(rows))
176
+ Day 1 Day 2 Day 3 Day 4 Day 5 Day 6 Day 7
177
+ 07e 18e 29e 3ae 4be 5ce 6de
178
+ 139 24a 35b 46c 05d 167 028
179
+ 26b 03c 14d 257 368 049 15a
180
+ 458 569 06a 01b 12c 23d 347
181
+ acd 7bd 78c 89d 79a 8ab 9bc
182
+
183
+ TESTS::
184
+
185
+ sage: for i in range(3,300,6): # needs sage.combinat
186
+ ....: _ = designs.kirkman_triple_system(i)
187
+ """
188
+ if v % 6 != 3:
189
+ if existence:
190
+ return False
191
+ raise ValueError("There is no KTS({}) as v!=3 mod(6)".format(v))
192
+
193
+ if existence:
194
+ return False
195
+
196
+ elif v == 3:
197
+ return BalancedIncompleteBlockDesign(3,[[0,1,2]],k=3,lambd=1)
198
+
199
+ elif v == 9:
200
+ classes = [[[0, 1, 5], [2, 6, 7], [3, 4, 8]],
201
+ [[1, 6, 8], [3, 5, 7], [0, 2, 4]],
202
+ [[1, 4, 7], [0, 3, 6], [2, 5, 8]],
203
+ [[4, 5, 6], [0, 7, 8], [1, 2, 3]]]
204
+ KTS = BalancedIncompleteBlockDesign(v,[tr for cl in classes for tr in cl],k=3,lambd=1,copy=False)
205
+ KTS._classes = classes
206
+ return KTS
207
+
208
+ # Construction 1.1 from [Stinson91] (originally Theorem 6 from [RCW71])
209
+ #
210
+ # For all prime powers q=1 mod 6, there exists a KTS(2q+1)
211
+ elif ((v-1)//2) % 6 == 1 and is_prime_power((v-1)//2):
212
+ from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
213
+ q = (v-1)//2
214
+ K = GF(q,'x')
215
+ a = K.primitive_element()
216
+ t = (q - 1) // 6
217
+
218
+ # m is the solution of a^m=(a^t+1)/2
219
+ from sage.groups.generic import discrete_log
220
+ m = discrete_log((a**t+1)/2, a)
221
+ assert 2*a**m == a**t+1
222
+
223
+ # First parallel class
224
+ first_class = [[(0,1),(0,2),'inf']]
225
+ b0 = K.one()
226
+ b1 = a**t
227
+ b2 = a**m
228
+ first_class.extend([(b0*a**i,1),(b1*a**i,1),(b2*a**i,2)]
229
+ for i in list(range(t))+list(range(2*t,3*t))+list(range(4*t,5*t)))
230
+ b0 = a**(m+t)
231
+ b1 = a**(m+3*t)
232
+ b2 = a**(m+5*t)
233
+ first_class.extend([[(b0*a**i,2),(b1*a**i,2),(b2*a**i,2)]
234
+ for i in range(t)])
235
+
236
+ # Action of K on the points
237
+ action = lambda v,x : (v+x[0],x[1]) if len(x) == 2 else x
238
+
239
+ # relabel to integer
240
+ relabel = {(p,x): i+(x-1)*q
241
+ for i,p in enumerate(K)
242
+ for x in [1,2]}
243
+ relabel['inf'] = 2*q
244
+
245
+ classes = [[[relabel[action(p,x)] for x in tr] for tr in first_class]
246
+ for p in K]
247
+
248
+ KTS = BalancedIncompleteBlockDesign(v,[tr for cl in classes for tr in cl],k=3,lambd=1,copy=False)
249
+
250
+ KTS._classes = classes
251
+ return KTS
252
+
253
+ # Construction 1.2 from [Stinson91] (originally Theorem 5 from [RCW71])
254
+ #
255
+ # For all prime powers q=1 mod 6, there exists a KTS(3q)
256
+ elif (v//3) % 6 == 1 and is_prime_power(v//3):
257
+ from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
258
+ q = v//3
259
+ K = GF(q,'x')
260
+ a = K.primitive_element()
261
+ t = (q - 1) // 6
262
+ A0 = [(0,0),(0,1),(0,2)]
263
+ B = [[(a**i,j),(a**(i+2*t),j),(a**(i+4*t),j)] for j in range(3)
264
+ for i in range(t)]
265
+ A = [[(a**i,0),(a**(i+2*t),1),(a**(i+4*t),2)] for i in range(6*t)]
266
+
267
+ # Action of K on the points
268
+ action = lambda v,x: (v+x[0],x[1])
269
+
270
+ # relabel to integer
271
+ relabel = {(p,j): i+j*q
272
+ for i,p in enumerate(K)
273
+ for j in range(3)}
274
+
275
+ B0 = [A0] + B + A[t:2*t] + A[3*t:4*t] + A[5*t:6*t]
276
+
277
+ # Classes
278
+ classes = [[[relabel[action(p,x)] for x in tr] for tr in B0]
279
+ for p in K]
280
+
281
+ for i in list(range(t))+list(range(2*t,3*t))+list(range(4*t,5*t)):
282
+ classes.append([[relabel[action(p,x)] for x in A[i]] for p in K])
283
+
284
+ KTS = BalancedIncompleteBlockDesign(v,[tr for cl in classes for tr in cl],k=3,lambd=1,copy=False)
285
+ KTS._classes = classes
286
+ return KTS
287
+
288
+ else:
289
+ # This is Lemma IX.6.4 from [BJL99].
290
+ #
291
+ # This construction takes a (v,{4,7})-PBD. All points are doubled (x has
292
+ # a copy x'), and an infinite point \infty is added.
293
+ #
294
+ # On all blocks of 2*4 points we "paste" a KTS(2*4+1) using the infinite
295
+ # point, in such a way that all {x,x',infty} are set of the design. We
296
+ # do the same for blocks with 2*7 points using a KTS(2*7+1).
297
+ #
298
+ # Note that the triples of points equal to {x,x',\infty} will be added
299
+ # several times.
300
+ #
301
+ # As all those subdesigns are resolvable, each class of the KTS(n) is
302
+ # obtained by considering a set {x,x',\infty} and all sets of all
303
+ # parallel classes of the subdesign which contain this set.
304
+
305
+ # We create the small KTS(n') we need, and relabel them such that
306
+ # 01(n'-1),23(n'-1),... are blocks of the design.
307
+ gdd4 = kirkman_triple_system(9)
308
+ gdd7 = kirkman_triple_system(15)
309
+
310
+ X = [B for B in gdd4 if 8 in B]
311
+ for b in X:
312
+ b.remove(8)
313
+ X = sum(X, []) + [8]
314
+ gdd4.relabel({v:i for i,v in enumerate(X)})
315
+ gdd4 = gdd4.is_resolvable(True)[1] # the relabeled classes
316
+
317
+ X = [B for B in gdd7 if 14 in B]
318
+ for b in X:
319
+ b.remove(14)
320
+ X = sum(X, []) + [14]
321
+ gdd7.relabel({v:i for i,v in enumerate(X)})
322
+ gdd7 = gdd7.is_resolvable(True)[1] # the relabeled classes
323
+
324
+ # The first parallel class contains 01(n'-1), the second contains
325
+ # 23(n'-1), etc..
326
+ # Then remove the blocks containing (n'-1)
327
+ for B in gdd4:
328
+ for i, b in enumerate(B):
329
+ if 8 in b:
330
+ j = min(b)
331
+ del B[i]
332
+ B.insert(0, j)
333
+ break
334
+ gdd4.sort()
335
+ for B in gdd4:
336
+ B.pop(0)
337
+
338
+ for B in gdd7:
339
+ for i, b in enumerate(B):
340
+ if 14 in b:
341
+ j = min(b)
342
+ del B[i]
343
+ B.insert(0, j)
344
+ break
345
+ gdd7.sort()
346
+ for B in gdd7:
347
+ B.pop(0)
348
+
349
+ # Pasting the KTS(n') without {x,x',\infty} blocks
350
+ classes = [[] for _ in repeat(None, (v - 1) // 2)]
351
+ gdd = {4: gdd4, 7: gdd7}
352
+ for B in PBD_4_7((v-1)//2,check=False):
353
+ for i,classs in enumerate(gdd[len(B)]):
354
+ classes[B[i]].extend([[2*B[x//2]+x % 2 for x in BB] for BB in classs])
355
+
356
+ # The {x,x',\infty} blocks
357
+ for i,classs in enumerate(classes):
358
+ classs.append([2*i,2*i+1,v-1])
359
+
360
+ KTS = BalancedIncompleteBlockDesign(v,
361
+ blocks=[tr for cl in classes for tr in cl],
362
+ k=3,
363
+ lambd=1,
364
+ check=True,
365
+ copy=False)
366
+ KTS._classes = classes
367
+ assert KTS.is_resolvable()
368
+
369
+ return KTS
370
+
371
+
372
+ def v_4_1_rbibd(v, existence=False):
373
+ r"""
374
+ Return a `(v,4,1)`-RBIBD.
375
+
376
+ INPUT:
377
+
378
+ - ``n`` -- integer
379
+
380
+ - ``existence`` -- boolean (default: ``False``); whether to build the
381
+ design or only answer whether it exists
382
+
383
+ .. SEEALSO::
384
+
385
+ - :meth:`IncidenceStructure.is_resolvable`
386
+ - :func:`resolvable_balanced_incomplete_block_design`
387
+
388
+ .. NOTE::
389
+
390
+ A resolvable `(v,4,1)`-BIBD exists whenever `1\equiv 4\pmod(12)`. This
391
+ function, however, only implements a construction of `(v,4,1)`-BIBD such
392
+ that `v=3q+1\equiv 1\pmod{3}` where `q` is a prime power (see VII.7.5.a
393
+ from [BJL99]_).
394
+
395
+ EXAMPLES::
396
+
397
+ sage: rBIBD = designs.resolvable_balanced_incomplete_block_design(28,4)
398
+ sage: rBIBD.is_resolvable()
399
+ True
400
+ sage: rBIBD.is_t_design(return_parameters=True)
401
+ (True, (2, 28, 4, 1))
402
+
403
+ TESTS::
404
+
405
+ sage: for q in prime_powers(2,30): # indirect doctest
406
+ ....: if (3*q+1)%12 == 4:
407
+ ....: _ = designs.resolvable_balanced_incomplete_block_design(3*q+1,4)
408
+ """
409
+ # Volume 1, VII.7.5.a from [BJL99]_
410
+ if v % 3 != 1 or not is_prime_power((v-1)//3):
411
+ if existence:
412
+ return Unknown
413
+ raise NotImplementedError("I don't know how to build a ({},{},1)-RBIBD!".format(v,4))
414
+ from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
415
+ q = (v-1)//3
416
+ nn = (q-1)//4
417
+ G = GF(q,'x')
418
+ w = G.primitive_element()
419
+ e = w**(nn)
420
+ assert e**2 == -1
421
+
422
+ first_class = [[(w**i,j),(-w**i,j),(e*w**i,j+1),(-e*w**i,j+1)]
423
+ for i in range(nn) for j in range(3)]
424
+
425
+ first_class.append([(0,0),(0,1),(0,2),'inf'])
426
+
427
+ label = {p:i for i,p in enumerate(G)}
428
+
429
+ classes = [[[v-1 if x == 'inf' else (x[1] % 3)*q+label[x[0]+g] for x in S]
430
+ for S in first_class]
431
+ for g in G]
432
+
433
+ BIBD = BalancedIncompleteBlockDesign(v,
434
+ blocks=sum(classes,[]),
435
+ k=4,
436
+ check=True,
437
+ copy=False)
438
+ BIBD._classes = classes
439
+ assert BIBD.is_resolvable()
440
+ return BIBD
441
+
442
+
443
+ def PBD_4_7(v, check=True, existence=False):
444
+ r"""
445
+ Return a `(v,\{4,7\})`-PBD.
446
+
447
+ For all `v` such that `n\equiv 1\pmod{3}` and `n\neq 10,19, 31` there exists
448
+ a `(v,\{4,7\})`-PBD. This is proved in Proposition IX.4.5 from [BJL99]_,
449
+ which this method implements.
450
+
451
+ This construction of PBD is used by the construction of Kirkman Triple
452
+ Systems.
453
+
454
+ EXAMPLES::
455
+
456
+ sage: from sage.combinat.designs.resolvable_bibd import PBD_4_7
457
+ sage: PBD_4_7(22)
458
+ Pairwise Balanced Design on 22 points with sets of sizes in [4, 7]
459
+
460
+ TESTS:
461
+
462
+ All values `\leq 300`::
463
+
464
+ sage: for i in range(1,300,3): # needs sage.schemes
465
+ ....: if i not in [10,19,31]:
466
+ ....: assert PBD_4_7(i,existence=True) is True
467
+ ....: _ = PBD_4_7(i,check=True)
468
+ """
469
+ if v % 3 != 1 or v in [10,19,31]:
470
+ if existence:
471
+ return Unknown
472
+ raise NotImplementedError
473
+ if existence:
474
+ return True
475
+
476
+ from .group_divisible_designs import GroupDivisibleDesign
477
+ from .group_divisible_designs import GDD_4_2
478
+ from .bibd import PairwiseBalancedDesign
479
+ from .bibd import balanced_incomplete_block_design
480
+
481
+ if v == 22:
482
+ # Beth/Jungnickel/Lenz: take KTS(15) and extend each of the 7 classes
483
+ # with a new point. Make those new points a 7-set.
484
+ KTS15 = kirkman_triple_system(15)
485
+ blocks = [S+[i+15] for i,classs in enumerate(KTS15._classes) for S in classs]+[list(range(15, 22))]
486
+
487
+ elif v == 34:
488
+ # [BJL99] (p527,vol1), but originally Brouwer
489
+ A = [(0,0),(1,1),(2,0),(4,1)]
490
+ B = [(0,0),(1,0),(4,2)]
491
+ C = [(0,0),(2,2),(5,0)]
492
+ D = [(0,0),(0,1),(0,2)]
493
+
494
+ A = [[(x+i, y+j) for x,y in A] for i in range(9) for j in range(3)]
495
+ B = [[(x+i, y+i+j) for x,y in B]+[27+j] for i in range(9) for j in range(3)]
496
+ C = [[(x+i+j,y+2*i+j) for x,y in C]+[30+j] for i in range(9) for j in range(3)]
497
+ D = [[(x+i, y+i) for x,y in D]+[33] for i in range(9)]
498
+
499
+ blocks = [[int(x) if not isinstance(x,tuple) else (x[1] % 3)*9+(x[0] % 9) for x in S]
500
+ for S in A+B+C+D+[list(range(27,34))]]
501
+ elif v == 46:
502
+ # [BJL99] (p527,vol1), but originally Brouwer
503
+ A = [(1,0),(3,0),(9,0),(0,1)]
504
+ B = [(2,0),(6,0),(5,0),(0,1)]
505
+ C = [(0,0),(1,1),(4,2)]
506
+ D = [(0,0),(2,1),(7,2)]
507
+ E = [(0,0),(0,1),(0,2)]
508
+
509
+ A = [[(x+i, y+j) for x,y in A] for i in range(13) for j in range(3)]
510
+ B = [[(x+i, y+j) for x,y in B] for i in range(13) for j in range(3)]
511
+ C = [[(x+i, y+j) for x,y in C]+[39+j] for i in range(13) for j in range(3)]
512
+ D = [[(x+i, y+j) for x,y in D]+[42+j] for i in range(13) for j in range(3)]
513
+ E = [[(x+i, y+i) for x,y in E]+[45] for i in range(13)]
514
+
515
+ blocks = [[int(x) if not isinstance(x,tuple) else (x[1] % 3)*13+(x[0] % 13) for x in S]
516
+ for S in A+B+C+D+E+[list(range(39, 46))]]
517
+
518
+ elif v == 58:
519
+ # [BJL99] (p527,vol1), but originally Brouwer
520
+ A = [(0,0),(1,0),(4,0),( 5,1)]
521
+ B = [(0,0),(2,0),(8,0),(11,1)]
522
+ C = [(0,0),(5,0),(2,1),(12,1)]
523
+ D = [(0,0),(8,1),(7,2)]
524
+ E = [(0,0),(6,1),(4,2)]
525
+ F = [(0,0),(0,1),(0,2)]
526
+
527
+ A = [[(x+i, y+j) for x,y in A] for i in range(17) for j in range(3)]
528
+ B = [[(x+i, y+j) for x,y in B] for i in range(17) for j in range(3)]
529
+ C = [[(x+i, y+j) for x,y in C] for i in range(17) for j in range(3)]
530
+ D = [[(x+i, y+j) for x,y in D]+[51+j] for i in range(17) for j in range(3)]
531
+ E = [[(x+i, y+j) for x,y in E]+[54+j] for i in range(17) for j in range(3)]
532
+ F = [[(x+i, y+i) for x,y in F]+[57] for i in range(17)]
533
+
534
+ blocks = [[int(x) if not isinstance(x,tuple) else (x[1] % 3)*17+(x[0] % 17) for x in S]
535
+ for S in A+B+C+D+E+F+[list(range(51,58))]]
536
+
537
+ elif v == 70:
538
+ # [BJL99] (p527,vol1), but originally Brouwer
539
+ A = [(0,0),(1,0),(5,1),(13,1)]
540
+ B = [(0,0),(4,0),(20,1),(10,1)]
541
+ C = [(0,0),(16,0),(17,1),(19,1)]
542
+ D = [(0,0),(2,1),(8,1),(11,1)]
543
+ E = [(0,0),(3,2),(9,1)]
544
+ F = [(0,0),(7,0),(14,1)]
545
+ H = [(0,0),(0,1),(0,2)]
546
+
547
+ A = [[(x+i, y+j) for x,y in A] for i in range(21) for j in range(3)]
548
+ B = [[(x+i, y+j) for x,y in B] for i in range(21) for j in range(3)]
549
+ C = [[(x+i, y+j) for x,y in C] for i in range(21) for j in range(3)]
550
+ D = [[(x+i, y+j) for x,y in D] for i in range(21) for j in range(3)]
551
+ E = [[(x+i, y+j) for x,y in E]+[63+j] for i in range(21) for j in range(3)]
552
+ F = [[(x+3*i+j, y+ii+j) for x,y in F]+[66+j] for i in range( 7) for j in range(3) for ii in range(3)]
553
+ H = [[(x+i, y+i) for x,y in H]+[69] for i in range(21)]
554
+
555
+ blocks = [[int(x) if not isinstance(x,tuple) else (x[1] % 3)*21+(x[0] % 21)
556
+ for x in S]
557
+ for S in A+B+C+D+E+F+H+[list(range(63,70))]]
558
+
559
+ elif v == 82:
560
+ # This construction is Theorem IX.3.16 from [BJL99] (p.627).
561
+ #
562
+ # A (15,{4},{3})-GDD from a (16,4)-BIBD
563
+ from .group_divisible_designs import group_divisible_design
564
+ from .orthogonal_arrays import transversal_design
565
+ GDD = group_divisible_design(3*5,K=[4],G=[3],check=False)
566
+ TD = transversal_design(5,5)
567
+
568
+ # A (75,{4},{15})-GDD
569
+ GDD2 = [[3*B[x//3]+x % 3 for x in BB] for B in TD for BB in GDD]
570
+
571
+ # We now complete the (75,{4},{15})-GDD into a (82,{4,7})-PBD. For this,
572
+ # we add 7 new points that are added to all groups of size 15.
573
+ #
574
+ # On these groups a (15+7,{4,7})-PBD is pasted, in such a way that the 7
575
+ # new points are a set of the final PBD
576
+ PBD22 = PBD_4_7(15+7)
577
+ S = next(SS for SS in PBD22 if len(SS) == 7) # a set of size 7
578
+ PBD22.relabel({v:i for i,v in enumerate([i for i in range(15+7) if i not in S] + S)})
579
+
580
+ for B in PBD22:
581
+ if B == S:
582
+ continue
583
+ for i in range(5):
584
+ GDD2.append([x+i*15 if x < 15 else x+60 for x in B])
585
+
586
+ GDD2.append(list(range(75,82)))
587
+ blocks = GDD2
588
+
589
+ elif v == 94:
590
+ # IX.4.5.l from [BJL99].
591
+ #
592
+ # take 4 parallel lines from an affine plane of order 7, and a 5th
593
+ # one. This is a (31,{4,5,7})-BIBD. And 94=3*31+1.
594
+ from sage.combinat.designs.block_design import AffineGeometryDesign
595
+ AF = AffineGeometryDesign(2,1,7)
596
+ parall = []
597
+ plus_one = None
598
+ for S in AF:
599
+ if all(x not in SS for SS in parall for x in S):
600
+ parall.append(S)
601
+ elif plus_one is None:
602
+ plus_one = S
603
+ if len(parall) == 4 and plus_one is not None:
604
+ break
605
+ X = set(sum(parall, plus_one))
606
+
607
+ S_4_5_7 = [X.intersection(S) for S in AF]
608
+ S_4_5_7 = [S for S in S_4_5_7 if len(S) > 1]
609
+ S_4_5_7 = PairwiseBalancedDesign(X,
610
+ blocks=S_4_5_7,
611
+ K=[4,5,7],
612
+ check=False)
613
+ S_4_5_7.relabel()
614
+ return PBD_4_7_from_Y(S_4_5_7,check=check)
615
+
616
+ elif v == 127 or v == 142:
617
+ # IX.4.5.o from [BJL99].
618
+ #
619
+ # Attach two or seven infinite points to a (40,4)-RBIBD to get a
620
+ # (42,{4,5},{1,2,7})-GDD or a (47,{4,5},{1,2,7})-GDD
621
+ points_to_add = 2 if v == 127 else 7
622
+ rBIBD4 = v_4_1_rbibd(40)
623
+ GDD = [S+[40+i] if i < points_to_add else S
624
+ for i,classs in enumerate(rBIBD4._classes)
625
+ for S in classs]
626
+ if points_to_add == 7:
627
+ GDD.append(list(range(40, 40 + points_to_add)))
628
+ groups = [[x] for x in range(40+points_to_add)]
629
+ else:
630
+ groups = [[x] for x in range(40)]
631
+ groups.append(list(range(40,40+points_to_add)))
632
+ GDD = GroupDivisibleDesign(40+points_to_add,
633
+ groups=groups,
634
+ blocks=GDD,
635
+ K=[2,4,5,7],
636
+ check=False,
637
+ copy=False)
638
+
639
+ return PBD_4_7_from_Y(GDD,check=check)
640
+
641
+ elif v % 6 == 1 and GDD_4_2((v - 1) // 6, existence=True) is True:
642
+ # VII.5.17 from [BJL99]
643
+ gdd = GDD_4_2((v - 1) // 6)
644
+ return PBD_4_7_from_Y(gdd, check=check)
645
+
646
+ elif v == 202:
647
+ # IV.4.5.p from [BJL99]
648
+ PBD = PBD_4_7(22,check=False)
649
+ PBD = PBD_4_7_from_Y(PBD,check=False)
650
+ return PBD_4_7_from_Y(PBD,check=check)
651
+
652
+ elif balanced_incomplete_block_design(v,4,existence=True) is True:
653
+ return balanced_incomplete_block_design(v,4)
654
+ elif balanced_incomplete_block_design(v,7,existence=True) is True:
655
+ return balanced_incomplete_block_design(v,7)
656
+ else:
657
+ from sage.combinat.designs.orthogonal_arrays import orthogonal_array
658
+ # IX.4.5.m from [BJL99].
659
+ #
660
+ # This construction takes a TD(5,g) and truncates its last column to
661
+ # size u: it yields a (4g+u,{4,5},{g,u})-GDD. If there exists a
662
+ # (3g+1,{4,7})-PBD and a (3u+1,{4,7})-PBD, then we can apply the x->3x+1
663
+ # construction on the truncated transversal design (which is a GDD).
664
+ #
665
+ # We write vv = 4g+u while satisfying the hypotheses.
666
+ vv = (v - 1) // 3
667
+ for g in range((vv + 5 - 1) // 5, vv // 4 + 1):
668
+ u = vv-4*g
669
+ if (orthogonal_array(5,g,existence=True) is True and
670
+ PBD_4_7(3*g+1,existence=True) is True and
671
+ PBD_4_7(3*u+1,existence=True) is True):
672
+ from .orthogonal_arrays import transversal_design
673
+ domain = set(range(vv))
674
+ GDD = transversal_design(5,g)
675
+ GDD = GroupDivisibleDesign(vv,
676
+ groups=[[x for x in gr if x in domain] for gr in GDD.groups()],
677
+ blocks=[[x for x in B if x in domain] for B in GDD],
678
+ G=set([g,u]),
679
+ K=[4,5],
680
+ check=False)
681
+ return PBD_4_7_from_Y(GDD,check=check)
682
+
683
+ return PairwiseBalancedDesign(v,
684
+ blocks=blocks,
685
+ K=[4,7],
686
+ check=check,
687
+ copy=False)
688
+
689
+
690
+ def PBD_4_7_from_Y(gdd, check=True):
691
+ r"""
692
+ Return a `(3v+1,\{4,7\})`-PBD from a `(v,\{4,5,7\},\NN-\{3,6,10\})`-GDD.
693
+
694
+ This implements Lemma IX.3.11 from [BJL99]_ (p.625). All points of the GDD
695
+ are tripled, and a `+\infty` point is added to the design.
696
+
697
+ - A group of size `s\in Y=\NN-\{3,6,10\}` becomes a set of size `3s`. Adding
698
+ `\infty` to it gives it size `3s+1`, and this set is then replaced by a
699
+ `(3s+1,\{4,7\})`-PBD.
700
+
701
+ - A block of size `s\in\{4,5,7\}` becomes a `(3s,\{4,7\},\{3\})`-GDD.
702
+
703
+ This lemma is part of the existence proof of `(v,\{4,7\})`-PBD as explained
704
+ in IX.4.5 from [BJL99]_).
705
+
706
+ INPUT:
707
+
708
+ - ``gdd`` -- a `(v,\{4,5,7\},Y)`-GDD where `Y=\NN-\{3,6,10\}`
709
+
710
+ - ``check`` -- boolean (default: ``True``); whether to check that output is
711
+ correct before returning it. As this is expected to be useless, you may
712
+ want to disable it whenever you want speed.
713
+
714
+ EXAMPLES::
715
+
716
+ sage: from sage.combinat.designs.resolvable_bibd import PBD_4_7_from_Y
717
+ sage: PBD_4_7_from_Y(designs.transversal_design(7,8)) # needs sage.schemes
718
+ Pairwise Balanced Design on 169 points with sets of sizes in [4, 7]
719
+
720
+ TESTS::
721
+
722
+ sage: PBD_4_7_from_Y(designs.balanced_incomplete_block_design(10,10)) # needs sage.schemes
723
+ Traceback (most recent call last):
724
+ ...
725
+ ValueError: The GDD should only contain blocks of size {4,5,7} but there are other: [10]
726
+ sage: PBD_4_7_from_Y(designs.transversal_design(4,3)) # needs sage.schemes
727
+ Traceback (most recent call last):
728
+ ...
729
+ RuntimeError: A group has size 3 but I do not know how to build a (10,[4,7])-PBD
730
+ """
731
+ from .group_divisible_designs import group_divisible_design
732
+ from .bibd import PairwiseBalancedDesign
733
+ block_sizes = set(map(len,gdd._blocks))
734
+ group_sizes = set(map(len,gdd._groups))
735
+ if not block_sizes.issubset([4, 5, 7]):
736
+ txt = list(block_sizes.difference([4, 5, 7]))
737
+ raise ValueError("The GDD should only contain blocks of size {{4,5,7}} "
738
+ "but there are other: {}".format(txt))
739
+
740
+ for gs in group_sizes:
741
+ if PBD_4_7(3*gs+1,existence=True) is not True:
742
+ raise RuntimeError("A group has size {} but I do not know how to "
743
+ "build a ({},[4,7])-PBD".format(gs,3*gs+1))
744
+
745
+ GDD = {} # the GDD we will need
746
+ if 4 in block_sizes:
747
+ # GDD[4] = GDD_from_BIBD(3*4,4)
748
+ GDD[4] = group_divisible_design(3*4,K=[4],G=[3])
749
+ if 5 in block_sizes:
750
+ # GDD[5] = GDD_from_BIBD(3*5,4)
751
+ GDD[5] = group_divisible_design(3*5,K=[4],G=[3])
752
+ if 7 in block_sizes:
753
+ # It is obtained from a PBD_4_7(22) by removing a point only contained
754
+ # in sets of size 4
755
+ GDD[7] = PBD_4_7(22)
756
+ x = set(range(22)).difference(*[S for S in GDD[7] if len(S) != 4]).pop()
757
+ relabel = sum((S for S in GDD[7] if x in S),[]) # the groups must be 012,345,...
758
+ relabel = [xx for xx in relabel if xx != x]+[x]
759
+ GDD[7].relabel({v:i for i,v in enumerate(relabel)})
760
+ GDD[7] = [S for S in GDD[7] if 21 not in S]
761
+
762
+ PBD = []
763
+
764
+ # The blocks
765
+ for B in gdd:
766
+ for B_GDD in GDD[len(B)]:
767
+ PBD.append([3*B[x//3]+(x % 3) for x in B_GDD])
768
+
769
+ # The groups
770
+ group_PBD = {gs:PBD_4_7(3*gs+1) for gs in group_sizes}
771
+ for G in gdd.groups():
772
+ gs = len(G)
773
+ for B in group_PBD[gs]:
774
+ PBD.append([3*G[x//3]+(x % 3) if x < 3*gs else 3*gdd.num_points()
775
+ for x in B])
776
+
777
+ return PairwiseBalancedDesign(3*gdd.num_points()+1,
778
+ blocks=PBD,
779
+ K=[4,7],
780
+ check=check,
781
+ copy=False)