passagemath-combinat 10.6.1__cp312-cp312-musllinux_1_2_aarch64.whl → 10.8.1a1__cp312-cp312-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 (221) hide show
  1. passagemath_combinat/__init__.py +3 -0
  2. {passagemath_combinat-10.6.1.dist-info → passagemath_combinat-10.8.1a1.dist-info}/METADATA +17 -20
  3. {passagemath_combinat-10.6.1.dist-info → passagemath_combinat-10.8.1a1.dist-info}/RECORD +220 -218
  4. {passagemath_combinat-10.6.1.dist-info → passagemath_combinat-10.8.1a1.dist-info}/WHEEL +1 -1
  5. passagemath_combinat-10.8.1a1.dist-info/top_level.txt +3 -0
  6. sage/algebras/affine_nil_temperley_lieb.py +3 -3
  7. sage/algebras/all.py +0 -1
  8. sage/algebras/askey_wilson.py +1 -1
  9. sage/algebras/associated_graded.py +2 -2
  10. sage/algebras/cellular_basis.py +3 -6
  11. sage/algebras/cluster_algebra.py +2 -3
  12. sage/algebras/down_up_algebra.py +6 -6
  13. sage/algebras/free_algebra.py +3 -32
  14. sage/algebras/free_algebra_element.py +21 -25
  15. sage/algebras/free_algebra_quotient_element.py +9 -38
  16. sage/algebras/free_zinbiel_algebra.py +4 -3
  17. sage/algebras/hall_algebra.py +2 -2
  18. sage/algebras/hecke_algebras/ariki_koike_algebra.py +8 -8
  19. sage/algebras/hecke_algebras/ariki_koike_specht_modules.py +2 -2
  20. sage/algebras/hecke_algebras/cubic_hecke_algebra.py +11 -14
  21. sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +1 -1
  22. sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py +5 -5
  23. sage/algebras/iwahori_hecke_algebra.py +59 -57
  24. sage/algebras/jordan_algebra.py +97 -89
  25. sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py +6 -6
  26. sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py +14 -12
  27. sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py +6 -6
  28. sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py +4 -4
  29. sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py +13 -13
  30. sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py +8 -6
  31. sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py +7 -5
  32. sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py +7 -7
  33. sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py +6 -5
  34. sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py +12 -11
  35. sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py +3 -3
  36. sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py +3 -3
  37. sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py +11 -11
  38. sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py +3 -3
  39. sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py +8 -7
  40. sage/algebras/lie_conformal_algebras/virasoro_lie_conformal_algebra.py +9 -8
  41. sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py +6 -5
  42. sage/algebras/nil_coxeter_algebra.py +4 -4
  43. sage/algebras/q_commuting_polynomials.py +6 -6
  44. sage/algebras/q_system.py +3 -3
  45. sage/algebras/quantum_clifford.py +8 -8
  46. sage/algebras/quantum_groups/fock_space.py +48 -8
  47. sage/algebras/quantum_groups/quantum_group_gap.py +5 -7
  48. sage/algebras/quantum_matrix_coordinate_algebra.py +7 -7
  49. sage/algebras/quantum_oscillator.py +3 -3
  50. sage/algebras/quaternion_algebra_element.py +5 -3
  51. sage/algebras/schur_algebra.py +3 -3
  52. sage/algebras/shuffle_algebra.py +5 -8
  53. sage/algebras/splitting_algebra.py +129 -85
  54. sage/algebras/tensor_algebra.py +7 -7
  55. sage/algebras/yangian.py +16 -15
  56. sage/algebras/yokonuma_hecke_algebra.py +13 -11
  57. sage/combinat/all.py +9 -0
  58. sage/combinat/all__sagemath_combinat.py +1 -0
  59. sage/combinat/alternating_sign_matrix.py +36 -29
  60. sage/combinat/baxter_permutations.py +32 -12
  61. sage/combinat/bijectionist.py +13 -17
  62. sage/combinat/chas/fsym.py +6 -6
  63. sage/combinat/chas/wqsym.py +23 -29
  64. sage/combinat/colored_permutations.py +9 -11
  65. sage/combinat/colored_permutations_representations.py +13 -12
  66. sage/combinat/composition_tableau.py +2 -2
  67. sage/combinat/constellation.py +57 -30
  68. sage/combinat/crystals/affine_factorization.py +5 -4
  69. sage/combinat/crystals/alcove_path.py +2 -2
  70. sage/combinat/crystals/fully_commutative_stable_grothendieck.py +3 -2
  71. sage/combinat/crystals/infinity_crystals.py +18 -18
  72. sage/combinat/crystals/kac_modules.py +1 -1
  73. sage/combinat/crystals/kirillov_reshetikhin.py +2 -2
  74. sage/combinat/crystals/letters.cpython-312-aarch64-linux-musl.so +0 -0
  75. sage/combinat/crystals/littelmann_path.py +1 -1
  76. sage/combinat/crystals/pbw_datum.cpython-312-aarch64-linux-musl.so +0 -0
  77. sage/combinat/crystals/pbw_datum.pyx +3 -2
  78. sage/combinat/crystals/spins.cpython-312-aarch64-linux-musl.so +0 -0
  79. sage/combinat/crystals/tensor_product.py +7 -5
  80. sage/combinat/crystals/tensor_product_element.cpython-312-aarch64-linux-musl.so +0 -0
  81. sage/combinat/debruijn_sequence.cpython-312-aarch64-linux-musl.so +0 -0
  82. sage/combinat/debruijn_sequence.pyx +1 -2
  83. sage/combinat/degree_sequences.cpython-312-aarch64-linux-musl.so +0 -0
  84. sage/combinat/degree_sequences.pyx +241 -188
  85. sage/combinat/derangements.py +28 -22
  86. sage/combinat/diagram_algebras.py +12 -14
  87. sage/combinat/dyck_word.py +15 -14
  88. sage/combinat/e_one_star.py +1 -1
  89. sage/combinat/expnums.cpython-312-aarch64-linux-musl.so +0 -0
  90. sage/combinat/fast_vector_partitions.cpython-312-aarch64-linux-musl.so +0 -0
  91. sage/combinat/fqsym.py +13 -19
  92. sage/combinat/free_dendriform_algebra.py +2 -2
  93. sage/combinat/free_prelie_algebra.py +2 -2
  94. sage/combinat/fully_commutative_elements.py +8 -8
  95. sage/combinat/fully_packed_loop.py +9 -9
  96. sage/combinat/gelfand_tsetlin_patterns.py +4 -5
  97. sage/combinat/gray_codes.py +3 -4
  98. sage/combinat/grossman_larson_algebras.py +2 -2
  99. sage/combinat/growth.py +13 -13
  100. sage/combinat/hall_polynomial.py +1 -1
  101. sage/combinat/hillman_grassl.py +1 -1
  102. sage/combinat/integer_matrices.py +5 -7
  103. sage/combinat/k_tableau.py +8 -7
  104. sage/combinat/kazhdan_lusztig.py +3 -3
  105. sage/combinat/key_polynomial.py +845 -298
  106. sage/combinat/knutson_tao_puzzles.py +11 -13
  107. sage/combinat/matrices/hadamard_matrix.py +1 -1
  108. sage/combinat/matrices/latin.py +75 -92
  109. sage/combinat/misc.py +3 -3
  110. sage/combinat/multiset_partition_into_sets_ordered.py +27 -10
  111. sage/combinat/ncsf_qsym/generic_basis_code.py +5 -5
  112. sage/combinat/ncsf_qsym/ncsf.py +6 -5
  113. sage/combinat/ncsf_qsym/qsym.py +9 -17
  114. sage/combinat/ncsym/ncsym.py +8 -12
  115. sage/combinat/nu_dyck_word.py +1 -1
  116. sage/combinat/parallelogram_polyomino.py +3 -5
  117. sage/combinat/parking_functions.py +6 -5
  118. sage/combinat/partition_algebra.py +22 -57
  119. sage/combinat/partition_kleshchev.py +4 -4
  120. sage/combinat/partition_tuple.py +12 -10
  121. sage/combinat/plane_partition.py +10 -13
  122. sage/combinat/positive_integer_semigroup_test.py +17 -0
  123. sage/combinat/q_bernoulli.cpython-312-aarch64-linux-musl.so +0 -0
  124. sage/combinat/quickref.py +2 -2
  125. sage/combinat/recognizable_series.py +2 -2
  126. sage/combinat/regular_sequence.py +7 -7
  127. sage/combinat/regular_sequence_bounded.py +15 -21
  128. sage/combinat/restricted_growth.py +3 -3
  129. sage/combinat/ribbon.py +3 -3
  130. sage/combinat/rigged_configurations/bijection.py +3 -3
  131. sage/combinat/rigged_configurations/rigged_partition.cpython-312-aarch64-linux-musl.so +0 -0
  132. sage/combinat/rsk.py +2 -0
  133. sage/combinat/schubert_polynomial.py +11 -2
  134. sage/combinat/set_partition.py +3 -7
  135. sage/combinat/set_partition_iterator.cpython-312-aarch64-linux-musl.so +0 -0
  136. sage/combinat/set_partition_iterator.pyx +0 -1
  137. sage/combinat/set_partition_ordered.py +2 -2
  138. sage/combinat/sf/classical.py +1 -1
  139. sage/combinat/sf/dual.py +4 -8
  140. sage/combinat/sf/elementary.py +13 -7
  141. sage/combinat/sf/hall_littlewood.py +10 -8
  142. sage/combinat/sf/homogeneous.py +6 -3
  143. sage/combinat/sf/jack.py +11 -9
  144. sage/combinat/sf/llt.py +4 -5
  145. sage/combinat/sf/macdonald.py +10 -11
  146. sage/combinat/sf/monomial.py +6 -0
  147. sage/combinat/sf/ns_macdonald.py +92 -51
  148. sage/combinat/sf/powersum.py +9 -14
  149. sage/combinat/sf/schur.py +6 -0
  150. sage/combinat/sf/sf.py +21 -19
  151. sage/combinat/sf/sfa.py +13 -64
  152. sage/combinat/shifted_primed_tableau.py +5 -7
  153. sage/combinat/shuffle.py +1 -1
  154. sage/combinat/sine_gordon.py +18 -38
  155. sage/combinat/skew_partition.py +9 -12
  156. sage/combinat/skew_tableau.py +2 -7
  157. sage/combinat/sloane_functions.py +1 -1
  158. sage/combinat/species/all.py +67 -2
  159. sage/combinat/species/characteristic_species.py +3 -0
  160. sage/combinat/species/composition_species.py +3 -0
  161. sage/combinat/species/cycle_species.py +4 -0
  162. sage/combinat/species/empty_species.py +3 -0
  163. sage/combinat/species/functorial_composition_species.py +3 -0
  164. sage/combinat/species/generating_series.py +3 -0
  165. sage/combinat/species/library.py +3 -0
  166. sage/combinat/species/linear_order_species.py +3 -0
  167. sage/combinat/species/partition_species.py +3 -0
  168. sage/combinat/species/permutation_species.py +4 -0
  169. sage/combinat/species/product_species.py +3 -0
  170. sage/combinat/species/recursive_species.py +3 -0
  171. sage/combinat/species/set_species.py +3 -0
  172. sage/combinat/species/species.py +13 -7
  173. sage/combinat/species/structure.py +8 -9
  174. sage/combinat/species/subset_species.py +3 -0
  175. sage/combinat/species/sum_species.py +3 -0
  176. sage/combinat/subword.py +4 -1
  177. sage/combinat/subword_complex.py +7 -7
  178. sage/combinat/subword_complex_c.cpython-312-aarch64-linux-musl.so +0 -0
  179. sage/combinat/superpartition.py +1 -1
  180. sage/combinat/symmetric_group_algebra.py +9 -9
  181. sage/combinat/symmetric_group_representations.py +5 -5
  182. sage/combinat/t_sequences.py +4 -4
  183. sage/combinat/tableau.py +3 -4
  184. sage/combinat/tableau_tuple.py +2 -2
  185. sage/combinat/tiling.py +39 -42
  186. sage/combinat/triangles_FHM.py +38 -15
  187. sage/combinat/tutorial.py +2 -2
  188. sage/combinat/vector_partition.py +43 -31
  189. sage/combinat/words/abstract_word.py +4 -4
  190. sage/combinat/words/alphabet.py +12 -12
  191. sage/combinat/words/finite_word.py +25 -229
  192. sage/combinat/words/infinite_word.py +1 -1
  193. sage/combinat/words/morphic.py +13 -13
  194. sage/combinat/words/morphism.py +3 -12
  195. sage/combinat/words/paths.py +16 -17
  196. sage/combinat/words/word.py +60 -35
  197. sage/combinat/words/word_char.cpython-312-aarch64-linux-musl.so +0 -0
  198. sage/combinat/words/word_char.pyx +46 -7
  199. sage/combinat/words/word_datatypes.cpython-312-aarch64-linux-musl.so +0 -0
  200. sage/combinat/words/word_generators.py +39 -38
  201. sage/databases/findstat.py +72 -31
  202. sage/databases/oeis.py +125 -25
  203. sage/databases/sloane.py +14 -8
  204. sage/games/sudoku_backtrack.cpython-312-aarch64-linux-musl.so +0 -0
  205. sage/groups/indexed_free_group.py +3 -4
  206. sage/libs/symmetrica/symmetrica.cpython-312-aarch64-linux-musl.so +0 -0
  207. sage/libs/symmetrica/symmetrica.pxi +1 -0
  208. sage/monoids/automatic_semigroup.py +1 -3
  209. sage/monoids/free_abelian_monoid.py +7 -33
  210. sage/monoids/free_abelian_monoid_element.cpython-312-aarch64-linux-musl.so +0 -0
  211. sage/monoids/free_monoid.py +8 -40
  212. sage/monoids/free_monoid_element.py +1 -9
  213. sage/monoids/string_monoid.py +5 -2
  214. sage/monoids/string_monoid_element.py +12 -66
  215. sage/rings/all__sagemath_combinat.py +7 -0
  216. sage/sat/solvers/__init__.py +3 -4
  217. sage/sat/solvers/cryptominisat.py +2 -3
  218. sage/sat/solvers/picosat.py +2 -3
  219. sage/sat/solvers/sat_lp.py +2 -2
  220. sage/sat/solvers/satsolver.cpython-312-aarch64-linux-musl.so +0 -0
  221. passagemath_combinat-10.6.1.dist-info/top_level.txt +0 -2
