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.
- passagemath_combinat/__init__.py +3 -0
- {passagemath_combinat-10.6.1.dist-info → passagemath_combinat-10.8.1a1.dist-info}/METADATA +17 -20
- {passagemath_combinat-10.6.1.dist-info → passagemath_combinat-10.8.1a1.dist-info}/RECORD +220 -218
- {passagemath_combinat-10.6.1.dist-info → passagemath_combinat-10.8.1a1.dist-info}/WHEEL +1 -1
- passagemath_combinat-10.8.1a1.dist-info/top_level.txt +3 -0
- sage/algebras/affine_nil_temperley_lieb.py +3 -3
- sage/algebras/all.py +0 -1
- sage/algebras/askey_wilson.py +1 -1
- sage/algebras/associated_graded.py +2 -2
- sage/algebras/cellular_basis.py +3 -6
- sage/algebras/cluster_algebra.py +2 -3
- sage/algebras/down_up_algebra.py +6 -6
- sage/algebras/free_algebra.py +3 -32
- sage/algebras/free_algebra_element.py +21 -25
- sage/algebras/free_algebra_quotient_element.py +9 -38
- sage/algebras/free_zinbiel_algebra.py +4 -3
- sage/algebras/hall_algebra.py +2 -2
- sage/algebras/hecke_algebras/ariki_koike_algebra.py +8 -8
- sage/algebras/hecke_algebras/ariki_koike_specht_modules.py +2 -2
- sage/algebras/hecke_algebras/cubic_hecke_algebra.py +11 -14
- sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +1 -1
- sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py +5 -5
- sage/algebras/iwahori_hecke_algebra.py +59 -57
- sage/algebras/jordan_algebra.py +97 -89
- sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py +6 -6
- sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py +14 -12
- sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py +6 -6
- sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py +4 -4
- sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py +13 -13
- sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py +8 -6
- sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py +7 -5
- sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py +7 -7
- sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py +6 -5
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py +12 -11
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py +3 -3
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py +3 -3
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py +11 -11
- sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py +3 -3
- sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py +8 -7
- sage/algebras/lie_conformal_algebras/virasoro_lie_conformal_algebra.py +9 -8
- sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py +6 -5
- sage/algebras/nil_coxeter_algebra.py +4 -4
- sage/algebras/q_commuting_polynomials.py +6 -6
- sage/algebras/q_system.py +3 -3
- sage/algebras/quantum_clifford.py +8 -8
- sage/algebras/quantum_groups/fock_space.py +48 -8
- sage/algebras/quantum_groups/quantum_group_gap.py +5 -7
- sage/algebras/quantum_matrix_coordinate_algebra.py +7 -7
- sage/algebras/quantum_oscillator.py +3 -3
- sage/algebras/quaternion_algebra_element.py +5 -3
- sage/algebras/schur_algebra.py +3 -3
- sage/algebras/shuffle_algebra.py +5 -8
- sage/algebras/splitting_algebra.py +129 -85
- sage/algebras/tensor_algebra.py +7 -7
- sage/algebras/yangian.py +16 -15
- sage/algebras/yokonuma_hecke_algebra.py +13 -11
- sage/combinat/all.py +9 -0
- sage/combinat/all__sagemath_combinat.py +1 -0
- sage/combinat/alternating_sign_matrix.py +36 -29
- sage/combinat/baxter_permutations.py +32 -12
- sage/combinat/bijectionist.py +13 -17
- sage/combinat/chas/fsym.py +6 -6
- sage/combinat/chas/wqsym.py +23 -29
- sage/combinat/colored_permutations.py +9 -11
- sage/combinat/colored_permutations_representations.py +13 -12
- sage/combinat/composition_tableau.py +2 -2
- sage/combinat/constellation.py +57 -30
- sage/combinat/crystals/affine_factorization.py +5 -4
- sage/combinat/crystals/alcove_path.py +2 -2
- sage/combinat/crystals/fully_commutative_stable_grothendieck.py +3 -2
- sage/combinat/crystals/infinity_crystals.py +18 -18
- sage/combinat/crystals/kac_modules.py +1 -1
- sage/combinat/crystals/kirillov_reshetikhin.py +2 -2
- sage/combinat/crystals/letters.cpython-312-aarch64-linux-musl.so +0 -0
- sage/combinat/crystals/littelmann_path.py +1 -1
- sage/combinat/crystals/pbw_datum.cpython-312-aarch64-linux-musl.so +0 -0
- sage/combinat/crystals/pbw_datum.pyx +3 -2
- sage/combinat/crystals/spins.cpython-312-aarch64-linux-musl.so +0 -0
- sage/combinat/crystals/tensor_product.py +7 -5
- sage/combinat/crystals/tensor_product_element.cpython-312-aarch64-linux-musl.so +0 -0
- sage/combinat/debruijn_sequence.cpython-312-aarch64-linux-musl.so +0 -0
- sage/combinat/debruijn_sequence.pyx +1 -2
- sage/combinat/degree_sequences.cpython-312-aarch64-linux-musl.so +0 -0
- sage/combinat/degree_sequences.pyx +241 -188
- sage/combinat/derangements.py +28 -22
- sage/combinat/diagram_algebras.py +12 -14
- sage/combinat/dyck_word.py +15 -14
- sage/combinat/e_one_star.py +1 -1
- sage/combinat/expnums.cpython-312-aarch64-linux-musl.so +0 -0
- sage/combinat/fast_vector_partitions.cpython-312-aarch64-linux-musl.so +0 -0
- sage/combinat/fqsym.py +13 -19
- sage/combinat/free_dendriform_algebra.py +2 -2
- sage/combinat/free_prelie_algebra.py +2 -2
- sage/combinat/fully_commutative_elements.py +8 -8
- sage/combinat/fully_packed_loop.py +9 -9
- sage/combinat/gelfand_tsetlin_patterns.py +4 -5
- sage/combinat/gray_codes.py +3 -4
- sage/combinat/grossman_larson_algebras.py +2 -2
- sage/combinat/growth.py +13 -13
- sage/combinat/hall_polynomial.py +1 -1
- sage/combinat/hillman_grassl.py +1 -1
- sage/combinat/integer_matrices.py +5 -7
- sage/combinat/k_tableau.py +8 -7
- sage/combinat/kazhdan_lusztig.py +3 -3
- sage/combinat/key_polynomial.py +845 -298
- sage/combinat/knutson_tao_puzzles.py +11 -13
- sage/combinat/matrices/hadamard_matrix.py +1 -1
- sage/combinat/matrices/latin.py +75 -92
- sage/combinat/misc.py +3 -3
- sage/combinat/multiset_partition_into_sets_ordered.py +27 -10
- sage/combinat/ncsf_qsym/generic_basis_code.py +5 -5
- sage/combinat/ncsf_qsym/ncsf.py +6 -5
- sage/combinat/ncsf_qsym/qsym.py +9 -17
- sage/combinat/ncsym/ncsym.py +8 -12
- sage/combinat/nu_dyck_word.py +1 -1
- sage/combinat/parallelogram_polyomino.py +3 -5
- sage/combinat/parking_functions.py +6 -5
- sage/combinat/partition_algebra.py +22 -57
- sage/combinat/partition_kleshchev.py +4 -4
- sage/combinat/partition_tuple.py +12 -10
- sage/combinat/plane_partition.py +10 -13
- sage/combinat/positive_integer_semigroup_test.py +17 -0
- sage/combinat/q_bernoulli.cpython-312-aarch64-linux-musl.so +0 -0
- sage/combinat/quickref.py +2 -2
- sage/combinat/recognizable_series.py +2 -2
- sage/combinat/regular_sequence.py +7 -7
- sage/combinat/regular_sequence_bounded.py +15 -21
- sage/combinat/restricted_growth.py +3 -3
- sage/combinat/ribbon.py +3 -3
- sage/combinat/rigged_configurations/bijection.py +3 -3
- sage/combinat/rigged_configurations/rigged_partition.cpython-312-aarch64-linux-musl.so +0 -0
- sage/combinat/rsk.py +2 -0
- sage/combinat/schubert_polynomial.py +11 -2
- sage/combinat/set_partition.py +3 -7
- sage/combinat/set_partition_iterator.cpython-312-aarch64-linux-musl.so +0 -0
- sage/combinat/set_partition_iterator.pyx +0 -1
- sage/combinat/set_partition_ordered.py +2 -2
- sage/combinat/sf/classical.py +1 -1
- sage/combinat/sf/dual.py +4 -8
- sage/combinat/sf/elementary.py +13 -7
- sage/combinat/sf/hall_littlewood.py +10 -8
- sage/combinat/sf/homogeneous.py +6 -3
- sage/combinat/sf/jack.py +11 -9
- sage/combinat/sf/llt.py +4 -5
- sage/combinat/sf/macdonald.py +10 -11
- sage/combinat/sf/monomial.py +6 -0
- sage/combinat/sf/ns_macdonald.py +92 -51
- sage/combinat/sf/powersum.py +9 -14
- sage/combinat/sf/schur.py +6 -0
- sage/combinat/sf/sf.py +21 -19
- sage/combinat/sf/sfa.py +13 -64
- sage/combinat/shifted_primed_tableau.py +5 -7
- sage/combinat/shuffle.py +1 -1
- sage/combinat/sine_gordon.py +18 -38
- sage/combinat/skew_partition.py +9 -12
- sage/combinat/skew_tableau.py +2 -7
- sage/combinat/sloane_functions.py +1 -1
- sage/combinat/species/all.py +67 -2
- sage/combinat/species/characteristic_species.py +3 -0
- sage/combinat/species/composition_species.py +3 -0
- sage/combinat/species/cycle_species.py +4 -0
- sage/combinat/species/empty_species.py +3 -0
- sage/combinat/species/functorial_composition_species.py +3 -0
- sage/combinat/species/generating_series.py +3 -0
- sage/combinat/species/library.py +3 -0
- sage/combinat/species/linear_order_species.py +3 -0
- sage/combinat/species/partition_species.py +3 -0
- sage/combinat/species/permutation_species.py +4 -0
- sage/combinat/species/product_species.py +3 -0
- sage/combinat/species/recursive_species.py +3 -0
- sage/combinat/species/set_species.py +3 -0
- sage/combinat/species/species.py +13 -7
- sage/combinat/species/structure.py +8 -9
- sage/combinat/species/subset_species.py +3 -0
- sage/combinat/species/sum_species.py +3 -0
- sage/combinat/subword.py +4 -1
- sage/combinat/subword_complex.py +7 -7
- sage/combinat/subword_complex_c.cpython-312-aarch64-linux-musl.so +0 -0
- sage/combinat/superpartition.py +1 -1
- sage/combinat/symmetric_group_algebra.py +9 -9
- sage/combinat/symmetric_group_representations.py +5 -5
- sage/combinat/t_sequences.py +4 -4
- sage/combinat/tableau.py +3 -4
- sage/combinat/tableau_tuple.py +2 -2
- sage/combinat/tiling.py +39 -42
- sage/combinat/triangles_FHM.py +38 -15
- sage/combinat/tutorial.py +2 -2
- sage/combinat/vector_partition.py +43 -31
- sage/combinat/words/abstract_word.py +4 -4
- sage/combinat/words/alphabet.py +12 -12
- sage/combinat/words/finite_word.py +25 -229
- sage/combinat/words/infinite_word.py +1 -1
- sage/combinat/words/morphic.py +13 -13
- sage/combinat/words/morphism.py +3 -12
- sage/combinat/words/paths.py +16 -17
- sage/combinat/words/word.py +60 -35
- sage/combinat/words/word_char.cpython-312-aarch64-linux-musl.so +0 -0
- sage/combinat/words/word_char.pyx +46 -7
- sage/combinat/words/word_datatypes.cpython-312-aarch64-linux-musl.so +0 -0
- sage/combinat/words/word_generators.py +39 -38
- sage/databases/findstat.py +72 -31
- sage/databases/oeis.py +125 -25
- sage/databases/sloane.py +14 -8
- sage/games/sudoku_backtrack.cpython-312-aarch64-linux-musl.so +0 -0
- sage/groups/indexed_free_group.py +3 -4
- sage/libs/symmetrica/symmetrica.cpython-312-aarch64-linux-musl.so +0 -0
- sage/libs/symmetrica/symmetrica.pxi +1 -0
- sage/monoids/automatic_semigroup.py +1 -3
- sage/monoids/free_abelian_monoid.py +7 -33
- sage/monoids/free_abelian_monoid_element.cpython-312-aarch64-linux-musl.so +0 -0
- sage/monoids/free_monoid.py +8 -40
- sage/monoids/free_monoid_element.py +1 -9
- sage/monoids/string_monoid.py +5 -2
- sage/monoids/string_monoid_element.py +12 -66
- sage/rings/all__sagemath_combinat.py +7 -0
- sage/sat/solvers/__init__.py +3 -4
- sage/sat/solvers/cryptominisat.py +2 -3
- sage/sat/solvers/picosat.py +2 -3
- sage/sat/solvers/sat_lp.py +2 -2
- sage/sat/solvers/satsolver.cpython-312-aarch64-linux-musl.so +0 -0
- 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:
|
|
16
|
+
sage: (4, 3, 3, 3, 3) in DS
|
|
17
17
|
True
|
|
18
|
-
sage:
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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 =
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
[
|
|
340
|
+
[(0,)]
|
|
341
341
|
sage: [d for d in DegreeSequences(3)]
|
|
342
|
-
[
|
|
342
|
+
[(0, 0, 0), (1, 1, 0), (2, 1, 1), (2, 2, 2)]
|
|
343
343
|
sage: [d for d in DegreeSequences(1)]
|
|
344
|
-
[
|
|
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
|
-
|
|
412
|
-
"""
|
|
413
|
-
Freeing the memory
|
|
414
|
-
"""
|
|
415
|
-
sig_free(seq)
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
cdef init(int n):
|
|
417
|
+
cdef class _DegreeSequenceEnumerator:
|
|
419
418
|
"""
|
|
420
|
-
|
|
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
|
-
|
|
423
|
-
|
|
424
|
-
global sequences
|
|
441
|
+
cdef int N
|
|
442
|
+
cdef unsigned char * seq
|
|
425
443
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
return [[0]]
|
|
444
|
+
def __cinit__(self, int n):
|
|
445
|
+
"""
|
|
446
|
+
Allocate memory for the degree sequence enumerator.
|
|
430
447
|
|
|
431
|
-
|
|
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
|
-
|
|
434
|
-
seq[0] = 1
|
|
453
|
+
INPUT:
|
|
435
454
|
|
|
436
|
-
|
|
437
|
-
sequences = []
|
|
438
|
-
enum(1, 0)
|
|
439
|
-
sig_free(seq)
|
|
440
|
-
return sequences
|
|
455
|
+
- ``n`` -- positive integer; the number of vertices
|
|
441
456
|
|
|
442
|
-
|
|
443
|
-
"""
|
|
444
|
-
This function is called whenever a sequence is found.
|
|
457
|
+
TESTS::
|
|
445
458
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
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
|
-
|
|
454
|
-
|
|
467
|
+
def __dealloc__(self):
|
|
468
|
+
"""
|
|
469
|
+
Deallocate the memory used by the enumerator.
|
|
455
470
|
|
|
456
|
-
|
|
457
|
-
|
|
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
|
-
|
|
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
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
493
|
-
|
|
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
|
-
|
|
497
|
-
|
|
498
|
-
|
|
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
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
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
|
-
|
|
506
|
-
|
|
611
|
+
seq[1] += i
|
|
612
|
+
seq[0] -= i
|
|
613
|
+
seq[taken+i] += 1
|
|
507
614
|
|
|
508
|
-
|
|
615
|
+
yield from self.enum(k+1, taken+i)
|
|
509
616
|
|
|
510
|
-
|
|
511
|
-
|
|
617
|
+
seq[taken+i] -= 1
|
|
618
|
+
seq[1] -= i
|
|
619
|
+
seq[0] += i
|
|
512
620
|
|
|
513
|
-
|
|
514
|
-
|
|
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
|
-
|
|
520
|
-
|
|
521
|
-
|
|
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
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
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
|
-
|
|
532
|
-
n_previous_box = seq[current_box-1]
|
|
639
|
+
cdef _DegreeSequenceEnumerator enumerator = _DegreeSequenceEnumerator(n)
|
|
533
640
|
|
|
534
|
-
|
|
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)
|
sage/combinat/derangements.py
CHANGED
|
@@ -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
|
|
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
|
-
|
|
389
|
-
|
|
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
|
|
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
|
-
|
|
444
|
+
Return a random derangement of `[1, 2, \ldots, n]`.
|
|
443
445
|
|
|
444
|
-
This is an
|
|
445
|
-
|
|
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)
|
|
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
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
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
|
|
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])
|