passagemath-combinat 10.6.42__cp314-cp314-musllinux_1_2_x86_64.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.42.dist-info/METADATA +160 -0
- passagemath_combinat-10.6.42.dist-info/RECORD +400 -0
- passagemath_combinat-10.6.42.dist-info/WHEEL +5 -0
- passagemath_combinat-10.6.42.dist-info/top_level.txt +3 -0
- passagemath_combinat.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
- passagemath_combinat.libs/libsymmetrica-81fe8739.so.3.0.0 +0 -0
- sage/algebras/affine_nil_temperley_lieb.py +263 -0
- sage/algebras/all.py +24 -0
- sage/algebras/all__sagemath_combinat.py +35 -0
- sage/algebras/askey_wilson.py +935 -0
- sage/algebras/associated_graded.py +345 -0
- sage/algebras/cellular_basis.py +350 -0
- sage/algebras/cluster_algebra.py +2766 -0
- sage/algebras/down_up_algebra.py +860 -0
- sage/algebras/free_algebra.py +1698 -0
- sage/algebras/free_algebra_element.py +345 -0
- sage/algebras/free_algebra_quotient.py +405 -0
- sage/algebras/free_algebra_quotient_element.py +295 -0
- sage/algebras/free_zinbiel_algebra.py +885 -0
- sage/algebras/hall_algebra.py +783 -0
- sage/algebras/hecke_algebras/all.py +4 -0
- sage/algebras/hecke_algebras/ariki_koike_algebra.py +1796 -0
- sage/algebras/hecke_algebras/ariki_koike_specht_modules.py +475 -0
- sage/algebras/hecke_algebras/cubic_hecke_algebra.py +3520 -0
- sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +1473 -0
- sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py +1079 -0
- sage/algebras/iwahori_hecke_algebra.py +3095 -0
- sage/algebras/jordan_algebra.py +1773 -0
- sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py +113 -0
- sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py +156 -0
- sage/algebras/lie_conformal_algebras/all.py +18 -0
- sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py +134 -0
- sage/algebras/lie_conformal_algebras/examples.py +43 -0
- sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py +131 -0
- sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py +139 -0
- sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py +174 -0
- sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py +167 -0
- sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py +107 -0
- sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py +135 -0
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py +353 -0
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py +236 -0
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py +78 -0
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py +328 -0
- sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py +117 -0
- sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py +86 -0
- sage/algebras/lie_conformal_algebras/virasoro_lie_conformal_algebra.py +82 -0
- sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py +205 -0
- sage/algebras/nil_coxeter_algebra.py +191 -0
- sage/algebras/q_commuting_polynomials.py +673 -0
- sage/algebras/q_system.py +608 -0
- sage/algebras/quantum_clifford.py +959 -0
- sage/algebras/quantum_groups/ace_quantum_onsager.py +693 -0
- sage/algebras/quantum_groups/all.py +9 -0
- sage/algebras/quantum_groups/fock_space.py +2219 -0
- sage/algebras/quantum_groups/q_numbers.py +207 -0
- sage/algebras/quantum_groups/quantum_group_gap.py +2695 -0
- sage/algebras/quantum_groups/representations.py +591 -0
- sage/algebras/quantum_matrix_coordinate_algebra.py +1006 -0
- sage/algebras/quantum_oscillator.py +623 -0
- sage/algebras/quaternion_algebra.py +20 -0
- sage/algebras/quaternion_algebra_element.py +55 -0
- sage/algebras/rational_cherednik_algebra.py +525 -0
- sage/algebras/schur_algebra.py +670 -0
- sage/algebras/shuffle_algebra.py +1011 -0
- sage/algebras/splitting_algebra.py +779 -0
- sage/algebras/tensor_algebra.py +709 -0
- sage/algebras/yangian.py +1082 -0
- sage/algebras/yokonuma_hecke_algebra.py +1018 -0
- sage/all__sagemath_combinat.py +35 -0
- sage/combinat/SJT.py +255 -0
- sage/combinat/affine_permutation.py +2405 -0
- sage/combinat/algebraic_combinatorics.py +55 -0
- sage/combinat/all.py +53 -0
- sage/combinat/all__sagemath_combinat.py +195 -0
- sage/combinat/alternating_sign_matrix.py +2063 -0
- sage/combinat/baxter_permutations.py +346 -0
- sage/combinat/bijectionist.py +3220 -0
- sage/combinat/binary_recurrence_sequences.py +1180 -0
- sage/combinat/blob_algebra.py +685 -0
- sage/combinat/catalog_partitions.py +27 -0
- sage/combinat/chas/all.py +23 -0
- sage/combinat/chas/fsym.py +1180 -0
- sage/combinat/chas/wqsym.py +2601 -0
- sage/combinat/cluster_complex.py +326 -0
- sage/combinat/colored_permutations.py +2039 -0
- sage/combinat/colored_permutations_representations.py +964 -0
- sage/combinat/composition_signed.py +142 -0
- sage/combinat/composition_tableau.py +855 -0
- sage/combinat/constellation.py +1729 -0
- sage/combinat/core.py +751 -0
- sage/combinat/counting.py +12 -0
- sage/combinat/crystals/affine.py +742 -0
- sage/combinat/crystals/affine_factorization.py +518 -0
- sage/combinat/crystals/affinization.py +331 -0
- sage/combinat/crystals/alcove_path.py +2013 -0
- sage/combinat/crystals/all.py +22 -0
- sage/combinat/crystals/bkk_crystals.py +141 -0
- sage/combinat/crystals/catalog.py +115 -0
- sage/combinat/crystals/catalog_elementary_crystals.py +18 -0
- sage/combinat/crystals/catalog_infinity_crystals.py +33 -0
- sage/combinat/crystals/catalog_kirillov_reshetikhin.py +18 -0
- sage/combinat/crystals/crystals.py +257 -0
- sage/combinat/crystals/direct_sum.py +260 -0
- sage/combinat/crystals/elementary_crystals.py +1251 -0
- sage/combinat/crystals/fast_crystals.py +441 -0
- sage/combinat/crystals/fully_commutative_stable_grothendieck.py +1205 -0
- sage/combinat/crystals/generalized_young_walls.py +1076 -0
- sage/combinat/crystals/highest_weight_crystals.py +436 -0
- sage/combinat/crystals/induced_structure.py +695 -0
- sage/combinat/crystals/infinity_crystals.py +730 -0
- sage/combinat/crystals/kac_modules.py +863 -0
- sage/combinat/crystals/kirillov_reshetikhin.py +4196 -0
- sage/combinat/crystals/kyoto_path_model.py +497 -0
- sage/combinat/crystals/letters.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/crystals/letters.pxd +79 -0
- sage/combinat/crystals/letters.pyx +3056 -0
- sage/combinat/crystals/littelmann_path.py +1518 -0
- sage/combinat/crystals/monomial_crystals.py +1262 -0
- sage/combinat/crystals/multisegments.py +462 -0
- sage/combinat/crystals/mv_polytopes.py +467 -0
- sage/combinat/crystals/pbw_crystal.py +511 -0
- sage/combinat/crystals/pbw_datum.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/crystals/pbw_datum.pxd +4 -0
- sage/combinat/crystals/pbw_datum.pyx +487 -0
- sage/combinat/crystals/polyhedral_realization.py +372 -0
- sage/combinat/crystals/spins.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/crystals/spins.pxd +21 -0
- sage/combinat/crystals/spins.pyx +756 -0
- sage/combinat/crystals/star_crystal.py +290 -0
- sage/combinat/crystals/subcrystal.py +464 -0
- sage/combinat/crystals/tensor_product.py +1177 -0
- sage/combinat/crystals/tensor_product_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/crystals/tensor_product_element.pxd +35 -0
- sage/combinat/crystals/tensor_product_element.pyx +1870 -0
- sage/combinat/crystals/virtual_crystal.py +420 -0
- sage/combinat/cyclic_sieving_phenomenon.py +204 -0
- sage/combinat/debruijn_sequence.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/debruijn_sequence.pyx +355 -0
- sage/combinat/decorated_permutation.py +270 -0
- sage/combinat/degree_sequences.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/degree_sequences.pyx +588 -0
- sage/combinat/derangements.py +527 -0
- sage/combinat/descent_algebra.py +1008 -0
- sage/combinat/diagram.py +1551 -0
- sage/combinat/diagram_algebras.py +5886 -0
- sage/combinat/dyck_word.py +4349 -0
- sage/combinat/e_one_star.py +1623 -0
- sage/combinat/enumerated_sets.py +123 -0
- sage/combinat/expnums.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/expnums.pyx +148 -0
- sage/combinat/fast_vector_partitions.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/fast_vector_partitions.pyx +346 -0
- sage/combinat/fqsym.py +1977 -0
- sage/combinat/free_dendriform_algebra.py +954 -0
- sage/combinat/free_prelie_algebra.py +1141 -0
- sage/combinat/fully_commutative_elements.py +1077 -0
- sage/combinat/fully_packed_loop.py +1523 -0
- sage/combinat/gelfand_tsetlin_patterns.py +1409 -0
- sage/combinat/gray_codes.py +311 -0
- sage/combinat/grossman_larson_algebras.py +667 -0
- sage/combinat/growth.py +4352 -0
- sage/combinat/hall_polynomial.py +188 -0
- sage/combinat/hillman_grassl.py +866 -0
- sage/combinat/integer_matrices.py +329 -0
- sage/combinat/integer_vectors_mod_permgroup.py +1238 -0
- sage/combinat/k_tableau.py +4564 -0
- sage/combinat/kazhdan_lusztig.py +215 -0
- sage/combinat/key_polynomial.py +885 -0
- sage/combinat/knutson_tao_puzzles.py +2286 -0
- sage/combinat/lr_tableau.py +311 -0
- sage/combinat/matrices/all.py +24 -0
- sage/combinat/matrices/hadamard_matrix.py +3790 -0
- sage/combinat/matrices/latin.py +2912 -0
- sage/combinat/misc.py +401 -0
- sage/combinat/multiset_partition_into_sets_ordered.py +3541 -0
- sage/combinat/ncsf_qsym/all.py +21 -0
- sage/combinat/ncsf_qsym/combinatorics.py +317 -0
- sage/combinat/ncsf_qsym/generic_basis_code.py +1427 -0
- sage/combinat/ncsf_qsym/ncsf.py +5637 -0
- sage/combinat/ncsf_qsym/qsym.py +4053 -0
- sage/combinat/ncsf_qsym/tutorial.py +447 -0
- sage/combinat/ncsym/all.py +21 -0
- sage/combinat/ncsym/bases.py +855 -0
- sage/combinat/ncsym/dual.py +593 -0
- sage/combinat/ncsym/ncsym.py +2076 -0
- sage/combinat/necklace.py +551 -0
- sage/combinat/non_decreasing_parking_function.py +634 -0
- sage/combinat/nu_dyck_word.py +1474 -0
- sage/combinat/output.py +861 -0
- sage/combinat/parallelogram_polyomino.py +4326 -0
- sage/combinat/parking_functions.py +1602 -0
- sage/combinat/partition_algebra.py +1998 -0
- sage/combinat/partition_kleshchev.py +1982 -0
- sage/combinat/partition_shifting_algebras.py +584 -0
- sage/combinat/partition_tuple.py +3114 -0
- sage/combinat/path_tableaux/all.py +13 -0
- sage/combinat/path_tableaux/catalog.py +29 -0
- sage/combinat/path_tableaux/dyck_path.py +380 -0
- sage/combinat/path_tableaux/frieze.py +476 -0
- sage/combinat/path_tableaux/path_tableau.py +728 -0
- sage/combinat/path_tableaux/semistandard.py +510 -0
- sage/combinat/perfect_matching.py +779 -0
- sage/combinat/plane_partition.py +3300 -0
- sage/combinat/q_bernoulli.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/q_bernoulli.pyx +128 -0
- sage/combinat/quickref.py +81 -0
- sage/combinat/recognizable_series.py +2051 -0
- sage/combinat/regular_sequence.py +4316 -0
- sage/combinat/regular_sequence_bounded.py +543 -0
- sage/combinat/restricted_growth.py +81 -0
- sage/combinat/ribbon.py +20 -0
- sage/combinat/ribbon_shaped_tableau.py +489 -0
- sage/combinat/ribbon_tableau.py +1180 -0
- sage/combinat/rigged_configurations/all.py +46 -0
- sage/combinat/rigged_configurations/bij_abstract_class.py +548 -0
- sage/combinat/rigged_configurations/bij_infinity.py +370 -0
- sage/combinat/rigged_configurations/bij_type_A.py +163 -0
- sage/combinat/rigged_configurations/bij_type_A2_dual.py +338 -0
- sage/combinat/rigged_configurations/bij_type_A2_even.py +218 -0
- sage/combinat/rigged_configurations/bij_type_A2_odd.py +199 -0
- sage/combinat/rigged_configurations/bij_type_B.py +900 -0
- sage/combinat/rigged_configurations/bij_type_C.py +267 -0
- sage/combinat/rigged_configurations/bij_type_D.py +771 -0
- sage/combinat/rigged_configurations/bij_type_D_tri.py +392 -0
- sage/combinat/rigged_configurations/bij_type_D_twisted.py +576 -0
- sage/combinat/rigged_configurations/bij_type_E67.py +402 -0
- sage/combinat/rigged_configurations/bijection.py +143 -0
- sage/combinat/rigged_configurations/kleber_tree.py +1475 -0
- sage/combinat/rigged_configurations/kr_tableaux.py +1898 -0
- sage/combinat/rigged_configurations/rc_crystal.py +461 -0
- sage/combinat/rigged_configurations/rc_infinity.py +540 -0
- sage/combinat/rigged_configurations/rigged_configuration_element.py +2403 -0
- sage/combinat/rigged_configurations/rigged_configurations.py +1918 -0
- sage/combinat/rigged_configurations/rigged_partition.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/rigged_configurations/rigged_partition.pxd +15 -0
- sage/combinat/rigged_configurations/rigged_partition.pyx +680 -0
- sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py +499 -0
- sage/combinat/rigged_configurations/tensor_product_kr_tableaux_element.py +428 -0
- sage/combinat/rsk.py +3438 -0
- sage/combinat/schubert_polynomial.py +508 -0
- sage/combinat/set_partition.py +3318 -0
- sage/combinat/set_partition_iterator.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/set_partition_iterator.pyx +136 -0
- sage/combinat/set_partition_ordered.py +1590 -0
- sage/combinat/sf/abreu_nigro.py +346 -0
- sage/combinat/sf/all.py +52 -0
- sage/combinat/sf/character.py +576 -0
- sage/combinat/sf/classical.py +319 -0
- sage/combinat/sf/dual.py +996 -0
- sage/combinat/sf/elementary.py +549 -0
- sage/combinat/sf/hall_littlewood.py +1028 -0
- sage/combinat/sf/hecke.py +336 -0
- sage/combinat/sf/homogeneous.py +464 -0
- sage/combinat/sf/jack.py +1428 -0
- sage/combinat/sf/k_dual.py +1458 -0
- sage/combinat/sf/kfpoly.py +447 -0
- sage/combinat/sf/llt.py +789 -0
- sage/combinat/sf/macdonald.py +2019 -0
- sage/combinat/sf/monomial.py +525 -0
- sage/combinat/sf/multiplicative.py +113 -0
- sage/combinat/sf/new_kschur.py +1786 -0
- sage/combinat/sf/ns_macdonald.py +964 -0
- sage/combinat/sf/orthogonal.py +246 -0
- sage/combinat/sf/orthotriang.py +355 -0
- sage/combinat/sf/powersum.py +963 -0
- sage/combinat/sf/schur.py +880 -0
- sage/combinat/sf/sf.py +1653 -0
- sage/combinat/sf/sfa.py +7053 -0
- sage/combinat/sf/symplectic.py +253 -0
- sage/combinat/sf/witt.py +721 -0
- sage/combinat/shifted_primed_tableau.py +2735 -0
- sage/combinat/shuffle.py +830 -0
- sage/combinat/sidon_sets.py +146 -0
- sage/combinat/similarity_class_type.py +1721 -0
- sage/combinat/sine_gordon.py +618 -0
- sage/combinat/six_vertex_model.py +784 -0
- sage/combinat/skew_partition.py +2053 -0
- sage/combinat/skew_tableau.py +2989 -0
- sage/combinat/sloane_functions.py +8935 -0
- sage/combinat/specht_module.py +1403 -0
- sage/combinat/species/all.py +48 -0
- sage/combinat/species/characteristic_species.py +321 -0
- sage/combinat/species/composition_species.py +273 -0
- sage/combinat/species/cycle_species.py +284 -0
- sage/combinat/species/empty_species.py +155 -0
- sage/combinat/species/functorial_composition_species.py +148 -0
- sage/combinat/species/generating_series.py +673 -0
- sage/combinat/species/library.py +148 -0
- sage/combinat/species/linear_order_species.py +169 -0
- sage/combinat/species/misc.py +83 -0
- sage/combinat/species/partition_species.py +290 -0
- sage/combinat/species/permutation_species.py +268 -0
- sage/combinat/species/product_species.py +423 -0
- sage/combinat/species/recursive_species.py +476 -0
- sage/combinat/species/set_species.py +192 -0
- sage/combinat/species/species.py +820 -0
- sage/combinat/species/structure.py +539 -0
- sage/combinat/species/subset_species.py +243 -0
- sage/combinat/species/sum_species.py +225 -0
- sage/combinat/subword.py +564 -0
- sage/combinat/subword_complex.py +2122 -0
- sage/combinat/subword_complex_c.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/subword_complex_c.pyx +119 -0
- sage/combinat/super_tableau.py +821 -0
- sage/combinat/superpartition.py +1154 -0
- sage/combinat/symmetric_group_algebra.py +3774 -0
- sage/combinat/symmetric_group_representations.py +1830 -0
- sage/combinat/t_sequences.py +877 -0
- sage/combinat/tableau.py +9506 -0
- sage/combinat/tableau_residues.py +860 -0
- sage/combinat/tableau_tuple.py +5353 -0
- sage/combinat/tiling.py +2432 -0
- sage/combinat/triangles_FHM.py +777 -0
- sage/combinat/tutorial.py +1857 -0
- sage/combinat/vector_partition.py +337 -0
- sage/combinat/words/abstract_word.py +1722 -0
- sage/combinat/words/all.py +59 -0
- sage/combinat/words/alphabet.py +268 -0
- sage/combinat/words/finite_word.py +7201 -0
- sage/combinat/words/infinite_word.py +113 -0
- sage/combinat/words/lyndon_word.py +652 -0
- sage/combinat/words/morphic.py +351 -0
- sage/combinat/words/morphism.py +3878 -0
- sage/combinat/words/paths.py +2932 -0
- sage/combinat/words/shuffle_product.py +278 -0
- sage/combinat/words/suffix_trees.py +1873 -0
- sage/combinat/words/word.py +769 -0
- sage/combinat/words/word_char.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/words/word_char.pyx +847 -0
- sage/combinat/words/word_datatypes.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/words/word_datatypes.pxd +4 -0
- sage/combinat/words/word_datatypes.pyx +1067 -0
- sage/combinat/words/word_generators.py +2026 -0
- sage/combinat/words/word_infinite_datatypes.py +1218 -0
- sage/combinat/words/word_options.py +99 -0
- sage/combinat/words/words.py +2396 -0
- sage/data_structures/all__sagemath_combinat.py +1 -0
- sage/databases/all__sagemath_combinat.py +13 -0
- sage/databases/findstat.py +4897 -0
- sage/databases/oeis.py +2058 -0
- sage/databases/sloane.py +393 -0
- sage/dynamics/all__sagemath_combinat.py +14 -0
- sage/dynamics/cellular_automata/all.py +7 -0
- sage/dynamics/cellular_automata/catalog.py +34 -0
- sage/dynamics/cellular_automata/elementary.py +612 -0
- sage/dynamics/cellular_automata/glca.py +477 -0
- sage/dynamics/cellular_automata/solitons.py +1463 -0
- sage/dynamics/finite_dynamical_system.py +1249 -0
- sage/dynamics/finite_dynamical_system_catalog.py +382 -0
- sage/games/all.py +7 -0
- sage/games/hexad.py +704 -0
- sage/games/quantumino.py +591 -0
- sage/games/sudoku.py +889 -0
- sage/games/sudoku_backtrack.cpython-314-x86_64-linux-musl.so +0 -0
- sage/games/sudoku_backtrack.pyx +189 -0
- sage/groups/all__sagemath_combinat.py +1 -0
- sage/groups/indexed_free_group.py +489 -0
- sage/libs/all__sagemath_combinat.py +6 -0
- sage/libs/lrcalc/__init__.py +1 -0
- sage/libs/lrcalc/lrcalc.py +525 -0
- sage/libs/symmetrica/__init__.py +7 -0
- sage/libs/symmetrica/all.py +101 -0
- sage/libs/symmetrica/kostka.pxi +168 -0
- sage/libs/symmetrica/part.pxi +193 -0
- sage/libs/symmetrica/plet.pxi +42 -0
- sage/libs/symmetrica/sab.pxi +196 -0
- sage/libs/symmetrica/sb.pxi +332 -0
- sage/libs/symmetrica/sc.pxi +192 -0
- sage/libs/symmetrica/schur.pxi +956 -0
- sage/libs/symmetrica/symmetrica.cpython-314-x86_64-linux-musl.so +0 -0
- sage/libs/symmetrica/symmetrica.pxi +1172 -0
- sage/libs/symmetrica/symmetrica.pyx +39 -0
- sage/monoids/all.py +13 -0
- sage/monoids/automatic_semigroup.py +1054 -0
- sage/monoids/free_abelian_monoid.py +315 -0
- sage/monoids/free_abelian_monoid_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/monoids/free_abelian_monoid_element.pxd +16 -0
- sage/monoids/free_abelian_monoid_element.pyx +397 -0
- sage/monoids/free_monoid.py +335 -0
- sage/monoids/free_monoid_element.py +431 -0
- sage/monoids/hecke_monoid.py +65 -0
- sage/monoids/string_monoid.py +817 -0
- sage/monoids/string_monoid_element.py +547 -0
- sage/monoids/string_ops.py +143 -0
- sage/monoids/trace_monoid.py +972 -0
- sage/rings/all__sagemath_combinat.py +2 -0
- sage/sat/all.py +4 -0
- sage/sat/boolean_polynomials.py +405 -0
- sage/sat/converters/__init__.py +6 -0
- sage/sat/converters/anf2cnf.py +14 -0
- sage/sat/converters/polybori.py +611 -0
- sage/sat/solvers/__init__.py +5 -0
- sage/sat/solvers/cryptominisat.py +287 -0
- sage/sat/solvers/dimacs.py +783 -0
- sage/sat/solvers/picosat.py +228 -0
- sage/sat/solvers/sat_lp.py +156 -0
- sage/sat/solvers/satsolver.cpython-314-x86_64-linux-musl.so +0 -0
- sage/sat/solvers/satsolver.pxd +3 -0
- sage/sat/solvers/satsolver.pyx +405 -0
|
@@ -0,0 +1,611 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-combinat
|
|
2
|
+
# sage.doctest: needs sage.rings.polynomial.pbori
|
|
3
|
+
"""
|
|
4
|
+
An ANF to CNF Converter using a Dense/Sparse Strategy
|
|
5
|
+
|
|
6
|
+
This converter is based on two converters. The first one, by Martin Albrecht, was based on [CB2007]_,
|
|
7
|
+
this is the basis of the "dense" part of the converter. It was later improved by Mate Soos. The
|
|
8
|
+
second one, by Michael Brickenstein, uses a reduced truth table based approach and forms the
|
|
9
|
+
"sparse" part of the converter.
|
|
10
|
+
|
|
11
|
+
AUTHORS:
|
|
12
|
+
|
|
13
|
+
- Martin Albrecht - (2008-09) initial version of 'anf2cnf.py'
|
|
14
|
+
- Michael Brickenstein - (2009) 'cnf.py' for PolyBoRi
|
|
15
|
+
- Mate Soos - (2010) improved version of 'anf2cnf.py'
|
|
16
|
+
- Martin Albrecht - (2012) unified and added to Sage
|
|
17
|
+
|
|
18
|
+
Classes and Methods
|
|
19
|
+
-------------------
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
# ###########################################################################
|
|
23
|
+
# Copyright (C) 2008-2009 Martin Albrecht <martinralbrecht@googlemail.com>
|
|
24
|
+
# Copyright (C) 2009 Michael Brickenstein <brickenstein@mfo.de>
|
|
25
|
+
# Copyright (C) 2010 Mate Soos
|
|
26
|
+
# Copyright (C) 2012 Martin Albrecht <martinralbrecht@googlemail.com>
|
|
27
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
28
|
+
# The full text of the GPL is available at:
|
|
29
|
+
# https://www.gnu.org/licenses/
|
|
30
|
+
# ###########################################################################
|
|
31
|
+
|
|
32
|
+
from random import Random
|
|
33
|
+
|
|
34
|
+
from sage.rings.integer_ring import ZZ
|
|
35
|
+
from sage.functions.other import ceil
|
|
36
|
+
from sage.misc.cachefunc import cached_method, cached_function
|
|
37
|
+
from sage.misc.lazy_import import lazy_import
|
|
38
|
+
from sage.combinat.permutation import Permutations
|
|
39
|
+
from sage.sat.converters import ANF2CNFConverter
|
|
40
|
+
|
|
41
|
+
lazy_import('sage.rings.polynomial.pbori.pbori', 'if_then_else', as_='ite')
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class CNFEncoder(ANF2CNFConverter):
|
|
45
|
+
"""
|
|
46
|
+
ANF to CNF Converter using a Dense/Sparse Strategy. This converter distinguishes two classes of
|
|
47
|
+
polynomials.
|
|
48
|
+
|
|
49
|
+
1. Sparse polynomials are those with at most ``max_vars_sparse`` variables. Those are converted
|
|
50
|
+
using reduced truth-tables based on PolyBoRi's internal representation.
|
|
51
|
+
|
|
52
|
+
2. Polynomials with more variables are converted by introducing new variables for monomials and
|
|
53
|
+
by converting these linearised polynomials.
|
|
54
|
+
|
|
55
|
+
Linearised polynomials are converted either by splitting XOR chains -- into chunks of length
|
|
56
|
+
``cutting_number`` -- or by constructing XOR clauses if the underlying solver supports it. This
|
|
57
|
+
behaviour is disabled by passing ``use_xor_clauses=False``.
|
|
58
|
+
|
|
59
|
+
.. automethod:: __init__
|
|
60
|
+
.. automethod:: __call__
|
|
61
|
+
"""
|
|
62
|
+
def __init__(self, solver, ring, max_vars_sparse=6, use_xor_clauses=None, cutting_number=6, random_seed=16):
|
|
63
|
+
"""
|
|
64
|
+
Construct ANF to CNF converter over ``ring`` passing clauses to ``solver``.
|
|
65
|
+
|
|
66
|
+
INPUT:
|
|
67
|
+
|
|
68
|
+
- ``solver`` -- a SAT-solver instance
|
|
69
|
+
|
|
70
|
+
- ``ring`` -- a :class:`sage.rings.polynomial.pbori.BooleanPolynomialRing`
|
|
71
|
+
|
|
72
|
+
- ``max_vars_sparse`` -- maximum number of variables for direct conversion
|
|
73
|
+
|
|
74
|
+
- ``use_xor_clauses`` -- use XOR clauses; if ``None`` use if
|
|
75
|
+
``solver`` supports it. (default: ``None``)
|
|
76
|
+
|
|
77
|
+
- ``cutting_number`` -- maximum length of XOR chains after
|
|
78
|
+
splitting if XOR clauses are not supported (default: 6)
|
|
79
|
+
|
|
80
|
+
- ``random_seed`` -- the direct conversion method uses
|
|
81
|
+
randomness, this sets the seed (default: 16)
|
|
82
|
+
|
|
83
|
+
EXAMPLES:
|
|
84
|
+
|
|
85
|
+
We compare the sparse and the dense strategies, sparse first::
|
|
86
|
+
|
|
87
|
+
sage: B.<a,b,c> = BooleanPolynomialRing()
|
|
88
|
+
sage: from sage.sat.converters.polybori import CNFEncoder
|
|
89
|
+
sage: from sage.sat.solvers.dimacs import DIMACS
|
|
90
|
+
sage: fn = tmp_filename()
|
|
91
|
+
sage: solver = DIMACS(filename=fn)
|
|
92
|
+
sage: e = CNFEncoder(solver, B)
|
|
93
|
+
sage: e.clauses_sparse(a*b + a + 1)
|
|
94
|
+
sage: _ = solver.write()
|
|
95
|
+
sage: print(open(fn).read())
|
|
96
|
+
p cnf 3 2
|
|
97
|
+
-2 0
|
|
98
|
+
1 0
|
|
99
|
+
sage: e.phi
|
|
100
|
+
[None, a, b, c]
|
|
101
|
+
|
|
102
|
+
Now, we convert using the dense strategy::
|
|
103
|
+
|
|
104
|
+
sage: B.<a,b,c> = BooleanPolynomialRing()
|
|
105
|
+
sage: from sage.sat.converters.polybori import CNFEncoder
|
|
106
|
+
sage: from sage.sat.solvers.dimacs import DIMACS
|
|
107
|
+
sage: fn = tmp_filename()
|
|
108
|
+
sage: solver = DIMACS(filename=fn)
|
|
109
|
+
sage: e = CNFEncoder(solver, B)
|
|
110
|
+
sage: e.clauses_dense(a*b + a + 1)
|
|
111
|
+
sage: _ = solver.write()
|
|
112
|
+
sage: print(open(fn).read())
|
|
113
|
+
p cnf 4 5
|
|
114
|
+
1 -4 0
|
|
115
|
+
2 -4 0
|
|
116
|
+
4 -1 -2 0
|
|
117
|
+
-4 -1 0
|
|
118
|
+
4 1 0
|
|
119
|
+
sage: e.phi
|
|
120
|
+
[None, a, b, c, a*b]
|
|
121
|
+
|
|
122
|
+
.. NOTE::
|
|
123
|
+
|
|
124
|
+
This constructor generates SAT variables for each Boolean polynomial variable.
|
|
125
|
+
"""
|
|
126
|
+
self.random_generator = Random(random_seed)
|
|
127
|
+
self.one_set = ring.one().set()
|
|
128
|
+
self.empty_set = ring.zero().set()
|
|
129
|
+
|
|
130
|
+
self.solver = solver
|
|
131
|
+
self.max_vars_sparse = max_vars_sparse
|
|
132
|
+
self.cutting_number = cutting_number
|
|
133
|
+
|
|
134
|
+
if use_xor_clauses is None:
|
|
135
|
+
use_xor_clauses = hasattr(solver, "add_xor_clause")
|
|
136
|
+
self.use_xor_clauses = use_xor_clauses
|
|
137
|
+
|
|
138
|
+
self.ring = ring
|
|
139
|
+
|
|
140
|
+
# If you change this, make sure we are calling m.index()
|
|
141
|
+
# below, as this relies on phi being sorted like this.
|
|
142
|
+
self._phi = [None]
|
|
143
|
+
for x in sorted([x.lm() for x in self.ring.gens()], key=lambda x: x.index()):
|
|
144
|
+
self.var(x)
|
|
145
|
+
|
|
146
|
+
def var(self, m=None, decision=None):
|
|
147
|
+
"""
|
|
148
|
+
Return a *new* variable.
|
|
149
|
+
|
|
150
|
+
This is a thin wrapper around the SAT-solvers function where
|
|
151
|
+
we keep track of which SAT variable corresponds to which
|
|
152
|
+
monomial.
|
|
153
|
+
|
|
154
|
+
INPUT:
|
|
155
|
+
|
|
156
|
+
- ``m`` -- something the new variables maps to, usually a monomial
|
|
157
|
+
- ``decision`` -- is this variable a decision variable?
|
|
158
|
+
|
|
159
|
+
EXAMPLES::
|
|
160
|
+
|
|
161
|
+
sage: from sage.sat.converters.polybori import CNFEncoder
|
|
162
|
+
sage: from sage.sat.solvers.dimacs import DIMACS
|
|
163
|
+
sage: B.<a,b,c> = BooleanPolynomialRing()
|
|
164
|
+
sage: ce = CNFEncoder(DIMACS(), B)
|
|
165
|
+
sage: ce.var()
|
|
166
|
+
4
|
|
167
|
+
"""
|
|
168
|
+
self._phi.append(m)
|
|
169
|
+
return self.solver.var(decision=decision)
|
|
170
|
+
|
|
171
|
+
@property
|
|
172
|
+
def phi(self):
|
|
173
|
+
"""
|
|
174
|
+
Map SAT variables to polynomial variables.
|
|
175
|
+
|
|
176
|
+
EXAMPLES::
|
|
177
|
+
|
|
178
|
+
sage: from sage.sat.converters.polybori import CNFEncoder
|
|
179
|
+
sage: from sage.sat.solvers.dimacs import DIMACS
|
|
180
|
+
sage: B.<a,b,c> = BooleanPolynomialRing()
|
|
181
|
+
sage: ce = CNFEncoder(DIMACS(), B)
|
|
182
|
+
sage: ce.var()
|
|
183
|
+
4
|
|
184
|
+
sage: ce.phi
|
|
185
|
+
[None, a, b, c, None]
|
|
186
|
+
"""
|
|
187
|
+
return list(self._phi)
|
|
188
|
+
|
|
189
|
+
##################################################
|
|
190
|
+
# Encoding based on polynomial roots
|
|
191
|
+
##################################################
|
|
192
|
+
|
|
193
|
+
def zero_blocks(self, f):
|
|
194
|
+
"""
|
|
195
|
+
Divide the zero set of ``f`` into blocks.
|
|
196
|
+
|
|
197
|
+
EXAMPLES::
|
|
198
|
+
|
|
199
|
+
sage: B.<a,b,c> = BooleanPolynomialRing()
|
|
200
|
+
sage: from sage.sat.converters.polybori import CNFEncoder
|
|
201
|
+
sage: from sage.sat.solvers.dimacs import DIMACS
|
|
202
|
+
sage: e = CNFEncoder(DIMACS(), B)
|
|
203
|
+
sage: sorted(sorted(d.items()) for d in e.zero_blocks(a*b*c))
|
|
204
|
+
[[(c, 0)], [(b, 0)], [(a, 0)]]
|
|
205
|
+
|
|
206
|
+
.. NOTE::
|
|
207
|
+
|
|
208
|
+
This function is randomised.
|
|
209
|
+
"""
|
|
210
|
+
variables = f.vars_as_monomial()
|
|
211
|
+
|
|
212
|
+
space = variables.divisors()
|
|
213
|
+
variables = list(variables.variables())
|
|
214
|
+
zeros = f.zeros_in(space)
|
|
215
|
+
rest = zeros
|
|
216
|
+
res = list()
|
|
217
|
+
|
|
218
|
+
def choose(s):
|
|
219
|
+
indices = []
|
|
220
|
+
assert not s.empty()
|
|
221
|
+
nav = s.navigation()
|
|
222
|
+
while not nav.constant():
|
|
223
|
+
e = nav.else_branch()
|
|
224
|
+
t = nav.then_branch()
|
|
225
|
+
if e.constant() and not e.terminal_one():
|
|
226
|
+
indices.append(nav.value())
|
|
227
|
+
nav = t
|
|
228
|
+
else:
|
|
229
|
+
if self.random_generator.randint(0, 1):
|
|
230
|
+
indices.append(nav.value())
|
|
231
|
+
nav = t
|
|
232
|
+
|
|
233
|
+
else:
|
|
234
|
+
nav = e
|
|
235
|
+
assert nav.terminal_one()
|
|
236
|
+
res = self.one_set
|
|
237
|
+
for i in reversed(indices):
|
|
238
|
+
res = ite(i, res, self.empty_set)
|
|
239
|
+
return next(iter(res))
|
|
240
|
+
|
|
241
|
+
while not rest.empty():
|
|
242
|
+
l = choose(rest)
|
|
243
|
+
l_variables = set(l.variables())
|
|
244
|
+
block_dict = {v: (1 if v in l_variables else 0) for v in variables}
|
|
245
|
+
l = l.set()
|
|
246
|
+
self.random_generator.shuffle(variables)
|
|
247
|
+
for v in variables:
|
|
248
|
+
candidate = l.change(v.index())
|
|
249
|
+
if candidate.diff(zeros).empty():
|
|
250
|
+
l = l.union(candidate)
|
|
251
|
+
del block_dict[v]
|
|
252
|
+
rest = rest.diff(l)
|
|
253
|
+
res.append(block_dict)
|
|
254
|
+
return res
|
|
255
|
+
|
|
256
|
+
def clauses_sparse(self, f):
|
|
257
|
+
"""
|
|
258
|
+
Convert ``f`` using the sparse strategy.
|
|
259
|
+
|
|
260
|
+
INPUT:
|
|
261
|
+
|
|
262
|
+
- ``f`` -- a :class:`sage.rings.polynomial.pbori.BooleanPolynomial`
|
|
263
|
+
|
|
264
|
+
EXAMPLES::
|
|
265
|
+
|
|
266
|
+
sage: B.<a,b,c> = BooleanPolynomialRing()
|
|
267
|
+
sage: from sage.sat.converters.polybori import CNFEncoder
|
|
268
|
+
sage: from sage.sat.solvers.dimacs import DIMACS
|
|
269
|
+
sage: fn = tmp_filename()
|
|
270
|
+
sage: solver = DIMACS(filename=fn)
|
|
271
|
+
sage: e = CNFEncoder(solver, B)
|
|
272
|
+
sage: e.clauses_sparse(a*b + a + 1)
|
|
273
|
+
sage: _ = solver.write()
|
|
274
|
+
sage: print(open(fn).read())
|
|
275
|
+
p cnf 3 2
|
|
276
|
+
-2 0
|
|
277
|
+
1 0
|
|
278
|
+
sage: e.phi
|
|
279
|
+
[None, a, b, c]
|
|
280
|
+
"""
|
|
281
|
+
# we form an expression for a var configuration *not* lying in
|
|
282
|
+
# the block it is evaluated to 0 by f, iff it is not lying in
|
|
283
|
+
# any zero block of f+1
|
|
284
|
+
|
|
285
|
+
blocks = self.zero_blocks(f + 1)
|
|
286
|
+
C = [{variable: 1 - value for variable, value in b.items()}
|
|
287
|
+
for b in blocks]
|
|
288
|
+
|
|
289
|
+
def to_dimacs_index(v):
|
|
290
|
+
return v.index() + 1
|
|
291
|
+
|
|
292
|
+
def clause(c):
|
|
293
|
+
return [to_dimacs_index(variable)
|
|
294
|
+
if value == 1 else -to_dimacs_index(variable)
|
|
295
|
+
for variable, value in c.items()]
|
|
296
|
+
|
|
297
|
+
data = (clause(c) for c in C)
|
|
298
|
+
for d in sorted(data):
|
|
299
|
+
self.solver.add_clause(d)
|
|
300
|
+
|
|
301
|
+
###################################################
|
|
302
|
+
# Indirect conversion, may add new variables
|
|
303
|
+
###################################################
|
|
304
|
+
|
|
305
|
+
def clauses_dense(self, f):
|
|
306
|
+
"""
|
|
307
|
+
Convert ``f`` using the dense strategy.
|
|
308
|
+
|
|
309
|
+
INPUT:
|
|
310
|
+
|
|
311
|
+
- ``f`` -- a :class:`sage.rings.polynomial.pbori.BooleanPolynomial`
|
|
312
|
+
|
|
313
|
+
EXAMPLES::
|
|
314
|
+
|
|
315
|
+
sage: B.<a,b,c> = BooleanPolynomialRing()
|
|
316
|
+
sage: from sage.sat.converters.polybori import CNFEncoder
|
|
317
|
+
sage: from sage.sat.solvers.dimacs import DIMACS
|
|
318
|
+
sage: fn = tmp_filename()
|
|
319
|
+
sage: solver = DIMACS(filename=fn)
|
|
320
|
+
sage: e = CNFEncoder(solver, B)
|
|
321
|
+
sage: e.clauses_dense(a*b + a + 1)
|
|
322
|
+
sage: _ = solver.write()
|
|
323
|
+
sage: print(open(fn).read())
|
|
324
|
+
p cnf 4 5
|
|
325
|
+
1 -4 0
|
|
326
|
+
2 -4 0
|
|
327
|
+
4 -1 -2 0
|
|
328
|
+
-4 -1 0
|
|
329
|
+
4 1 0
|
|
330
|
+
sage: e.phi
|
|
331
|
+
[None, a, b, c, a*b]
|
|
332
|
+
"""
|
|
333
|
+
equal_zero = not bool(f.constant_coefficient())
|
|
334
|
+
|
|
335
|
+
f = (f - f.constant_coefficient())
|
|
336
|
+
f = [self.monomial(m) for m in f]
|
|
337
|
+
|
|
338
|
+
if self.use_xor_clauses:
|
|
339
|
+
self.solver.add_xor_clause(f, rhs=not equal_zero)
|
|
340
|
+
elif len(f) > self.cutting_number:
|
|
341
|
+
for fpart, this_equal_zero in self.split_xor(f, equal_zero):
|
|
342
|
+
ll = len(fpart)
|
|
343
|
+
for p in self.permutations(ll, this_equal_zero):
|
|
344
|
+
self.solver.add_clause([p[i] * fpart[i] for i in range(ll)])
|
|
345
|
+
else:
|
|
346
|
+
ll = len(f)
|
|
347
|
+
for p in self.permutations(ll, equal_zero):
|
|
348
|
+
self.solver.add_clause([p[i] * f[i] for i in range(ll)])
|
|
349
|
+
|
|
350
|
+
@cached_method
|
|
351
|
+
def monomial(self, m):
|
|
352
|
+
"""
|
|
353
|
+
Return SAT variable for ``m``.
|
|
354
|
+
|
|
355
|
+
INPUT:
|
|
356
|
+
|
|
357
|
+
- ``m`` -- a monomial
|
|
358
|
+
|
|
359
|
+
OUTPUT: an index for a SAT variable corresponding to ``m``
|
|
360
|
+
|
|
361
|
+
EXAMPLES::
|
|
362
|
+
|
|
363
|
+
sage: B.<a,b,c> = BooleanPolynomialRing()
|
|
364
|
+
sage: from sage.sat.converters.polybori import CNFEncoder
|
|
365
|
+
sage: from sage.sat.solvers.dimacs import DIMACS
|
|
366
|
+
sage: fn = tmp_filename()
|
|
367
|
+
sage: solver = DIMACS(filename=fn)
|
|
368
|
+
sage: e = CNFEncoder(solver, B)
|
|
369
|
+
sage: e.clauses_dense(a*b + a + 1)
|
|
370
|
+
sage: e.phi
|
|
371
|
+
[None, a, b, c, a*b]
|
|
372
|
+
|
|
373
|
+
If monomial is called on a new monomial, a new variable is created::
|
|
374
|
+
|
|
375
|
+
sage: e.monomial(a*b*c)
|
|
376
|
+
5
|
|
377
|
+
sage: e.phi
|
|
378
|
+
[None, a, b, c, a*b, a*b*c]
|
|
379
|
+
|
|
380
|
+
If monomial is called on a monomial that was queried before,
|
|
381
|
+
the index of the old variable is returned and no new variable
|
|
382
|
+
is created::
|
|
383
|
+
|
|
384
|
+
sage: e.monomial(a*b)
|
|
385
|
+
4
|
|
386
|
+
sage: e.phi
|
|
387
|
+
[None, a, b, c, a*b, a*b*c]
|
|
388
|
+
|
|
389
|
+
.. NOTE::
|
|
390
|
+
|
|
391
|
+
For correctness, this function is cached.
|
|
392
|
+
"""
|
|
393
|
+
if m.deg() == 1:
|
|
394
|
+
return m.index() + 1
|
|
395
|
+
|
|
396
|
+
# we need to encode the relationship between the monomial
|
|
397
|
+
# and its variables
|
|
398
|
+
variables = [self.monomial(v) for v in m.variables()]
|
|
399
|
+
monomial = self.var(m)
|
|
400
|
+
|
|
401
|
+
# (a | -w) & (b | -w) & (w | -a | -b) <=> w == a*b
|
|
402
|
+
for v in variables:
|
|
403
|
+
self.solver.add_clause((v, -monomial))
|
|
404
|
+
self.solver.add_clause(tuple([monomial] + [-v for v in variables]))
|
|
405
|
+
|
|
406
|
+
return monomial
|
|
407
|
+
|
|
408
|
+
@cached_function
|
|
409
|
+
def permutations(length, equal_zero):
|
|
410
|
+
"""
|
|
411
|
+
Return permutations of length ``length`` which are equal to
|
|
412
|
+
zero if ``equal_zero`` and equal to one otherwise.
|
|
413
|
+
|
|
414
|
+
A variable is false if the integer in its position is smaller
|
|
415
|
+
than zero and true otherwise.
|
|
416
|
+
|
|
417
|
+
INPUT:
|
|
418
|
+
|
|
419
|
+
- ``length`` -- the number of variables
|
|
420
|
+
- ``equal_zero`` -- should the sum be equal to zero?
|
|
421
|
+
|
|
422
|
+
EXAMPLES::
|
|
423
|
+
|
|
424
|
+
sage: from sage.sat.converters.polybori import CNFEncoder
|
|
425
|
+
sage: from sage.sat.solvers.dimacs import DIMACS
|
|
426
|
+
sage: B.<a,b,c> = BooleanPolynomialRing()
|
|
427
|
+
sage: ce = CNFEncoder(DIMACS(), B)
|
|
428
|
+
sage: ce.permutations(3, True)
|
|
429
|
+
[[-1, -1, -1], [1, 1, -1], [1, -1, 1], [-1, 1, 1]]
|
|
430
|
+
|
|
431
|
+
sage: ce.permutations(3, False)
|
|
432
|
+
[[1, -1, -1], [-1, 1, -1], [-1, -1, 1], [1, 1, 1]]
|
|
433
|
+
"""
|
|
434
|
+
E = []
|
|
435
|
+
for num_negated in range(length + 1):
|
|
436
|
+
if ((num_negated % 2) ^ ((length + 1) % 2)) == equal_zero:
|
|
437
|
+
continue
|
|
438
|
+
start = [1 for _ in range(num_negated)]
|
|
439
|
+
start.extend(-1 for _ in range(length - num_negated))
|
|
440
|
+
E.extend(Permutations(start))
|
|
441
|
+
return E
|
|
442
|
+
|
|
443
|
+
def split_xor(self, monomial_list, equal_zero):
|
|
444
|
+
"""
|
|
445
|
+
Split XOR chains into subchains.
|
|
446
|
+
|
|
447
|
+
INPUT:
|
|
448
|
+
|
|
449
|
+
- ``monomial_list`` -- list of monomials
|
|
450
|
+
- ``equal_zero`` -- is the constant coefficient zero?
|
|
451
|
+
|
|
452
|
+
EXAMPLES::
|
|
453
|
+
|
|
454
|
+
sage: from sage.sat.converters.polybori import CNFEncoder
|
|
455
|
+
sage: from sage.sat.solvers.dimacs import DIMACS
|
|
456
|
+
sage: B.<a,b,c,d,e,f> = BooleanPolynomialRing()
|
|
457
|
+
sage: ce = CNFEncoder(DIMACS(), B, cutting_number=3)
|
|
458
|
+
sage: ce.split_xor([1,2,3,4,5,6], False)
|
|
459
|
+
[[[1, 7], False], [[7, 2, 8], True], [[8, 3, 9], True], [[9, 4, 10], True], [[10, 5, 11], True], [[11, 6], True]]
|
|
460
|
+
|
|
461
|
+
sage: ce = CNFEncoder(DIMACS(), B, cutting_number=4)
|
|
462
|
+
sage: ce.split_xor([1,2,3,4,5,6], False)
|
|
463
|
+
[[[1, 2, 7], False], [[7, 3, 4, 8], True], [[8, 5, 6], True]]
|
|
464
|
+
|
|
465
|
+
sage: ce = CNFEncoder(DIMACS(), B, cutting_number=5)
|
|
466
|
+
sage: ce.split_xor([1,2,3,4,5,6], False)
|
|
467
|
+
[[[1, 2, 3, 7], False], [[7, 4, 5, 6], True]]
|
|
468
|
+
"""
|
|
469
|
+
c = self.cutting_number
|
|
470
|
+
|
|
471
|
+
nm = len(monomial_list)
|
|
472
|
+
step = ceil((c-2)/ZZ(nm) * nm)
|
|
473
|
+
M = []
|
|
474
|
+
|
|
475
|
+
new_variables = []
|
|
476
|
+
for j in range(0, nm, step):
|
|
477
|
+
m = new_variables + monomial_list[j:j+step]
|
|
478
|
+
if (j + step) < nm:
|
|
479
|
+
new_variables = [self.var(None)]
|
|
480
|
+
m += new_variables
|
|
481
|
+
M.append([m, equal_zero])
|
|
482
|
+
equal_zero = True
|
|
483
|
+
return M
|
|
484
|
+
|
|
485
|
+
###################################################
|
|
486
|
+
# Highlevel Functions
|
|
487
|
+
###################################################
|
|
488
|
+
|
|
489
|
+
def clauses(self, f):
|
|
490
|
+
"""
|
|
491
|
+
Convert ``f`` using the sparse strategy if ``f.nvariables()`` is
|
|
492
|
+
at most ``max_vars_sparse`` and the dense strategy otherwise.
|
|
493
|
+
|
|
494
|
+
INPUT:
|
|
495
|
+
|
|
496
|
+
- ``f`` -- a :class:`sage.rings.polynomial.pbori.BooleanPolynomial`
|
|
497
|
+
|
|
498
|
+
EXAMPLES::
|
|
499
|
+
|
|
500
|
+
sage: B.<a,b,c> = BooleanPolynomialRing()
|
|
501
|
+
sage: from sage.sat.converters.polybori import CNFEncoder
|
|
502
|
+
sage: from sage.sat.solvers.dimacs import DIMACS
|
|
503
|
+
sage: fn = tmp_filename()
|
|
504
|
+
sage: solver = DIMACS(filename=fn)
|
|
505
|
+
sage: e = CNFEncoder(solver, B, max_vars_sparse=2)
|
|
506
|
+
sage: e.clauses(a*b + a + 1)
|
|
507
|
+
sage: _ = solver.write()
|
|
508
|
+
sage: print(open(fn).read())
|
|
509
|
+
p cnf 3 2
|
|
510
|
+
-2 0
|
|
511
|
+
1 0
|
|
512
|
+
sage: e.phi
|
|
513
|
+
[None, a, b, c]
|
|
514
|
+
|
|
515
|
+
sage: B.<a,b,c> = BooleanPolynomialRing()
|
|
516
|
+
sage: from sage.sat.converters.polybori import CNFEncoder
|
|
517
|
+
sage: from sage.sat.solvers.dimacs import DIMACS
|
|
518
|
+
sage: fn = tmp_filename()
|
|
519
|
+
sage: solver = DIMACS(filename=fn)
|
|
520
|
+
sage: e = CNFEncoder(solver, B, max_vars_sparse=2)
|
|
521
|
+
sage: e.clauses(a*b + a + c)
|
|
522
|
+
sage: _ = solver.write()
|
|
523
|
+
sage: print(open(fn).read())
|
|
524
|
+
p cnf 4 7
|
|
525
|
+
1 -4 0
|
|
526
|
+
2 -4 0
|
|
527
|
+
4 -1 -2 0
|
|
528
|
+
-4 -1 -3 0
|
|
529
|
+
4 1 -3 0
|
|
530
|
+
4 -1 3 0
|
|
531
|
+
-4 1 3 0
|
|
532
|
+
|
|
533
|
+
sage: e.phi
|
|
534
|
+
[None, a, b, c, a*b]
|
|
535
|
+
"""
|
|
536
|
+
if f.nvariables() <= self.max_vars_sparse:
|
|
537
|
+
self.clauses_sparse(f)
|
|
538
|
+
else:
|
|
539
|
+
self.clauses_dense(f)
|
|
540
|
+
|
|
541
|
+
def __call__(self, F):
|
|
542
|
+
"""
|
|
543
|
+
Encode the boolean polynomials in ``F`` .
|
|
544
|
+
|
|
545
|
+
INPUT:
|
|
546
|
+
|
|
547
|
+
- ``F`` -- an iterable of :class:`sage.rings.polynomial.pbori.BooleanPolynomial`
|
|
548
|
+
|
|
549
|
+
OUTPUT: an inverse map int -> variable
|
|
550
|
+
|
|
551
|
+
EXAMPLES::
|
|
552
|
+
|
|
553
|
+
sage: B.<a,b,c> = BooleanPolynomialRing()
|
|
554
|
+
sage: from sage.sat.converters.polybori import CNFEncoder
|
|
555
|
+
sage: from sage.sat.solvers.dimacs import DIMACS
|
|
556
|
+
sage: fn = tmp_filename()
|
|
557
|
+
sage: solver = DIMACS(filename=fn)
|
|
558
|
+
sage: e = CNFEncoder(solver, B, max_vars_sparse=2)
|
|
559
|
+
sage: e([a*b + a + 1, a*b+ a + c])
|
|
560
|
+
[None, a, b, c, a*b]
|
|
561
|
+
sage: _ = solver.write()
|
|
562
|
+
sage: print(open(fn).read())
|
|
563
|
+
p cnf 4 9
|
|
564
|
+
-2 0
|
|
565
|
+
1 0
|
|
566
|
+
1 -4 0
|
|
567
|
+
2 -4 0
|
|
568
|
+
4 -1 -2 0
|
|
569
|
+
-4 -1 -3 0
|
|
570
|
+
4 1 -3 0
|
|
571
|
+
4 -1 3 0
|
|
572
|
+
-4 1 3 0
|
|
573
|
+
|
|
574
|
+
sage: e.phi
|
|
575
|
+
[None, a, b, c, a*b]
|
|
576
|
+
"""
|
|
577
|
+
for f in F:
|
|
578
|
+
self.clauses(f)
|
|
579
|
+
return self.phi
|
|
580
|
+
|
|
581
|
+
####################################################
|
|
582
|
+
# Highlevel Functions
|
|
583
|
+
###################################################
|
|
584
|
+
|
|
585
|
+
def to_polynomial(self, c):
|
|
586
|
+
"""
|
|
587
|
+
Convert clause to :class:`sage.rings.polynomial.pbori.BooleanPolynomial`.
|
|
588
|
+
|
|
589
|
+
INPUT:
|
|
590
|
+
|
|
591
|
+
- ``c`` -- a clause
|
|
592
|
+
|
|
593
|
+
EXAMPLES::
|
|
594
|
+
|
|
595
|
+
sage: B.<a,b,c> = BooleanPolynomialRing()
|
|
596
|
+
sage: from sage.sat.converters.polybori import CNFEncoder
|
|
597
|
+
sage: from sage.sat.solvers.dimacs import DIMACS
|
|
598
|
+
sage: fn = tmp_filename()
|
|
599
|
+
sage: solver = DIMACS(filename=fn)
|
|
600
|
+
sage: e = CNFEncoder(solver, B, max_vars_sparse=2)
|
|
601
|
+
sage: _ = e([a*b + a + 1, a*b+ a + c])
|
|
602
|
+
sage: e.to_polynomial( (1,-2,3) )
|
|
603
|
+
a*b*c + a*b + b*c + b
|
|
604
|
+
"""
|
|
605
|
+
phi = self.phi
|
|
606
|
+
product = self.ring.one()
|
|
607
|
+
for v in c:
|
|
608
|
+
if phi[abs(v)] is None:
|
|
609
|
+
raise ValueError("clause contains an XOR glueing variable")
|
|
610
|
+
product *= phi[abs(v)] + int(v > 0)
|
|
611
|
+
return product
|