@@ -13,26 +13,26 @@ With the object ``DegreeSequences(n)``, one can:
13
13
  * Check whether a sequence is indeed a degree sequence::
14
14
 
15
15
  sage: DS = DegreeSequences(5)
16
- sage: [4, 3, 3, 3, 3] in DS
16
+ sage: (4, 3, 3, 3, 3) in DS
17
17
  True
18
- sage: [4, 4, 0, 0, 0] in DS
18
+ sage: (4, 4, 0, 0, 0) in DS
19
19
  False
20
20
 
21
21
  * List all the possible degree sequences of length `n`::
22
22
 
23
23
  sage: for seq in DegreeSequences(4):
24
24
  ....: print(seq)
25
- [0, 0, 0, 0]
26
- [1, 1, 0, 0]
27
- [2, 1, 1, 0]
28
- [3, 1, 1, 1]
29
- [1, 1, 1, 1]
30
- [2, 2, 1, 1]
31
- [2, 2, 2, 0]
32
- [3, 2, 2, 1]
33
- [2, 2, 2, 2]
34
- [3, 3, 2, 2]
35
- [3, 3, 3, 3]
25
+ (0, 0, 0, 0)
26
+ (1, 1, 0, 0)
27
+ (2, 1, 1, 0)
28
+ (3, 1, 1, 1)
29
+ (1, 1, 1, 1)
30
+ (2, 2, 1, 1)
31
+ (2, 2, 2, 0)
32
+ (3, 2, 2, 1)
33
+ (2, 2, 2, 2)
34
+ (3, 3, 2, 2)
35
+ (3, 3, 3, 3)
36
36
 
