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,1698 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-combinat
|
|
2
|
+
# sage.doctest: needs sage.combinat sage.modules
|
|
3
|
+
"""
|
|
4
|
+
Free algebras
|
|
5
|
+
|
|
6
|
+
AUTHORS:
|
|
7
|
+
|
|
8
|
+
- David Kohel (2005-09)
|
|
9
|
+
|
|
10
|
+
- William Stein (2006-11-01): add all doctests; implemented many
|
|
11
|
+
things.
|
|
12
|
+
|
|
13
|
+
- Simon King (2011-04): Put free algebras into the category framework.
|
|
14
|
+
Reimplement free algebra constructor, using a
|
|
15
|
+
:class:`~sage.structure.factory.UniqueFactory` for handling
|
|
16
|
+
different implementations of free algebras. Allow degree weights
|
|
17
|
+
for free algebras in letterplace implementation.
|
|
18
|
+
|
|
19
|
+
EXAMPLES::
|
|
20
|
+
|
|
21
|
+
sage: F = FreeAlgebra(ZZ, 3, 'x,y,z')
|
|
22
|
+
sage: F.base_ring()
|
|
23
|
+
Integer Ring
|
|
24
|
+
sage: G = FreeAlgebra(F, 2, 'm,n'); G
|
|
25
|
+
Free Algebra on 2 generators (m, n) over
|
|
26
|
+
Free Algebra on 3 generators (x, y, z) over Integer Ring
|
|
27
|
+
sage: G.base_ring()
|
|
28
|
+
Free Algebra on 3 generators (x, y, z) over Integer Ring
|
|
29
|
+
|
|
30
|
+
The above free algebra is based on a generic implementation. By
|
|
31
|
+
:issue:`7797`, there is a different implementation
|
|
32
|
+
:class:`~sage.algebras.letterplace.free_algebra_letterplace.FreeAlgebra_letterplace`
|
|
33
|
+
based on Singular's letterplace rings. It is currently restricted to
|
|
34
|
+
weighted homogeneous elements and is therefore not the default. But the
|
|
35
|
+
arithmetic is much faster than in the generic implementation.
|
|
36
|
+
Moreover, we can compute Groebner bases with degree bound for its
|
|
37
|
+
two-sided ideals, and thus provide ideal containment tests::
|
|
38
|
+
|
|
39
|
+
sage: # needs sage.libs.singular
|
|
40
|
+
sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace'); F
|
|
41
|
+
Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field
|
|
42
|
+
sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F
|
|
43
|
+
sage: I.groebner_basis(degbound=4)
|
|
44
|
+
Twosided Ideal (x*y + y*z,
|
|
45
|
+
x*x - y*x - y*y - y*z,
|
|
46
|
+
y*y*y - y*y*z + y*z*y - y*z*z,
|
|
47
|
+
y*y*x + y*y*z + y*z*x + y*z*z,
|
|
48
|
+
y*y*z*y - y*y*z*z + y*z*z*y - y*z*z*z,
|
|
49
|
+
y*z*y*y - y*z*y*z + y*z*z*y - y*z*z*z,
|
|
50
|
+
y*y*z*x + y*y*z*z + y*z*z*x + y*z*z*z,
|
|
51
|
+
y*z*y*x + y*z*y*z + y*z*z*x + y*z*z*z) of Free Associative Unital
|
|
52
|
+
Algebra on 3 generators (x, y, z) over Rational Field
|
|
53
|
+
sage: y*z*y*y*z*z + 2*y*z*y*z*z*x + y*z*y*z*z*z - y*z*z*y*z*x + y*z*z*z*z*x in I
|
|
54
|
+
True
|
|
55
|
+
|
|
56
|
+
Positive integral degree weights for the letterplace implementation
|
|
57
|
+
was introduced in :issue:`7797`::
|
|
58
|
+
|
|
59
|
+
sage: # needs sage.libs.singular
|
|
60
|
+
sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3])
|
|
61
|
+
sage: x.degree()
|
|
62
|
+
2
|
|
63
|
+
sage: y.degree()
|
|
64
|
+
1
|
|
65
|
+
sage: z.degree()
|
|
66
|
+
3
|
|
67
|
+
sage: I = F*[x*y-y*x, x^2+2*y*z, (x*y)^2-z^2]*F
|
|
68
|
+
sage: Q.<a,b,c> = F.quo(I)
|
|
69
|
+
sage: TestSuite(Q).run()
|
|
70
|
+
sage: a^2*b^2
|
|
71
|
+
c*c
|
|
72
|
+
|
|
73
|
+
TESTS::
|
|
74
|
+
|
|
75
|
+
sage: F = FreeAlgebra(GF(5),3,'x')
|
|
76
|
+
sage: TestSuite(F).run()
|
|
77
|
+
sage: F is loads(dumps(F))
|
|
78
|
+
True
|
|
79
|
+
|
|
80
|
+
sage: # needs sage.libs.singular
|
|
81
|
+
sage: F = FreeAlgebra(GF(5),3,'x', implementation='letterplace')
|
|
82
|
+
sage: TestSuite(F).run()
|
|
83
|
+
sage: F is loads(dumps(F))
|
|
84
|
+
True
|
|
85
|
+
|
|
86
|
+
::
|
|
87
|
+
|
|
88
|
+
sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
|
|
89
|
+
sage: TestSuite(F).run()
|
|
90
|
+
sage: F is loads(dumps(F))
|
|
91
|
+
True
|
|
92
|
+
|
|
93
|
+
sage: # needs sage.libs.singular
|
|
94
|
+
sage: F.<x,y,z> = FreeAlgebra(GF(5),3, implementation='letterplace')
|
|
95
|
+
sage: TestSuite(F).run()
|
|
96
|
+
sage: F is loads(dumps(F))
|
|
97
|
+
True
|
|
98
|
+
|
|
99
|
+
::
|
|
100
|
+
|
|
101
|
+
sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y'])
|
|
102
|
+
sage: TestSuite(F).run()
|
|
103
|
+
sage: F is loads(dumps(F))
|
|
104
|
+
True
|
|
105
|
+
|
|
106
|
+
sage: # needs sage.libs.singular
|
|
107
|
+
sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y'], implementation='letterplace')
|
|
108
|
+
sage: TestSuite(F).run()
|
|
109
|
+
sage: F is loads(dumps(F))
|
|
110
|
+
True
|
|
111
|
+
|
|
112
|
+
::
|
|
113
|
+
|
|
114
|
+
sage: F = FreeAlgebra(GF(5),3, 'abc')
|
|
115
|
+
sage: TestSuite(F).run()
|
|
116
|
+
sage: F is loads(dumps(F))
|
|
117
|
+
True
|
|
118
|
+
|
|
119
|
+
sage: # needs sage.libs.singular
|
|
120
|
+
sage: F = FreeAlgebra(GF(5),3, 'abc', implementation='letterplace')
|
|
121
|
+
sage: TestSuite(F).run()
|
|
122
|
+
sage: F is loads(dumps(F))
|
|
123
|
+
True
|
|
124
|
+
|
|
125
|
+
::
|
|
126
|
+
|
|
127
|
+
sage: F = FreeAlgebra(FreeAlgebra(ZZ,2,'ab'), 2, 'x')
|
|
128
|
+
sage: TestSuite(F).run()
|
|
129
|
+
sage: F is loads(dumps(F))
|
|
130
|
+
True
|
|
131
|
+
|
|
132
|
+
Note that the letterplace implementation can only be used if the corresponding
|
|
133
|
+
(multivariate) polynomial ring has an implementation in Singular::
|
|
134
|
+
|
|
135
|
+
sage: FreeAlgebra(FreeAlgebra(ZZ,2,'ab'), 2, 'x', implementation='letterplace') # needs sage.libs.singular
|
|
136
|
+
Traceback (most recent call last):
|
|
137
|
+
...
|
|
138
|
+
NotImplementedError: polynomials over Free Algebra on 2 generators (a, b)
|
|
139
|
+
over Integer Ring are not supported in Singular
|
|
140
|
+
|
|
141
|
+
Some tests for the category::
|
|
142
|
+
|
|
143
|
+
sage: R.<x> = FreeAlgebra(QQ,1)
|
|
144
|
+
sage: R.is_commutative()
|
|
145
|
+
True
|
|
146
|
+
sage: R.<x,y> = FreeAlgebra(QQ,2)
|
|
147
|
+
sage: R.is_commutative()
|
|
148
|
+
False
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
# ***************************************************************************
|
|
152
|
+
# Copyright (C) 2005 David Kohel <kohel@maths.usyd.edu>
|
|
153
|
+
# Copyright (C) 2005,2006 William Stein <wstein@gmail.com>
|
|
154
|
+
# Copyright (C) 2011 Simon King <simon.king@uni-jena.de>
|
|
155
|
+
#
|
|
156
|
+
# This program is free software: you can redistribute it and/or modify
|
|
157
|
+
# it under the terms of the GNU General Public License as published by
|
|
158
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
159
|
+
# (at your option) any later version.
|
|
160
|
+
# https://www.gnu.org/licenses/
|
|
161
|
+
# ***************************************************************************
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
from sage.algebras.free_algebra_element import FreeAlgebraElement
|
|
165
|
+
from sage.categories.algebras_with_basis import AlgebrasWithBasis
|
|
166
|
+
from sage.categories.functor import Functor
|
|
167
|
+
from sage.categories.pushout import (ConstructionFunctor,
|
|
168
|
+
CompositeConstructionFunctor,
|
|
169
|
+
IdentityConstructionFunctor)
|
|
170
|
+
from sage.categories.rings import Rings
|
|
171
|
+
from sage.combinat.free_module import CombinatorialFreeModule
|
|
172
|
+
from sage.combinat.words.word import Word
|
|
173
|
+
from sage.misc.cachefunc import cached_method
|
|
174
|
+
from sage.misc.lazy_import import lazy_import
|
|
175
|
+
from sage.monoids.free_monoid import FreeMonoid
|
|
176
|
+
from sage.monoids.free_monoid_element import FreeMonoidElement
|
|
177
|
+
from sage.rings.integer_ring import ZZ
|
|
178
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
179
|
+
from sage.structure.category_object import normalize_names
|
|
180
|
+
from sage.structure.coerce_exceptions import CoercionException
|
|
181
|
+
from sage.structure.factory import UniqueFactory
|
|
182
|
+
|
|
183
|
+
lazy_import('sage.algebras.letterplace.free_algebra_letterplace', 'FreeAlgebra_letterplace')
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class FreeAlgebraFactory(UniqueFactory):
|
|
187
|
+
"""
|
|
188
|
+
A constructor of free algebras.
|
|
189
|
+
|
|
190
|
+
See :mod:`~sage.algebras.free_algebra` for examples and corner cases.
|
|
191
|
+
|
|
192
|
+
EXAMPLES::
|
|
193
|
+
|
|
194
|
+
sage: FreeAlgebra(GF(5),3,'x')
|
|
195
|
+
Free Algebra on 3 generators (x0, x1, x2) over Finite Field of size 5
|
|
196
|
+
sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
|
|
197
|
+
sage: (x+y+z)^2
|
|
198
|
+
x^2 + x*y + x*z + y*x + y^2 + y*z + z*x + z*y + z^2
|
|
199
|
+
sage: FreeAlgebra(GF(5),3, 'xx, zba, Y')
|
|
200
|
+
Free Algebra on 3 generators (xx, zba, Y) over Finite Field of size 5
|
|
201
|
+
sage: FreeAlgebra(GF(5),3, 'abc')
|
|
202
|
+
Free Algebra on 3 generators (a, b, c) over Finite Field of size 5
|
|
203
|
+
sage: FreeAlgebra(GF(5),1, 'z')
|
|
204
|
+
Free Algebra on 1 generator (z,) over Finite Field of size 5
|
|
205
|
+
sage: FreeAlgebra(GF(5),1, ['alpha'])
|
|
206
|
+
Free Algebra on 1 generator (alpha,) over Finite Field of size 5
|
|
207
|
+
sage: FreeAlgebra(FreeAlgebra(ZZ,1,'a'), 2, 'x')
|
|
208
|
+
Free Algebra on 2 generators (x0, x1) over
|
|
209
|
+
Free Algebra on 1 generator (a,) over Integer Ring
|
|
210
|
+
|
|
211
|
+
Free algebras are globally unique::
|
|
212
|
+
|
|
213
|
+
sage: F = FreeAlgebra(ZZ,3,'x,y,z')
|
|
214
|
+
sage: G = FreeAlgebra(ZZ,3,'x,y,z')
|
|
215
|
+
sage: F is G
|
|
216
|
+
True
|
|
217
|
+
sage: F.<x,y,z> = FreeAlgebra(GF(5),3) # indirect doctest
|
|
218
|
+
sage: F is loads(dumps(F))
|
|
219
|
+
True
|
|
220
|
+
sage: F is FreeAlgebra(GF(5),['x','y','z'])
|
|
221
|
+
True
|
|
222
|
+
sage: copy(F) is F is loads(dumps(F))
|
|
223
|
+
True
|
|
224
|
+
sage: TestSuite(F).run()
|
|
225
|
+
|
|
226
|
+
By :issue:`7797`, we provide a different implementation of free
|
|
227
|
+
algebras, based on Singular's "letterplace rings". Our letterplace
|
|
228
|
+
wrapper allows for choosing positive integral degree weights for the
|
|
229
|
+
generators of the free algebra. However, only (weighted) homogeneous
|
|
230
|
+
elements are supported. Of course, isomorphic algebras in different
|
|
231
|
+
implementations are not identical::
|
|
232
|
+
|
|
233
|
+
sage: # needs sage.libs.singular
|
|
234
|
+
sage: G = FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace')
|
|
235
|
+
sage: F == G
|
|
236
|
+
False
|
|
237
|
+
sage: G is FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace')
|
|
238
|
+
True
|
|
239
|
+
sage: copy(G) is G is loads(dumps(G))
|
|
240
|
+
True
|
|
241
|
+
sage: TestSuite(G).run()
|
|
242
|
+
|
|
243
|
+
::
|
|
244
|
+
|
|
245
|
+
sage: # needs sage.libs.singular
|
|
246
|
+
sage: H = FreeAlgebra(GF(5), ['x','y','z'], implementation='letterplace',
|
|
247
|
+
....: degrees=[1,2,3])
|
|
248
|
+
sage: F != H != G
|
|
249
|
+
True
|
|
250
|
+
sage: H is FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace',
|
|
251
|
+
....: degrees=[1,2,3])
|
|
252
|
+
True
|
|
253
|
+
sage: copy(H) is H is loads(dumps(H))
|
|
254
|
+
True
|
|
255
|
+
sage: TestSuite(H).run()
|
|
256
|
+
|
|
257
|
+
Free algebras commute with their base ring.
|
|
258
|
+
::
|
|
259
|
+
|
|
260
|
+
sage: K.<a,b> = FreeAlgebra(QQ,2)
|
|
261
|
+
sage: K.is_commutative()
|
|
262
|
+
False
|
|
263
|
+
sage: L.<c> = FreeAlgebra(K,1)
|
|
264
|
+
sage: L.is_commutative()
|
|
265
|
+
False
|
|
266
|
+
sage: s = a*b^2 * c^3; s
|
|
267
|
+
a*b^2*c^3
|
|
268
|
+
sage: parent(s)
|
|
269
|
+
Free Algebra on 1 generator (c,) over
|
|
270
|
+
Free Algebra on 2 generators (a, b) over Rational Field
|
|
271
|
+
sage: c^3 * a * b^2
|
|
272
|
+
a*b^2*c^3
|
|
273
|
+
"""
|
|
274
|
+
def create_key(self, base_ring, arg1=None, arg2=None,
|
|
275
|
+
sparse=None, order=None,
|
|
276
|
+
names=None, name=None,
|
|
277
|
+
implementation=None, degrees=None):
|
|
278
|
+
"""
|
|
279
|
+
Create the key under which a free algebra is stored.
|
|
280
|
+
|
|
281
|
+
TESTS::
|
|
282
|
+
|
|
283
|
+
sage: FreeAlgebra.create_key(GF(5),['x','y','z'])
|
|
284
|
+
(Finite Field of size 5, ('x', 'y', 'z'))
|
|
285
|
+
sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3)
|
|
286
|
+
(Finite Field of size 5, ('x', 'y', 'z'))
|
|
287
|
+
sage: FreeAlgebra.create_key(GF(5),3,'xyz')
|
|
288
|
+
(Finite Field of size 5, ('x', 'y', 'z'))
|
|
289
|
+
|
|
290
|
+
sage: # needs sage.libs.singular
|
|
291
|
+
sage: FreeAlgebra.create_key(GF(5),['x','y','z'],
|
|
292
|
+
....: implementation='letterplace')
|
|
293
|
+
(Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
|
|
294
|
+
sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3,
|
|
295
|
+
....: implementation='letterplace')
|
|
296
|
+
(Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
|
|
297
|
+
sage: FreeAlgebra.create_key(GF(5),3,'xyz',
|
|
298
|
+
....: implementation='letterplace')
|
|
299
|
+
(Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
|
|
300
|
+
sage: FreeAlgebra.create_key(GF(5),3,'xyz',
|
|
301
|
+
....: implementation='letterplace', degrees=[1,2,3])
|
|
302
|
+
((1, 2, 3), Multivariate Polynomial Ring in x, y, z, x_ over Finite Field of size 5)
|
|
303
|
+
"""
|
|
304
|
+
if arg1 is None and arg2 is None and names is None:
|
|
305
|
+
# this is used for pickling
|
|
306
|
+
if degrees is None:
|
|
307
|
+
return (base_ring,)
|
|
308
|
+
return tuple(degrees), base_ring
|
|
309
|
+
# test if we can use libSingular/letterplace
|
|
310
|
+
if implementation == "letterplace":
|
|
311
|
+
if order is None:
|
|
312
|
+
order = 'degrevlex' if degrees is None else 'deglex'
|
|
313
|
+
args = [arg for arg in (arg1, arg2) if arg is not None]
|
|
314
|
+
kwds = {'sparse': sparse, 'order': order, 'implementation': "singular"}
|
|
315
|
+
if name is not None:
|
|
316
|
+
kwds["name"] = name
|
|
317
|
+
if names is not None:
|
|
318
|
+
kwds["names"] = names
|
|
319
|
+
PolRing = PolynomialRing(base_ring, *args, **kwds)
|
|
320
|
+
if degrees is None:
|
|
321
|
+
return (PolRing,)
|
|
322
|
+
from sage.rings.polynomial.term_order import TermOrder
|
|
323
|
+
T = TermOrder(PolRing.term_order(), PolRing.ngens() + 1)
|
|
324
|
+
varnames = list(PolRing.variable_names())
|
|
325
|
+
newname = 'x'
|
|
326
|
+
while newname in varnames:
|
|
327
|
+
newname += '_'
|
|
328
|
+
varnames.append(newname)
|
|
329
|
+
R = PolynomialRing(
|
|
330
|
+
PolRing.base(), varnames,
|
|
331
|
+
sparse=sparse, order=T)
|
|
332
|
+
return tuple(degrees), R
|
|
333
|
+
# normalise the generator names
|
|
334
|
+
from sage.rings.integer import Integer
|
|
335
|
+
if isinstance(arg1, (Integer, int)):
|
|
336
|
+
arg1, arg2 = arg2, arg1
|
|
337
|
+
if names is not None:
|
|
338
|
+
arg1 = names
|
|
339
|
+
elif name is not None:
|
|
340
|
+
arg1 = name
|
|
341
|
+
if arg2 is None:
|
|
342
|
+
arg2 = len(arg1)
|
|
343
|
+
names = normalize_names(arg2, arg1)
|
|
344
|
+
if degrees is None:
|
|
345
|
+
return base_ring, names
|
|
346
|
+
if degrees in ZZ:
|
|
347
|
+
return base_ring, names, (degrees,) * len(names)
|
|
348
|
+
return base_ring, names, tuple(degrees)
|
|
349
|
+
|
|
350
|
+
def create_object(self, version, key):
|
|
351
|
+
"""
|
|
352
|
+
Construct the free algebra that belongs to a unique key.
|
|
353
|
+
|
|
354
|
+
NOTE:
|
|
355
|
+
|
|
356
|
+
Of course, that method should not be called directly,
|
|
357
|
+
since it does not use the cache of free algebras.
|
|
358
|
+
|
|
359
|
+
TESTS::
|
|
360
|
+
|
|
361
|
+
sage: FreeAlgebra.create_object('4.7.1', (QQ['x','y'],)) # needs sage.libs.singular
|
|
362
|
+
Free Associative Unital Algebra on 2 generators (x, y) over Rational Field
|
|
363
|
+
sage: FreeAlgebra.create_object('4.7.1', (QQ['x','y'],)) is FreeAlgebra(QQ,['x','y']) # needs sage.libs.singular
|
|
364
|
+
False
|
|
365
|
+
"""
|
|
366
|
+
if len(key) == 1:
|
|
367
|
+
from sage.algebras.letterplace.free_algebra_letterplace import FreeAlgebra_letterplace
|
|
368
|
+
return FreeAlgebra_letterplace(key[0])
|
|
369
|
+
if isinstance(key[0], tuple):
|
|
370
|
+
from sage.algebras.letterplace.free_algebra_letterplace import FreeAlgebra_letterplace
|
|
371
|
+
return FreeAlgebra_letterplace(key[1], degrees=key[0])
|
|
372
|
+
if len(key) == 2:
|
|
373
|
+
return FreeAlgebra_generic(key[0], len(key[1]), key[1])
|
|
374
|
+
return FreeAlgebra_generic(key[0], len(key[1]), key[1], key[2])
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
FreeAlgebra = FreeAlgebraFactory('FreeAlgebra')
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def is_FreeAlgebra(x) -> bool:
|
|
381
|
+
"""
|
|
382
|
+
Return ``True`` if x is a free algebra; otherwise, return ``False``.
|
|
383
|
+
|
|
384
|
+
EXAMPLES::
|
|
385
|
+
|
|
386
|
+
sage: from sage.algebras.free_algebra import is_FreeAlgebra
|
|
387
|
+
sage: is_FreeAlgebra(5)
|
|
388
|
+
doctest:warning...
|
|
389
|
+
DeprecationWarning: the function is_FreeAlgebra is deprecated;
|
|
390
|
+
use 'isinstance(..., (FreeAlgebra_generic, FreeAlgebra_letterplace))' instead
|
|
391
|
+
See https://github.com/sagemath/sage/issues/37896 for details.
|
|
392
|
+
False
|
|
393
|
+
sage: is_FreeAlgebra(ZZ)
|
|
394
|
+
False
|
|
395
|
+
sage: is_FreeAlgebra(FreeAlgebra(ZZ,100,'x'))
|
|
396
|
+
True
|
|
397
|
+
sage: is_FreeAlgebra(FreeAlgebra(ZZ,10,'x',implementation='letterplace')) # needs sage.libs.singular
|
|
398
|
+
True
|
|
399
|
+
sage: is_FreeAlgebra(FreeAlgebra(ZZ,10,'x',implementation='letterplace', # needs sage.libs.singular
|
|
400
|
+
....: degrees=list(range(1,11))))
|
|
401
|
+
True
|
|
402
|
+
"""
|
|
403
|
+
from sage.misc.superseded import deprecation
|
|
404
|
+
deprecation(37896, "the function is_FreeAlgebra is deprecated; use 'isinstance(..., (FreeAlgebra_generic, FreeAlgebra_letterplace))' instead")
|
|
405
|
+
return isinstance(x, (FreeAlgebra_generic, FreeAlgebra_letterplace))
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
class FreeAlgebra_generic(CombinatorialFreeModule):
|
|
409
|
+
"""
|
|
410
|
+
The free algebra on `n` generators over a base ring.
|
|
411
|
+
|
|
412
|
+
INPUT:
|
|
413
|
+
|
|
414
|
+
- ``R`` -- a ring
|
|
415
|
+
- ``n`` -- integer
|
|
416
|
+
- ``names`` -- the generator names
|
|
417
|
+
- ``degrees`` -- (optional) a tuple or list specifying the
|
|
418
|
+
degrees of all the generators, if omitted, the algebra is not
|
|
419
|
+
graded
|
|
420
|
+
|
|
421
|
+
EXAMPLES::
|
|
422
|
+
|
|
423
|
+
sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F
|
|
424
|
+
Free Algebra on 3 generators (x, y, z) over Rational Field
|
|
425
|
+
sage: mul(F.gens())
|
|
426
|
+
x*y*z
|
|
427
|
+
sage: mul([ F.gen(i%3) for i in range(12) ])
|
|
428
|
+
x*y*z*x*y*z*x*y*z*x*y*z
|
|
429
|
+
sage: mul([ F.gen(i%3) for i in range(12) ]) + mul([ F.gen(i%2) for i in range(12) ])
|
|
430
|
+
x*y*x*y*x*y*x*y*x*y*x*y + x*y*z*x*y*z*x*y*z*x*y*z
|
|
431
|
+
sage: (2 + x*z + x^2)^2 + (x - y)^2
|
|
432
|
+
4 + 5*x^2 - x*y + 4*x*z - y*x + y^2 + x^4 + x^3*z + x*z*x^2 + x*z*x*z
|
|
433
|
+
|
|
434
|
+
TESTS:
|
|
435
|
+
|
|
436
|
+
Free algebras commute with their base ring::
|
|
437
|
+
|
|
438
|
+
sage: K.<a,b> = FreeAlgebra(QQ)
|
|
439
|
+
sage: K.is_commutative()
|
|
440
|
+
False
|
|
441
|
+
sage: L.<c,d> = FreeAlgebra(K)
|
|
442
|
+
sage: L.is_commutative()
|
|
443
|
+
False
|
|
444
|
+
sage: s = a*b^2 * c^3; s
|
|
445
|
+
a*b^2*c^3
|
|
446
|
+
sage: parent(s)
|
|
447
|
+
Free Algebra on 2 generators (c, d) over Free Algebra on 2 generators (a, b) over Rational Field
|
|
448
|
+
sage: c^3 * a * b^2
|
|
449
|
+
a*b^2*c^3
|
|
450
|
+
|
|
451
|
+
Two free algebras are considered the same if they have the same
|
|
452
|
+
base ring, number of generators and variable names, and the same
|
|
453
|
+
implementation::
|
|
454
|
+
|
|
455
|
+
sage: F = FreeAlgebra(QQ,3,'x')
|
|
456
|
+
sage: F == FreeAlgebra(QQ,3,'x')
|
|
457
|
+
True
|
|
458
|
+
sage: F is FreeAlgebra(QQ,3,'x')
|
|
459
|
+
True
|
|
460
|
+
sage: F == FreeAlgebra(ZZ,3,'x')
|
|
461
|
+
False
|
|
462
|
+
sage: F == FreeAlgebra(QQ,4,'x')
|
|
463
|
+
False
|
|
464
|
+
sage: F == FreeAlgebra(QQ,3,'y')
|
|
465
|
+
False
|
|
466
|
+
|
|
467
|
+
Note that since :issue:`7797` there is a different
|
|
468
|
+
implementation of free algebras. Two corresponding free
|
|
469
|
+
algebras in different implementations are not equal, but there
|
|
470
|
+
is a coercion.
|
|
471
|
+
"""
|
|
472
|
+
Element = FreeAlgebraElement
|
|
473
|
+
|
|
474
|
+
def __init__(self, R, n, names, degrees=None):
|
|
475
|
+
"""
|
|
476
|
+
The free algebra on `n` generators over a base ring.
|
|
477
|
+
|
|
478
|
+
EXAMPLES::
|
|
479
|
+
|
|
480
|
+
sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F # indirect doctest
|
|
481
|
+
Free Algebra on 3 generators (x, y, z) over Rational Field
|
|
482
|
+
|
|
483
|
+
TESTS:
|
|
484
|
+
|
|
485
|
+
Note that the following is *not* the recommended way to create
|
|
486
|
+
a free algebra::
|
|
487
|
+
|
|
488
|
+
sage: from sage.algebras.free_algebra import FreeAlgebra_generic
|
|
489
|
+
sage: FreeAlgebra_generic(ZZ, 3, 'abc')
|
|
490
|
+
Free Algebra on 3 generators (a, b, c) over Integer Ring
|
|
491
|
+
"""
|
|
492
|
+
if R not in Rings():
|
|
493
|
+
raise TypeError("argument R must be a ring")
|
|
494
|
+
self.__ngens = n
|
|
495
|
+
indices = FreeMonoid(n, names=names)
|
|
496
|
+
cat = AlgebrasWithBasis(R)
|
|
497
|
+
if self.__ngens <= 1 and R.is_commutative():
|
|
498
|
+
cat = cat.Commutative()
|
|
499
|
+
if degrees is not None:
|
|
500
|
+
if len(degrees) != len(names) or not all(d in ZZ for d in degrees):
|
|
501
|
+
raise ValueError("argument degrees must specify an integer for each generator")
|
|
502
|
+
cat = cat.Graded()
|
|
503
|
+
|
|
504
|
+
CombinatorialFreeModule.__init__(self, R, indices, prefix='F',
|
|
505
|
+
category=cat)
|
|
506
|
+
self._assign_names(indices.variable_names())
|
|
507
|
+
if degrees is None:
|
|
508
|
+
self._degrees = None
|
|
509
|
+
else:
|
|
510
|
+
self._degrees = {g: ZZ(d) for g, d in zip(self.monoid().gens(), degrees)}
|
|
511
|
+
|
|
512
|
+
def construction(self):
|
|
513
|
+
"""
|
|
514
|
+
Return the construction of ``self``.
|
|
515
|
+
|
|
516
|
+
EXAMPLES::
|
|
517
|
+
|
|
518
|
+
sage: F, R = algebras.Free(QQ,4,'x,y,z,t').construction(); F
|
|
519
|
+
Associative[x,y,z,t]
|
|
520
|
+
"""
|
|
521
|
+
return AssociativeFunctor(self.variable_names(), self._degrees), self.base_ring()
|
|
522
|
+
|
|
523
|
+
def one_basis(self):
|
|
524
|
+
"""
|
|
525
|
+
Return the index of the basis element `1`.
|
|
526
|
+
|
|
527
|
+
EXAMPLES::
|
|
528
|
+
|
|
529
|
+
sage: F = FreeAlgebra(QQ, 2, 'x,y')
|
|
530
|
+
sage: F.one_basis()
|
|
531
|
+
1
|
|
532
|
+
sage: F.one_basis().parent()
|
|
533
|
+
Free monoid on 2 generators (x, y)
|
|
534
|
+
"""
|
|
535
|
+
return self._indices.one()
|
|
536
|
+
|
|
537
|
+
def is_field(self, proof=True) -> bool:
|
|
538
|
+
"""
|
|
539
|
+
Return ``True`` if this Free Algebra is a field.
|
|
540
|
+
|
|
541
|
+
This happens only if the
|
|
542
|
+
base ring is a field and there are no generators
|
|
543
|
+
|
|
544
|
+
EXAMPLES::
|
|
545
|
+
|
|
546
|
+
sage: A = FreeAlgebra(QQ,0,'')
|
|
547
|
+
sage: A.is_field()
|
|
548
|
+
True
|
|
549
|
+
sage: A = FreeAlgebra(QQ,1,'x')
|
|
550
|
+
sage: A.is_field()
|
|
551
|
+
False
|
|
552
|
+
"""
|
|
553
|
+
if self.__ngens == 0:
|
|
554
|
+
return self.base_ring().is_field(proof)
|
|
555
|
+
return False
|
|
556
|
+
|
|
557
|
+
def _repr_(self) -> str:
|
|
558
|
+
"""
|
|
559
|
+
Text representation of this free algebra.
|
|
560
|
+
|
|
561
|
+
EXAMPLES::
|
|
562
|
+
|
|
563
|
+
sage: F = FreeAlgebra(QQ, 3, 'x')
|
|
564
|
+
sage: F # indirect doctest
|
|
565
|
+
Free Algebra on 3 generators (x0, x1, x2) over Rational Field
|
|
566
|
+
sage: F.rename('QQ<<x0,x1,x2>>')
|
|
567
|
+
sage: F # indirect doctest
|
|
568
|
+
QQ<<x0,x1,x2>>
|
|
569
|
+
sage: FreeAlgebra(ZZ, 1, ['a'])
|
|
570
|
+
Free Algebra on 1 generator (a,) over Integer Ring
|
|
571
|
+
|
|
572
|
+
sage: FreeAlgebra(QQ, 2, ['x', 'y'], degrees=(2,1))
|
|
573
|
+
Free Algebra on 2 generators (x, y) with degrees (2, 1) over Rational Field
|
|
574
|
+
"""
|
|
575
|
+
txt = "generator" if self.__ngens == 1 else "generators"
|
|
576
|
+
if self._degrees is None:
|
|
577
|
+
return "Free Algebra on {} {} {} over {}".format(
|
|
578
|
+
self.__ngens, txt, self.gens(), self.base_ring())
|
|
579
|
+
return "Free Algebra on {} {} {} with degrees {} over {}".format(
|
|
580
|
+
self.__ngens, txt, self.gens(), tuple(self._degrees.values()), self.base_ring())
|
|
581
|
+
|
|
582
|
+
def _latex_(self) -> str:
|
|
583
|
+
r"""
|
|
584
|
+
Return a latex representation of ``self``.
|
|
585
|
+
|
|
586
|
+
EXAMPLES::
|
|
587
|
+
|
|
588
|
+
sage: F = FreeAlgebra(QQ,3,'x')
|
|
589
|
+
sage: latex(F)
|
|
590
|
+
\Bold{Q}\langle x_{0}, x_{1}, x_{2}\rangle
|
|
591
|
+
sage: F = FreeAlgebra(ZZ['q'], 3, 'a,b,c')
|
|
592
|
+
sage: latex(F)
|
|
593
|
+
\Bold{Z}[q]\langle a, b, c\rangle
|
|
594
|
+
"""
|
|
595
|
+
from sage.misc.latex import latex
|
|
596
|
+
return "{}\\langle {}\\rangle".format(latex(self.base_ring()),
|
|
597
|
+
', '.join(self.latex_variable_names()))
|
|
598
|
+
|
|
599
|
+
def _element_constructor_(self, x):
|
|
600
|
+
"""
|
|
601
|
+
Convert ``x`` into ``self``.
|
|
602
|
+
|
|
603
|
+
EXAMPLES::
|
|
604
|
+
|
|
605
|
+
sage: R.<x,y> = FreeAlgebra(QQ,2)
|
|
606
|
+
sage: R(3) # indirect doctest
|
|
607
|
+
3
|
|
608
|
+
|
|
609
|
+
TESTS::
|
|
610
|
+
|
|
611
|
+
sage: # needs sage.libs.singular
|
|
612
|
+
sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
|
|
613
|
+
sage: L.<x,y,z> = FreeAlgebra(ZZ,3,implementation='letterplace')
|
|
614
|
+
sage: F(x) # indirect doctest
|
|
615
|
+
x
|
|
616
|
+
sage: F.1*L.2
|
|
617
|
+
y*z
|
|
618
|
+
sage: (F.1*L.2).parent() is F
|
|
619
|
+
True
|
|
620
|
+
|
|
621
|
+
::
|
|
622
|
+
|
|
623
|
+
sage: # needs sage.libs.singular sage.rings.finite_rings
|
|
624
|
+
sage: K.<z> = GF(25)
|
|
625
|
+
sage: F.<a,b,c> = FreeAlgebra(K,3)
|
|
626
|
+
sage: L.<a,b,c> = FreeAlgebra(K,3, implementation='letterplace')
|
|
627
|
+
sage: F.1 + (z+1)*L.2
|
|
628
|
+
b + (z+1)*c
|
|
629
|
+
|
|
630
|
+
Check that :issue:`15169` is fixed::
|
|
631
|
+
|
|
632
|
+
sage: A.<x> = FreeAlgebra(CC)
|
|
633
|
+
sage: A(2)
|
|
634
|
+
2.00000000000000
|
|
635
|
+
|
|
636
|
+
We check that the string coercions work correctly over
|
|
637
|
+
inexact fields::
|
|
638
|
+
|
|
639
|
+
sage: F.<x,y> = FreeAlgebra(CC)
|
|
640
|
+
sage: F('2')
|
|
641
|
+
2.00000000000000
|
|
642
|
+
sage: F('x')
|
|
643
|
+
1.00000000000000*x
|
|
644
|
+
|
|
645
|
+
Check that it also converts factorizations::
|
|
646
|
+
|
|
647
|
+
sage: f = Factorization([(x,2),(y,3)]); f
|
|
648
|
+
1.00000000000000*x^2 * 1.00000000000000*y^3
|
|
649
|
+
sage: F(f)
|
|
650
|
+
1.00000000000000*x^2*y^3
|
|
651
|
+
|
|
652
|
+
Check for extended coercion::
|
|
653
|
+
|
|
654
|
+
sage: A = algebras.Free(QQ,['x','y'])
|
|
655
|
+
sage: B = algebras.Free(QQ,['y'])
|
|
656
|
+
sage: y, = B.gens()
|
|
657
|
+
sage: A(4+y)
|
|
658
|
+
4 + y
|
|
659
|
+
"""
|
|
660
|
+
if isinstance(x, FreeAlgebraElement):
|
|
661
|
+
P = x.parent()
|
|
662
|
+
if P is self:
|
|
663
|
+
return x
|
|
664
|
+
# from another FreeAlgebra:
|
|
665
|
+
if x not in self.base_ring():
|
|
666
|
+
D = {self.monoid()(T): cf
|
|
667
|
+
for T, cf in x.monomial_coefficients().items()}
|
|
668
|
+
return self.element_class(self, D)
|
|
669
|
+
elif hasattr(x, 'letterplace_polynomial'):
|
|
670
|
+
P = x.parent()
|
|
671
|
+
if self.has_coerce_map_from(P): # letterplace versus generic
|
|
672
|
+
ngens = P.ngens()
|
|
673
|
+
M = self._indices
|
|
674
|
+
|
|
675
|
+
def exp_to_monomial(T):
|
|
676
|
+
return M([(i % ngens, Ti) for i, Ti in enumerate(T) if Ti])
|
|
677
|
+
|
|
678
|
+
return self.element_class(self, {exp_to_monomial(T): c
|
|
679
|
+
for T, c in x.letterplace_polynomial().monomial_coefficients().items()})
|
|
680
|
+
# ok, not a free algebra element (or should not be viewed as one).
|
|
681
|
+
if isinstance(x, str):
|
|
682
|
+
from sage.misc.sage_eval import sage_eval
|
|
683
|
+
G = self.gens()
|
|
684
|
+
d = {str(v): G[i] for i, v in enumerate(self.variable_names())}
|
|
685
|
+
return self(sage_eval(x, locals=d))
|
|
686
|
+
R = self.base_ring()
|
|
687
|
+
# coercion from free monoid
|
|
688
|
+
if isinstance(x, FreeMonoidElement) and x.parent() is self._indices:
|
|
689
|
+
return self.element_class(self, {x: R.one()})
|
|
690
|
+
# coercion from the PBW basis
|
|
691
|
+
if isinstance(x, PBWBasisOfFreeAlgebra.Element) \
|
|
692
|
+
and self.has_coerce_map_from(x.parent()._alg):
|
|
693
|
+
return self(x.parent().expansion(x))
|
|
694
|
+
|
|
695
|
+
# Check if it's a factorization
|
|
696
|
+
from sage.structure.factorization import Factorization
|
|
697
|
+
if isinstance(x, Factorization):
|
|
698
|
+
return self.prod(f**i for f, i in x)
|
|
699
|
+
|
|
700
|
+
# coercion via base ring
|
|
701
|
+
x = R(x)
|
|
702
|
+
if x == 0:
|
|
703
|
+
return self.element_class(self, {})
|
|
704
|
+
return self.element_class(self, {self.one_basis(): x})
|
|
705
|
+
|
|
706
|
+
def _coerce_map_from_(self, R) -> bool:
|
|
707
|
+
"""
|
|
708
|
+
Return ``True`` if there is a coercion from ``R`` into ``self`` and
|
|
709
|
+
``False`` otherwise.
|
|
710
|
+
|
|
711
|
+
The things that coerce into ``self`` are:
|
|
712
|
+
|
|
713
|
+
- This free algebra.
|
|
714
|
+
|
|
715
|
+
- The PBW basis of ``self``.
|
|
716
|
+
|
|
717
|
+
- Free algebras in some subset of variables
|
|
718
|
+
over a base with a coercion map into ``self.base_ring()``.
|
|
719
|
+
|
|
720
|
+
- The underlying monoid.
|
|
721
|
+
|
|
722
|
+
- Anything with a coercion into ``self.monoid()``.
|
|
723
|
+
|
|
724
|
+
- Anything with a coercion into ``self.base_ring()``.
|
|
725
|
+
|
|
726
|
+
TESTS::
|
|
727
|
+
|
|
728
|
+
sage: F = FreeAlgebra(ZZ, 3, 'x,y,z')
|
|
729
|
+
sage: G = FreeAlgebra(QQ, 3, 'x,y,z')
|
|
730
|
+
sage: H = FreeAlgebra(ZZ, 1, 'y')
|
|
731
|
+
sage: F._coerce_map_from_(G)
|
|
732
|
+
False
|
|
733
|
+
sage: G._coerce_map_from_(F)
|
|
734
|
+
True
|
|
735
|
+
sage: F._coerce_map_from_(H)
|
|
736
|
+
True
|
|
737
|
+
sage: F._coerce_map_from_(QQ)
|
|
738
|
+
False
|
|
739
|
+
sage: G._coerce_map_from_(QQ)
|
|
740
|
+
True
|
|
741
|
+
sage: F._coerce_map_from_(G.monoid())
|
|
742
|
+
True
|
|
743
|
+
sage: F._coerce_map_from_(F.pbw_basis())
|
|
744
|
+
True
|
|
745
|
+
sage: F.has_coerce_map_from(PolynomialRing(ZZ, 3, 'x,y,z'))
|
|
746
|
+
False
|
|
747
|
+
|
|
748
|
+
sage: # needs sage.rings.finite_rings
|
|
749
|
+
sage: K.<z> = GF(25)
|
|
750
|
+
sage: F.<a,b,c> = FreeAlgebra(K,3)
|
|
751
|
+
sage: F._coerce_map_from_(ZZ)
|
|
752
|
+
True
|
|
753
|
+
sage: F._coerce_map_from_(QQ)
|
|
754
|
+
False
|
|
755
|
+
sage: F._coerce_map_from_(F.monoid())
|
|
756
|
+
True
|
|
757
|
+
sage: F._coerce_map_from_(F.pbw_basis())
|
|
758
|
+
True
|
|
759
|
+
sage: G = FreeAlgebra(ZZ, 3, 'a,b,c')
|
|
760
|
+
sage: F._coerce_map_from_(G)
|
|
761
|
+
True
|
|
762
|
+
sage: G._coerce_map_from_(F)
|
|
763
|
+
False
|
|
764
|
+
sage: L.<a,b,c> = FreeAlgebra(K,3, implementation='letterplace') # needs sage.libs.singular
|
|
765
|
+
sage: F.1 + (z+1) * L.2 # needs sage.libs.singular
|
|
766
|
+
b + (z+1)*c
|
|
767
|
+
"""
|
|
768
|
+
if self._indices.has_coerce_map_from(R):
|
|
769
|
+
return True
|
|
770
|
+
|
|
771
|
+
# free algebras in the same variable over any base that coerces in:
|
|
772
|
+
if isinstance(R, (FreeAlgebra_generic, FreeAlgebra_letterplace)):
|
|
773
|
+
if all(x in self.variable_names() for x in R.variable_names()):
|
|
774
|
+
return self.base_ring().has_coerce_map_from(R.base_ring())
|
|
775
|
+
if isinstance(R, PBWBasisOfFreeAlgebra):
|
|
776
|
+
return self.has_coerce_map_from(R._alg)
|
|
777
|
+
|
|
778
|
+
return self.base_ring().has_coerce_map_from(R)
|
|
779
|
+
|
|
780
|
+
def _is_valid_homomorphism_(self, other, im_gens, base_map=None):
|
|
781
|
+
"""
|
|
782
|
+
Check that the number of given images is correct.
|
|
783
|
+
|
|
784
|
+
EXAMPLES::
|
|
785
|
+
|
|
786
|
+
sage: ring = algebras.Free(QQ, ['a', 'b'])
|
|
787
|
+
sage: a, b = ring.gens()
|
|
788
|
+
sage: A = matrix(QQ, 2, 2, [1, 5, 1, 5])
|
|
789
|
+
sage: B = matrix(QQ, 2, 2, [1, 4, 9, 2])
|
|
790
|
+
sage: C = matrix(QQ, 2, 2, [1, 7, 8, 9])
|
|
791
|
+
sage: f = ring.hom([A, B])
|
|
792
|
+
sage: f(a*b+1)
|
|
793
|
+
[47 14]
|
|
794
|
+
[46 15]
|
|
795
|
+
|
|
796
|
+
sage: ring.hom([A, B, C])
|
|
797
|
+
Traceback (most recent call last):
|
|
798
|
+
...
|
|
799
|
+
ValueError: number of images must equal number of generators
|
|
800
|
+
"""
|
|
801
|
+
return len(im_gens) == self.__ngens
|
|
802
|
+
|
|
803
|
+
def gen(self, i):
|
|
804
|
+
"""
|
|
805
|
+
The ``i``-th generator of the algebra.
|
|
806
|
+
|
|
807
|
+
EXAMPLES::
|
|
808
|
+
|
|
809
|
+
sage: F = FreeAlgebra(ZZ,3,'x,y,z')
|
|
810
|
+
sage: F.gen(0)
|
|
811
|
+
x
|
|
812
|
+
"""
|
|
813
|
+
if i < 0 or not i < self.__ngens:
|
|
814
|
+
raise IndexError("argument i (= {}) must be between 0 and {}".format(i, self.__ngens - 1))
|
|
815
|
+
R = self.base_ring()
|
|
816
|
+
F = self._indices
|
|
817
|
+
return self.element_class(self, {F.gen(i): R.one()})
|
|
818
|
+
|
|
819
|
+
@cached_method
|
|
820
|
+
def algebra_generators(self):
|
|
821
|
+
"""
|
|
822
|
+
Return the algebra generators of ``self``.
|
|
823
|
+
|
|
824
|
+
EXAMPLES::
|
|
825
|
+
|
|
826
|
+
sage: F = FreeAlgebra(ZZ,3,'x,y,z')
|
|
827
|
+
sage: F.algebra_generators()
|
|
828
|
+
Finite family {'x': x, 'y': y, 'z': z}
|
|
829
|
+
"""
|
|
830
|
+
ret = {}
|
|
831
|
+
for i in range(self.__ngens):
|
|
832
|
+
x = self.gen(i)
|
|
833
|
+
ret[str(x)] = x
|
|
834
|
+
from sage.sets.family import Family
|
|
835
|
+
return Family(self.variable_names(), lambda i: ret[i])
|
|
836
|
+
|
|
837
|
+
@cached_method
|
|
838
|
+
def gens(self) -> tuple:
|
|
839
|
+
"""
|
|
840
|
+
Return the generators of ``self``.
|
|
841
|
+
|
|
842
|
+
EXAMPLES::
|
|
843
|
+
|
|
844
|
+
sage: F = FreeAlgebra(ZZ,3,'x,y,z')
|
|
845
|
+
sage: F.gens()
|
|
846
|
+
(x, y, z)
|
|
847
|
+
"""
|
|
848
|
+
return tuple(self.gen(i) for i in range(self.__ngens))
|
|
849
|
+
|
|
850
|
+
def degree_on_basis(self, m):
|
|
851
|
+
r"""
|
|
852
|
+
Return the degree of the basis element indexed by ``m``.
|
|
853
|
+
|
|
854
|
+
EXAMPLES::
|
|
855
|
+
|
|
856
|
+
sage: A.<a, b> = FreeAlgebra(QQ, degrees=(1, -1))
|
|
857
|
+
sage: m = A.basis().keys()[42]
|
|
858
|
+
sage: m
|
|
859
|
+
a*b*a*b^2
|
|
860
|
+
sage: A.degree_on_basis(m)
|
|
861
|
+
-1
|
|
862
|
+
sage: (a*b*a*b^2).degree()
|
|
863
|
+
-1
|
|
864
|
+
"""
|
|
865
|
+
return ZZ.sum(self._degrees[g] * e for g, e in m)
|
|
866
|
+
|
|
867
|
+
def product_on_basis(self, x, y):
|
|
868
|
+
"""
|
|
869
|
+
Return the product of the basis elements indexed by ``x`` and ``y``.
|
|
870
|
+
|
|
871
|
+
EXAMPLES::
|
|
872
|
+
|
|
873
|
+
sage: F = FreeAlgebra(ZZ,3,'x,y,z')
|
|
874
|
+
sage: I = F.basis().keys()
|
|
875
|
+
sage: x,y,z = I.gens()
|
|
876
|
+
sage: F.product_on_basis(x*y, z*y)
|
|
877
|
+
x*y*z*y
|
|
878
|
+
"""
|
|
879
|
+
return self.monomial(x * y)
|
|
880
|
+
|
|
881
|
+
def quotient(self, mons, mats=None, names=None, **args):
|
|
882
|
+
"""
|
|
883
|
+
Return a quotient algebra.
|
|
884
|
+
|
|
885
|
+
The quotient algebra is defined via the action of a free algebra
|
|
886
|
+
`A` on a (finitely generated) free module. The input for the quotient
|
|
887
|
+
algebra is a list of monomials (in the underlying monoid for `A`)
|
|
888
|
+
which form a free basis for the module of `A`, and a list of
|
|
889
|
+
matrices, which give the action of the free generators of `A` on this
|
|
890
|
+
monomial basis.
|
|
891
|
+
|
|
892
|
+
EXAMPLES:
|
|
893
|
+
|
|
894
|
+
Here is the quaternion algebra defined in terms of three generators::
|
|
895
|
+
|
|
896
|
+
sage: n = 3
|
|
897
|
+
sage: A = FreeAlgebra(QQ,n,'i')
|
|
898
|
+
sage: F = A.monoid()
|
|
899
|
+
sage: i, j, k = F.gens()
|
|
900
|
+
sage: mons = [ F(1), i, j, k ]
|
|
901
|
+
sage: M = MatrixSpace(QQ,4)
|
|
902
|
+
sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]),
|
|
903
|
+
....: M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]),
|
|
904
|
+
....: M([0,0,0,1, 0,0,-1,0, 0,1,0,0, -1,0,0,0]) ]
|
|
905
|
+
sage: H.<i,j,k> = A.quotient(mons, mats); H
|
|
906
|
+
Free algebra quotient on 3 generators ('i', 'j', 'k') and dimension 4
|
|
907
|
+
over Rational Field
|
|
908
|
+
"""
|
|
909
|
+
if mats is None:
|
|
910
|
+
return super().quotient(mons, names)
|
|
911
|
+
from . import free_algebra_quotient
|
|
912
|
+
return free_algebra_quotient.FreeAlgebraQuotient(self, mons, mats, names)
|
|
913
|
+
|
|
914
|
+
quo = quotient
|
|
915
|
+
|
|
916
|
+
def ngens(self):
|
|
917
|
+
"""
|
|
918
|
+
The number of generators of the algebra.
|
|
919
|
+
|
|
920
|
+
EXAMPLES::
|
|
921
|
+
|
|
922
|
+
sage: F = FreeAlgebra(ZZ,3,'x,y,z')
|
|
923
|
+
sage: F.ngens()
|
|
924
|
+
3
|
|
925
|
+
"""
|
|
926
|
+
return self.__ngens
|
|
927
|
+
|
|
928
|
+
def monoid(self):
|
|
929
|
+
"""
|
|
930
|
+
The free monoid of generators of the algebra.
|
|
931
|
+
|
|
932
|
+
EXAMPLES::
|
|
933
|
+
|
|
934
|
+
sage: F = FreeAlgebra(ZZ,3,'x,y,z')
|
|
935
|
+
sage: F.monoid()
|
|
936
|
+
Free monoid on 3 generators (x, y, z)
|
|
937
|
+
"""
|
|
938
|
+
return self._indices
|
|
939
|
+
|
|
940
|
+
def g_algebra(self, relations, names=None, order='degrevlex', check=True):
|
|
941
|
+
"""
|
|
942
|
+
The `G`-Algebra derived from this algebra by relations.
|
|
943
|
+
|
|
944
|
+
By default it is assumed that any two variables commute.
|
|
945
|
+
|
|
946
|
+
.. TODO::
|
|
947
|
+
|
|
948
|
+
- Coercion doesn't work yet, there is some cheating about assumptions
|
|
949
|
+
- The optional argument ``check`` controls checking the degeneracy
|
|
950
|
+
conditions. Furthermore, the default values interfere with
|
|
951
|
+
non-degeneracy conditions.
|
|
952
|
+
|
|
953
|
+
EXAMPLES::
|
|
954
|
+
|
|
955
|
+
sage: # needs sage.libs.singular
|
|
956
|
+
sage: A.<x,y,z> = FreeAlgebra(QQ,3)
|
|
957
|
+
sage: G = A.g_algebra({y*x: -x*y})
|
|
958
|
+
sage: (x,y,z) = G.gens()
|
|
959
|
+
sage: x*y
|
|
960
|
+
x*y
|
|
961
|
+
sage: y*x
|
|
962
|
+
-x*y
|
|
963
|
+
sage: z*x
|
|
964
|
+
x*z
|
|
965
|
+
sage: (x,y,z) = A.gens()
|
|
966
|
+
sage: G = A.g_algebra({y*x: -x*y + 1})
|
|
967
|
+
sage: (x,y,z) = G.gens()
|
|
968
|
+
sage: y*x
|
|
969
|
+
-x*y + 1
|
|
970
|
+
sage: (x,y,z) = A.gens()
|
|
971
|
+
sage: G = A.g_algebra({y*x: -x*y + z})
|
|
972
|
+
sage: (x,y,z) = G.gens()
|
|
973
|
+
sage: y*x
|
|
974
|
+
-x*y + z
|
|
975
|
+
|
|
976
|
+
TESTS::
|
|
977
|
+
|
|
978
|
+
sage: # needs sage.libs.singular
|
|
979
|
+
sage: S = FractionField(QQ['t'])
|
|
980
|
+
sage: t = S.gen()
|
|
981
|
+
sage: F.<x,y> = FreeAlgebra(S)
|
|
982
|
+
sage: K = F.g_algebra({y*x: -x*y + 1 + y})
|
|
983
|
+
sage: x,y = K.gens()
|
|
984
|
+
sage: 1 + t*y*x
|
|
985
|
+
(-t)*x*y + t*y + (t + 1)
|
|
986
|
+
"""
|
|
987
|
+
from sage.matrix.constructor import Matrix
|
|
988
|
+
commutative = not relations
|
|
989
|
+
|
|
990
|
+
base_ring = self.base_ring()
|
|
991
|
+
polynomial_ring = PolynomialRing(base_ring, self.gens())
|
|
992
|
+
n = self.__ngens
|
|
993
|
+
cmat = Matrix(base_ring, n)
|
|
994
|
+
dmat = Matrix(polynomial_ring, n)
|
|
995
|
+
for i in range(n):
|
|
996
|
+
for j in range(i + 1, n):
|
|
997
|
+
cmat[i, j] = 1
|
|
998
|
+
for to_commute, commuted in relations.items():
|
|
999
|
+
# This is dirty, coercion is broken
|
|
1000
|
+
assert isinstance(to_commute, FreeAlgebraElement), to_commute
|
|
1001
|
+
assert isinstance(commuted, FreeAlgebraElement), commuted
|
|
1002
|
+
(v1, e1), (v2, e2) = next(iter(to_commute))[0]
|
|
1003
|
+
assert e1 == 1
|
|
1004
|
+
assert e2 == 1
|
|
1005
|
+
assert v1 > v2
|
|
1006
|
+
c_coef = None
|
|
1007
|
+
d_poly = None
|
|
1008
|
+
reverse_monomial = v2 * v1
|
|
1009
|
+
for m, c in commuted:
|
|
1010
|
+
if m == reverse_monomial:
|
|
1011
|
+
c_coef = c
|
|
1012
|
+
# buggy coercion workaround
|
|
1013
|
+
d_poly = commuted - c * self.monomial(m)
|
|
1014
|
+
break
|
|
1015
|
+
assert c_coef is not None, m
|
|
1016
|
+
v2_ind = self.gens().index(v2)
|
|
1017
|
+
v1_ind = self.gens().index(v1)
|
|
1018
|
+
cmat[v2_ind, v1_ind] = c_coef
|
|
1019
|
+
if d_poly:
|
|
1020
|
+
dmat[v2_ind, v1_ind] = polynomial_ring(d_poly)
|
|
1021
|
+
from sage.rings.polynomial.plural import g_Algebra
|
|
1022
|
+
return g_Algebra(base_ring, cmat, dmat,
|
|
1023
|
+
names=names or self.variable_names(),
|
|
1024
|
+
order=order, check=check, commutative=commutative)
|
|
1025
|
+
|
|
1026
|
+
def poincare_birkhoff_witt_basis(self):
|
|
1027
|
+
"""
|
|
1028
|
+
Return the Poincaré-Birkhoff-Witt (PBW) basis of ``self``.
|
|
1029
|
+
|
|
1030
|
+
EXAMPLES::
|
|
1031
|
+
|
|
1032
|
+
sage: F.<x,y> = FreeAlgebra(QQ, 2)
|
|
1033
|
+
sage: F.poincare_birkhoff_witt_basis()
|
|
1034
|
+
The Poincare-Birkhoff-Witt basis of Free Algebra on 2 generators (x, y) over Rational Field
|
|
1035
|
+
"""
|
|
1036
|
+
return PBWBasisOfFreeAlgebra(self)
|
|
1037
|
+
|
|
1038
|
+
pbw_basis = poincare_birkhoff_witt_basis
|
|
1039
|
+
|
|
1040
|
+
def pbw_element(self, elt):
|
|
1041
|
+
"""
|
|
1042
|
+
Return the element ``elt`` in the Poincaré-Birkhoff-Witt basis.
|
|
1043
|
+
|
|
1044
|
+
EXAMPLES::
|
|
1045
|
+
|
|
1046
|
+
sage: F.<x,y> = FreeAlgebra(QQ, 2)
|
|
1047
|
+
sage: F.pbw_element(x*y - y*x + 2)
|
|
1048
|
+
2*PBW[1] + PBW[x*y]
|
|
1049
|
+
sage: F.pbw_element(F.one())
|
|
1050
|
+
PBW[1]
|
|
1051
|
+
sage: F.pbw_element(x*y*x + x^3*y)
|
|
1052
|
+
PBW[x*y]*PBW[x] + PBW[y]*PBW[x]^2 + PBW[x^3*y]
|
|
1053
|
+
+ 3*PBW[x^2*y]*PBW[x] + 3*PBW[x*y]*PBW[x]^2 + PBW[y]*PBW[x]^3
|
|
1054
|
+
"""
|
|
1055
|
+
PBW = self.pbw_basis()
|
|
1056
|
+
if elt == self.zero():
|
|
1057
|
+
return PBW.zero()
|
|
1058
|
+
|
|
1059
|
+
l = {}
|
|
1060
|
+
while elt: # != 0
|
|
1061
|
+
lst = list(elt)
|
|
1062
|
+
support = [i[0].to_word() for i in lst]
|
|
1063
|
+
min_elt = support[0]
|
|
1064
|
+
for word in support[1:len(support) - 1]:
|
|
1065
|
+
if min_elt.lex_less(word):
|
|
1066
|
+
min_elt = word
|
|
1067
|
+
coeff = lst[support.index(min_elt)][1]
|
|
1068
|
+
min_elt = min_elt.to_monoid_element()
|
|
1069
|
+
l[min_elt] = l.get(min_elt, 0) + coeff
|
|
1070
|
+
elt = elt - coeff * self.lie_polynomial(min_elt)
|
|
1071
|
+
return PBW.sum_of_terms([(k, v) for k, v in l.items() if v != 0], distinct=True)
|
|
1072
|
+
|
|
1073
|
+
def lie_polynomial(self, w):
|
|
1074
|
+
"""
|
|
1075
|
+
Return the Lie polynomial associated to the Lyndon word ``w``. If
|
|
1076
|
+
``w`` is not Lyndon, then return the product of Lie polynomials of
|
|
1077
|
+
the Lyndon factorization of ``w``.
|
|
1078
|
+
|
|
1079
|
+
Given a Lyndon word `w`, the Lie polynomial `L_w` is defined
|
|
1080
|
+
recursively by `L_w = [L_u, L_v]`, where `w = uv` is the
|
|
1081
|
+
:meth:`standard factorization
|
|
1082
|
+
<sage.combinat.words.finite_word.FiniteWord_class.standard_factorization>`
|
|
1083
|
+
of `w`, and `L_w = w` when `w` is a single letter.
|
|
1084
|
+
|
|
1085
|
+
INPUT:
|
|
1086
|
+
|
|
1087
|
+
- ``w`` -- a word or an element of the free monoid
|
|
1088
|
+
|
|
1089
|
+
EXAMPLES::
|
|
1090
|
+
|
|
1091
|
+
sage: F = FreeAlgebra(QQ, 3, 'x,y,z')
|
|
1092
|
+
sage: M.<x,y,z> = FreeMonoid(3)
|
|
1093
|
+
sage: F.lie_polynomial(x*y)
|
|
1094
|
+
x*y - y*x
|
|
1095
|
+
sage: F.lie_polynomial(y*x)
|
|
1096
|
+
y*x
|
|
1097
|
+
sage: F.lie_polynomial(x^2*y*x)
|
|
1098
|
+
x^2*y*x - 2*x*y*x^2 + y*x^3
|
|
1099
|
+
sage: F.lie_polynomial(y*z*x*z*x*z)
|
|
1100
|
+
y*z*x*z*x*z - y*z*x*z^2*x - y*z^2*x^2*z + y*z^2*x*z*x
|
|
1101
|
+
- z*y*x*z*x*z + z*y*x*z^2*x + z*y*z*x^2*z - z*y*z*x*z*x
|
|
1102
|
+
|
|
1103
|
+
TESTS:
|
|
1104
|
+
|
|
1105
|
+
We test some corner cases and alternative inputs::
|
|
1106
|
+
|
|
1107
|
+
sage: F = FreeAlgebra(QQ, 3, 'x,y,z')
|
|
1108
|
+
sage: M.<x,y,z> = FreeMonoid(3)
|
|
1109
|
+
sage: F.lie_polynomial(Word('xy'))
|
|
1110
|
+
x*y - y*x
|
|
1111
|
+
sage: F.lie_polynomial('xy')
|
|
1112
|
+
x*y - y*x
|
|
1113
|
+
sage: F.lie_polynomial(M.one())
|
|
1114
|
+
1
|
|
1115
|
+
sage: F.lie_polynomial(Word([]))
|
|
1116
|
+
1
|
|
1117
|
+
sage: F.lie_polynomial('')
|
|
1118
|
+
1
|
|
1119
|
+
|
|
1120
|
+
We check that :issue:`22251` is fixed::
|
|
1121
|
+
|
|
1122
|
+
sage: F.lie_polynomial(x*y*z)
|
|
1123
|
+
x*y*z - x*z*y - y*z*x + z*y*x
|
|
1124
|
+
"""
|
|
1125
|
+
if not w:
|
|
1126
|
+
return self.one()
|
|
1127
|
+
M = self._indices
|
|
1128
|
+
|
|
1129
|
+
if len(w) == 1:
|
|
1130
|
+
return self(M(w))
|
|
1131
|
+
|
|
1132
|
+
ret = self.one()
|
|
1133
|
+
# We have to be careful about order here.
|
|
1134
|
+
# Since the Lyndon factors appear from left to right
|
|
1135
|
+
# we must multiply from left to right as well.
|
|
1136
|
+
for factor in Word(w).lyndon_factorization():
|
|
1137
|
+
if len(factor) == 1:
|
|
1138
|
+
ret = ret * self(M(factor))
|
|
1139
|
+
continue
|
|
1140
|
+
x, y = factor.standard_factorization()
|
|
1141
|
+
x = self.lie_polynomial(M(x))
|
|
1142
|
+
y = self.lie_polynomial(M(y))
|
|
1143
|
+
ret = ret * (x * y - y * x)
|
|
1144
|
+
return ret
|
|
1145
|
+
|
|
1146
|
+
|
|
1147
|
+
class PBWBasisOfFreeAlgebra(CombinatorialFreeModule):
|
|
1148
|
+
"""
|
|
1149
|
+
The Poincaré-Birkhoff-Witt basis of the free algebra.
|
|
1150
|
+
|
|
1151
|
+
EXAMPLES::
|
|
1152
|
+
|
|
1153
|
+
sage: F.<x,y> = FreeAlgebra(QQ, 2)
|
|
1154
|
+
sage: PBW = F.pbw_basis()
|
|
1155
|
+
sage: px, py = PBW.gens()
|
|
1156
|
+
sage: px * py
|
|
1157
|
+
PBW[x*y] + PBW[y]*PBW[x]
|
|
1158
|
+
sage: py * px
|
|
1159
|
+
PBW[y]*PBW[x]
|
|
1160
|
+
sage: px * py^3 * px - 2*px * py
|
|
1161
|
+
-2*PBW[x*y] - 2*PBW[y]*PBW[x] + PBW[x*y^3]*PBW[x]
|
|
1162
|
+
+ 3*PBW[y]*PBW[x*y^2]*PBW[x] + 3*PBW[y]^2*PBW[x*y]*PBW[x]
|
|
1163
|
+
+ PBW[y]^3*PBW[x]^2
|
|
1164
|
+
|
|
1165
|
+
We can convert between the two bases::
|
|
1166
|
+
|
|
1167
|
+
sage: p = PBW(x*y - y*x + 2); p
|
|
1168
|
+
2*PBW[1] + PBW[x*y]
|
|
1169
|
+
sage: F(p)
|
|
1170
|
+
2 + x*y - y*x
|
|
1171
|
+
sage: f = F.pbw_element(x*y*x + x^3*y + x + 3)
|
|
1172
|
+
sage: F(PBW(f)) == f
|
|
1173
|
+
True
|
|
1174
|
+
sage: p = px*py + py^4*px^2
|
|
1175
|
+
sage: F(p)
|
|
1176
|
+
x*y + y^4*x^2
|
|
1177
|
+
sage: PBW(F(p)) == p
|
|
1178
|
+
True
|
|
1179
|
+
|
|
1180
|
+
Note that multiplication in the PBW basis agrees with multiplication
|
|
1181
|
+
as monomials::
|
|
1182
|
+
|
|
1183
|
+
sage: F(px * py^3 * px - 2*px * py) == x*y^3*x - 2*x*y
|
|
1184
|
+
True
|
|
1185
|
+
|
|
1186
|
+
We verify Examples 1 and 2 in [MR1989]_::
|
|
1187
|
+
|
|
1188
|
+
sage: F.<x,y,z> = FreeAlgebra(QQ)
|
|
1189
|
+
sage: PBW = F.pbw_basis()
|
|
1190
|
+
sage: PBW(x*y*z)
|
|
1191
|
+
PBW[x*y*z] + PBW[x*z*y] + PBW[y]*PBW[x*z] + PBW[y*z]*PBW[x]
|
|
1192
|
+
+ PBW[z]*PBW[x*y] + PBW[z]*PBW[y]*PBW[x]
|
|
1193
|
+
sage: PBW(x*y*y*x)
|
|
1194
|
+
PBW[x*y^2]*PBW[x] + 2*PBW[y]*PBW[x*y]*PBW[x] + PBW[y]^2*PBW[x]^2
|
|
1195
|
+
|
|
1196
|
+
TESTS:
|
|
1197
|
+
|
|
1198
|
+
Check that going between the two bases is the identity::
|
|
1199
|
+
|
|
1200
|
+
sage: F = FreeAlgebra(QQ, 2, 'x,y')
|
|
1201
|
+
sage: PBW = F.pbw_basis()
|
|
1202
|
+
sage: M = F.monoid()
|
|
1203
|
+
sage: L = [j.to_monoid_element() for i in range(6) for j in Words('xy', i)]
|
|
1204
|
+
sage: all(PBW(F(PBW(m))) == PBW(m) for m in L)
|
|
1205
|
+
True
|
|
1206
|
+
sage: all(F(PBW(F(m))) == F(m) for m in L)
|
|
1207
|
+
True
|
|
1208
|
+
"""
|
|
1209
|
+
@staticmethod
|
|
1210
|
+
def __classcall_private__(cls, R, n=None, names=None):
|
|
1211
|
+
"""
|
|
1212
|
+
Normalize input to ensure a unique representation.
|
|
1213
|
+
|
|
1214
|
+
EXAMPLES::
|
|
1215
|
+
|
|
1216
|
+
sage: from sage.algebras.free_algebra import PBWBasisOfFreeAlgebra
|
|
1217
|
+
sage: PBW1 = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
|
|
1218
|
+
sage: PBW2.<x,y> = PBWBasisOfFreeAlgebra(QQ)
|
|
1219
|
+
sage: PBW3 = PBWBasisOfFreeAlgebra(QQ, 2, ['x','y'])
|
|
1220
|
+
sage: PBW1 is PBW2 and PBW2 is PBW3
|
|
1221
|
+
True
|
|
1222
|
+
"""
|
|
1223
|
+
if n is None and names is None:
|
|
1224
|
+
if not isinstance(R, FreeAlgebra_generic):
|
|
1225
|
+
raise ValueError("{} is not a free algebra".format(R))
|
|
1226
|
+
alg = R
|
|
1227
|
+
else:
|
|
1228
|
+
if n is None:
|
|
1229
|
+
n = len(names)
|
|
1230
|
+
alg = FreeAlgebra(R, n, names)
|
|
1231
|
+
return super().__classcall__(cls, alg)
|
|
1232
|
+
|
|
1233
|
+
def __init__(self, alg):
|
|
1234
|
+
"""
|
|
1235
|
+
Initialize ``self``.
|
|
1236
|
+
|
|
1237
|
+
EXAMPLES::
|
|
1238
|
+
|
|
1239
|
+
sage: PBW = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
|
|
1240
|
+
sage: TestSuite(PBW).run()
|
|
1241
|
+
"""
|
|
1242
|
+
R = alg.base_ring()
|
|
1243
|
+
self._alg = alg
|
|
1244
|
+
category = AlgebrasWithBasis(R)
|
|
1245
|
+
CombinatorialFreeModule.__init__(self, R, alg.monoid(), prefix='PBW',
|
|
1246
|
+
category=category)
|
|
1247
|
+
self._assign_names(alg.variable_names())
|
|
1248
|
+
|
|
1249
|
+
def _repr_(self):
|
|
1250
|
+
"""
|
|
1251
|
+
Return a string representation of ``self``.
|
|
1252
|
+
|
|
1253
|
+
EXAMPLES::
|
|
1254
|
+
|
|
1255
|
+
sage: FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
|
|
1256
|
+
The Poincare-Birkhoff-Witt basis of Free Algebra on 2 generators (x, y) over Rational Field
|
|
1257
|
+
"""
|
|
1258
|
+
return "The Poincare-Birkhoff-Witt basis of {}".format(self._alg)
|
|
1259
|
+
|
|
1260
|
+
def _repr_term(self, w):
|
|
1261
|
+
"""
|
|
1262
|
+
Return a representation of term indexed by ``w``.
|
|
1263
|
+
|
|
1264
|
+
EXAMPLES::
|
|
1265
|
+
|
|
1266
|
+
sage: PBW = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
|
|
1267
|
+
sage: x,y = PBW.gens()
|
|
1268
|
+
sage: x*y # indirect doctest
|
|
1269
|
+
PBW[x*y] + PBW[y]*PBW[x]
|
|
1270
|
+
sage: y*x
|
|
1271
|
+
PBW[y]*PBW[x]
|
|
1272
|
+
sage: x^3
|
|
1273
|
+
PBW[x]^3
|
|
1274
|
+
sage: PBW.one()
|
|
1275
|
+
PBW[1]
|
|
1276
|
+
sage: 3*PBW.one()
|
|
1277
|
+
3*PBW[1]
|
|
1278
|
+
"""
|
|
1279
|
+
if len(w) == 0:
|
|
1280
|
+
return super()._repr_term(w)
|
|
1281
|
+
ret = ''
|
|
1282
|
+
p = 1
|
|
1283
|
+
cur = None
|
|
1284
|
+
for x in w.to_word().lyndon_factorization():
|
|
1285
|
+
if x == cur:
|
|
1286
|
+
p += 1
|
|
1287
|
+
else:
|
|
1288
|
+
if len(ret) != 0:
|
|
1289
|
+
if p != 1:
|
|
1290
|
+
ret += "^{}".format(p)
|
|
1291
|
+
ret += "*"
|
|
1292
|
+
ret += super()._repr_term(x.to_monoid_element())
|
|
1293
|
+
cur = x
|
|
1294
|
+
p = 1
|
|
1295
|
+
if p != 1:
|
|
1296
|
+
ret += "^{}".format(p)
|
|
1297
|
+
return ret
|
|
1298
|
+
|
|
1299
|
+
def _element_constructor_(self, x):
|
|
1300
|
+
"""
|
|
1301
|
+
Convert ``x`` into ``self``.
|
|
1302
|
+
|
|
1303
|
+
EXAMPLES::
|
|
1304
|
+
|
|
1305
|
+
sage: F.<x,y> = FreeAlgebra(QQ, 2)
|
|
1306
|
+
sage: R = F.pbw_basis()
|
|
1307
|
+
sage: R(3)
|
|
1308
|
+
3*PBW[1]
|
|
1309
|
+
sage: R(x*y)
|
|
1310
|
+
PBW[x*y] + PBW[y]*PBW[x]
|
|
1311
|
+
"""
|
|
1312
|
+
if isinstance(x, FreeAlgebraElement):
|
|
1313
|
+
return self._alg.pbw_element(self._alg(x))
|
|
1314
|
+
return CombinatorialFreeModule._element_constructor_(self, x)
|
|
1315
|
+
|
|
1316
|
+
def _coerce_map_from_(self, R):
|
|
1317
|
+
"""
|
|
1318
|
+
Return ``True`` if there is a coercion from ``R`` into ``self`` and
|
|
1319
|
+
``False`` otherwise. The things that coerce into ``self`` are:
|
|
1320
|
+
|
|
1321
|
+
- Anything that coerces into the associated free algebra of ``self``
|
|
1322
|
+
|
|
1323
|
+
TESTS::
|
|
1324
|
+
|
|
1325
|
+
sage: F = FreeAlgebra(ZZ, 3, 'x,y,z').pbw_basis()
|
|
1326
|
+
sage: G = FreeAlgebra(QQ, 3, 'x,y,z').pbw_basis()
|
|
1327
|
+
sage: H = FreeAlgebra(ZZ, 1, 'y').pbw_basis()
|
|
1328
|
+
sage: F._coerce_map_from_(G)
|
|
1329
|
+
False
|
|
1330
|
+
sage: G._coerce_map_from_(F)
|
|
1331
|
+
True
|
|
1332
|
+
sage: F._coerce_map_from_(H)
|
|
1333
|
+
True
|
|
1334
|
+
sage: F._coerce_map_from_(QQ)
|
|
1335
|
+
False
|
|
1336
|
+
sage: G._coerce_map_from_(QQ)
|
|
1337
|
+
True
|
|
1338
|
+
sage: F._coerce_map_from_(G._alg.monoid())
|
|
1339
|
+
True
|
|
1340
|
+
sage: F.has_coerce_map_from(PolynomialRing(ZZ, 3, 'x,y,z'))
|
|
1341
|
+
False
|
|
1342
|
+
sage: F.has_coerce_map_from(FreeAlgebra(ZZ, 3, 'x,y,z'))
|
|
1343
|
+
True
|
|
1344
|
+
"""
|
|
1345
|
+
return self._alg.has_coerce_map_from(R)
|
|
1346
|
+
|
|
1347
|
+
def one_basis(self):
|
|
1348
|
+
"""
|
|
1349
|
+
Return the index of the basis element for `1`.
|
|
1350
|
+
|
|
1351
|
+
EXAMPLES::
|
|
1352
|
+
|
|
1353
|
+
sage: PBW = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
|
|
1354
|
+
sage: PBW.one_basis()
|
|
1355
|
+
1
|
|
1356
|
+
sage: PBW.one_basis().parent()
|
|
1357
|
+
Free monoid on 2 generators (x, y)
|
|
1358
|
+
"""
|
|
1359
|
+
return self._indices.one()
|
|
1360
|
+
|
|
1361
|
+
def algebra_generators(self):
|
|
1362
|
+
"""
|
|
1363
|
+
Return the generators of ``self`` as an algebra.
|
|
1364
|
+
|
|
1365
|
+
EXAMPLES::
|
|
1366
|
+
|
|
1367
|
+
sage: PBW = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
|
|
1368
|
+
sage: gens = PBW.algebra_generators(); gens
|
|
1369
|
+
(PBW[x], PBW[y])
|
|
1370
|
+
sage: all(g.parent() is PBW for g in gens)
|
|
1371
|
+
True
|
|
1372
|
+
"""
|
|
1373
|
+
return tuple(self.monomial(x) for x in self._indices.gens())
|
|
1374
|
+
|
|
1375
|
+
gens = algebra_generators
|
|
1376
|
+
|
|
1377
|
+
def gen(self, i):
|
|
1378
|
+
"""
|
|
1379
|
+
Return the ``i``-th generator of ``self``.
|
|
1380
|
+
|
|
1381
|
+
EXAMPLES::
|
|
1382
|
+
|
|
1383
|
+
sage: PBW = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
|
|
1384
|
+
sage: PBW.gen(0)
|
|
1385
|
+
PBW[x]
|
|
1386
|
+
sage: PBW.gen(1)
|
|
1387
|
+
PBW[y]
|
|
1388
|
+
"""
|
|
1389
|
+
return self.algebra_generators()[i]
|
|
1390
|
+
|
|
1391
|
+
def free_algebra(self):
|
|
1392
|
+
"""
|
|
1393
|
+
Return the associated free algebra of ``self``.
|
|
1394
|
+
|
|
1395
|
+
EXAMPLES::
|
|
1396
|
+
|
|
1397
|
+
sage: PBW = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
|
|
1398
|
+
sage: PBW.free_algebra()
|
|
1399
|
+
Free Algebra on 2 generators (x, y) over Rational Field
|
|
1400
|
+
"""
|
|
1401
|
+
return self._alg
|
|
1402
|
+
|
|
1403
|
+
def product(self, u, v):
|
|
1404
|
+
"""
|
|
1405
|
+
Return the product of two elements ``u`` and ``v``.
|
|
1406
|
+
|
|
1407
|
+
EXAMPLES::
|
|
1408
|
+
|
|
1409
|
+
sage: F = FreeAlgebra(QQ, 2, 'x,y')
|
|
1410
|
+
sage: PBW = F.pbw_basis()
|
|
1411
|
+
sage: x, y = PBW.gens()
|
|
1412
|
+
sage: PBW.product(x, y)
|
|
1413
|
+
PBW[x*y] + PBW[y]*PBW[x]
|
|
1414
|
+
sage: PBW.product(y, x)
|
|
1415
|
+
PBW[y]*PBW[x]
|
|
1416
|
+
sage: PBW.product(y^2*x, x*y*x)
|
|
1417
|
+
PBW[y]^2*PBW[x^2*y]*PBW[x] + 2*PBW[y]^2*PBW[x*y]*PBW[x]^2 + PBW[y]^3*PBW[x]^3
|
|
1418
|
+
|
|
1419
|
+
TESTS:
|
|
1420
|
+
|
|
1421
|
+
Check that multiplication agrees with the multiplication in the
|
|
1422
|
+
free algebra::
|
|
1423
|
+
|
|
1424
|
+
sage: F = FreeAlgebra(QQ, 2, 'x,y')
|
|
1425
|
+
sage: PBW = F.pbw_basis()
|
|
1426
|
+
sage: x, y = PBW.gens()
|
|
1427
|
+
sage: F(x*y)
|
|
1428
|
+
x*y
|
|
1429
|
+
sage: F(x*y*x)
|
|
1430
|
+
x*y*x
|
|
1431
|
+
sage: PBW(F(x)*F(y)*F(x)) == x*y*x
|
|
1432
|
+
True
|
|
1433
|
+
"""
|
|
1434
|
+
return self(self.expansion(u) * self.expansion(v))
|
|
1435
|
+
|
|
1436
|
+
def expansion(self, t):
|
|
1437
|
+
"""
|
|
1438
|
+
Return the expansion of the element ``t`` of the Poincaré-Birkhoff-Witt
|
|
1439
|
+
basis in the monomials of the free algebra.
|
|
1440
|
+
|
|
1441
|
+
EXAMPLES::
|
|
1442
|
+
|
|
1443
|
+
sage: F = FreeAlgebra(QQ, 2, 'x,y')
|
|
1444
|
+
sage: PBW = F.pbw_basis()
|
|
1445
|
+
sage: x,y = F.monoid().gens()
|
|
1446
|
+
sage: PBW.expansion(PBW(x*y))
|
|
1447
|
+
x*y - y*x
|
|
1448
|
+
sage: PBW.expansion(PBW.one())
|
|
1449
|
+
1
|
|
1450
|
+
sage: PBW.expansion(PBW(x*y*x) + 2*PBW(x) + 3)
|
|
1451
|
+
3 + 2*x + x*y*x - y*x^2
|
|
1452
|
+
|
|
1453
|
+
TESTS:
|
|
1454
|
+
|
|
1455
|
+
Check that we have the correct parent::
|
|
1456
|
+
|
|
1457
|
+
sage: PBW.expansion(PBW(x*y)).parent() is F
|
|
1458
|
+
True
|
|
1459
|
+
sage: PBW.expansion(PBW.one()).parent() is F
|
|
1460
|
+
True
|
|
1461
|
+
"""
|
|
1462
|
+
return sum([i[1] * self._alg.lie_polynomial(i[0]) for i in list(t)],
|
|
1463
|
+
self._alg.zero())
|
|
1464
|
+
|
|
1465
|
+
class Element(CombinatorialFreeModule.Element):
|
|
1466
|
+
def expand(self):
|
|
1467
|
+
"""
|
|
1468
|
+
Expand ``self`` in the monomials of the free algebra.
|
|
1469
|
+
|
|
1470
|
+
EXAMPLES::
|
|
1471
|
+
|
|
1472
|
+
sage: F = FreeAlgebra(QQ, 2, 'x,y')
|
|
1473
|
+
sage: PBW = F.pbw_basis()
|
|
1474
|
+
sage: x,y = F.monoid().gens()
|
|
1475
|
+
sage: f = PBW(x^2*y) + PBW(x) + PBW(y^4*x)
|
|
1476
|
+
sage: f.expand()
|
|
1477
|
+
x + x^2*y - 2*x*y*x + y*x^2 + y^4*x
|
|
1478
|
+
"""
|
|
1479
|
+
return self.parent().expansion(self)
|
|
1480
|
+
|
|
1481
|
+
|
|
1482
|
+
class AssociativeFunctor(ConstructionFunctor):
|
|
1483
|
+
"""
|
|
1484
|
+
A constructor for free associative algebras.
|
|
1485
|
+
|
|
1486
|
+
EXAMPLES::
|
|
1487
|
+
|
|
1488
|
+
sage: P = algebras.Free(ZZ, 2, 'x,y')
|
|
1489
|
+
sage: x,y = P.gens()
|
|
1490
|
+
sage: F = P.construction()[0]; F
|
|
1491
|
+
Associative[x,y]
|
|
1492
|
+
|
|
1493
|
+
sage: A = GF(5)['a,b']
|
|
1494
|
+
sage: a, b = A.gens()
|
|
1495
|
+
sage: F(A)
|
|
1496
|
+
Free Algebra on 2 generators (x, y) over Multivariate Polynomial Ring in a, b over Finite Field of size 5
|
|
1497
|
+
|
|
1498
|
+
sage: f = A.hom([a+b,a-b],A)
|
|
1499
|
+
sage: F(f)
|
|
1500
|
+
Generic endomorphism of Free Algebra on 2 generators (x, y)
|
|
1501
|
+
over Multivariate Polynomial Ring in a, b over Finite Field of size 5
|
|
1502
|
+
|
|
1503
|
+
sage: F(f)(a * F(A)(x))
|
|
1504
|
+
(a+b)*x
|
|
1505
|
+
"""
|
|
1506
|
+
rank = 9
|
|
1507
|
+
|
|
1508
|
+
def __init__(self, vars, degs=None):
|
|
1509
|
+
"""
|
|
1510
|
+
EXAMPLES::
|
|
1511
|
+
|
|
1512
|
+
sage: from sage.algebras.free_algebra import AssociativeFunctor
|
|
1513
|
+
sage: F = AssociativeFunctor(['x','y'])
|
|
1514
|
+
sage: F
|
|
1515
|
+
Associative[x,y]
|
|
1516
|
+
sage: F(ZZ)
|
|
1517
|
+
Free Algebra on 2 generators (x, y) over Integer Ring
|
|
1518
|
+
"""
|
|
1519
|
+
Functor.__init__(self, Rings(), Rings())
|
|
1520
|
+
if not isinstance(vars, (list, tuple)):
|
|
1521
|
+
raise TypeError("vars must be a list or tuple")
|
|
1522
|
+
if degs is not None and not isinstance(degs, (list, tuple, dict)):
|
|
1523
|
+
raise TypeError("degs must be a list, tuple or dict")
|
|
1524
|
+
self.vars = vars
|
|
1525
|
+
self.degs = degs
|
|
1526
|
+
|
|
1527
|
+
def _apply_functor(self, R):
|
|
1528
|
+
"""
|
|
1529
|
+
Apply the functor to an object of ``self``'s domain.
|
|
1530
|
+
|
|
1531
|
+
EXAMPLES::
|
|
1532
|
+
|
|
1533
|
+
sage: R = algebras.Free(ZZ, 3, 'x,y,z')
|
|
1534
|
+
sage: F = R.construction()[0]; F
|
|
1535
|
+
Associative[x,y,z]
|
|
1536
|
+
sage: type(F)
|
|
1537
|
+
<class 'sage.algebras.free_algebra.AssociativeFunctor'>
|
|
1538
|
+
sage: F(ZZ) # indirect doctest
|
|
1539
|
+
Free Algebra on 3 generators (x, y, z) over Integer Ring
|
|
1540
|
+
"""
|
|
1541
|
+
return FreeAlgebra(R, self.vars, self.degs)
|
|
1542
|
+
|
|
1543
|
+
def _apply_functor_to_morphism(self, f):
|
|
1544
|
+
"""
|
|
1545
|
+
Apply the functor ``self`` to the ring morphism `f`.
|
|
1546
|
+
|
|
1547
|
+
TESTS::
|
|
1548
|
+
|
|
1549
|
+
sage: R = algebras.Free(ZZ, 'x').construction()[0]
|
|
1550
|
+
sage: R(ZZ.hom(GF(3))) # indirect doctest
|
|
1551
|
+
Generic morphism:
|
|
1552
|
+
From: Free Algebra on 1 generator (x,) over Integer Ring
|
|
1553
|
+
To: Free Algebra on 1 generator (x,) over Finite Field of size 3
|
|
1554
|
+
"""
|
|
1555
|
+
dom = self(f.domain())
|
|
1556
|
+
codom = self(f.codomain())
|
|
1557
|
+
|
|
1558
|
+
def action(x):
|
|
1559
|
+
return codom._from_dict({a: f(b)
|
|
1560
|
+
for a, b in x.monomial_coefficients().items()})
|
|
1561
|
+
return dom.module_morphism(function=action, codomain=codom)
|
|
1562
|
+
|
|
1563
|
+
def __eq__(self, other):
|
|
1564
|
+
"""
|
|
1565
|
+
EXAMPLES::
|
|
1566
|
+
|
|
1567
|
+
sage: F = algebras.Free(ZZ, 3, 'x,y,z').construction()[0]
|
|
1568
|
+
sage: G = algebras.Free(QQ, 3, 'x,y,z').construction()[0]
|
|
1569
|
+
sage: F == G
|
|
1570
|
+
True
|
|
1571
|
+
sage: G == loads(dumps(G))
|
|
1572
|
+
True
|
|
1573
|
+
sage: G = algebras.Free(QQ, 2, 'x,y').construction()[0]
|
|
1574
|
+
sage: F == G
|
|
1575
|
+
False
|
|
1576
|
+
"""
|
|
1577
|
+
if not isinstance(other, AssociativeFunctor):
|
|
1578
|
+
return False
|
|
1579
|
+
return self.vars == other.vars and self.degs == other.degs
|
|
1580
|
+
|
|
1581
|
+
def __mul__(self, other):
|
|
1582
|
+
"""
|
|
1583
|
+
If two Associative functors are given in a row, form a single Associative functor
|
|
1584
|
+
with all of the variables.
|
|
1585
|
+
|
|
1586
|
+
EXAMPLES::
|
|
1587
|
+
|
|
1588
|
+
sage: from sage.algebras.free_algebra import AssociativeFunctor
|
|
1589
|
+
sage: F = AssociativeFunctor(['x','y'])
|
|
1590
|
+
sage: G = AssociativeFunctor(['t'])
|
|
1591
|
+
sage: G * F
|
|
1592
|
+
Associative[x,y,t]
|
|
1593
|
+
"""
|
|
1594
|
+
if isinstance(other, IdentityConstructionFunctor):
|
|
1595
|
+
return self
|
|
1596
|
+
if isinstance(other, AssociativeFunctor):
|
|
1597
|
+
if set(self.vars).intersection(other.vars):
|
|
1598
|
+
raise CoercionException("Overlapping variables (%s,%s)" %
|
|
1599
|
+
(self.vars, other.vars))
|
|
1600
|
+
return AssociativeFunctor(other.vars + self.vars)
|
|
1601
|
+
elif (isinstance(other, CompositeConstructionFunctor) and
|
|
1602
|
+
isinstance(other.all[-1], AssociativeFunctor)):
|
|
1603
|
+
return CompositeConstructionFunctor(other.all[:-1],
|
|
1604
|
+
self * other.all[-1])
|
|
1605
|
+
else:
|
|
1606
|
+
return CompositeConstructionFunctor(other, self)
|
|
1607
|
+
|
|
1608
|
+
def merge(self, other):
|
|
1609
|
+
"""
|
|
1610
|
+
Merge ``self`` with another construction functor, or return ``None``.
|
|
1611
|
+
|
|
1612
|
+
EXAMPLES::
|
|
1613
|
+
|
|
1614
|
+
sage: from sage.algebras.free_algebra import AssociativeFunctor
|
|
1615
|
+
sage: F = AssociativeFunctor(['x','y'])
|
|
1616
|
+
sage: G = AssociativeFunctor(['t'])
|
|
1617
|
+
sage: F.merge(G)
|
|
1618
|
+
Associative[x,y,t]
|
|
1619
|
+
sage: F.merge(F)
|
|
1620
|
+
Associative[x,y]
|
|
1621
|
+
|
|
1622
|
+
With degrees::
|
|
1623
|
+
|
|
1624
|
+
sage: F = AssociativeFunctor(['x','y'], (2,3))
|
|
1625
|
+
sage: G = AssociativeFunctor(['t'], (4,))
|
|
1626
|
+
sage: H = AssociativeFunctor(['z','y'], (5,3))
|
|
1627
|
+
sage: F.merge(G)
|
|
1628
|
+
Associative[x,y,t] with degrees (2, 3, 4)
|
|
1629
|
+
sage: F.merge(H)
|
|
1630
|
+
Associative[x,y,z] with degrees (2, 3, 5)
|
|
1631
|
+
|
|
1632
|
+
Now some actual use cases::
|
|
1633
|
+
|
|
1634
|
+
sage: R = algebras.Free(ZZ, 3, 'x,y,z')
|
|
1635
|
+
sage: x,y,z = R.gens()
|
|
1636
|
+
sage: 1/2 * x
|
|
1637
|
+
1/2*x
|
|
1638
|
+
sage: parent(1/2 * x)
|
|
1639
|
+
Free Algebra on 3 generators (x, y, z) over Rational Field
|
|
1640
|
+
|
|
1641
|
+
sage: S = algebras.Free(QQ, 2, 'z,t')
|
|
1642
|
+
sage: z,t = S.gens()
|
|
1643
|
+
sage: x + t
|
|
1644
|
+
t + x
|
|
1645
|
+
sage: parent(x + t)
|
|
1646
|
+
Free Algebra on 4 generators (z, t, x, y) over Rational Field
|
|
1647
|
+
|
|
1648
|
+
TESTS::
|
|
1649
|
+
|
|
1650
|
+
sage: F = AssociativeFunctor(['x','y'], (2,3))
|
|
1651
|
+
sage: H = AssociativeFunctor(['z','y'], (5,4))
|
|
1652
|
+
sage: F.merge(H)
|
|
1653
|
+
"""
|
|
1654
|
+
if isinstance(other, AssociativeFunctor):
|
|
1655
|
+
if self.vars == other.vars and self.degs == other.degs:
|
|
1656
|
+
return self
|
|
1657
|
+
|
|
1658
|
+
ret = list(self.vars)
|
|
1659
|
+
self_vars = set(ret)
|
|
1660
|
+
ret.extend(v for v in other.vars if v not in self_vars)
|
|
1661
|
+
|
|
1662
|
+
# first case: no degrees
|
|
1663
|
+
if self.degs is None and other.degs is None:
|
|
1664
|
+
return AssociativeFunctor(tuple(ret))
|
|
1665
|
+
|
|
1666
|
+
# second case: merge the degrees
|
|
1667
|
+
if self.degs is None:
|
|
1668
|
+
deg = [1] * len(self.vars)
|
|
1669
|
+
else:
|
|
1670
|
+
deg = list(self.degs)
|
|
1671
|
+
if other.degs is None:
|
|
1672
|
+
o_degs = [1] * len(other.vars)
|
|
1673
|
+
else:
|
|
1674
|
+
o_degs = list(other.degs)
|
|
1675
|
+
self_table = dict(zip(self.vars, deg))
|
|
1676
|
+
for v, d in zip(other.vars, o_degs):
|
|
1677
|
+
if v not in self_vars:
|
|
1678
|
+
deg.append(d)
|
|
1679
|
+
elif d != self_table[v]:
|
|
1680
|
+
# incompatible degrees
|
|
1681
|
+
return None
|
|
1682
|
+
return AssociativeFunctor(tuple(ret), tuple(deg))
|
|
1683
|
+
|
|
1684
|
+
return None
|
|
1685
|
+
|
|
1686
|
+
def _repr_(self) -> str:
|
|
1687
|
+
"""
|
|
1688
|
+
TESTS::
|
|
1689
|
+
|
|
1690
|
+
sage: algebras.Free(QQ,4,'x,y,z,t').construction()[0]
|
|
1691
|
+
Associative[x,y,z,t]
|
|
1692
|
+
sage: algebras.Free(QQ,4,'x,y,z,t',degrees=(1,2,3,4)).construction()[0]
|
|
1693
|
+
Associative[x,y,z,t] with degrees {x: 1, y: 2, z: 3, t: 4}
|
|
1694
|
+
"""
|
|
1695
|
+
vars = ','.join(self.vars)
|
|
1696
|
+
if self.degs is None:
|
|
1697
|
+
return f"Associative[{vars}]"
|
|
1698
|
+
return f"Associative[{vars}] with degrees {self.degs}"
|