passagemath-modules 10.6.31rc3__cp314-cp314-musllinux_1_2_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-modules might be problematic. Click here for more details.
- passagemath_modules-10.6.31rc3.dist-info/METADATA +281 -0
- passagemath_modules-10.6.31rc3.dist-info/RECORD +807 -0
- passagemath_modules-10.6.31rc3.dist-info/WHEEL +5 -0
- passagemath_modules-10.6.31rc3.dist-info/top_level.txt +2 -0
- passagemath_modules.libs/libgcc_s-2d945d6c.so.1 +0 -0
- passagemath_modules.libs/libgfortran-67378ab2.so.5.0.0 +0 -0
- passagemath_modules.libs/libgmp-28992bcb.so.10.5.0 +0 -0
- passagemath_modules.libs/libgsl-23768756.so.28.0.0 +0 -0
- passagemath_modules.libs/libmpc-7897025b.so.3.3.1 +0 -0
- passagemath_modules.libs/libmpfr-e34bb864.so.6.2.1 +0 -0
- passagemath_modules.libs/libopenblasp-r0-503f0c35.3.29.so +0 -0
- sage/algebras/all__sagemath_modules.py +20 -0
- sage/algebras/catalog.py +148 -0
- sage/algebras/clifford_algebra.py +3107 -0
- sage/algebras/clifford_algebra_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/algebras/clifford_algebra_element.pxd +16 -0
- sage/algebras/clifford_algebra_element.pyx +997 -0
- sage/algebras/commutative_dga.py +4252 -0
- sage/algebras/exterior_algebra_groebner.cpython-314-aarch64-linux-musl.so +0 -0
- sage/algebras/exterior_algebra_groebner.pxd +55 -0
- sage/algebras/exterior_algebra_groebner.pyx +727 -0
- sage/algebras/finite_dimensional_algebras/all.py +2 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +1029 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pxd +12 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx +706 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py +196 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py +255 -0
- sage/algebras/finite_gca.py +528 -0
- sage/algebras/group_algebra.py +232 -0
- sage/algebras/lie_algebras/abelian.py +197 -0
- sage/algebras/lie_algebras/affine_lie_algebra.py +1213 -0
- sage/algebras/lie_algebras/all.py +25 -0
- sage/algebras/lie_algebras/all__sagemath_modules.py +1 -0
- sage/algebras/lie_algebras/bch.py +177 -0
- sage/algebras/lie_algebras/bgg_dual_module.py +1184 -0
- sage/algebras/lie_algebras/bgg_resolution.py +232 -0
- sage/algebras/lie_algebras/center_uea.py +767 -0
- sage/algebras/lie_algebras/classical_lie_algebra.py +2516 -0
- sage/algebras/lie_algebras/examples.py +683 -0
- sage/algebras/lie_algebras/free_lie_algebra.py +973 -0
- sage/algebras/lie_algebras/heisenberg.py +820 -0
- sage/algebras/lie_algebras/lie_algebra.py +1562 -0
- sage/algebras/lie_algebras/lie_algebra_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/algebras/lie_algebras/lie_algebra_element.pxd +68 -0
- sage/algebras/lie_algebras/lie_algebra_element.pyx +2122 -0
- sage/algebras/lie_algebras/morphism.py +661 -0
- sage/algebras/lie_algebras/nilpotent_lie_algebra.py +457 -0
- sage/algebras/lie_algebras/onsager.py +1324 -0
- sage/algebras/lie_algebras/poincare_birkhoff_witt.py +816 -0
- sage/algebras/lie_algebras/quotient.py +462 -0
- sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py +355 -0
- sage/algebras/lie_algebras/representation.py +1040 -0
- sage/algebras/lie_algebras/structure_coefficients.py +459 -0
- sage/algebras/lie_algebras/subalgebra.py +967 -0
- sage/algebras/lie_algebras/symplectic_derivation.py +289 -0
- sage/algebras/lie_algebras/verma_module.py +1630 -0
- sage/algebras/lie_algebras/virasoro.py +1186 -0
- sage/algebras/octonion_algebra.cpython-314-aarch64-linux-musl.so +0 -0
- sage/algebras/octonion_algebra.pxd +20 -0
- sage/algebras/octonion_algebra.pyx +987 -0
- sage/algebras/orlik_solomon.py +907 -0
- sage/algebras/orlik_terao.py +779 -0
- sage/algebras/steenrod/all.py +7 -0
- sage/algebras/steenrod/steenrod_algebra.py +4258 -0
- sage/algebras/steenrod/steenrod_algebra_bases.py +1179 -0
- sage/algebras/steenrod/steenrod_algebra_misc.py +1167 -0
- sage/algebras/steenrod/steenrod_algebra_mult.py +954 -0
- sage/algebras/weyl_algebra.py +1126 -0
- sage/all__sagemath_modules.py +62 -0
- sage/calculus/all__sagemath_modules.py +19 -0
- sage/calculus/expr.py +205 -0
- sage/calculus/integration.cpython-314-aarch64-linux-musl.so +0 -0
- sage/calculus/integration.pyx +698 -0
- sage/calculus/interpolation.cpython-314-aarch64-linux-musl.so +0 -0
- sage/calculus/interpolation.pxd +13 -0
- sage/calculus/interpolation.pyx +387 -0
- sage/calculus/interpolators.cpython-314-aarch64-linux-musl.so +0 -0
- sage/calculus/interpolators.pyx +326 -0
- sage/calculus/ode.cpython-314-aarch64-linux-musl.so +0 -0
- sage/calculus/ode.pxd +5 -0
- sage/calculus/ode.pyx +610 -0
- sage/calculus/riemann.cpython-314-aarch64-linux-musl.so +0 -0
- sage/calculus/riemann.pyx +1521 -0
- sage/calculus/test_sympy.py +201 -0
- sage/calculus/transforms/all.py +7 -0
- sage/calculus/transforms/dft.py +844 -0
- sage/calculus/transforms/dwt.cpython-314-aarch64-linux-musl.so +0 -0
- sage/calculus/transforms/dwt.pxd +7 -0
- sage/calculus/transforms/dwt.pyx +160 -0
- sage/calculus/transforms/fft.cpython-314-aarch64-linux-musl.so +0 -0
- sage/calculus/transforms/fft.pxd +12 -0
- sage/calculus/transforms/fft.pyx +487 -0
- sage/calculus/wester.py +662 -0
- sage/coding/abstract_code.py +1108 -0
- sage/coding/ag_code.py +868 -0
- sage/coding/ag_code_decoders.cpython-314-aarch64-linux-musl.so +0 -0
- sage/coding/ag_code_decoders.pyx +2639 -0
- sage/coding/all.py +15 -0
- sage/coding/bch_code.py +494 -0
- sage/coding/binary_code.cpython-314-aarch64-linux-musl.so +0 -0
- sage/coding/binary_code.pxd +124 -0
- sage/coding/binary_code.pyx +4139 -0
- sage/coding/bounds_catalog.py +43 -0
- sage/coding/channel.py +819 -0
- sage/coding/channels_catalog.py +29 -0
- sage/coding/code_bounds.py +755 -0
- sage/coding/code_constructions.py +804 -0
- sage/coding/codes_catalog.py +111 -0
- sage/coding/cyclic_code.py +1329 -0
- sage/coding/databases.py +316 -0
- sage/coding/decoder.py +373 -0
- sage/coding/decoders_catalog.py +88 -0
- sage/coding/delsarte_bounds.py +709 -0
- sage/coding/encoder.py +390 -0
- sage/coding/encoders_catalog.py +64 -0
- sage/coding/extended_code.py +468 -0
- sage/coding/gabidulin_code.py +1058 -0
- sage/coding/golay_code.py +404 -0
- sage/coding/goppa_code.py +441 -0
- sage/coding/grs_code.py +2371 -0
- sage/coding/guava.py +107 -0
- sage/coding/guruswami_sudan/all.py +1 -0
- sage/coding/guruswami_sudan/gs_decoder.py +897 -0
- sage/coding/guruswami_sudan/interpolation.py +409 -0
- sage/coding/guruswami_sudan/utils.py +176 -0
- sage/coding/hamming_code.py +176 -0
- sage/coding/information_set_decoder.py +1032 -0
- sage/coding/kasami_codes.cpython-314-aarch64-linux-musl.so +0 -0
- sage/coding/kasami_codes.pyx +351 -0
- sage/coding/linear_code.py +3067 -0
- sage/coding/linear_code_no_metric.py +1354 -0
- sage/coding/linear_rank_metric.py +961 -0
- sage/coding/parity_check_code.py +353 -0
- sage/coding/punctured_code.py +719 -0
- sage/coding/reed_muller_code.py +999 -0
- sage/coding/self_dual_codes.py +942 -0
- sage/coding/source_coding/all.py +2 -0
- sage/coding/source_coding/huffman.py +553 -0
- sage/coding/subfield_subcode.py +423 -0
- sage/coding/two_weight_db.py +399 -0
- sage/combinat/all__sagemath_modules.py +7 -0
- sage/combinat/cartesian_product.py +347 -0
- sage/combinat/family.py +11 -0
- sage/combinat/free_module.py +1977 -0
- sage/combinat/root_system/all.py +147 -0
- sage/combinat/root_system/ambient_space.py +527 -0
- sage/combinat/root_system/associahedron.py +471 -0
- sage/combinat/root_system/braid_move_calculator.py +143 -0
- sage/combinat/root_system/braid_orbit.cpython-314-aarch64-linux-musl.so +0 -0
- sage/combinat/root_system/braid_orbit.pyx +144 -0
- sage/combinat/root_system/branching_rules.py +2301 -0
- sage/combinat/root_system/cartan_matrix.py +1245 -0
- sage/combinat/root_system/cartan_type.py +3069 -0
- sage/combinat/root_system/coxeter_group.py +162 -0
- sage/combinat/root_system/coxeter_matrix.py +1261 -0
- sage/combinat/root_system/coxeter_type.py +681 -0
- sage/combinat/root_system/dynkin_diagram.py +900 -0
- sage/combinat/root_system/extended_affine_weyl_group.py +2993 -0
- sage/combinat/root_system/fundamental_group.py +795 -0
- sage/combinat/root_system/hecke_algebra_representation.py +1203 -0
- sage/combinat/root_system/integrable_representations.py +1227 -0
- sage/combinat/root_system/non_symmetric_macdonald_polynomials.py +1965 -0
- sage/combinat/root_system/pieri_factors.py +1147 -0
- sage/combinat/root_system/plot.py +1615 -0
- sage/combinat/root_system/root_lattice_realization_algebras.py +1214 -0
- sage/combinat/root_system/root_lattice_realizations.py +4628 -0
- sage/combinat/root_system/root_space.py +487 -0
- sage/combinat/root_system/root_system.py +882 -0
- sage/combinat/root_system/type_A.py +348 -0
- sage/combinat/root_system/type_A_affine.py +227 -0
- sage/combinat/root_system/type_A_infinity.py +241 -0
- sage/combinat/root_system/type_B.py +347 -0
- sage/combinat/root_system/type_BC_affine.py +287 -0
- sage/combinat/root_system/type_B_affine.py +216 -0
- sage/combinat/root_system/type_C.py +317 -0
- sage/combinat/root_system/type_C_affine.py +188 -0
- sage/combinat/root_system/type_D.py +357 -0
- sage/combinat/root_system/type_D_affine.py +208 -0
- sage/combinat/root_system/type_E.py +641 -0
- sage/combinat/root_system/type_E_affine.py +231 -0
- sage/combinat/root_system/type_F.py +387 -0
- sage/combinat/root_system/type_F_affine.py +137 -0
- sage/combinat/root_system/type_G.py +293 -0
- sage/combinat/root_system/type_G_affine.py +132 -0
- sage/combinat/root_system/type_H.py +105 -0
- sage/combinat/root_system/type_I.py +110 -0
- sage/combinat/root_system/type_Q.py +150 -0
- sage/combinat/root_system/type_affine.py +509 -0
- sage/combinat/root_system/type_dual.py +704 -0
- sage/combinat/root_system/type_folded.py +301 -0
- sage/combinat/root_system/type_marked.py +748 -0
- sage/combinat/root_system/type_reducible.py +601 -0
- sage/combinat/root_system/type_relabel.py +730 -0
- sage/combinat/root_system/type_super_A.py +837 -0
- sage/combinat/root_system/weight_lattice_realizations.py +1188 -0
- sage/combinat/root_system/weight_space.py +639 -0
- sage/combinat/root_system/weyl_characters.py +2238 -0
- sage/crypto/__init__.py +4 -0
- sage/crypto/all.py +28 -0
- sage/crypto/block_cipher/all.py +7 -0
- sage/crypto/block_cipher/des.py +1065 -0
- sage/crypto/block_cipher/miniaes.py +2171 -0
- sage/crypto/block_cipher/present.py +909 -0
- sage/crypto/block_cipher/sdes.py +1527 -0
- sage/crypto/boolean_function.cpython-314-aarch64-linux-musl.so +0 -0
- sage/crypto/boolean_function.pxd +10 -0
- sage/crypto/boolean_function.pyx +1487 -0
- sage/crypto/cipher.py +78 -0
- sage/crypto/classical.py +3668 -0
- sage/crypto/classical_cipher.py +569 -0
- sage/crypto/cryptosystem.py +387 -0
- sage/crypto/key_exchange/all.py +7 -0
- sage/crypto/key_exchange/catalog.py +24 -0
- sage/crypto/key_exchange/diffie_hellman.py +323 -0
- sage/crypto/key_exchange/key_exchange_scheme.py +107 -0
- sage/crypto/lattice.py +312 -0
- sage/crypto/lfsr.py +295 -0
- sage/crypto/lwe.py +840 -0
- sage/crypto/mq/__init__.py +4 -0
- sage/crypto/mq/mpolynomialsystemgenerator.py +204 -0
- sage/crypto/mq/rijndael_gf.py +2345 -0
- sage/crypto/mq/sbox.py +7 -0
- sage/crypto/mq/sr.py +3344 -0
- sage/crypto/public_key/all.py +5 -0
- sage/crypto/public_key/blum_goldwasser.py +776 -0
- sage/crypto/sbox.cpython-314-aarch64-linux-musl.so +0 -0
- sage/crypto/sbox.pyx +2090 -0
- sage/crypto/sboxes.py +2090 -0
- sage/crypto/stream.py +390 -0
- sage/crypto/stream_cipher.py +297 -0
- sage/crypto/util.py +519 -0
- sage/ext/all__sagemath_modules.py +1 -0
- sage/ext/interpreters/__init__.py +1 -0
- sage/ext/interpreters/all__sagemath_modules.py +2 -0
- sage/ext/interpreters/wrapper_cc.cpython-314-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_cc.pxd +30 -0
- sage/ext/interpreters/wrapper_cc.pyx +252 -0
- sage/ext/interpreters/wrapper_cdf.cpython-314-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_cdf.pxd +26 -0
- sage/ext/interpreters/wrapper_cdf.pyx +245 -0
- sage/ext/interpreters/wrapper_rdf.cpython-314-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_rdf.pxd +23 -0
- sage/ext/interpreters/wrapper_rdf.pyx +221 -0
- sage/ext/interpreters/wrapper_rr.cpython-314-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_rr.pxd +28 -0
- sage/ext/interpreters/wrapper_rr.pyx +335 -0
- sage/geometry/all__sagemath_modules.py +5 -0
- sage/geometry/toric_lattice.py +1745 -0
- sage/geometry/toric_lattice_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/geometry/toric_lattice_element.pyx +432 -0
- sage/groups/abelian_gps/abelian_group.py +1925 -0
- sage/groups/abelian_gps/abelian_group_element.py +164 -0
- sage/groups/abelian_gps/all__sagemath_modules.py +5 -0
- sage/groups/abelian_gps/dual_abelian_group.py +421 -0
- sage/groups/abelian_gps/dual_abelian_group_element.py +179 -0
- sage/groups/abelian_gps/element_base.py +341 -0
- sage/groups/abelian_gps/values.py +488 -0
- sage/groups/additive_abelian/additive_abelian_group.py +476 -0
- sage/groups/additive_abelian/additive_abelian_wrapper.py +857 -0
- sage/groups/additive_abelian/all.py +4 -0
- sage/groups/additive_abelian/qmodnz.py +231 -0
- sage/groups/additive_abelian/qmodnz_element.py +349 -0
- sage/groups/affine_gps/affine_group.py +535 -0
- sage/groups/affine_gps/all.py +1 -0
- sage/groups/affine_gps/catalog.py +17 -0
- sage/groups/affine_gps/euclidean_group.py +246 -0
- sage/groups/affine_gps/group_element.py +562 -0
- sage/groups/all__sagemath_modules.py +12 -0
- sage/groups/galois_group.py +479 -0
- sage/groups/matrix_gps/all.py +4 -0
- sage/groups/matrix_gps/all__sagemath_modules.py +13 -0
- sage/groups/matrix_gps/catalog.py +26 -0
- sage/groups/matrix_gps/coxeter_group.py +927 -0
- sage/groups/matrix_gps/finitely_generated.py +487 -0
- sage/groups/matrix_gps/group_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/groups/matrix_gps/group_element.pxd +11 -0
- sage/groups/matrix_gps/group_element.pyx +431 -0
- sage/groups/matrix_gps/linear.py +440 -0
- sage/groups/matrix_gps/matrix_group.py +617 -0
- sage/groups/matrix_gps/named_group.py +296 -0
- sage/groups/matrix_gps/orthogonal.py +544 -0
- sage/groups/matrix_gps/symplectic.py +251 -0
- sage/groups/matrix_gps/unitary.py +436 -0
- sage/groups/misc_gps/all__sagemath_modules.py +1 -0
- sage/groups/misc_gps/argument_groups.py +1905 -0
- sage/groups/misc_gps/imaginary_groups.py +479 -0
- sage/groups/perm_gps/all__sagemath_modules.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_modules.py +1 -0
- sage/groups/perm_gps/partn_ref/refinement_binary.cpython-314-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_binary.pxd +41 -0
- sage/groups/perm_gps/partn_ref/refinement_binary.pyx +1167 -0
- sage/groups/perm_gps/partn_ref/refinement_matrices.cpython-314-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_matrices.pxd +31 -0
- sage/groups/perm_gps/partn_ref/refinement_matrices.pyx +385 -0
- sage/homology/algebraic_topological_model.py +595 -0
- sage/homology/all.py +2 -0
- sage/homology/all__sagemath_modules.py +8 -0
- sage/homology/chain_complex.py +2148 -0
- sage/homology/chain_complex_homspace.py +165 -0
- sage/homology/chain_complex_morphism.py +629 -0
- sage/homology/chain_homotopy.py +604 -0
- sage/homology/chains.py +653 -0
- sage/homology/free_resolution.py +923 -0
- sage/homology/graded_resolution.py +567 -0
- sage/homology/hochschild_complex.py +756 -0
- sage/homology/homology_group.py +188 -0
- sage/homology/homology_morphism.py +422 -0
- sage/homology/homology_vector_space_with_basis.py +1454 -0
- sage/homology/koszul_complex.py +169 -0
- sage/homology/matrix_utils.py +205 -0
- sage/libs/all__sagemath_modules.py +1 -0
- sage/libs/gsl/__init__.py +1 -0
- sage/libs/gsl/airy.pxd +56 -0
- sage/libs/gsl/all.pxd +66 -0
- sage/libs/gsl/array.cpython-314-aarch64-linux-musl.so +0 -0
- sage/libs/gsl/array.pxd +5 -0
- sage/libs/gsl/array.pyx +102 -0
- sage/libs/gsl/bessel.pxd +208 -0
- sage/libs/gsl/blas.pxd +116 -0
- sage/libs/gsl/blas_types.pxd +34 -0
- sage/libs/gsl/block.pxd +52 -0
- sage/libs/gsl/chebyshev.pxd +37 -0
- sage/libs/gsl/clausen.pxd +12 -0
- sage/libs/gsl/combination.pxd +47 -0
- sage/libs/gsl/complex.pxd +151 -0
- sage/libs/gsl/coulomb.pxd +30 -0
- sage/libs/gsl/coupling.pxd +21 -0
- sage/libs/gsl/dawson.pxd +12 -0
- sage/libs/gsl/debye.pxd +24 -0
- sage/libs/gsl/dilog.pxd +14 -0
- sage/libs/gsl/eigen.pxd +46 -0
- sage/libs/gsl/elementary.pxd +12 -0
- sage/libs/gsl/ellint.pxd +48 -0
- sage/libs/gsl/elljac.pxd +8 -0
- sage/libs/gsl/erf.pxd +32 -0
- sage/libs/gsl/errno.pxd +26 -0
- sage/libs/gsl/exp.pxd +44 -0
- sage/libs/gsl/expint.pxd +44 -0
- sage/libs/gsl/fermi_dirac.pxd +44 -0
- sage/libs/gsl/fft.pxd +121 -0
- sage/libs/gsl/fit.pxd +50 -0
- sage/libs/gsl/gamma.pxd +94 -0
- sage/libs/gsl/gegenbauer.pxd +26 -0
- sage/libs/gsl/histogram.pxd +176 -0
- sage/libs/gsl/hyperg.pxd +52 -0
- sage/libs/gsl/integration.pxd +69 -0
- sage/libs/gsl/interp.pxd +109 -0
- sage/libs/gsl/laguerre.pxd +24 -0
- sage/libs/gsl/lambert.pxd +16 -0
- sage/libs/gsl/legendre.pxd +90 -0
- sage/libs/gsl/linalg.pxd +185 -0
- sage/libs/gsl/log.pxd +26 -0
- sage/libs/gsl/math.pxd +43 -0
- sage/libs/gsl/matrix.pxd +143 -0
- sage/libs/gsl/matrix_complex.pxd +130 -0
- sage/libs/gsl/min.pxd +67 -0
- sage/libs/gsl/monte.pxd +56 -0
- sage/libs/gsl/ntuple.pxd +32 -0
- sage/libs/gsl/odeiv.pxd +70 -0
- sage/libs/gsl/permutation.pxd +78 -0
- sage/libs/gsl/poly.pxd +40 -0
- sage/libs/gsl/pow_int.pxd +12 -0
- sage/libs/gsl/psi.pxd +28 -0
- sage/libs/gsl/qrng.pxd +29 -0
- sage/libs/gsl/random.pxd +257 -0
- sage/libs/gsl/rng.pxd +100 -0
- sage/libs/gsl/roots.pxd +72 -0
- sage/libs/gsl/sort.pxd +36 -0
- sage/libs/gsl/statistics.pxd +59 -0
- sage/libs/gsl/sum.pxd +55 -0
- sage/libs/gsl/synchrotron.pxd +16 -0
- sage/libs/gsl/transport.pxd +24 -0
- sage/libs/gsl/trig.pxd +58 -0
- sage/libs/gsl/types.pxd +137 -0
- sage/libs/gsl/vector.pxd +101 -0
- sage/libs/gsl/vector_complex.pxd +83 -0
- sage/libs/gsl/wavelet.pxd +49 -0
- sage/libs/gsl/zeta.pxd +28 -0
- sage/libs/mpc/__init__.pxd +114 -0
- sage/libs/mpc/types.pxd +28 -0
- sage/libs/mpfr/__init__.pxd +299 -0
- sage/libs/mpfr/types.pxd +26 -0
- sage/libs/mpmath/__init__.py +1 -0
- sage/libs/mpmath/all.py +27 -0
- sage/libs/mpmath/all__sagemath_modules.py +1 -0
- sage/libs/mpmath/utils.cpython-314-aarch64-linux-musl.so +0 -0
- sage/libs/mpmath/utils.pxd +4 -0
- sage/libs/mpmath/utils.pyx +319 -0
- sage/matrix/action.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/action.pxd +26 -0
- sage/matrix/action.pyx +596 -0
- sage/matrix/all.py +9 -0
- sage/matrix/args.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/args.pxd +144 -0
- sage/matrix/args.pyx +1668 -0
- sage/matrix/benchmark.py +1258 -0
- sage/matrix/berlekamp_massey.py +95 -0
- sage/matrix/compute_J_ideal.py +926 -0
- sage/matrix/constructor.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/constructor.pyx +750 -0
- sage/matrix/docs.py +430 -0
- sage/matrix/echelon_matrix.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/echelon_matrix.pyx +155 -0
- sage/matrix/matrix.pxd +2 -0
- sage/matrix/matrix0.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix0.pxd +68 -0
- sage/matrix/matrix0.pyx +6324 -0
- sage/matrix/matrix1.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix1.pxd +8 -0
- sage/matrix/matrix1.pyx +2851 -0
- sage/matrix/matrix2.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix2.pxd +25 -0
- sage/matrix/matrix2.pyx +20181 -0
- sage/matrix/matrix_cdv.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_cdv.pxd +4 -0
- sage/matrix/matrix_cdv.pyx +93 -0
- sage/matrix/matrix_complex_double_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_complex_double_dense.pxd +5 -0
- sage/matrix/matrix_complex_double_dense.pyx +98 -0
- sage/matrix/matrix_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_dense.pxd +5 -0
- sage/matrix/matrix_dense.pyx +343 -0
- sage/matrix/matrix_domain_dense.pxd +5 -0
- sage/matrix/matrix_domain_sparse.pxd +5 -0
- sage/matrix/matrix_double_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_double_dense.pxd +7 -0
- sage/matrix/matrix_double_dense.pyx +3906 -0
- sage/matrix/matrix_double_sparse.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_double_sparse.pxd +6 -0
- sage/matrix/matrix_double_sparse.pyx +248 -0
- sage/matrix/matrix_generic_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_generic_dense.pxd +7 -0
- sage/matrix/matrix_generic_dense.pyx +354 -0
- sage/matrix/matrix_generic_sparse.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_generic_sparse.pxd +7 -0
- sage/matrix/matrix_generic_sparse.pyx +461 -0
- sage/matrix/matrix_laurent_mpolynomial_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_laurent_mpolynomial_dense.pxd +5 -0
- sage/matrix/matrix_laurent_mpolynomial_dense.pyx +115 -0
- sage/matrix/matrix_misc.py +313 -0
- sage/matrix/matrix_numpy_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_numpy_dense.pxd +14 -0
- sage/matrix/matrix_numpy_dense.pyx +450 -0
- sage/matrix/matrix_numpy_integer_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_numpy_integer_dense.pxd +7 -0
- sage/matrix/matrix_numpy_integer_dense.pyx +59 -0
- sage/matrix/matrix_polynomial_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_polynomial_dense.pxd +5 -0
- sage/matrix/matrix_polynomial_dense.pyx +5341 -0
- sage/matrix/matrix_real_double_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_real_double_dense.pxd +7 -0
- sage/matrix/matrix_real_double_dense.pyx +122 -0
- sage/matrix/matrix_space.py +2848 -0
- sage/matrix/matrix_sparse.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_sparse.pxd +5 -0
- sage/matrix/matrix_sparse.pyx +1222 -0
- sage/matrix/matrix_window.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_window.pxd +37 -0
- sage/matrix/matrix_window.pyx +242 -0
- sage/matrix/misc_mpfr.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/misc_mpfr.pyx +80 -0
- sage/matrix/operation_table.py +1182 -0
- sage/matrix/special.py +3666 -0
- sage/matrix/strassen.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/strassen.pyx +851 -0
- sage/matrix/symplectic_basis.py +541 -0
- sage/matrix/template.pxd +6 -0
- sage/matrix/tests.py +71 -0
- sage/matroids/advanced.py +77 -0
- sage/matroids/all.py +13 -0
- sage/matroids/basis_exchange_matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/basis_exchange_matroid.pxd +96 -0
- sage/matroids/basis_exchange_matroid.pyx +2344 -0
- sage/matroids/basis_matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/basis_matroid.pxd +45 -0
- sage/matroids/basis_matroid.pyx +1217 -0
- sage/matroids/catalog.py +44 -0
- sage/matroids/chow_ring.py +473 -0
- sage/matroids/chow_ring_ideal.py +849 -0
- sage/matroids/circuit_closures_matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/circuit_closures_matroid.pxd +16 -0
- sage/matroids/circuit_closures_matroid.pyx +559 -0
- sage/matroids/circuits_matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/circuits_matroid.pxd +38 -0
- sage/matroids/circuits_matroid.pyx +947 -0
- sage/matroids/constructor.py +1086 -0
- sage/matroids/database_collections.py +365 -0
- sage/matroids/database_matroids.py +5338 -0
- sage/matroids/dual_matroid.py +583 -0
- sage/matroids/extension.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/extension.pxd +34 -0
- sage/matroids/extension.pyx +519 -0
- sage/matroids/flats_matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/flats_matroid.pxd +28 -0
- sage/matroids/flats_matroid.pyx +715 -0
- sage/matroids/gammoid.py +600 -0
- sage/matroids/graphic_matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/graphic_matroid.pxd +39 -0
- sage/matroids/graphic_matroid.pyx +2024 -0
- sage/matroids/lean_matrix.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/lean_matrix.pxd +126 -0
- sage/matroids/lean_matrix.pyx +3667 -0
- sage/matroids/linear_matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/linear_matroid.pxd +180 -0
- sage/matroids/linear_matroid.pyx +6649 -0
- sage/matroids/matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/matroid.pxd +243 -0
- sage/matroids/matroid.pyx +8759 -0
- sage/matroids/matroids_catalog.py +190 -0
- sage/matroids/matroids_plot_helpers.py +890 -0
- sage/matroids/minor_matroid.py +480 -0
- sage/matroids/minorfix.h +9 -0
- sage/matroids/named_matroids.py +5 -0
- sage/matroids/rank_matroid.py +268 -0
- sage/matroids/set_system.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/set_system.pxd +38 -0
- sage/matroids/set_system.pyx +800 -0
- sage/matroids/transversal_matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/transversal_matroid.pxd +14 -0
- sage/matroids/transversal_matroid.pyx +893 -0
- sage/matroids/union_matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/union_matroid.pxd +20 -0
- sage/matroids/union_matroid.pyx +331 -0
- sage/matroids/unpickling.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/unpickling.pyx +843 -0
- sage/matroids/utilities.py +809 -0
- sage/misc/all__sagemath_modules.py +20 -0
- sage/misc/c3.cpython-314-aarch64-linux-musl.so +0 -0
- sage/misc/c3.pyx +238 -0
- sage/misc/compat.py +87 -0
- sage/misc/element_with_label.py +173 -0
- sage/misc/func_persist.py +79 -0
- sage/misc/pickle_old.cpython-314-aarch64-linux-musl.so +0 -0
- sage/misc/pickle_old.pyx +19 -0
- sage/misc/proof.py +7 -0
- sage/misc/replace_dot_all.py +472 -0
- sage/misc/sagedoc_conf.py +168 -0
- sage/misc/sphinxify.py +167 -0
- sage/misc/test_class_pickling.py +85 -0
- sage/modules/all.py +42 -0
- sage/modules/complex_double_vector.py +25 -0
- sage/modules/diamond_cutting.py +380 -0
- sage/modules/fg_pid/all.py +1 -0
- sage/modules/fg_pid/fgp_element.py +456 -0
- sage/modules/fg_pid/fgp_module.py +2091 -0
- sage/modules/fg_pid/fgp_morphism.py +550 -0
- sage/modules/filtered_vector_space.py +1271 -0
- sage/modules/finite_submodule_iter.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/finite_submodule_iter.pxd +27 -0
- sage/modules/finite_submodule_iter.pyx +452 -0
- sage/modules/fp_graded/all.py +1 -0
- sage/modules/fp_graded/element.py +346 -0
- sage/modules/fp_graded/free_element.py +298 -0
- sage/modules/fp_graded/free_homspace.py +53 -0
- sage/modules/fp_graded/free_module.py +1060 -0
- sage/modules/fp_graded/free_morphism.py +217 -0
- sage/modules/fp_graded/homspace.py +563 -0
- sage/modules/fp_graded/module.py +1340 -0
- sage/modules/fp_graded/morphism.py +1990 -0
- sage/modules/fp_graded/steenrod/all.py +1 -0
- sage/modules/fp_graded/steenrod/homspace.py +65 -0
- sage/modules/fp_graded/steenrod/module.py +477 -0
- sage/modules/fp_graded/steenrod/morphism.py +404 -0
- sage/modules/fp_graded/steenrod/profile.py +241 -0
- sage/modules/free_module.py +8447 -0
- sage/modules/free_module_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/free_module_element.pxd +22 -0
- sage/modules/free_module_element.pyx +5445 -0
- sage/modules/free_module_homspace.py +369 -0
- sage/modules/free_module_integer.py +896 -0
- sage/modules/free_module_morphism.py +823 -0
- sage/modules/free_module_pseudohomspace.py +352 -0
- sage/modules/free_module_pseudomorphism.py +578 -0
- sage/modules/free_quadratic_module.py +1706 -0
- sage/modules/free_quadratic_module_integer_symmetric.py +1790 -0
- sage/modules/matrix_morphism.py +1745 -0
- sage/modules/misc.py +103 -0
- sage/modules/module_functors.py +192 -0
- sage/modules/multi_filtered_vector_space.py +719 -0
- sage/modules/ore_module.py +2208 -0
- sage/modules/ore_module_element.py +178 -0
- sage/modules/ore_module_homspace.py +147 -0
- sage/modules/ore_module_morphism.py +968 -0
- sage/modules/quotient_module.py +699 -0
- sage/modules/real_double_vector.py +22 -0
- sage/modules/submodule.py +255 -0
- sage/modules/tensor_operations.py +567 -0
- sage/modules/torsion_quadratic_module.py +1352 -0
- sage/modules/tutorial_free_modules.py +248 -0
- sage/modules/vector_complex_double_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_complex_double_dense.pxd +6 -0
- sage/modules/vector_complex_double_dense.pyx +117 -0
- sage/modules/vector_double_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_double_dense.pxd +6 -0
- sage/modules/vector_double_dense.pyx +604 -0
- sage/modules/vector_integer_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_integer_dense.pxd +15 -0
- sage/modules/vector_integer_dense.pyx +361 -0
- sage/modules/vector_integer_sparse.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_integer_sparse.pxd +29 -0
- sage/modules/vector_integer_sparse.pyx +406 -0
- sage/modules/vector_modn_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_modn_dense.pxd +12 -0
- sage/modules/vector_modn_dense.pyx +394 -0
- sage/modules/vector_modn_sparse.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_modn_sparse.pxd +21 -0
- sage/modules/vector_modn_sparse.pyx +298 -0
- sage/modules/vector_numpy_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_numpy_dense.pxd +15 -0
- sage/modules/vector_numpy_dense.pyx +304 -0
- sage/modules/vector_numpy_integer_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_numpy_integer_dense.pxd +7 -0
- sage/modules/vector_numpy_integer_dense.pyx +54 -0
- sage/modules/vector_rational_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_rational_dense.pxd +15 -0
- sage/modules/vector_rational_dense.pyx +387 -0
- sage/modules/vector_rational_sparse.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_rational_sparse.pxd +30 -0
- sage/modules/vector_rational_sparse.pyx +413 -0
- sage/modules/vector_real_double_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_real_double_dense.pxd +6 -0
- sage/modules/vector_real_double_dense.pyx +126 -0
- sage/modules/vector_space_homspace.py +430 -0
- sage/modules/vector_space_morphism.py +989 -0
- sage/modules/with_basis/all.py +15 -0
- sage/modules/with_basis/cell_module.py +494 -0
- sage/modules/with_basis/indexed_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/with_basis/indexed_element.pxd +13 -0
- sage/modules/with_basis/indexed_element.pyx +1058 -0
- sage/modules/with_basis/invariant.py +1075 -0
- sage/modules/with_basis/morphism.py +1636 -0
- sage/modules/with_basis/representation.py +2939 -0
- sage/modules/with_basis/subquotient.py +685 -0
- sage/numerical/all__sagemath_modules.py +6 -0
- sage/numerical/gauss_legendre.cpython-314-aarch64-linux-musl.so +0 -0
- sage/numerical/gauss_legendre.pyx +381 -0
- sage/numerical/optimize.py +910 -0
- sage/probability/all.py +10 -0
- sage/probability/probability_distribution.cpython-314-aarch64-linux-musl.so +0 -0
- sage/probability/probability_distribution.pyx +1242 -0
- sage/probability/random_variable.py +411 -0
- sage/quadratic_forms/all.py +4 -0
- sage/quadratic_forms/all__sagemath_modules.py +15 -0
- sage/quadratic_forms/binary_qf.py +2042 -0
- sage/quadratic_forms/bqf_class_group.py +748 -0
- sage/quadratic_forms/constructions.py +93 -0
- sage/quadratic_forms/count_local_2.cpython-314-aarch64-linux-musl.so +0 -0
- sage/quadratic_forms/count_local_2.pyx +365 -0
- sage/quadratic_forms/extras.py +195 -0
- sage/quadratic_forms/quadratic_form.py +1753 -0
- sage/quadratic_forms/quadratic_form__count_local_2.py +221 -0
- sage/quadratic_forms/quadratic_form__equivalence_testing.py +708 -0
- sage/quadratic_forms/quadratic_form__evaluate.cpython-314-aarch64-linux-musl.so +0 -0
- sage/quadratic_forms/quadratic_form__evaluate.pyx +139 -0
- sage/quadratic_forms/quadratic_form__local_density_congruence.py +977 -0
- sage/quadratic_forms/quadratic_form__local_field_invariants.py +1072 -0
- sage/quadratic_forms/quadratic_form__neighbors.py +424 -0
- sage/quadratic_forms/quadratic_form__reduction_theory.py +488 -0
- sage/quadratic_forms/quadratic_form__split_local_covering.py +416 -0
- sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +657 -0
- sage/quadratic_forms/quadratic_form__theta.py +352 -0
- sage/quadratic_forms/quadratic_form__variable_substitutions.py +370 -0
- sage/quadratic_forms/random_quadraticform.py +209 -0
- sage/quadratic_forms/ternary.cpython-314-aarch64-linux-musl.so +0 -0
- sage/quadratic_forms/ternary.pyx +1154 -0
- sage/quadratic_forms/ternary_qf.py +2027 -0
- sage/rings/all__sagemath_modules.py +28 -0
- sage/rings/asymptotic/all__sagemath_modules.py +1 -0
- sage/rings/asymptotic/misc.py +1252 -0
- sage/rings/cc.py +4 -0
- sage/rings/cfinite_sequence.py +1306 -0
- sage/rings/complex_conversion.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/complex_conversion.pxd +8 -0
- sage/rings/complex_conversion.pyx +23 -0
- sage/rings/complex_double.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/complex_double.pxd +21 -0
- sage/rings/complex_double.pyx +2654 -0
- sage/rings/complex_mpc.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/complex_mpc.pxd +21 -0
- sage/rings/complex_mpc.pyx +2576 -0
- sage/rings/complex_mpfr.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/complex_mpfr.pxd +18 -0
- sage/rings/complex_mpfr.pyx +3602 -0
- sage/rings/derivation.py +2334 -0
- sage/rings/finite_rings/all__sagemath_modules.py +1 -0
- sage/rings/finite_rings/maps_finite_field.py +191 -0
- sage/rings/function_field/all__sagemath_modules.py +8 -0
- sage/rings/function_field/derivations.py +102 -0
- sage/rings/function_field/derivations_rational.py +132 -0
- sage/rings/function_field/differential.py +853 -0
- sage/rings/function_field/divisor.py +1107 -0
- sage/rings/function_field/drinfeld_modules/action.py +199 -0
- sage/rings/function_field/drinfeld_modules/all.py +1 -0
- sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py +673 -0
- sage/rings/function_field/drinfeld_modules/drinfeld_module.py +2087 -0
- sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py +1131 -0
- sage/rings/function_field/drinfeld_modules/homset.py +420 -0
- sage/rings/function_field/drinfeld_modules/morphism.py +820 -0
- sage/rings/function_field/hermite_form_polynomial.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/hermite_form_polynomial.pyx +188 -0
- sage/rings/function_field/khuri_makdisi.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/khuri_makdisi.pyx +935 -0
- sage/rings/invariants/all.py +4 -0
- sage/rings/invariants/invariant_theory.py +4597 -0
- sage/rings/invariants/reconstruction.py +395 -0
- sage/rings/polynomial/all__sagemath_modules.py +17 -0
- sage/rings/polynomial/integer_valued_polynomials.py +1230 -0
- sage/rings/polynomial/laurent_polynomial_mpair.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/laurent_polynomial_mpair.pxd +15 -0
- sage/rings/polynomial/laurent_polynomial_mpair.pyx +2023 -0
- sage/rings/polynomial/ore_function_element.py +952 -0
- sage/rings/polynomial/ore_function_field.py +1028 -0
- sage/rings/polynomial/ore_polynomial_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/ore_polynomial_element.pxd +48 -0
- sage/rings/polynomial/ore_polynomial_element.pyx +3145 -0
- sage/rings/polynomial/ore_polynomial_ring.py +1334 -0
- sage/rings/polynomial/polynomial_real_mpfr_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +788 -0
- sage/rings/polynomial/q_integer_valued_polynomials.py +1264 -0
- sage/rings/polynomial/skew_polynomial_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/skew_polynomial_element.pxd +9 -0
- sage/rings/polynomial/skew_polynomial_element.pyx +684 -0
- sage/rings/polynomial/skew_polynomial_finite_field.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/skew_polynomial_finite_field.pxd +19 -0
- sage/rings/polynomial/skew_polynomial_finite_field.pyx +1093 -0
- sage/rings/polynomial/skew_polynomial_finite_order.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/skew_polynomial_finite_order.pxd +10 -0
- sage/rings/polynomial/skew_polynomial_finite_order.pyx +567 -0
- sage/rings/polynomial/skew_polynomial_ring.py +908 -0
- sage/rings/real_double_element_gsl.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/real_double_element_gsl.pxd +8 -0
- sage/rings/real_double_element_gsl.pyx +794 -0
- sage/rings/real_field.py +58 -0
- sage/rings/real_mpfr.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/real_mpfr.pxd +29 -0
- sage/rings/real_mpfr.pyx +6122 -0
- sage/rings/ring_extension.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/ring_extension.pxd +42 -0
- sage/rings/ring_extension.pyx +2779 -0
- sage/rings/ring_extension_conversion.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/ring_extension_conversion.pxd +16 -0
- sage/rings/ring_extension_conversion.pyx +462 -0
- sage/rings/ring_extension_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/ring_extension_element.pxd +21 -0
- sage/rings/ring_extension_element.pyx +1635 -0
- sage/rings/ring_extension_homset.py +64 -0
- sage/rings/ring_extension_morphism.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/ring_extension_morphism.pxd +35 -0
- sage/rings/ring_extension_morphism.pyx +920 -0
- sage/schemes/all__sagemath_modules.py +1 -0
- sage/schemes/projective/all__sagemath_modules.py +1 -0
- sage/schemes/projective/coherent_sheaf.py +300 -0
- sage/schemes/projective/cohomology.py +510 -0
- sage/stats/all.py +15 -0
- sage/stats/basic_stats.py +489 -0
- sage/stats/distributions/all.py +7 -0
- sage/stats/distributions/catalog.py +34 -0
- sage/stats/distributions/dgs.h +50 -0
- sage/stats/distributions/dgs.pxd +111 -0
- sage/stats/distributions/dgs_bern.h +400 -0
- sage/stats/distributions/dgs_gauss.h +614 -0
- sage/stats/distributions/dgs_misc.h +104 -0
- sage/stats/distributions/discrete_gaussian_integer.cpython-314-aarch64-linux-musl.so +0 -0
- sage/stats/distributions/discrete_gaussian_integer.pxd +14 -0
- sage/stats/distributions/discrete_gaussian_integer.pyx +498 -0
- sage/stats/distributions/discrete_gaussian_lattice.py +908 -0
- sage/stats/distributions/discrete_gaussian_polynomial.py +141 -0
- sage/stats/hmm/all.py +15 -0
- sage/stats/hmm/chmm.cpython-314-aarch64-linux-musl.so +0 -0
- sage/stats/hmm/chmm.pyx +1595 -0
- sage/stats/hmm/distributions.cpython-314-aarch64-linux-musl.so +0 -0
- sage/stats/hmm/distributions.pxd +29 -0
- sage/stats/hmm/distributions.pyx +531 -0
- sage/stats/hmm/hmm.cpython-314-aarch64-linux-musl.so +0 -0
- sage/stats/hmm/hmm.pxd +17 -0
- sage/stats/hmm/hmm.pyx +1388 -0
- sage/stats/hmm/util.cpython-314-aarch64-linux-musl.so +0 -0
- sage/stats/hmm/util.pxd +7 -0
- sage/stats/hmm/util.pyx +165 -0
- sage/stats/intlist.cpython-314-aarch64-linux-musl.so +0 -0
- sage/stats/intlist.pxd +14 -0
- sage/stats/intlist.pyx +588 -0
- sage/stats/r.py +49 -0
- sage/stats/time_series.cpython-314-aarch64-linux-musl.so +0 -0
- sage/stats/time_series.pxd +6 -0
- sage/stats/time_series.pyx +2546 -0
- sage/tensor/all.py +2 -0
- sage/tensor/modules/all.py +8 -0
- sage/tensor/modules/alternating_contr_tensor.py +761 -0
- sage/tensor/modules/comp.py +5598 -0
- sage/tensor/modules/ext_pow_free_module.py +824 -0
- sage/tensor/modules/finite_rank_free_module.py +3589 -0
- sage/tensor/modules/format_utilities.py +333 -0
- sage/tensor/modules/free_module_alt_form.py +858 -0
- sage/tensor/modules/free_module_automorphism.py +1207 -0
- sage/tensor/modules/free_module_basis.py +1074 -0
- sage/tensor/modules/free_module_element.py +284 -0
- sage/tensor/modules/free_module_homset.py +652 -0
- sage/tensor/modules/free_module_linear_group.py +564 -0
- sage/tensor/modules/free_module_morphism.py +1581 -0
- sage/tensor/modules/free_module_tensor.py +3289 -0
- sage/tensor/modules/reflexive_module.py +386 -0
- sage/tensor/modules/tensor_free_module.py +780 -0
- sage/tensor/modules/tensor_free_submodule.py +538 -0
- sage/tensor/modules/tensor_free_submodule_basis.py +140 -0
- sage/tensor/modules/tensor_with_indices.py +1043 -0
|
@@ -0,0 +1,4258 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-modules
|
|
2
|
+
# sage.doctest: needs sage.combinat sage.modules
|
|
3
|
+
r"""
|
|
4
|
+
The Steenrod algebra
|
|
5
|
+
|
|
6
|
+
AUTHORS:
|
|
7
|
+
|
|
8
|
+
- John H. Palmieri (2008-07-30): version 0.9: Initial implementation.
|
|
9
|
+
- John H. Palmieri (2010-06-30): version 1.0: Implemented sub-Hopf
|
|
10
|
+
algebras and profile functions; direct multiplication of admissible
|
|
11
|
+
sequences (rather than conversion to the Milnor basis); implemented
|
|
12
|
+
the Steenrod algebra using CombinatorialFreeModule; improved the
|
|
13
|
+
test suite.
|
|
14
|
+
|
|
15
|
+
This module defines the mod `p` Steenrod algebra `\mathcal{A}_p`, some
|
|
16
|
+
of its properties, and ways to define elements of it.
|
|
17
|
+
|
|
18
|
+
From a topological point of view, `\mathcal{A}_p` is the algebra of
|
|
19
|
+
stable cohomology operations on mod `p` cohomology; thus for any
|
|
20
|
+
topological space `X`, its mod `p` cohomology algebra
|
|
21
|
+
`H^*(X,\mathbf{F}_p)` is a module over `\mathcal{A}_p`.
|
|
22
|
+
|
|
23
|
+
From an algebraic point of view, `\mathcal{A}_p` is an
|
|
24
|
+
`\mathbf{F}_p`-algebra; when `p=2`, it is generated by elements
|
|
25
|
+
`\text{Sq}^i` for `i\geq 0` (the *Steenrod squares*), and when `p` is
|
|
26
|
+
odd, it is generated by elements `\mathcal{P}^i` for `i \geq 0` (the
|
|
27
|
+
*Steenrod reduced `p`-th powers*) along with an element `\beta` (the *mod
|
|
28
|
+
p Bockstein*). The Steenrod algebra is graded: `\text{Sq}^i` is in
|
|
29
|
+
degree `i` for each `i`, `\beta` is in degree 1, and `\mathcal{P}^i`
|
|
30
|
+
is in degree `2(p-1)i`.
|
|
31
|
+
|
|
32
|
+
The unit element is `\text{Sq}^0` when `p=2` and
|
|
33
|
+
`\mathcal{P}^0` when `p` is odd. The generating
|
|
34
|
+
elements also satisfy the *Adem relations*. At the prime 2, these
|
|
35
|
+
have the form
|
|
36
|
+
|
|
37
|
+
.. MATH::
|
|
38
|
+
|
|
39
|
+
\text{Sq}^a \text{Sq}^b = \sum_{c=0}^{[a/2]} \binom{b-c-1}{a-2c} \text{Sq}^{a+b-c} \text{Sq}^c.
|
|
40
|
+
|
|
41
|
+
At odd primes, they are a bit more complicated; see Steenrod and
|
|
42
|
+
Epstein [SE1962]_ or :mod:`sage.algebras.steenrod.steenrod_algebra_bases`
|
|
43
|
+
for full details. These relations lead to the existence of the
|
|
44
|
+
*Serre-Cartan* basis for `\mathcal{A}_p`.
|
|
45
|
+
|
|
46
|
+
The mod `p` Steenrod algebra has the structure of a Hopf
|
|
47
|
+
algebra, and Milnor [Mil1958]_ has a beautiful description of the dual,
|
|
48
|
+
leading to a construction of the *Milnor basis* for
|
|
49
|
+
`\mathcal{A}_p`. In this module, elements in the Steenrod
|
|
50
|
+
algebra are represented, by default, using the Milnor basis.
|
|
51
|
+
|
|
52
|
+
.. rubric:: Bases for the Steenrod algebra
|
|
53
|
+
|
|
54
|
+
There are a handful of other bases studied in the literature; the
|
|
55
|
+
paper by Monks [Mon1998]_ is a good reference. Here is a quick summary:
|
|
56
|
+
|
|
57
|
+
- The *Milnor basis*. When `p=2`, the Milnor basis consists of symbols
|
|
58
|
+
of the form `\text{Sq}(m_1, m_2, ..., m_t)`, where each `m_i` is a
|
|
59
|
+
nonnegative integer and if `t>1`, then the last entry `m_t > 0`.
|
|
60
|
+
When `p` is odd, the Milnor basis consists of symbols of the form
|
|
61
|
+
`Q_{e_1} Q_{e_2} ... \mathcal{P}(m_1, m_2, ..., m_t)`, where `0 \leq
|
|
62
|
+
e_1 < e_2 < ...`, each `m_i` is a nonnegative integer, and if
|
|
63
|
+
`t>1`, then the last entry `m_t > 0`.
|
|
64
|
+
|
|
65
|
+
When `p=2`, it can be convenient to use the notation
|
|
66
|
+
`\mathcal{P}(-)` to mean `\text{Sq}(-)`, so that there is consistent
|
|
67
|
+
notation for all primes.
|
|
68
|
+
|
|
69
|
+
- The *Serre-Cartan basis*. This basis consists of 'admissible
|
|
70
|
+
monomials' in the Steenrod operations. Thus at the prime 2, it
|
|
71
|
+
consists of monomials `\text{Sq}^{m_1} \text{Sq}^{m_2}
|
|
72
|
+
... \text{Sq}^{m_t}` with `m_i \geq 2m_{i+1}` for each `i`. At odd
|
|
73
|
+
primes, this basis consists of monomials `\beta^{\epsilon_0}
|
|
74
|
+
\mathcal{P}^{s_1} \beta^{\epsilon_1} \mathcal{P}^{s_2} ...
|
|
75
|
+
\mathcal{P}^{s_k} \beta^{\epsilon_k}` with each `\epsilon_i` either
|
|
76
|
+
0 or 1, `s_i \geq p s_{i+1} + \epsilon_i`, and `s_k \geq 1`.
|
|
77
|
+
|
|
78
|
+
Most of the rest of the bases are only defined when `p=2`. The only
|
|
79
|
+
exceptions are the `P^s_t`-bases and the commutator bases, which are
|
|
80
|
+
defined at all primes.
|
|
81
|
+
|
|
82
|
+
- *Wood's Y basis*. For pairs of nonnegative integers `(m,k)`, let
|
|
83
|
+
`w(m,k) = \text{Sq}^{2^m (2^{k+1}-1)}`. Wood's `Y` basis consists of
|
|
84
|
+
monomials `w(m_0,k_0) ... w(m_t, k_t)` with `(m_i,k_i) >
|
|
85
|
+
(m_{i+1},k_{i+1})`, in left lex order.
|
|
86
|
+
|
|
87
|
+
- *Wood's Z basis*. For pairs of nonnegative integers `(m,k)`, let
|
|
88
|
+
`w(m,k) = \text{Sq}^{2^m (2^{k+1}-1)}`. Wood's `Z` basis consists of
|
|
89
|
+
monomials `w(m_0,k_0) ... w(m_t, k_t)` with `(m_i+k_i,m_i) >
|
|
90
|
+
(m_{i+1}+k_{i+1},m_{i+1})`, in left lex order.
|
|
91
|
+
|
|
92
|
+
- *Wall's basis*. For any pair of integers `(m,k)` with `m \geq k \geq
|
|
93
|
+
0`, let `Q^m_k = \text{Sq}^{2^k} \text{Sq}^{2^{k+1}}
|
|
94
|
+
... \text{Sq}^{2^m}`. The elements of Wall's basis are monomials
|
|
95
|
+
`Q^{m_0}_{k_0} ... Q^{m_t}_{k_t}` with `(m_i, k_i) > (m_{i+1},
|
|
96
|
+
k_{i+1})`, ordered left lexicographically.
|
|
97
|
+
|
|
98
|
+
(Note that `Q^m_k` is the reverse of the element `X^m_k` used in
|
|
99
|
+
defining Arnon's A basis.)
|
|
100
|
+
|
|
101
|
+
- *Arnon's A basis*. For any pair of integers `(m,k)` with `m \geq k
|
|
102
|
+
\geq 0`, let `X^m_k = \text{Sq}^{2^m} \text{Sq}^{2^{m-1}}
|
|
103
|
+
... \text{Sq}^{2^k}`. The elements of Arnon's A basis are monomials
|
|
104
|
+
`X^{m_0}_{k_0} ... X^{m_t}_{k_t}` with `(m_i, k_i) < (m_{i+1},
|
|
105
|
+
k_{i+1})`, ordered left lexicographically.
|
|
106
|
+
|
|
107
|
+
(Note that `X^m_k` is the reverse of the element `Q^m_k` used in
|
|
108
|
+
defining Wall's basis.)
|
|
109
|
+
|
|
110
|
+
- *Arnon's C basis*. The elements of Arnon's C basis are monomials of
|
|
111
|
+
the form `\text{Sq}^{t_1} ... \text{Sq}^{t_m}` where for each `i`,
|
|
112
|
+
we have `t_i \leq 2t_{i+1}` and `2^i | t_{m-i}`.
|
|
113
|
+
|
|
114
|
+
- `P^s_t` *bases*. Let `p=2`. For integers `s \geq 0` and `t > 0`,
|
|
115
|
+
the element `P^s_t` is the Milnor basis element `\mathcal{P}(0, ...,
|
|
116
|
+
0, p^s, 0, ...)`, with the nonzero entry in position `t`. To obtain
|
|
117
|
+
a `P^s_t`-basis, for each set `\{P^{s_1}_{t_1}, ...,
|
|
118
|
+
P^{s_k}_{t_k}\}` of (distinct) `P^s_t`'s, one chooses an ordering
|
|
119
|
+
and forms the monomials
|
|
120
|
+
|
|
121
|
+
.. MATH::
|
|
122
|
+
|
|
123
|
+
(P^{s_1}_{t_1})^{i_1} ... (P^{s_k}_{t_k})^{i_k}
|
|
124
|
+
|
|
125
|
+
for all exponents `i_j` with `0 < i_j < p`. When `p=2`, the set of
|
|
126
|
+
all such monomials then forms a basis, and when `p` is odd, if one
|
|
127
|
+
multiplies each such monomial on the left by products of the form
|
|
128
|
+
`Q_{e_1} Q_{e_2} ...` with `0 \leq e_1 < e_2 < ...`, one obtains a
|
|
129
|
+
basis.
|
|
130
|
+
|
|
131
|
+
Thus one gets a basis by choosing an ordering on each set of
|
|
132
|
+
`P^s_t`'s. There are infinitely many orderings possible, and we
|
|
133
|
+
have implemented four of them:
|
|
134
|
+
|
|
135
|
+
- 'rlex': right lexicographic ordering
|
|
136
|
+
|
|
137
|
+
- 'llex': left lexicographic ordering
|
|
138
|
+
|
|
139
|
+
- 'deg': ordered by degree, which is the same as left lexicographic
|
|
140
|
+
ordering on the pair `(s+t,t)`
|
|
141
|
+
|
|
142
|
+
- 'revz': left lexicographic ordering on the pair `(s+t,s)`, which
|
|
143
|
+
is the reverse of the ordering used (on elements in the same
|
|
144
|
+
degrees as the `P^s_t`'s) in Wood's Z basis: 'revz' stands for
|
|
145
|
+
'reversed Z'. This is the default: 'pst' is the same as
|
|
146
|
+
'pst_revz'.
|
|
147
|
+
|
|
148
|
+
- *Commutator bases*. Let `c_{i,1} = \mathcal{P}(p^i)`, let `c_{i,2}
|
|
149
|
+
= [c_{i+1,1}, c_{i,1}]`, and inductively define `c_{i,k} =
|
|
150
|
+
[c_{i+k-1,1}, c_{i,k-1}]`. Thus `c_{i,k}` is a `k`-fold iterated
|
|
151
|
+
commutator of the elements `\mathcal{P}(p^i)`, ...,
|
|
152
|
+
`\mathcal{P}(p^{i+k-1})`. Note that `\dim c_{i,k} = \dim P^i_k`.
|
|
153
|
+
|
|
154
|
+
Commutator bases are obtained in much the same way as `P^s_t`-bases:
|
|
155
|
+
for each set `\{c_{s_1,t_1}, ..., c_{s_k,t_k}\}` of (distinct)
|
|
156
|
+
`c_{s,t}`'s, one chooses an ordering and forms the resulting
|
|
157
|
+
monomials
|
|
158
|
+
|
|
159
|
+
.. MATH::
|
|
160
|
+
|
|
161
|
+
c_{s_1, t_1}^{i_1} ... c_{s_k,t_k}^{i_k}
|
|
162
|
+
|
|
163
|
+
for all exponents `i_j` with `0 < i_j < p`. When `p` is odd, one
|
|
164
|
+
also needs to left-multiply by products of the `Q_i`'s. As for
|
|
165
|
+
`P^s_t`-bases, every ordering on each set of iterated commutators
|
|
166
|
+
determines a basis, and the same four orderings have been defined
|
|
167
|
+
for these bases as for the `P^s_t` bases: 'rlex', 'llex', 'deg',
|
|
168
|
+
'revz'.
|
|
169
|
+
|
|
170
|
+
.. rubric:: Sub-Hopf algebras of the Steenrod algebra
|
|
171
|
+
|
|
172
|
+
The sub-Hopf algebras of the Steenrod algebra have been
|
|
173
|
+
classified. Milnor proved that at the prime 2, the dual of the
|
|
174
|
+
Steenrod algebra `A_*` is isomorphic to a polynomial algebra
|
|
175
|
+
|
|
176
|
+
.. MATH::
|
|
177
|
+
|
|
178
|
+
A_* \cong \GF{2} [\xi_1, \xi_2, \xi_3, ...].
|
|
179
|
+
|
|
180
|
+
The Milnor basis is dual to the monomial basis. Furthermore, any sub-Hopf
|
|
181
|
+
algebra corresponds to a quotient of this of the form
|
|
182
|
+
|
|
183
|
+
.. MATH::
|
|
184
|
+
|
|
185
|
+
A_* /(\xi_1^{2^{e_1}}, \xi_2^{2^{e_2}}, \xi_3^{2^{e_3}}, ...).
|
|
186
|
+
|
|
187
|
+
The list of exponents `(e_1, e_2, ...)` may be considered a function
|
|
188
|
+
`e` from the positive integers to the extended nonnegative integers
|
|
189
|
+
(the nonnegative integers and `\infty`); this is called the *profile
|
|
190
|
+
function* for the sub-Hopf algebra. The profile function must satisfy
|
|
191
|
+
the condition
|
|
192
|
+
|
|
193
|
+
- `e(r) \geq \min( e(r-i) - i, e(i))` for all `0 < i < r`.
|
|
194
|
+
|
|
195
|
+
At odd primes, the situation is similar: the dual is isomorphic to the
|
|
196
|
+
tensor product of a polynomial algebra and an exterior algebra,
|
|
197
|
+
|
|
198
|
+
.. MATH::
|
|
199
|
+
|
|
200
|
+
A_* = \GF{p} [\xi_1, \xi_2, \xi_3, ...] \otimes \Lambda (\tau_0, \tau_1, ...),
|
|
201
|
+
|
|
202
|
+
and any sub-Hopf algebra corresponds to a quotient of this of the form
|
|
203
|
+
|
|
204
|
+
.. MATH::
|
|
205
|
+
|
|
206
|
+
A_* / (\xi_1^{p^{e_1}}, \xi_2^{p^{e_2}}, ...; \tau_0^{k_0}, \tau_1^{k_1}, ...).
|
|
207
|
+
|
|
208
|
+
Here the profile function has two pieces, `e` as at the prime 2, and
|
|
209
|
+
`k`, which maps the nonnegative integers to the set `\{1, 2\}`.
|
|
210
|
+
These must satisfy the following conditions:
|
|
211
|
+
|
|
212
|
+
- `e(r) \geq \min( e(r-i) - i, e(i))` for all `0 < i < r`.
|
|
213
|
+
|
|
214
|
+
- if `k(i+j) = 1`, then either `e(i) \leq j` or `k(j) = 1` for all `i
|
|
215
|
+
\geq 1`, `j \geq 0`.
|
|
216
|
+
|
|
217
|
+
(See Adams-Margolis [AM1974]_, for example, for these results on profile
|
|
218
|
+
functions.)
|
|
219
|
+
|
|
220
|
+
This module allows one to construct the Steenrod algebra or any of its
|
|
221
|
+
sub-Hopf algebras, at any prime. When defining a sub-Hopf algebra,
|
|
222
|
+
you must work with the Milnor basis or a `P^s_t`-basis.
|
|
223
|
+
|
|
224
|
+
.. rubric:: Elements of the Steenrod algebra
|
|
225
|
+
|
|
226
|
+
Basic arithmetic, `p=2`. To construct an element of the mod 2 Steenrod
|
|
227
|
+
algebra, use the function ``Sq``::
|
|
228
|
+
|
|
229
|
+
sage: a = Sq(1,2)
|
|
230
|
+
sage: b = Sq(4,1)
|
|
231
|
+
sage: z = a + b
|
|
232
|
+
sage: z
|
|
233
|
+
Sq(1,2) + Sq(4,1)
|
|
234
|
+
sage: Sq(4) * Sq(1,2)
|
|
235
|
+
Sq(1,1,1) + Sq(2,3) + Sq(5,2)
|
|
236
|
+
sage: z**2 # nonnegative exponents work as they should
|
|
237
|
+
Sq(1,2,1) + Sq(4,1,1)
|
|
238
|
+
sage: z**0
|
|
239
|
+
1
|
|
240
|
+
|
|
241
|
+
Basic arithmetic, `p>2`. To construct an element of the mod `p`
|
|
242
|
+
Steenrod algebra when `p` is odd, you should first define a Steenrod
|
|
243
|
+
algebra, using the ``SteenrodAlgebra`` command::
|
|
244
|
+
|
|
245
|
+
sage: A3 = SteenrodAlgebra(3)
|
|
246
|
+
|
|
247
|
+
Having done this, the newly created algebra ``A3`` has methods ``Q``
|
|
248
|
+
and ``P`` which construct elements of ``A3``::
|
|
249
|
+
|
|
250
|
+
sage: c = A3.Q(1,3,6); c
|
|
251
|
+
Q_1 Q_3 Q_6
|
|
252
|
+
sage: d = A3.P(2,0,1); d
|
|
253
|
+
P(2,0,1)
|
|
254
|
+
sage: c * d
|
|
255
|
+
Q_1 Q_3 Q_6 P(2,0,1)
|
|
256
|
+
sage: e = A3.P(3)
|
|
257
|
+
sage: d * e
|
|
258
|
+
P(5,0,1)
|
|
259
|
+
sage: e * d
|
|
260
|
+
P(1,1,1) + P(5,0,1)
|
|
261
|
+
sage: c * c
|
|
262
|
+
0
|
|
263
|
+
sage: e ** 3
|
|
264
|
+
2 P(1,2)
|
|
265
|
+
|
|
266
|
+
Note that one can construct an element like ``c`` above in one step,
|
|
267
|
+
without first constructing the algebra::
|
|
268
|
+
|
|
269
|
+
sage: c = SteenrodAlgebra(3).Q(1,3,6)
|
|
270
|
+
sage: c
|
|
271
|
+
Q_1 Q_3 Q_6
|
|
272
|
+
|
|
273
|
+
And of course, you can do similar constructions with the mod 2
|
|
274
|
+
Steenrod algebra::
|
|
275
|
+
|
|
276
|
+
sage: A = SteenrodAlgebra(2); A
|
|
277
|
+
mod 2 Steenrod algebra, milnor basis
|
|
278
|
+
sage: A.Sq(2,3,5)
|
|
279
|
+
Sq(2,3,5)
|
|
280
|
+
sage: A.P(2,3,5) # when p=2, P = Sq
|
|
281
|
+
Sq(2,3,5)
|
|
282
|
+
sage: A.Q(1,4) # when p=2, this gives a product of Milnor primitives
|
|
283
|
+
Sq(0,1,0,0,1)
|
|
284
|
+
|
|
285
|
+
Associated to each element is its prime (the characteristic of the
|
|
286
|
+
underlying base field) and its basis (the basis for the Steenrod
|
|
287
|
+
algebra in which it lies)::
|
|
288
|
+
|
|
289
|
+
sage: a = SteenrodAlgebra(basis='milnor').Sq(1,2,1)
|
|
290
|
+
sage: a.prime()
|
|
291
|
+
2
|
|
292
|
+
sage: a.basis_name()
|
|
293
|
+
'milnor'
|
|
294
|
+
sage: a.degree()
|
|
295
|
+
14
|
|
296
|
+
|
|
297
|
+
It can be viewed in other bases::
|
|
298
|
+
|
|
299
|
+
sage: a.milnor() # same as a
|
|
300
|
+
Sq(1,2,1)
|
|
301
|
+
sage: a.change_basis('adem')
|
|
302
|
+
Sq^9 Sq^4 Sq^1 + Sq^11 Sq^2 Sq^1 + Sq^13 Sq^1
|
|
303
|
+
sage: a.change_basis('adem').change_basis('milnor')
|
|
304
|
+
Sq(1,2,1)
|
|
305
|
+
|
|
306
|
+
Regardless of the prime, each element has an ``excess``, and if the
|
|
307
|
+
element is homogeneous, a ``degree``. The excess of
|
|
308
|
+
`\text{Sq}(i_1,i_2,i_3,...)` is `i_1 + i_2 + i_3 + ...`; when `p` is
|
|
309
|
+
odd, the excess of `Q_{0}^{e_0} Q_{1}^{e_1} ... \mathcal{P}(r_1, r_2,
|
|
310
|
+
...)` is `\sum e_i + 2 \sum r_i`. The excess of a linear combination
|
|
311
|
+
of Milnor basis elements is the minimum of the excesses of those basis
|
|
312
|
+
elements.
|
|
313
|
+
|
|
314
|
+
The degree of `\text{Sq}(i_1,i_2,i_3,...)` is `\sum (2^n-1) i_n`, and
|
|
315
|
+
when `p` is odd, the degree of `Q_{0}^{\epsilon_0} Q_{1}^{\epsilon_1}
|
|
316
|
+
... \mathcal{P}(r_1, r_2, ...)` is `\sum \epsilon_i (2p^i - 1) + \sum
|
|
317
|
+
r_j (2p^j - 2)`. The degree of a linear combination of such terms is
|
|
318
|
+
only defined if the terms all have the same degree.
|
|
319
|
+
|
|
320
|
+
Here are some simple examples::
|
|
321
|
+
|
|
322
|
+
sage: z = Sq(1,2) + Sq(4,1)
|
|
323
|
+
sage: z.degree()
|
|
324
|
+
7
|
|
325
|
+
sage: (Sq(0,0,1) + Sq(5,3)).degree()
|
|
326
|
+
Traceback (most recent call last):
|
|
327
|
+
...
|
|
328
|
+
ValueError: element is not homogeneous
|
|
329
|
+
sage: Sq(7,2,1).excess()
|
|
330
|
+
10
|
|
331
|
+
sage: z.excess()
|
|
332
|
+
3
|
|
333
|
+
sage: B = SteenrodAlgebra(3)
|
|
334
|
+
sage: x = B.Q(1,4)
|
|
335
|
+
sage: y = B.P(1,2,3)
|
|
336
|
+
sage: x.degree()
|
|
337
|
+
166
|
|
338
|
+
sage: x.excess()
|
|
339
|
+
2
|
|
340
|
+
sage: y.excess()
|
|
341
|
+
12
|
|
342
|
+
|
|
343
|
+
Elements have a ``weight`` in the May filtration, which (when `p=2`)
|
|
344
|
+
is related to the ``height`` function defined by Wall::
|
|
345
|
+
|
|
346
|
+
sage: Sq(2,1,5).may_weight()
|
|
347
|
+
9
|
|
348
|
+
sage: Sq(2,1,5).wall_height()
|
|
349
|
+
[2, 3, 2, 1, 1]
|
|
350
|
+
sage: b = Sq(4)*Sq(8) + Sq(8)*Sq(4)
|
|
351
|
+
sage: b.may_weight()
|
|
352
|
+
2
|
|
353
|
+
sage: b.wall_height()
|
|
354
|
+
[0, 0, 1, 1]
|
|
355
|
+
|
|
356
|
+
Odd primary May weights::
|
|
357
|
+
|
|
358
|
+
sage: A5 = SteenrodAlgebra(5)
|
|
359
|
+
sage: a = A5.Q(1,2,4)
|
|
360
|
+
sage: b = A5.P(1,2,1)
|
|
361
|
+
sage: a.may_weight()
|
|
362
|
+
10
|
|
363
|
+
sage: b.may_weight()
|
|
364
|
+
8
|
|
365
|
+
sage: (a * b).may_weight()
|
|
366
|
+
18
|
|
367
|
+
sage: A5.P(0,0,1).may_weight()
|
|
368
|
+
3
|
|
369
|
+
|
|
370
|
+
Since the Steenrod algebra is a Hopf algebra, every element has a
|
|
371
|
+
coproduct and an antipode::
|
|
372
|
+
|
|
373
|
+
sage: Sq(5).coproduct()
|
|
374
|
+
1 # Sq(5) + Sq(1) # Sq(4) + Sq(2) # Sq(3) + Sq(3) # Sq(2) + Sq(4) # Sq(1) + Sq(5) # 1
|
|
375
|
+
sage: Sq(5).antipode()
|
|
376
|
+
Sq(2,1) + Sq(5)
|
|
377
|
+
sage: d = Sq(0,0,1); d
|
|
378
|
+
Sq(0,0,1)
|
|
379
|
+
sage: d.antipode()
|
|
380
|
+
Sq(0,0,1)
|
|
381
|
+
sage: Sq(4).antipode()
|
|
382
|
+
Sq(1,1) + Sq(4)
|
|
383
|
+
sage: (Sq(4) * Sq(2)).antipode()
|
|
384
|
+
Sq(6)
|
|
385
|
+
sage: SteenrodAlgebra(7).P(3,1).antipode()
|
|
386
|
+
P(3,1)
|
|
387
|
+
|
|
388
|
+
Applying the antipode twice returns the original element::
|
|
389
|
+
|
|
390
|
+
sage: y = Sq(8)*Sq(4)
|
|
391
|
+
sage: y == (y.antipode()).antipode()
|
|
392
|
+
True
|
|
393
|
+
|
|
394
|
+
Internal representation: you can use any element as an iterator (``for
|
|
395
|
+
x in a: ...``), and the method :meth:`monomial_coefficients` returns a
|
|
396
|
+
dictionary with keys tuples representing basis elements and with
|
|
397
|
+
corresponding value representing the coefficient of that term::
|
|
398
|
+
|
|
399
|
+
sage: c = Sq(5).antipode(); c
|
|
400
|
+
Sq(2,1) + Sq(5)
|
|
401
|
+
sage: for mono, coeff in c: print((coeff, mono))
|
|
402
|
+
(1, (5,))
|
|
403
|
+
(1, (2, 1))
|
|
404
|
+
sage: c.monomial_coefficients() == {(2, 1): 1, (5,): 1}
|
|
405
|
+
True
|
|
406
|
+
sage: sorted(c.monomials(), key=lambda x: tuple(x.support()))
|
|
407
|
+
[Sq(2,1), Sq(5)]
|
|
408
|
+
sage: sorted(c.support())
|
|
409
|
+
[(2, 1), (5,)]
|
|
410
|
+
sage: Adem = SteenrodAlgebra(basis='adem')
|
|
411
|
+
sage: elt = Adem.Sq(10) + Adem.Sq(9) * Adem.Sq(1)
|
|
412
|
+
sage: sorted(elt.monomials(), key=lambda x: tuple(x.support()))
|
|
413
|
+
[Sq^9 Sq^1, Sq^10]
|
|
414
|
+
|
|
415
|
+
sage: A7 = SteenrodAlgebra(p=7)
|
|
416
|
+
sage: a = A7.P(1) * A7.P(1); a
|
|
417
|
+
2 P(2)
|
|
418
|
+
sage: a.leading_coefficient()
|
|
419
|
+
2
|
|
420
|
+
sage: a.leading_monomial()
|
|
421
|
+
P(2)
|
|
422
|
+
sage: a.leading_term()
|
|
423
|
+
2 P(2)
|
|
424
|
+
sage: a.change_basis('adem').monomial_coefficients()
|
|
425
|
+
{(0, 2, 0): 2}
|
|
426
|
+
|
|
427
|
+
The tuple in the previous output stands for the element `\beta^0
|
|
428
|
+
P^2 \beta^0`, i.e., `P^2`. Going in the other direction, if you
|
|
429
|
+
want to specify a basis element by giving the corresponding tuple,
|
|
430
|
+
you can use the :meth:`monomial` method on the algebra::
|
|
431
|
+
|
|
432
|
+
sage: SteenrodAlgebra(p=7, basis='adem').monomial((0, 2, 0))
|
|
433
|
+
P^2
|
|
434
|
+
sage: 10 * SteenrodAlgebra(p=7, basis='adem').monomial((0, 2, 0))
|
|
435
|
+
3 P^2
|
|
436
|
+
|
|
437
|
+
In the following example, elements in Wood's Z basis are certain
|
|
438
|
+
products of the elements `w(m,k) = \text{Sq}^{2^m (2^{k+1}-1)}`.
|
|
439
|
+
Internally, each `w(m,k)` is represented by the pair `(m,k)`, and
|
|
440
|
+
products of them are represented by tuples of such pairs. ::
|
|
441
|
+
|
|
442
|
+
sage: A = SteenrodAlgebra(basis='wood_z')
|
|
443
|
+
sage: t = ((2, 0), (0, 0))
|
|
444
|
+
sage: A.monomial(t)
|
|
445
|
+
Sq^4 Sq^1
|
|
446
|
+
|
|
447
|
+
See the documentation for :func:`SteenrodAlgebra` for more details and
|
|
448
|
+
examples.
|
|
449
|
+
"""
|
|
450
|
+
|
|
451
|
+
# ****************************************************************************
|
|
452
|
+
# Copyright (C) 2008-2010 John H. Palmieri <palmieri@math.washington.edu>
|
|
453
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
454
|
+
# ****************************************************************************
|
|
455
|
+
|
|
456
|
+
from sage.categories.homset import Hom
|
|
457
|
+
from sage.categories.modules_with_basis import ModulesWithBasis
|
|
458
|
+
from sage.categories.tensor import tensor
|
|
459
|
+
from sage.combinat.free_module import CombinatorialFreeModule
|
|
460
|
+
from sage.misc.cachefunc import cached_method
|
|
461
|
+
from sage.misc.lazy_attribute import lazy_attribute
|
|
462
|
+
from sage.sets.family import Family
|
|
463
|
+
|
|
464
|
+
######################################################
|
|
465
|
+
# the main class
|
|
466
|
+
######################################################
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
class SteenrodAlgebra_generic(CombinatorialFreeModule):
|
|
470
|
+
r"""
|
|
471
|
+
The mod `p` Steenrod algebra.
|
|
472
|
+
|
|
473
|
+
Users should not call this, but use the function
|
|
474
|
+
:func:`SteenrodAlgebra` instead. See that function for
|
|
475
|
+
extensive documentation.
|
|
476
|
+
|
|
477
|
+
EXAMPLES::
|
|
478
|
+
|
|
479
|
+
sage: sage.algebras.steenrod.steenrod_algebra.SteenrodAlgebra_generic()
|
|
480
|
+
mod 2 Steenrod algebra, milnor basis
|
|
481
|
+
sage: sage.algebras.steenrod.steenrod_algebra.SteenrodAlgebra_generic(5)
|
|
482
|
+
mod 5 Steenrod algebra, milnor basis
|
|
483
|
+
sage: sage.algebras.steenrod.steenrod_algebra.SteenrodAlgebra_generic(5, 'adem')
|
|
484
|
+
mod 5 Steenrod algebra, serre-cartan basis
|
|
485
|
+
"""
|
|
486
|
+
@staticmethod
|
|
487
|
+
def __classcall__(self, p=2, basis='milnor', **kwds):
|
|
488
|
+
"""
|
|
489
|
+
This normalizes the basis name and the profile, to make unique
|
|
490
|
+
representation work properly.
|
|
491
|
+
|
|
492
|
+
EXAMPLES::
|
|
493
|
+
|
|
494
|
+
sage: SteenrodAlgebra(basis='adem') is SteenrodAlgebra(basis='serre-cartan')
|
|
495
|
+
True
|
|
496
|
+
sage: SteenrodAlgebra(profile=[3,2,1,0]) is SteenrodAlgebra(profile=lambda n: max(4-n,0), truncation_type=0)
|
|
497
|
+
True
|
|
498
|
+
sage: SteenrodAlgebra(p=5) is SteenrodAlgebra(p=5, generic=True)
|
|
499
|
+
True
|
|
500
|
+
"""
|
|
501
|
+
from .steenrod_algebra_misc import get_basis_name, normalize_profile
|
|
502
|
+
profile = kwds.get('profile', None)
|
|
503
|
+
precision = kwds.get('precision', None)
|
|
504
|
+
truncation_type = kwds.get('truncation_type', 'auto')
|
|
505
|
+
generic = kwds.get('generic', 'auto')
|
|
506
|
+
if generic == 'auto':
|
|
507
|
+
std_generic = p != 2
|
|
508
|
+
else:
|
|
509
|
+
std_generic = generic
|
|
510
|
+
if p != 2:
|
|
511
|
+
std_generic = True
|
|
512
|
+
if not (std_generic is True or std_generic is False):
|
|
513
|
+
raise ValueError("option 'generic' is not a boolean")
|
|
514
|
+
|
|
515
|
+
std_basis = get_basis_name(basis, p, generic=std_generic)
|
|
516
|
+
std_profile, std_type = normalize_profile(profile, precision=precision,
|
|
517
|
+
truncation_type=truncation_type, p=p, generic=std_generic)
|
|
518
|
+
return super().__classcall__(self, p=p, basis=std_basis, profile=std_profile,
|
|
519
|
+
truncation_type=std_type, generic=std_generic)
|
|
520
|
+
|
|
521
|
+
def __init__(self, p=2, basis='milnor', **kwds):
|
|
522
|
+
r"""
|
|
523
|
+
INPUT:
|
|
524
|
+
|
|
525
|
+
- ``p`` -- positive prime integer (default: 2)
|
|
526
|
+
- ``basis`` -- string (default: ``'milnor'``)
|
|
527
|
+
- ``profile`` -- profile function (default: ``None``)
|
|
528
|
+
- ``truncation_type`` -- (default: ``'auto'``)
|
|
529
|
+
- ``precision`` -- (default: ``None``)
|
|
530
|
+
- ``generic`` -- (default: ``'auto'``)
|
|
531
|
+
|
|
532
|
+
OUTPUT:
|
|
533
|
+
|
|
534
|
+
mod `p` Steenrod algebra with basis, or a sub-Hopf
|
|
535
|
+
algebra of the mod `p` Steenrod algebra defined by the given
|
|
536
|
+
profile function.
|
|
537
|
+
|
|
538
|
+
See :func:`SteenrodAlgebra` for full documentation.
|
|
539
|
+
|
|
540
|
+
EXAMPLES::
|
|
541
|
+
|
|
542
|
+
sage: SteenrodAlgebra() # 2 is the default prime
|
|
543
|
+
mod 2 Steenrod algebra, milnor basis
|
|
544
|
+
sage: SteenrodAlgebra(5)
|
|
545
|
+
mod 5 Steenrod algebra, milnor basis
|
|
546
|
+
sage: SteenrodAlgebra(2, 'milnor').Sq(0,1)
|
|
547
|
+
Sq(0,1)
|
|
548
|
+
sage: SteenrodAlgebra(2, 'adem').Sq(0,1)
|
|
549
|
+
Sq^2 Sq^1 + Sq^3
|
|
550
|
+
|
|
551
|
+
TESTS::
|
|
552
|
+
|
|
553
|
+
sage: TestSuite(SteenrodAlgebra()).run()
|
|
554
|
+
sage: TestSuite(SteenrodAlgebra(profile=[4,3,2,2,1])).run()
|
|
555
|
+
sage: TestSuite(SteenrodAlgebra(basis='adem')).run()
|
|
556
|
+
sage: TestSuite(SteenrodAlgebra(basis='wall')).run()
|
|
557
|
+
sage: TestSuite(SteenrodAlgebra(basis='arnonc')).run() # long time
|
|
558
|
+
sage: TestSuite(SteenrodAlgebra(basis='woody')).run() # long time
|
|
559
|
+
sage: A3 = SteenrodAlgebra(3)
|
|
560
|
+
sage: A3.category()
|
|
561
|
+
Category of supercocommutative super Hopf algebras
|
|
562
|
+
with basis over Finite Field of size 3
|
|
563
|
+
sage: TestSuite(A3).run() # long time
|
|
564
|
+
sage: TestSuite(SteenrodAlgebra(basis='adem', p=3)).run()
|
|
565
|
+
sage: TestSuite(SteenrodAlgebra(basis='pst_llex', p=7)).run() # long time
|
|
566
|
+
sage: TestSuite(SteenrodAlgebra(basis='comm_deg', p=5)).run() # long time
|
|
567
|
+
sage: TestSuite(SteenrodAlgebra(p=2, generic=True)).run() # long time
|
|
568
|
+
|
|
569
|
+
Two Steenrod algebras are equal iff their associated primes,
|
|
570
|
+
bases, and profile functions (if present) are equal. Because
|
|
571
|
+
this class inherits from :class:`UniqueRepresentation`, this
|
|
572
|
+
means that they are equal if and only they are identical: ``A
|
|
573
|
+
== B`` is True if and only if ``A is B`` is ``True``::
|
|
574
|
+
|
|
575
|
+
sage: A = SteenrodAlgebra(2)
|
|
576
|
+
sage: B = SteenrodAlgebra(2, 'adem')
|
|
577
|
+
sage: A == B
|
|
578
|
+
False
|
|
579
|
+
sage: C = SteenrodAlgebra(17)
|
|
580
|
+
sage: A == C
|
|
581
|
+
False
|
|
582
|
+
|
|
583
|
+
sage: A1 = SteenrodAlgebra(2, profile=[2,1])
|
|
584
|
+
sage: A1 == A
|
|
585
|
+
False
|
|
586
|
+
sage: A1 == SteenrodAlgebra(2, profile=[2,1,0])
|
|
587
|
+
True
|
|
588
|
+
sage: A1 == SteenrodAlgebra(2, profile=[2,1], basis='pst')
|
|
589
|
+
False
|
|
590
|
+
"""
|
|
591
|
+
from sage.arith.misc import is_prime
|
|
592
|
+
from sage.categories.super_hopf_algebras_with_basis import SuperHopfAlgebrasWithBasis
|
|
593
|
+
from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets
|
|
594
|
+
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
|
|
595
|
+
from sage.rings.infinity import Infinity
|
|
596
|
+
from sage.sets.set_from_iterator import EnumeratedSetFromIterator
|
|
597
|
+
from functools import partial
|
|
598
|
+
from .steenrod_algebra_bases import steenrod_algebra_basis
|
|
599
|
+
from sage.rings.finite_rings.finite_field_constructor import GF
|
|
600
|
+
profile = kwds.get('profile', None)
|
|
601
|
+
truncation_type = kwds.get('truncation_type', 'auto')
|
|
602
|
+
self._generic = kwds.get('generic')
|
|
603
|
+
assert (self._generic is True or (p == 2 and self._generic is False))
|
|
604
|
+
|
|
605
|
+
if not is_prime(p):
|
|
606
|
+
raise ValueError("%s is not prime" % p)
|
|
607
|
+
self._prime = p
|
|
608
|
+
base_ring = GF(p)
|
|
609
|
+
self._profile = profile
|
|
610
|
+
self._truncation_type = truncation_type
|
|
611
|
+
if ((not self._generic and profile and profile[0] < Infinity)
|
|
612
|
+
or (self._generic and profile != ((), ()) and profile[0]
|
|
613
|
+
and profile[0][0] < Infinity)
|
|
614
|
+
or (truncation_type < Infinity)):
|
|
615
|
+
if basis != 'milnor' and basis.find('pst') == -1:
|
|
616
|
+
raise NotImplementedError("for sub-Hopf algebras of the Steenrod algebra, only the Milnor basis and the pst bases are implemented")
|
|
617
|
+
self._basis_name = basis
|
|
618
|
+
basis_category = FiniteEnumeratedSets() if self.is_finite() else InfiniteEnumeratedSets()
|
|
619
|
+
basis_set = EnumeratedSetFromIterator(self._basis_key_iterator,
|
|
620
|
+
category=basis_category,
|
|
621
|
+
name="basis key family of %s" % self,
|
|
622
|
+
cache=False)
|
|
623
|
+
|
|
624
|
+
self._basis_fcn = partial(steenrod_algebra_basis,
|
|
625
|
+
p=p,
|
|
626
|
+
basis=basis,
|
|
627
|
+
profile=profile,
|
|
628
|
+
truncation_type=truncation_type,
|
|
629
|
+
generic=self._generic)
|
|
630
|
+
|
|
631
|
+
cat = SuperHopfAlgebrasWithBasis(base_ring).Supercocommutative()
|
|
632
|
+
CombinatorialFreeModule.__init__(self,
|
|
633
|
+
base_ring,
|
|
634
|
+
basis_set,
|
|
635
|
+
prefix=self._basis_name,
|
|
636
|
+
element_class=self.Element,
|
|
637
|
+
category=cat,
|
|
638
|
+
scalar_mult=' ')
|
|
639
|
+
|
|
640
|
+
# For the graded modules
|
|
641
|
+
from sage.modules.fp_graded.steenrod.module import SteenrodFPModule, SteenrodFreeModule
|
|
642
|
+
self._fp_graded_module_class = SteenrodFPModule
|
|
643
|
+
self._free_graded_module_class = SteenrodFreeModule
|
|
644
|
+
|
|
645
|
+
def _basis_key_iterator(self):
|
|
646
|
+
"""
|
|
647
|
+
An iterator for the basis keys of the Steenrod algebra.
|
|
648
|
+
|
|
649
|
+
EXAMPLES::
|
|
650
|
+
|
|
651
|
+
sage: A = SteenrodAlgebra(3,basis='adem')
|
|
652
|
+
sage: for (idx,key) in zip((1,..,10),A._basis_key_iterator()):
|
|
653
|
+
....: print("> %2d %-20s %s" % (idx,key,A.monomial(key)))
|
|
654
|
+
> 1 () 1
|
|
655
|
+
> 2 (1,) beta
|
|
656
|
+
> 3 (0, 1, 0) P^1
|
|
657
|
+
> 4 (1, 1, 0) beta P^1
|
|
658
|
+
> 5 (0, 1, 1) P^1 beta
|
|
659
|
+
> 6 (1, 1, 1) beta P^1 beta
|
|
660
|
+
> 7 (0, 2, 0) P^2
|
|
661
|
+
> 8 (1, 2, 0) beta P^2
|
|
662
|
+
> 9 (0, 2, 1) P^2 beta
|
|
663
|
+
> 10 (1, 2, 1) beta P^2 beta
|
|
664
|
+
"""
|
|
665
|
+
from .steenrod_algebra_bases import steenrod_algebra_basis
|
|
666
|
+
from sage.sets.integer_range import IntegerRange
|
|
667
|
+
from sage.rings.integer import Integer
|
|
668
|
+
from sage.rings.infinity import Infinity
|
|
669
|
+
from functools import partial
|
|
670
|
+
import itertools
|
|
671
|
+
if self.is_finite():
|
|
672
|
+
maxdim = self.top_class().degree()
|
|
673
|
+
Ir = IntegerRange(Integer(0), Integer(maxdim + 1))
|
|
674
|
+
else:
|
|
675
|
+
Ir = IntegerRange(Integer(0), Infinity)
|
|
676
|
+
basfnc = partial(steenrod_algebra_basis,
|
|
677
|
+
p=self.prime(),
|
|
678
|
+
basis=self._basis_name,
|
|
679
|
+
profile=self._profile,
|
|
680
|
+
truncation_type=self._truncation_type)
|
|
681
|
+
return itertools.chain.from_iterable(basfnc(dim) for dim in Ir)
|
|
682
|
+
|
|
683
|
+
def prime(self):
|
|
684
|
+
r"""
|
|
685
|
+
The prime associated to ``self``.
|
|
686
|
+
|
|
687
|
+
EXAMPLES::
|
|
688
|
+
|
|
689
|
+
sage: SteenrodAlgebra(p=2, profile=[1,1]).prime()
|
|
690
|
+
2
|
|
691
|
+
sage: SteenrodAlgebra(p=7).prime()
|
|
692
|
+
7
|
|
693
|
+
"""
|
|
694
|
+
return self._prime
|
|
695
|
+
|
|
696
|
+
def basis_name(self):
|
|
697
|
+
r"""
|
|
698
|
+
The basis name associated to ``self``.
|
|
699
|
+
|
|
700
|
+
EXAMPLES::
|
|
701
|
+
|
|
702
|
+
sage: SteenrodAlgebra(p=2, profile=[1,1]).basis_name()
|
|
703
|
+
'milnor'
|
|
704
|
+
sage: SteenrodAlgebra(basis='serre-cartan').basis_name()
|
|
705
|
+
'serre-cartan'
|
|
706
|
+
sage: SteenrodAlgebra(basis='adem').basis_name()
|
|
707
|
+
'serre-cartan'
|
|
708
|
+
"""
|
|
709
|
+
return self.prefix()
|
|
710
|
+
|
|
711
|
+
def _has_nontrivial_profile(self):
|
|
712
|
+
r"""
|
|
713
|
+
Return ``True`` if the profile function for this algebra seems to be that
|
|
714
|
+
for a proper sub-Hopf algebra of the Steenrod algebra.
|
|
715
|
+
|
|
716
|
+
EXAMPLES::
|
|
717
|
+
|
|
718
|
+
sage: SteenrodAlgebra()._has_nontrivial_profile()
|
|
719
|
+
False
|
|
720
|
+
sage: SteenrodAlgebra(p=3)._has_nontrivial_profile()
|
|
721
|
+
False
|
|
722
|
+
sage: SteenrodAlgebra(profile=[3,2,1])._has_nontrivial_profile()
|
|
723
|
+
True
|
|
724
|
+
sage: SteenrodAlgebra(profile=([1], [2, 2]), p=3)._has_nontrivial_profile()
|
|
725
|
+
True
|
|
726
|
+
sage: SteenrodAlgebra(generic=True)._has_nontrivial_profile()
|
|
727
|
+
False
|
|
728
|
+
sage: SteenrodAlgebra(generic=True, profile=[[3,2,1], []])._has_nontrivial_profile()
|
|
729
|
+
True
|
|
730
|
+
|
|
731
|
+
Check that a bug in :issue:`11832` has been fixed::
|
|
732
|
+
|
|
733
|
+
sage: P3 = SteenrodAlgebra(p=3, profile=(lambda n: Infinity, lambda n: 1))
|
|
734
|
+
sage: P3._has_nontrivial_profile()
|
|
735
|
+
True
|
|
736
|
+
"""
|
|
737
|
+
from sage.rings.infinity import Infinity
|
|
738
|
+
profile = self._profile
|
|
739
|
+
trunc = self._truncation_type
|
|
740
|
+
if not self._generic:
|
|
741
|
+
return ((profile and profile[0] < Infinity)
|
|
742
|
+
or (trunc < Infinity))
|
|
743
|
+
return ((profile != ((), ()) and
|
|
744
|
+
((profile[0] and profile[0][0] < Infinity)
|
|
745
|
+
or (profile[1] and min(profile[1]) == 1)))
|
|
746
|
+
or (trunc < Infinity))
|
|
747
|
+
|
|
748
|
+
def _repr_(self):
|
|
749
|
+
r"""
|
|
750
|
+
Printed representation of the Steenrod algebra.
|
|
751
|
+
|
|
752
|
+
EXAMPLES::
|
|
753
|
+
|
|
754
|
+
sage: SteenrodAlgebra(3)
|
|
755
|
+
mod 3 Steenrod algebra, milnor basis
|
|
756
|
+
sage: SteenrodAlgebra(2, basis='adem')
|
|
757
|
+
mod 2 Steenrod algebra, serre-cartan basis
|
|
758
|
+
sage: B = SteenrodAlgebra(2003) # needs sage.rings.finite_rings
|
|
759
|
+
sage: B._repr_() # needs sage.rings.finite_rings
|
|
760
|
+
'mod 2003 Steenrod algebra, milnor basis'
|
|
761
|
+
sage: SteenrodAlgebra(generic=True, basis='adem')
|
|
762
|
+
generic mod 2 Steenrod algebra, serre-cartan basis
|
|
763
|
+
|
|
764
|
+
sage: SteenrodAlgebra(profile=(3,2,1,0))
|
|
765
|
+
sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
|
|
766
|
+
sage: SteenrodAlgebra(profile=lambda n: 4)
|
|
767
|
+
sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 4, 4, ..., 4, 4, +Infinity, +Infinity, +Infinity, ...]
|
|
768
|
+
sage: SteenrodAlgebra(p=5, profile=(lambda n: 4, lambda n: 1))
|
|
769
|
+
sub-Hopf algebra of mod 5 Steenrod algebra, milnor basis, profile function ([4, 4, 4, ..., 4, 4, +Infinity, +Infinity, +Infinity, ...], [1, 1, 1, ..., 1, 1, 2, 2, ...])
|
|
770
|
+
"""
|
|
771
|
+
def abridge_list(l):
|
|
772
|
+
"""
|
|
773
|
+
String rep for list ``l`` if ``l`` is short enough;
|
|
774
|
+
otherwise print the first few terms and the last few
|
|
775
|
+
terms, with an ellipsis in between.
|
|
776
|
+
"""
|
|
777
|
+
if len(l) < 8:
|
|
778
|
+
l_str = str(l)
|
|
779
|
+
else:
|
|
780
|
+
l_str = str(l[:3]).rstrip("]") + ", ..., " + str(l[-2:]).lstrip("[")
|
|
781
|
+
return l_str
|
|
782
|
+
|
|
783
|
+
from sage.rings.infinity import Infinity
|
|
784
|
+
profile = self._profile
|
|
785
|
+
trunc = self._truncation_type
|
|
786
|
+
p = self.prime()
|
|
787
|
+
genprefix = "generic " if p == 2 and self._generic else ""
|
|
788
|
+
if self._has_nontrivial_profile():
|
|
789
|
+
if not self._generic:
|
|
790
|
+
pro_str = abridge_list(list(profile))
|
|
791
|
+
if trunc != 0:
|
|
792
|
+
pro_str = pro_str.rstrip("]") + ", " + str([Infinity] * 3).strip("[]") + ", ...]"
|
|
793
|
+
else:
|
|
794
|
+
e_str = abridge_list(list(profile[0]))
|
|
795
|
+
k_str = abridge_list(list(profile[1]))
|
|
796
|
+
if trunc != 0:
|
|
797
|
+
e_str = e_str.rstrip("]") + ", " + str([Infinity] * 3).strip("[]") + ", ...]"
|
|
798
|
+
k_str = k_str.rstrip("]") + ", " + str([2] * 2).strip("[]") + ", ...]"
|
|
799
|
+
pro_str = "(%s, %s)" % (e_str, k_str)
|
|
800
|
+
return "sub-Hopf algebra of %smod %d Steenrod algebra, %s basis, profile function %s" % (genprefix, self.prime(), self._basis_name, pro_str)
|
|
801
|
+
return "%smod %d Steenrod algebra, %s basis" % (genprefix, self.prime(), self._basis_name)
|
|
802
|
+
|
|
803
|
+
def _latex_(self):
|
|
804
|
+
r"""
|
|
805
|
+
LaTeX representation of the Steenrod algebra.
|
|
806
|
+
|
|
807
|
+
EXAMPLES::
|
|
808
|
+
|
|
809
|
+
sage: C = SteenrodAlgebra(3)
|
|
810
|
+
sage: C
|
|
811
|
+
mod 3 Steenrod algebra, milnor basis
|
|
812
|
+
sage: C._latex_()
|
|
813
|
+
'\\mathcal{A}_{3}'
|
|
814
|
+
"""
|
|
815
|
+
return "\\mathcal{A}_{%s}" % self.prime()
|
|
816
|
+
|
|
817
|
+
def _repr_term(self, t):
|
|
818
|
+
r"""
|
|
819
|
+
String representation of the monomial specified by the tuple ``t``.
|
|
820
|
+
|
|
821
|
+
INPUT:
|
|
822
|
+
|
|
823
|
+
- ``t`` -- tuple, representing basis element in the current basis
|
|
824
|
+
|
|
825
|
+
OUTPUT: string
|
|
826
|
+
|
|
827
|
+
This is tested in many places: any place elements are printed
|
|
828
|
+
is essentially a doctest for this method. Also, each basis
|
|
829
|
+
has its own method for printing monomials, and those are
|
|
830
|
+
doctested individually. We give a few doctests here, in
|
|
831
|
+
addition.
|
|
832
|
+
|
|
833
|
+
EXAMPLES::
|
|
834
|
+
|
|
835
|
+
sage: SteenrodAlgebra()._repr_term((3,2))
|
|
836
|
+
'Sq(3,2)'
|
|
837
|
+
sage: SteenrodAlgebra(p=7)._repr_term(((0,2), (3,2)))
|
|
838
|
+
'Q_0 Q_2 P(3,2)'
|
|
839
|
+
sage: SteenrodAlgebra(basis='adem')._repr_term((14,2))
|
|
840
|
+
'Sq^14 Sq^2'
|
|
841
|
+
sage: SteenrodAlgebra(basis='adem', p=3)._repr_term((1,3,0))
|
|
842
|
+
'beta P^3'
|
|
843
|
+
sage: SteenrodAlgebra(basis='pst')._repr_term(((0,2), (1,3)))
|
|
844
|
+
'P^0_2 P^1_3'
|
|
845
|
+
sage: SteenrodAlgebra(basis='arnon_a')._repr_term(((0,2), (1,3)))
|
|
846
|
+
'X^0_2 X^1_3'
|
|
847
|
+
|
|
848
|
+
sage: A7 = SteenrodAlgebra(7)
|
|
849
|
+
sage: x = A7.Q(0,3) * A7.P(2,2)
|
|
850
|
+
sage: x._repr_()
|
|
851
|
+
'Q_0 Q_3 P(2,2)'
|
|
852
|
+
sage: x
|
|
853
|
+
Q_0 Q_3 P(2,2)
|
|
854
|
+
sage: a = SteenrodAlgebra().Sq(0,0,2)
|
|
855
|
+
sage: a
|
|
856
|
+
Sq(0,0,2)
|
|
857
|
+
sage: A2_adem = SteenrodAlgebra(2,'admissible')
|
|
858
|
+
sage: A2_adem(a)
|
|
859
|
+
Sq^8 Sq^4 Sq^2 + Sq^9 Sq^4 Sq^1 + Sq^10 Sq^3 Sq^1 +
|
|
860
|
+
Sq^10 Sq^4 + Sq^11 Sq^2 Sq^1 + Sq^12 Sq^2 + Sq^13 Sq^1
|
|
861
|
+
+ Sq^14
|
|
862
|
+
sage: SteenrodAlgebra(2, 'woodz')(a)
|
|
863
|
+
Sq^6 Sq^7 Sq^1 + Sq^14 + Sq^4 Sq^7 Sq^3 + Sq^4 Sq^7
|
|
864
|
+
Sq^2 Sq^1 + Sq^12 Sq^2 + Sq^8 Sq^6 + Sq^8 Sq^4 Sq^2
|
|
865
|
+
sage: SteenrodAlgebra(2, 'arnonc')(a)
|
|
866
|
+
Sq^4 Sq^2 Sq^8 + Sq^4 Sq^4 Sq^6 + Sq^4 Sq^6 Sq^4 +
|
|
867
|
+
Sq^6 Sq^8 + Sq^8 Sq^4 Sq^2 + Sq^8 Sq^6
|
|
868
|
+
sage: SteenrodAlgebra(2, 'pst_llex')(a)
|
|
869
|
+
P^1_3
|
|
870
|
+
sage: SteenrodAlgebra(2, 'comm_revz')(a)
|
|
871
|
+
c_0,1 c_1,1 c_0,3 c_2,1 + c_0,2 c_0,3 c_2,1 + c_1,3
|
|
872
|
+
sage: SteenrodAlgebra(2, generic=True, basis='pst').P(0,0,2)
|
|
873
|
+
P^1_3
|
|
874
|
+
"""
|
|
875
|
+
from .steenrod_algebra_misc import milnor_mono_to_string, \
|
|
876
|
+
serre_cartan_mono_to_string, wood_mono_to_string, \
|
|
877
|
+
wall_mono_to_string, wall_long_mono_to_string, \
|
|
878
|
+
arnonA_mono_to_string, arnonA_long_mono_to_string, \
|
|
879
|
+
pst_mono_to_string, \
|
|
880
|
+
comm_long_mono_to_string, comm_mono_to_string
|
|
881
|
+
p = self.prime()
|
|
882
|
+
basis = self.basis_name()
|
|
883
|
+
if basis == 'milnor':
|
|
884
|
+
s = milnor_mono_to_string(t, generic=self._generic)
|
|
885
|
+
elif basis == 'serre-cartan':
|
|
886
|
+
s = serre_cartan_mono_to_string(t, generic=self._generic)
|
|
887
|
+
elif basis.find('wood') >= 0:
|
|
888
|
+
s = wood_mono_to_string(t)
|
|
889
|
+
elif basis == 'wall':
|
|
890
|
+
s = wall_mono_to_string(t)
|
|
891
|
+
elif basis == 'wall_long':
|
|
892
|
+
s = wall_long_mono_to_string(t)
|
|
893
|
+
elif basis == 'arnona':
|
|
894
|
+
s = arnonA_mono_to_string(t)
|
|
895
|
+
elif basis == 'arnona_long':
|
|
896
|
+
s = arnonA_long_mono_to_string(t)
|
|
897
|
+
elif basis == 'arnonc':
|
|
898
|
+
s = serre_cartan_mono_to_string(t, generic=self._generic)
|
|
899
|
+
elif basis.find('pst') >= 0:
|
|
900
|
+
s = pst_mono_to_string(t, generic=self._generic)
|
|
901
|
+
elif basis.find('comm') >= 0 and basis.find('long') >= 0:
|
|
902
|
+
s = comm_long_mono_to_string(t, p, generic=self._generic)
|
|
903
|
+
elif basis.find('comm') >= 0:
|
|
904
|
+
s = comm_mono_to_string(t, generic=self._generic)
|
|
905
|
+
s = s.replace('{', '').replace('}', '')
|
|
906
|
+
return s
|
|
907
|
+
|
|
908
|
+
def _latex_term(self, t):
|
|
909
|
+
r"""
|
|
910
|
+
LaTeX representation of the monomial specified by the tuple ``t``.
|
|
911
|
+
|
|
912
|
+
INPUT:
|
|
913
|
+
|
|
914
|
+
- ``t`` -- tuple, representing basis element in the current basis
|
|
915
|
+
|
|
916
|
+
OUTPUT: string
|
|
917
|
+
|
|
918
|
+
The string depends on the basis over which the element is defined.
|
|
919
|
+
|
|
920
|
+
EXAMPLES::
|
|
921
|
+
|
|
922
|
+
sage: A7 = SteenrodAlgebra(7)
|
|
923
|
+
sage: A7._latex_term(((0, 3), (2,2)))
|
|
924
|
+
'Q_{0} Q_{3} \\mathcal{P}(2,2)'
|
|
925
|
+
sage: x = A7.Q(0,3) * A7.P(2,2)
|
|
926
|
+
sage: x._latex_() # indirect doctest
|
|
927
|
+
'Q_{0} Q_{3} \\mathcal{P}(2,2)'
|
|
928
|
+
sage: latex(x)
|
|
929
|
+
Q_{0} Q_{3} \mathcal{P}(2,2)
|
|
930
|
+
sage: b = Sq(0,2)
|
|
931
|
+
sage: b.change_basis('adem')._latex_()
|
|
932
|
+
'\\text{Sq}^{4} \\text{Sq}^{2} + \\text{Sq}^{5} \\text{Sq}^{1} +
|
|
933
|
+
\\text{Sq}^{6}'
|
|
934
|
+
sage: b.change_basis('woody')._latex_()
|
|
935
|
+
'\\text{Sq}^{2} \\text{Sq}^{3} \\text{Sq}^{1} + \\text{Sq}^{6} +
|
|
936
|
+
\\text{Sq}^{4} \\text{Sq}^{2}'
|
|
937
|
+
sage: SteenrodAlgebra(2, 'arnona')(b)._latex_()
|
|
938
|
+
'X^{1}_{1} X^{2}_{2} + X^{2}_{1}'
|
|
939
|
+
sage: SteenrodAlgebra(p=3, basis='serre-cartan').Q(0)._latex_()
|
|
940
|
+
'\\beta'
|
|
941
|
+
sage: latex(Sq(2).change_basis('adem').coproduct())
|
|
942
|
+
1 \otimes \text{Sq}^{2} + \text{Sq}^{1} \otimes \text{Sq}^{1} + \text{Sq}^{2} \otimes 1
|
|
943
|
+
sage: latex(SteenrodAlgebra(basis='pst').P(0,0,2))
|
|
944
|
+
P^{1}_{3}
|
|
945
|
+
"""
|
|
946
|
+
import re
|
|
947
|
+
s = self._repr_term(t)
|
|
948
|
+
s = re.sub(r"\^([0-9]*)", r"^{\1}", s)
|
|
949
|
+
s = re.sub("_([0-9,]*)", r"_{\1}", s)
|
|
950
|
+
s = s.replace("Sq", "\\text{Sq}")
|
|
951
|
+
if not self.basis_name().find('pst') >= 0:
|
|
952
|
+
s = s.replace("P", "\\mathcal{P}")
|
|
953
|
+
s = s.replace("beta", "\\beta")
|
|
954
|
+
return s
|
|
955
|
+
|
|
956
|
+
def profile(self, i, component=0):
|
|
957
|
+
r"""
|
|
958
|
+
Profile function for this algebra.
|
|
959
|
+
|
|
960
|
+
INPUT:
|
|
961
|
+
|
|
962
|
+
- ``i`` -- integer
|
|
963
|
+
- ``component`` -- either 0 or 1 (default: 0)
|
|
964
|
+
|
|
965
|
+
OUTPUT: integer or `\infty`
|
|
966
|
+
|
|
967
|
+
See the documentation for
|
|
968
|
+
:mod:`sage.algebras.steenrod.steenrod_algebra` and
|
|
969
|
+
:func:`SteenrodAlgebra` for information on profile functions.
|
|
970
|
+
|
|
971
|
+
This applies the profile function to the integer `i`. Thus
|
|
972
|
+
when `p=2`, `i` must be a positive integer. When `p` is odd,
|
|
973
|
+
there are two profile functions, `e` and `k` (in the notation
|
|
974
|
+
of the aforementioned documentation), corresponding,
|
|
975
|
+
respectively to ``component=0`` and ``component=1``. So when
|
|
976
|
+
`p` is odd and ``component`` is 0, `i` must be positive, while
|
|
977
|
+
when ``component`` is 1, `i` must be nonnegative.
|
|
978
|
+
|
|
979
|
+
EXAMPLES::
|
|
980
|
+
|
|
981
|
+
sage: SteenrodAlgebra().profile(3)
|
|
982
|
+
+Infinity
|
|
983
|
+
sage: SteenrodAlgebra(profile=[3,2,1]).profile(1)
|
|
984
|
+
3
|
|
985
|
+
sage: SteenrodAlgebra(profile=[3,2,1]).profile(2)
|
|
986
|
+
2
|
|
987
|
+
|
|
988
|
+
When the profile is specified by a list, the default behavior
|
|
989
|
+
is to return zero values outside the range of the list. This
|
|
990
|
+
can be overridden if the algebra is created with an infinite
|
|
991
|
+
``truncation_type``::
|
|
992
|
+
|
|
993
|
+
sage: SteenrodAlgebra(profile=[3,2,1]).profile(9)
|
|
994
|
+
0
|
|
995
|
+
sage: SteenrodAlgebra(profile=[3,2,1], truncation_type=Infinity).profile(9)
|
|
996
|
+
+Infinity
|
|
997
|
+
|
|
998
|
+
sage: B = SteenrodAlgebra(p=3, profile=(lambda n: n, lambda n: 1))
|
|
999
|
+
sage: B.profile(3)
|
|
1000
|
+
3
|
|
1001
|
+
sage: B.profile(3, component=1)
|
|
1002
|
+
1
|
|
1003
|
+
|
|
1004
|
+
sage: EA = SteenrodAlgebra(generic=True, profile=(lambda n: n, lambda n: 1))
|
|
1005
|
+
sage: EA.profile(4)
|
|
1006
|
+
4
|
|
1007
|
+
sage: EA.profile(2, component=1)
|
|
1008
|
+
1
|
|
1009
|
+
"""
|
|
1010
|
+
# determine the tuple t to use
|
|
1011
|
+
if not self._generic:
|
|
1012
|
+
t = self._profile
|
|
1013
|
+
elif component == 0:
|
|
1014
|
+
t = self._profile[0]
|
|
1015
|
+
else:
|
|
1016
|
+
t = self._profile[1]
|
|
1017
|
+
# case 1: exponents of the xi's
|
|
1018
|
+
if not self._generic or component == 0:
|
|
1019
|
+
if i <= 0:
|
|
1020
|
+
return 0
|
|
1021
|
+
try:
|
|
1022
|
+
return t[i-1]
|
|
1023
|
+
except IndexError:
|
|
1024
|
+
return self._truncation_type
|
|
1025
|
+
else:
|
|
1026
|
+
# case 2: exponents of the tau's
|
|
1027
|
+
if i < 0:
|
|
1028
|
+
return 1
|
|
1029
|
+
try:
|
|
1030
|
+
return t[i]
|
|
1031
|
+
except IndexError:
|
|
1032
|
+
if self._truncation_type > 0:
|
|
1033
|
+
return 2
|
|
1034
|
+
else:
|
|
1035
|
+
return 1
|
|
1036
|
+
|
|
1037
|
+
def homogeneous_component(self, n):
|
|
1038
|
+
"""
|
|
1039
|
+
Return the `n`-th homogeneous piece of the Steenrod algebra.
|
|
1040
|
+
|
|
1041
|
+
INPUT:
|
|
1042
|
+
|
|
1043
|
+
- ``n`` -- integer
|
|
1044
|
+
|
|
1045
|
+
OUTPUT: a vector space spanned by the basis for this algebra in dimension `n`
|
|
1046
|
+
|
|
1047
|
+
EXAMPLES::
|
|
1048
|
+
|
|
1049
|
+
sage: A = SteenrodAlgebra()
|
|
1050
|
+
sage: A.homogeneous_component(4)
|
|
1051
|
+
Vector space spanned by (Sq(1,1), Sq(4)) over Finite Field of size 2
|
|
1052
|
+
sage: SteenrodAlgebra(profile=[2,1,0]).homogeneous_component(4)
|
|
1053
|
+
Vector space spanned by (Sq(1,1),) over Finite Field of size 2
|
|
1054
|
+
|
|
1055
|
+
The notation A[n] may also be used::
|
|
1056
|
+
|
|
1057
|
+
sage: A[5]
|
|
1058
|
+
Vector space spanned by (Sq(2,1), Sq(5)) over Finite Field of size 2
|
|
1059
|
+
sage: SteenrodAlgebra(basis='wall')[4]
|
|
1060
|
+
Vector space spanned by (Q^1_0 Q^0_0, Q^2_2) over Finite Field of size 2
|
|
1061
|
+
sage: SteenrodAlgebra(p=5)[17]
|
|
1062
|
+
Vector space spanned by (Q_1 P(1), Q_0 P(2)) over Finite Field of size 5
|
|
1063
|
+
|
|
1064
|
+
Note that A[n] is just a vector space, not a Hopf algebra, so
|
|
1065
|
+
its elements don't have products, coproducts, or antipodes
|
|
1066
|
+
defined on them. If you want to use operations like this on
|
|
1067
|
+
elements of some A[n], then convert them back to elements of A::
|
|
1068
|
+
|
|
1069
|
+
sage: sorted(A[5].basis())
|
|
1070
|
+
[milnor[(2, 1)], milnor[(5,)]]
|
|
1071
|
+
sage: a = list(A[5].basis())[1]
|
|
1072
|
+
sage: a # not in A, doesn't print like an element of A
|
|
1073
|
+
milnor[(5,)]
|
|
1074
|
+
sage: A(a) # in A
|
|
1075
|
+
Sq(5)
|
|
1076
|
+
sage: A(a) * A(a)
|
|
1077
|
+
Sq(7,1)
|
|
1078
|
+
sage: a * A(a) # only need to convert one factor
|
|
1079
|
+
Sq(7,1)
|
|
1080
|
+
sage: a.antipode() # not defined
|
|
1081
|
+
Traceback (most recent call last):
|
|
1082
|
+
...
|
|
1083
|
+
AttributeError: 'CombinatorialFreeModule_with_category.element_class' object has no attribute 'antipode'...
|
|
1084
|
+
sage: A(a).antipode() # convert to elt of A, then compute antipode
|
|
1085
|
+
Sq(2,1) + Sq(5)
|
|
1086
|
+
|
|
1087
|
+
sage: G = SteenrodAlgebra(p=5, profile=[[2,1], [2,2,2]], basis='pst')
|
|
1088
|
+
|
|
1089
|
+
TESTS:
|
|
1090
|
+
|
|
1091
|
+
The following sort of thing is also tested by the function
|
|
1092
|
+
:func:`steenrod_basis_error_check
|
|
1093
|
+
<sage.algebras.steenrod.steenrod_algebra_bases.steenrod_basis_error_check>`::
|
|
1094
|
+
|
|
1095
|
+
sage: H = SteenrodAlgebra(p=5, profile=[[2,1], [2,2,2]])
|
|
1096
|
+
sage: G = SteenrodAlgebra(p=5, profile=[[2,1], [2,2,2]], basis='pst')
|
|
1097
|
+
sage: max([H[n].dimension() - G[n].dimension() for n in range(100)])
|
|
1098
|
+
0
|
|
1099
|
+
"""
|
|
1100
|
+
from sage.rings.finite_rings.finite_field_constructor import GF
|
|
1101
|
+
basis = self._basis_fcn(n)
|
|
1102
|
+
M = CombinatorialFreeModule(GF(self.prime()), basis,
|
|
1103
|
+
element_class=self.Element,
|
|
1104
|
+
prefix=self._basis_name)
|
|
1105
|
+
M._name = "Vector space spanned by %s" % (tuple(self.monomial(a) for a in basis),)
|
|
1106
|
+
return M
|
|
1107
|
+
|
|
1108
|
+
__getitem__ = homogeneous_component
|
|
1109
|
+
|
|
1110
|
+
def one_basis(self):
|
|
1111
|
+
"""
|
|
1112
|
+
The index of the element 1 in the basis for the Steenrod algebra.
|
|
1113
|
+
|
|
1114
|
+
EXAMPLES::
|
|
1115
|
+
|
|
1116
|
+
sage: SteenrodAlgebra(p=2).one_basis()
|
|
1117
|
+
()
|
|
1118
|
+
sage: SteenrodAlgebra(p=7).one_basis()
|
|
1119
|
+
((), ())
|
|
1120
|
+
"""
|
|
1121
|
+
basis = self.basis_name()
|
|
1122
|
+
if basis == 'serre-cartan' or basis == 'arnonc':
|
|
1123
|
+
return (0,)
|
|
1124
|
+
if not self._generic:
|
|
1125
|
+
return ()
|
|
1126
|
+
return ((), ())
|
|
1127
|
+
|
|
1128
|
+
def product_on_basis(self, t1, t2):
|
|
1129
|
+
"""
|
|
1130
|
+
The product of two basis elements of this algebra.
|
|
1131
|
+
|
|
1132
|
+
INPUT:
|
|
1133
|
+
|
|
1134
|
+
- ``t1``, ``t2`` -- tuples, the indices of two basis elements of self
|
|
1135
|
+
|
|
1136
|
+
OUTPUT:
|
|
1137
|
+
|
|
1138
|
+
the product of the two corresponding basis elements,
|
|
1139
|
+
as an element of self
|
|
1140
|
+
|
|
1141
|
+
ALGORITHM: If the two elements are represented in the Milnor
|
|
1142
|
+
basis, use Milnor multiplication as implemented in
|
|
1143
|
+
:mod:`sage.algebras.steenrod.steenrod_algebra_mult`. If the two
|
|
1144
|
+
elements are represented in the Serre-Cartan basis, then
|
|
1145
|
+
multiply them using Adem relations (also implemented in
|
|
1146
|
+
:mod:`sage.algebras.steenrod.steenrod_algebra_mult`). This
|
|
1147
|
+
provides a good way of checking work -- multiply Milnor
|
|
1148
|
+
elements, then convert them to Adem elements and multiply
|
|
1149
|
+
those, and see if the answers correspond.
|
|
1150
|
+
|
|
1151
|
+
If the two elements are represented in some other basis, then
|
|
1152
|
+
convert them both to the Milnor basis and multiply.
|
|
1153
|
+
|
|
1154
|
+
EXAMPLES::
|
|
1155
|
+
|
|
1156
|
+
sage: Milnor = SteenrodAlgebra()
|
|
1157
|
+
sage: Milnor.product_on_basis((2,), (2,))
|
|
1158
|
+
Sq(1,1)
|
|
1159
|
+
sage: Adem = SteenrodAlgebra(basis='adem')
|
|
1160
|
+
sage: Adem.Sq(2) * Adem.Sq(2) # indirect doctest
|
|
1161
|
+
Sq^3 Sq^1
|
|
1162
|
+
|
|
1163
|
+
When multiplying elements from different bases, the left-hand
|
|
1164
|
+
factor determines the form of the output::
|
|
1165
|
+
|
|
1166
|
+
sage: Adem.Sq(2) * Milnor.Sq(2)
|
|
1167
|
+
Sq^3 Sq^1
|
|
1168
|
+
sage: Milnor.Sq(2) * Adem.Sq(2)
|
|
1169
|
+
Sq(1,1)
|
|
1170
|
+
|
|
1171
|
+
TESTS::
|
|
1172
|
+
|
|
1173
|
+
sage: all(Adem(Milnor.Sq(n) ** 3)._repr_() == (Adem.Sq(n) ** 3)._repr_() for n in range(10))
|
|
1174
|
+
True
|
|
1175
|
+
sage: Wall = SteenrodAlgebra(basis='wall')
|
|
1176
|
+
sage: Wall(Adem.Sq(4,4) * Milnor.Sq(4)) == Adem(Wall.Sq(4,4) * Milnor.Sq(4))
|
|
1177
|
+
True
|
|
1178
|
+
|
|
1179
|
+
sage: A3 = SteenrodAlgebra(p=3, basis='adem')
|
|
1180
|
+
sage: M3 = SteenrodAlgebra(p=3, basis='milnor')
|
|
1181
|
+
sage: all(A3(M3.P(n) * M3.Q(0) * M3.P(n))._repr_() == (A3.P(n) * A3.Q(0) * A3.P(n))._repr_() for n in range(5))
|
|
1182
|
+
True
|
|
1183
|
+
|
|
1184
|
+
sage: EA = SteenrodAlgebra(generic=True)
|
|
1185
|
+
sage: EA.product_on_basis(((1, 3), (2, 1)), ((2, ), (0, 0, 1)))
|
|
1186
|
+
Q_1 Q_2 Q_3 P(2,1,1)
|
|
1187
|
+
|
|
1188
|
+
sage: EA2 = SteenrodAlgebra(basis='serre-cartan', generic=True)
|
|
1189
|
+
sage: EA2.product_on_basis((1, 2, 0, 1, 0), (1, 2, 0, 1, 0))
|
|
1190
|
+
beta P^4 P^2 beta + beta P^5 beta P^1
|
|
1191
|
+
"""
|
|
1192
|
+
p = self.prime()
|
|
1193
|
+
basis = self.basis_name()
|
|
1194
|
+
if basis == 'milnor':
|
|
1195
|
+
if not self._generic:
|
|
1196
|
+
from .steenrod_algebra_mult import milnor_multiplication
|
|
1197
|
+
d = milnor_multiplication(t1, t2)
|
|
1198
|
+
else:
|
|
1199
|
+
from .steenrod_algebra_mult import milnor_multiplication_odd
|
|
1200
|
+
d = milnor_multiplication_odd(t1, t2, p)
|
|
1201
|
+
return self._from_dict(d, coerce=True)
|
|
1202
|
+
elif basis == 'serre-cartan':
|
|
1203
|
+
from .steenrod_algebra_mult import make_mono_admissible
|
|
1204
|
+
if self._generic:
|
|
1205
|
+
# make sure output has an odd number of terms. if both t1
|
|
1206
|
+
# and t2 have an odd number, concatenate them, adding the
|
|
1207
|
+
# middle term...
|
|
1208
|
+
#
|
|
1209
|
+
# if either t1 or t2 has an even number of terms, append a
|
|
1210
|
+
# 0.
|
|
1211
|
+
if (len(t1) % 2) == 0:
|
|
1212
|
+
t1 = t1 + (0,)
|
|
1213
|
+
if (len(t2) % 2) == 0:
|
|
1214
|
+
t2 = t2 + (0,)
|
|
1215
|
+
if t1[-1] + t2[0] == 2:
|
|
1216
|
+
return self.zero()
|
|
1217
|
+
mono = t1[:-1] + (t1[-1] + t2[0],) + t2[1:]
|
|
1218
|
+
d = make_mono_admissible(mono, p, generic=self._generic)
|
|
1219
|
+
else: # p=2
|
|
1220
|
+
mono = t1 + t2
|
|
1221
|
+
while len(mono) > 1 and mono[-1] == 0:
|
|
1222
|
+
mono = mono[:-1]
|
|
1223
|
+
d = make_mono_admissible(mono, generic=self._generic)
|
|
1224
|
+
return self._from_dict(d, coerce=True)
|
|
1225
|
+
else:
|
|
1226
|
+
x = self({t1: 1})
|
|
1227
|
+
y = self({t2: 1})
|
|
1228
|
+
A = SteenrodAlgebra(basis='milnor', p=p, generic=self._generic)
|
|
1229
|
+
return self(A(x) * A(y))
|
|
1230
|
+
|
|
1231
|
+
def coproduct_on_basis(self, t, algorithm=None):
|
|
1232
|
+
r"""
|
|
1233
|
+
The coproduct of a basis element of this algebra.
|
|
1234
|
+
|
|
1235
|
+
INPUT:
|
|
1236
|
+
|
|
1237
|
+
- ``t`` -- tuple, the index of a basis element of self
|
|
1238
|
+
|
|
1239
|
+
- ``algorithm`` -- ``None`` or a string, either 'milnor' or
|
|
1240
|
+
'serre-cartan' (or anything which will be converted to one
|
|
1241
|
+
of these by the function :func:`get_basis_name
|
|
1242
|
+
<sage.algebras.steenrod.steenrod_algebra_misc.get_basis_name>`.
|
|
1243
|
+
If ``None``, default to 'milnor' unless current basis is
|
|
1244
|
+
'serre-cartan', in which case use 'serre-cartan'.
|
|
1245
|
+
|
|
1246
|
+
ALGORITHM: The coproduct on a Milnor basis element `P(n_1,
|
|
1247
|
+
n_2, ...)` is `\sum P(i_1, i_2, ...) \otimes P(j_1, j_2,
|
|
1248
|
+
...)`, summed over all `i_k + j_k = n_k` for each `k`. At odd
|
|
1249
|
+
primes, each element `Q_n` is primitive: its coproduct is `Q_n
|
|
1250
|
+
\otimes 1 + 1 \otimes Q_n`.
|
|
1251
|
+
|
|
1252
|
+
One can deduce a coproduct formula for the Serre-Cartan basis
|
|
1253
|
+
from this: the coproduct on each `P^n` is `\sum P^i \otimes
|
|
1254
|
+
P^{n-i}` and at odd primes `\beta` is primitive. Since the
|
|
1255
|
+
coproduct is an algebra map, one can then compute the
|
|
1256
|
+
coproduct on any Serre-Cartan basis element.
|
|
1257
|
+
|
|
1258
|
+
Which of these methods is used is controlled by whether
|
|
1259
|
+
``algorithm`` is 'milnor' or 'serre-cartan'.
|
|
1260
|
+
|
|
1261
|
+
OUTPUT:
|
|
1262
|
+
|
|
1263
|
+
the coproduct of the corresponding basis element,
|
|
1264
|
+
as an element of ``self`` tensor ``self``.
|
|
1265
|
+
|
|
1266
|
+
EXAMPLES::
|
|
1267
|
+
|
|
1268
|
+
sage: A = SteenrodAlgebra()
|
|
1269
|
+
sage: A.coproduct_on_basis((3,))
|
|
1270
|
+
1 # Sq(3) + Sq(1) # Sq(2) + Sq(2) # Sq(1) + Sq(3) # 1
|
|
1271
|
+
|
|
1272
|
+
TESTS::
|
|
1273
|
+
|
|
1274
|
+
sage: all(A.coproduct_on_basis((n,1), algorithm='milnor') == A.coproduct_on_basis((n,1), algorithm='adem') for n in range(9)) # long time
|
|
1275
|
+
True
|
|
1276
|
+
sage: A7 = SteenrodAlgebra(p=7, basis='adem')
|
|
1277
|
+
sage: all(A7.coproduct_on_basis((0,n,1), algorithm='milnor') == A7.coproduct_on_basis((0,n,1), algorithm='adem') for n in range(9)) # long time
|
|
1278
|
+
True
|
|
1279
|
+
"""
|
|
1280
|
+
def coprod_list(t):
|
|
1281
|
+
"""
|
|
1282
|
+
If t = (n0, n1, ...), then return list of terms (i0, i1,
|
|
1283
|
+
...) where ik <= nk for each k. From each such term, can
|
|
1284
|
+
recover the second factor in the coproduct.
|
|
1285
|
+
"""
|
|
1286
|
+
if len(t) == 0:
|
|
1287
|
+
return [()]
|
|
1288
|
+
if len(t) == 1:
|
|
1289
|
+
return [[a] for a in range(t[0] + 1)]
|
|
1290
|
+
ans = []
|
|
1291
|
+
for i in range(t[0] + 1):
|
|
1292
|
+
ans.extend([[i] + x for x in coprod_list(t[1:])])
|
|
1293
|
+
return ans
|
|
1294
|
+
|
|
1295
|
+
from .steenrod_algebra_misc import get_basis_name
|
|
1296
|
+
p = self.prime()
|
|
1297
|
+
basis = self.basis_name()
|
|
1298
|
+
if algorithm is None:
|
|
1299
|
+
if basis == 'serre-cartan':
|
|
1300
|
+
algorithm = 'serre-cartan'
|
|
1301
|
+
else:
|
|
1302
|
+
algorithm = 'milnor'
|
|
1303
|
+
else:
|
|
1304
|
+
algorithm = get_basis_name(algorithm, p, generic=self._generic)
|
|
1305
|
+
if basis == algorithm:
|
|
1306
|
+
if basis == 'milnor':
|
|
1307
|
+
if not self._generic:
|
|
1308
|
+
left = coprod_list(t)
|
|
1309
|
+
right = [[x - y for x, y in zip(t, m)] for m in left]
|
|
1310
|
+
old = list(left)
|
|
1311
|
+
left = []
|
|
1312
|
+
# trim trailing zeros:
|
|
1313
|
+
for a in old:
|
|
1314
|
+
while a and a[-1] == 0:
|
|
1315
|
+
a = a[:-1]
|
|
1316
|
+
left.append(tuple(a))
|
|
1317
|
+
old = list(right)
|
|
1318
|
+
right = []
|
|
1319
|
+
for a in old:
|
|
1320
|
+
while a and a[-1] == 0:
|
|
1321
|
+
a = a[:-1]
|
|
1322
|
+
right.append(tuple(a))
|
|
1323
|
+
tens = dict.fromkeys(zip(left, right), 1)
|
|
1324
|
+
return self.tensor_square()._from_dict(tens, coerce=True)
|
|
1325
|
+
else: # p odd
|
|
1326
|
+
from sage.combinat.permutation import Permutation
|
|
1327
|
+
from .steenrod_algebra_misc import convert_perm
|
|
1328
|
+
from sage.sets.set import Set
|
|
1329
|
+
left_p = coprod_list(t[1])
|
|
1330
|
+
right_p = [[x - y for x, y in zip(t[1], m)] for m in left_p]
|
|
1331
|
+
old = list(left_p)
|
|
1332
|
+
left_p = []
|
|
1333
|
+
# trim trailing zeros:
|
|
1334
|
+
for a in old:
|
|
1335
|
+
while a and a[-1] == 0:
|
|
1336
|
+
a = a[:-1]
|
|
1337
|
+
left_p.append(tuple(a))
|
|
1338
|
+
old = list(right_p)
|
|
1339
|
+
right_p = []
|
|
1340
|
+
for a in old:
|
|
1341
|
+
while a and a[-1] == 0:
|
|
1342
|
+
a = a[:-1]
|
|
1343
|
+
right_p.append(tuple(a))
|
|
1344
|
+
all_q = Set(t[0])
|
|
1345
|
+
tens_q = {}
|
|
1346
|
+
for a in all_q.subsets():
|
|
1347
|
+
left_q = sorted(a)
|
|
1348
|
+
right_q = sorted(all_q - a)
|
|
1349
|
+
sign = Permutation(convert_perm(left_q + right_q)).signature()
|
|
1350
|
+
tens_q[(tuple(left_q), tuple(right_q))] = sign
|
|
1351
|
+
tens = {((q[0], l), (q[1], r)): tq
|
|
1352
|
+
for l, r in zip(left_p, right_p)
|
|
1353
|
+
for q, tq in tens_q.items()}
|
|
1354
|
+
return self.tensor_square()._from_dict(tens, coerce=True)
|
|
1355
|
+
elif basis == 'serre-cartan':
|
|
1356
|
+
result = self.tensor_square().one()
|
|
1357
|
+
if not self._generic:
|
|
1358
|
+
for n in t:
|
|
1359
|
+
s = self.tensor_square().zero()
|
|
1360
|
+
for i in range(n + 1):
|
|
1361
|
+
s += tensor((self.Sq(i), self.Sq(n-i)))
|
|
1362
|
+
result = result * s
|
|
1363
|
+
return result
|
|
1364
|
+
else:
|
|
1365
|
+
bockstein = True
|
|
1366
|
+
for n in t:
|
|
1367
|
+
if bockstein:
|
|
1368
|
+
if n != 0:
|
|
1369
|
+
s = tensor((self.Q(0), self.one())) + tensor((self.one(), self.Q(0)))
|
|
1370
|
+
else:
|
|
1371
|
+
s = self.tensor_square().one()
|
|
1372
|
+
bockstein = False
|
|
1373
|
+
else:
|
|
1374
|
+
s = self.tensor_square().zero()
|
|
1375
|
+
for i in range(n + 1):
|
|
1376
|
+
s += tensor((self.P(i), self.P(n-i)))
|
|
1377
|
+
bockstein = True
|
|
1378
|
+
result = result * s
|
|
1379
|
+
return result
|
|
1380
|
+
else:
|
|
1381
|
+
A = SteenrodAlgebra(p=p, basis=algorithm, generic=self._generic)
|
|
1382
|
+
x = A(self._change_basis_on_basis(t, algorithm)).coproduct(algorithm=algorithm)
|
|
1383
|
+
result = []
|
|
1384
|
+
for (a, b), coeff in x:
|
|
1385
|
+
result.append((tensor((A._change_basis_on_basis(a, basis),
|
|
1386
|
+
A._change_basis_on_basis(b, basis))),
|
|
1387
|
+
coeff))
|
|
1388
|
+
return self.tensor_square().linear_combination(result)
|
|
1389
|
+
|
|
1390
|
+
def coproduct(self, x, algorithm='milnor'):
|
|
1391
|
+
r"""
|
|
1392
|
+
Return the coproduct of an element ``x`` of this algebra.
|
|
1393
|
+
|
|
1394
|
+
INPUT:
|
|
1395
|
+
|
|
1396
|
+
- ``x`` -- element of ``self``
|
|
1397
|
+
|
|
1398
|
+
- ``algorithm`` -- ``None`` or a string, either ``'milnor'`` or
|
|
1399
|
+
``'serre-cartan'`` (or anything which will be converted to one
|
|
1400
|
+
of these by the function :func:`get_basis_name
|
|
1401
|
+
<sage.algebras.steenrod.steenrod_algebra_misc.get_basis_name>`.
|
|
1402
|
+
If ``None``, default to ``'serre-cartan'`` if current basis is
|
|
1403
|
+
``'serre-cartan'``; otherwise use ``'milnor'``.
|
|
1404
|
+
|
|
1405
|
+
This calls :meth:`coproduct_on_basis` on the summands of ``x``
|
|
1406
|
+
and extends linearly.
|
|
1407
|
+
|
|
1408
|
+
EXAMPLES::
|
|
1409
|
+
|
|
1410
|
+
sage: SteenrodAlgebra().Sq(3).coproduct()
|
|
1411
|
+
1 # Sq(3) + Sq(1) # Sq(2) + Sq(2) # Sq(1) + Sq(3) # 1
|
|
1412
|
+
|
|
1413
|
+
The element `\text{Sq}(0,1)` is primitive::
|
|
1414
|
+
|
|
1415
|
+
sage: SteenrodAlgebra(basis='adem').Sq(0,1).coproduct()
|
|
1416
|
+
1 # Sq^2 Sq^1 + 1 # Sq^3 + Sq^2 Sq^1 # 1 + Sq^3 # 1
|
|
1417
|
+
sage: SteenrodAlgebra(basis='pst').Sq(0,1).coproduct()
|
|
1418
|
+
1 # P^0_2 + P^0_2 # 1
|
|
1419
|
+
|
|
1420
|
+
sage: SteenrodAlgebra(p=3).P(4).coproduct()
|
|
1421
|
+
1 # P(4) + P(1) # P(3) + P(2) # P(2) + P(3) # P(1) + P(4) # 1
|
|
1422
|
+
sage: SteenrodAlgebra(p=3).P(4).coproduct(algorithm='serre-cartan')
|
|
1423
|
+
1 # P(4) + P(1) # P(3) + P(2) # P(2) + P(3) # P(1) + P(4) # 1
|
|
1424
|
+
sage: SteenrodAlgebra(p=3, basis='serre-cartan').P(4).coproduct()
|
|
1425
|
+
1 # P^4 + P^1 # P^3 + P^2 # P^2 + P^3 # P^1 + P^4 # 1
|
|
1426
|
+
sage: SteenrodAlgebra(p=11, profile=((), (2,1,2))).Q(0,2).coproduct()
|
|
1427
|
+
1 # Q_0 Q_2 + Q_0 # Q_2 + Q_0 Q_2 # 1 + 10*Q_2 # Q_0
|
|
1428
|
+
"""
|
|
1429
|
+
# taken from categories.coalgebras_with_basis, then modified
|
|
1430
|
+
# to allow the use of the "algorithm" keyword
|
|
1431
|
+
|
|
1432
|
+
def coprod(x):
|
|
1433
|
+
return self.coproduct_on_basis(x, algorithm)
|
|
1434
|
+
return Hom(self, tensor([self, self]),
|
|
1435
|
+
ModulesWithBasis(self.base_ring()))(on_basis=coprod)(x)
|
|
1436
|
+
|
|
1437
|
+
def antipode_on_basis(self, t):
|
|
1438
|
+
r"""
|
|
1439
|
+
The antipode of a basis element of this algebra.
|
|
1440
|
+
|
|
1441
|
+
INPUT:
|
|
1442
|
+
|
|
1443
|
+
- ``t`` -- tuple, the index of a basis element of ``self``
|
|
1444
|
+
|
|
1445
|
+
OUTPUT:
|
|
1446
|
+
|
|
1447
|
+
the antipode of the corresponding basis element,
|
|
1448
|
+
as an element of ``self``.
|
|
1449
|
+
|
|
1450
|
+
ALGORITHM: according to a result of Milnor's, the antipode of
|
|
1451
|
+
`\text{Sq}(n)` is the sum of all of the Milnor basis elements
|
|
1452
|
+
in dimension `n`. So: convert the element to the Serre-Cartan
|
|
1453
|
+
basis, thus writing it as a sum of products of elements
|
|
1454
|
+
`\text{Sq}(n)`, and use Milnor's formula for the antipode of
|
|
1455
|
+
`\text{Sq}(n)`, together with the fact that the antipode is an
|
|
1456
|
+
antihomomorphism: if we call the antipode `c`, then `c(ab) =
|
|
1457
|
+
c(b) c(a)`.
|
|
1458
|
+
|
|
1459
|
+
At odd primes, a similar method is used: the antipode of
|
|
1460
|
+
`P(n)` is the sum of the Milnor P basis elements in dimension
|
|
1461
|
+
`n*2(p-1)`, multiplied by `(-1)^n`, and the antipode of `\beta
|
|
1462
|
+
= Q_0` is `-Q_0`. So convert to the Serre-Cartan basis, as in
|
|
1463
|
+
the `p = 2` case. Note that in the odd prime case, there is a
|
|
1464
|
+
sign in the antihomomorphism formula:
|
|
1465
|
+
`c(ab) = (-1)^{\deg a \deg b} c(b) c(a)`.
|
|
1466
|
+
|
|
1467
|
+
EXAMPLES::
|
|
1468
|
+
|
|
1469
|
+
sage: A = SteenrodAlgebra()
|
|
1470
|
+
sage: A.antipode_on_basis((4,))
|
|
1471
|
+
Sq(1,1) + Sq(4)
|
|
1472
|
+
sage: A.Sq(4).antipode()
|
|
1473
|
+
Sq(1,1) + Sq(4)
|
|
1474
|
+
sage: Adem = SteenrodAlgebra(basis='adem')
|
|
1475
|
+
sage: Adem.Sq(4).antipode()
|
|
1476
|
+
Sq^3 Sq^1 + Sq^4
|
|
1477
|
+
sage: SteenrodAlgebra(basis='pst').Sq(3).antipode()
|
|
1478
|
+
P^0_1 P^1_1 + P^0_2
|
|
1479
|
+
sage: a = SteenrodAlgebra(basis='wall_long').Sq(10)
|
|
1480
|
+
sage: a.antipode()
|
|
1481
|
+
Sq^1 Sq^2 Sq^4 Sq^1 Sq^2 + Sq^2 Sq^4 Sq^1 Sq^2 Sq^1 + Sq^8 Sq^2
|
|
1482
|
+
sage: a.antipode().antipode() == a
|
|
1483
|
+
True
|
|
1484
|
+
|
|
1485
|
+
sage: SteenrodAlgebra(p=3).P(6).antipode()
|
|
1486
|
+
P(2,1) + P(6)
|
|
1487
|
+
sage: SteenrodAlgebra(p=3).P(6).antipode().antipode()
|
|
1488
|
+
P(6)
|
|
1489
|
+
|
|
1490
|
+
TESTS::
|
|
1491
|
+
|
|
1492
|
+
sage: Milnor = SteenrodAlgebra()
|
|
1493
|
+
sage: all(x.antipode().antipode() == x for x in Milnor.basis(11)) # long time
|
|
1494
|
+
True
|
|
1495
|
+
sage: A5 = SteenrodAlgebra(p=5, basis='adem')
|
|
1496
|
+
sage: all(x.antipode().antipode() == x for x in A5.basis(25))
|
|
1497
|
+
True
|
|
1498
|
+
sage: H = SteenrodAlgebra(profile=[2,2,1])
|
|
1499
|
+
sage: H.Sq(1,2).antipode() in H
|
|
1500
|
+
True
|
|
1501
|
+
|
|
1502
|
+
sage: Q = A5.Q
|
|
1503
|
+
sage: (Q(0) * Q(1)).antipode() == - Q(1).antipode() * Q(0).antipode()
|
|
1504
|
+
True
|
|
1505
|
+
"""
|
|
1506
|
+
p = self.prime()
|
|
1507
|
+
if self.basis_name() == 'serre-cartan':
|
|
1508
|
+
antipode = self.one()
|
|
1509
|
+
if not self._generic:
|
|
1510
|
+
for n in t:
|
|
1511
|
+
antipode = self(sum(SteenrodAlgebra().basis(n))) * antipode
|
|
1512
|
+
else:
|
|
1513
|
+
from sage.misc.functional import is_even
|
|
1514
|
+
for index, n in enumerate(t):
|
|
1515
|
+
if is_even(index):
|
|
1516
|
+
if n != 0:
|
|
1517
|
+
antipode = -self.Q(0) * antipode * (-1)**antipode.degree()
|
|
1518
|
+
else:
|
|
1519
|
+
B = SteenrodAlgebra(p=p, generic=self._generic).basis(n * 2 * (p-1))
|
|
1520
|
+
s = self(0)
|
|
1521
|
+
for b in B:
|
|
1522
|
+
if len(b.leading_support()[0]) == 0:
|
|
1523
|
+
s += self(b)
|
|
1524
|
+
antipode = (-1)**n * s * antipode
|
|
1525
|
+
return antipode
|
|
1526
|
+
return self(self._change_basis_on_basis(t, 'serre-cartan').antipode())
|
|
1527
|
+
|
|
1528
|
+
def counit_on_basis(self, t):
|
|
1529
|
+
"""
|
|
1530
|
+
The counit sends all elements of positive degree to zero.
|
|
1531
|
+
|
|
1532
|
+
INPUT:
|
|
1533
|
+
|
|
1534
|
+
- ``t`` -- tuple, the index of a basis element of ``self``
|
|
1535
|
+
|
|
1536
|
+
EXAMPLES::
|
|
1537
|
+
|
|
1538
|
+
sage: A2 = SteenrodAlgebra(p=2)
|
|
1539
|
+
sage: A2.counit_on_basis(())
|
|
1540
|
+
1
|
|
1541
|
+
sage: A2.counit_on_basis((0,0,1))
|
|
1542
|
+
0
|
|
1543
|
+
sage: parent(A2.counit_on_basis((0,0,1)))
|
|
1544
|
+
Finite Field of size 2
|
|
1545
|
+
sage: A3 = SteenrodAlgebra(p=3)
|
|
1546
|
+
sage: A3.counit_on_basis(((1,2,3), (1,1,1)))
|
|
1547
|
+
0
|
|
1548
|
+
sage: A3.counit_on_basis(((), ()))
|
|
1549
|
+
1
|
|
1550
|
+
sage: A3.counit(A3.P(10,5))
|
|
1551
|
+
0
|
|
1552
|
+
sage: A3.counit(A3.P(0))
|
|
1553
|
+
1
|
|
1554
|
+
"""
|
|
1555
|
+
if t != () and t != ((), ()):
|
|
1556
|
+
return self.base_ring().zero()
|
|
1557
|
+
else:
|
|
1558
|
+
return self.base_ring().one()
|
|
1559
|
+
|
|
1560
|
+
def _milnor_on_basis(self, t):
|
|
1561
|
+
r"""
|
|
1562
|
+
Convert the tuple ``t`` in the current basis to an element in the
|
|
1563
|
+
Milnor basis.
|
|
1564
|
+
|
|
1565
|
+
INPUT:
|
|
1566
|
+
|
|
1567
|
+
- ``t`` -- tuple, representing basis element in the current basis
|
|
1568
|
+
|
|
1569
|
+
OUTPUT: element of the Steenrod algebra with the Milnor basis
|
|
1570
|
+
|
|
1571
|
+
ALGORITHM: there is a simple conversion from each basis to the
|
|
1572
|
+
Milnor basis, so use that. In more detail:
|
|
1573
|
+
|
|
1574
|
+
- If the current basis is the Milnor basis, just return the
|
|
1575
|
+
corresponding element.
|
|
1576
|
+
|
|
1577
|
+
- If the current basis is the Serre-Cartan basis: when `p=2`,
|
|
1578
|
+
the element `\text{Sq}^a` equals the Milnor element
|
|
1579
|
+
`\text{Sq}(a)`; when `p` is odd, `\mathcal{P}^a =
|
|
1580
|
+
\mathcal{P}(a)` and `\beta = Q_0`. Hence for any
|
|
1581
|
+
Serre-Cartan basis element, represent it in the
|
|
1582
|
+
Milnor basis by computing an appropriate product using
|
|
1583
|
+
Milnor multiplication.
|
|
1584
|
+
|
|
1585
|
+
- The same goes for Arnon's C basis, since the elements are
|
|
1586
|
+
monomials in the Steenrod squares.
|
|
1587
|
+
|
|
1588
|
+
- If the current basis is Wood's Y or Z bases, then each basis
|
|
1589
|
+
element is a monomial in the classes `w(m,k) =
|
|
1590
|
+
\text{Sq}^{2^m (2^{k+1}-1)}`. So again, multiply the
|
|
1591
|
+
corresponding Milnor elements together.
|
|
1592
|
+
|
|
1593
|
+
- The Wall basis: each basis element is a monomial in the
|
|
1594
|
+
elements `Q^m_k = Sq(2^k) Sq(2^{k+1}) ... Sq(2^m)`.
|
|
1595
|
+
|
|
1596
|
+
- Arnon's A basis: each basis element is a monomial in the
|
|
1597
|
+
elements `X^m_k = Sq(2^m) ... Sq(2^{k+1}) Sq(2^k)`.
|
|
1598
|
+
|
|
1599
|
+
- The `P^s_t` bases: when `p=2`, each basis element is a
|
|
1600
|
+
monomial in the elements `P^s_t`. When `p` is odd, each
|
|
1601
|
+
basis element is a product of elements `Q_i` and a monomial
|
|
1602
|
+
in the elements `(P^s_t)^n` where `0 < n < p`.
|
|
1603
|
+
|
|
1604
|
+
- The commutator bases: when `p=2`, each basis element is a
|
|
1605
|
+
monomial in the iterated commutators `c_{i,j}`, defined by
|
|
1606
|
+
`c_{i,1} = \text{Sq}(2^i)` and `c_{i,j} = [c_{i,j-1},
|
|
1607
|
+
\text{Sq}(2^{i+j-1})]`. When `p` is odd, each basis element
|
|
1608
|
+
is a product of elements `Q_i` and a monomial in the
|
|
1609
|
+
elements `c_{i,j}^n` where `0 < n < p`, `c_{i,1} =
|
|
1610
|
+
P(p^i)` and `c_{i,j} = [P(p^{i+j-1}), c_{i,j-1}]`.
|
|
1611
|
+
|
|
1612
|
+
EXAMPLES::
|
|
1613
|
+
|
|
1614
|
+
sage: Adem = SteenrodAlgebra(basis='serre-cartan')
|
|
1615
|
+
sage: Adem._milnor_on_basis((2,1)) # Sq^2 Sq^1
|
|
1616
|
+
Sq(0,1) + Sq(3)
|
|
1617
|
+
sage: Pst = SteenrodAlgebra(basis='pst')
|
|
1618
|
+
sage: Pst._milnor_on_basis(((0,1), (1,1), (2,1)))
|
|
1619
|
+
Sq(7)
|
|
1620
|
+
"""
|
|
1621
|
+
basis = self.basis_name()
|
|
1622
|
+
p = self.prime()
|
|
1623
|
+
A = SteenrodAlgebra(p=p, generic=self._generic)
|
|
1624
|
+
# milnor
|
|
1625
|
+
if basis == 'milnor':
|
|
1626
|
+
return A({t: 1})
|
|
1627
|
+
|
|
1628
|
+
ans = A(1)
|
|
1629
|
+
# serre-cartan, arnonc
|
|
1630
|
+
if not self._generic and (basis == 'serre-cartan' or basis == 'arnonc'):
|
|
1631
|
+
for j in t:
|
|
1632
|
+
ans = ans * A.Sq(j)
|
|
1633
|
+
|
|
1634
|
+
elif self._generic and basis == 'serre-cartan':
|
|
1635
|
+
bockstein = True
|
|
1636
|
+
for j in t:
|
|
1637
|
+
if bockstein:
|
|
1638
|
+
if j != 0:
|
|
1639
|
+
ans = ans * A.Q(0)
|
|
1640
|
+
bockstein = False
|
|
1641
|
+
else:
|
|
1642
|
+
ans = ans * A.P(j)
|
|
1643
|
+
bockstein = True
|
|
1644
|
+
# wood_y:
|
|
1645
|
+
elif basis == 'woody' or basis == 'woodz':
|
|
1646
|
+
# each entry in t is a pair (m,k), corresponding to w(m,k), defined by
|
|
1647
|
+
# `w(m,k) = \text{Sq}^{2^m (2^{k+1}-1)}`.
|
|
1648
|
+
for (m, k) in t:
|
|
1649
|
+
ans = ans * A.Sq(2**m * (2**(k+1) - 1))
|
|
1650
|
+
|
|
1651
|
+
# wall[_long]
|
|
1652
|
+
elif basis.find('wall') >= 0:
|
|
1653
|
+
# each entry in t is a pair (m,k), corresponding to Q^m_k, defined by
|
|
1654
|
+
# `Q^m_k = Sq(2^k) Sq(2^{k+1}) ... Sq(2^m)`.
|
|
1655
|
+
for (m, k) in t:
|
|
1656
|
+
exponent = 2**k
|
|
1657
|
+
ans = ans * A.Sq(exponent)
|
|
1658
|
+
for i in range(m-k):
|
|
1659
|
+
exponent = exponent * 2
|
|
1660
|
+
ans = ans * A.Sq(exponent)
|
|
1661
|
+
|
|
1662
|
+
# pst...
|
|
1663
|
+
elif basis.find('pst') >= 0:
|
|
1664
|
+
if not self._generic:
|
|
1665
|
+
# each entry in t is a pair (i,j), corresponding to P^i_j
|
|
1666
|
+
for (i, j) in t:
|
|
1667
|
+
ans = ans * A.pst(i, j)
|
|
1668
|
+
else:
|
|
1669
|
+
# t = (Q, P) where Q is the tuple of Q_i's, and P is a
|
|
1670
|
+
# tuple with entries of the form ((i,j), n),
|
|
1671
|
+
# corresponding to (P^i_j)^n
|
|
1672
|
+
if t[0]:
|
|
1673
|
+
ans = ans * A.Q(*t[0])
|
|
1674
|
+
for ((i, j), n) in t[1]:
|
|
1675
|
+
ans = ans * (A.pst(i, j))**n
|
|
1676
|
+
|
|
1677
|
+
# arnona[_long]
|
|
1678
|
+
elif basis.find('arnona') >= 0:
|
|
1679
|
+
# each entry in t is a pair (m,k), corresponding to X^m_k, defined by
|
|
1680
|
+
# `X^m_k = Sq(2^m) ... Sq(2^{k+1}) Sq(2^k)`
|
|
1681
|
+
for (m, k) in t:
|
|
1682
|
+
exponent = 2**k
|
|
1683
|
+
X = A.Sq(exponent)
|
|
1684
|
+
for i in range(m-k):
|
|
1685
|
+
exponent = exponent * 2
|
|
1686
|
+
X = A.Sq(exponent) * X
|
|
1687
|
+
ans = ans * X
|
|
1688
|
+
|
|
1689
|
+
# comm...[_long]
|
|
1690
|
+
elif basis.find('comm') >= 0:
|
|
1691
|
+
if not self._generic:
|
|
1692
|
+
# each entry in t is a pair (i,j), corresponding to
|
|
1693
|
+
# c_{i,j}, the iterated commutator defined by c_{i,1}
|
|
1694
|
+
# = Sq(2^i) and c_{i,j} = [c_{i,j-1}, Sq(2^{i+j-1})].
|
|
1695
|
+
for (i, j) in t:
|
|
1696
|
+
comm = A.Sq(2**i)
|
|
1697
|
+
for k in range(2, j+1):
|
|
1698
|
+
y = A.Sq(2**(i+k-1))
|
|
1699
|
+
comm = comm * y + y * comm
|
|
1700
|
+
ans = ans * comm
|
|
1701
|
+
else:
|
|
1702
|
+
# t = (Q, P) where Q is the tuple of Q_i's, and P is a
|
|
1703
|
+
# tuple with entries of the form ((i,j), n),
|
|
1704
|
+
# corresponding to (c_{i,j})^n. Here c_{i,j} is the
|
|
1705
|
+
# iterated commutator defined by c_{i,1} = P(p^i) and
|
|
1706
|
+
# c_{i,j} = [P(p^{i+j-1}), c_{i,j-1}].
|
|
1707
|
+
if t[0]:
|
|
1708
|
+
ans = ans * A.Q(*t[0])
|
|
1709
|
+
for ((i, j), n) in t[1]:
|
|
1710
|
+
comm = A.P(p**i)
|
|
1711
|
+
for k in range(2, j+1):
|
|
1712
|
+
y = A.P(p**(i+k-1))
|
|
1713
|
+
comm = y * comm - comm * y
|
|
1714
|
+
ans = ans * comm**n
|
|
1715
|
+
return ans
|
|
1716
|
+
|
|
1717
|
+
@lazy_attribute
|
|
1718
|
+
def milnor(self):
|
|
1719
|
+
"""
|
|
1720
|
+
Convert an element of this algebra to the Milnor basis.
|
|
1721
|
+
|
|
1722
|
+
INPUT:
|
|
1723
|
+
|
|
1724
|
+
- ``x`` -- an element of this algebra
|
|
1725
|
+
|
|
1726
|
+
OUTPUT: x converted to the Milnor basis
|
|
1727
|
+
|
|
1728
|
+
ALGORITHM: use the method ``_milnor_on_basis`` and linearity.
|
|
1729
|
+
|
|
1730
|
+
EXAMPLES::
|
|
1731
|
+
|
|
1732
|
+
sage: Adem = SteenrodAlgebra(basis='adem')
|
|
1733
|
+
sage: a = Adem.Sq(2) * Adem.Sq(1)
|
|
1734
|
+
sage: Adem.milnor(a)
|
|
1735
|
+
Sq(0,1) + Sq(3)
|
|
1736
|
+
"""
|
|
1737
|
+
A = SteenrodAlgebra(p=self.prime(), basis='milnor', generic=self._generic)
|
|
1738
|
+
return self._module_morphism(self._milnor_on_basis, codomain=A)
|
|
1739
|
+
|
|
1740
|
+
def _change_basis_on_basis(self, t, basis='milnor'):
|
|
1741
|
+
"""
|
|
1742
|
+
Convert the tuple t to the named basis.
|
|
1743
|
+
|
|
1744
|
+
INPUT:
|
|
1745
|
+
|
|
1746
|
+
- ``t`` -- tuple, representing basis element in the current basis
|
|
1747
|
+
|
|
1748
|
+
- ``basis`` -- string, the basis to which to convert, optional
|
|
1749
|
+
(default: ``'milnor'``)
|
|
1750
|
+
|
|
1751
|
+
OUTPUT: an element of the Steenrod algebra with basis ``basis``
|
|
1752
|
+
|
|
1753
|
+
ALGORITHM: it's straightforward to convert to the Milnor basis
|
|
1754
|
+
(using :meth:`milnor` or :meth:`_milnor_on_basis`), so it's
|
|
1755
|
+
straightforward to produce a matrix representing this
|
|
1756
|
+
conversion in any degree. The function
|
|
1757
|
+
:func:`convert_from_milnor_matrix
|
|
1758
|
+
<steenrod_algebra_bases.convert_from_milnor_matrix>` provides
|
|
1759
|
+
the inverse operation.
|
|
1760
|
+
|
|
1761
|
+
So: convert from the current basis to the Milnor basis, then
|
|
1762
|
+
from the Milnor basis to the new basis.
|
|
1763
|
+
|
|
1764
|
+
EXAMPLES::
|
|
1765
|
+
|
|
1766
|
+
sage: Adem = SteenrodAlgebra(basis='adem')
|
|
1767
|
+
sage: a = Adem({(2,1): 1}); a
|
|
1768
|
+
Sq^2 Sq^1
|
|
1769
|
+
sage: a.change_basis('adem') # indirect doctest
|
|
1770
|
+
Sq^2 Sq^1
|
|
1771
|
+
sage: a.change_basis('milnor')
|
|
1772
|
+
Sq(0,1) + Sq(3)
|
|
1773
|
+
sage: a.change_basis('pst')
|
|
1774
|
+
P^0_1 P^1_1 + P^0_2
|
|
1775
|
+
sage: a.change_basis('milnor').change_basis('adem').change_basis('adem')
|
|
1776
|
+
Sq^2 Sq^1
|
|
1777
|
+
sage: a.change_basis('wall') == a.change_basis('woody')
|
|
1778
|
+
True
|
|
1779
|
+
|
|
1780
|
+
TESTS::
|
|
1781
|
+
|
|
1782
|
+
sage: a = sum(SteenrodAlgebra(basis='comm').basis(10))
|
|
1783
|
+
sage: a.change_basis('adem').change_basis('wall').change_basis('comm')._repr_() == a._repr_()
|
|
1784
|
+
True
|
|
1785
|
+
sage: a.change_basis('pst').change_basis('milnor').change_basis('comm')._repr_() == a._repr_()
|
|
1786
|
+
True
|
|
1787
|
+
sage: a.change_basis('woody').change_basis('arnona').change_basis('comm')._repr_() == a._repr_()
|
|
1788
|
+
True
|
|
1789
|
+
|
|
1790
|
+
sage: b = sum(SteenrodAlgebra(p=3).basis(41))
|
|
1791
|
+
sage: b.change_basis('adem').change_basis('adem').change_basis('milnor')._repr_() == b._repr_()
|
|
1792
|
+
True
|
|
1793
|
+
|
|
1794
|
+
sage: SteenrodAlgebra(generic=True).P(0,2).change_basis('serre-cartan')
|
|
1795
|
+
P^4 P^2 + P^5 P^1 + P^6
|
|
1796
|
+
"""
|
|
1797
|
+
from sage.matrix.constructor import matrix
|
|
1798
|
+
from sage.rings.finite_rings.finite_field_constructor import GF
|
|
1799
|
+
from .steenrod_algebra_bases import steenrod_algebra_basis, \
|
|
1800
|
+
convert_from_milnor_matrix
|
|
1801
|
+
from .steenrod_algebra_misc import get_basis_name
|
|
1802
|
+
basis = get_basis_name(basis, self.prime(), generic=self._generic)
|
|
1803
|
+
if basis == self.basis_name():
|
|
1804
|
+
return self({t: 1})
|
|
1805
|
+
a = self._milnor_on_basis(t)
|
|
1806
|
+
if basis == 'milnor':
|
|
1807
|
+
return a
|
|
1808
|
+
d = a.monomial_coefficients()
|
|
1809
|
+
p = self.prime()
|
|
1810
|
+
deg = a.degree()
|
|
1811
|
+
A = SteenrodAlgebra(basis=basis, p=p, generic=self._generic)
|
|
1812
|
+
if deg == 0:
|
|
1813
|
+
return A(a.leading_coefficient())
|
|
1814
|
+
Bnew = steenrod_algebra_basis(deg, basis, p, generic=self._generic)
|
|
1815
|
+
Bmil = steenrod_algebra_basis(deg, 'milnor', p, generic=self._generic)
|
|
1816
|
+
v = [d.get(a, 0) for a in Bmil]
|
|
1817
|
+
out = (matrix(GF(p), 1, len(v), v) *
|
|
1818
|
+
convert_from_milnor_matrix(deg, basis, p, generic=self._generic))
|
|
1819
|
+
new_d = dict(zip(Bnew, out[0]))
|
|
1820
|
+
return A(new_d)
|
|
1821
|
+
|
|
1822
|
+
def _change_basis(self, x, basis='milnor'):
|
|
1823
|
+
"""
|
|
1824
|
+
Convert an element of this algebra to the specified basis.
|
|
1825
|
+
|
|
1826
|
+
INPUT:
|
|
1827
|
+
|
|
1828
|
+
- ``x`` -- an element of this algebra
|
|
1829
|
+
|
|
1830
|
+
- ``basis`` -- string, the basis to which to convert, optional
|
|
1831
|
+
(default: ``'milnor'``)
|
|
1832
|
+
|
|
1833
|
+
OUTPUT: an element of the Steenrod algebra with basis ``basis``
|
|
1834
|
+
|
|
1835
|
+
ALGORITHM: use :meth:`_change_basis_on_basis` and linearity
|
|
1836
|
+
|
|
1837
|
+
EXAMPLES::
|
|
1838
|
+
|
|
1839
|
+
sage: Adem = SteenrodAlgebra(basis='adem')
|
|
1840
|
+
sage: a = Adem({(2,1): 1}); a
|
|
1841
|
+
Sq^2 Sq^1
|
|
1842
|
+
sage: a.change_basis('adem') # indirect doctest
|
|
1843
|
+
Sq^2 Sq^1
|
|
1844
|
+
sage: a.change_basis('milnor')
|
|
1845
|
+
Sq(0,1) + Sq(3)
|
|
1846
|
+
sage: a.change_basis('pst')
|
|
1847
|
+
P^0_1 P^1_1 + P^0_2
|
|
1848
|
+
"""
|
|
1849
|
+
if basis == 'milnor':
|
|
1850
|
+
return x.milnor()
|
|
1851
|
+
A = SteenrodAlgebra(p=self.prime(), basis=basis, generic=self._generic)
|
|
1852
|
+
|
|
1853
|
+
def change(y):
|
|
1854
|
+
return self._change_basis_on_basis(y, basis)
|
|
1855
|
+
f = self._module_morphism(change, codomain=A)
|
|
1856
|
+
return f(x)
|
|
1857
|
+
|
|
1858
|
+
def degree_on_basis(self, t):
|
|
1859
|
+
r"""
|
|
1860
|
+
The degree of the monomial specified by the tuple ``t``.
|
|
1861
|
+
|
|
1862
|
+
INPUT:
|
|
1863
|
+
|
|
1864
|
+
- ``t`` -- tuple, representing basis element in the current basis
|
|
1865
|
+
|
|
1866
|
+
OUTPUT: integer, the degree of the corresponding element
|
|
1867
|
+
|
|
1868
|
+
The degree of `\text{Sq}(i_1,i_2,i_3,...)` is
|
|
1869
|
+
|
|
1870
|
+
.. MATH::
|
|
1871
|
+
|
|
1872
|
+
i_1 + 3i_2 + 7i_3 + ... + (2^k - 1) i_k + ....
|
|
1873
|
+
|
|
1874
|
+
At an odd prime `p`, the degree of `Q_k` is `2p^k - 1` and the
|
|
1875
|
+
degree of `\mathcal{P}(i_1, i_2, ...)` is
|
|
1876
|
+
|
|
1877
|
+
.. MATH::
|
|
1878
|
+
|
|
1879
|
+
\sum_{k \geq 0} 2(p^k - 1) i_k.
|
|
1880
|
+
|
|
1881
|
+
ALGORITHM: Each basis element is represented in terms relevant
|
|
1882
|
+
to the particular basis: 'milnor' basis elements (at the prime
|
|
1883
|
+
2) are given by tuples ``(a,b,c,...)`` corresponding to the
|
|
1884
|
+
element `\text{Sq}(a,b,c,...)`, while 'pst' basis elements are
|
|
1885
|
+
given by tuples of pairs ``((a, b), (c, d), ...)``,
|
|
1886
|
+
corresponding to the product `P^a_b P^c_d ...`. The other
|
|
1887
|
+
bases have similar descriptions. The degree of each basis
|
|
1888
|
+
element is computed from this data, rather than converting the
|
|
1889
|
+
element to the Milnor basis, for example, and then computing
|
|
1890
|
+
the degree.
|
|
1891
|
+
|
|
1892
|
+
EXAMPLES::
|
|
1893
|
+
|
|
1894
|
+
sage: SteenrodAlgebra().degree_on_basis((0,0,1))
|
|
1895
|
+
7
|
|
1896
|
+
sage: Sq(7).degree()
|
|
1897
|
+
7
|
|
1898
|
+
|
|
1899
|
+
sage: A11 = SteenrodAlgebra(p=11)
|
|
1900
|
+
sage: A11.degree_on_basis(((), (1,1)))
|
|
1901
|
+
260
|
|
1902
|
+
sage: A11.degree_on_basis(((2,), ()))
|
|
1903
|
+
241
|
|
1904
|
+
"""
|
|
1905
|
+
def p_degree(m, mult=1, prime=2):
|
|
1906
|
+
"""
|
|
1907
|
+
For m=(n_1, n_2, n_3, ...), Sum_i (mult) * n_i * (p^i - 1)
|
|
1908
|
+
"""
|
|
1909
|
+
i = 0
|
|
1910
|
+
deg = 0
|
|
1911
|
+
for n in m:
|
|
1912
|
+
i += 1
|
|
1913
|
+
deg += n*mult*(prime**i - 1)
|
|
1914
|
+
return deg
|
|
1915
|
+
|
|
1916
|
+
def q_degree(m, prime=3):
|
|
1917
|
+
"""
|
|
1918
|
+
For m=(n_0, n_1, n_2, ...), Sum_i 2*p^(n_i) - 1
|
|
1919
|
+
"""
|
|
1920
|
+
deg = 0
|
|
1921
|
+
for n in m:
|
|
1922
|
+
deg += 2*prime**n - 1
|
|
1923
|
+
return deg
|
|
1924
|
+
|
|
1925
|
+
p = self.prime()
|
|
1926
|
+
basis = self.basis_name()
|
|
1927
|
+
# milnor
|
|
1928
|
+
if basis == 'milnor':
|
|
1929
|
+
if not self._generic:
|
|
1930
|
+
return p_degree(t)
|
|
1931
|
+
else:
|
|
1932
|
+
return q_degree(t[0], prime=p) + p_degree(t[1], prime=p, mult=2)
|
|
1933
|
+
# serre-cartan, arnonc
|
|
1934
|
+
if not self._generic and (basis == 'serre-cartan' or basis == 'arnonc'):
|
|
1935
|
+
return sum(t)
|
|
1936
|
+
if self._generic and basis == 'serre-cartan':
|
|
1937
|
+
bockstein = True
|
|
1938
|
+
n = 0
|
|
1939
|
+
for j in t:
|
|
1940
|
+
if bockstein:
|
|
1941
|
+
if j != 0:
|
|
1942
|
+
n += 1
|
|
1943
|
+
bockstein = False
|
|
1944
|
+
else:
|
|
1945
|
+
n += 2 * j * (p - 1)
|
|
1946
|
+
bockstein = True
|
|
1947
|
+
return n
|
|
1948
|
+
|
|
1949
|
+
# wood_y:
|
|
1950
|
+
if basis == 'woody' or basis == 'woodz':
|
|
1951
|
+
# each entry in t is a pair (m,k), corresponding to w(m,k), defined by
|
|
1952
|
+
# `w(m,k) = \text{Sq}^{2^m (2^{k+1}-1)}`.
|
|
1953
|
+
return sum(2**m * (2**(k+1)-1) for (m, k) in t)
|
|
1954
|
+
|
|
1955
|
+
# wall, arnon_a
|
|
1956
|
+
if basis.find('wall') >= 0 or basis.find('arnona') >= 0:
|
|
1957
|
+
# Wall: each entry in t is a pair (m,k), corresponding to
|
|
1958
|
+
# Q^m_k, defined by `Q^m_k = Sq(2^k) Sq(2^{k+1})
|
|
1959
|
+
# ... Sq(2^m)`.
|
|
1960
|
+
#
|
|
1961
|
+
# Arnon A: each entry in t is a pair (m,k), corresponding
|
|
1962
|
+
# to X^m_k, defined by `X^m_k = Sq(2^m) ... Sq(2^{k+1})
|
|
1963
|
+
# Sq(2^k)`
|
|
1964
|
+
return sum(2**k * (2**(m-k+1)-1) for (m, k) in t)
|
|
1965
|
+
|
|
1966
|
+
# pst, comm
|
|
1967
|
+
if basis.find('pst') >= 0 or basis.find('comm') >= 0:
|
|
1968
|
+
if not self._generic:
|
|
1969
|
+
# Pst: each entry in t is a pair (i,j), corresponding to P^i_j
|
|
1970
|
+
#
|
|
1971
|
+
# Comm: each entry in t is a pair (i,j), corresponding
|
|
1972
|
+
# to c_{i,j}, the iterated commutator defined by
|
|
1973
|
+
# c_{i,1} = Sq(2^i) and c_{i,j} = [c_{i,j-1},
|
|
1974
|
+
# Sq(2^{i+j-1})].
|
|
1975
|
+
return sum(2**m * (2**k - 1) for (m, k) in t)
|
|
1976
|
+
# p odd:
|
|
1977
|
+
#
|
|
1978
|
+
# Pst: have pair (Q, P) where Q is a tuple of Q's, as in
|
|
1979
|
+
# the Milnor basis, and P is a tuple of terms of the form
|
|
1980
|
+
# ((i,j), n), corresponding to (P^i_j)^n.
|
|
1981
|
+
#
|
|
1982
|
+
# Comm: similarly (Q, C) with Q as above and C a tuple
|
|
1983
|
+
# with each entry in t is of the form ((s,t), n),
|
|
1984
|
+
# corresponding to c_{s,t}^n. here c_{s,t} is the
|
|
1985
|
+
# iterated commutator defined by c_{s,1} = P(p^s) and
|
|
1986
|
+
# c_{s,t} = [P(p^{s+t-1}), c_{s,t-1}].
|
|
1987
|
+
q_deg = q_degree(t[0], prime=p)
|
|
1988
|
+
p_deg = sum(2 * n * p**s * (p**t - 1) for ((s, t), n) in t[1])
|
|
1989
|
+
return q_deg + p_deg
|
|
1990
|
+
|
|
1991
|
+
# coercion methods:
|
|
1992
|
+
|
|
1993
|
+
def _coerce_map_from_(self, S):
|
|
1994
|
+
r"""
|
|
1995
|
+
Return ``True`` if there is a coercion from ``S`` to ``self``, ``False``
|
|
1996
|
+
otherwise.
|
|
1997
|
+
|
|
1998
|
+
INPUT:
|
|
1999
|
+
|
|
2000
|
+
- ``S`` -- a Sage object
|
|
2001
|
+
|
|
2002
|
+
The algebras that coerce into the mod p Steenrod algebra are:
|
|
2003
|
+
|
|
2004
|
+
- the mod p Steenrod algebra `A`
|
|
2005
|
+
- its sub-Hopf algebras
|
|
2006
|
+
- its homogeneous components
|
|
2007
|
+
- its base field `GF(p)`
|
|
2008
|
+
- `ZZ`
|
|
2009
|
+
|
|
2010
|
+
Similarly, a sub-Hopf algebra `B` of `A` coerces into another
|
|
2011
|
+
sub-Hopf algebra `C` if and only if the profile function for
|
|
2012
|
+
`B` is less than or equal to that of `C`, pointwise.
|
|
2013
|
+
|
|
2014
|
+
EXAMPLES::
|
|
2015
|
+
|
|
2016
|
+
sage: A = SteenrodAlgebra()
|
|
2017
|
+
sage: A1 = SteenrodAlgebra(profile=[2,1])
|
|
2018
|
+
sage: A2 = SteenrodAlgebra(profile=[3,2,1])
|
|
2019
|
+
sage: B = SteenrodAlgebra(profile=[1,2,1])
|
|
2020
|
+
sage: A._coerce_map_from_(A1)
|
|
2021
|
+
True
|
|
2022
|
+
sage: A2._coerce_map_from_(A1)
|
|
2023
|
+
True
|
|
2024
|
+
sage: A1._coerce_map_from_(A)
|
|
2025
|
+
False
|
|
2026
|
+
sage: A1._coerce_map_from_(B)
|
|
2027
|
+
False
|
|
2028
|
+
sage: B._coerce_map_from_(A1)
|
|
2029
|
+
False
|
|
2030
|
+
|
|
2031
|
+
sage: A._coerce_map_from_(A[12])
|
|
2032
|
+
True
|
|
2033
|
+
|
|
2034
|
+
sage: EA = SteenrodAlgebra(generic=True)
|
|
2035
|
+
sage: A._coerce_map_from_(EA)
|
|
2036
|
+
False
|
|
2037
|
+
sage: EA._coerce_map_from_(A)
|
|
2038
|
+
False
|
|
2039
|
+
sage: EA._coerce_map_from_(EA)
|
|
2040
|
+
True
|
|
2041
|
+
|
|
2042
|
+
sage: A3 = SteenrodAlgebra(p=3)
|
|
2043
|
+
sage: A31 = SteenrodAlgebra(p=3, profile=([1], [2, 2]))
|
|
2044
|
+
sage: B3 = SteenrodAlgebra(p=3, profile=([1, 2, 1], [1]))
|
|
2045
|
+
sage: A3._coerce_map_from_(A31)
|
|
2046
|
+
True
|
|
2047
|
+
sage: A31._coerce_map_from_(A3)
|
|
2048
|
+
False
|
|
2049
|
+
sage: A31._coerce_map_from_(B3)
|
|
2050
|
+
False
|
|
2051
|
+
sage: B3._coerce_map_from_(A31)
|
|
2052
|
+
False
|
|
2053
|
+
"""
|
|
2054
|
+
from sage.rings.integer_ring import ZZ
|
|
2055
|
+
from sage.rings.finite_rings.finite_field_constructor import GF
|
|
2056
|
+
from sage.rings.infinity import Infinity
|
|
2057
|
+
p = self.prime()
|
|
2058
|
+
if S == ZZ or S == GF(p):
|
|
2059
|
+
return True
|
|
2060
|
+
if (isinstance(S, SteenrodAlgebra_generic) and p == S.prime() and self._generic == S._generic):
|
|
2061
|
+
# deal with profiles.
|
|
2062
|
+
if not self._generic:
|
|
2063
|
+
self_prec = len(self._profile)
|
|
2064
|
+
S_prec = len(S._profile)
|
|
2065
|
+
return all(self.profile(i) >= S.profile(i)
|
|
2066
|
+
for i in range(1, max(self_prec, S_prec)+1))
|
|
2067
|
+
self_prec = len(self._profile[0])
|
|
2068
|
+
S_prec = len(S._profile[0])
|
|
2069
|
+
return (all(self.profile(i) >= S.profile(i)
|
|
2070
|
+
for i in range(1, max(self_prec, S_prec)+1))
|
|
2071
|
+
and all(self.profile(i, 1) >= S.profile(i, 1)
|
|
2072
|
+
for i in range(1, max(self_prec, S_prec)+1)))
|
|
2073
|
+
if (isinstance(S, CombinatorialFreeModule)
|
|
2074
|
+
and S.dimension() < Infinity and p == S.base_ring().characteristic()):
|
|
2075
|
+
from .steenrod_algebra_misc import get_basis_name
|
|
2076
|
+
try:
|
|
2077
|
+
get_basis_name(S.prefix(), S.base_ring().characteristic())
|
|
2078
|
+
# return all(a in self for a in S.basis())
|
|
2079
|
+
return True
|
|
2080
|
+
except ValueError:
|
|
2081
|
+
return False
|
|
2082
|
+
return False
|
|
2083
|
+
|
|
2084
|
+
def _element_constructor_(self, x):
|
|
2085
|
+
r"""
|
|
2086
|
+
Try to turn ``x`` into an element of ``self``.
|
|
2087
|
+
|
|
2088
|
+
INPUT:
|
|
2089
|
+
|
|
2090
|
+
- ``x`` -- an element of some Steenrod algebra or an element of
|
|
2091
|
+
`\ZZ` or `\GF{p}` or a dict
|
|
2092
|
+
|
|
2093
|
+
OUTPUT: ``x`` as a member of ``self``
|
|
2094
|
+
|
|
2095
|
+
If ``x`` is a dict, then call :meth:`_from_dict` on it,
|
|
2096
|
+
coercing the coefficients into the base field. That is, treat
|
|
2097
|
+
it as having entries of the form ``tuple: coeff``, where
|
|
2098
|
+
``tuple`` is a tuple representing a basis element and
|
|
2099
|
+
``coeff`` is the coefficient of that element.
|
|
2100
|
+
|
|
2101
|
+
EXAMPLES::
|
|
2102
|
+
|
|
2103
|
+
sage: A1 = SteenrodAlgebra(profile=[2,1])
|
|
2104
|
+
sage: A1(Sq(2)) # indirect doctest
|
|
2105
|
+
Sq(2)
|
|
2106
|
+
sage: A1._element_constructor_(Sq(2))
|
|
2107
|
+
Sq(2)
|
|
2108
|
+
sage: A1(3) # map integer into A1
|
|
2109
|
+
1
|
|
2110
|
+
sage: A1._element_constructor_(Sq(4)) # Sq(4) not in A1
|
|
2111
|
+
Traceback (most recent call last):
|
|
2112
|
+
...
|
|
2113
|
+
ValueError: element does not lie in this Steenrod algebra
|
|
2114
|
+
sage: A1({(2,): 1, (1,): 13})
|
|
2115
|
+
Sq(1) + Sq(2)
|
|
2116
|
+
"""
|
|
2117
|
+
from sage.rings.integer_ring import ZZ
|
|
2118
|
+
from sage.rings.finite_rings.finite_field_constructor import GF
|
|
2119
|
+
if x in GF(self.prime()) or x in ZZ:
|
|
2120
|
+
return self.from_base_ring_from_one_basis(x)
|
|
2121
|
+
|
|
2122
|
+
if isinstance(x, dict):
|
|
2123
|
+
A = SteenrodAlgebra(p=self.prime(), basis=self.basis_name(), generic=self._generic)
|
|
2124
|
+
x = A._from_dict(x, coerce=True)
|
|
2125
|
+
if x in self:
|
|
2126
|
+
if x.basis_name() == self.basis_name():
|
|
2127
|
+
if x.parent() is self:
|
|
2128
|
+
return x
|
|
2129
|
+
return self._from_dict(x.monomial_coefficients(), coerce=True)
|
|
2130
|
+
else:
|
|
2131
|
+
a = x.milnor()
|
|
2132
|
+
if self.basis_name() == 'milnor':
|
|
2133
|
+
return a
|
|
2134
|
+
return a.change_basis(self.basis_name())
|
|
2135
|
+
raise ValueError("element does not lie in this Steenrod algebra")
|
|
2136
|
+
|
|
2137
|
+
def __contains__(self, x):
|
|
2138
|
+
r"""
|
|
2139
|
+
Return ``True`` if ``self`` contains `x`.
|
|
2140
|
+
|
|
2141
|
+
EXAMPLES::
|
|
2142
|
+
|
|
2143
|
+
sage: Sq(3,1,1) in SteenrodAlgebra()
|
|
2144
|
+
True
|
|
2145
|
+
sage: Sq(3,1,1) in SteenrodAlgebra(p=5)
|
|
2146
|
+
False
|
|
2147
|
+
|
|
2148
|
+
sage: A1 = SteenrodAlgebra(profile=[2,1])
|
|
2149
|
+
sage: Sq(3) in A1
|
|
2150
|
+
True
|
|
2151
|
+
sage: Sq(4) in A1
|
|
2152
|
+
False
|
|
2153
|
+
sage: Sq(0,2) in A1
|
|
2154
|
+
False
|
|
2155
|
+
|
|
2156
|
+
sage: Sq(3) in SteenrodAlgebra(generic=True)
|
|
2157
|
+
False
|
|
2158
|
+
|
|
2159
|
+
sage: A_3 = SteenrodAlgebra(p=3)
|
|
2160
|
+
sage: B_3 = SteenrodAlgebra(p=3, profile=([1], [2,2,1,1]))
|
|
2161
|
+
sage: A_3.P(2) in B_3
|
|
2162
|
+
True
|
|
2163
|
+
sage: A_3.P(3) in B_3
|
|
2164
|
+
False
|
|
2165
|
+
sage: A_3.Q(1) in B_3
|
|
2166
|
+
True
|
|
2167
|
+
sage: A_3.P(1) * A_3.Q(2) in B_3
|
|
2168
|
+
False
|
|
2169
|
+
"""
|
|
2170
|
+
from sage.rings.finite_rings.finite_field_constructor import GF
|
|
2171
|
+
p = self.prime()
|
|
2172
|
+
if x in GF(p):
|
|
2173
|
+
return True
|
|
2174
|
+
if (isinstance(x, self.Element) and x.prime() == p):
|
|
2175
|
+
try:
|
|
2176
|
+
if x.parent()._generic != self._generic:
|
|
2177
|
+
return False
|
|
2178
|
+
except AttributeError:
|
|
2179
|
+
pass
|
|
2180
|
+
A = SteenrodAlgebra(p=p, basis=self.basis_name(),
|
|
2181
|
+
generic=self._generic)
|
|
2182
|
+
if self._has_nontrivial_profile():
|
|
2183
|
+
return all(self._check_profile_on_basis(mono)
|
|
2184
|
+
for mono in A(x).support())
|
|
2185
|
+
return True # trivial profile, so True
|
|
2186
|
+
return False
|
|
2187
|
+
|
|
2188
|
+
def basis(self, d=None):
|
|
2189
|
+
"""
|
|
2190
|
+
Return basis for ``self``, either the whole basis or the basis in
|
|
2191
|
+
degree `d`.
|
|
2192
|
+
|
|
2193
|
+
INPUT:
|
|
2194
|
+
|
|
2195
|
+
- ``d`` -- integer or ``None`` (default: ``None``)
|
|
2196
|
+
|
|
2197
|
+
OUTPUT:
|
|
2198
|
+
|
|
2199
|
+
If `d` is ``None``, then return a basis of the algebra.
|
|
2200
|
+
Otherwise, return the basis in degree `d`.
|
|
2201
|
+
|
|
2202
|
+
EXAMPLES::
|
|
2203
|
+
|
|
2204
|
+
sage: A3 = SteenrodAlgebra(3)
|
|
2205
|
+
sage: A3.basis(13)
|
|
2206
|
+
Family (Q_1 P(2), Q_0 P(3))
|
|
2207
|
+
sage: SteenrodAlgebra(2, 'adem').basis(12)
|
|
2208
|
+
Family (Sq^12, Sq^11 Sq^1, Sq^9 Sq^2 Sq^1, Sq^8 Sq^3 Sq^1, Sq^10 Sq^2, Sq^9 Sq^3, Sq^8 Sq^4)
|
|
2209
|
+
|
|
2210
|
+
sage: A = SteenrodAlgebra(profile=[1,2,1])
|
|
2211
|
+
sage: A.basis(2)
|
|
2212
|
+
Family ()
|
|
2213
|
+
sage: A.basis(3)
|
|
2214
|
+
Family (Sq(0,1),)
|
|
2215
|
+
sage: SteenrodAlgebra().basis(3)
|
|
2216
|
+
Family (Sq(0,1), Sq(3))
|
|
2217
|
+
sage: A_pst = SteenrodAlgebra(profile=[1,2,1], basis='pst')
|
|
2218
|
+
sage: A_pst.basis(3)
|
|
2219
|
+
Family (P^0_2,)
|
|
2220
|
+
|
|
2221
|
+
sage: A7 = SteenrodAlgebra(p=7)
|
|
2222
|
+
sage: B = SteenrodAlgebra(p=7, profile=([1,2,1], [1]))
|
|
2223
|
+
sage: A7.basis(84)
|
|
2224
|
+
Family (P(7),)
|
|
2225
|
+
sage: B.basis(84)
|
|
2226
|
+
Family ()
|
|
2227
|
+
sage: C = SteenrodAlgebra(p=7, profile=([1], [2,2]))
|
|
2228
|
+
sage: A7.Q(0,1) in C.basis(14)
|
|
2229
|
+
True
|
|
2230
|
+
sage: A7.Q(2) in A7.basis(97)
|
|
2231
|
+
True
|
|
2232
|
+
sage: A7.Q(2) in C.basis(97)
|
|
2233
|
+
False
|
|
2234
|
+
|
|
2235
|
+
With no arguments, return the basis of the whole algebra.
|
|
2236
|
+
This does not print in a very helpful way, unfortunately::
|
|
2237
|
+
|
|
2238
|
+
sage: A7.basis()
|
|
2239
|
+
Lazy family (Term map from basis key family of mod 7 Steenrod algebra, milnor basis
|
|
2240
|
+
to mod 7 Steenrod algebra, milnor basis(i))_{i in basis key family
|
|
2241
|
+
of mod 7 Steenrod algebra, milnor basis}
|
|
2242
|
+
sage: for (idx,a) in zip((1,..,9),A7.basis()):
|
|
2243
|
+
....: print("{} {}".format(idx, a))
|
|
2244
|
+
1 1
|
|
2245
|
+
2 Q_0
|
|
2246
|
+
3 P(1)
|
|
2247
|
+
4 Q_1
|
|
2248
|
+
5 Q_0 P(1)
|
|
2249
|
+
6 Q_0 Q_1
|
|
2250
|
+
7 P(2)
|
|
2251
|
+
8 Q_1 P(1)
|
|
2252
|
+
9 Q_0 P(2)
|
|
2253
|
+
sage: D = SteenrodAlgebra(p=3, profile=([1], [2,2]))
|
|
2254
|
+
sage: sorted(D.basis())
|
|
2255
|
+
[1, P(1), P(2), Q_0, Q_0 P(1), Q_0 P(2), Q_0 Q_1,
|
|
2256
|
+
Q_0 Q_1 P(1), Q_0 Q_1 P(2), Q_1, Q_1 P(1), Q_1 P(2)]
|
|
2257
|
+
"""
|
|
2258
|
+
from sage.sets.family import Family
|
|
2259
|
+
if d is None:
|
|
2260
|
+
return Family(self._indices, self.monomial)
|
|
2261
|
+
else:
|
|
2262
|
+
return Family([self.monomial(tuple(a)) for a in self._basis_fcn(d)])
|
|
2263
|
+
|
|
2264
|
+
def _check_profile_on_basis(self, t):
|
|
2265
|
+
"""
|
|
2266
|
+
Return ``True`` if the element specified by the tuple ``t`` is in this
|
|
2267
|
+
algebra.
|
|
2268
|
+
|
|
2269
|
+
INPUT:
|
|
2270
|
+
|
|
2271
|
+
- ``t`` -- tuple
|
|
2272
|
+
|
|
2273
|
+
EXAMPLES::
|
|
2274
|
+
|
|
2275
|
+
sage: A = SteenrodAlgebra(profile=[1,2,1])
|
|
2276
|
+
sage: A._check_profile_on_basis((0,0,1))
|
|
2277
|
+
True
|
|
2278
|
+
sage: A._check_profile_on_basis((0,0,2))
|
|
2279
|
+
False
|
|
2280
|
+
sage: A5 = SteenrodAlgebra(p=5, profile=([3,2,1], [2,2,2,2,2]))
|
|
2281
|
+
sage: A5._check_profile_on_basis(((), (1,5)))
|
|
2282
|
+
True
|
|
2283
|
+
sage: A5._check_profile_on_basis(((1,1,1), (1,5)))
|
|
2284
|
+
True
|
|
2285
|
+
sage: A5._check_profile_on_basis(((1,1,1), (1,5,5)))
|
|
2286
|
+
False
|
|
2287
|
+
"""
|
|
2288
|
+
if self.basis_name() != 'milnor':
|
|
2289
|
+
A = SteenrodAlgebra(p=self.prime(),
|
|
2290
|
+
profile=self._profile,
|
|
2291
|
+
truncation_type=self._truncation_type,
|
|
2292
|
+
generic=self._generic)
|
|
2293
|
+
return all(A._check_profile_on_basis(a[0])
|
|
2294
|
+
for a in self._milnor_on_basis(t))
|
|
2295
|
+
|
|
2296
|
+
from sage.rings.infinity import Infinity
|
|
2297
|
+
p = self.prime()
|
|
2298
|
+
if not self._has_nontrivial_profile():
|
|
2299
|
+
return True
|
|
2300
|
+
if not self._generic:
|
|
2301
|
+
return all(self.profile(i+1) == Infinity
|
|
2302
|
+
or t[i] < 2**self.profile(i+1)
|
|
2303
|
+
for i in range(len(t)))
|
|
2304
|
+
# p odd:
|
|
2305
|
+
if any(self.profile(i, 1) != 2 for i in t[0]):
|
|
2306
|
+
return False
|
|
2307
|
+
return all(self.profile(i + 1, 0) == Infinity
|
|
2308
|
+
or t[1][i] < p**self.profile(i + 1, 0)
|
|
2309
|
+
for i in range(len(t[1])))
|
|
2310
|
+
|
|
2311
|
+
def P(self, *nums):
|
|
2312
|
+
r"""
|
|
2313
|
+
The element `P(a, b, c, \ldots)`.
|
|
2314
|
+
|
|
2315
|
+
INPUT:
|
|
2316
|
+
|
|
2317
|
+
- ``a``, ``b``, ``c``, ... -- nonnegative integers
|
|
2318
|
+
|
|
2319
|
+
OUTPUT:
|
|
2320
|
+
|
|
2321
|
+
element of the Steenrod algebra given by the Milnor
|
|
2322
|
+
single basis element `P(a, b, c, ...)`
|
|
2323
|
+
|
|
2324
|
+
Note that at the prime 2, this is the same element as
|
|
2325
|
+
`\text{Sq}(a, b, c, ...)`.
|
|
2326
|
+
|
|
2327
|
+
EXAMPLES::
|
|
2328
|
+
|
|
2329
|
+
sage: A = SteenrodAlgebra(2)
|
|
2330
|
+
sage: A.P(5)
|
|
2331
|
+
Sq(5)
|
|
2332
|
+
sage: B = SteenrodAlgebra(3)
|
|
2333
|
+
sage: B.P(5,1,1)
|
|
2334
|
+
P(5,1,1)
|
|
2335
|
+
sage: B.P(1,1,-12,1)
|
|
2336
|
+
Traceback (most recent call last):
|
|
2337
|
+
...
|
|
2338
|
+
TypeError: entries must be nonnegative integers
|
|
2339
|
+
|
|
2340
|
+
sage: SteenrodAlgebra(basis='serre-cartan').P(0,1)
|
|
2341
|
+
Sq^2 Sq^1 + Sq^3
|
|
2342
|
+
sage: SteenrodAlgebra(generic=True).P(2,0,1)
|
|
2343
|
+
P(2,0,1)
|
|
2344
|
+
"""
|
|
2345
|
+
from sage.rings.integer import Integer
|
|
2346
|
+
if self.basis_name() != 'milnor':
|
|
2347
|
+
return self(SteenrodAlgebra(p=self.prime(),
|
|
2348
|
+
generic=self._generic).P(*nums))
|
|
2349
|
+
while nums and nums[-1] == 0:
|
|
2350
|
+
nums = nums[:-1]
|
|
2351
|
+
if len(nums) == 0 or (len(nums) == 1 and nums[0] == 0):
|
|
2352
|
+
return self.one()
|
|
2353
|
+
for i in nums:
|
|
2354
|
+
try:
|
|
2355
|
+
assert Integer(i) >= 0
|
|
2356
|
+
except (TypeError, AssertionError):
|
|
2357
|
+
raise TypeError("entries must be nonnegative integers")
|
|
2358
|
+
|
|
2359
|
+
if not self._generic:
|
|
2360
|
+
t = nums
|
|
2361
|
+
else:
|
|
2362
|
+
t = ((), nums)
|
|
2363
|
+
if self._check_profile_on_basis(t):
|
|
2364
|
+
A = SteenrodAlgebra_generic(p=self.prime(),
|
|
2365
|
+
generic=self._generic)
|
|
2366
|
+
a = A.monomial(t)
|
|
2367
|
+
return self(a)
|
|
2368
|
+
raise ValueError("element not in this algebra")
|
|
2369
|
+
|
|
2370
|
+
def Q_exp(self, *nums):
|
|
2371
|
+
r"""
|
|
2372
|
+
The element `Q_0^{e_0} Q_1^{e_1} ...` , given by
|
|
2373
|
+
specifying the exponents.
|
|
2374
|
+
|
|
2375
|
+
INPUT:
|
|
2376
|
+
|
|
2377
|
+
- ``e0``, ``e1``, ... -- sequence of 0s and 1s
|
|
2378
|
+
|
|
2379
|
+
OUTPUT: the element `Q_0^{e_0} Q_1^{e_1} ...`
|
|
2380
|
+
|
|
2381
|
+
Note that at the prime 2, `Q_n` is the element
|
|
2382
|
+
`\text{Sq}(0,0,...,1)` , where the 1 is in the
|
|
2383
|
+
`(n+1)^{st}` position.
|
|
2384
|
+
|
|
2385
|
+
Compare this to the method :meth:`Q`, which defines a similar
|
|
2386
|
+
element, but by specifying the tuple of subscripts of terms
|
|
2387
|
+
with exponent 1.
|
|
2388
|
+
|
|
2389
|
+
EXAMPLES::
|
|
2390
|
+
|
|
2391
|
+
sage: A2 = SteenrodAlgebra(2)
|
|
2392
|
+
sage: A5 = SteenrodAlgebra(5)
|
|
2393
|
+
sage: A2.Q_exp(0,0,1,1,0)
|
|
2394
|
+
Sq(0,0,1,1)
|
|
2395
|
+
sage: A5.Q_exp(0,0,1,1,0)
|
|
2396
|
+
Q_2 Q_3
|
|
2397
|
+
sage: A5.Q(2,3)
|
|
2398
|
+
Q_2 Q_3
|
|
2399
|
+
sage: A5.Q_exp(0,0,1,1,0) == A5.Q(2,3)
|
|
2400
|
+
True
|
|
2401
|
+
sage: SteenrodAlgebra(2,generic=True).Q_exp(1,0,1)
|
|
2402
|
+
Q_0 Q_2
|
|
2403
|
+
"""
|
|
2404
|
+
if not all(x in (0, 1) for x in nums):
|
|
2405
|
+
raise ValueError("the tuple %s should consist " % (nums,) +
|
|
2406
|
+
"only of 0s and 1s")
|
|
2407
|
+
else:
|
|
2408
|
+
if self.basis_name() != 'milnor':
|
|
2409
|
+
return self(SteenrodAlgebra(p=self.prime(),
|
|
2410
|
+
generic=self._generic).Q_exp(*nums))
|
|
2411
|
+
while nums[-1] == 0:
|
|
2412
|
+
nums = nums[:-1]
|
|
2413
|
+
if not self._generic:
|
|
2414
|
+
return self.P(*nums)
|
|
2415
|
+
else:
|
|
2416
|
+
mono = ()
|
|
2417
|
+
index = 0
|
|
2418
|
+
for e in nums:
|
|
2419
|
+
if e == 1:
|
|
2420
|
+
mono = mono + (index,)
|
|
2421
|
+
index += 1
|
|
2422
|
+
return self.Q(*mono)
|
|
2423
|
+
|
|
2424
|
+
def Q(self, *nums):
|
|
2425
|
+
r"""
|
|
2426
|
+
The element `Q_{n0} Q_{n1} ...` , given by specifying the
|
|
2427
|
+
subscripts.
|
|
2428
|
+
|
|
2429
|
+
INPUT:
|
|
2430
|
+
|
|
2431
|
+
- ``n0``, ``n1``, ... -- nonnegative integers
|
|
2432
|
+
|
|
2433
|
+
OUTPUT: the element `Q_{n0} Q_{n1} ...`
|
|
2434
|
+
|
|
2435
|
+
Note that at the prime 2, `Q_n` is the element
|
|
2436
|
+
`\text{Sq}(0,0,...,1)` , where the 1 is in the
|
|
2437
|
+
`(n+1)^{st}` position.
|
|
2438
|
+
|
|
2439
|
+
Compare this to the method :meth:`Q_exp`, which defines a
|
|
2440
|
+
similar element, but by specifying the tuple of exponents.
|
|
2441
|
+
|
|
2442
|
+
EXAMPLES::
|
|
2443
|
+
|
|
2444
|
+
sage: A2 = SteenrodAlgebra(2)
|
|
2445
|
+
sage: A2.Q(2,3)
|
|
2446
|
+
Sq(0,0,1,1)
|
|
2447
|
+
sage: A5 = SteenrodAlgebra(5)
|
|
2448
|
+
sage: A5.Q(1,4)
|
|
2449
|
+
Q_1 Q_4
|
|
2450
|
+
sage: A5.Q(1,4) == A5.Q_exp(0,1,0,0,1)
|
|
2451
|
+
True
|
|
2452
|
+
sage: H = SteenrodAlgebra(p=5, profile=[[2,1], [2,2,2]])
|
|
2453
|
+
sage: H.Q(2)
|
|
2454
|
+
Q_2
|
|
2455
|
+
sage: H.Q(4)
|
|
2456
|
+
Traceback (most recent call last):
|
|
2457
|
+
...
|
|
2458
|
+
ValueError: element not in this algebra
|
|
2459
|
+
"""
|
|
2460
|
+
if len(nums) != len(set(nums)):
|
|
2461
|
+
return self(0)
|
|
2462
|
+
else:
|
|
2463
|
+
if self.basis_name() != 'milnor':
|
|
2464
|
+
return self(SteenrodAlgebra(p=self.prime(),
|
|
2465
|
+
generic=self._generic).Q(*nums))
|
|
2466
|
+
if not self._generic:
|
|
2467
|
+
if len(nums) == 0:
|
|
2468
|
+
return self.one()
|
|
2469
|
+
else:
|
|
2470
|
+
list = (1+max(nums)) * [0]
|
|
2471
|
+
for i in nums:
|
|
2472
|
+
list[i] = 1
|
|
2473
|
+
return self.Sq(*tuple(list))
|
|
2474
|
+
else:
|
|
2475
|
+
answer = self.one()
|
|
2476
|
+
for i in nums:
|
|
2477
|
+
answer = answer * self.monomial(((i,), ()))
|
|
2478
|
+
t = answer.leading_support()
|
|
2479
|
+
if self._check_profile_on_basis(t):
|
|
2480
|
+
return answer
|
|
2481
|
+
raise ValueError("element not in this algebra")
|
|
2482
|
+
|
|
2483
|
+
def _an_element_(self):
|
|
2484
|
+
"""
|
|
2485
|
+
An element of this Steenrod algebra.
|
|
2486
|
+
|
|
2487
|
+
The element depends on
|
|
2488
|
+
the basis and whether there is a nontrivial profile function.
|
|
2489
|
+
(This is used by the automatic test suite, so having different
|
|
2490
|
+
elements in different bases may help in discovering bugs.)
|
|
2491
|
+
|
|
2492
|
+
EXAMPLES::
|
|
2493
|
+
|
|
2494
|
+
sage: SteenrodAlgebra().an_element()
|
|
2495
|
+
Sq(2,1)
|
|
2496
|
+
sage: SteenrodAlgebra(basis='adem').an_element()
|
|
2497
|
+
Sq^4 Sq^2 Sq^1
|
|
2498
|
+
sage: SteenrodAlgebra(p=5).an_element()
|
|
2499
|
+
4 Q_1 Q_3 P(2,1)
|
|
2500
|
+
sage: SteenrodAlgebra(basis='pst').an_element()
|
|
2501
|
+
P^3_1
|
|
2502
|
+
sage: SteenrodAlgebra(basis='pst', profile=[3,2,1]).an_element()
|
|
2503
|
+
P^0_1
|
|
2504
|
+
"""
|
|
2505
|
+
from sage.rings.finite_rings.finite_field_constructor import GF
|
|
2506
|
+
basis = self.basis_name()
|
|
2507
|
+
p = self.prime()
|
|
2508
|
+
|
|
2509
|
+
if self._has_nontrivial_profile():
|
|
2510
|
+
if self.ngens():
|
|
2511
|
+
return self.gen(0)
|
|
2512
|
+
else:
|
|
2513
|
+
return self.one()
|
|
2514
|
+
|
|
2515
|
+
if basis == 'milnor' and not self._generic:
|
|
2516
|
+
return self.monomial((2, 1))
|
|
2517
|
+
if basis == 'milnor' and self._generic:
|
|
2518
|
+
return self.term(((1, 3), (2, 1)), GF(p)(p - 1))
|
|
2519
|
+
if basis == 'serre-cartan' and not self._generic:
|
|
2520
|
+
return self.monomial((4, 2, 1))
|
|
2521
|
+
if basis == 'serre-cartan' and self._generic:
|
|
2522
|
+
return self.term((1, p, 0, 1, 0), GF(p)(p - 1))
|
|
2523
|
+
if basis == 'woody' or basis == 'woodz':
|
|
2524
|
+
return self._from_dict({((3, 0),): 1,
|
|
2525
|
+
((1, 1), (1, 0)): 1}, coerce=True)
|
|
2526
|
+
if basis.find('wall') >= 0:
|
|
2527
|
+
return self._from_dict({((1, 1), (1, 0)): 1,
|
|
2528
|
+
((2, 2), (0, 0)): 1}, coerce=True)
|
|
2529
|
+
if basis.find('arnona') >= 0:
|
|
2530
|
+
return self._from_dict({((3, 3),): 1,
|
|
2531
|
+
((1, 1), (2, 1)): 1}, coerce=True)
|
|
2532
|
+
if basis == 'arnonc':
|
|
2533
|
+
return self._from_dict({(8,): 1, (4, 4): 1}, coerce=True)
|
|
2534
|
+
if basis.find('pst') >= 0:
|
|
2535
|
+
if not self._generic:
|
|
2536
|
+
return self.monomial(((3, 1),))
|
|
2537
|
+
return self.term(((1,), (((1, 1), 2),)), GF(p)(p - 1))
|
|
2538
|
+
if basis.find('comm') >= 0:
|
|
2539
|
+
if not self._generic:
|
|
2540
|
+
return self.monomial(((1, 2),))
|
|
2541
|
+
return self.term(((), (((1, 2), 1),)), GF(p)(p - 1))
|
|
2542
|
+
|
|
2543
|
+
def pst(self, s, t):
|
|
2544
|
+
r"""
|
|
2545
|
+
The Margolis element `P^s_t`.
|
|
2546
|
+
|
|
2547
|
+
INPUT:
|
|
2548
|
+
|
|
2549
|
+
- ``s`` -- nonnegative integer
|
|
2550
|
+
|
|
2551
|
+
- ``t`` -- positive integer
|
|
2552
|
+
|
|
2553
|
+
- ``p`` -- positive prime number
|
|
2554
|
+
|
|
2555
|
+
OUTPUT: element of the Steenrod algebra
|
|
2556
|
+
|
|
2557
|
+
This returns the Margolis element `P^s_t` of the mod
|
|
2558
|
+
`p` Steenrod algebra: the element equal to
|
|
2559
|
+
`P(0,0,...,0,p^s)`, where the `p^s` is in position
|
|
2560
|
+
`t`.
|
|
2561
|
+
|
|
2562
|
+
EXAMPLES::
|
|
2563
|
+
|
|
2564
|
+
sage: A2 = SteenrodAlgebra(2)
|
|
2565
|
+
sage: A2.pst(3,5)
|
|
2566
|
+
Sq(0,0,0,0,8)
|
|
2567
|
+
sage: A2.pst(1,2) == Sq(4)*Sq(2) + Sq(2)*Sq(4)
|
|
2568
|
+
True
|
|
2569
|
+
sage: SteenrodAlgebra(5).pst(3,5)
|
|
2570
|
+
P(0,0,0,0,125)
|
|
2571
|
+
"""
|
|
2572
|
+
from sage.rings.integer import Integer
|
|
2573
|
+
if self.basis_name() != 'milnor':
|
|
2574
|
+
return self(SteenrodAlgebra(p=self.prime(),
|
|
2575
|
+
generic=self._generic).pst(s, t))
|
|
2576
|
+
if not isinstance(s, (Integer, int)) and s >= 0:
|
|
2577
|
+
raise ValueError("%s is not a nonnegative integer" % s)
|
|
2578
|
+
if not isinstance(t, (Integer, int)) and t > 0:
|
|
2579
|
+
raise ValueError("%s is not a positive integer" % t)
|
|
2580
|
+
nums = (0,)*(t-1) + (self.prime()**s,)
|
|
2581
|
+
return self.P(*nums)
|
|
2582
|
+
|
|
2583
|
+
def ngens(self):
|
|
2584
|
+
r"""
|
|
2585
|
+
Number of generators of ``self``.
|
|
2586
|
+
|
|
2587
|
+
OUTPUT: number or Infinity
|
|
2588
|
+
|
|
2589
|
+
The Steenrod algebra is infinitely generated. A sub-Hopf
|
|
2590
|
+
algebra may be finitely or infinitely generated; in general,
|
|
2591
|
+
it is not clear what a minimal generating set is, nor the
|
|
2592
|
+
cardinality of that set. So: if the algebra is
|
|
2593
|
+
infinite-dimensional, this returns Infinity. If the algebra
|
|
2594
|
+
is finite-dimensional and is equal to one of the sub-Hopf
|
|
2595
|
+
algebras `A(n)`, then their minimal generating set is known,
|
|
2596
|
+
and this returns the cardinality of that set. Otherwise, any
|
|
2597
|
+
sub-Hopf algebra is (not necessarily minimally) generated by
|
|
2598
|
+
the `P^s_t`'s that it contains (along with the `Q_n`'s it
|
|
2599
|
+
contains, at odd primes), so this returns the number of
|
|
2600
|
+
`P^s_t`'s and `Q_n`'s in the algebra.
|
|
2601
|
+
|
|
2602
|
+
EXAMPLES::
|
|
2603
|
+
|
|
2604
|
+
sage: A = SteenrodAlgebra(3)
|
|
2605
|
+
sage: A.ngens()
|
|
2606
|
+
+Infinity
|
|
2607
|
+
sage: SteenrodAlgebra(profile=lambda n: n).ngens()
|
|
2608
|
+
+Infinity
|
|
2609
|
+
sage: SteenrodAlgebra(profile=[3,2,1]).ngens() # A(2)
|
|
2610
|
+
3
|
|
2611
|
+
sage: SteenrodAlgebra(profile=[3,2,1], basis='pst').ngens()
|
|
2612
|
+
3
|
|
2613
|
+
sage: SteenrodAlgebra(p=3, profile=[[3,2,1], [2,2,2,2]]).ngens() # A(3) at p=3
|
|
2614
|
+
4
|
|
2615
|
+
sage: SteenrodAlgebra(profile=[1,2,1,1]).ngens()
|
|
2616
|
+
5
|
|
2617
|
+
"""
|
|
2618
|
+
from sage.rings.infinity import Infinity
|
|
2619
|
+
if self._truncation_type == Infinity:
|
|
2620
|
+
return Infinity
|
|
2621
|
+
n = self.profile(1)
|
|
2622
|
+
p = self.prime()
|
|
2623
|
+
if not self._generic and self._profile == AA(n-1, p=p)._profile:
|
|
2624
|
+
return n
|
|
2625
|
+
if self._generic and self._profile == AA(n, p=p)._profile:
|
|
2626
|
+
return n+1
|
|
2627
|
+
if not self._generic:
|
|
2628
|
+
return sum(self._profile)
|
|
2629
|
+
return sum(self._profile[0]) + len([a for a in self._profile[1] if a == 2])
|
|
2630
|
+
|
|
2631
|
+
def gens(self) -> Family:
|
|
2632
|
+
r"""
|
|
2633
|
+
Family of generators for this algebra.
|
|
2634
|
+
|
|
2635
|
+
OUTPUT: family of elements of this algebra
|
|
2636
|
+
|
|
2637
|
+
At the prime 2, the Steenrod algebra is generated by the
|
|
2638
|
+
elements `\text{Sq}^{2^i}` for `i \geq 0`. At odd primes, it
|
|
2639
|
+
is generated by the elements `Q_0` and `\mathcal{P}^{p^i}` for
|
|
2640
|
+
`i \geq 0`. So if this algebra is the entire Steenrod
|
|
2641
|
+
algebra, return an infinite family made up of these elements.
|
|
2642
|
+
|
|
2643
|
+
For sub-Hopf algebras of the Steenrod algebra, it is not
|
|
2644
|
+
always clear what a minimal generating set is. The sub-Hopf
|
|
2645
|
+
algebra `A(n)` is minimally generated by the elements
|
|
2646
|
+
`\text{Sq}^{2^i}` for `0 \leq i \leq n` at the prime 2. At
|
|
2647
|
+
odd primes, `A(n)` is minimally generated by `Q_0` along with
|
|
2648
|
+
`\mathcal{P}^{p^i}` for `0 \leq i \leq n-1`. So if this
|
|
2649
|
+
algebra is `A(n)`, return the appropriate list of generators.
|
|
2650
|
+
|
|
2651
|
+
For other sub-Hopf algebras: return a non-minimal generating
|
|
2652
|
+
set: the family of `P^s_t`'s and `Q_n`'s contained in the
|
|
2653
|
+
algebra.
|
|
2654
|
+
|
|
2655
|
+
EXAMPLES::
|
|
2656
|
+
|
|
2657
|
+
sage: A3 = SteenrodAlgebra(3, 'adem')
|
|
2658
|
+
sage: A3.gens()
|
|
2659
|
+
Lazy family (<bound method SteenrodAlgebra_generic.gen of mod 3 Steenrod algebra,
|
|
2660
|
+
serre-cartan basis>(i))_{i in Non negative integers}
|
|
2661
|
+
sage: A3.gens()[0]
|
|
2662
|
+
beta
|
|
2663
|
+
sage: A3.gens()[1]
|
|
2664
|
+
P^1
|
|
2665
|
+
sage: A3.gens()[2]
|
|
2666
|
+
P^3
|
|
2667
|
+
sage: SteenrodAlgebra(profile=[3,2,1]).gens()
|
|
2668
|
+
Family (Sq(1), Sq(2), Sq(4))
|
|
2669
|
+
|
|
2670
|
+
In the following case, return a non-minimal generating set.
|
|
2671
|
+
(It is not minimal because `\text{Sq}(0,0,1)` is the
|
|
2672
|
+
commutator of `\text{Sq}(1)` and `\text{Sq}(0,2)`.) ::
|
|
2673
|
+
|
|
2674
|
+
sage: SteenrodAlgebra(profile=[1,2,1]).gens()
|
|
2675
|
+
Family (Sq(1), Sq(0,1), Sq(0,2), Sq(0,0,1))
|
|
2676
|
+
sage: SteenrodAlgebra(p=5, profile=[[2,1], [2,2,2]]).gens()
|
|
2677
|
+
Family (Q_0, P(1), P(5))
|
|
2678
|
+
sage: SteenrodAlgebra(profile=lambda n: n).gens()
|
|
2679
|
+
Lazy family (<bound method SteenrodAlgebra_generic.gen of sub-Hopf algebra
|
|
2680
|
+
of mod 2 Steenrod algebra, milnor basis, profile function [1, 2, 3, ...,
|
|
2681
|
+
98, 99, +Infinity, +Infinity, +Infinity, ...]>(i))_{i in Non negative integers}
|
|
2682
|
+
|
|
2683
|
+
You may also use ``algebra_generators`` instead of ``gens``::
|
|
2684
|
+
|
|
2685
|
+
sage: SteenrodAlgebra(p=5, profile=[[2,1], [2,2,2]]).algebra_generators()
|
|
2686
|
+
Family (Q_0, P(1), P(5))
|
|
2687
|
+
"""
|
|
2688
|
+
from sage.sets.non_negative_integers import NonNegativeIntegers
|
|
2689
|
+
from sage.rings.infinity import Infinity
|
|
2690
|
+
n = self.ngens()
|
|
2691
|
+
if n < Infinity:
|
|
2692
|
+
return Family([self.gen(i) for i in range(n)])
|
|
2693
|
+
return Family(NonNegativeIntegers(), self.gen)
|
|
2694
|
+
|
|
2695
|
+
algebra_generators = gens
|
|
2696
|
+
|
|
2697
|
+
def gen(self, i=0):
|
|
2698
|
+
r"""
|
|
2699
|
+
The `i`-th generator of this algebra.
|
|
2700
|
+
|
|
2701
|
+
INPUT:
|
|
2702
|
+
|
|
2703
|
+
- ``i`` -- nonnegative integer
|
|
2704
|
+
|
|
2705
|
+
OUTPUT: the `i`-th generator of this algebra
|
|
2706
|
+
|
|
2707
|
+
For the full Steenrod algebra, the `i`-th generator is
|
|
2708
|
+
`\text{Sq}(2^i)` at the prime 2; when `p` is odd, the `0`-th generator
|
|
2709
|
+
is `\beta = Q(0)`, and for `i>0`, the `i`-th generator is
|
|
2710
|
+
`P(p^{i-1})`.
|
|
2711
|
+
|
|
2712
|
+
For sub-Hopf algebras of the Steenrod algebra, it is not
|
|
2713
|
+
always clear what a minimal generating set is. The sub-Hopf
|
|
2714
|
+
algebra `A(n)` is minimally generated by the elements
|
|
2715
|
+
`\text{Sq}^{2^i}` for `0 \leq i \leq n` at the prime 2. At
|
|
2716
|
+
odd primes, `A(n)` is minimally generated by `Q_0` along with
|
|
2717
|
+
`\mathcal{P}^{p^i}` for `0 \leq i \leq n-1`. So if this
|
|
2718
|
+
algebra is `A(n)`, return the appropriate generator.
|
|
2719
|
+
|
|
2720
|
+
For other sub-Hopf algebras: they are generated (but not
|
|
2721
|
+
necessarily minimally) by the `P^s_t`'s (and `Q_n`'s, if `p`
|
|
2722
|
+
is odd) that they contain. So order the `P^s_t`'s (and
|
|
2723
|
+
`Q_n`'s) in the algebra by degree and return the `i`-th one.
|
|
2724
|
+
|
|
2725
|
+
EXAMPLES::
|
|
2726
|
+
|
|
2727
|
+
sage: A = SteenrodAlgebra(2)
|
|
2728
|
+
sage: A.gen(4)
|
|
2729
|
+
Sq(16)
|
|
2730
|
+
sage: A.gen(200)
|
|
2731
|
+
Sq(1606938044258990275541962092341162602522202993782792835301376)
|
|
2732
|
+
sage: SteenrodAlgebra(2, basis='adem').gen(2)
|
|
2733
|
+
Sq^4
|
|
2734
|
+
sage: SteenrodAlgebra(2, basis='pst').gen(2)
|
|
2735
|
+
P^2_1
|
|
2736
|
+
sage: B = SteenrodAlgebra(5)
|
|
2737
|
+
sage: B.gen(0)
|
|
2738
|
+
Q_0
|
|
2739
|
+
sage: B.gen(2)
|
|
2740
|
+
P(5)
|
|
2741
|
+
|
|
2742
|
+
sage: SteenrodAlgebra(profile=[2,1]).gen(1)
|
|
2743
|
+
Sq(2)
|
|
2744
|
+
sage: SteenrodAlgebra(profile=[1,2,1]).gen(1)
|
|
2745
|
+
Sq(0,1)
|
|
2746
|
+
sage: SteenrodAlgebra(profile=[1,2,1]).gen(5)
|
|
2747
|
+
Traceback (most recent call last):
|
|
2748
|
+
...
|
|
2749
|
+
ValueError: this algebra only has 4 generators, so call gen(i) with 0 <= i < 4
|
|
2750
|
+
|
|
2751
|
+
sage: D = SteenrodAlgebra(profile=lambda n: n)
|
|
2752
|
+
sage: [D.gen(n) for n in range(5)]
|
|
2753
|
+
[Sq(1), Sq(0,1), Sq(0,2), Sq(0,0,1), Sq(0,0,2)]
|
|
2754
|
+
sage: D3 = SteenrodAlgebra(p=3, profile=(lambda n: n, lambda n: 2))
|
|
2755
|
+
sage: [D3.gen(n) for n in range(9)]
|
|
2756
|
+
[Q_0, P(1), Q_1, P(0,1), Q_2, P(0,3), P(0,0,1), Q_3, P(0,0,3)]
|
|
2757
|
+
sage: D3 = SteenrodAlgebra(p=3, profile=(lambda n: n, lambda n: 1 if n<1 else 2))
|
|
2758
|
+
sage: [D3.gen(n) for n in range(9)]
|
|
2759
|
+
[P(1), Q_1, P(0,1), Q_2, P(0,3), P(0,0,1), Q_3, P(0,0,3), P(0,0,0,1)]
|
|
2760
|
+
sage: SteenrodAlgebra(p=5, profile=[[2,1], [2,2,2]], basis='pst').gen(2)
|
|
2761
|
+
P^1_1
|
|
2762
|
+
"""
|
|
2763
|
+
from sage.rings.infinity import Infinity
|
|
2764
|
+
from sage.rings.integer import Integer
|
|
2765
|
+
p = self.prime()
|
|
2766
|
+
if not isinstance(i, (Integer, int)) and i >= 0:
|
|
2767
|
+
raise ValueError("%s is not a nonnegative integer" % i)
|
|
2768
|
+
num = self.ngens()
|
|
2769
|
+
if num < Infinity:
|
|
2770
|
+
if i >= num:
|
|
2771
|
+
raise ValueError("this algebra only has %s generators, so call gen(i) with 0 <= i < %s" % (num, num))
|
|
2772
|
+
# check to see if equal to A(n) for some n.
|
|
2773
|
+
n = self.profile(1)
|
|
2774
|
+
if not self._generic and self._profile == AA(n-1, p=p)._profile:
|
|
2775
|
+
return self.pst(i, 1)
|
|
2776
|
+
if self._generic and self._profile == AA(n, p=p)._profile:
|
|
2777
|
+
if i == 0:
|
|
2778
|
+
return self.Q(0)
|
|
2779
|
+
return self.pst(i-1, 1)
|
|
2780
|
+
# if not A(n), return list of P^s_t's in algebra, along with Q's if p is odd
|
|
2781
|
+
idx = -1
|
|
2782
|
+
if not self._generic:
|
|
2783
|
+
last_t = len(self._profile)
|
|
2784
|
+
else:
|
|
2785
|
+
last_t = max(len(self._profile[0]), len(self._profile[1]))
|
|
2786
|
+
last_s = self.profile(last_t)
|
|
2787
|
+
for j in range(1, last_s + last_t + 1):
|
|
2788
|
+
if self._generic and self.profile(j-1, 1) == 2:
|
|
2789
|
+
guess = self.Q(j-1)
|
|
2790
|
+
idx += 1
|
|
2791
|
+
if idx == i:
|
|
2792
|
+
elt = guess
|
|
2793
|
+
break
|
|
2794
|
+
for t in range(1, min(j, last_t) + 1):
|
|
2795
|
+
s = j - t
|
|
2796
|
+
if self.profile(t) > s:
|
|
2797
|
+
guess = self.pst(s, t)
|
|
2798
|
+
idx += 1
|
|
2799
|
+
if idx == i:
|
|
2800
|
+
elt = guess
|
|
2801
|
+
break
|
|
2802
|
+
return elt
|
|
2803
|
+
|
|
2804
|
+
# entire Steenrod algebra:
|
|
2805
|
+
if self.profile(1) == Infinity:
|
|
2806
|
+
if not self._generic:
|
|
2807
|
+
return self.Sq(p**i)
|
|
2808
|
+
elif self.profile(0, 1) == 2:
|
|
2809
|
+
if i == 0:
|
|
2810
|
+
return self.Q(0)
|
|
2811
|
+
else:
|
|
2812
|
+
return self.P(p**(i-1))
|
|
2813
|
+
|
|
2814
|
+
# infinite-dimensional sub-Hopf algebra
|
|
2815
|
+
idx = -1
|
|
2816
|
+
tot = 1
|
|
2817
|
+
found = False
|
|
2818
|
+
A = SteenrodAlgebra(p=p, generic=self._generic)
|
|
2819
|
+
while not found:
|
|
2820
|
+
if self._generic:
|
|
2821
|
+
test = A.Q(tot-1)
|
|
2822
|
+
if test in self:
|
|
2823
|
+
idx += 1
|
|
2824
|
+
if idx == i:
|
|
2825
|
+
break
|
|
2826
|
+
for t in range(1, tot+1):
|
|
2827
|
+
s = tot - t
|
|
2828
|
+
test = A.pst(s, t)
|
|
2829
|
+
if test in self:
|
|
2830
|
+
idx += 1
|
|
2831
|
+
if idx == i:
|
|
2832
|
+
found = True
|
|
2833
|
+
break
|
|
2834
|
+
tot += 1
|
|
2835
|
+
return test
|
|
2836
|
+
|
|
2837
|
+
def is_commutative(self) -> bool:
|
|
2838
|
+
r"""
|
|
2839
|
+
Return ``True`` if ``self`` is graded commutative, as determined by the
|
|
2840
|
+
profile function.
|
|
2841
|
+
|
|
2842
|
+
In particular, a sub-Hopf algebra of the
|
|
2843
|
+
mod 2 Steenrod algebra is commutative if and only if there is
|
|
2844
|
+
an integer `n>0` so that its profile function `e` satisfies
|
|
2845
|
+
|
|
2846
|
+
- `e(i) = 0` for `i < n`,
|
|
2847
|
+
- `e(i) \leq n` for `i \geq n`.
|
|
2848
|
+
|
|
2849
|
+
When `p` is odd, there must be an integer `n \geq 0` so that
|
|
2850
|
+
the profile functions `e` and `k` satisfy
|
|
2851
|
+
|
|
2852
|
+
- `e(i) = 0` for `i < n`,
|
|
2853
|
+
- `e(i) \leq n` for `i \geq n`.
|
|
2854
|
+
- `k(i) = 1` for `i < n`.
|
|
2855
|
+
|
|
2856
|
+
EXAMPLES::
|
|
2857
|
+
|
|
2858
|
+
sage: A = SteenrodAlgebra(p=3)
|
|
2859
|
+
sage: A.is_commutative()
|
|
2860
|
+
False
|
|
2861
|
+
sage: SteenrodAlgebra(profile=[2,1]).is_commutative()
|
|
2862
|
+
False
|
|
2863
|
+
sage: SteenrodAlgebra(profile=[0,2,2,1]).is_commutative()
|
|
2864
|
+
True
|
|
2865
|
+
|
|
2866
|
+
Note that if the profile function is specified by a function,
|
|
2867
|
+
then by default it has infinite truncation type: the profile
|
|
2868
|
+
function is assumed to be infinite after the 100th term. ::
|
|
2869
|
+
|
|
2870
|
+
sage: SteenrodAlgebra(profile=lambda n: 1).is_commutative()
|
|
2871
|
+
False
|
|
2872
|
+
sage: SteenrodAlgebra(profile=lambda n: 1, truncation_type=0).is_commutative()
|
|
2873
|
+
True
|
|
2874
|
+
|
|
2875
|
+
sage: SteenrodAlgebra(p=5, profile=([0,2,2,1], [])).is_commutative()
|
|
2876
|
+
True
|
|
2877
|
+
sage: SteenrodAlgebra(p=5, profile=([0,2,2,1], [1,1,2])).is_commutative()
|
|
2878
|
+
True
|
|
2879
|
+
sage: SteenrodAlgebra(p=5, profile=([0,2,1], [1,2,2,2])).is_commutative()
|
|
2880
|
+
False
|
|
2881
|
+
"""
|
|
2882
|
+
if not self._has_nontrivial_profile() or self._truncation_type > 0:
|
|
2883
|
+
return False
|
|
2884
|
+
if not self._generic:
|
|
2885
|
+
n = max(self._profile)
|
|
2886
|
+
return all(self.profile(i) == 0 for i in range(1, n))
|
|
2887
|
+
n = max(self._profile[0])
|
|
2888
|
+
return (all(self.profile(i, 0) == 0 for i in range(1, n))
|
|
2889
|
+
and all(self.profile(i, 1) == 1 for i in range(n)))
|
|
2890
|
+
|
|
2891
|
+
def is_finite(self):
|
|
2892
|
+
r"""
|
|
2893
|
+
Return ``True`` if this algebra is finite-dimensional.
|
|
2894
|
+
|
|
2895
|
+
Therefore true if the profile function is finite, and in
|
|
2896
|
+
particular the ``truncation_type`` must be finite.
|
|
2897
|
+
|
|
2898
|
+
EXAMPLES::
|
|
2899
|
+
|
|
2900
|
+
sage: A = SteenrodAlgebra(p=3)
|
|
2901
|
+
sage: A.is_finite()
|
|
2902
|
+
False
|
|
2903
|
+
sage: SteenrodAlgebra(profile=[3,2,1]).is_finite()
|
|
2904
|
+
True
|
|
2905
|
+
sage: SteenrodAlgebra(profile=lambda n: n).is_finite()
|
|
2906
|
+
False
|
|
2907
|
+
"""
|
|
2908
|
+
return self._has_nontrivial_profile() and self._truncation_type == 0
|
|
2909
|
+
|
|
2910
|
+
def dimension(self):
|
|
2911
|
+
r"""
|
|
2912
|
+
The dimension of this algebra as a vector space over `\GF{p}`.
|
|
2913
|
+
|
|
2914
|
+
If the algebra is infinite, return ``+Infinity``. Otherwise,
|
|
2915
|
+
the profile function must be finite. In this case, at the
|
|
2916
|
+
prime 2, its dimension is `2^s`, where `s` is the sum of the
|
|
2917
|
+
entries in the profile function. At odd primes, the dimension
|
|
2918
|
+
is `p^s * 2^t` where `s` is the sum of the `e` component of
|
|
2919
|
+
the profile function and `t` is the number of 2's in the `k`
|
|
2920
|
+
component of the profile function.
|
|
2921
|
+
|
|
2922
|
+
EXAMPLES::
|
|
2923
|
+
|
|
2924
|
+
sage: SteenrodAlgebra(p=7).dimension()
|
|
2925
|
+
+Infinity
|
|
2926
|
+
sage: SteenrodAlgebra(profile=[3,2,1]).dimension()
|
|
2927
|
+
64
|
|
2928
|
+
sage: SteenrodAlgebra(p=3, profile=([1,1], [])).dimension()
|
|
2929
|
+
9
|
|
2930
|
+
sage: SteenrodAlgebra(p=5, profile=([1], [2,2])).dimension()
|
|
2931
|
+
20
|
|
2932
|
+
"""
|
|
2933
|
+
from sage.rings.infinity import Infinity
|
|
2934
|
+
if not self.is_finite():
|
|
2935
|
+
return Infinity
|
|
2936
|
+
p = self.prime()
|
|
2937
|
+
if not self._generic:
|
|
2938
|
+
return 2**sum(self._profile)
|
|
2939
|
+
return p**sum(self._profile[0]) * 2**len([a for a in self._profile[1] if a == 2])
|
|
2940
|
+
|
|
2941
|
+
@cached_method
|
|
2942
|
+
def top_class(self):
|
|
2943
|
+
r"""
|
|
2944
|
+
Highest dimensional basis element. This is only defined if the algebra is finite.
|
|
2945
|
+
|
|
2946
|
+
EXAMPLES::
|
|
2947
|
+
|
|
2948
|
+
sage: SteenrodAlgebra(2, profile=(3,2,1)).top_class()
|
|
2949
|
+
Sq(7,3,1)
|
|
2950
|
+
sage: SteenrodAlgebra(3, profile=((2,2,1),(1,2,2,2,2))).top_class()
|
|
2951
|
+
Q_1 Q_2 Q_3 Q_4 P(8,8,2)
|
|
2952
|
+
|
|
2953
|
+
TESTS::
|
|
2954
|
+
|
|
2955
|
+
sage: SteenrodAlgebra(2, profile=(3,2,1), basis='pst').top_class()
|
|
2956
|
+
P^0_1 P^0_2 P^1_1 P^0_3 P^1_2 P^2_1
|
|
2957
|
+
sage: SteenrodAlgebra(5, profile=((0,),(2,1,2,2))).top_class()
|
|
2958
|
+
Q_0 Q_2 Q_3
|
|
2959
|
+
sage: SteenrodAlgebra(5).top_class()
|
|
2960
|
+
Traceback (most recent call last):
|
|
2961
|
+
...
|
|
2962
|
+
ValueError: the algebra is not finite dimensional
|
|
2963
|
+
|
|
2964
|
+
Currently, we create the top class in the Milnor basis version and transform
|
|
2965
|
+
this result back into the requested basis. This approach is easy to implement
|
|
2966
|
+
but far from optimal for the 'pst' basis. Occasionally, it also gives an awkward
|
|
2967
|
+
leading coefficient::
|
|
2968
|
+
|
|
2969
|
+
sage: SteenrodAlgebra(3, profile=((2,1),(1,2,2)), basis='pst').top_class()
|
|
2970
|
+
2 Q_1 Q_2 (P^0_1)^2 (P^0_2)^2 (P^1_1)^2
|
|
2971
|
+
|
|
2972
|
+
TESTS::
|
|
2973
|
+
|
|
2974
|
+
sage: A=SteenrodAlgebra(2, profile=(3,2,1), basis='pst')
|
|
2975
|
+
sage: A.top_class().parent() is A
|
|
2976
|
+
True
|
|
2977
|
+
"""
|
|
2978
|
+
if not self.is_finite():
|
|
2979
|
+
raise ValueError("the algebra is not finite dimensional")
|
|
2980
|
+
p = self.prime()
|
|
2981
|
+
# we create the top class in the Milnor basis version
|
|
2982
|
+
AM = SteenrodAlgebra(basis='milnor', p=p, generic=self._generic)
|
|
2983
|
+
if not self._generic:
|
|
2984
|
+
ans = AM.monomial(tuple((1 << k) - 1 for k in self._profile))
|
|
2985
|
+
else:
|
|
2986
|
+
rp, ep = self._profile
|
|
2987
|
+
e = [kk for kk in range(len(ep)) if ep[kk] == 2]
|
|
2988
|
+
r = [p**kk-1 for kk in rp]
|
|
2989
|
+
ans = AM.monomial((tuple(e), tuple(r)))
|
|
2990
|
+
return self(ans.change_basis(self.basis_name()))
|
|
2991
|
+
|
|
2992
|
+
def order(self):
|
|
2993
|
+
r"""
|
|
2994
|
+
The order of this algebra.
|
|
2995
|
+
|
|
2996
|
+
This is computed by computing its vector space dimension `d`
|
|
2997
|
+
and then returning `p^d`.
|
|
2998
|
+
|
|
2999
|
+
EXAMPLES::
|
|
3000
|
+
|
|
3001
|
+
sage: SteenrodAlgebra(p=7).order()
|
|
3002
|
+
+Infinity
|
|
3003
|
+
sage: SteenrodAlgebra(profile=[2,1]).dimension()
|
|
3004
|
+
8
|
|
3005
|
+
sage: SteenrodAlgebra(profile=[2,1]).order()
|
|
3006
|
+
256
|
|
3007
|
+
sage: SteenrodAlgebra(p=3, profile=([1], [])).dimension()
|
|
3008
|
+
3
|
|
3009
|
+
sage: SteenrodAlgebra(p=3, profile=([1], [])).order()
|
|
3010
|
+
27
|
|
3011
|
+
sage: SteenrodAlgebra(p=5, profile=([], [2, 2])).dimension()
|
|
3012
|
+
4
|
|
3013
|
+
sage: SteenrodAlgebra(p=5, profile=([], [2, 2])).order() == 5**4
|
|
3014
|
+
True
|
|
3015
|
+
"""
|
|
3016
|
+
from sage.rings.infinity import Infinity
|
|
3017
|
+
if not self.is_finite():
|
|
3018
|
+
return Infinity
|
|
3019
|
+
return self.prime() ** self.dimension()
|
|
3020
|
+
|
|
3021
|
+
def is_division_algebra(self):
|
|
3022
|
+
r"""
|
|
3023
|
+
The only way this algebra can be a division algebra is if it
|
|
3024
|
+
is the ground field `\GF{p}`.
|
|
3025
|
+
|
|
3026
|
+
EXAMPLES::
|
|
3027
|
+
|
|
3028
|
+
sage: SteenrodAlgebra(11).is_division_algebra()
|
|
3029
|
+
False
|
|
3030
|
+
sage: SteenrodAlgebra(profile=lambda n: 0, truncation_type=0).is_division_algebra()
|
|
3031
|
+
True
|
|
3032
|
+
"""
|
|
3033
|
+
return self.is_field()
|
|
3034
|
+
|
|
3035
|
+
def is_field(self, proof=True):
|
|
3036
|
+
r"""
|
|
3037
|
+
The only way this algebra can be a field is if it is the
|
|
3038
|
+
ground field `\GF{p}`.
|
|
3039
|
+
|
|
3040
|
+
EXAMPLES::
|
|
3041
|
+
|
|
3042
|
+
sage: SteenrodAlgebra(11).is_field()
|
|
3043
|
+
False
|
|
3044
|
+
sage: SteenrodAlgebra(profile=lambda n: 0, truncation_type=0).is_field()
|
|
3045
|
+
True
|
|
3046
|
+
"""
|
|
3047
|
+
return self.dimension() == 1
|
|
3048
|
+
|
|
3049
|
+
def is_integral_domain(self, proof=True):
|
|
3050
|
+
r"""
|
|
3051
|
+
The only way this algebra can be an integral domain is if it
|
|
3052
|
+
is the ground field `\GF{p}`.
|
|
3053
|
+
|
|
3054
|
+
EXAMPLES::
|
|
3055
|
+
|
|
3056
|
+
sage: SteenrodAlgebra(11).is_integral_domain()
|
|
3057
|
+
False
|
|
3058
|
+
sage: SteenrodAlgebra(profile=lambda n: 0, truncation_type=0).is_integral_domain()
|
|
3059
|
+
True
|
|
3060
|
+
"""
|
|
3061
|
+
return self.is_field()
|
|
3062
|
+
|
|
3063
|
+
def is_noetherian(self) -> bool:
|
|
3064
|
+
"""
|
|
3065
|
+
This algebra is Noetherian if and only if it is finite.
|
|
3066
|
+
|
|
3067
|
+
EXAMPLES::
|
|
3068
|
+
|
|
3069
|
+
sage: SteenrodAlgebra(3).is_noetherian()
|
|
3070
|
+
False
|
|
3071
|
+
sage: SteenrodAlgebra(profile=[1,2,1]).is_noetherian()
|
|
3072
|
+
True
|
|
3073
|
+
sage: SteenrodAlgebra(profile=lambda n: n+2).is_noetherian()
|
|
3074
|
+
False
|
|
3075
|
+
"""
|
|
3076
|
+
return self.is_finite()
|
|
3077
|
+
|
|
3078
|
+
def is_generic(self):
|
|
3079
|
+
r"""
|
|
3080
|
+
The algebra is generic if it is based on the odd-primary relations,
|
|
3081
|
+
i.e. if its dual is a quotient of
|
|
3082
|
+
|
|
3083
|
+
.. MATH::
|
|
3084
|
+
|
|
3085
|
+
A_* = \GF{p} [\xi_1, \xi_2, \xi_3, ...] \otimes \Lambda (\tau_0, \tau_1, ...)
|
|
3086
|
+
|
|
3087
|
+
Sage also allows this for `p=2`. Only the usual Steenrod algebra at the prime `2` and
|
|
3088
|
+
its sub algebras are non-generic.
|
|
3089
|
+
|
|
3090
|
+
EXAMPLES::
|
|
3091
|
+
|
|
3092
|
+
sage: SteenrodAlgebra(3).is_generic()
|
|
3093
|
+
True
|
|
3094
|
+
sage: SteenrodAlgebra(2).is_generic()
|
|
3095
|
+
False
|
|
3096
|
+
sage: SteenrodAlgebra(2, generic=True).is_generic()
|
|
3097
|
+
True
|
|
3098
|
+
"""
|
|
3099
|
+
return self._generic
|
|
3100
|
+
|
|
3101
|
+
######################################################
|
|
3102
|
+
# element class
|
|
3103
|
+
######################################################
|
|
3104
|
+
|
|
3105
|
+
class Element(CombinatorialFreeModule.Element):
|
|
3106
|
+
r"""
|
|
3107
|
+
Class for elements of the Steenrod algebra. Since the
|
|
3108
|
+
Steenrod algebra class is based on
|
|
3109
|
+
:class:`CombinatorialFreeModule
|
|
3110
|
+
<sage.combinat.free_module.CombinatorialFreeModule>`, this is
|
|
3111
|
+
based on :class:`IndexedFreeModuleElement
|
|
3112
|
+
<sage.modules.with_basis.indexed_element.IndexedFreeModuleElement>`.
|
|
3113
|
+
It has new methods reflecting its role, like :meth:`degree`
|
|
3114
|
+
for computing the degree of an element.
|
|
3115
|
+
|
|
3116
|
+
EXAMPLES:
|
|
3117
|
+
|
|
3118
|
+
Since this class inherits from
|
|
3119
|
+
:class:`IndexedFreeModuleElement
|
|
3120
|
+
<sage.modules.with_basis.indexed_element.IndexedFreeModuleElement>`,
|
|
3121
|
+
elements can be used as iterators, and there are other useful
|
|
3122
|
+
methods::
|
|
3123
|
+
|
|
3124
|
+
sage: c = Sq(5).antipode(); c
|
|
3125
|
+
Sq(2,1) + Sq(5)
|
|
3126
|
+
sage: for mono, coeff in c: print((coeff, mono))
|
|
3127
|
+
(1, (5,))
|
|
3128
|
+
(1, (2, 1))
|
|
3129
|
+
sage: c.monomial_coefficients() == {(2, 1): 1, (5,): 1}
|
|
3130
|
+
True
|
|
3131
|
+
sage: sorted(c.monomials(), key=lambda x: tuple(x.support()))
|
|
3132
|
+
[Sq(2,1), Sq(5)]
|
|
3133
|
+
sage: sorted(c.support())
|
|
3134
|
+
[(2, 1), (5,)]
|
|
3135
|
+
|
|
3136
|
+
See the documentation for this module (type
|
|
3137
|
+
``sage.algebras.steenrod.steenrod_algebra?``) for more
|
|
3138
|
+
information about elements of the Steenrod algebra.
|
|
3139
|
+
"""
|
|
3140
|
+
def prime(self):
|
|
3141
|
+
"""
|
|
3142
|
+
The prime associated to ``self``.
|
|
3143
|
+
|
|
3144
|
+
EXAMPLES::
|
|
3145
|
+
|
|
3146
|
+
sage: a = SteenrodAlgebra().Sq(3,2,1)
|
|
3147
|
+
sage: a.prime()
|
|
3148
|
+
2
|
|
3149
|
+
sage: a.change_basis('adem').prime()
|
|
3150
|
+
2
|
|
3151
|
+
sage: b = SteenrodAlgebra(p=7).basis(36)[0]
|
|
3152
|
+
sage: b.prime()
|
|
3153
|
+
7
|
|
3154
|
+
sage: SteenrodAlgebra(p=3, basis='adem').one().prime()
|
|
3155
|
+
3
|
|
3156
|
+
"""
|
|
3157
|
+
return self.base_ring().characteristic()
|
|
3158
|
+
|
|
3159
|
+
def basis_name(self):
|
|
3160
|
+
"""
|
|
3161
|
+
The basis name associated to ``self``.
|
|
3162
|
+
|
|
3163
|
+
EXAMPLES::
|
|
3164
|
+
|
|
3165
|
+
sage: a = SteenrodAlgebra().Sq(3,2,1)
|
|
3166
|
+
sage: a.basis_name()
|
|
3167
|
+
'milnor'
|
|
3168
|
+
sage: a.change_basis('adem').basis_name()
|
|
3169
|
+
'serre-cartan'
|
|
3170
|
+
sage: a.change_basis('wood____y').basis_name()
|
|
3171
|
+
'woody'
|
|
3172
|
+
sage: b = SteenrodAlgebra(p=7).basis(36)[0]
|
|
3173
|
+
sage: b.basis_name()
|
|
3174
|
+
'milnor'
|
|
3175
|
+
sage: a.change_basis('adem').basis_name()
|
|
3176
|
+
'serre-cartan'
|
|
3177
|
+
"""
|
|
3178
|
+
return self.parent().prefix()
|
|
3179
|
+
|
|
3180
|
+
def is_homogeneous(self):
|
|
3181
|
+
"""
|
|
3182
|
+
Return ``True`` iff this element is homogeneous.
|
|
3183
|
+
|
|
3184
|
+
EXAMPLES::
|
|
3185
|
+
|
|
3186
|
+
sage: (Sq(0,0,1) + Sq(7)).is_homogeneous()
|
|
3187
|
+
True
|
|
3188
|
+
sage: (Sq(0,0,1) + Sq(2)).is_homogeneous()
|
|
3189
|
+
False
|
|
3190
|
+
"""
|
|
3191
|
+
monos = self.support()
|
|
3192
|
+
if len(monos) <= 1:
|
|
3193
|
+
return True
|
|
3194
|
+
degree = None
|
|
3195
|
+
deg = self.parent().degree_on_basis
|
|
3196
|
+
for mono in monos:
|
|
3197
|
+
if degree is None:
|
|
3198
|
+
degree = deg(mono)
|
|
3199
|
+
elif deg(mono) != degree:
|
|
3200
|
+
return False
|
|
3201
|
+
return True
|
|
3202
|
+
|
|
3203
|
+
def degree(self):
|
|
3204
|
+
r"""
|
|
3205
|
+
The degree of ``self``.
|
|
3206
|
+
|
|
3207
|
+
The degree of `\text{Sq}(i_1,i_2,i_3,...)` is
|
|
3208
|
+
|
|
3209
|
+
.. MATH::
|
|
3210
|
+
|
|
3211
|
+
i_1 + 3i_2 + 7i_3 + ... + (2^k - 1) i_k + ....
|
|
3212
|
+
|
|
3213
|
+
At an odd prime `p`, the degree of `Q_k` is `2p^k - 1` and the
|
|
3214
|
+
degree of `\mathcal{P}(i_1, i_2, ...)` is
|
|
3215
|
+
|
|
3216
|
+
.. MATH::
|
|
3217
|
+
|
|
3218
|
+
\sum_{k \geq 0} 2(p^k - 1) i_k.
|
|
3219
|
+
|
|
3220
|
+
ALGORITHM: If :meth:`is_homogeneous` returns True, call
|
|
3221
|
+
:meth:`SteenrodAlgebra_generic.degree_on_basis` on the leading
|
|
3222
|
+
summand.
|
|
3223
|
+
|
|
3224
|
+
EXAMPLES::
|
|
3225
|
+
|
|
3226
|
+
sage: Sq(0,0,1).degree()
|
|
3227
|
+
7
|
|
3228
|
+
sage: (Sq(0,0,1) + Sq(7)).degree()
|
|
3229
|
+
7
|
|
3230
|
+
sage: (Sq(0,0,1) + Sq(2)).degree()
|
|
3231
|
+
Traceback (most recent call last):
|
|
3232
|
+
...
|
|
3233
|
+
ValueError: element is not homogeneous
|
|
3234
|
+
|
|
3235
|
+
sage: A11 = SteenrodAlgebra(p=11)
|
|
3236
|
+
sage: A11.P(1).degree()
|
|
3237
|
+
20
|
|
3238
|
+
sage: A11.P(1,1).degree()
|
|
3239
|
+
260
|
|
3240
|
+
sage: A11.Q(2).degree()
|
|
3241
|
+
241
|
|
3242
|
+
|
|
3243
|
+
TESTS::
|
|
3244
|
+
|
|
3245
|
+
sage: all(x.degree() == 10 for x in SteenrodAlgebra(basis='woody').basis(10))
|
|
3246
|
+
True
|
|
3247
|
+
sage: all(x.degree() == 11 for x in SteenrodAlgebra(basis='woodz').basis(11))
|
|
3248
|
+
True
|
|
3249
|
+
sage: all(x.degree() == x.milnor().degree() for x in SteenrodAlgebra(basis='wall').basis(11))
|
|
3250
|
+
True
|
|
3251
|
+
sage: a = SteenrodAlgebra(basis='pst').basis(10)[0]
|
|
3252
|
+
sage: a.degree() == a.change_basis('arnonc').degree()
|
|
3253
|
+
True
|
|
3254
|
+
sage: b = SteenrodAlgebra(basis='comm').basis(12)[1]
|
|
3255
|
+
sage: b.degree() == b.change_basis('adem').change_basis('arnona').degree()
|
|
3256
|
+
True
|
|
3257
|
+
sage: all(x.degree() == 9 for x in SteenrodAlgebra(basis='comm').basis(9))
|
|
3258
|
+
True
|
|
3259
|
+
sage: all(x.degree() == 8 for x in SteenrodAlgebra(basis='adem').basis(8))
|
|
3260
|
+
True
|
|
3261
|
+
sage: all(x.degree() == 7 for x in SteenrodAlgebra(basis='milnor').basis(7))
|
|
3262
|
+
True
|
|
3263
|
+
sage: all(x.degree() == 24 for x in SteenrodAlgebra(p=3).basis(24))
|
|
3264
|
+
True
|
|
3265
|
+
sage: all(x.degree() == 40 for x in SteenrodAlgebra(p=5, basis='serre-cartan').basis(40))
|
|
3266
|
+
True
|
|
3267
|
+
"""
|
|
3268
|
+
if len(self.support()) == 0:
|
|
3269
|
+
raise ValueError("the zero element does not have a well-defined degree")
|
|
3270
|
+
if not self.is_homogeneous():
|
|
3271
|
+
raise ValueError("element is not homogeneous")
|
|
3272
|
+
return self.parent().degree_on_basis(self.leading_support())
|
|
3273
|
+
|
|
3274
|
+
def milnor(self):
|
|
3275
|
+
"""
|
|
3276
|
+
Return this element in the Milnor basis; that is, as an
|
|
3277
|
+
element of the appropriate Steenrod algebra.
|
|
3278
|
+
|
|
3279
|
+
This just calls the method
|
|
3280
|
+
:meth:`SteenrodAlgebra_generic.milnor`.
|
|
3281
|
+
|
|
3282
|
+
EXAMPLES::
|
|
3283
|
+
|
|
3284
|
+
sage: Adem = SteenrodAlgebra(basis='adem')
|
|
3285
|
+
sage: a = Adem.basis(4)[1]; a
|
|
3286
|
+
Sq^3 Sq^1
|
|
3287
|
+
sage: a.milnor()
|
|
3288
|
+
Sq(1,1)
|
|
3289
|
+
"""
|
|
3290
|
+
A = self.parent()
|
|
3291
|
+
return A.milnor(self)
|
|
3292
|
+
|
|
3293
|
+
def change_basis(self, basis='milnor'):
|
|
3294
|
+
r"""
|
|
3295
|
+
Representation of element with respect to basis.
|
|
3296
|
+
|
|
3297
|
+
INPUT:
|
|
3298
|
+
|
|
3299
|
+
- ``basis`` -- string; basis in which to work
|
|
3300
|
+
|
|
3301
|
+
OUTPUT: representation of ``self`` in given basis
|
|
3302
|
+
|
|
3303
|
+
The choices for ``basis`` are:
|
|
3304
|
+
|
|
3305
|
+
- 'milnor' for the Milnor basis.
|
|
3306
|
+
- 'serre-cartan', 'serre_cartan', 'sc', 'adem', 'admissible'
|
|
3307
|
+
for the Serre-Cartan basis.
|
|
3308
|
+
- 'wood_y' for Wood's Y basis.
|
|
3309
|
+
- 'wood_z' for Wood's Z basis.
|
|
3310
|
+
- 'wall' for Wall's basis.
|
|
3311
|
+
- 'wall_long' for Wall's basis, alternate representation
|
|
3312
|
+
- 'arnon_a' for Arnon's A basis.
|
|
3313
|
+
- 'arnon_a_long' for Arnon's A basis, alternate representation.
|
|
3314
|
+
- 'arnon_c' for Arnon's C basis.
|
|
3315
|
+
- 'pst', 'pst_rlex', 'pst_llex', 'pst_deg', 'pst_revz' for
|
|
3316
|
+
various `P^s_t`-bases.
|
|
3317
|
+
- 'comm', 'comm_rlex', 'comm_llex', 'comm_deg', 'comm_revz'
|
|
3318
|
+
for various commutator bases.
|
|
3319
|
+
- 'comm_long', 'comm_rlex_long', etc., for commutator bases,
|
|
3320
|
+
alternate representations.
|
|
3321
|
+
|
|
3322
|
+
See documentation for this module (by browsing the
|
|
3323
|
+
reference manual or by typing
|
|
3324
|
+
``sage.algebras.steenrod.steenrod_algebra?``) for
|
|
3325
|
+
descriptions of the different bases.
|
|
3326
|
+
|
|
3327
|
+
EXAMPLES::
|
|
3328
|
+
|
|
3329
|
+
sage: c = Sq(2) * Sq(1)
|
|
3330
|
+
sage: c.change_basis('milnor')
|
|
3331
|
+
Sq(0,1) + Sq(3)
|
|
3332
|
+
sage: c.change_basis('serre-cartan')
|
|
3333
|
+
Sq^2 Sq^1
|
|
3334
|
+
sage: d = Sq(0,0,1)
|
|
3335
|
+
sage: d.change_basis('arnonc')
|
|
3336
|
+
Sq^2 Sq^5 + Sq^4 Sq^2 Sq^1 + Sq^4 Sq^3 + Sq^7
|
|
3337
|
+
"""
|
|
3338
|
+
A = self.parent()
|
|
3339
|
+
return A._change_basis(self, basis)
|
|
3340
|
+
|
|
3341
|
+
def _basis_dictionary(self, basis):
|
|
3342
|
+
r"""
|
|
3343
|
+
Convert ``self`` to ``basis``, returning a dictionary of terms of
|
|
3344
|
+
the form (mono: coeff), where mono is a monomial in the given
|
|
3345
|
+
basis.
|
|
3346
|
+
|
|
3347
|
+
INPUT:
|
|
3348
|
+
|
|
3349
|
+
- ``basis`` -- string, basis in which to work
|
|
3350
|
+
|
|
3351
|
+
OUTPUT: dictionary
|
|
3352
|
+
|
|
3353
|
+
This just calls :meth:`change_basis` to get an element of the
|
|
3354
|
+
Steenrod algebra with the new basis, and then calls
|
|
3355
|
+
:meth:`monomial_coefficients` on this element to produce its
|
|
3356
|
+
dictionary representation.
|
|
3357
|
+
|
|
3358
|
+
EXAMPLES::
|
|
3359
|
+
|
|
3360
|
+
sage: c = Sq(2) * Sq(1)
|
|
3361
|
+
sage: c._basis_dictionary('milnor') == {(0, 1): 1, (3,): 1}
|
|
3362
|
+
True
|
|
3363
|
+
sage: c
|
|
3364
|
+
Sq(0,1) + Sq(3)
|
|
3365
|
+
sage: c._basis_dictionary('serre-cartan')
|
|
3366
|
+
{(2, 1): 1}
|
|
3367
|
+
sage: c.change_basis('serre-cartan')
|
|
3368
|
+
Sq^2 Sq^1
|
|
3369
|
+
sage: d = Sq(0,0,1)
|
|
3370
|
+
sage: sorted(d._basis_dictionary('arnonc').items())
|
|
3371
|
+
[((2, 5), 1), ((4, 2, 1), 1), ((4, 3), 1), ((7,), 1)]
|
|
3372
|
+
sage: d.change_basis('arnonc')
|
|
3373
|
+
Sq^2 Sq^5 + Sq^4 Sq^2 Sq^1 + Sq^4 Sq^3 + Sq^7
|
|
3374
|
+
|
|
3375
|
+
At odd primes::
|
|
3376
|
+
|
|
3377
|
+
sage: e = 2 * SteenrodAlgebra(3).P(1,2)
|
|
3378
|
+
sage: e._basis_dictionary('milnor')
|
|
3379
|
+
{((), (1, 2)): 2}
|
|
3380
|
+
sage: e
|
|
3381
|
+
2 P(1,2)
|
|
3382
|
+
sage: sorted(e._basis_dictionary('serre-cartan').items())
|
|
3383
|
+
[((0, 7, 0, 2, 0), 2), ((0, 8, 0, 1, 0), 2)]
|
|
3384
|
+
sage: e.change_basis('adem')
|
|
3385
|
+
2 P^7 P^2 + 2 P^8 P^1
|
|
3386
|
+
"""
|
|
3387
|
+
a = self.change_basis(basis)
|
|
3388
|
+
return a.monomial_coefficients()
|
|
3389
|
+
|
|
3390
|
+
def coproduct(self, algorithm='milnor'):
|
|
3391
|
+
"""
|
|
3392
|
+
The coproduct of this element.
|
|
3393
|
+
|
|
3394
|
+
INPUT:
|
|
3395
|
+
|
|
3396
|
+
- ``algorithm`` -- ``None`` or a string, either 'milnor' or
|
|
3397
|
+
'serre-cartan' (or anything which will be converted to
|
|
3398
|
+
one of these by the function :func:`get_basis_name
|
|
3399
|
+
<sage.algebras.steenrod.steenrod_algebra_misc.get_basis_name>`).
|
|
3400
|
+
If ``None``, default to 'serre-cartan' if current basis is
|
|
3401
|
+
'serre-cartan'; otherwise use 'milnor'.
|
|
3402
|
+
|
|
3403
|
+
See :meth:`SteenrodAlgebra_generic.coproduct_on_basis` for
|
|
3404
|
+
more information on computing the coproduct.
|
|
3405
|
+
|
|
3406
|
+
EXAMPLES::
|
|
3407
|
+
|
|
3408
|
+
sage: a = Sq(2)
|
|
3409
|
+
sage: a.coproduct()
|
|
3410
|
+
1 # Sq(2) + Sq(1) # Sq(1) + Sq(2) # 1
|
|
3411
|
+
sage: b = Sq(4)
|
|
3412
|
+
sage: (a*b).coproduct() == (a.coproduct()) * (b.coproduct())
|
|
3413
|
+
True
|
|
3414
|
+
|
|
3415
|
+
sage: c = a.change_basis('adem'); c.coproduct(algorithm='milnor')
|
|
3416
|
+
1 # Sq^2 + Sq^1 # Sq^1 + Sq^2 # 1
|
|
3417
|
+
sage: c = a.change_basis('adem'); c.coproduct(algorithm='adem')
|
|
3418
|
+
1 # Sq^2 + Sq^1 # Sq^1 + Sq^2 # 1
|
|
3419
|
+
|
|
3420
|
+
sage: d = a.change_basis('comm_long'); d.coproduct()
|
|
3421
|
+
1 # s_2 + s_1 # s_1 + s_2 # 1
|
|
3422
|
+
|
|
3423
|
+
sage: A7 = SteenrodAlgebra(p=7)
|
|
3424
|
+
sage: a = A7.Q(1) * A7.P(1); a
|
|
3425
|
+
Q_1 P(1)
|
|
3426
|
+
sage: a.coproduct()
|
|
3427
|
+
1 # Q_1 P(1) + P(1) # Q_1 + Q_1 # P(1) + Q_1 P(1) # 1
|
|
3428
|
+
sage: a.coproduct(algorithm='adem')
|
|
3429
|
+
1 # Q_1 P(1) + P(1) # Q_1 + Q_1 # P(1) + Q_1 P(1) # 1
|
|
3430
|
+
|
|
3431
|
+
Once you have an element of the tensor product, you may
|
|
3432
|
+
want to extract the tensor factors of its summands. ::
|
|
3433
|
+
|
|
3434
|
+
sage: b = Sq(2).coproduct()
|
|
3435
|
+
sage: b
|
|
3436
|
+
1 # Sq(2) + Sq(1) # Sq(1) + Sq(2) # 1
|
|
3437
|
+
sage: supp = sorted(b.support()); supp
|
|
3438
|
+
[((), (2,)), ((1,), (1,)), ((2,), ())]
|
|
3439
|
+
sage: Sq(*supp[0][0])
|
|
3440
|
+
1
|
|
3441
|
+
sage: Sq(*supp[0][1])
|
|
3442
|
+
Sq(2)
|
|
3443
|
+
sage: [(Sq(*x), Sq(*y)) for (x,y) in supp]
|
|
3444
|
+
[(1, Sq(2)), (Sq(1), Sq(1)), (Sq(2), 1)]
|
|
3445
|
+
|
|
3446
|
+
The ``support`` of an element does not include the
|
|
3447
|
+
coefficients, so at odd primes it may be better to use
|
|
3448
|
+
``monomial_coefficients``::
|
|
3449
|
+
|
|
3450
|
+
sage: A3 = SteenrodAlgebra(p=3)
|
|
3451
|
+
sage: b = (A3.P(1)**2).coproduct()
|
|
3452
|
+
sage: b
|
|
3453
|
+
2*1 # P(2) + 2*P(1) # P(1) + 2*P(2) # 1
|
|
3454
|
+
sage: sorted(b.support())
|
|
3455
|
+
[(((), ()), ((), (2,))), (((), (1,)), ((), (1,))), (((), (2,)), ((), ()))]
|
|
3456
|
+
sage: b.monomial_coefficients()
|
|
3457
|
+
{(((), ()), ((), (2,))): 2,
|
|
3458
|
+
(((), (1,)), ((), (1,))): 2,
|
|
3459
|
+
(((), (2,)), ((), ())): 2}
|
|
3460
|
+
sage: mc = b.monomial_coefficients()
|
|
3461
|
+
sage: sorted([(A3.monomial(x), A3.monomial(y), mc[x,y]) for (x,y) in mc])
|
|
3462
|
+
[(1, P(2), 2), (P(1), P(1), 2), (P(2), 1, 2)]
|
|
3463
|
+
"""
|
|
3464
|
+
A = self.parent()
|
|
3465
|
+
return A.coproduct(self, algorithm=algorithm)
|
|
3466
|
+
|
|
3467
|
+
def excess(self):
|
|
3468
|
+
r"""
|
|
3469
|
+
Excess of element.
|
|
3470
|
+
|
|
3471
|
+
OUTPUT: ``excess`` -- nonnegative integer
|
|
3472
|
+
|
|
3473
|
+
The excess of a Milnor basis element `\text{Sq}(a,b,c,...)` is
|
|
3474
|
+
`a + b + c + \cdots`. When `p` is odd, the excess of `Q_{0}^{e_0}
|
|
3475
|
+
Q_{1}^{e_1} \cdots P(r_1, r_2, ...)` is `\sum e_i + 2 \sum r_i`.
|
|
3476
|
+
The excess of a linear combination of Milnor basis elements is
|
|
3477
|
+
the minimum of the excesses of those basis elements.
|
|
3478
|
+
|
|
3479
|
+
See [Kr1971]_ for the proofs of these assertions.
|
|
3480
|
+
|
|
3481
|
+
EXAMPLES::
|
|
3482
|
+
|
|
3483
|
+
sage: a = Sq(1,2,3)
|
|
3484
|
+
sage: a.excess()
|
|
3485
|
+
6
|
|
3486
|
+
sage: (Sq(0,0,1) + Sq(4,1) + Sq(7)).excess()
|
|
3487
|
+
1
|
|
3488
|
+
sage: elt = Sq(0,0,1) + Sq(4,1) + Sq(7)
|
|
3489
|
+
sage: M = sorted(elt.monomials(), key=lambda x: tuple(x.support()))
|
|
3490
|
+
sage: [m.excess() for m in M]
|
|
3491
|
+
[1, 5, 7]
|
|
3492
|
+
sage: [m for m in M]
|
|
3493
|
+
[Sq(0,0,1), Sq(4,1), Sq(7)]
|
|
3494
|
+
sage: B = SteenrodAlgebra(7)
|
|
3495
|
+
sage: a = B.Q(1,2,5)
|
|
3496
|
+
sage: b = B.P(2,2,3)
|
|
3497
|
+
sage: a.excess()
|
|
3498
|
+
3
|
|
3499
|
+
sage: b.excess()
|
|
3500
|
+
14
|
|
3501
|
+
sage: (a + b).excess()
|
|
3502
|
+
3
|
|
3503
|
+
sage: (a * b).excess()
|
|
3504
|
+
17
|
|
3505
|
+
"""
|
|
3506
|
+
def excess_odd(mono):
|
|
3507
|
+
"""
|
|
3508
|
+
Excess of mono, where mono has the form
|
|
3509
|
+
((s0, s1, ...), (r1, r2, ...)).
|
|
3510
|
+
|
|
3511
|
+
Return the length of the first component, since that
|
|
3512
|
+
is the number of factors, plus twice the sum of the
|
|
3513
|
+
terms in the second component.
|
|
3514
|
+
"""
|
|
3515
|
+
if not mono:
|
|
3516
|
+
return 0
|
|
3517
|
+
else:
|
|
3518
|
+
return len(mono[0]) + 2 * sum(mono[1])
|
|
3519
|
+
|
|
3520
|
+
a = self.milnor()
|
|
3521
|
+
if not self.parent()._generic:
|
|
3522
|
+
excesses = [sum(mono) for mono in a.support()]
|
|
3523
|
+
else:
|
|
3524
|
+
excesses = [excess_odd(mono) for mono in a.support()]
|
|
3525
|
+
return min(excesses)
|
|
3526
|
+
|
|
3527
|
+
def is_unit(self):
|
|
3528
|
+
r"""
|
|
3529
|
+
Return ``True`` if element has a nonzero scalar multiple of
|
|
3530
|
+
`P(0)` as a summand, ``False`` otherwise.
|
|
3531
|
+
|
|
3532
|
+
EXAMPLES::
|
|
3533
|
+
|
|
3534
|
+
sage: z = Sq(4,2) + Sq(7,1) + Sq(3,0,1)
|
|
3535
|
+
sage: z.is_unit()
|
|
3536
|
+
False
|
|
3537
|
+
sage: u = Sq(0) + Sq(3,1)
|
|
3538
|
+
sage: u == 1 + Sq(3,1)
|
|
3539
|
+
True
|
|
3540
|
+
sage: u.is_unit()
|
|
3541
|
+
True
|
|
3542
|
+
sage: A5 = SteenrodAlgebra(5)
|
|
3543
|
+
sage: v = A5.P(0)
|
|
3544
|
+
sage: (v + v + v).is_unit()
|
|
3545
|
+
True
|
|
3546
|
+
"""
|
|
3547
|
+
return self.parent().one() in self.monomials()
|
|
3548
|
+
|
|
3549
|
+
def is_nilpotent(self):
|
|
3550
|
+
"""
|
|
3551
|
+
Return ``True`` if element is not a unit, ``False`` otherwise.
|
|
3552
|
+
|
|
3553
|
+
EXAMPLES::
|
|
3554
|
+
|
|
3555
|
+
sage: z = Sq(4,2) + Sq(7,1) + Sq(3,0,1)
|
|
3556
|
+
sage: z.is_nilpotent()
|
|
3557
|
+
True
|
|
3558
|
+
sage: u = 1 + Sq(3,1)
|
|
3559
|
+
sage: u == 1 + Sq(3,1)
|
|
3560
|
+
True
|
|
3561
|
+
sage: u.is_nilpotent()
|
|
3562
|
+
False
|
|
3563
|
+
"""
|
|
3564
|
+
return not self.is_unit()
|
|
3565
|
+
|
|
3566
|
+
def may_weight(self):
|
|
3567
|
+
r"""
|
|
3568
|
+
May's 'weight' of element.
|
|
3569
|
+
|
|
3570
|
+
OUTPUT: ``weight`` -- nonnegative integer
|
|
3571
|
+
|
|
3572
|
+
If we let `F_* (A)` be the May filtration of the Steenrod
|
|
3573
|
+
algebra, the weight of an element `x` is the integer `k` so
|
|
3574
|
+
that `x` is in `F_k(A)` and not in `F_{k+1}(A)`. According to
|
|
3575
|
+
Theorem 2.6 in May's thesis [May1964]_, the weight of a Milnor
|
|
3576
|
+
basis element is computed as follows: first, to compute the
|
|
3577
|
+
weight of `P(r_1,r_2, ...)`, write each `r_i` in base `p` as
|
|
3578
|
+
`r_i = \sum_j p^j r_{ij}`. Then each nonzero binary digit
|
|
3579
|
+
`r_{ij}` contributes `i` to the weight: the weight is
|
|
3580
|
+
`\sum_{i,j} i r_{ij}`. When `p` is odd, the weight of `Q_i` is
|
|
3581
|
+
`i+1`, so the weight of a product `Q_{i_1} Q_{i_2} ...` equals
|
|
3582
|
+
`(i_1+1) + (i_2+1) + ...`. Then the weight of `Q_{i_1} Q_{i_2}
|
|
3583
|
+
...P(r_1,r_2, ...)` is the sum of `(i_1+1) + (i_2+1) + ...`
|
|
3584
|
+
and `\sum_{i,j} i r_{ij}`.
|
|
3585
|
+
|
|
3586
|
+
The weight of a sum of Milnor basis elements is the minimum of
|
|
3587
|
+
the weights of the summands.
|
|
3588
|
+
|
|
3589
|
+
When `p=2`, we compute the weight on Milnor basis elements by
|
|
3590
|
+
adding up the terms in their 'height' - see
|
|
3591
|
+
:meth:`wall_height` for documentation. (When `p` is odd, the
|
|
3592
|
+
height of an element is not defined.)
|
|
3593
|
+
|
|
3594
|
+
EXAMPLES::
|
|
3595
|
+
|
|
3596
|
+
sage: Sq(0).may_weight()
|
|
3597
|
+
0
|
|
3598
|
+
sage: a = Sq(4)
|
|
3599
|
+
sage: a.may_weight()
|
|
3600
|
+
1
|
|
3601
|
+
sage: b = Sq(4)*Sq(8) + Sq(8)*Sq(4)
|
|
3602
|
+
sage: b.may_weight()
|
|
3603
|
+
2
|
|
3604
|
+
sage: Sq(2,1,5).wall_height()
|
|
3605
|
+
[2, 3, 2, 1, 1]
|
|
3606
|
+
sage: Sq(2,1,5).may_weight()
|
|
3607
|
+
9
|
|
3608
|
+
sage: A5 = SteenrodAlgebra(5)
|
|
3609
|
+
sage: a = A5.Q(1,2,4)
|
|
3610
|
+
sage: b = A5.P(1,2,1)
|
|
3611
|
+
sage: a.may_weight()
|
|
3612
|
+
10
|
|
3613
|
+
sage: b.may_weight()
|
|
3614
|
+
8
|
|
3615
|
+
sage: (a * b).may_weight()
|
|
3616
|
+
18
|
|
3617
|
+
sage: A5.P(0,0,1).may_weight()
|
|
3618
|
+
3
|
|
3619
|
+
"""
|
|
3620
|
+
from sage.rings.infinity import Infinity
|
|
3621
|
+
from sage.rings.integer import Integer
|
|
3622
|
+
p = self.prime()
|
|
3623
|
+
generic = self.parent()._generic
|
|
3624
|
+
if self == 0:
|
|
3625
|
+
return Infinity
|
|
3626
|
+
elif self.is_unit():
|
|
3627
|
+
return 0
|
|
3628
|
+
elif not generic:
|
|
3629
|
+
wt = Infinity
|
|
3630
|
+
for mono in self.milnor().monomials():
|
|
3631
|
+
wt = min(wt, sum(mono.wall_height()))
|
|
3632
|
+
return wt
|
|
3633
|
+
else: # p odd
|
|
3634
|
+
wt = Infinity
|
|
3635
|
+
for (mono1, mono2) in self.milnor().support():
|
|
3636
|
+
P_wt = 0
|
|
3637
|
+
index = 1
|
|
3638
|
+
for n in mono2:
|
|
3639
|
+
P_wt += index * sum(Integer(n).digits(p))
|
|
3640
|
+
index += 1
|
|
3641
|
+
wt = min(wt, sum(mono1) + len(mono1) + P_wt)
|
|
3642
|
+
return wt
|
|
3643
|
+
|
|
3644
|
+
def is_decomposable(self):
|
|
3645
|
+
r"""
|
|
3646
|
+
Return ``True`` if element is decomposable, ``False`` otherwise.
|
|
3647
|
+
|
|
3648
|
+
That is, if element is in the square of the augmentation ideal,
|
|
3649
|
+
return ``True``; otherwise, return ``False``.
|
|
3650
|
+
|
|
3651
|
+
OUTPUT: boolean
|
|
3652
|
+
|
|
3653
|
+
EXAMPLES::
|
|
3654
|
+
|
|
3655
|
+
sage: a = Sq(6)
|
|
3656
|
+
sage: a.is_decomposable()
|
|
3657
|
+
True
|
|
3658
|
+
sage: for i in range(9):
|
|
3659
|
+
....: if not Sq(i).is_decomposable():
|
|
3660
|
+
....: print(Sq(i))
|
|
3661
|
+
1
|
|
3662
|
+
Sq(1)
|
|
3663
|
+
Sq(2)
|
|
3664
|
+
Sq(4)
|
|
3665
|
+
Sq(8)
|
|
3666
|
+
sage: A3 = SteenrodAlgebra(p=3, basis='adem')
|
|
3667
|
+
sage: [A3.P(n) for n in range(30) if not A3.P(n).is_decomposable()]
|
|
3668
|
+
[1, P^1, P^3, P^9, P^27]
|
|
3669
|
+
|
|
3670
|
+
TESTS:
|
|
3671
|
+
|
|
3672
|
+
These all test changing bases and printing in various bases::
|
|
3673
|
+
|
|
3674
|
+
sage: A = SteenrodAlgebra(basis='milnor')
|
|
3675
|
+
sage: [A.Sq(n) for n in range(9) if not A.Sq(n).is_decomposable()]
|
|
3676
|
+
[1, Sq(1), Sq(2), Sq(4), Sq(8)]
|
|
3677
|
+
sage: A = SteenrodAlgebra(basis='wall_long')
|
|
3678
|
+
sage: [A.Sq(n) for n in range(9) if not A.Sq(n).is_decomposable()]
|
|
3679
|
+
[1, Sq^1, Sq^2, Sq^4, Sq^8]
|
|
3680
|
+
sage: A = SteenrodAlgebra(basis='arnona_long')
|
|
3681
|
+
sage: [A.Sq(n) for n in range(9) if not A.Sq(n).is_decomposable()]
|
|
3682
|
+
[1, Sq^1, Sq^2, Sq^4, Sq^8]
|
|
3683
|
+
sage: A = SteenrodAlgebra(basis='woodz')
|
|
3684
|
+
sage: [A.Sq(n) for n in range(20) if not A.Sq(n).is_decomposable()] # long time
|
|
3685
|
+
[1, Sq^1, Sq^2, Sq^4, Sq^8, Sq^16]
|
|
3686
|
+
sage: A = SteenrodAlgebra(basis='comm_long')
|
|
3687
|
+
sage: [A.Sq(n) for n in range(25) if not A.Sq(n).is_decomposable()] # long time
|
|
3688
|
+
[1, s_1, s_2, s_4, s_8, s_16]
|
|
3689
|
+
"""
|
|
3690
|
+
return self.may_weight() > 1
|
|
3691
|
+
|
|
3692
|
+
def wall_height(self):
|
|
3693
|
+
r"""
|
|
3694
|
+
Wall's 'height' of element.
|
|
3695
|
+
|
|
3696
|
+
OUTPUT: list of nonnegative integers
|
|
3697
|
+
|
|
3698
|
+
The height of an element of the mod 2 Steenrod algebra is a
|
|
3699
|
+
list of nonnegative integers, defined as follows: if the
|
|
3700
|
+
element is a monomial in the generators `\text{Sq}(2^i)`, then
|
|
3701
|
+
the `i`-th entry in the list is the number of times
|
|
3702
|
+
`\text{Sq}(2^i)` appears. For an arbitrary element, write it
|
|
3703
|
+
as a sum of such monomials; then its height is the maximum,
|
|
3704
|
+
ordered right-lexicographically, of the heights of those
|
|
3705
|
+
monomials.
|
|
3706
|
+
|
|
3707
|
+
When `p` is odd, the height of an element is not defined.
|
|
3708
|
+
|
|
3709
|
+
According to Theorem 3 in [Wal1960]_, the height of the Milnor
|
|
3710
|
+
basis element `\text{Sq}(r_1, r_2, ...)` is obtained as
|
|
3711
|
+
follows: write each `r_i` in binary as `r_i = \sum_j 2^j
|
|
3712
|
+
r_{ij}`. Then each nonzero binary digit `r_{ij}` contributes 1
|
|
3713
|
+
to the `k`-th entry in the height, for `j \leq k \leq
|
|
3714
|
+
i+j-1`.
|
|
3715
|
+
|
|
3716
|
+
EXAMPLES::
|
|
3717
|
+
|
|
3718
|
+
sage: Sq(0).wall_height()
|
|
3719
|
+
[]
|
|
3720
|
+
sage: a = Sq(4)
|
|
3721
|
+
sage: a.wall_height()
|
|
3722
|
+
[0, 0, 1]
|
|
3723
|
+
sage: b = Sq(4)*Sq(8) + Sq(8)*Sq(4)
|
|
3724
|
+
sage: b.wall_height()
|
|
3725
|
+
[0, 0, 1, 1]
|
|
3726
|
+
sage: Sq(0,0,3).wall_height()
|
|
3727
|
+
[1, 2, 2, 1]
|
|
3728
|
+
"""
|
|
3729
|
+
from sage.rings.integer import Integer
|
|
3730
|
+
if self.parent()._generic:
|
|
3731
|
+
raise NotImplementedError("Wall height is not defined at odd primes")
|
|
3732
|
+
if self == 0 or self == 1:
|
|
3733
|
+
return []
|
|
3734
|
+
result = []
|
|
3735
|
+
deg = self.parent().degree_on_basis
|
|
3736
|
+
for r in self.milnor().support():
|
|
3737
|
+
h = [0]*(1 + deg(r))
|
|
3738
|
+
i = 1
|
|
3739
|
+
for x in r:
|
|
3740
|
+
if x > 0:
|
|
3741
|
+
for j in range(1+Integer(x).exact_log(2)):
|
|
3742
|
+
if (2**j & x) != 0:
|
|
3743
|
+
for k in range(j, i+j):
|
|
3744
|
+
h[k] += 1
|
|
3745
|
+
i += 1
|
|
3746
|
+
h.reverse()
|
|
3747
|
+
result = max(h, result)
|
|
3748
|
+
result.reverse()
|
|
3749
|
+
while result and result[-1] == 0:
|
|
3750
|
+
result = result[:-1]
|
|
3751
|
+
return result
|
|
3752
|
+
|
|
3753
|
+
def additive_order(self):
|
|
3754
|
+
"""
|
|
3755
|
+
The additive order of any nonzero element of the mod p
|
|
3756
|
+
Steenrod algebra is p.
|
|
3757
|
+
|
|
3758
|
+
OUTPUT: 1 (for the zero element) or p (for anything else)
|
|
3759
|
+
|
|
3760
|
+
EXAMPLES::
|
|
3761
|
+
|
|
3762
|
+
sage: z = Sq(4) + Sq(6) + 1
|
|
3763
|
+
sage: z.additive_order()
|
|
3764
|
+
2
|
|
3765
|
+
sage: (Sq(3) + Sq(3)).additive_order()
|
|
3766
|
+
1
|
|
3767
|
+
"""
|
|
3768
|
+
if self == 0:
|
|
3769
|
+
return 1
|
|
3770
|
+
return self.prime()
|
|
3771
|
+
|
|
3772
|
+
|
|
3773
|
+
class SteenrodAlgebra_mod_two(SteenrodAlgebra_generic):
|
|
3774
|
+
"""
|
|
3775
|
+
The mod 2 Steenrod algebra.
|
|
3776
|
+
|
|
3777
|
+
Users should not call this, but use the function
|
|
3778
|
+
:func:`SteenrodAlgebra` instead. See that function for extensive
|
|
3779
|
+
documentation. (This differs from :class:`SteenrodAlgebra_generic`
|
|
3780
|
+
only in that it has a method :meth:`Sq` for defining elements.)
|
|
3781
|
+
"""
|
|
3782
|
+
def Sq(self, *nums):
|
|
3783
|
+
r"""
|
|
3784
|
+
Milnor element `\text{Sq}(a,b,c,...)`.
|
|
3785
|
+
|
|
3786
|
+
INPUT:
|
|
3787
|
+
|
|
3788
|
+
- ``a``, ``b``, ``c``, ... -- nonnegative integers
|
|
3789
|
+
|
|
3790
|
+
OUTPUT: element of the Steenrod algebra
|
|
3791
|
+
|
|
3792
|
+
This returns the Milnor basis element
|
|
3793
|
+
`\text{Sq}(a, b, c, ...)`.
|
|
3794
|
+
|
|
3795
|
+
EXAMPLES::
|
|
3796
|
+
|
|
3797
|
+
sage: A = SteenrodAlgebra(2)
|
|
3798
|
+
sage: A.Sq(5)
|
|
3799
|
+
Sq(5)
|
|
3800
|
+
sage: A.Sq(5,0,2)
|
|
3801
|
+
Sq(5,0,2)
|
|
3802
|
+
|
|
3803
|
+
Entries must be nonnegative integers; otherwise, an error
|
|
3804
|
+
results.
|
|
3805
|
+
"""
|
|
3806
|
+
if self.prime() == 2:
|
|
3807
|
+
return self.P(*nums)
|
|
3808
|
+
else:
|
|
3809
|
+
raise ValueError("Sq is only defined at the prime 2")
|
|
3810
|
+
|
|
3811
|
+
|
|
3812
|
+
def SteenrodAlgebra(p=2, basis='milnor', generic='auto', **kwds):
|
|
3813
|
+
r"""
|
|
3814
|
+
The mod `p` Steenrod algebra.
|
|
3815
|
+
|
|
3816
|
+
INPUT:
|
|
3817
|
+
|
|
3818
|
+
- ``p`` -- positive prime integer (default: 2)
|
|
3819
|
+
- ``basis`` -- string (default: ``'milnor'``)
|
|
3820
|
+
- ``profile`` -- a profile function in form specified below (default: ``None``)
|
|
3821
|
+
- ``truncation_type`` -- 0 or `\infty` or 'auto' (default: ``'auto'``)
|
|
3822
|
+
- ``precision`` -- integer or ``None`` (default: ``None``)
|
|
3823
|
+
- ``generic`` -- (default: ``'auto'``)
|
|
3824
|
+
|
|
3825
|
+
OUTPUT:
|
|
3826
|
+
|
|
3827
|
+
mod `p` Steenrod algebra or one of its sub-Hopf algebras,
|
|
3828
|
+
elements of which are printed using ``basis``
|
|
3829
|
+
|
|
3830
|
+
See below for information about ``basis``, ``profile``, etc.
|
|
3831
|
+
|
|
3832
|
+
EXAMPLES:
|
|
3833
|
+
|
|
3834
|
+
Some properties of the Steenrod algebra are available::
|
|
3835
|
+
|
|
3836
|
+
sage: A = SteenrodAlgebra(2)
|
|
3837
|
+
sage: A.order()
|
|
3838
|
+
+Infinity
|
|
3839
|
+
sage: A.is_finite()
|
|
3840
|
+
False
|
|
3841
|
+
sage: A.is_commutative()
|
|
3842
|
+
False
|
|
3843
|
+
sage: A.is_noetherian()
|
|
3844
|
+
False
|
|
3845
|
+
sage: A.is_integral_domain()
|
|
3846
|
+
False
|
|
3847
|
+
sage: A.is_field()
|
|
3848
|
+
False
|
|
3849
|
+
sage: A.is_division_algebra()
|
|
3850
|
+
False
|
|
3851
|
+
sage: A.category()
|
|
3852
|
+
Category of supercocommutative super Hopf algebras
|
|
3853
|
+
with basis over Finite Field of size 2
|
|
3854
|
+
|
|
3855
|
+
There are methods for constructing elements of the Steenrod
|
|
3856
|
+
algebra::
|
|
3857
|
+
|
|
3858
|
+
sage: A2 = SteenrodAlgebra(2); A2
|
|
3859
|
+
mod 2 Steenrod algebra, milnor basis
|
|
3860
|
+
sage: A2.Sq(1,2,6)
|
|
3861
|
+
Sq(1,2,6)
|
|
3862
|
+
sage: A2.Q(3,4) # product of Milnor primitives Q_3 and Q_4
|
|
3863
|
+
Sq(0,0,0,1,1)
|
|
3864
|
+
sage: A2.pst(2,3) # Margolis pst element
|
|
3865
|
+
Sq(0,0,4)
|
|
3866
|
+
sage: A5 = SteenrodAlgebra(5); A5
|
|
3867
|
+
mod 5 Steenrod algebra, milnor basis
|
|
3868
|
+
sage: A5.P(1,2,6)
|
|
3869
|
+
P(1,2,6)
|
|
3870
|
+
sage: A5.Q(3,4)
|
|
3871
|
+
Q_3 Q_4
|
|
3872
|
+
sage: A5.Q(3,4) * A5.P(1,2,6)
|
|
3873
|
+
Q_3 Q_4 P(1,2,6)
|
|
3874
|
+
sage: A5.pst(2,3)
|
|
3875
|
+
P(0,0,25)
|
|
3876
|
+
|
|
3877
|
+
You can test whether elements are contained in the Steenrod
|
|
3878
|
+
algebra::
|
|
3879
|
+
|
|
3880
|
+
sage: w = Sq(2) * Sq(4)
|
|
3881
|
+
sage: w in SteenrodAlgebra(2)
|
|
3882
|
+
True
|
|
3883
|
+
sage: w in SteenrodAlgebra(17)
|
|
3884
|
+
False
|
|
3885
|
+
|
|
3886
|
+
.. rubric:: Different bases for the Steenrod algebra:
|
|
3887
|
+
|
|
3888
|
+
There are two standard vector space bases for the mod `p` Steenrod
|
|
3889
|
+
algebra: the Milnor basis and the Serre-Cartan basis. When `p=2`,
|
|
3890
|
+
there are also several other, less well-known, bases. See the
|
|
3891
|
+
documentation for this module (type
|
|
3892
|
+
``sage.algebras.steenrod.steenrod_algebra?``) and the function
|
|
3893
|
+
:func:`steenrod_algebra_basis
|
|
3894
|
+
<sage.algebras.steenrod.steenrod_algebra_bases.steenrod_algebra_basis_>`
|
|
3895
|
+
for full descriptions of each of the implemented bases.
|
|
3896
|
+
|
|
3897
|
+
This module implements the following bases at all primes:
|
|
3898
|
+
|
|
3899
|
+
- 'milnor': Milnor basis.
|
|
3900
|
+
|
|
3901
|
+
- 'serre-cartan' or 'adem' or 'admissible': Serre-Cartan basis.
|
|
3902
|
+
|
|
3903
|
+
- 'pst', 'pst_rlex', 'pst_llex', 'pst_deg', 'pst_revz': various
|
|
3904
|
+
`P^s_t`-bases.
|
|
3905
|
+
|
|
3906
|
+
- 'comm', 'comm_rlex', 'comm_llex', 'comm_deg', 'comm_revz', or
|
|
3907
|
+
these with '_long' appended: various commutator bases.
|
|
3908
|
+
|
|
3909
|
+
It implements the following bases when `p=2`:
|
|
3910
|
+
|
|
3911
|
+
- 'wood_y': Wood's Y basis.
|
|
3912
|
+
|
|
3913
|
+
- 'wood_z': Wood's Z basis.
|
|
3914
|
+
|
|
3915
|
+
- 'wall', 'wall_long': Wall's basis.
|
|
3916
|
+
|
|
3917
|
+
- 'arnon_a', 'arnon_a_long': Arnon's A basis.
|
|
3918
|
+
|
|
3919
|
+
- 'arnon_c': Arnon's C basis.
|
|
3920
|
+
|
|
3921
|
+
When defining a Steenrod algebra, you can specify a basis. Then
|
|
3922
|
+
elements of that Steenrod algebra are printed in that basis::
|
|
3923
|
+
|
|
3924
|
+
sage: adem = SteenrodAlgebra(2, 'adem')
|
|
3925
|
+
sage: x = adem.Sq(2,1) # Sq(-) always means a Milnor basis element
|
|
3926
|
+
sage: x
|
|
3927
|
+
Sq^4 Sq^1 + Sq^5
|
|
3928
|
+
sage: y = Sq(0,1) # unadorned Sq defines elements w.r.t. Milnor basis
|
|
3929
|
+
sage: y
|
|
3930
|
+
Sq(0,1)
|
|
3931
|
+
sage: adem(y)
|
|
3932
|
+
Sq^2 Sq^1 + Sq^3
|
|
3933
|
+
sage: adem5 = SteenrodAlgebra(5, 'serre-cartan')
|
|
3934
|
+
sage: adem5.P(0,2)
|
|
3935
|
+
P^10 P^2 + 4 P^11 P^1 + P^12
|
|
3936
|
+
|
|
3937
|
+
If you add or multiply elements defined using different bases, the
|
|
3938
|
+
left-hand factor determines the form of the output::
|
|
3939
|
+
|
|
3940
|
+
sage: SteenrodAlgebra(basis='adem').Sq(3) + SteenrodAlgebra(basis='pst').Sq(0,1)
|
|
3941
|
+
Sq^2 Sq^1
|
|
3942
|
+
sage: SteenrodAlgebra(basis='pst').Sq(3) + SteenrodAlgebra(basis='milnor').Sq(0,1)
|
|
3943
|
+
P^0_1 P^1_1 + P^0_2
|
|
3944
|
+
sage: SteenrodAlgebra(basis='milnor').Sq(2) * SteenrodAlgebra(basis='arnonc').Sq(2)
|
|
3945
|
+
Sq(1,1)
|
|
3946
|
+
|
|
3947
|
+
You can get a list of basis elements in a given dimension::
|
|
3948
|
+
|
|
3949
|
+
sage: A3 = SteenrodAlgebra(3, 'milnor')
|
|
3950
|
+
sage: A3.basis(13)
|
|
3951
|
+
Family (Q_1 P(2), Q_0 P(3))
|
|
3952
|
+
|
|
3953
|
+
Algebras defined over different bases are not equal::
|
|
3954
|
+
|
|
3955
|
+
sage: SteenrodAlgebra(basis='milnor') == SteenrodAlgebra(basis='pst')
|
|
3956
|
+
False
|
|
3957
|
+
|
|
3958
|
+
Bases have various synonyms, and in general Sage tries to figure
|
|
3959
|
+
out what basis you meant::
|
|
3960
|
+
|
|
3961
|
+
sage: SteenrodAlgebra(basis='MiLNOr')
|
|
3962
|
+
mod 2 Steenrod algebra, milnor basis
|
|
3963
|
+
sage: SteenrodAlgebra(basis='MiLNOr') == SteenrodAlgebra(basis='milnor')
|
|
3964
|
+
True
|
|
3965
|
+
sage: SteenrodAlgebra(basis='adem')
|
|
3966
|
+
mod 2 Steenrod algebra, serre-cartan basis
|
|
3967
|
+
sage: SteenrodAlgebra(basis='adem').basis_name()
|
|
3968
|
+
'serre-cartan'
|
|
3969
|
+
sage: SteenrodAlgebra(basis='wood---z---').basis_name()
|
|
3970
|
+
'woodz'
|
|
3971
|
+
|
|
3972
|
+
As noted above, several of the bases ('arnon_a', 'wall', 'comm')
|
|
3973
|
+
have alternate, sometimes longer, representations. These provide
|
|
3974
|
+
ways of expressing elements of the Steenrod algebra in terms of
|
|
3975
|
+
the `\text{Sq}^{2^n}`.
|
|
3976
|
+
|
|
3977
|
+
::
|
|
3978
|
+
|
|
3979
|
+
sage: A_long = SteenrodAlgebra(2, 'arnon_a_long')
|
|
3980
|
+
sage: A_long(Sq(6))
|
|
3981
|
+
Sq^1 Sq^2 Sq^1 Sq^2 + Sq^2 Sq^4
|
|
3982
|
+
sage: SteenrodAlgebra(2, 'wall_long')(Sq(6))
|
|
3983
|
+
Sq^2 Sq^1 Sq^2 Sq^1 + Sq^2 Sq^4
|
|
3984
|
+
sage: SteenrodAlgebra(2, 'comm_deg_long')(Sq(6))
|
|
3985
|
+
s_1 s_2 s_12 + s_2 s_4
|
|
3986
|
+
|
|
3987
|
+
.. rubric:: Sub-Hopf algebras of the Steenrod algebra:
|
|
3988
|
+
|
|
3989
|
+
These are specified using the argument ``profile``, along with,
|
|
3990
|
+
optionally, ``truncation_type`` and ``precision``. The
|
|
3991
|
+
``profile`` argument specifies the profile function for this
|
|
3992
|
+
algebra. Any sub-Hopf algebra of the Steenrod algebra is
|
|
3993
|
+
determined by its *profile function*. When `p=2`, this is a map `e`
|
|
3994
|
+
from the positive integers to the set of nonnegative integers,
|
|
3995
|
+
plus `\infty`, corresponding to the sub-Hopf algebra dual to this
|
|
3996
|
+
quotient of the dual Steenrod algebra:
|
|
3997
|
+
|
|
3998
|
+
.. MATH::
|
|
3999
|
+
|
|
4000
|
+
\GF{2} [\xi_1, \xi_2, \xi_3, ...] / (\xi_1^{2^{e(1)}}, \xi_2^{2^{e(2)}}, \xi_3^{2^{e(3)}}, ...).
|
|
4001
|
+
|
|
4002
|
+
The profile function `e` must satisfy the condition
|
|
4003
|
+
|
|
4004
|
+
- `e(r) \geq \min( e(r-i) - i, e(i))` for all `0 < i < r`.
|
|
4005
|
+
|
|
4006
|
+
This is specified via ``profile``, and optionally ``precision``
|
|
4007
|
+
and ``truncation_type``. First, ``profile`` must have one of the
|
|
4008
|
+
following forms:
|
|
4009
|
+
|
|
4010
|
+
- a list or tuple, e.g., ``[3,2,1]``, corresponding to the
|
|
4011
|
+
function sending 1 to 3, 2 to 2, 3 to 1, and all other integers
|
|
4012
|
+
to the value of ``truncation_type``.
|
|
4013
|
+
- a function from positive integers to nonnegative integers (and
|
|
4014
|
+
`\infty`), e.g., ``lambda n: n+2``.
|
|
4015
|
+
- ``None`` or ``Infinity`` -- use this for the profile function for
|
|
4016
|
+
the whole Steenrod algebra
|
|
4017
|
+
|
|
4018
|
+
In the first and third cases, ``precision`` is ignored. In the
|
|
4019
|
+
second case, this function is converted to a tuple of length one
|
|
4020
|
+
less than ``precision``, which has default value 100. The
|
|
4021
|
+
function is truncated at this point, and all remaining values are
|
|
4022
|
+
set to the value of ``truncation_type``.
|
|
4023
|
+
|
|
4024
|
+
``truncation_type`` may be 0, `\infty`, or 'auto'. If it's
|
|
4025
|
+
'auto', then it gets converted to 0 in the first case above (when
|
|
4026
|
+
``profile`` is a list), and otherwise (when ``profile`` is a
|
|
4027
|
+
function, ``None``, or ``Infinity``) it gets converted to `\infty`.
|
|
4028
|
+
|
|
4029
|
+
For example, the sub-Hopf algebra `A(2)` has profile function
|
|
4030
|
+
``[3,2,1,0,0,0,...]``, so it can be defined by any of the
|
|
4031
|
+
following::
|
|
4032
|
+
|
|
4033
|
+
sage: A2 = SteenrodAlgebra(profile=[3,2,1])
|
|
4034
|
+
sage: B2 = SteenrodAlgebra(profile=[3,2,1,0,0]) # trailing 0s ignored
|
|
4035
|
+
sage: A2 == B2
|
|
4036
|
+
True
|
|
4037
|
+
sage: C2 = SteenrodAlgebra(profile=lambda n: max(4-n, 0), truncation_type=0)
|
|
4038
|
+
sage: A2 == C2
|
|
4039
|
+
True
|
|
4040
|
+
|
|
4041
|
+
In the following case, the profile function is specified by a
|
|
4042
|
+
function and ``truncation_type`` isn't specified, so it defaults
|
|
4043
|
+
to `\infty`; therefore this gives a different sub-Hopf algebra::
|
|
4044
|
+
|
|
4045
|
+
sage: D2 = SteenrodAlgebra(profile=lambda n: max(4-n, 0))
|
|
4046
|
+
sage: A2 == D2
|
|
4047
|
+
False
|
|
4048
|
+
sage: D2.is_finite()
|
|
4049
|
+
False
|
|
4050
|
+
sage: E2 = SteenrodAlgebra(profile=lambda n: max(4-n, 0), truncation_type=Infinity)
|
|
4051
|
+
sage: D2 == E2
|
|
4052
|
+
True
|
|
4053
|
+
|
|
4054
|
+
The argument ``precision`` only needs to be specified if the
|
|
4055
|
+
profile function is defined by a function and you want to control
|
|
4056
|
+
when the profile switches from the given function to the
|
|
4057
|
+
truncation type. For example::
|
|
4058
|
+
|
|
4059
|
+
sage: D3 = SteenrodAlgebra(profile=lambda n: n, precision=3)
|
|
4060
|
+
sage: D3
|
|
4061
|
+
sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [1, 2, +Infinity, +Infinity, +Infinity, ...]
|
|
4062
|
+
sage: D4 = SteenrodAlgebra(profile=lambda n: n, precision=4); D4
|
|
4063
|
+
sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [1, 2, 3, +Infinity, +Infinity, +Infinity, ...]
|
|
4064
|
+
sage: D3 == D4
|
|
4065
|
+
False
|
|
4066
|
+
|
|
4067
|
+
When `p` is odd, ``profile`` is a pair of functions `e` and `k`,
|
|
4068
|
+
corresponding to the quotient
|
|
4069
|
+
|
|
4070
|
+
.. MATH::
|
|
4071
|
+
|
|
4072
|
+
\GF{p} [\xi_1, \xi_2, \xi_3, ...] \otimes \Lambda (\tau_0,
|
|
4073
|
+
\tau_1, ...) / (\xi_1^{p^{e_1}}, \xi_2^{p^{e_2}}, ...;
|
|
4074
|
+
\tau_0^{k_0}, \tau_1^{k_1}, ...).
|
|
4075
|
+
|
|
4076
|
+
Together, the functions `e` and `k` must satisfy the conditions
|
|
4077
|
+
|
|
4078
|
+
- `e(r) \geq \min( e(r-i) - i, e(i))` for all `0 < i < r`,
|
|
4079
|
+
|
|
4080
|
+
- if `k(i+j) = 1`, then either `e(i) \leq j` or `k(j) = 1` for all `i
|
|
4081
|
+
\geq 1`, `j \geq 0`.
|
|
4082
|
+
|
|
4083
|
+
Therefore ``profile`` must have one of the following forms:
|
|
4084
|
+
|
|
4085
|
+
- a pair of lists or tuples, the second of which takes values in
|
|
4086
|
+
the set `\{1,2\}`, e.g., ``([3,2,1,1], [1,1,2,2,1])``.
|
|
4087
|
+
|
|
4088
|
+
- a pair of functions, one from the positive integers to
|
|
4089
|
+
nonnegative integers (and `\infty`), one from the nonnegative
|
|
4090
|
+
integers to the set `\{1,2\}`, e.g., ``(lambda n: n+2, lambda n:
|
|
4091
|
+
1 if n<3 else 2)``.
|
|
4092
|
+
|
|
4093
|
+
- ``None`` or ``Infinity`` -- use this for the profile function for
|
|
4094
|
+
the whole Steenrod algebra
|
|
4095
|
+
|
|
4096
|
+
You can also mix and match the first two, passing a pair with
|
|
4097
|
+
first entry a list and second entry a function, for instance. The
|
|
4098
|
+
values of ``precision`` and ``truncation_type`` are determined by
|
|
4099
|
+
the first entry.
|
|
4100
|
+
|
|
4101
|
+
More examples::
|
|
4102
|
+
|
|
4103
|
+
sage: E = SteenrodAlgebra(profile=lambda n: 0 if n<3 else 3, truncation_type=0)
|
|
4104
|
+
sage: E.is_commutative()
|
|
4105
|
+
True
|
|
4106
|
+
|
|
4107
|
+
sage: A2 = SteenrodAlgebra(profile=[3,2,1]) # the algebra A(2)
|
|
4108
|
+
sage: Sq(7,3,1) in A2
|
|
4109
|
+
True
|
|
4110
|
+
sage: Sq(8) in A2
|
|
4111
|
+
False
|
|
4112
|
+
sage: Sq(8) in SteenrodAlgebra().basis(8)
|
|
4113
|
+
True
|
|
4114
|
+
sage: Sq(8) in A2.basis(8)
|
|
4115
|
+
False
|
|
4116
|
+
sage: A2.basis(8)
|
|
4117
|
+
Family (Sq(1,0,1), Sq(2,2), Sq(5,1))
|
|
4118
|
+
|
|
4119
|
+
sage: A5 = SteenrodAlgebra(p=5)
|
|
4120
|
+
sage: A51 = SteenrodAlgebra(p=5, profile=([1], [2,2]))
|
|
4121
|
+
sage: A5.Q(0,1) * A5.P(4) in A51
|
|
4122
|
+
True
|
|
4123
|
+
sage: A5.Q(2) in A51
|
|
4124
|
+
False
|
|
4125
|
+
sage: A5.P(5) in A51
|
|
4126
|
+
False
|
|
4127
|
+
|
|
4128
|
+
For sub-Hopf algebras of the Steenrod algebra, only the Milnor
|
|
4129
|
+
basis or the various `P^s_t`-bases may be used. ::
|
|
4130
|
+
|
|
4131
|
+
sage: SteenrodAlgebra(profile=[1,2,1,1], basis='adem')
|
|
4132
|
+
Traceback (most recent call last):
|
|
4133
|
+
...
|
|
4134
|
+
NotImplementedError: for sub-Hopf algebras of the Steenrod algebra, only the Milnor basis and the pst bases are implemented
|
|
4135
|
+
|
|
4136
|
+
.. rubric:: The generic Steenrod algebra at the prime `2`:
|
|
4137
|
+
|
|
4138
|
+
The structure formulas for the Steenrod algebra at odd primes `p` also make sense
|
|
4139
|
+
when `p` is set to `2`. We refer to the resulting algebra as the "generic Steenrod algebra" for
|
|
4140
|
+
the prime `2`. The dual Hopf algebra is given by
|
|
4141
|
+
|
|
4142
|
+
.. MATH::
|
|
4143
|
+
|
|
4144
|
+
A_* = \GF{2} [\xi_1, \xi_2, \xi_3, ...] \otimes \Lambda (\tau_0, \tau_1, ...)
|
|
4145
|
+
|
|
4146
|
+
The degree of `\xi_k` is `2^{k+1}-2` and the degree of `\tau_k` is `2^{k+1}-1`.
|
|
4147
|
+
|
|
4148
|
+
The generic Steenrod algebra is an associated graded algebra of the usual Steenrod algebra
|
|
4149
|
+
that is occasionally useful. Its cohomology, for example, is the `E_2`-term of a spectral sequence
|
|
4150
|
+
that computes the `E_2`-term of the Novikov spectral sequence. It can also be obtained as a
|
|
4151
|
+
specialisation of Voevodsky's "motivic Steenrod algebra": in the notation of [Voe2003]_, Remark 12.12,
|
|
4152
|
+
it corresponds to setting `\rho = \tau = 0`. The usual Steenrod algebra is given by `\rho = 0`
|
|
4153
|
+
and `\tau = 1`.
|
|
4154
|
+
|
|
4155
|
+
In Sage this algebra is constructed using the 'generic' keyword.
|
|
4156
|
+
|
|
4157
|
+
Example::
|
|
4158
|
+
|
|
4159
|
+
sage: EA = SteenrodAlgebra(p=2,generic=True) ; EA
|
|
4160
|
+
generic mod 2 Steenrod algebra, milnor basis
|
|
4161
|
+
sage: EA[8]
|
|
4162
|
+
Vector space spanned by (Q_0 Q_2, Q_0 Q_1 P(2), P(1,1), P(4))
|
|
4163
|
+
over Finite Field of size 2
|
|
4164
|
+
|
|
4165
|
+
TESTS:
|
|
4166
|
+
|
|
4167
|
+
Testing unique parents::
|
|
4168
|
+
|
|
4169
|
+
sage: S0 = SteenrodAlgebra(2)
|
|
4170
|
+
sage: S1 = SteenrodAlgebra(2)
|
|
4171
|
+
sage: S0 is S1
|
|
4172
|
+
True
|
|
4173
|
+
sage: S2 = SteenrodAlgebra(2, basis='adem')
|
|
4174
|
+
sage: S0 is S2
|
|
4175
|
+
False
|
|
4176
|
+
sage: S0 == S2
|
|
4177
|
+
False
|
|
4178
|
+
sage: A1 = SteenrodAlgebra(profile=[2,1])
|
|
4179
|
+
sage: B1 = SteenrodAlgebra(profile=[2,1,0,0])
|
|
4180
|
+
sage: A1 is B1
|
|
4181
|
+
True
|
|
4182
|
+
"""
|
|
4183
|
+
if generic == 'auto':
|
|
4184
|
+
generic = p != 2
|
|
4185
|
+
if not generic:
|
|
4186
|
+
return SteenrodAlgebra_mod_two(p=2, basis=basis, **kwds)
|
|
4187
|
+
else:
|
|
4188
|
+
return SteenrodAlgebra_generic(p=p, basis=basis, generic=True, **kwds)
|
|
4189
|
+
|
|
4190
|
+
|
|
4191
|
+
def AA(n=None, p=2):
|
|
4192
|
+
r"""
|
|
4193
|
+
This returns the Steenrod algebra `A` or its sub-Hopf algebra `A(n)`.
|
|
4194
|
+
|
|
4195
|
+
INPUT:
|
|
4196
|
+
|
|
4197
|
+
- ``n`` -- nonnegative integer (default: ``None``)
|
|
4198
|
+
- ``p`` -- prime number (default: 2)
|
|
4199
|
+
|
|
4200
|
+
OUTPUT:
|
|
4201
|
+
|
|
4202
|
+
If `n` is ``None``, then return the full Steenrod algebra.
|
|
4203
|
+
Otherwise, return `A(n)`.
|
|
4204
|
+
|
|
4205
|
+
When `p=2`, `A(n)` is the sub-Hopf algebra generated by the
|
|
4206
|
+
elements `\text{Sq}^i` for `i \leq 2^n`. Its profile function is
|
|
4207
|
+
`(n+1, n, n-1, ...)`. When `p` is odd, `A(n)` is the sub-Hopf
|
|
4208
|
+
algebra generated by the elements `Q_0` and `\mathcal{P}^i` for `i
|
|
4209
|
+
\leq p^{n-1}`. Its profile function is `e=(n, n-1, n-2, ...)`
|
|
4210
|
+
and `k=(2, 2, ..., 2)` (length `n+1`).
|
|
4211
|
+
|
|
4212
|
+
EXAMPLES::
|
|
4213
|
+
|
|
4214
|
+
sage: from sage.algebras.steenrod.steenrod_algebra import AA as A
|
|
4215
|
+
sage: A()
|
|
4216
|
+
mod 2 Steenrod algebra, milnor basis
|
|
4217
|
+
sage: A(2)
|
|
4218
|
+
sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis,
|
|
4219
|
+
profile function [3, 2, 1]
|
|
4220
|
+
sage: A(2, p=5)
|
|
4221
|
+
sub-Hopf algebra of mod 5 Steenrod algebra, milnor basis,
|
|
4222
|
+
profile function ([2, 1], [2, 2, 2])
|
|
4223
|
+
"""
|
|
4224
|
+
if n is None:
|
|
4225
|
+
return SteenrodAlgebra(p=p)
|
|
4226
|
+
if p == 2:
|
|
4227
|
+
return SteenrodAlgebra(p=p, profile=list(range(n + 1, 0, -1)))
|
|
4228
|
+
return SteenrodAlgebra(p=p, profile=(list(range(n, 0, -1)), [2]*(n+1)))
|
|
4229
|
+
|
|
4230
|
+
|
|
4231
|
+
def Sq(*nums):
|
|
4232
|
+
r"""
|
|
4233
|
+
Milnor element Sq(a,b,c,...).
|
|
4234
|
+
|
|
4235
|
+
INPUT:
|
|
4236
|
+
|
|
4237
|
+
- ``a``, ``b``, ``c``, ... -- nonnegative integers
|
|
4238
|
+
|
|
4239
|
+
OUTPUT: element of the Steenrod algebra
|
|
4240
|
+
|
|
4241
|
+
This returns the Milnor basis element `\text{Sq}(a, b, c, ...)`.
|
|
4242
|
+
|
|
4243
|
+
EXAMPLES::
|
|
4244
|
+
|
|
4245
|
+
sage: Sq(5)
|
|
4246
|
+
Sq(5)
|
|
4247
|
+
sage: Sq(5) + Sq(2,1) + Sq(5) # addition is mod 2:
|
|
4248
|
+
Sq(2,1)
|
|
4249
|
+
sage: (Sq(4,3) + Sq(7,2)).degree()
|
|
4250
|
+
13
|
|
4251
|
+
|
|
4252
|
+
Entries must be nonnegative integers; otherwise, an error
|
|
4253
|
+
results.
|
|
4254
|
+
|
|
4255
|
+
This function is a good way to define elements of the Steenrod
|
|
4256
|
+
algebra.
|
|
4257
|
+
"""
|
|
4258
|
+
return SteenrodAlgebra(p=2).Sq(*nums)
|