37
37
  .. NOTE::
38
38
 
@@ -40,7 +40,7 @@ With the object ``DegreeSequences(n)``, one can:
40
40
  :func:`~sage.graphs.generators.degree_sequence.DegreeSequence`.
41
41
  For instance::
42
42
 
43
- sage: ds = [3, 3, 2, 2, 2, 2, 2, 1, 1, 0]
43
+ sage: ds = (3, 3, 2, 2, 2, 2, 2, 1, 1, 0)
44
44
  sage: g = graphs.DegreeSequence(ds) # needs networkx sage.graphs
45
45
  sage: g.degree_sequence() # needs networkx sage.graphs
46
46
  [3, 3, 2, 2, 2, 2, 2, 1, 1, 0]
@@ -196,7 +196,8 @@ Indeed, when enumerating all the degree sequences of length `n`, Sage first
196
196
  allocates an array ``seq`` of `n+1` integers where ``seq[i]`` is the number of
197
197
  elements of value ``i`` in the current sequence. Obviously, ``seq[n]=0`` holds
198
198
  in permanence : it is useful to allocate a larger array than necessary to
199
- simplify the code. The ``seq`` array is a global variable.
199
+ simplify the code. The ``seq`` array lives inside a short-lived enumerator
200
+ object created for each traversal so that no global state leaks between calls.
200
201
 
201
202
  The recursive function ``enum(depth, maximum)`` is the one building the list of
202
203
  sequences. It builds the list of degree sequences of length `n` which *extend*
@@ -254,15 +255,6 @@ Checking the consistency of enumeration and test::
254
255
  sage: DS = DegreeSequences(6)
255
256
  sage: all(seq in DS for seq in DS)
256
257
  True
257
-
258
- .. WARNING::
259
-
260
- For the moment, iterating over all degree sequences involves building the
261
- list of them first, then iterate on this list. This is obviously bad,
262
- as it requires uselessly a **lot** of memory for large values of `n`.
263
-
264
- This should be changed. Updating the code does not require more
265
- than a couple of minutes.
266
258
  """
267
259
 
268
260
  # ****************************************************************************
@@ -276,11 +268,7 @@ Checking the consistency of enumeration and test::
276
268
  # ****************************************************************************
277
269
 
278
270
  from cysignals.memory cimport check_calloc, sig_free
279
- from cysignals.signals cimport sig_on, sig_off
280
-
281
-
282
- cdef unsigned char * seq
283
- cdef list sequences
271
+ from sage.rings.integer import Integer
284
272
 
285
273
 
286
274
  class DegreeSequences:
@@ -299,20 +287,32 @@ class DegreeSequences:
299
287
 
300
288
  sage: DegreeSequences(8)
301
289
  Degree sequences on 8 elements
302
- sage: [3,3,2,2,2,2,2,2] in DegreeSequences(8)
290
+ sage: DegreeSequences(1)
291
+ Degree sequences on 1 element
292
+ sage: (3,3,2,2,2,2,2,2) in DegreeSequences(8)
303
293
  True
304
294
 
305
295
  TESTS:
306
296
 
307
297
  :issue:`21824`::
308
298
 
299
+ sage: DegreeSequences(RR(1/2))
300
+ Traceback (most recent call last):
301
+ ...
302
+ TypeError: the input parameter must be a non-negative integer
309
303
  sage: DegreeSequences(-1)
310
304
  Traceback (most recent call last):
311
305
  ...
312
306
  ValueError: the input parameter must be >= 0
313
307
  """
308
+ try:
309
+ n = Integer(n)
310
+ except (TypeError, ValueError):
311
+ raise TypeError("the input parameter must be a non-negative integer")
312
+
314
313
  if n < 0:
315
314
  raise ValueError("the input parameter must be >= 0")
315
+
316
316
  self._n = n
317
317
 
318
318
  def __contains__(self, seq):
@@ -322,26 +322,33 @@ class DegreeSequences:
322
322
 
323
323
  EXAMPLES::
324
324
 
325
- sage: [3,3,2,2,2,2,2,2] in DegreeSequences(8)
325
+ sage: (3,3,2,2,2,2,2,2) in DegreeSequences(8)
326
326
  True
327
327
 
328
328
  TESTS:
329
329
 
330
330
  :issue:`15503`::
331
331
 
332
- sage: [2,2,2,2,1,1,1] in DegreeSequences(7)
332
+ sage: (2,2,2,2,1,1,1) in DegreeSequences(7)
333
333
  False
334
334
 
335
335
  :issue:`21824`::
336
336
 
337
337
  sage: [d for d in DegreeSequences(0)]
338
- [[]]
338
+ [()]
339
339
  sage: [d for d in DegreeSequences(1)]
340
- [[0]]
340
+ [(0,)]
341
341
  sage: [d for d in DegreeSequences(3)]
342
- [[0, 0, 0], [1, 1, 0], [2, 1, 1], [2, 2, 2]]
342
+ [(0, 0, 0), (1, 1, 0), (2, 1, 1), (2, 2, 2)]
343
343
  sage: [d for d in DegreeSequences(1)]
344
- [[0]]
344
+ [(0,)]
345
+
346
+ For lists we can also check containment::
347
+
348
+ sage: [3,3,2,2,2,2,2,2] in DegreeSequences(8)
349
+ True
350
+ sage: [2,2,2,2,1,1,1] in DegreeSequences(7)
351
+ False
345
352
  """
346
353
  cdef int n = self._n
347
354
  if len(seq) != n:
@@ -391,15 +398,14 @@ class DegreeSequences:
391
398
  sage: DegreeSequences(6)
392
399
  Degree sequences on 6 elements
393
400
  """
401
+ if self._n == 1:
402
+ return "Degree sequences on 1 element"
394
403
  return "Degree sequences on "+str(self._n)+" elements"
395
404
 
396
405
  def __iter__(self):
397
406
  """
398
407
  Iterate over all the degree sequences.
399
408
 
400
- TODO: THIS SHOULD BE UPDATED AS SOON AS THE YIELD KEYWORD APPEARS IN
401
- CYTHON. See comment in the class' documentation.
402
-
403
409
  EXAMPLES::
404
410
 
405
411
  sage: DS = DegreeSequences(6)
@@ -408,181 +414,228 @@ class DegreeSequences:
408
414
  """
409
415
  yield from init(self._n)
410
416
 
411
- def __dealloc__():
412
- """
413
- Freeing the memory
414
- """
415
- sig_free(seq)
416
-
417
-
418
- cdef init(int n):
417
+ cdef class _DegreeSequenceEnumerator:
419
418
  """
420
- Initialize the memory and starts the enumeration algorithm.
419
+ Internal enumerator class for degree sequences.
420
+
421
+ This class manages the memory and state for enumerating all degree
422
+ sequences of a given length using the algorithm described in [RCES1994]_.
423
+
424
+ EXAMPLES::
425
+
426
+ sage: from sage.combinat.degree_sequences import _DegreeSequenceEnumerator
427
+ sage: e = _DegreeSequenceEnumerator(4)
428
+ sage: list(e.enum(1, 0))
429
+ [(0, 0, 0, 0),
430
+ (1, 1, 0, 0),
431
+ (2, 1, 1, 0),
432
+ (3, 1, 1, 1),
433
+ (1, 1, 1, 1),
434
+ (2, 2, 1, 1),
435
+ (2, 2, 2, 0),
436
+ (3, 2, 2, 1),
437
+ (2, 2, 2, 2),
438
+ (3, 3, 2, 2),
439
+ (3, 3, 3, 3)]
421
440
  """
422
- global seq
423
- global N
424
- global sequences
441
+ cdef int N
442
+ cdef unsigned char * seq
425
443
 
426
- if n == 0:
427
- return [[]]
428
- elif n == 1:
429
- return [[0]]
444
+ def __cinit__(self, int n):
445
+ """
446
+ Allocate memory for the degree sequence enumerator.
430
447
 
431
- seq = <unsigned char *>check_calloc(n + 1, sizeof(unsigned char))
448
+ This method allocates an array of `n+1` unsigned chars to store
449
+ the count of vertices at each degree level. The array is
450
+ zero-initialized, and ``seq[0]`` is set to 1 to represent the
451
+ initial state with one vertex of degree 0.
432
452
 
433
- # We begin with one vertex of degree 0
434
- seq[0] = 1
453
+ INPUT:
435
454
 
436
- N = n
437
- sequences = []
438
- enum(1, 0)
439
- sig_free(seq)
440
- return sequences
455
+ - ``n`` -- positive integer; the number of vertices
441
456
 
442
- cdef inline add_seq():
443
- """
444
- This function is called whenever a sequence is found.
457
+ TESTS::
445
458
 
446
- Build the degree sequence corresponding to the current state of the
447
- algorithm and adds it to the sequences list.
448
- """
449
- global sequences
450
- global N
451
- global seq
459
+ sage: from sage.combinat.degree_sequences import _DegreeSequenceEnumerator
460
+ sage: e = _DegreeSequenceEnumerator(2)
461
+ """
462
+ self.seq = NULL
463
+ self.N = n
464
+ self.seq = <unsigned char *>check_calloc(n + 1, sizeof(unsigned char))
465
+ self.seq[0] = 1
452
466
 
453
- cdef list s = []
454
- cdef int i, j
467
+ def __dealloc__(self):
468
+ """
469
+ Deallocate the memory used by the enumerator.
455
470
 
456
- for N > i >= 0:
457
- for 0 <= j < seq[i]:
458
- s.append(i)
471
+ This method frees the memory allocated for the ``seq`` array
472
+ when the enumerator object is garbage collected.
459
473
 
460
- sequences.append(s)
474
+ TESTS::
461
475
 
476
+ sage: from sage.combinat.degree_sequences import _DegreeSequenceEnumerator
477
+ sage: e = _DegreeSequenceEnumerator(3)
478
+ sage: del e
479
+ """
480
+ if self.seq != NULL:
481
+ sig_free(self.seq)
482
+ self.seq = NULL
462
483
 
463
- cdef void enum(int k, int M) noexcept:
464
- r"""
465
- Main function; for an explanation of the algorithm please refer to the
466
- :mod:`sage.combinat.degree_sequences` documentation.
484
+ cdef tuple build_current_seq(self):
485
+ """
486
+ Return the degree sequence represented by the current counts.
487
+ """
488
+ cdef list s = []
489
+ cdef int i, j
490
+ cdef int count
467
491
 
468
- INPUT:
492
+ for i in range(self.N - 1, -1, -1):
493
+ count = self.seq[i]
494
+ for j in range(count):
495
+ s.append(i)
469
496
 
470
- - ``k`` -- depth of the partial degree sequence
471
- - ``M`` -- value of a maximum element in the partial degree sequence
472
- """
473
- cdef int i, j
474
- global seq
475
- cdef int taken = 0
476
- cdef int current_box
477
- cdef int n_current_box
478
- cdef int n_previous_box
479
- cdef int new_vertex
480
-
481
- # Have we found a new degree sequence ? End of recursion !
482
- if k == N:
483
- add_seq()
484
- return
497
+ return tuple(s)
485
498
 
486
- sig_on()
499
+ def enum(self, int k, int M):
500
+ r"""
501
+ Main function; for an explanation of the algorithm please refer to the
502
+ :mod:`sage.combinat.degree_sequences` documentation.
487
503
 
488
- #############################################
489
- # Creating vertices of Vertices of degree M #
490
- #############################################
504
+ INPUT:
491
505
 
492
- # If 0 is the current maximum degree, we can always extend the degree
493
- # sequence with another 0
494
- if M == 0:
506
+ - ``k`` -- depth of the partial degree sequence
507
+ - ``M`` -- value of a maximum element in the partial degree sequence
495
508
 
496
- seq[0] += 1
497
- enum(k + 1, M)
498
- seq[0] -= 1
509
+ This is a generator that yields degree sequences.
510
+ """
511
+ cdef int i, j
512
+ cdef unsigned char * seq = self.seq
513
+ cdef int N = self.N
514
+ cdef int taken = 0
515
+ cdef int current_box
516
+ cdef int n_current_box
517
+ cdef int n_previous_box
518
+ cdef int new_vertex
519
+
520
+ # Have we found a new degree sequence ? End of recursion !
521
+ if k == N:
522
+ yield self.build_current_seq()
523
+ return
524
+
525
+ ####################################
526
+ # Creating vertices of degree M #
527
+ ####################################
528
+
529
+ # If 0 is the current maximum degree, we can always extend the degree
530
+ # sequence with another 0
531
+ if M == 0:
532
+
533
+ seq[0] += 1
534
+ yield from self.enum(k + 1, M)
535
+ seq[0] -= 1
536
+
537
+ # We need not automatically increase the degree at each step. In this case,
538
+ # we have no other choice but to link the new vertex of degree M to vertices
539
+ # of degree M-1, which will become vertices of degree M too.
540
+ elif seq[M - 1] >= M:
541
+
542
+ seq[M] += M + 1
543
+ seq[M - 1] -= M
544
+
545
+ yield from self.enum(k + 1, M)
546
+
547
+ seq[M] -= M + 1
548
+ seq[M - 1] += M
549
+
550
+ ######################################
551
+ # Creating vertices of degree > M #
552
+ ######################################
553
+
554
+ for current_box in range(M, 0, -1):
555
+
556
+ # If there is not enough vertices in the boxes available
557
+ if taken + (seq[current_box] - 1) + seq[current_box-1] <= M:
558
+ taken += seq[current_box]
559
+ seq[current_box+1] += seq[current_box]
560
+ seq[current_box] = 0
561
+ continue
562
+
563
+ # The degree of the new vertex will be taken + i + j where:
564
+ #
565
+ # * i is the number of vertices taken in the *current* box
566
+ # * j the number of vertices taken in the *previous* one
567
+
568
+ n_current_box = seq[current_box]
569
+ n_previous_box = seq[current_box-1]
570
+
571
+ # Note to self, and others:
572
+ #
573
+ # In the following lines, there are many incrementation/decrementation
574
+ # that *may* be replaced by only +1 and -1 and save some
575
+ # instructions. This would involve adding several "if", and I feared it
576
+ # would make the code even uglier. If you are willing to give it a try,
577
+ # **please check the results** ! It is trickier that it seems ! Even
578
+ # changing the lower bounds in the for loops would require tests
579
+ # afterwards.
580
+
581
+ for i in range(max(0, (M + 1) - n_previous_box - taken), n_current_box):
582
+ seq[current_box] -= i
583
+ seq[current_box+1] += i
584
+
585
+ for j in range(max(0, (M + 1) - taken - i), n_previous_box + 1):
586
+ seq[current_box-1] -= j
587
+ seq[current_box] += j
588
+
589
+ new_vertex = taken + i + j
590
+ seq[new_vertex] += 1
591
+ yield from self.enum(k+1, new_vertex)
592
+ seq[new_vertex] -= 1
593
+
594
+ seq[current_box-1] += j
595
+ seq[current_box] -= j
596
+
597
+ seq[current_box] += i
598
+ seq[current_box+1] -= i
599
+
600
+ taken += n_current_box
601
+ seq[current_box] = 0
602
+ seq[current_box+1] += n_current_box
499
603
 
500
- # We need not automatically increase the degree at each step. In this case,
501
- # we have no other choice but to link the new vertex of degree M to vertices
502
- # of degree M-1, which will become vertices of degree M too.
503
- elif seq[M - 1] >= M:
604
+ # Corner case
605
+ #
606
+ # Now current_box = 0. All the vertices of nonzero degree are taken, we just
607
+ # want to know how many vertices of degree 0 will be neighbors of the new
608
+ # vertex.
609
+ for i in range(max(0, (M + 1) - taken), seq[0] + 1):
504
610
 
505
- seq[M] += M + 1
506
- seq[M - 1] -= M
611
+ seq[1] += i
612
+ seq[0] -= i
613
+ seq[taken+i] += 1
507
614
 
508
- enum(k + 1, M)
615
+ yield from self.enum(k+1, taken+i)
509
616
 
510
- seq[M] -= M + 1
511
- seq[M - 1] += M
617
+ seq[taken+i] -= 1
618
+ seq[1] -= i
619
+ seq[0] += i
512
620
 
513
- ###############################################
514
- # Creating vertices of Vertices of degree > M #
515
- ###############################################
621
+ # Shift everything back to normal ! ( cell N is always equal to 0)
622
+ for i in range(1, N):
623
+ seq[i] = seq[i+1]
516
624
 
517
- for M >= current_box > 0:
518
625
 
519
- # If there is not enough vertices in the boxes available
520
- if taken + (seq[current_box] - 1) + seq[current_box-1] <= M:
521
- taken += seq[current_box]
522
- seq[current_box+1] += seq[current_box]
523
- seq[current_box] = 0
524
- continue
626
+ def init(int n):
627
+ """
628
+ Initialize the memory and starts the enumeration algorithm.
525
629
 
526
- # The degree of the new vertex will be taken + i + j where:
527
- #
528
- # * i is the number of vertices taken in the *current* box
529
- # * j the number of vertices taken in the *previous* one
630
+ This is a generator that yields degree sequences one at a time.
631
+ """
632
+ if n == 0:
633
+ yield ()
634
+ return
635
+ elif n == 1:
636
+ yield (0,)
637
+ return
530
638
 
531
- n_current_box = seq[current_box]
532
- n_previous_box = seq[current_box-1]
639
+ cdef _DegreeSequenceEnumerator enumerator = _DegreeSequenceEnumerator(n)
533
640
 
534
- # Note to self, and others:
535
- #
536
- # In the following lines, there are many incrementation/decrementation
537
- # that *may* be replaced by only +1 and -1 and save some
538
- # instructions. This would involve adding several "if", and I feared it
539
- # would make the code even uglier. If you are willing to give it a try,
540
- # **please check the results** ! It is trickier that it seems ! Even
541
- # changing the lower bounds in the for loops would require tests
542
- # afterwards.
543
-
544
- for max(0, (M+1)-n_previous_box-taken) <= i < n_current_box:
545
- seq[current_box] -= i
546
- seq[current_box+1] += i
547
-
548
- for max(0, ((M+1)-taken-i)) <= j <= n_previous_box:
549
- seq[current_box-1] -= j
550
- seq[current_box] += j
551
-
552
- new_vertex = taken + i + j
553
- seq[new_vertex] += 1
554
- enum(k+1, new_vertex)
555
- seq[new_vertex] -= 1
556
-
557
- seq[current_box-1] += j
558
- seq[current_box] -= j
559
-
560
- seq[current_box] += i
561
- seq[current_box+1] -= i
562
-
563
- taken += n_current_box
564
- seq[current_box] = 0
565
- seq[current_box+1] += n_current_box
566
-
567
- # Corner case
568
- #
569
- # Now current_box = 0. All the vertices of nonzero degree are taken, we just
570
- # want to know how many vertices of degree 0 will be neighbors of the new
571
- # vertex.
572
- for max(0, ((M+1)-taken)) <= i <= seq[0]:
573
-
574
- seq[1] += i
575
- seq[0] -= i
576
- seq[taken+i] += 1
577
-
578
- enum(k+1, taken+i)
579
-
580
- seq[taken+i] -= 1
581
- seq[1] -= i
582
- seq[0] += i
583
-
584
- # Shift everything back to normal ! ( cell N is always equal to 0)
585
- for 1 <= i < N:
586
- seq[i] = seq[i+1]
587
-
588
- sig_off()
641
+ yield from enumerator.enum(1, 0)
@@ -349,9 +349,9 @@ class Derangements(UniqueRepresentation, Parent):
349
349
  sage: D._fixed_point([5,4,3,2,1])
350
350
  True
351
351
  """
352
- return any(x == y for (x, y) in zip(a, self._set))
352
+ return any(x == y for x, y in zip(a, self._set))
353
353
 
354
- def _count_der(self, n):
354
+ def _count_der(self, n) -> Integer:
355
355
  """
356
356
  Count the number of derangements of `n` using the recursion
357
357
  `D_2 = 1, D_3 = 2, D_n = (n-1) (D_{n-1} + D_{n-2})`.
@@ -385,8 +385,10 @@ class Derangements(UniqueRepresentation, Parent):
385
385
 
386
386
  def cardinality(self):
387
387
  r"""
388
- Counts the number of derangements of a positive integer, a
389
- list, or a string. The list or string may contain repeated
388
+ Count the number of derangements of a positive integer, a list,
389
+ or a string.
390
+
391
+ The list or string may contain repeated
390
392
  elements. If an integer `n` is given, the value returned
391
393
  is the number of derangements of `[1, 2, 3, \ldots, n]`.
392
394
 
@@ -433,17 +435,16 @@ class Derangements(UniqueRepresentation, Parent):
433
435
  A = [self._set.count(i) for i in sL]
434
436
  R = PolynomialRing(QQ, 'x', len(A))
435
437
  S = sum(R.gens())
436
- e = prod((S - x)**y for (x, y) in zip(R.gens(), A))
438
+ e = prod((S - x)**y for x, y in zip(R.gens(), A))
437
439
  return Integer(e.coefficient(dict(zip(R.gens(), A))))
438
440
  return self._count_der(len(self._set))
439
441
 
440
442
  def _rand_der(self):
441
443
  r"""
442
- Produces a random derangement of `[1, 2, \ldots, n]`.
444
+ Return a random derangement of `[1, 2, \ldots, n]`.
443
445
 
444
- This is an
445
- implementation of the algorithm described by Martinez et. al. in
446
- [MPP2008]_.
446
+ This is an implementation of the algorithm described by
447
+ Martinez et. al. in [MPP2008]_.
447
448
 
448
449
  EXAMPLES::
449
450
 
@@ -464,7 +465,7 @@ class Derangements(UniqueRepresentation, Parent):
464
465
  A[i - 1], A[j - 1] = A[j - 1], A[i - 1]
465
466
  break
466
467
  p = random()
467
- if p < (u - 1) * self._count_der(u - 2) // self._count_der(u):
468
+ if p * self._count_der(u) < (u - 1) * self._count_der(u - 2):
468
469
  mark[j - 1] = True
469
470
  u -= 1
470
471
  u -= 1
@@ -472,22 +473,17 @@ class Derangements(UniqueRepresentation, Parent):
472
473
  return A
473
474
 
474
475
  def random_element(self):
475
- r"""
476
- Produce all derangements of a positive integer, a list, or
477
- a string. The list or string may contain repeated elements.
478
- If an integer `n` is given, then a random
479
- derangements of `[1, 2, 3, \ldots, n]` is returned
476
+ r"""Return a random derangement.
480
477
 
481
- For an integer, or a list or string with all elements
482
- distinct, the value is obtained by an algorithm described in
483
- [MPP2008]_. For a list or string with repeated elements the
484
- derangement is formed by choosing an element at random from the list of
485
- all possible derangements.
478
+ If the elements of the underlying multiset are all distinct,
479
+ an algorithm described in [MPP2008]_ is used. For a list or
480
+ string with repeated elements the derangement is formed by
481
+ choosing an element at random from the list of all possible
482
+ derangements.
486
483
 
487
484
  OUTPUT:
488
485
 
489
- A single list or string containing a derangement, or an
490
- empty list if there are no derangements.
486
+ A derangement, or an empty list if there are no derangements.
491
487
 
492
488
  EXAMPLES::
493
489
 
@@ -516,6 +512,13 @@ class Derangements(UniqueRepresentation, Parent):
516
512
 
517
513
  sage: D = Derangements([1,1,2,2])
518
514
  sage: _ = [D.random_element() for _ in range(20)]
515
+
516
+ Check that we do not produce a derangement of a single
517
+ element::
518
+
519
+ sage: D = Derangements(1)
520
+ sage: D.random_element()
521
+ []
519
522
  """
520
523
  if self.__multi:
521
524
  L = list(self)
@@ -523,5 +526,8 @@ class Derangements(UniqueRepresentation, Parent):
523
526
  return self.element_class(self, [])
524
527
  i = randrange(len(L))
525
528
  return L[i]
529
+
530
+ if len(self._set) == 1:
531
+ return self.element_class(self, [])
526
532
  temp = self._rand_der()
527
533
  return self.element_class(self, [self._set[ii - 1] for ii in temp])