passagemath-modules 10.6.31rc3__cp314-cp314-musllinux_1_2_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +808 -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-0cd532bd.so.1 +0 -0
- passagemath_modules.libs/libgfortran-2c33b284.so.5.0.0 +0 -0
- passagemath_modules.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
- passagemath_modules.libs/libgsl-42cda06f.so.28.0.0 +0 -0
- passagemath_modules.libs/libmpc-d8ebe4b5.so.3.3.1 +0 -0
- passagemath_modules.libs/libmpfr-aaecbfc0.so.6.2.1 +0 -0
- passagemath_modules.libs/libopenblasp-r0-905cb27d.3.29.so +0 -0
- passagemath_modules.libs/libquadmath-bb76a5fc.so.0.0.0 +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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-linux-musl.so +0 -0
- sage/calculus/integration.pyx +698 -0
- sage/calculus/interpolation.cpython-314-x86_64-linux-musl.so +0 -0
- sage/calculus/interpolation.pxd +13 -0
- sage/calculus/interpolation.pyx +387 -0
- sage/calculus/interpolators.cpython-314-x86_64-linux-musl.so +0 -0
- sage/calculus/interpolators.pyx +326 -0
- sage/calculus/ode.cpython-314-x86_64-linux-musl.so +0 -0
- sage/calculus/ode.pxd +5 -0
- sage/calculus/ode.pyx +610 -0
- sage/calculus/riemann.cpython-314-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-linux-musl.so +0 -0
- sage/libs/mpmath/utils.pxd +4 -0
- sage/libs/mpmath/utils.pyx +319 -0
- sage/matrix/action.cpython-314-x86_64-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-x86_64-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-x86_64-linux-musl.so +0 -0
- sage/matrix/constructor.pyx +750 -0
- sage/matrix/docs.py +430 -0
- sage/matrix/echelon_matrix.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/echelon_matrix.pyx +155 -0
- sage/matrix/matrix.pxd +2 -0
- sage/matrix/matrix0.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix0.pxd +68 -0
- sage/matrix/matrix0.pyx +6324 -0
- sage/matrix/matrix1.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix1.pxd +8 -0
- sage/matrix/matrix1.pyx +2851 -0
- sage/matrix/matrix2.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix2.pxd +25 -0
- sage/matrix/matrix2.pyx +20181 -0
- sage/matrix/matrix_cdv.cpython-314-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-linux-musl.so +0 -0
- sage/matroids/extension.pxd +34 -0
- sage/matroids/extension.pyx +519 -0
- sage/matroids/flats_matroid.cpython-314-x86_64-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-x86_64-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-x86_64-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-x86_64-linux-musl.so +0 -0
- sage/matroids/linear_matroid.pxd +180 -0
- sage/matroids/linear_matroid.pyx +6649 -0
- sage/matroids/matroid.cpython-314-x86_64-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-x86_64-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-x86_64-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-x86_64-linux-musl.so +0 -0
- sage/matroids/union_matroid.pxd +20 -0
- sage/matroids/union_matroid.pyx +331 -0
- sage/matroids/unpickling.cpython-314-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-linux-musl.so +0 -0
- sage/rings/function_field/hermite_form_polynomial.pyx +188 -0
- sage/rings/function_field/khuri_makdisi.cpython-314-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-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-x86_64-linux-musl.so +0 -0
- sage/stats/hmm/chmm.pyx +1595 -0
- sage/stats/hmm/distributions.cpython-314-x86_64-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-x86_64-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-x86_64-linux-musl.so +0 -0
- sage/stats/hmm/util.pxd +7 -0
- sage/stats/hmm/util.pyx +165 -0
- sage/stats/intlist.cpython-314-x86_64-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-x86_64-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,3107 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-modules
|
|
2
|
+
# sage.doctest: needs sage.modules
|
|
3
|
+
r"""
|
|
4
|
+
Clifford Algebras
|
|
5
|
+
|
|
6
|
+
AUTHORS:
|
|
7
|
+
|
|
8
|
+
- Travis Scrimshaw (2013-09-06): Initial version
|
|
9
|
+
- Trevor K. Karn (2022-07-27): Rewrite basis indexing using FrozenBitset
|
|
10
|
+
"""
|
|
11
|
+
# ****************************************************************************
|
|
12
|
+
# Copyright (C) 2013-2022 Travis Scrimshaw <tcscrims at gmail.com>
|
|
13
|
+
# (C) 2022 Trevor Karn <karnx018 at umn.edu>
|
|
14
|
+
#
|
|
15
|
+
# This program is free software: you can redistribute it and/or modify
|
|
16
|
+
# it under the terms of the GNU General Public License as published by
|
|
17
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
18
|
+
# (at your option) any later version.
|
|
19
|
+
# https://www.gnu.org/licenses/
|
|
20
|
+
# ****************************************************************************
|
|
21
|
+
from sage.misc.cachefunc import cached_method
|
|
22
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
|
23
|
+
from sage.structure.parent import Parent
|
|
24
|
+
from sage.structure.element import Element
|
|
25
|
+
from sage.structure.richcmp import (richcmp_method, op_EQ, op_NE,
|
|
26
|
+
op_LT, op_GT, op_LE, op_GE, rich_to_bool)
|
|
27
|
+
from sage.data_structures.bitset import Bitset, FrozenBitset
|
|
28
|
+
|
|
29
|
+
from sage.algebras.clifford_algebra_element import CliffordAlgebraElement, ExteriorAlgebraElement
|
|
30
|
+
from sage.categories.algebras_with_basis import AlgebrasWithBasis
|
|
31
|
+
from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis
|
|
32
|
+
from sage.categories.fields import Fields
|
|
33
|
+
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
|
|
34
|
+
from sage.modules.with_basis.morphism import ModuleMorphismByLinearity
|
|
35
|
+
from sage.categories.poor_man_map import PoorManMap
|
|
36
|
+
from sage.rings.integer_ring import ZZ
|
|
37
|
+
from sage.rings.noncommutative_ideals import Ideal_nc
|
|
38
|
+
from sage.modules.free_module import FreeModule, FreeModule_generic
|
|
39
|
+
from sage.matrix.constructor import Matrix
|
|
40
|
+
from sage.matrix.args import MatrixArgs
|
|
41
|
+
from sage.sets.family import Family
|
|
42
|
+
from sage.combinat.free_module import CombinatorialFreeModule
|
|
43
|
+
from sage.quadratic_forms.quadratic_form import QuadraticForm
|
|
44
|
+
from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass
|
|
45
|
+
from sage.typeset.ascii_art import ascii_art
|
|
46
|
+
from sage.typeset.unicode_art import unicode_art
|
|
47
|
+
import unicodedata
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class CliffordAlgebraIndices(UniqueRepresentation, Parent):
|
|
51
|
+
r"""
|
|
52
|
+
A facade parent for the indices of Clifford algebra.
|
|
53
|
+
Users should not create instances of this class directly.
|
|
54
|
+
"""
|
|
55
|
+
def __init__(self, Qdim, degree=None):
|
|
56
|
+
r"""
|
|
57
|
+
Initialize ``self``.
|
|
58
|
+
|
|
59
|
+
EXAMPLES::
|
|
60
|
+
|
|
61
|
+
sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices
|
|
62
|
+
sage: idx = CliffordAlgebraIndices(7)
|
|
63
|
+
sage: idx._nbits
|
|
64
|
+
7
|
|
65
|
+
sage: idx._cardinality
|
|
66
|
+
128
|
|
67
|
+
sage: i = idx.an_element(); i
|
|
68
|
+
1111
|
|
69
|
+
sage: type(i)
|
|
70
|
+
<class 'sage.data_structures.bitset.FrozenBitset'>
|
|
71
|
+
|
|
72
|
+
sage: idx = CliffordAlgebraIndices(7, 3)
|
|
73
|
+
sage: idx._nbits
|
|
74
|
+
7
|
|
75
|
+
sage: idx._degree
|
|
76
|
+
3
|
|
77
|
+
sage: idx._cardinality
|
|
78
|
+
35
|
|
79
|
+
|
|
80
|
+
sage: idx = CliffordAlgebraIndices(7, 0)
|
|
81
|
+
sage: idx._nbits
|
|
82
|
+
7
|
|
83
|
+
sage: idx._degree
|
|
84
|
+
0
|
|
85
|
+
sage: idx._cardinality
|
|
86
|
+
1
|
|
87
|
+
"""
|
|
88
|
+
self._nbits = Qdim
|
|
89
|
+
if degree is None:
|
|
90
|
+
self._cardinality = 2 ** Qdim
|
|
91
|
+
else:
|
|
92
|
+
from sage.arith.misc import binomial
|
|
93
|
+
self._cardinality = binomial(Qdim, degree)
|
|
94
|
+
self._degree = degree
|
|
95
|
+
# the if statement here is in case Qdim is 0.
|
|
96
|
+
category = FiniteEnumeratedSets().Facade()
|
|
97
|
+
Parent.__init__(self, category=category, facade=True)
|
|
98
|
+
|
|
99
|
+
def _element_constructor_(self, x):
|
|
100
|
+
r"""
|
|
101
|
+
Construct an element of ``self``.
|
|
102
|
+
|
|
103
|
+
EXAMPLES::
|
|
104
|
+
|
|
105
|
+
sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices
|
|
106
|
+
sage: idx = CliffordAlgebraIndices(7)
|
|
107
|
+
sage: idx([1,3,6])
|
|
108
|
+
0101001
|
|
109
|
+
sage: for i in range(7): print(idx(i))
|
|
110
|
+
1
|
|
111
|
+
01
|
|
112
|
+
001
|
|
113
|
+
0001
|
|
114
|
+
00001
|
|
115
|
+
000001
|
|
116
|
+
0000001
|
|
117
|
+
|
|
118
|
+
sage: idx = CliffordAlgebraIndices(0)
|
|
119
|
+
sage: idx([])
|
|
120
|
+
0
|
|
121
|
+
"""
|
|
122
|
+
if isinstance(x, (list, tuple, set, frozenset)):
|
|
123
|
+
if len(x) > self._nbits:
|
|
124
|
+
raise ValueError(f"{x=} is too long")
|
|
125
|
+
if not x:
|
|
126
|
+
return FrozenBitset()
|
|
127
|
+
return FrozenBitset(x)
|
|
128
|
+
|
|
129
|
+
if isinstance(x, int):
|
|
130
|
+
return FrozenBitset((x,))
|
|
131
|
+
|
|
132
|
+
def __call__(self, el):
|
|
133
|
+
r"""
|
|
134
|
+
EXAMPLES::
|
|
135
|
+
|
|
136
|
+
sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices
|
|
137
|
+
sage: idx = CliffordAlgebraIndices(7)
|
|
138
|
+
sage: idx([1,3,6])
|
|
139
|
+
0101001
|
|
140
|
+
sage: E = ExteriorAlgebra(QQ, 7)
|
|
141
|
+
sage: B = E.basis()
|
|
142
|
+
"""
|
|
143
|
+
if not isinstance(el, Element):
|
|
144
|
+
return self._element_constructor_(el)
|
|
145
|
+
else:
|
|
146
|
+
return Parent.__call__(self, el)
|
|
147
|
+
|
|
148
|
+
def cardinality(self):
|
|
149
|
+
r"""
|
|
150
|
+
Return the cardinality of ``self``.
|
|
151
|
+
|
|
152
|
+
EXAMPLES::
|
|
153
|
+
|
|
154
|
+
sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices
|
|
155
|
+
sage: idx = CliffordAlgebraIndices(7)
|
|
156
|
+
sage: idx.cardinality() == 2^7
|
|
157
|
+
True
|
|
158
|
+
sage: len(idx) == 2^7
|
|
159
|
+
True
|
|
160
|
+
|
|
161
|
+
sage: idx = CliffordAlgebraIndices(7, 3)
|
|
162
|
+
sage: idx.cardinality() == binomial(7, 3)
|
|
163
|
+
True
|
|
164
|
+
sage: len(idx) == binomial(7, 3)
|
|
165
|
+
True
|
|
166
|
+
"""
|
|
167
|
+
return self._cardinality
|
|
168
|
+
|
|
169
|
+
__len__ = cardinality
|
|
170
|
+
|
|
171
|
+
def _repr_(self):
|
|
172
|
+
r"""
|
|
173
|
+
Return a string representation of ``self``.
|
|
174
|
+
|
|
175
|
+
EXAMPLES::
|
|
176
|
+
|
|
177
|
+
sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices
|
|
178
|
+
sage: CliffordAlgebraIndices(7)
|
|
179
|
+
Subsets of {0,1,...,6}
|
|
180
|
+
sage: CliffordAlgebraIndices(0)
|
|
181
|
+
Subsets of {}
|
|
182
|
+
sage: CliffordAlgebraIndices(1)
|
|
183
|
+
Subsets of {0}
|
|
184
|
+
sage: CliffordAlgebraIndices(2)
|
|
185
|
+
Subsets of {0,1}
|
|
186
|
+
sage: CliffordAlgebraIndices(5, 3)
|
|
187
|
+
Subsets of {0,1,...,4} of size 3
|
|
188
|
+
"""
|
|
189
|
+
if self._degree is not None:
|
|
190
|
+
extra = f" of size {self._degree}"
|
|
191
|
+
else:
|
|
192
|
+
extra = ""
|
|
193
|
+
if self._nbits == 0:
|
|
194
|
+
return "Subsets of {}" + extra
|
|
195
|
+
if self._nbits == 1:
|
|
196
|
+
return "Subsets of {0}" + extra
|
|
197
|
+
if self._nbits == 2:
|
|
198
|
+
return "Subsets of {0,1}" + extra
|
|
199
|
+
return f"Subsets of {{0,1,...,{self._nbits-1}}}" + extra
|
|
200
|
+
|
|
201
|
+
def _latex_(self):
|
|
202
|
+
r"""
|
|
203
|
+
Return a latex representation of ``self``.
|
|
204
|
+
|
|
205
|
+
EXAMPLES::
|
|
206
|
+
|
|
207
|
+
sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices
|
|
208
|
+
sage: latex(CliffordAlgebraIndices(7))
|
|
209
|
+
\mathcal{P}(\{0,1,\ldots,6\})
|
|
210
|
+
sage: latex(CliffordAlgebraIndices(0))
|
|
211
|
+
\mathcal{P}(\emptyset)
|
|
212
|
+
sage: latex(CliffordAlgebraIndices(1))
|
|
213
|
+
\mathcal{P}(\{0\})
|
|
214
|
+
sage: latex(CliffordAlgebraIndices(2))
|
|
215
|
+
\mathcal{P}(\{0,1\})
|
|
216
|
+
sage: latex(CliffordAlgebraIndices(2, 1))
|
|
217
|
+
\mathcal{P}(\{0,1\}, 1)
|
|
218
|
+
"""
|
|
219
|
+
if self._degree is not None:
|
|
220
|
+
extra = f", {self._degree}"
|
|
221
|
+
else:
|
|
222
|
+
extra = ""
|
|
223
|
+
if self._nbits == 0:
|
|
224
|
+
return f"\\mathcal{{P}}(\\emptyset{extra})"
|
|
225
|
+
if self._nbits == 1:
|
|
226
|
+
return f"\\mathcal{{P}}(\\{{0\\}}{extra})"
|
|
227
|
+
if self._nbits == 2:
|
|
228
|
+
return f"\\mathcal{{P}}(\\{{0,1\\}}{extra})"
|
|
229
|
+
return f"\\mathcal{{P}}(\\{{0,1,\\ldots,{self._nbits-1}\\}}{extra})"
|
|
230
|
+
|
|
231
|
+
def __iter__(self):
|
|
232
|
+
r"""
|
|
233
|
+
Iterate over ``self``.
|
|
234
|
+
|
|
235
|
+
EXAMPLES::
|
|
236
|
+
|
|
237
|
+
sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices
|
|
238
|
+
sage: idx = CliffordAlgebraIndices(3)
|
|
239
|
+
sage: for i in idx:
|
|
240
|
+
....: print(i)
|
|
241
|
+
0
|
|
242
|
+
1
|
|
243
|
+
01
|
|
244
|
+
001
|
|
245
|
+
11
|
|
246
|
+
101
|
|
247
|
+
011
|
|
248
|
+
111
|
|
249
|
+
|
|
250
|
+
sage: idx = CliffordAlgebraIndices(5, 3)
|
|
251
|
+
sage: list(idx)
|
|
252
|
+
[111, 1101, 11001, 1011, 10101, 10011, 0111, 01101, 01011, 00111]
|
|
253
|
+
|
|
254
|
+
sage: idx = CliffordAlgebraIndices(7, 0)
|
|
255
|
+
sage: list(idx)
|
|
256
|
+
[0]
|
|
257
|
+
"""
|
|
258
|
+
import itertools
|
|
259
|
+
n = self._nbits
|
|
260
|
+
if self._degree is not None:
|
|
261
|
+
if self._degree == 0: # special corner case
|
|
262
|
+
yield FrozenBitset()
|
|
263
|
+
return
|
|
264
|
+
for C in itertools.combinations(range(n), self._degree):
|
|
265
|
+
yield FrozenBitset(C)
|
|
266
|
+
return
|
|
267
|
+
|
|
268
|
+
yield FrozenBitset()
|
|
269
|
+
k = 1
|
|
270
|
+
while k <= n:
|
|
271
|
+
for C in itertools.combinations(range(n), k):
|
|
272
|
+
yield FrozenBitset(C)
|
|
273
|
+
k += 1
|
|
274
|
+
|
|
275
|
+
def __contains__(self, elt):
|
|
276
|
+
r"""
|
|
277
|
+
Check containment of ``elt`` in ``self``.
|
|
278
|
+
|
|
279
|
+
EXAMPLES::
|
|
280
|
+
|
|
281
|
+
sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices
|
|
282
|
+
sage: idx = CliffordAlgebraIndices(3)
|
|
283
|
+
sage: int(8) in idx # representing the set {4}
|
|
284
|
+
False
|
|
285
|
+
sage: int(5) in idx # representing the set {1,3}
|
|
286
|
+
True
|
|
287
|
+
sage: FrozenBitset('1') in idx
|
|
288
|
+
True
|
|
289
|
+
sage: FrozenBitset('000001') in idx
|
|
290
|
+
False
|
|
291
|
+
|
|
292
|
+
sage: idx = CliffordAlgebraIndices(6, 3)
|
|
293
|
+
sage: FrozenBitset('01011') in idx
|
|
294
|
+
True
|
|
295
|
+
sage: FrozenBitset('00011') in idx
|
|
296
|
+
False
|
|
297
|
+
sage: int(7) in idx
|
|
298
|
+
True
|
|
299
|
+
sage: int(8) in idx
|
|
300
|
+
False
|
|
301
|
+
|
|
302
|
+
sage: idx = CliffordAlgebraIndices(7, 0)
|
|
303
|
+
sage: FrozenBitset() in idx
|
|
304
|
+
True
|
|
305
|
+
sage: FrozenBitset('01') in idx
|
|
306
|
+
False
|
|
307
|
+
sage: int(0) in idx
|
|
308
|
+
True
|
|
309
|
+
sage: int(5) in idx
|
|
310
|
+
False
|
|
311
|
+
"""
|
|
312
|
+
if isinstance(elt, int):
|
|
313
|
+
if self._degree is not None and sum(ZZ(elt).bits()) != self._degree:
|
|
314
|
+
return False
|
|
315
|
+
return elt < self._cardinality and elt >= 0
|
|
316
|
+
if not isinstance(elt, FrozenBitset):
|
|
317
|
+
return False
|
|
318
|
+
if self._degree is not None and len(elt) != self._degree:
|
|
319
|
+
return False
|
|
320
|
+
return elt.capacity() <= self._nbits
|
|
321
|
+
|
|
322
|
+
def _an_element_(self):
|
|
323
|
+
r"""
|
|
324
|
+
Return an element of ``self``.
|
|
325
|
+
|
|
326
|
+
EXAMPLES::
|
|
327
|
+
|
|
328
|
+
sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices
|
|
329
|
+
sage: idx = CliffordAlgebraIndices(0)
|
|
330
|
+
sage: idx._an_element_()
|
|
331
|
+
0
|
|
332
|
+
sage: idx = CliffordAlgebraIndices(1)
|
|
333
|
+
sage: idx._an_element_()
|
|
334
|
+
1
|
|
335
|
+
sage: idx = CliffordAlgebraIndices(2)
|
|
336
|
+
sage: idx._an_element_()
|
|
337
|
+
01
|
|
338
|
+
sage: idx = CliffordAlgebraIndices(3)
|
|
339
|
+
sage: idx._an_element_()
|
|
340
|
+
11
|
|
341
|
+
sage: idx = CliffordAlgebraIndices(5, 3)
|
|
342
|
+
sage: idx._an_element_()
|
|
343
|
+
111
|
|
344
|
+
sage: idx = CliffordAlgebraIndices(7, 0)
|
|
345
|
+
sage: idx._an_element_()
|
|
346
|
+
0
|
|
347
|
+
"""
|
|
348
|
+
if not self._nbits:
|
|
349
|
+
return FrozenBitset()
|
|
350
|
+
|
|
351
|
+
if self._degree is not None:
|
|
352
|
+
if self._degree == 0: # special corner case
|
|
353
|
+
return FrozenBitset()
|
|
354
|
+
return FrozenBitset(range(self._degree))
|
|
355
|
+
|
|
356
|
+
from sage.combinat.subset import SubsetsSorted
|
|
357
|
+
X = SubsetsSorted(range(self._nbits))
|
|
358
|
+
return FrozenBitset(X.an_element())
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
class CliffordAlgebra(CombinatorialFreeModule):
|
|
362
|
+
r"""
|
|
363
|
+
The Clifford algebra of a quadratic form.
|
|
364
|
+
|
|
365
|
+
Let `Q : V \to \mathbf{k}` denote a quadratic form on a vector space `V`
|
|
366
|
+
over a field `\mathbf{k}`. The Clifford algebra `Cl(V, Q)` is defined as
|
|
367
|
+
`T(V) / I_Q` where `T(V)` is the tensor algebra of `V` and `I_Q` is the
|
|
368
|
+
two-sided ideal generated by all elements of the form `v \otimes v - Q(v)`
|
|
369
|
+
for all `v \in V`.
|
|
370
|
+
|
|
371
|
+
We abuse notation to denote the projection of a pure tensor
|
|
372
|
+
`x_1 \otimes x_2 \otimes \cdots \otimes x_m \in T(V)` onto
|
|
373
|
+
`T(V) / I_Q = Cl(V, Q)` by `x_1 \wedge x_2 \wedge \cdots \wedge x_m`.
|
|
374
|
+
This is motivated by the fact that `Cl(V, Q)` is the exterior algebra
|
|
375
|
+
`\wedge V` when `Q = 0` (one can also think of a Clifford algebra as
|
|
376
|
+
a quantization of the exterior algebra). See :class:`ExteriorAlgebra`
|
|
377
|
+
for the concept of an exterior algebra.
|
|
378
|
+
|
|
379
|
+
From the definition, a basis of `Cl(V, Q)` is given by monomials of
|
|
380
|
+
the form
|
|
381
|
+
|
|
382
|
+
.. MATH::
|
|
383
|
+
|
|
384
|
+
\{ e_{i_1} \wedge \cdots \wedge e_{i_k} \mid 1 \leq i_1 < \cdots <
|
|
385
|
+
i_k \leq n \},
|
|
386
|
+
|
|
387
|
+
where `n = \dim(V)` and where `\{ e_1, e_2, \cdots, e_n \}` is any
|
|
388
|
+
fixed basis of `V`. Hence
|
|
389
|
+
|
|
390
|
+
.. MATH::
|
|
391
|
+
|
|
392
|
+
\dim(Cl(V, Q)) = \sum_{k=0}^n \binom{n}{k} = 2^n.
|
|
393
|
+
|
|
394
|
+
.. NOTE::
|
|
395
|
+
|
|
396
|
+
The algebra `Cl(V, Q)` is a `\ZZ / 2\ZZ`-graded algebra, but not
|
|
397
|
+
(in general) `\ZZ`-graded (in a reasonable way).
|
|
398
|
+
|
|
399
|
+
This construction satisfies the following universal property. Let
|
|
400
|
+
`i : V \to Cl(V, Q)` denote the natural inclusion (which is an
|
|
401
|
+
embedding). Then for every associative `\mathbf{k}`-algebra `A`
|
|
402
|
+
and any `\mathbf{k}`-linear map `j : V \to A` satisfying
|
|
403
|
+
|
|
404
|
+
.. MATH::
|
|
405
|
+
|
|
406
|
+
j(v)^2 = Q(v) \cdot 1_A
|
|
407
|
+
|
|
408
|
+
for all `v \in V`, there exists a unique `\mathbf{k}`-algebra
|
|
409
|
+
homomorphism `f : Cl(V, Q) \to A` such that `f \circ i = j`.
|
|
410
|
+
This property determines the Clifford algebra uniquely up to
|
|
411
|
+
canonical isomorphism. The inclusion `i` is commonly used to
|
|
412
|
+
identify `V` with a vector subspace of `Cl(V)`.
|
|
413
|
+
|
|
414
|
+
The Clifford algebra `Cl(V, Q)` is a `\ZZ_2`-graded algebra
|
|
415
|
+
(where `\ZZ_2 = \ZZ / 2 \ZZ`); this grading is determined by
|
|
416
|
+
placing all elements of `V` in degree `1`. It is also an
|
|
417
|
+
`\NN`-filtered algebra, with the filtration too being defined
|
|
418
|
+
by placing all elements of `V` in degree `1`. The :meth:`degree` gives
|
|
419
|
+
the `\NN`-*filtration* degree, and to get the super degree use instead
|
|
420
|
+
:meth:`~sage.categories.super_modules.SuperModules.ElementMethods.is_even_odd`.
|
|
421
|
+
|
|
422
|
+
The Clifford algebra also can be considered as a covariant functor
|
|
423
|
+
from the category of vector spaces equipped with quadratic forms
|
|
424
|
+
to the category of algebras. In fact, if `(V, Q)` and `(W, R)`
|
|
425
|
+
are two vector spaces endowed with quadratic forms, and if
|
|
426
|
+
`g : W \to V` is a linear map preserving the quadratic form,
|
|
427
|
+
then we can define an algebra morphism
|
|
428
|
+
`Cl(g) : Cl(W, R) \to Cl(V, Q)` by requiring that it send every
|
|
429
|
+
`w \in W` to `g(w) \in V`. Since the quadratic form `R` on `W`
|
|
430
|
+
is uniquely determined by the quadratic form `Q` on `V` (due to
|
|
431
|
+
the assumption that `g` preserves the quadratic form), this fact
|
|
432
|
+
can be rewritten as follows: If `(V, Q)` is a vector space with a
|
|
433
|
+
quadratic form, and `W` is another vector space, and
|
|
434
|
+
`\phi : W \to V` is any linear map, then we obtain an algebra
|
|
435
|
+
morphism `Cl(\phi) : Cl(W, \phi(Q)) \to Cl(V, Q)` where
|
|
436
|
+
`\phi(Q) = \phi^T \cdot Q \cdot \phi` (we consider `\phi` as a
|
|
437
|
+
matrix) is the quadratic form `Q` pulled back to `W`. In fact, the
|
|
438
|
+
map `\phi` preserves the quadratic form because of
|
|
439
|
+
|
|
440
|
+
.. MATH::
|
|
441
|
+
|
|
442
|
+
\phi(Q)(x) = x^T \cdot \phi^T \cdot Q \cdot \phi \cdot x
|
|
443
|
+
= (\phi \cdot x)^T \cdot Q \cdot (\phi \cdot x) = Q(\phi(x)).
|
|
444
|
+
|
|
445
|
+
Hence we have `\phi(w)^2 = Q(\phi(w)) = \phi(Q)(w)` for all `w \in W`.
|
|
446
|
+
|
|
447
|
+
REFERENCES:
|
|
448
|
+
|
|
449
|
+
- :wikipedia:`Clifford_algebra`
|
|
450
|
+
|
|
451
|
+
INPUT:
|
|
452
|
+
|
|
453
|
+
- ``Q`` -- a quadratic form
|
|
454
|
+
- ``names`` -- (default: ``'e'``) the generator names
|
|
455
|
+
|
|
456
|
+
EXAMPLES:
|
|
457
|
+
|
|
458
|
+
To create a Clifford algebra, all one needs to do is specify a
|
|
459
|
+
quadratic form::
|
|
460
|
+
|
|
461
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
462
|
+
sage: Cl = CliffordAlgebra(Q)
|
|
463
|
+
sage: Cl
|
|
464
|
+
The Clifford algebra of the Quadratic form in 3 variables
|
|
465
|
+
over Integer Ring with coefficients:
|
|
466
|
+
[ 1 2 3 ]
|
|
467
|
+
[ * 4 5 ]
|
|
468
|
+
[ * * 6 ]
|
|
469
|
+
|
|
470
|
+
We can also explicitly name the generators. In this example, the
|
|
471
|
+
Clifford algebra we construct is an exterior algebra (since we
|
|
472
|
+
choose the quadratic form to be zero)::
|
|
473
|
+
|
|
474
|
+
sage: Q = QuadraticForm(ZZ, 4, [0]*10)
|
|
475
|
+
sage: Cl.<a,b,c,d> = CliffordAlgebra(Q)
|
|
476
|
+
sage: a*d
|
|
477
|
+
a*d
|
|
478
|
+
sage: d*c*b*a + a + 4*b*c
|
|
479
|
+
a*b*c*d + 4*b*c + a
|
|
480
|
+
"""
|
|
481
|
+
@staticmethod
|
|
482
|
+
def __classcall_private__(cls, Q, names=None):
|
|
483
|
+
"""
|
|
484
|
+
Normalize arguments to ensure a unique representation.
|
|
485
|
+
|
|
486
|
+
EXAMPLES::
|
|
487
|
+
|
|
488
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
489
|
+
sage: Cl1.<e0,e1,e2> = CliffordAlgebra(Q)
|
|
490
|
+
sage: Cl2 = CliffordAlgebra(Q)
|
|
491
|
+
sage: Cl3 = CliffordAlgebra(Q, ['e0','e1','e2'])
|
|
492
|
+
sage: Cl1 is Cl2 and Cl2 is Cl3
|
|
493
|
+
True
|
|
494
|
+
"""
|
|
495
|
+
if not isinstance(Q, QuadraticForm):
|
|
496
|
+
raise ValueError("{} is not a quadratic form".format(Q))
|
|
497
|
+
if names is None:
|
|
498
|
+
names = 'e'
|
|
499
|
+
names = tuple(names)
|
|
500
|
+
if len(names) != Q.dim():
|
|
501
|
+
if len(names) == 1:
|
|
502
|
+
names = tuple('{}{}'.format(names[0], i) for i in range(Q.dim()))
|
|
503
|
+
else:
|
|
504
|
+
raise ValueError("the number of variables does not match the number of generators")
|
|
505
|
+
return super().__classcall__(cls, Q, names)
|
|
506
|
+
|
|
507
|
+
def __init__(self, Q, names, category=None):
|
|
508
|
+
r"""
|
|
509
|
+
Initialize ``self``.
|
|
510
|
+
|
|
511
|
+
EXAMPLES::
|
|
512
|
+
|
|
513
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
514
|
+
sage: Cl = CliffordAlgebra(Q)
|
|
515
|
+
sage: Cl.category()
|
|
516
|
+
Category of finite dimensional super algebras with basis over
|
|
517
|
+
(Dedekind domains and euclidean domains
|
|
518
|
+
and noetherian rings
|
|
519
|
+
and infinite enumerated sets and metric spaces)
|
|
520
|
+
sage: TestSuite(Cl).run()
|
|
521
|
+
|
|
522
|
+
TESTS:
|
|
523
|
+
|
|
524
|
+
We check that the basis elements are indeed indexed by
|
|
525
|
+
*strictly increasing* tuples::
|
|
526
|
+
|
|
527
|
+
sage: Q = QuadraticForm(ZZ, 9)
|
|
528
|
+
sage: Cl = CliffordAlgebra(Q)
|
|
529
|
+
sage: ba = Cl.basis().keys()
|
|
530
|
+
sage: all(FrozenBitset(format(i,'b')[::-1]) in ba for i in range(2**9))
|
|
531
|
+
True
|
|
532
|
+
"""
|
|
533
|
+
self._quadratic_form = Q
|
|
534
|
+
R = Q.base_ring()
|
|
535
|
+
category = AlgebrasWithBasis(R.category()).Super().Filtered().FiniteDimensional().or_subcategory(category)
|
|
536
|
+
indices = CliffordAlgebraIndices(Q.dim())
|
|
537
|
+
CombinatorialFreeModule.__init__(self, R, indices, category=category, sorting_key=tuple)
|
|
538
|
+
self._assign_names(names)
|
|
539
|
+
|
|
540
|
+
def _repr_(self):
|
|
541
|
+
r"""
|
|
542
|
+
Return a string representation of ``self``.
|
|
543
|
+
|
|
544
|
+
EXAMPLES::
|
|
545
|
+
|
|
546
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
547
|
+
sage: CliffordAlgebra(Q)
|
|
548
|
+
The Clifford algebra of the Quadratic form in 3 variables
|
|
549
|
+
over Integer Ring with coefficients:
|
|
550
|
+
[ 1 2 3 ]
|
|
551
|
+
[ * 4 5 ]
|
|
552
|
+
[ * * 6 ]
|
|
553
|
+
"""
|
|
554
|
+
return "The Clifford algebra of the {}".format(self._quadratic_form)
|
|
555
|
+
|
|
556
|
+
def _repr_term(self, m):
|
|
557
|
+
"""
|
|
558
|
+
Return a string representation of the basis element indexed by ``m``.
|
|
559
|
+
|
|
560
|
+
EXAMPLES::
|
|
561
|
+
|
|
562
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
563
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
564
|
+
sage: Cl._repr_term((0,2))
|
|
565
|
+
'x*z'
|
|
566
|
+
sage: Cl._repr_term(FrozenBitset('101'))
|
|
567
|
+
'x*z'
|
|
568
|
+
sage: Cl._repr_term(())
|
|
569
|
+
'1'
|
|
570
|
+
sage: Cl._repr_term((1,))
|
|
571
|
+
'y'
|
|
572
|
+
"""
|
|
573
|
+
if not m:
|
|
574
|
+
return '1'
|
|
575
|
+
term = ''
|
|
576
|
+
for i in m:
|
|
577
|
+
if term:
|
|
578
|
+
term += '*'
|
|
579
|
+
term += self.variable_names()[i]
|
|
580
|
+
return term
|
|
581
|
+
|
|
582
|
+
def _latex_term(self, m):
|
|
583
|
+
r"""
|
|
584
|
+
Return a `\LaTeX` representation of the basis element indexed
|
|
585
|
+
by ``m``.
|
|
586
|
+
|
|
587
|
+
EXAMPLES::
|
|
588
|
+
|
|
589
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
590
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
591
|
+
sage: Cl._latex_term((0,2))
|
|
592
|
+
' x z'
|
|
593
|
+
"""
|
|
594
|
+
if not m:
|
|
595
|
+
return '1'
|
|
596
|
+
term = ''
|
|
597
|
+
for i in m:
|
|
598
|
+
term += ' ' + self.latex_variable_names()[i]
|
|
599
|
+
return term
|
|
600
|
+
|
|
601
|
+
def _coerce_map_from_(self, V):
|
|
602
|
+
"""
|
|
603
|
+
Return if there is a coerce map from ``V`` into ``self``.
|
|
604
|
+
|
|
605
|
+
The things which coerce into ``self`` are:
|
|
606
|
+
|
|
607
|
+
- Clifford algebras with the same generator names and an equal
|
|
608
|
+
quadratic form over a ring which coerces into the base
|
|
609
|
+
ring of ``self``.
|
|
610
|
+
- The underlying free module of ``self``.
|
|
611
|
+
- The base ring of ``self``.
|
|
612
|
+
|
|
613
|
+
EXAMPLES::
|
|
614
|
+
|
|
615
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
616
|
+
sage: Qp = QuadraticForm(QQ, 3, [1,2,3,4,5,6])
|
|
617
|
+
sage: Cl = CliffordAlgebra(Q)
|
|
618
|
+
sage: Clp = CliffordAlgebra(Qp)
|
|
619
|
+
sage: Cl.has_coerce_map_from(Clp)
|
|
620
|
+
False
|
|
621
|
+
sage: Clp.has_coerce_map_from(Cl)
|
|
622
|
+
True
|
|
623
|
+
|
|
624
|
+
Check that we preserve the multiplicative structure::
|
|
625
|
+
|
|
626
|
+
sage: all(Clp(b)*Clp(b) == Clp(b*b) for b in Cl.basis())
|
|
627
|
+
True
|
|
628
|
+
|
|
629
|
+
Check from the underlying free module::
|
|
630
|
+
|
|
631
|
+
sage: M = ZZ^3
|
|
632
|
+
sage: Mp = QQ^3
|
|
633
|
+
sage: Cl.has_coerce_map_from(M)
|
|
634
|
+
True
|
|
635
|
+
sage: Cl.has_coerce_map_from(Mp)
|
|
636
|
+
False
|
|
637
|
+
sage: Clp.has_coerce_map_from(M)
|
|
638
|
+
True
|
|
639
|
+
sage: Clp.has_coerce_map_from(Mp)
|
|
640
|
+
True
|
|
641
|
+
|
|
642
|
+
Names matter::
|
|
643
|
+
|
|
644
|
+
sage: Cln = CliffordAlgebra(Q, names=['x','y','z'])
|
|
645
|
+
sage: Cln.has_coerce_map_from(Cl)
|
|
646
|
+
False
|
|
647
|
+
sage: Cl.has_coerce_map_from(Cln)
|
|
648
|
+
False
|
|
649
|
+
|
|
650
|
+
Non-injective homomorphisms of base rings don't cause zero
|
|
651
|
+
values in the coordinate dictionary (this had to be manually
|
|
652
|
+
ensured)::
|
|
653
|
+
|
|
654
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
655
|
+
sage: Qp = QuadraticForm(Integers(3), 3, [1,2,3,4,5,6])
|
|
656
|
+
sage: Cl = CliffordAlgebra(Q)
|
|
657
|
+
sage: Clp = CliffordAlgebra(Qp)
|
|
658
|
+
sage: a = Cl.basis()[(1,2)]
|
|
659
|
+
sage: a
|
|
660
|
+
e1*e2
|
|
661
|
+
sage: Clp(a) # so far so good
|
|
662
|
+
e1*e2
|
|
663
|
+
sage: Clp(3*a) # but now
|
|
664
|
+
0
|
|
665
|
+
sage: Clp(3*a) == 0
|
|
666
|
+
True
|
|
667
|
+
sage: b = Cl.basis()[(0,2)]
|
|
668
|
+
sage: Clp(3*a-4*b)
|
|
669
|
+
2*e0*e2
|
|
670
|
+
"""
|
|
671
|
+
if isinstance(V, CliffordAlgebra):
|
|
672
|
+
Q = self._quadratic_form
|
|
673
|
+
try:
|
|
674
|
+
return (V.variable_names() == self.variable_names() and
|
|
675
|
+
V._quadratic_form.change_ring(self.base_ring()) == Q)
|
|
676
|
+
except (TypeError, AttributeError):
|
|
677
|
+
return False
|
|
678
|
+
|
|
679
|
+
if self.free_module().has_coerce_map_from(V):
|
|
680
|
+
return True
|
|
681
|
+
|
|
682
|
+
return super()._coerce_map_from_(V)
|
|
683
|
+
|
|
684
|
+
def _element_constructor_(self, x):
|
|
685
|
+
"""
|
|
686
|
+
Construct an element of ``self`` from ``x``.
|
|
687
|
+
|
|
688
|
+
EXAMPLES::
|
|
689
|
+
|
|
690
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
691
|
+
sage: Qp = QuadraticForm(QQ, 3, [1,2,3,4,5,6])
|
|
692
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
693
|
+
sage: Clp = CliffordAlgebra(Qp, names=['x','y','z'])
|
|
694
|
+
sage: M = ZZ^3
|
|
695
|
+
sage: Mp = QQ^3
|
|
696
|
+
sage: Cl(2/3)
|
|
697
|
+
Traceback (most recent call last):
|
|
698
|
+
...
|
|
699
|
+
TypeError: do not know how to make x=2/3 an element of self
|
|
700
|
+
sage: Clp(2/3)
|
|
701
|
+
2/3
|
|
702
|
+
sage: Clp(x)
|
|
703
|
+
x
|
|
704
|
+
sage: M = ZZ^3
|
|
705
|
+
sage: Clp( M((1,-3,2)) )
|
|
706
|
+
x - 3*y + 2*z
|
|
707
|
+
|
|
708
|
+
Zero coordinates are handled appropriately::
|
|
709
|
+
|
|
710
|
+
sage: Q3 = QuadraticForm(Integers(3), 3, [1,2,3,4,5,6])
|
|
711
|
+
sage: Cl3 = CliffordAlgebra(Q3, names='xyz') # different syntax for a change
|
|
712
|
+
sage: Cl3( M((1,-3,2)) )
|
|
713
|
+
x + 2*z
|
|
714
|
+
"""
|
|
715
|
+
# This is the natural lift morphism of the underlying free module
|
|
716
|
+
if x in self.free_module():
|
|
717
|
+
R = self.base_ring()
|
|
718
|
+
if x.parent().base_ring() is R:
|
|
719
|
+
return self.element_class(self, {FrozenBitset((i,)): c for i, c in x.items()})
|
|
720
|
+
# if the base ring is different, attempt to coerce it into R
|
|
721
|
+
return self.element_class(self, {FrozenBitset((i,)): R(c) for i, c in x.items() if R(c) != R.zero()})
|
|
722
|
+
|
|
723
|
+
if (isinstance(x, CliffordAlgebraElement)
|
|
724
|
+
and self.has_coerce_map_from(x.parent())):
|
|
725
|
+
R = self.base_ring()
|
|
726
|
+
return self.element_class(self, {i: R(c) for i, c in x if R(c) != R.zero()})
|
|
727
|
+
|
|
728
|
+
if isinstance(x, tuple):
|
|
729
|
+
R = self.base_ring()
|
|
730
|
+
return self.element_class(self, {FrozenBitset((i,)): R.one() for i in x})
|
|
731
|
+
|
|
732
|
+
try:
|
|
733
|
+
return super()._element_constructor_(x)
|
|
734
|
+
except TypeError:
|
|
735
|
+
raise TypeError(f'do not know how to make {x=} an element of self')
|
|
736
|
+
|
|
737
|
+
def _basis_index_function(self, x):
|
|
738
|
+
"""
|
|
739
|
+
Given an integer indexing the basis, return the correct
|
|
740
|
+
bitset.
|
|
741
|
+
|
|
742
|
+
For backwards compatibility, tuples are also accepted.
|
|
743
|
+
|
|
744
|
+
EXAMPLES::
|
|
745
|
+
|
|
746
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
747
|
+
sage: Cl = CliffordAlgebra(Q)
|
|
748
|
+
sage: Cl._basis_index_function(7)
|
|
749
|
+
111
|
|
750
|
+
sage: Cl._basis_index_function(5)
|
|
751
|
+
101
|
|
752
|
+
sage: Cl._basis_index_function(4)
|
|
753
|
+
001
|
|
754
|
+
|
|
755
|
+
sage: Cl._basis_index_function((0, 1, 2))
|
|
756
|
+
111
|
|
757
|
+
sage: Cl._basis_index_function((0, 2))
|
|
758
|
+
101
|
|
759
|
+
sage: Cl._basis_index_function((2,))
|
|
760
|
+
001
|
|
761
|
+
"""
|
|
762
|
+
Q = self._quadratic_form
|
|
763
|
+
format_style = f"0{Q.dim()}b"
|
|
764
|
+
|
|
765
|
+
# if the input is a tuple, assume that it has
|
|
766
|
+
# entries in {0, ..., 2**Q.dim()-1}
|
|
767
|
+
if isinstance(x, tuple):
|
|
768
|
+
return FrozenBitset(x, capacity=Q.dim())
|
|
769
|
+
|
|
770
|
+
# slice the output of format in order to make conventions
|
|
771
|
+
# of format and FrozenBitset agree.
|
|
772
|
+
return FrozenBitset(format(x, format_style)[::-1], capacity=Q.dim())
|
|
773
|
+
|
|
774
|
+
def gen(self, i):
|
|
775
|
+
"""
|
|
776
|
+
Return the ``i``-th standard generator of the algebra ``self``.
|
|
777
|
+
|
|
778
|
+
This is the ``i``-th basis vector of the vector space on which
|
|
779
|
+
the quadratic form defining ``self`` is defined, regarded as an
|
|
780
|
+
element of ``self``.
|
|
781
|
+
|
|
782
|
+
EXAMPLES::
|
|
783
|
+
|
|
784
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
785
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
786
|
+
sage: [Cl.gen(i) for i in range(3)]
|
|
787
|
+
[x, y, z]
|
|
788
|
+
"""
|
|
789
|
+
return self._from_dict({FrozenBitset((i,)): self.base_ring().one()}, remove_zeros=False)
|
|
790
|
+
|
|
791
|
+
def algebra_generators(self) -> Family:
|
|
792
|
+
"""
|
|
793
|
+
Return the algebra generators of ``self``.
|
|
794
|
+
|
|
795
|
+
EXAMPLES::
|
|
796
|
+
|
|
797
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
798
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
799
|
+
sage: Cl.algebra_generators()
|
|
800
|
+
Finite family {'x': x, 'y': y, 'z': z}
|
|
801
|
+
"""
|
|
802
|
+
d = {x: self.gen(i) for i, x in enumerate(self.variable_names())}
|
|
803
|
+
return Family(self.variable_names(), lambda x: d[x])
|
|
804
|
+
|
|
805
|
+
def gens(self) -> tuple:
|
|
806
|
+
r"""
|
|
807
|
+
Return the generators of ``self`` (as an algebra).
|
|
808
|
+
|
|
809
|
+
EXAMPLES::
|
|
810
|
+
|
|
811
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
812
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
813
|
+
sage: Cl.gens()
|
|
814
|
+
(x, y, z)
|
|
815
|
+
"""
|
|
816
|
+
return tuple(self.algebra_generators())
|
|
817
|
+
|
|
818
|
+
@cached_method
|
|
819
|
+
def ngens(self):
|
|
820
|
+
"""
|
|
821
|
+
Return the number of algebra generators of ``self``.
|
|
822
|
+
|
|
823
|
+
EXAMPLES::
|
|
824
|
+
|
|
825
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
826
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
827
|
+
sage: Cl.ngens()
|
|
828
|
+
3
|
|
829
|
+
"""
|
|
830
|
+
return self._quadratic_form.dim()
|
|
831
|
+
|
|
832
|
+
@cached_method
|
|
833
|
+
def one_basis(self):
|
|
834
|
+
"""
|
|
835
|
+
Return the basis index of the element ``1``. The element ``1``
|
|
836
|
+
is indexed by the emptyset, which is represented by the
|
|
837
|
+
:class:`sage.data_structures.bitset.Bitset` ``0``.
|
|
838
|
+
|
|
839
|
+
EXAMPLES::
|
|
840
|
+
|
|
841
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
842
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
843
|
+
sage: Cl.one_basis()
|
|
844
|
+
0
|
|
845
|
+
"""
|
|
846
|
+
return FrozenBitset()
|
|
847
|
+
|
|
848
|
+
def is_commutative(self) -> bool:
|
|
849
|
+
"""
|
|
850
|
+
Check if ``self`` is a commutative algebra.
|
|
851
|
+
|
|
852
|
+
EXAMPLES::
|
|
853
|
+
|
|
854
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
855
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
856
|
+
sage: Cl.is_commutative()
|
|
857
|
+
False
|
|
858
|
+
"""
|
|
859
|
+
return self._quadratic_form.dim() < 2
|
|
860
|
+
|
|
861
|
+
def quadratic_form(self):
|
|
862
|
+
"""
|
|
863
|
+
Return the quadratic form of ``self``.
|
|
864
|
+
|
|
865
|
+
This is the quadratic form used to define ``self``. The
|
|
866
|
+
quadratic form on ``self`` is yet to be implemented.
|
|
867
|
+
|
|
868
|
+
EXAMPLES::
|
|
869
|
+
|
|
870
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
871
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
872
|
+
sage: Cl.quadratic_form()
|
|
873
|
+
Quadratic form in 3 variables over Integer Ring with coefficients:
|
|
874
|
+
[ 1 2 3 ]
|
|
875
|
+
[ * 4 5 ]
|
|
876
|
+
[ * * 6 ]
|
|
877
|
+
"""
|
|
878
|
+
return self._quadratic_form
|
|
879
|
+
|
|
880
|
+
def degree_on_basis(self, m):
|
|
881
|
+
r"""
|
|
882
|
+
Return the degree of the monomial indexed by ``m``.
|
|
883
|
+
|
|
884
|
+
We are considering the Clifford algebra to be `\NN`-filtered,
|
|
885
|
+
and the degree of the monomial ``m`` is the length of ``m``.
|
|
886
|
+
|
|
887
|
+
EXAMPLES::
|
|
888
|
+
|
|
889
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
890
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
891
|
+
sage: Cl.degree_on_basis((0,))
|
|
892
|
+
1
|
|
893
|
+
sage: Cl.degree_on_basis((0,1))
|
|
894
|
+
2
|
|
895
|
+
"""
|
|
896
|
+
return ZZ(len(m))
|
|
897
|
+
|
|
898
|
+
def graded_algebra(self):
|
|
899
|
+
"""
|
|
900
|
+
Return the associated graded algebra of ``self``.
|
|
901
|
+
|
|
902
|
+
EXAMPLES::
|
|
903
|
+
|
|
904
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
905
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
906
|
+
sage: Cl.graded_algebra()
|
|
907
|
+
The exterior algebra of rank 3 over Integer Ring
|
|
908
|
+
"""
|
|
909
|
+
return ExteriorAlgebra(self.base_ring(), self.variable_names())
|
|
910
|
+
|
|
911
|
+
@cached_method
|
|
912
|
+
def free_module(self):
|
|
913
|
+
"""
|
|
914
|
+
Return the underlying free module `V` of ``self``.
|
|
915
|
+
|
|
916
|
+
This is the free module on which the quadratic form that was
|
|
917
|
+
used to construct ``self`` is defined.
|
|
918
|
+
|
|
919
|
+
EXAMPLES::
|
|
920
|
+
|
|
921
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
922
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
923
|
+
sage: Cl.free_module()
|
|
924
|
+
Ambient free module of rank 3 over the principal ideal domain Integer Ring
|
|
925
|
+
"""
|
|
926
|
+
return FreeModule(self.base_ring(), self._quadratic_form.dim())
|
|
927
|
+
|
|
928
|
+
def dimension(self):
|
|
929
|
+
"""
|
|
930
|
+
Return the rank of ``self`` as a free module.
|
|
931
|
+
|
|
932
|
+
Let `V` be a free `R`-module of rank `n`; then, `Cl(V, Q)` is a
|
|
933
|
+
free `R`-module of rank `2^n`.
|
|
934
|
+
|
|
935
|
+
EXAMPLES::
|
|
936
|
+
|
|
937
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
938
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
939
|
+
sage: Cl.dimension()
|
|
940
|
+
8
|
|
941
|
+
"""
|
|
942
|
+
return ZZ(2)**self._quadratic_form.dim()
|
|
943
|
+
|
|
944
|
+
def pseudoscalar(self):
|
|
945
|
+
r"""
|
|
946
|
+
Return the unit pseudoscalar of ``self``.
|
|
947
|
+
|
|
948
|
+
Given the basis `e_1, e_2, \ldots, e_n` of the underlying
|
|
949
|
+
`R`-module, the unit pseudoscalar is defined as
|
|
950
|
+
`e_1 \cdot e_2 \cdots e_n`.
|
|
951
|
+
|
|
952
|
+
This depends on the choice of basis.
|
|
953
|
+
|
|
954
|
+
EXAMPLES::
|
|
955
|
+
|
|
956
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
957
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
958
|
+
sage: Cl.pseudoscalar()
|
|
959
|
+
x*y*z
|
|
960
|
+
|
|
961
|
+
sage: Q = QuadraticForm(ZZ, 0, [])
|
|
962
|
+
sage: Cl = CliffordAlgebra(Q)
|
|
963
|
+
sage: Cl.pseudoscalar()
|
|
964
|
+
1
|
|
965
|
+
|
|
966
|
+
REFERENCES:
|
|
967
|
+
|
|
968
|
+
- :wikipedia:`Classification_of_Clifford_algebras#Unit_pseudoscalar`
|
|
969
|
+
"""
|
|
970
|
+
d = self._quadratic_form.dim()
|
|
971
|
+
return self.element_class(self, {tuple(range(d)): self.base_ring().one()})
|
|
972
|
+
|
|
973
|
+
def lift_module_morphism(self, m, names=None):
|
|
974
|
+
r"""
|
|
975
|
+
Lift the matrix ``m`` to an algebra morphism of Clifford algebras.
|
|
976
|
+
|
|
977
|
+
Given a linear map `m : W \to V` (here represented by a matrix
|
|
978
|
+
acting on column vectors), this method returns the algebra
|
|
979
|
+
morphism `Cl(m) : Cl(W, m(Q)) \to Cl(V, Q)`, where `Cl(V, Q)`
|
|
980
|
+
is the Clifford algebra ``self`` and where `m(Q)` is the pullback
|
|
981
|
+
of the quadratic form `Q` to `W`. See the documentation
|
|
982
|
+
of :class:`CliffordAlgebra` for how this pullback and the
|
|
983
|
+
morphism `Cl(m)` are defined.
|
|
984
|
+
|
|
985
|
+
.. NOTE::
|
|
986
|
+
|
|
987
|
+
This is a map into ``self``.
|
|
988
|
+
|
|
989
|
+
INPUT:
|
|
990
|
+
|
|
991
|
+
- ``m`` -- a matrix
|
|
992
|
+
- ``names`` -- (default: ``'e'``) the names of the generators of the
|
|
993
|
+
Clifford algebra of the domain of (the map represented by) ``m``
|
|
994
|
+
|
|
995
|
+
OUTPUT: the algebra morphism `Cl(m)` from `Cl(W, m(Q))` to ``self``
|
|
996
|
+
|
|
997
|
+
EXAMPLES::
|
|
998
|
+
|
|
999
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
1000
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
1001
|
+
sage: m = matrix([[1,-1,-1],[0,1,-1],[1,1,1]])
|
|
1002
|
+
sage: phi = Cl.lift_module_morphism(m, 'abc')
|
|
1003
|
+
sage: phi
|
|
1004
|
+
Generic morphism:
|
|
1005
|
+
From: The Clifford algebra of the Quadratic form in 3 variables over Integer Ring with coefficients:
|
|
1006
|
+
[ 10 17 3 ]
|
|
1007
|
+
[ * 11 0 ]
|
|
1008
|
+
[ * * 5 ]
|
|
1009
|
+
To: The Clifford algebra of the Quadratic form in 3 variables over Integer Ring with coefficients:
|
|
1010
|
+
[ 1 2 3 ]
|
|
1011
|
+
[ * 4 5 ]
|
|
1012
|
+
[ * * 6 ]
|
|
1013
|
+
sage: a,b,c = phi.domain().gens()
|
|
1014
|
+
sage: phi(a)
|
|
1015
|
+
x + z
|
|
1016
|
+
sage: phi(b)
|
|
1017
|
+
-x + y + z
|
|
1018
|
+
sage: phi(c)
|
|
1019
|
+
-x - y + z
|
|
1020
|
+
sage: phi(a + 3*b)
|
|
1021
|
+
-2*x + 3*y + 4*z
|
|
1022
|
+
sage: phi(a) + 3*phi(b)
|
|
1023
|
+
-2*x + 3*y + 4*z
|
|
1024
|
+
sage: phi(a*b)
|
|
1025
|
+
x*y + 2*x*z - y*z + 7
|
|
1026
|
+
sage: phi(b*a)
|
|
1027
|
+
-x*y - 2*x*z + y*z + 10
|
|
1028
|
+
sage: phi(a*b + c)
|
|
1029
|
+
x*y + 2*x*z - y*z - x - y + z + 7
|
|
1030
|
+
sage: phi(a*b) + phi(c)
|
|
1031
|
+
x*y + 2*x*z - y*z - x - y + z + 7
|
|
1032
|
+
|
|
1033
|
+
We check that the map is an algebra morphism::
|
|
1034
|
+
|
|
1035
|
+
sage: phi(a)*phi(b)
|
|
1036
|
+
x*y + 2*x*z - y*z + 7
|
|
1037
|
+
sage: phi(a*b)
|
|
1038
|
+
x*y + 2*x*z - y*z + 7
|
|
1039
|
+
sage: phi(a*a)
|
|
1040
|
+
10
|
|
1041
|
+
sage: phi(a)*phi(a)
|
|
1042
|
+
10
|
|
1043
|
+
sage: phi(b*a)
|
|
1044
|
+
-x*y - 2*x*z + y*z + 10
|
|
1045
|
+
sage: phi(b) * phi(a)
|
|
1046
|
+
-x*y - 2*x*z + y*z + 10
|
|
1047
|
+
sage: phi((a + b)*(a + c)) == phi(a + b) * phi(a + c)
|
|
1048
|
+
True
|
|
1049
|
+
|
|
1050
|
+
We can also lift arbitrary linear maps::
|
|
1051
|
+
|
|
1052
|
+
sage: m = matrix([[1,1],[0,1],[1,1]])
|
|
1053
|
+
sage: phi = Cl.lift_module_morphism(m, 'ab')
|
|
1054
|
+
sage: a,b = phi.domain().gens()
|
|
1055
|
+
sage: phi(a)
|
|
1056
|
+
x + z
|
|
1057
|
+
sage: phi(b)
|
|
1058
|
+
x + y + z
|
|
1059
|
+
sage: phi(a*b)
|
|
1060
|
+
x*y - y*z + 15
|
|
1061
|
+
sage: phi(a)*phi(b)
|
|
1062
|
+
x*y - y*z + 15
|
|
1063
|
+
sage: phi(b*a)
|
|
1064
|
+
-x*y + y*z + 12
|
|
1065
|
+
sage: phi(b)*phi(a)
|
|
1066
|
+
-x*y + y*z + 12
|
|
1067
|
+
|
|
1068
|
+
sage: m = matrix([[1,1,1,2], [0,1,1,1], [0,1,1,1]])
|
|
1069
|
+
sage: phi = Cl.lift_module_morphism(m, 'abcd')
|
|
1070
|
+
sage: a,b,c,d = phi.domain().gens()
|
|
1071
|
+
sage: phi(a)
|
|
1072
|
+
x
|
|
1073
|
+
sage: phi(b)
|
|
1074
|
+
x + y + z
|
|
1075
|
+
sage: phi(c)
|
|
1076
|
+
x + y + z
|
|
1077
|
+
sage: phi(d)
|
|
1078
|
+
2*x + y + z
|
|
1079
|
+
sage: phi(a*b*c + d*a)
|
|
1080
|
+
-x*y - x*z + 21*x + 7
|
|
1081
|
+
sage: phi(a*b*c*d)
|
|
1082
|
+
21*x*y + 21*x*z + 42
|
|
1083
|
+
|
|
1084
|
+
TESTS:
|
|
1085
|
+
|
|
1086
|
+
Check that the resulting morphism knows it is for
|
|
1087
|
+
finite-dimensional algebras (:issue:`25339`)::
|
|
1088
|
+
|
|
1089
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
1090
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
1091
|
+
sage: m = matrix([[1,-1,-1],[0,1,-1],[1,1,1]])
|
|
1092
|
+
sage: phi = Cl.lift_module_morphism(m, 'abc')
|
|
1093
|
+
sage: phi.category_for()
|
|
1094
|
+
Category of finite dimensional super algebras with basis over
|
|
1095
|
+
(Dedekind domains and euclidean domains
|
|
1096
|
+
and noetherian rings
|
|
1097
|
+
and infinite enumerated sets and metric spaces)
|
|
1098
|
+
sage: phi.matrix()
|
|
1099
|
+
[ 1 0 0 0 7 -3 -7 0]
|
|
1100
|
+
[ 0 1 -1 -1 0 0 0 -17]
|
|
1101
|
+
[ 0 0 1 -1 0 0 0 -4]
|
|
1102
|
+
[ 0 1 1 1 0 0 0 3]
|
|
1103
|
+
[ 0 0 0 0 1 -1 2 0]
|
|
1104
|
+
[ 0 0 0 0 2 2 0 0]
|
|
1105
|
+
[ 0 0 0 0 -1 1 2 0]
|
|
1106
|
+
[ 0 0 0 0 0 0 0 4]
|
|
1107
|
+
"""
|
|
1108
|
+
Q = self._quadratic_form(m)
|
|
1109
|
+
# If R is a quadratic form and m is a matrix, then R(m) returns
|
|
1110
|
+
# the quadratic form m^t R m.
|
|
1111
|
+
|
|
1112
|
+
if Q == self._quadratic_form and names is None:
|
|
1113
|
+
Cl = self
|
|
1114
|
+
else:
|
|
1115
|
+
Cl = CliffordAlgebra(Q, names)
|
|
1116
|
+
|
|
1117
|
+
n = self._quadratic_form.dim()
|
|
1118
|
+
f = lambda x: self.prod(self._from_dict({FrozenBitset((j, )): m[j, i] for j in range(n)},
|
|
1119
|
+
remove_zeros=True) for i in x)
|
|
1120
|
+
cat = AlgebrasWithBasis(self.category().base_ring()).Super().FiniteDimensional()
|
|
1121
|
+
return Cl.module_morphism(on_basis=f, codomain=self, category=cat)
|
|
1122
|
+
|
|
1123
|
+
def lift_isometry(self, m, names=None):
|
|
1124
|
+
r"""
|
|
1125
|
+
Lift an invertible isometry ``m`` of the quadratic form of
|
|
1126
|
+
``self`` to a Clifford algebra morphism.
|
|
1127
|
+
|
|
1128
|
+
Given an invertible linear map `m : V \to W` (here represented by
|
|
1129
|
+
a matrix acting on column vectors), this method returns the
|
|
1130
|
+
algebra morphism `Cl(m)` from `Cl(V, Q)` to `Cl(W, m^{-1}(Q))`,
|
|
1131
|
+
where `Cl(V, Q)` is the Clifford algebra ``self`` and where
|
|
1132
|
+
`m^{-1}(Q)` is the pullback of the quadratic form `Q` to `W` along
|
|
1133
|
+
the inverse map `m^{-1} : W \to V`. See the documentation of
|
|
1134
|
+
:class:`CliffordAlgebra` for how this pullback and the morphism
|
|
1135
|
+
`Cl(m)` are defined.
|
|
1136
|
+
|
|
1137
|
+
INPUT:
|
|
1138
|
+
|
|
1139
|
+
- ``m`` -- an isometry of the quadratic form of ``self``
|
|
1140
|
+
- ``names`` -- (default: ``'e'``) the names of the generators of
|
|
1141
|
+
the Clifford algebra of the codomain of (the map represented by)
|
|
1142
|
+
``m``
|
|
1143
|
+
|
|
1144
|
+
OUTPUT: the algebra morphism `Cl(m)` from ``self`` to `Cl(W, m^{-1}(Q))`
|
|
1145
|
+
|
|
1146
|
+
EXAMPLES::
|
|
1147
|
+
|
|
1148
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
1149
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
1150
|
+
sage: m = matrix([[1,1,2],[0,1,1],[0,0,1]])
|
|
1151
|
+
sage: phi = Cl.lift_isometry(m, 'abc')
|
|
1152
|
+
sage: phi(x)
|
|
1153
|
+
a
|
|
1154
|
+
sage: phi(y)
|
|
1155
|
+
a + b
|
|
1156
|
+
sage: phi(x*y)
|
|
1157
|
+
a*b + 1
|
|
1158
|
+
sage: phi(x) * phi(y)
|
|
1159
|
+
a*b + 1
|
|
1160
|
+
sage: phi(z*y)
|
|
1161
|
+
a*b - a*c - b*c
|
|
1162
|
+
sage: phi(z) * phi(y)
|
|
1163
|
+
a*b - a*c - b*c
|
|
1164
|
+
sage: phi(x + z) * phi(y + z) == phi((x + z) * (y + z))
|
|
1165
|
+
True
|
|
1166
|
+
|
|
1167
|
+
TESTS:
|
|
1168
|
+
|
|
1169
|
+
Check that the resulting morphism knows it is for
|
|
1170
|
+
finite-dimensional algebras (:issue:`25339`)::
|
|
1171
|
+
|
|
1172
|
+
sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6])
|
|
1173
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
1174
|
+
sage: m = matrix([[1,1,2],[0,1,1],[0,0,1]])
|
|
1175
|
+
sage: phi = Cl.lift_isometry(m, 'abc')
|
|
1176
|
+
sage: phi.category_for()
|
|
1177
|
+
Category of finite dimensional super algebras with basis over
|
|
1178
|
+
(Dedekind domains and euclidean domains
|
|
1179
|
+
and noetherian rings
|
|
1180
|
+
and infinite enumerated sets and metric spaces)
|
|
1181
|
+
sage: phi.matrix()
|
|
1182
|
+
[ 1 0 0 0 1 2 5 0]
|
|
1183
|
+
[ 0 1 1 2 0 0 0 5]
|
|
1184
|
+
[ 0 0 1 1 0 0 0 -1]
|
|
1185
|
+
[ 0 0 0 1 0 0 0 1]
|
|
1186
|
+
[ 0 0 0 0 1 1 -1 0]
|
|
1187
|
+
[ 0 0 0 0 0 1 1 0]
|
|
1188
|
+
[ 0 0 0 0 0 0 1 0]
|
|
1189
|
+
[ 0 0 0 0 0 0 0 1]
|
|
1190
|
+
"""
|
|
1191
|
+
MS = m.parent()
|
|
1192
|
+
if not m.is_invertible():
|
|
1193
|
+
raise ValueError('{} is not invertible')
|
|
1194
|
+
Q = self._quadratic_form(MS(m.inverse()))
|
|
1195
|
+
|
|
1196
|
+
if Q == self._quadratic_form and names is None:
|
|
1197
|
+
Cl = self
|
|
1198
|
+
else:
|
|
1199
|
+
if names is None:
|
|
1200
|
+
names = 'e'
|
|
1201
|
+
Cl = CliffordAlgebra(Q, names)
|
|
1202
|
+
|
|
1203
|
+
n = Q.dim()
|
|
1204
|
+
|
|
1205
|
+
f = lambda x: Cl.prod(Cl._from_dict({FrozenBitset((j, )): m[j, i] for j in range(n)},
|
|
1206
|
+
remove_zeros=True) for i in x)
|
|
1207
|
+
cat = AlgebrasWithBasis(self.category().base_ring()).Super().FiniteDimensional()
|
|
1208
|
+
return self.module_morphism(on_basis=f, codomain=Cl, category=cat)
|
|
1209
|
+
|
|
1210
|
+
# This is a general method for finite dimensional algebras with bases
|
|
1211
|
+
# and should be moved to the corresponding category once there is
|
|
1212
|
+
# a category level method for getting the indexing set of the basis;
|
|
1213
|
+
# similar to #15289 but on a category level.
|
|
1214
|
+
@cached_method
|
|
1215
|
+
def center_basis(self):
|
|
1216
|
+
"""
|
|
1217
|
+
Return a list of elements which correspond to a basis for the center
|
|
1218
|
+
of ``self``.
|
|
1219
|
+
|
|
1220
|
+
This assumes that the ground ring can be used to compute the
|
|
1221
|
+
kernel of a matrix.
|
|
1222
|
+
|
|
1223
|
+
.. SEEALSO::
|
|
1224
|
+
|
|
1225
|
+
:meth:`supercenter_basis`,
|
|
1226
|
+
http://math.stackexchange.com/questions/129183/center-of-clifford-algebra-depending-on-the-parity-of-dim-v
|
|
1227
|
+
|
|
1228
|
+
.. TODO::
|
|
1229
|
+
|
|
1230
|
+
Deprecate this in favor of a method called `center()` once
|
|
1231
|
+
subalgebras are properly implemented in Sage.
|
|
1232
|
+
|
|
1233
|
+
EXAMPLES::
|
|
1234
|
+
|
|
1235
|
+
sage: Q = QuadraticForm(QQ, 3, [1,2,3,4,5,6])
|
|
1236
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
1237
|
+
sage: Z = Cl.center_basis(); Z
|
|
1238
|
+
(1, -2/5*x*y*z + x - 3/5*y + 2/5*z)
|
|
1239
|
+
sage: all(z*b - b*z == 0 for z in Z for b in Cl.basis())
|
|
1240
|
+
True
|
|
1241
|
+
|
|
1242
|
+
sage: Q = QuadraticForm(QQ, 3, [1,-2,-3, 4, 2, 1])
|
|
1243
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
1244
|
+
sage: Z = Cl.center_basis(); Z
|
|
1245
|
+
(1, -x*y*z + x + 3/2*y - z)
|
|
1246
|
+
sage: all(z*b - b*z == 0 for z in Z for b in Cl.basis())
|
|
1247
|
+
True
|
|
1248
|
+
|
|
1249
|
+
sage: Q = QuadraticForm(QQ, 2, [1,-2,-3])
|
|
1250
|
+
sage: Cl.<x,y> = CliffordAlgebra(Q)
|
|
1251
|
+
sage: Cl.center_basis()
|
|
1252
|
+
(1,)
|
|
1253
|
+
|
|
1254
|
+
sage: Q = QuadraticForm(QQ, 2, [-1,1,-3])
|
|
1255
|
+
sage: Cl.<x,y> = CliffordAlgebra(Q)
|
|
1256
|
+
sage: Cl.center_basis()
|
|
1257
|
+
(1,)
|
|
1258
|
+
|
|
1259
|
+
A degenerate case::
|
|
1260
|
+
|
|
1261
|
+
sage: Q = QuadraticForm(QQ, 3, [4,4,-4,1,-2,1])
|
|
1262
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
1263
|
+
sage: Cl.center_basis()
|
|
1264
|
+
(1, x*y*z + x - 2*y - 2*z, x*y + x*z - 2*y*z)
|
|
1265
|
+
|
|
1266
|
+
The most degenerate case (the exterior algebra)::
|
|
1267
|
+
|
|
1268
|
+
sage: Q = QuadraticForm(QQ, 3)
|
|
1269
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
1270
|
+
sage: Cl.center_basis()
|
|
1271
|
+
(1, x*y, x*z, y*z, x*y*z)
|
|
1272
|
+
"""
|
|
1273
|
+
R = self.base_ring()
|
|
1274
|
+
B = self.basis()
|
|
1275
|
+
K = list(B.keys())
|
|
1276
|
+
k = len(K)
|
|
1277
|
+
d = {}
|
|
1278
|
+
for a, i in enumerate(K):
|
|
1279
|
+
Bi = B[i]
|
|
1280
|
+
for b, j in enumerate(K):
|
|
1281
|
+
Bj = B[j]
|
|
1282
|
+
for m, c in (Bi*Bj - Bj*Bi):
|
|
1283
|
+
d[(a, K.index(m)+k*b)] = c
|
|
1284
|
+
m = Matrix(R, d, nrows=k, ncols=k*k, sparse=True)
|
|
1285
|
+
from_vector = lambda x: self.sum_of_terms(((K[i], c) for i, c in x.items()),
|
|
1286
|
+
distinct=True)
|
|
1287
|
+
return tuple(map(from_vector, m.kernel().basis()))
|
|
1288
|
+
|
|
1289
|
+
# Same as center except for superalgebras
|
|
1290
|
+
@cached_method
|
|
1291
|
+
def supercenter_basis(self):
|
|
1292
|
+
"""
|
|
1293
|
+
Return a list of elements which correspond to a basis for the
|
|
1294
|
+
supercenter of ``self``.
|
|
1295
|
+
|
|
1296
|
+
This assumes that the ground ring can be used to compute the
|
|
1297
|
+
kernel of a matrix.
|
|
1298
|
+
|
|
1299
|
+
.. SEEALSO::
|
|
1300
|
+
|
|
1301
|
+
:meth:`center_basis`,
|
|
1302
|
+
http://math.stackexchange.com/questions/129183/center-of-clifford-algebra-depending-on-the-parity-of-dim-v
|
|
1303
|
+
|
|
1304
|
+
.. TODO::
|
|
1305
|
+
|
|
1306
|
+
Deprecate this in favor of a method called `supercenter()` once
|
|
1307
|
+
subalgebras are properly implemented in Sage.
|
|
1308
|
+
|
|
1309
|
+
EXAMPLES::
|
|
1310
|
+
|
|
1311
|
+
sage: Q = QuadraticForm(QQ, 3, [1,2,3,4,5,6])
|
|
1312
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
1313
|
+
sage: SZ = Cl.supercenter_basis(); SZ
|
|
1314
|
+
(1,)
|
|
1315
|
+
sage: all(z.supercommutator(b) == 0 for z in SZ for b in Cl.basis())
|
|
1316
|
+
True
|
|
1317
|
+
|
|
1318
|
+
sage: Q = QuadraticForm(QQ, 3, [1,-2,-3, 4, 2, 1])
|
|
1319
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
1320
|
+
sage: Cl.supercenter_basis()
|
|
1321
|
+
(1,)
|
|
1322
|
+
|
|
1323
|
+
sage: Q = QuadraticForm(QQ, 2, [1,-2,-3])
|
|
1324
|
+
sage: Cl.<x,y> = CliffordAlgebra(Q)
|
|
1325
|
+
sage: Cl.supercenter_basis()
|
|
1326
|
+
(1,)
|
|
1327
|
+
|
|
1328
|
+
sage: Q = QuadraticForm(QQ, 2, [-1,1,-3])
|
|
1329
|
+
sage: Cl.<x,y> = CliffordAlgebra(Q)
|
|
1330
|
+
sage: Cl.supercenter_basis()
|
|
1331
|
+
(1,)
|
|
1332
|
+
|
|
1333
|
+
Singular vectors of a quadratic form generate in the supercenter::
|
|
1334
|
+
|
|
1335
|
+
sage: Q = QuadraticForm(QQ, 3, [1/2,-2,4,256/249,3,-185/8])
|
|
1336
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
1337
|
+
sage: Cl.supercenter_basis()
|
|
1338
|
+
(1, x + 249/322*y + 22/161*z)
|
|
1339
|
+
|
|
1340
|
+
sage: Q = QuadraticForm(QQ, 3, [4,4,-4,1,-2,1])
|
|
1341
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
1342
|
+
sage: Cl.supercenter_basis()
|
|
1343
|
+
(1, x + 2*z, y + z, x*y + x*z - 2*y*z)
|
|
1344
|
+
|
|
1345
|
+
The most degenerate case::
|
|
1346
|
+
|
|
1347
|
+
sage: Q = QuadraticForm(QQ, 3)
|
|
1348
|
+
sage: Cl.<x,y,z> = CliffordAlgebra(Q)
|
|
1349
|
+
sage: Cl.supercenter_basis()
|
|
1350
|
+
(1, x, y, z, x*y, x*z, y*z, x*y*z)
|
|
1351
|
+
"""
|
|
1352
|
+
R = self.base_ring()
|
|
1353
|
+
B = self.basis()
|
|
1354
|
+
K = list(B.keys())
|
|
1355
|
+
k = len(K)
|
|
1356
|
+
d = {}
|
|
1357
|
+
for a, i in enumerate(K):
|
|
1358
|
+
Bi = B[i]
|
|
1359
|
+
for b, j in enumerate(K):
|
|
1360
|
+
Bj = B[j]
|
|
1361
|
+
if len(i) % 2 and len(j) % 2:
|
|
1362
|
+
supercommutator = Bi * Bj + Bj * Bi
|
|
1363
|
+
else:
|
|
1364
|
+
supercommutator = Bi * Bj - Bj * Bi
|
|
1365
|
+
for m, c in supercommutator:
|
|
1366
|
+
d[(a, K.index(m) + k * b)] = c
|
|
1367
|
+
m = Matrix(R, d, nrows=k, ncols=k * k, sparse=True)
|
|
1368
|
+
from_vector = lambda x: self.sum_of_terms(((K[i], c) for i, c in x.items()),
|
|
1369
|
+
distinct=True)
|
|
1370
|
+
return tuple(map(from_vector, m.kernel().basis()))
|
|
1371
|
+
|
|
1372
|
+
Element = CliffordAlgebraElement
|
|
1373
|
+
|
|
1374
|
+
|
|
1375
|
+
class ExteriorAlgebra(CliffordAlgebra):
|
|
1376
|
+
r"""
|
|
1377
|
+
An exterior algebra of a free module over a commutative ring.
|
|
1378
|
+
|
|
1379
|
+
Let `V` be a module over a commutative ring `R`. The exterior algebra
|
|
1380
|
+
(or Grassmann algebra) `\Lambda(V)` of `V` is defined as the quotient
|
|
1381
|
+
of the tensor algebra `T(V)` of `V` modulo the two-sided ideal
|
|
1382
|
+
generated by all tensors of the form `x \otimes x` with `x \in V`. The
|
|
1383
|
+
multiplication on `\Lambda(V)` is denoted by `\wedge` (so
|
|
1384
|
+
`v_1 \wedge v_2 \wedge \cdots \wedge v_n` is the projection of
|
|
1385
|
+
`v_1 \otimes v_2 \otimes \cdots \otimes v_n` onto `\Lambda(V)`) and
|
|
1386
|
+
called the "exterior product" or "wedge product".
|
|
1387
|
+
|
|
1388
|
+
If `V` is a rank-`n` free `R`-module with a basis
|
|
1389
|
+
`\{e_1, \ldots, e_n\}`, then `\Lambda(V)` is the `R`-algebra
|
|
1390
|
+
noncommutatively generated by the `n` generators `e_1, \ldots, e_n`
|
|
1391
|
+
subject to the relations `e_i^2 = 0` for all `i`, and
|
|
1392
|
+
`e_i e_j = - e_j e_i` for all `i < j`. As an `R`-module,
|
|
1393
|
+
`\Lambda(V)` then has a basis `(\bigwedge_{i \in I} e_i)` with `I`
|
|
1394
|
+
ranging over the subsets of `\{1, 2, \ldots, n\}` (where
|
|
1395
|
+
`\bigwedge_{i \in I} e_i` is the wedge product of `e_i` for `i`
|
|
1396
|
+
running through all elements of `I` from smallest to largest), and
|
|
1397
|
+
hence is free of rank `2^n`.
|
|
1398
|
+
|
|
1399
|
+
The exterior algebra of an `R`-module `V` can also be realized
|
|
1400
|
+
as the Clifford algebra of `V` for the quadratic form `Q` given by
|
|
1401
|
+
`Q(v) = 0` for all vectors `v \in V`. See :class:`CliffordAlgebra`
|
|
1402
|
+
for the notion of a Clifford algebra.
|
|
1403
|
+
|
|
1404
|
+
The exterior algebra of an `R`-module `V` is a connected `\ZZ`-graded
|
|
1405
|
+
Hopf superalgebra. It is commutative in the super sense (i.e., the
|
|
1406
|
+
odd elements anticommute and square to `0`).
|
|
1407
|
+
|
|
1408
|
+
This class implements the exterior algebra `\Lambda(R^n)` for
|
|
1409
|
+
`n` a nonnegative integer.
|
|
1410
|
+
|
|
1411
|
+
INPUT:
|
|
1412
|
+
|
|
1413
|
+
- ``R`` -- the base ring, *or* the free module whose exterior algebra
|
|
1414
|
+
is to be computed
|
|
1415
|
+
|
|
1416
|
+
- ``names`` -- list of strings to name the generators of the
|
|
1417
|
+
exterior algebra; this list can either have one entry only (in which
|
|
1418
|
+
case the generators will be called ``e + '0'``, ``e + '1'``, ...,
|
|
1419
|
+
``e + 'n-1'``, with ``e`` being said entry), or have ``n`` entries
|
|
1420
|
+
(in which case these entries will be used directly as names for the
|
|
1421
|
+
generators)
|
|
1422
|
+
|
|
1423
|
+
- ``n`` -- the number of generators, i.e., the rank of the free
|
|
1424
|
+
module whose exterior algebra is to be computed (this doesn't have
|
|
1425
|
+
to be provided if it can be inferred from the rest of the input)
|
|
1426
|
+
|
|
1427
|
+
REFERENCES:
|
|
1428
|
+
|
|
1429
|
+
- :wikipedia:`Exterior_algebra`
|
|
1430
|
+
"""
|
|
1431
|
+
@staticmethod
|
|
1432
|
+
def __classcall_private__(cls, R, names=None, n=None):
|
|
1433
|
+
"""
|
|
1434
|
+
Normalize arguments to ensure a unique representation.
|
|
1435
|
+
|
|
1436
|
+
EXAMPLES::
|
|
1437
|
+
|
|
1438
|
+
sage: E1.<e0,e1,e2> = ExteriorAlgebra(QQ)
|
|
1439
|
+
sage: E2 = ExteriorAlgebra(QQ, 3)
|
|
1440
|
+
sage: E3 = ExteriorAlgebra(QQ, ['e0','e1','e2'])
|
|
1441
|
+
sage: E1 is E2 and E2 is E3
|
|
1442
|
+
True
|
|
1443
|
+
"""
|
|
1444
|
+
if names is None:
|
|
1445
|
+
names = 'e'
|
|
1446
|
+
elif names in ZZ:
|
|
1447
|
+
n = names
|
|
1448
|
+
names = 'e'
|
|
1449
|
+
|
|
1450
|
+
if isinstance(R, FreeModule_generic):
|
|
1451
|
+
if n is not None and n != R.dimension():
|
|
1452
|
+
raise ValueError("the number of variables does not match the dimension")
|
|
1453
|
+
n = R.dimension()
|
|
1454
|
+
R = R.base_ring()
|
|
1455
|
+
|
|
1456
|
+
names = tuple(names)
|
|
1457
|
+
if n is not None and len(names) != n:
|
|
1458
|
+
if len(names) == 1:
|
|
1459
|
+
names = tuple('{}{}'.format(names[0], i) for i in range(n))
|
|
1460
|
+
else:
|
|
1461
|
+
raise ValueError("the number of variables does not match the number of generators")
|
|
1462
|
+
return super().__classcall__(cls, R, names)
|
|
1463
|
+
|
|
1464
|
+
def __init__(self, R, names):
|
|
1465
|
+
"""
|
|
1466
|
+
Initialize ``self``.
|
|
1467
|
+
|
|
1468
|
+
EXAMPLES::
|
|
1469
|
+
|
|
1470
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
1471
|
+
sage: E.category()
|
|
1472
|
+
Category of finite dimensional supercommutative supercocommutative
|
|
1473
|
+
super Hopf algebras with basis over Rational Field
|
|
1474
|
+
sage: TestSuite(E).run()
|
|
1475
|
+
|
|
1476
|
+
sage: TestSuite(ExteriorAlgebra(GF(3), ['a', 'b'])).run()
|
|
1477
|
+
"""
|
|
1478
|
+
cat = HopfAlgebrasWithBasis(R).FiniteDimensional().Supercommutative().Supercocommutative()
|
|
1479
|
+
CliffordAlgebra.__init__(self, QuadraticForm(R, len(names)), names, category=cat)
|
|
1480
|
+
|
|
1481
|
+
def _repr_(self):
|
|
1482
|
+
r"""
|
|
1483
|
+
Return a string representation of ``self``.
|
|
1484
|
+
|
|
1485
|
+
EXAMPLES::
|
|
1486
|
+
|
|
1487
|
+
sage: ExteriorAlgebra(QQ, 3)
|
|
1488
|
+
The exterior algebra of rank 3 over Rational Field
|
|
1489
|
+
"""
|
|
1490
|
+
return "The exterior algebra of rank {} over {}".format(self.ngens(), self.base_ring())
|
|
1491
|
+
|
|
1492
|
+
def _repr_term(self, m):
|
|
1493
|
+
"""
|
|
1494
|
+
Return a string representation of the basis element indexed by
|
|
1495
|
+
``m``.
|
|
1496
|
+
|
|
1497
|
+
EXAMPLES::
|
|
1498
|
+
|
|
1499
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
1500
|
+
sage: E._repr_term((0,1,2))
|
|
1501
|
+
'x*y*z'
|
|
1502
|
+
sage: y*x + x*z
|
|
1503
|
+
-x*y + x*z
|
|
1504
|
+
"""
|
|
1505
|
+
if len(m) == 0:
|
|
1506
|
+
return '1'
|
|
1507
|
+
term = ''
|
|
1508
|
+
for i in m:
|
|
1509
|
+
if len(term) != 0:
|
|
1510
|
+
term += '*'
|
|
1511
|
+
term += self.variable_names()[i]
|
|
1512
|
+
return term
|
|
1513
|
+
|
|
1514
|
+
def _ascii_art_term(self, m):
|
|
1515
|
+
r"""
|
|
1516
|
+
Return ascii art for the basis element indexed by ``m``.
|
|
1517
|
+
|
|
1518
|
+
EXAMPLES::
|
|
1519
|
+
|
|
1520
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
1521
|
+
sage: E._ascii_art_term((0,1,2))
|
|
1522
|
+
x/\y/\z
|
|
1523
|
+
sage: ascii_art(y*x + 2*x*z)
|
|
1524
|
+
-x/\y + 2*x/\z
|
|
1525
|
+
"""
|
|
1526
|
+
if len(m) == 0:
|
|
1527
|
+
return ascii_art('1')
|
|
1528
|
+
wedge = '/\\'
|
|
1529
|
+
return ascii_art(*[repr(self.basis()[FrozenBitset((i, ))]) for i in m], sep=wedge)
|
|
1530
|
+
|
|
1531
|
+
def _unicode_art_term(self, m):
|
|
1532
|
+
"""
|
|
1533
|
+
Return unicode art for the basis element indexed by ``m``.
|
|
1534
|
+
|
|
1535
|
+
EXAMPLES::
|
|
1536
|
+
|
|
1537
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
1538
|
+
sage: E._unicode_art_term((0,1,2))
|
|
1539
|
+
x∧y∧z
|
|
1540
|
+
sage: unicode_art(y*x + x*z)
|
|
1541
|
+
-x∧y + x∧z
|
|
1542
|
+
"""
|
|
1543
|
+
if len(m) == 0:
|
|
1544
|
+
return unicode_art('1')
|
|
1545
|
+
wedge = unicodedata.lookup('LOGICAL AND')
|
|
1546
|
+
return unicode_art(*[self.variable_names()[i] for i in m], sep=wedge)
|
|
1547
|
+
|
|
1548
|
+
def _latex_term(self, m):
|
|
1549
|
+
r"""
|
|
1550
|
+
Return a `\LaTeX` representation of the basis element indexed
|
|
1551
|
+
by ``m``.
|
|
1552
|
+
|
|
1553
|
+
EXAMPLES::
|
|
1554
|
+
|
|
1555
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
1556
|
+
sage: E._latex_term((0,1,2))
|
|
1557
|
+
' x \\wedge y \\wedge z'
|
|
1558
|
+
sage: E.<x0,x1,x2> = ExteriorAlgebra(QQ)
|
|
1559
|
+
sage: E._latex_term((0,1,2))
|
|
1560
|
+
' x_{0} \\wedge x_{1} \\wedge x_{2}'
|
|
1561
|
+
sage: E._latex_term(())
|
|
1562
|
+
'1'
|
|
1563
|
+
sage: E._latex_term((0,))
|
|
1564
|
+
' x_{0}'
|
|
1565
|
+
"""
|
|
1566
|
+
if len(m) == 0:
|
|
1567
|
+
return '1'
|
|
1568
|
+
term = ''
|
|
1569
|
+
for i in m:
|
|
1570
|
+
if len(term) != 0:
|
|
1571
|
+
term += ' \\wedge'
|
|
1572
|
+
term += ' ' + self.latex_variable_names()[i]
|
|
1573
|
+
return term
|
|
1574
|
+
|
|
1575
|
+
def lift_morphism(self, phi, names=None):
|
|
1576
|
+
r"""
|
|
1577
|
+
Lift the matrix ``m`` to an algebra morphism of exterior algebras.
|
|
1578
|
+
|
|
1579
|
+
Given a linear map `\phi : V \to W` (here represented by a matrix
|
|
1580
|
+
acting on column vectors over the base ring of `V`), this method
|
|
1581
|
+
returns the algebra morphism
|
|
1582
|
+
`\Lambda(\phi) : \Lambda(V) \to \Lambda(W)`. This morphism is defined
|
|
1583
|
+
on generators `v_i \in \Lambda(V)` by `v_i \mapsto \phi(v_i)`.
|
|
1584
|
+
|
|
1585
|
+
.. NOTE::
|
|
1586
|
+
|
|
1587
|
+
This is the map going out of ``self`` as opposed to
|
|
1588
|
+
:meth:`~sage.algebras.clifford_algebra.CliffordAlgebraElement.lift_module_morphism()`
|
|
1589
|
+
for general Clifford algebras.
|
|
1590
|
+
|
|
1591
|
+
INPUT:
|
|
1592
|
+
|
|
1593
|
+
- ``phi`` -- a linear map `\phi` from `V` to `W`, encoded as a
|
|
1594
|
+
matrix
|
|
1595
|
+
- ``names`` -- (default: ``'e'``) the names of the generators of
|
|
1596
|
+
the Clifford algebra of the domain of (the map represented by)
|
|
1597
|
+
``phi``
|
|
1598
|
+
|
|
1599
|
+
OUTPUT: the algebra morphism `\Lambda(\phi)` from ``self`` to
|
|
1600
|
+
`\Lambda(W)`
|
|
1601
|
+
|
|
1602
|
+
EXAMPLES::
|
|
1603
|
+
|
|
1604
|
+
sage: E.<x,y> = ExteriorAlgebra(QQ)
|
|
1605
|
+
sage: phi = matrix([[0,1],[1,1],[1,2]]); phi
|
|
1606
|
+
[0 1]
|
|
1607
|
+
[1 1]
|
|
1608
|
+
[1 2]
|
|
1609
|
+
sage: L = E.lift_morphism(phi, ['a','b','c']); L
|
|
1610
|
+
Generic morphism:
|
|
1611
|
+
From: The exterior algebra of rank 2 over Rational Field
|
|
1612
|
+
To: The exterior algebra of rank 3 over Rational Field
|
|
1613
|
+
sage: L(x)
|
|
1614
|
+
b + c
|
|
1615
|
+
sage: L(y)
|
|
1616
|
+
a + b + 2*c
|
|
1617
|
+
sage: L.on_basis()((1,))
|
|
1618
|
+
a + b + 2*c
|
|
1619
|
+
sage: p = L(E.one()); p
|
|
1620
|
+
1
|
|
1621
|
+
sage: p.parent()
|
|
1622
|
+
The exterior algebra of rank 3 over Rational Field
|
|
1623
|
+
sage: L(x*y)
|
|
1624
|
+
-a*b - a*c + b*c
|
|
1625
|
+
sage: L(x)*L(y)
|
|
1626
|
+
-a*b - a*c + b*c
|
|
1627
|
+
sage: L(x + y)
|
|
1628
|
+
a + 2*b + 3*c
|
|
1629
|
+
sage: L(x) + L(y)
|
|
1630
|
+
a + 2*b + 3*c
|
|
1631
|
+
sage: L(1/2*x + 2)
|
|
1632
|
+
1/2*b + 1/2*c + 2
|
|
1633
|
+
sage: L(E(3))
|
|
1634
|
+
3
|
|
1635
|
+
|
|
1636
|
+
sage: psi = matrix([[1, -3/2]]); psi
|
|
1637
|
+
[ 1 -3/2]
|
|
1638
|
+
sage: Lp = E.lift_morphism(psi, ['a']); Lp
|
|
1639
|
+
Generic morphism:
|
|
1640
|
+
From: The exterior algebra of rank 2 over Rational Field
|
|
1641
|
+
To: The exterior algebra of rank 1 over Rational Field
|
|
1642
|
+
sage: Lp(x)
|
|
1643
|
+
a
|
|
1644
|
+
sage: Lp(y)
|
|
1645
|
+
-3/2*a
|
|
1646
|
+
sage: Lp(x + 2*y + 3)
|
|
1647
|
+
-2*a + 3
|
|
1648
|
+
|
|
1649
|
+
TESTS:
|
|
1650
|
+
|
|
1651
|
+
Check that the resulting morphism knows it is for
|
|
1652
|
+
finite-dimensional algebras (:issue:`25339`)::
|
|
1653
|
+
|
|
1654
|
+
sage: E = ExteriorAlgebra(ZZ, 'e', 3)
|
|
1655
|
+
sage: T = jordan_block(0, 2).block_sum(jordan_block(0, 1))
|
|
1656
|
+
sage: phi = E.lift_morphism(T)
|
|
1657
|
+
sage: phi.category_for()
|
|
1658
|
+
Category of finite dimensional super algebras with basis over Integer Ring
|
|
1659
|
+
sage: phi.matrix()
|
|
1660
|
+
[1 0 0 0 0 0 0 0]
|
|
1661
|
+
[0 0 1 0 0 0 0 0]
|
|
1662
|
+
[0 0 0 0 0 0 0 0]
|
|
1663
|
+
[0 0 0 0 0 0 0 0]
|
|
1664
|
+
[0 0 0 0 0 0 0 0]
|
|
1665
|
+
[0 0 0 0 0 0 0 0]
|
|
1666
|
+
[0 0 0 0 0 0 0 0]
|
|
1667
|
+
[0 0 0 0 0 0 0 0]
|
|
1668
|
+
"""
|
|
1669
|
+
n = phi.nrows()
|
|
1670
|
+
R = self.base_ring()
|
|
1671
|
+
E = ExteriorAlgebra(R, names, n)
|
|
1672
|
+
f = lambda x: E.prod(E._from_dict({FrozenBitset((j, )): phi[j, i] for j in range(n)},
|
|
1673
|
+
remove_zeros=True) for i in x)
|
|
1674
|
+
cat = AlgebrasWithBasis(R).Super().FiniteDimensional()
|
|
1675
|
+
return self.module_morphism(on_basis=f, codomain=E, category=cat)
|
|
1676
|
+
|
|
1677
|
+
def volume_form(self):
|
|
1678
|
+
r"""
|
|
1679
|
+
Return the volume form of ``self``.
|
|
1680
|
+
|
|
1681
|
+
Given the basis `e_1, e_2, \ldots, e_n` of the underlying
|
|
1682
|
+
`R`-module, the volume form is defined as `e_1 \wedge e_2
|
|
1683
|
+
\wedge \cdots \wedge e_n`.
|
|
1684
|
+
|
|
1685
|
+
This depends on the choice of basis.
|
|
1686
|
+
|
|
1687
|
+
EXAMPLES::
|
|
1688
|
+
|
|
1689
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
1690
|
+
sage: E.volume_form()
|
|
1691
|
+
x*y*z
|
|
1692
|
+
"""
|
|
1693
|
+
d = self._quadratic_form.dim()
|
|
1694
|
+
return self.element_class(self, {tuple(range(d)): self.base_ring().one()})
|
|
1695
|
+
|
|
1696
|
+
def boundary(self, s_coeff):
|
|
1697
|
+
r"""
|
|
1698
|
+
Return the boundary operator `\partial` defined by the structure
|
|
1699
|
+
coefficients ``s_coeff`` of a Lie algebra.
|
|
1700
|
+
|
|
1701
|
+
For more on the boundary operator, see
|
|
1702
|
+
:class:`ExteriorAlgebraBoundary`.
|
|
1703
|
+
|
|
1704
|
+
INPUT:
|
|
1705
|
+
|
|
1706
|
+
- ``s_coeff`` -- dictionary whose keys are in `I \times I`, where
|
|
1707
|
+
`I` is the index set of the underlying vector space `V`, and whose
|
|
1708
|
+
values can be coerced into 1-forms (degree 1 elements) in ``E``
|
|
1709
|
+
(usually, these values will just be elements of `V`)
|
|
1710
|
+
|
|
1711
|
+
EXAMPLES::
|
|
1712
|
+
|
|
1713
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
1714
|
+
sage: E.boundary({(0,1): z, (1,2): x, (2,0): y})
|
|
1715
|
+
Boundary endomorphism of The exterior algebra of rank 3 over Rational Field
|
|
1716
|
+
"""
|
|
1717
|
+
return ExteriorAlgebraBoundary(self, s_coeff)
|
|
1718
|
+
|
|
1719
|
+
def coboundary(self, s_coeff):
|
|
1720
|
+
r"""
|
|
1721
|
+
Return the coboundary operator `d` defined by the structure
|
|
1722
|
+
coefficients ``s_coeff`` of a Lie algebra.
|
|
1723
|
+
|
|
1724
|
+
For more on the coboundary operator, see
|
|
1725
|
+
:class:`ExteriorAlgebraCoboundary`.
|
|
1726
|
+
|
|
1727
|
+
INPUT:
|
|
1728
|
+
|
|
1729
|
+
- ``s_coeff`` -- dictionary whose keys are in `I \times I`, where
|
|
1730
|
+
`I` is the index set of the underlying vector space `V`, and whose
|
|
1731
|
+
values can be coerced into 1-forms (degree 1 elements) in ``E``
|
|
1732
|
+
(usually, these values will just be elements of `V`)
|
|
1733
|
+
|
|
1734
|
+
EXAMPLES::
|
|
1735
|
+
|
|
1736
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
1737
|
+
sage: E.coboundary({(0,1): z, (1,2): x, (2,0): y})
|
|
1738
|
+
Coboundary endomorphism of The exterior algebra of rank 3 over Rational Field
|
|
1739
|
+
"""
|
|
1740
|
+
return ExteriorAlgebraCoboundary(self, s_coeff)
|
|
1741
|
+
|
|
1742
|
+
def degree_on_basis(self, m):
|
|
1743
|
+
r"""
|
|
1744
|
+
Return the degree of the monomial indexed by ``m``.
|
|
1745
|
+
|
|
1746
|
+
The degree of ``m`` in the `\ZZ`-grading of ``self`` is defined
|
|
1747
|
+
to be the length of ``m``.
|
|
1748
|
+
|
|
1749
|
+
EXAMPLES::
|
|
1750
|
+
|
|
1751
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
1752
|
+
sage: E.degree_on_basis(())
|
|
1753
|
+
0
|
|
1754
|
+
sage: E.degree_on_basis((0,))
|
|
1755
|
+
1
|
|
1756
|
+
sage: E.degree_on_basis((0,1))
|
|
1757
|
+
2
|
|
1758
|
+
"""
|
|
1759
|
+
return ZZ(len(m))
|
|
1760
|
+
|
|
1761
|
+
def coproduct_on_basis(self, a):
|
|
1762
|
+
r"""
|
|
1763
|
+
Return the coproduct on the basis element indexed by ``a``.
|
|
1764
|
+
|
|
1765
|
+
The coproduct is defined by
|
|
1766
|
+
|
|
1767
|
+
.. MATH::
|
|
1768
|
+
|
|
1769
|
+
\Delta(e_{i_1} \wedge \cdots \wedge e_{i_m}) = \sum_{k=0}^m
|
|
1770
|
+
\sum_{\sigma \in Ush_{k,m-k}} (-1)^{\sigma}
|
|
1771
|
+
(e_{i_{\sigma(1)}} \wedge \cdots \wedge e_{i_{\sigma(k)}}) \otimes
|
|
1772
|
+
(e_{i_{\sigma(k+1)}} \wedge \cdots \wedge e_{i_{\sigma(m)}}),
|
|
1773
|
+
|
|
1774
|
+
where `Ush_{k,m-k}` denotes the set of all `(k,m-k)`-unshuffles
|
|
1775
|
+
(i.e., permutations in `S_m` which are increasing on the interval
|
|
1776
|
+
`\{1, 2, \ldots, k\}` and on the interval
|
|
1777
|
+
`\{k+1, k+2, \ldots, k+m\}`).
|
|
1778
|
+
|
|
1779
|
+
.. WARNING::
|
|
1780
|
+
|
|
1781
|
+
This coproduct is a homomorphism of superalgebras, not a
|
|
1782
|
+
homomorphism of algebras!
|
|
1783
|
+
|
|
1784
|
+
EXAMPLES::
|
|
1785
|
+
|
|
1786
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
1787
|
+
sage: E.coproduct_on_basis((0,))
|
|
1788
|
+
1 # x + x # 1
|
|
1789
|
+
sage: E.coproduct_on_basis((0,1))
|
|
1790
|
+
1 # x*y + x # y - y # x + x*y # 1
|
|
1791
|
+
sage: E.coproduct_on_basis((0,1,2))
|
|
1792
|
+
1 # x*y*z + x # y*z - y # x*z + x*y # z
|
|
1793
|
+
+ z # x*y - x*z # y + y*z # x + x*y*z # 1
|
|
1794
|
+
"""
|
|
1795
|
+
from sage.combinat.combinat import unshuffle_iterator
|
|
1796
|
+
one = self.base_ring().one()
|
|
1797
|
+
L = unshuffle_iterator(tuple(a), one)
|
|
1798
|
+
return self.tensor_square()._from_dict(
|
|
1799
|
+
{tuple(FrozenBitset(e) if e else FrozenBitset() for e in t): c for t, c in L if c},
|
|
1800
|
+
coerce=False,
|
|
1801
|
+
remove_zeros=False)
|
|
1802
|
+
|
|
1803
|
+
def antipode_on_basis(self, m):
|
|
1804
|
+
r"""
|
|
1805
|
+
Return the antipode on the basis element indexed by ``m``.
|
|
1806
|
+
|
|
1807
|
+
Given a basis element `\omega`, the antipode is defined by
|
|
1808
|
+
`S(\omega) = (-1)^{\deg(\omega)} \omega`.
|
|
1809
|
+
|
|
1810
|
+
EXAMPLES::
|
|
1811
|
+
|
|
1812
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
1813
|
+
sage: E.antipode_on_basis(())
|
|
1814
|
+
1
|
|
1815
|
+
sage: E.antipode_on_basis((1,))
|
|
1816
|
+
-y
|
|
1817
|
+
sage: E.antipode_on_basis((1,2))
|
|
1818
|
+
y*z
|
|
1819
|
+
"""
|
|
1820
|
+
return self.term(m, (-self.base_ring().one())**len(m))
|
|
1821
|
+
|
|
1822
|
+
def counit(self, x):
|
|
1823
|
+
r"""
|
|
1824
|
+
Return the counit of ``x``.
|
|
1825
|
+
|
|
1826
|
+
The counit of an element `\omega` of the exterior algebra
|
|
1827
|
+
is its constant coefficient.
|
|
1828
|
+
|
|
1829
|
+
EXAMPLES::
|
|
1830
|
+
|
|
1831
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
1832
|
+
sage: elt = x*y - 2*x + 3
|
|
1833
|
+
sage: E.counit(elt)
|
|
1834
|
+
3
|
|
1835
|
+
"""
|
|
1836
|
+
return x.constant_coefficient()
|
|
1837
|
+
|
|
1838
|
+
def interior_product_on_basis(self, a, b):
|
|
1839
|
+
r"""
|
|
1840
|
+
Return the interior product `\iota_b a` of ``a`` with respect to
|
|
1841
|
+
``b``.
|
|
1842
|
+
|
|
1843
|
+
See :meth:`~sage.algebras.clifford_algebra.CliffordAlgebra.Element.interior_product`
|
|
1844
|
+
for more information.
|
|
1845
|
+
|
|
1846
|
+
In this method, ``a`` and ``b`` are supposed to be
|
|
1847
|
+
basis elements (see
|
|
1848
|
+
:meth:`~sage.algebras.clifford_algebra.CliffordAlgebra.Element.interior_product`
|
|
1849
|
+
for a method that computes interior product of arbitrary
|
|
1850
|
+
elements), and to be input as their keys.
|
|
1851
|
+
|
|
1852
|
+
This depends on the choice of basis of the vector space
|
|
1853
|
+
whose exterior algebra is ``self``.
|
|
1854
|
+
|
|
1855
|
+
EXAMPLES::
|
|
1856
|
+
|
|
1857
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
1858
|
+
sage: k = list(E.basis().keys())
|
|
1859
|
+
sage: E.interior_product_on_basis(k[1], k[1])
|
|
1860
|
+
1
|
|
1861
|
+
sage: E.interior_product_on_basis(k[5], k[1])
|
|
1862
|
+
z
|
|
1863
|
+
sage: E.interior_product_on_basis(k[2], k[5])
|
|
1864
|
+
0
|
|
1865
|
+
sage: E.interior_product_on_basis(k[5], k[2])
|
|
1866
|
+
0
|
|
1867
|
+
sage: E.interior_product_on_basis(k[7], k[5])
|
|
1868
|
+
-y
|
|
1869
|
+
|
|
1870
|
+
Check :issue:`34694`::
|
|
1871
|
+
|
|
1872
|
+
sage: # needs sage.symbolic
|
|
1873
|
+
sage: E = ExteriorAlgebra(SR,'e',3)
|
|
1874
|
+
sage: E.inject_variables()
|
|
1875
|
+
Defining e0, e1, e2
|
|
1876
|
+
sage: a = (e0*e1).interior_product(e0)
|
|
1877
|
+
sage: a * e0
|
|
1878
|
+
-e0*e1
|
|
1879
|
+
"""
|
|
1880
|
+
sgn = True
|
|
1881
|
+
t = list(a)
|
|
1882
|
+
for i in b:
|
|
1883
|
+
if i not in t:
|
|
1884
|
+
return self.zero()
|
|
1885
|
+
if t.index(i) % 2:
|
|
1886
|
+
sgn = not sgn
|
|
1887
|
+
t.remove(i)
|
|
1888
|
+
R = self.base_ring()
|
|
1889
|
+
if not t: # catch empty sets
|
|
1890
|
+
t = None
|
|
1891
|
+
return self.term(FrozenBitset(t), (R.one() if sgn else - R.one()))
|
|
1892
|
+
|
|
1893
|
+
def lifted_bilinear_form(self, M):
|
|
1894
|
+
r"""
|
|
1895
|
+
Return the bilinear form on the exterior algebra ``self``
|
|
1896
|
+
`= \Lambda(V)` which is obtained by lifting the bilinear
|
|
1897
|
+
form `f` on `V` given by the matrix ``M``.
|
|
1898
|
+
|
|
1899
|
+
Let `V` be a module over a commutative ring `R`, and let
|
|
1900
|
+
`f : V \times V \to R` be a bilinear form on `V`. Then,
|
|
1901
|
+
a bilinear form `\Lambda(f) : \Lambda(V) \times
|
|
1902
|
+
\Lambda(V) \to R` on `\Lambda(V)` can be canonically
|
|
1903
|
+
defined as follows: For every `n \in \NN`, `m \in \NN`,
|
|
1904
|
+
`v_1, v_2, \ldots, v_n, w_1, w_2, \ldots, w_m \in V`,
|
|
1905
|
+
we define
|
|
1906
|
+
|
|
1907
|
+
.. MATH::
|
|
1908
|
+
|
|
1909
|
+
\Lambda(f)
|
|
1910
|
+
( v_1 \wedge v_2 \wedge \cdots \wedge v_n ,
|
|
1911
|
+
w_1 \wedge w_2 \wedge \cdots \wedge w_m )
|
|
1912
|
+
:= \begin{cases}
|
|
1913
|
+
0, &\mbox{if } n \neq m ; \\
|
|
1914
|
+
\det G, & \mbox{if } n = m \end{cases} ,
|
|
1915
|
+
|
|
1916
|
+
where `G` is the `n \times m`-matrix whose
|
|
1917
|
+
`(i, j)`-th entry is `f(v_i, w_j)`. This bilinear form
|
|
1918
|
+
`\Lambda(f)` is known as the bilinear form on
|
|
1919
|
+
`\Lambda(V)` obtained by lifting the bilinear form `f`.
|
|
1920
|
+
Its restriction to the `1`-st homogeneous component
|
|
1921
|
+
`V` of `\Lambda(V)` is `f`.
|
|
1922
|
+
|
|
1923
|
+
The bilinear form `\Lambda(f)` is symmetric if `f` is.
|
|
1924
|
+
|
|
1925
|
+
INPUT:
|
|
1926
|
+
|
|
1927
|
+
- ``M`` -- a matrix over the same base ring as ``self``,
|
|
1928
|
+
whose `(i, j)`-th entry is `f(e_i, e_j)`, where
|
|
1929
|
+
`(e_1, e_2, \ldots, e_N)` is the standard basis of the
|
|
1930
|
+
module `V` for which ``self`` `= \Lambda(V)` (so that
|
|
1931
|
+
`N = \dim(V)`), and where `f` is the bilinear form
|
|
1932
|
+
which is to be lifted.
|
|
1933
|
+
|
|
1934
|
+
OUTPUT:
|
|
1935
|
+
|
|
1936
|
+
A bivariate function which takes two elements `p` and
|
|
1937
|
+
`q` of ``self`` to `\Lambda(f)(p, q)`.
|
|
1938
|
+
|
|
1939
|
+
.. NOTE::
|
|
1940
|
+
|
|
1941
|
+
This takes a bilinear form on `V` as matrix, and
|
|
1942
|
+
returns a bilinear form on ``self`` as a function in
|
|
1943
|
+
two arguments. We do not return the bilinear form as
|
|
1944
|
+
a matrix since this matrix can be huge and one often
|
|
1945
|
+
needs just a particular value.
|
|
1946
|
+
|
|
1947
|
+
.. TODO::
|
|
1948
|
+
|
|
1949
|
+
Implement a class for bilinear forms and rewrite this
|
|
1950
|
+
method to use that class.
|
|
1951
|
+
|
|
1952
|
+
EXAMPLES::
|
|
1953
|
+
|
|
1954
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
1955
|
+
sage: M = Matrix(QQ, [[1, 2, 3], [2, 3, 4], [3, 4, 5]])
|
|
1956
|
+
sage: Eform = E.lifted_bilinear_form(M)
|
|
1957
|
+
sage: Eform
|
|
1958
|
+
Bilinear Form from The exterior algebra of rank 3 over Rational
|
|
1959
|
+
Field (+) The exterior algebra of rank 3 over Rational Field to
|
|
1960
|
+
Rational Field
|
|
1961
|
+
sage: Eform(x*y, y*z)
|
|
1962
|
+
-1
|
|
1963
|
+
sage: Eform(x*y, y)
|
|
1964
|
+
0
|
|
1965
|
+
sage: Eform(x*(y+z), y*z)
|
|
1966
|
+
-3
|
|
1967
|
+
sage: Eform(x*(y+z), y*(z+x))
|
|
1968
|
+
0
|
|
1969
|
+
sage: N = Matrix(QQ, [[3, 1, 7], [2, 0, 4], [-1, -3, -1]])
|
|
1970
|
+
sage: N.determinant()
|
|
1971
|
+
-8
|
|
1972
|
+
sage: Eform = E.lifted_bilinear_form(N)
|
|
1973
|
+
sage: Eform(x, E.one())
|
|
1974
|
+
0
|
|
1975
|
+
sage: Eform(x, x*z*y)
|
|
1976
|
+
0
|
|
1977
|
+
sage: Eform(E.one(), E.one())
|
|
1978
|
+
1
|
|
1979
|
+
sage: Eform(E.zero(), E.one())
|
|
1980
|
+
0
|
|
1981
|
+
sage: Eform(x, y)
|
|
1982
|
+
1
|
|
1983
|
+
sage: Eform(z, y)
|
|
1984
|
+
-3
|
|
1985
|
+
sage: Eform(x*z, y*z)
|
|
1986
|
+
20
|
|
1987
|
+
sage: Eform(x+x*y+x*y*z, z+z*y+z*y*x)
|
|
1988
|
+
11
|
|
1989
|
+
|
|
1990
|
+
TESTS:
|
|
1991
|
+
|
|
1992
|
+
Exterior algebra over a zero space (a border case)::
|
|
1993
|
+
|
|
1994
|
+
sage: E = ExteriorAlgebra(QQ, 0)
|
|
1995
|
+
sage: M = Matrix(QQ, [])
|
|
1996
|
+
sage: Eform = E.lifted_bilinear_form(M)
|
|
1997
|
+
sage: Eform(E.one(), E.one())
|
|
1998
|
+
1
|
|
1999
|
+
sage: Eform(E.zero(), E.one())
|
|
2000
|
+
0
|
|
2001
|
+
|
|
2002
|
+
.. TODO::
|
|
2003
|
+
|
|
2004
|
+
Another way to compute this bilinear form seems to be to
|
|
2005
|
+
map `x` and `y` to the appropriate Clifford algebra and
|
|
2006
|
+
there compute `x^t y`, then send the result back to the
|
|
2007
|
+
exterior algebra and return its constant coefficient. Or
|
|
2008
|
+
something like this. Once the maps to the Clifford and
|
|
2009
|
+
back are implemented, check if this is faster.
|
|
2010
|
+
"""
|
|
2011
|
+
R = self.base_ring()
|
|
2012
|
+
|
|
2013
|
+
def lifted_form(x, y):
|
|
2014
|
+
result = R.zero()
|
|
2015
|
+
for mx, cx in x:
|
|
2016
|
+
for my, cy in y:
|
|
2017
|
+
n = len(mx)
|
|
2018
|
+
m = len(my)
|
|
2019
|
+
if m != n:
|
|
2020
|
+
continue
|
|
2021
|
+
matrix_list = [M[i, j] for i in mx for j in my]
|
|
2022
|
+
MA = MatrixArgs(R, n, matrix_list)
|
|
2023
|
+
del matrix_list
|
|
2024
|
+
result += cx * cy * MA.matrix(False).determinant()
|
|
2025
|
+
return result
|
|
2026
|
+
from sage.categories.cartesian_product import cartesian_product
|
|
2027
|
+
return PoorManMap(lifted_form, domain=cartesian_product([self, self]),
|
|
2028
|
+
codomain=self.base_ring(),
|
|
2029
|
+
name="Bilinear Form")
|
|
2030
|
+
|
|
2031
|
+
def _ideal_class_(self, n=0):
|
|
2032
|
+
"""
|
|
2033
|
+
Return the class that is used to implement ideals of ``self``.
|
|
2034
|
+
|
|
2035
|
+
EXAMPLES::
|
|
2036
|
+
|
|
2037
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
2038
|
+
sage: type(E.ideal(x*y - z))
|
|
2039
|
+
<class 'sage.algebras.clifford_algebra.ExteriorAlgebraIdeal'>
|
|
2040
|
+
|
|
2041
|
+
TESTS::
|
|
2042
|
+
|
|
2043
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
2044
|
+
sage: E._ideal_class_()
|
|
2045
|
+
<class 'sage.algebras.clifford_algebra.ExteriorAlgebraIdeal'>
|
|
2046
|
+
"""
|
|
2047
|
+
return ExteriorAlgebraIdeal
|
|
2048
|
+
|
|
2049
|
+
Element = ExteriorAlgebraElement
|
|
2050
|
+
|
|
2051
|
+
|
|
2052
|
+
#####################################################################
|
|
2053
|
+
# Differentials
|
|
2054
|
+
|
|
2055
|
+
|
|
2056
|
+
class ExteriorAlgebraDifferential(ModuleMorphismByLinearity,
|
|
2057
|
+
UniqueRepresentation,
|
|
2058
|
+
metaclass=InheritComparisonClasscallMetaclass):
|
|
2059
|
+
r"""
|
|
2060
|
+
Internal class to store the data of a boundary or coboundary of
|
|
2061
|
+
an exterior algebra `\Lambda(L)` defined by the structure
|
|
2062
|
+
coefficients of a Lie algebra `L`.
|
|
2063
|
+
|
|
2064
|
+
See :class:`ExteriorAlgebraBoundary` and
|
|
2065
|
+
:class:`ExteriorAlgebraCoboundary` for the actual classes, which
|
|
2066
|
+
inherit from this.
|
|
2067
|
+
|
|
2068
|
+
.. WARNING::
|
|
2069
|
+
|
|
2070
|
+
This is not a general class for differentials on the exterior
|
|
2071
|
+
algebra.
|
|
2072
|
+
"""
|
|
2073
|
+
@staticmethod
|
|
2074
|
+
def __classcall__(cls, E, s_coeff):
|
|
2075
|
+
"""
|
|
2076
|
+
Standardize the structure coefficients to ensure a unique
|
|
2077
|
+
representation.
|
|
2078
|
+
|
|
2079
|
+
EXAMPLES::
|
|
2080
|
+
|
|
2081
|
+
sage: from sage.algebras.clifford_algebra import ExteriorAlgebraDifferential
|
|
2082
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
2083
|
+
sage: par1 = ExteriorAlgebraDifferential(E, {(0,1): z, (1,2): x, (2,0): y})
|
|
2084
|
+
sage: par2 = ExteriorAlgebraDifferential(E, {(0,1): z, (1,2): x, (0,2): -y})
|
|
2085
|
+
sage: par3 = ExteriorAlgebraDifferential(E, {(1,0): {2:-1}, (1,2): {0:1}, (2,0):{1:1}})
|
|
2086
|
+
sage: par1 is par2
|
|
2087
|
+
True
|
|
2088
|
+
sage: par1 is par3
|
|
2089
|
+
True
|
|
2090
|
+
sage: par2 is par3
|
|
2091
|
+
True
|
|
2092
|
+
|
|
2093
|
+
sage: par4 = ExteriorAlgebraDifferential(E, {})
|
|
2094
|
+
sage: par5 = ExteriorAlgebraDifferential(E, {(1,0): 0, (1,2): {}, (0,2): E.zero()})
|
|
2095
|
+
sage: par6 = ExteriorAlgebraDifferential(E, {(1,0): 0, (1,2): 0, (0,2): 0})
|
|
2096
|
+
sage: par4 is par5 and par5 is par6
|
|
2097
|
+
True
|
|
2098
|
+
"""
|
|
2099
|
+
d = {}
|
|
2100
|
+
|
|
2101
|
+
for k, v in dict(s_coeff).items():
|
|
2102
|
+
if not v: # Strip terms with 0
|
|
2103
|
+
continue
|
|
2104
|
+
|
|
2105
|
+
if isinstance(v, dict):
|
|
2106
|
+
R = E.base_ring()
|
|
2107
|
+
v = E._from_dict({FrozenBitset((i,)): R(c) for i, c in v.items()})
|
|
2108
|
+
else:
|
|
2109
|
+
# Make sure v is in ``E``
|
|
2110
|
+
v = E(v)
|
|
2111
|
+
# It's okay if v.degree results in an error
|
|
2112
|
+
# (we'd throw a similar error) unless v == 0 (which
|
|
2113
|
+
# is what v.list() is testing for)
|
|
2114
|
+
if v.list() and v.degree() != 1:
|
|
2115
|
+
raise ValueError("elements must be degree 1")
|
|
2116
|
+
|
|
2117
|
+
if k[0] < k[1]:
|
|
2118
|
+
d[tuple(k)] = v
|
|
2119
|
+
else:
|
|
2120
|
+
d[(k[1], k[0])] = -v
|
|
2121
|
+
|
|
2122
|
+
from sage.sets.family import Family
|
|
2123
|
+
return super().__classcall__(cls, E, Family(d))
|
|
2124
|
+
|
|
2125
|
+
def __init__(self, E, s_coeff):
|
|
2126
|
+
"""
|
|
2127
|
+
Initialize ``self``.
|
|
2128
|
+
|
|
2129
|
+
EXAMPLES::
|
|
2130
|
+
|
|
2131
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
2132
|
+
sage: par = E.boundary({(0,1): z, (1,2):x, (2,0):y})
|
|
2133
|
+
|
|
2134
|
+
We skip the pickling test as there is an infinite recursion when
|
|
2135
|
+
doing equality checks::
|
|
2136
|
+
|
|
2137
|
+
sage: TestSuite(par).run(skip='_test_pickling')
|
|
2138
|
+
|
|
2139
|
+
Check that it knows it is a finite-dimensional algebra
|
|
2140
|
+
morphism (:issue:`25339`):;
|
|
2141
|
+
|
|
2142
|
+
sage: par.category_for()
|
|
2143
|
+
Category of finite dimensional algebras with basis over Rational Field
|
|
2144
|
+
sage: par.matrix()
|
|
2145
|
+
[ 0 0 0 0 0 0 0 0]
|
|
2146
|
+
[ 0 0 0 0 0 0 1 0]
|
|
2147
|
+
[ 0 0 0 0 0 -1 0 0]
|
|
2148
|
+
[ 0 0 0 0 1 0 0 0]
|
|
2149
|
+
[ 0 0 0 0 0 0 0 0]
|
|
2150
|
+
[ 0 0 0 0 0 0 0 0]
|
|
2151
|
+
[ 0 0 0 0 0 0 0 0]
|
|
2152
|
+
[ 0 0 0 0 0 0 0 0]
|
|
2153
|
+
"""
|
|
2154
|
+
self._s_coeff = s_coeff
|
|
2155
|
+
|
|
2156
|
+
# Technically this preserves the grading but with a shift of -1
|
|
2157
|
+
cat = AlgebrasWithBasis(E.base_ring()).FiniteDimensional()
|
|
2158
|
+
ModuleMorphismByLinearity.__init__(self, domain=E, codomain=E, category=cat)
|
|
2159
|
+
|
|
2160
|
+
def homology(self, deg=None, **kwds):
|
|
2161
|
+
"""
|
|
2162
|
+
Return the homology determined by ``self``.
|
|
2163
|
+
|
|
2164
|
+
EXAMPLES::
|
|
2165
|
+
|
|
2166
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
2167
|
+
sage: par = E.boundary({(0,1): z, (1,2): x, (2,0): y})
|
|
2168
|
+
sage: par.homology()
|
|
2169
|
+
{0: Vector space of dimension 1 over Rational Field,
|
|
2170
|
+
1: Vector space of dimension 0 over Rational Field,
|
|
2171
|
+
2: Vector space of dimension 0 over Rational Field,
|
|
2172
|
+
3: Vector space of dimension 1 over Rational Field}
|
|
2173
|
+
sage: d = E.coboundary({(0,1): z, (1,2): x, (2,0): y})
|
|
2174
|
+
sage: d.homology()
|
|
2175
|
+
{0: Vector space of dimension 1 over Rational Field,
|
|
2176
|
+
1: Vector space of dimension 0 over Rational Field,
|
|
2177
|
+
2: Vector space of dimension 0 over Rational Field,
|
|
2178
|
+
3: Vector space of dimension 1 over Rational Field}
|
|
2179
|
+
"""
|
|
2180
|
+
return self.chain_complex().homology(deg, **kwds)
|
|
2181
|
+
|
|
2182
|
+
|
|
2183
|
+
class ExteriorAlgebraBoundary(ExteriorAlgebraDifferential):
|
|
2184
|
+
r"""
|
|
2185
|
+
The boundary `\partial` of an exterior algebra `\Lambda(L)` defined
|
|
2186
|
+
by the structure coefficients of `L`.
|
|
2187
|
+
|
|
2188
|
+
Let `L` be a Lie algebra. We give the exterior algebra
|
|
2189
|
+
`E = \Lambda(L)` a chain complex structure by considering a
|
|
2190
|
+
differential `\partial : \Lambda^{k+1}(L) \to \Lambda^k(L)` defined by
|
|
2191
|
+
|
|
2192
|
+
.. MATH::
|
|
2193
|
+
|
|
2194
|
+
\partial(x_1 \wedge x_2 \wedge \cdots \wedge x_{k+1})
|
|
2195
|
+
= \sum_{i < j} (-1)^{i+j+1}
|
|
2196
|
+
[x_i, x_j] \wedge x_1 \wedge \cdots \wedge \hat{x}_i \wedge \cdots
|
|
2197
|
+
\wedge \hat{x}_j \wedge \cdots \wedge x_{k+1}
|
|
2198
|
+
|
|
2199
|
+
where `\hat{x}_i` denotes a missing index. The corresponding homology is
|
|
2200
|
+
the Lie algebra homology.
|
|
2201
|
+
|
|
2202
|
+
INPUT:
|
|
2203
|
+
|
|
2204
|
+
- ``E`` -- an exterior algebra of a vector space `L`
|
|
2205
|
+
- ``s_coeff`` -- dictionary whose keys are in `I \times I`, where
|
|
2206
|
+
`I` is the index set of the basis of the vector space `L`, and whose
|
|
2207
|
+
values can be coerced into 1-forms (degree 1 elements) in ``E``;
|
|
2208
|
+
this dictionary will be used to define the Lie algebra structure
|
|
2209
|
+
on `L` (indeed, the `i`-th coordinate of the Lie bracket of the
|
|
2210
|
+
`j`-th and `k`-th basis vectors of `L` for `j < k` is set to be
|
|
2211
|
+
the value at the key `(j, k)` if this key appears in ``s_coeff``,
|
|
2212
|
+
or otherwise the negated of the value at the key `(k, j)`)
|
|
2213
|
+
|
|
2214
|
+
.. WARNING::
|
|
2215
|
+
|
|
2216
|
+
The values of ``s_coeff`` are supposed to be coercible into
|
|
2217
|
+
1-forms in ``E``; but they can also be dictionaries themselves
|
|
2218
|
+
(in which case they are interpreted as giving the coordinates of
|
|
2219
|
+
vectors in ``L``). In the interest of speed, these dictionaries
|
|
2220
|
+
are not sanitized or checked.
|
|
2221
|
+
|
|
2222
|
+
.. WARNING::
|
|
2223
|
+
|
|
2224
|
+
For any two distinct elements `i` and `j` of `I`, the dictionary
|
|
2225
|
+
``s_coeff`` must have only one of the pairs `(i, j)` and
|
|
2226
|
+
`(j, i)` as a key. This is not checked.
|
|
2227
|
+
|
|
2228
|
+
EXAMPLES:
|
|
2229
|
+
|
|
2230
|
+
We consider the differential given by Lie algebra given by the cross
|
|
2231
|
+
product `\times` of `\RR^3`::
|
|
2232
|
+
|
|
2233
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
2234
|
+
sage: par = E.boundary({(0,1): z, (1,2): x, (2,0): y})
|
|
2235
|
+
sage: par(x)
|
|
2236
|
+
0
|
|
2237
|
+
sage: par(x*y)
|
|
2238
|
+
z
|
|
2239
|
+
sage: par(x*y*z)
|
|
2240
|
+
0
|
|
2241
|
+
sage: par(x+y-y*z+x*y)
|
|
2242
|
+
-x + z
|
|
2243
|
+
sage: par(E.zero())
|
|
2244
|
+
0
|
|
2245
|
+
|
|
2246
|
+
We check that `\partial \circ \partial = 0`::
|
|
2247
|
+
|
|
2248
|
+
sage: p2 = par * par
|
|
2249
|
+
sage: all(p2(b) == 0 for b in E.basis())
|
|
2250
|
+
True
|
|
2251
|
+
|
|
2252
|
+
Another example: the Lie algebra `\mathfrak{sl}_2`, which has a
|
|
2253
|
+
basis `e,f,h` satisfying `[h,e] = 2e`, `[h,f] = -2f`, and `[e,f] = h`::
|
|
2254
|
+
|
|
2255
|
+
sage: E.<e,f,h> = ExteriorAlgebra(QQ)
|
|
2256
|
+
sage: par = E.boundary({(0,1): h, (2,1): -2*f, (2,0): 2*e})
|
|
2257
|
+
sage: par(E.zero())
|
|
2258
|
+
0
|
|
2259
|
+
sage: par(e)
|
|
2260
|
+
0
|
|
2261
|
+
sage: par(e*f)
|
|
2262
|
+
h
|
|
2263
|
+
sage: par(f*h)
|
|
2264
|
+
2*f
|
|
2265
|
+
sage: par(h*f)
|
|
2266
|
+
-2*f
|
|
2267
|
+
sage: C = par.chain_complex(); C
|
|
2268
|
+
Chain complex with at most 4 nonzero terms over Rational Field
|
|
2269
|
+
sage: ascii_art(C)
|
|
2270
|
+
[ 0 -2 0] [0]
|
|
2271
|
+
[ 0 0 2] [0]
|
|
2272
|
+
[0 0 0] [ 1 0 0] [0]
|
|
2273
|
+
0 <-- C_0 <-------- C_1 <----------- C_2 <---- C_3 <-- 0
|
|
2274
|
+
sage: C.homology()
|
|
2275
|
+
{0: Vector space of dimension 1 over Rational Field,
|
|
2276
|
+
1: Vector space of dimension 0 over Rational Field,
|
|
2277
|
+
2: Vector space of dimension 0 over Rational Field,
|
|
2278
|
+
3: Vector space of dimension 1 over Rational Field}
|
|
2279
|
+
|
|
2280
|
+
Over the integers::
|
|
2281
|
+
|
|
2282
|
+
sage: C = par.chain_complex(R=ZZ); C
|
|
2283
|
+
Chain complex with at most 4 nonzero terms over Integer Ring
|
|
2284
|
+
sage: ascii_art(C)
|
|
2285
|
+
[ 0 -2 0] [0]
|
|
2286
|
+
[ 0 0 2] [0]
|
|
2287
|
+
[0 0 0] [ 1 0 0] [0]
|
|
2288
|
+
0 <-- C_0 <-------- C_1 <----------- C_2 <---- C_3 <-- 0
|
|
2289
|
+
sage: C.homology() # needs sage.libs.pari
|
|
2290
|
+
{0: Z, 1: C2 x C2, 2: 0, 3: Z}
|
|
2291
|
+
|
|
2292
|
+
REFERENCES:
|
|
2293
|
+
|
|
2294
|
+
- :wikipedia:`Exterior_algebra#Lie_algebra_homology`
|
|
2295
|
+
"""
|
|
2296
|
+
def _repr_type(self):
|
|
2297
|
+
"""
|
|
2298
|
+
TESTS::
|
|
2299
|
+
|
|
2300
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
2301
|
+
sage: par = E.boundary({(0,1): z, (1,2): x, (2,0): y})
|
|
2302
|
+
sage: par._repr_type()
|
|
2303
|
+
'Boundary'
|
|
2304
|
+
"""
|
|
2305
|
+
return "Boundary"
|
|
2306
|
+
|
|
2307
|
+
def _on_basis(self, m):
|
|
2308
|
+
"""
|
|
2309
|
+
Return the differential on the basis element indexed by ``m``.
|
|
2310
|
+
|
|
2311
|
+
EXAMPLES::
|
|
2312
|
+
|
|
2313
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
2314
|
+
sage: par = E.boundary({(0,1): z, (1,2): x, (2,0): y})
|
|
2315
|
+
sage: par._on_basis(FrozenBitset())
|
|
2316
|
+
0
|
|
2317
|
+
sage: par._on_basis((0,))
|
|
2318
|
+
0
|
|
2319
|
+
sage: par._on_basis((0,1))
|
|
2320
|
+
z
|
|
2321
|
+
sage: par._on_basis((0,2))
|
|
2322
|
+
-y
|
|
2323
|
+
sage: par._on_basis((0,1,2))
|
|
2324
|
+
0
|
|
2325
|
+
"""
|
|
2326
|
+
from itertools import combinations
|
|
2327
|
+
E = self.domain()
|
|
2328
|
+
sc = self._s_coeff
|
|
2329
|
+
keys = sc.keys()
|
|
2330
|
+
|
|
2331
|
+
s = E.zero()
|
|
2332
|
+
|
|
2333
|
+
for b, (i, j) in enumerate(combinations(m, 2)):
|
|
2334
|
+
if (i, j) not in keys:
|
|
2335
|
+
continue
|
|
2336
|
+
t = Bitset(m)
|
|
2337
|
+
t.discard(i)
|
|
2338
|
+
t.discard(j)
|
|
2339
|
+
s += sc[i, j] * E.term(FrozenBitset(t), (-1)**b)
|
|
2340
|
+
|
|
2341
|
+
return s
|
|
2342
|
+
|
|
2343
|
+
@cached_method
|
|
2344
|
+
def chain_complex(self, R=None):
|
|
2345
|
+
"""
|
|
2346
|
+
Return the chain complex over ``R`` determined by ``self``.
|
|
2347
|
+
|
|
2348
|
+
INPUT:
|
|
2349
|
+
|
|
2350
|
+
- ``R`` -- the base ring; the default is the base ring of
|
|
2351
|
+
the exterior algebra
|
|
2352
|
+
|
|
2353
|
+
EXAMPLES::
|
|
2354
|
+
|
|
2355
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
2356
|
+
sage: par = E.boundary({(0,1): z, (1,2): x, (2,0): y})
|
|
2357
|
+
sage: C = par.chain_complex(); C
|
|
2358
|
+
Chain complex with at most 4 nonzero terms over Rational Field
|
|
2359
|
+
sage: ascii_art(C)
|
|
2360
|
+
[ 0 0 1] [0]
|
|
2361
|
+
[ 0 -1 0] [0]
|
|
2362
|
+
[0 0 0] [ 1 0 0] [0]
|
|
2363
|
+
0 <-- C_0 <-------- C_1 <----------- C_2 <---- C_3 <-- 0
|
|
2364
|
+
|
|
2365
|
+
TESTS:
|
|
2366
|
+
|
|
2367
|
+
This still works in degree `1`::
|
|
2368
|
+
|
|
2369
|
+
sage: E.<x> = ExteriorAlgebra(QQ)
|
|
2370
|
+
sage: par = E.boundary({})
|
|
2371
|
+
sage: C = par.chain_complex(); C
|
|
2372
|
+
Chain complex with at most 2 nonzero terms over Rational Field
|
|
2373
|
+
sage: ascii_art(C)
|
|
2374
|
+
[0]
|
|
2375
|
+
0 <-- C_0 <---- C_1 <-- 0
|
|
2376
|
+
|
|
2377
|
+
Also in degree `0`::
|
|
2378
|
+
|
|
2379
|
+
sage: E = ExteriorAlgebra(QQ, 0)
|
|
2380
|
+
sage: par = E.boundary({})
|
|
2381
|
+
sage: C = par.chain_complex(); C
|
|
2382
|
+
Chain complex with at most 1 nonzero terms over Rational Field
|
|
2383
|
+
sage: ascii_art(C)
|
|
2384
|
+
0 <-- C_0 <-- 0
|
|
2385
|
+
"""
|
|
2386
|
+
from sage.homology.chain_complex import ChainComplex
|
|
2387
|
+
from sage.matrix.constructor import Matrix
|
|
2388
|
+
E = self.domain()
|
|
2389
|
+
n = E.ngens()
|
|
2390
|
+
if R is None:
|
|
2391
|
+
R = E.base_ring()
|
|
2392
|
+
|
|
2393
|
+
if n == 0:
|
|
2394
|
+
# Special case because there are no matrices and thus the
|
|
2395
|
+
# ChainComplex constructor needs the dimension of the
|
|
2396
|
+
# 0th degree space explicitly given.
|
|
2397
|
+
return ChainComplex({1: Matrix(R, [[]])}, degree=-1)
|
|
2398
|
+
# If you are reading this because you changed something about
|
|
2399
|
+
# the ChainComplex constructor and the doctests are failing:
|
|
2400
|
+
# This should return a chain complex with degree -1 and
|
|
2401
|
+
# only one nontrivial module, namely a free module of rank 1,
|
|
2402
|
+
# situated in degree 0.
|
|
2403
|
+
|
|
2404
|
+
# Group the basis into degrees
|
|
2405
|
+
basis_by_deg = {deg: [] for deg in range(n+1)}
|
|
2406
|
+
for b in E.basis().keys():
|
|
2407
|
+
basis_by_deg[len(b)].append(b)
|
|
2408
|
+
|
|
2409
|
+
# Construct the transition matrices
|
|
2410
|
+
data = {}
|
|
2411
|
+
prev_basis = basis_by_deg[0]
|
|
2412
|
+
for deg in range(1, n+1):
|
|
2413
|
+
# Make sure within each basis we're sorted by lex
|
|
2414
|
+
basis = sorted(basis_by_deg[deg])
|
|
2415
|
+
mat = []
|
|
2416
|
+
for b in basis:
|
|
2417
|
+
ret = self._on_basis(b)
|
|
2418
|
+
mat.append([ret.coefficient(p) for p in prev_basis])
|
|
2419
|
+
data[deg] = Matrix(mat).transpose().change_ring(R)
|
|
2420
|
+
prev_basis = basis
|
|
2421
|
+
|
|
2422
|
+
return ChainComplex(data, degree=-1)
|
|
2423
|
+
|
|
2424
|
+
|
|
2425
|
+
class ExteriorAlgebraCoboundary(ExteriorAlgebraDifferential):
|
|
2426
|
+
r"""
|
|
2427
|
+
The coboundary `d` of an exterior algebra `\Lambda(L)` defined
|
|
2428
|
+
by the structure coefficients of a Lie algebra `L`.
|
|
2429
|
+
|
|
2430
|
+
Let `L` be a Lie algebra. We endow its exterior algebra
|
|
2431
|
+
`E = \Lambda(L)` with a cochain complex structure by considering a
|
|
2432
|
+
differential `d : \Lambda^k(L) \to \Lambda^{k+1}(L)` defined by
|
|
2433
|
+
|
|
2434
|
+
.. MATH::
|
|
2435
|
+
|
|
2436
|
+
d x_i = \sum_{j < k} s_{jk}^i x_j x_k,
|
|
2437
|
+
|
|
2438
|
+
where `(x_1, x_2, \ldots, x_n)` is a basis of `L`, and where
|
|
2439
|
+
`s_{jk}^i` is the `x_i`-coordinate of the Lie bracket `[x_j, x_k]`.
|
|
2440
|
+
|
|
2441
|
+
The corresponding cohomology is the Lie algebra cohomology of `L`.
|
|
2442
|
+
|
|
2443
|
+
This can also be thought of as the exterior derivative, in which case
|
|
2444
|
+
the resulting cohomology is the de Rham cohomology of a manifold whose
|
|
2445
|
+
exterior algebra of differential forms is ``E``.
|
|
2446
|
+
|
|
2447
|
+
INPUT:
|
|
2448
|
+
|
|
2449
|
+
- ``E`` -- an exterior algebra of a vector space `L`
|
|
2450
|
+
- ``s_coeff`` -- dictionary whose keys are in `I \times I`, where
|
|
2451
|
+
`I` is the index set of the basis of the vector space `L`, and whose
|
|
2452
|
+
values can be coerced into 1-forms (degree 1 elements) in ``E``;
|
|
2453
|
+
this dictionary will be used to define the Lie algebra structure
|
|
2454
|
+
on `L` (indeed, the `i`-th coordinate of the Lie bracket of the
|
|
2455
|
+
`j`-th and `k`-th basis vectors of `L` for `j < k` is set to be
|
|
2456
|
+
the value at the key `(j, k)` if this key appears in ``s_coeff``,
|
|
2457
|
+
or otherwise the negated of the value at the key `(k, j)`)
|
|
2458
|
+
|
|
2459
|
+
.. WARNING::
|
|
2460
|
+
|
|
2461
|
+
For any two distinct elements `i` and `j` of `I`, the dictionary
|
|
2462
|
+
``s_coeff`` must have only one of the pairs `(i, j)` and
|
|
2463
|
+
`(j, i)` as a key. This is not checked.
|
|
2464
|
+
|
|
2465
|
+
EXAMPLES:
|
|
2466
|
+
|
|
2467
|
+
We consider the differential coming from the Lie algebra given by the
|
|
2468
|
+
cross product `\times` of `\RR^3`::
|
|
2469
|
+
|
|
2470
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
2471
|
+
sage: d = E.coboundary({(0,1): z, (1,2): x, (0, 2): -y})
|
|
2472
|
+
sage: d(x)
|
|
2473
|
+
y*z
|
|
2474
|
+
sage: d(y)
|
|
2475
|
+
-x*z
|
|
2476
|
+
sage: d(x+y-y*z)
|
|
2477
|
+
-x*z + y*z
|
|
2478
|
+
sage: d(x*y)
|
|
2479
|
+
0
|
|
2480
|
+
sage: d(E.one())
|
|
2481
|
+
0
|
|
2482
|
+
sage: d(E.zero())
|
|
2483
|
+
0
|
|
2484
|
+
|
|
2485
|
+
We check that `d \circ d = 0`::
|
|
2486
|
+
|
|
2487
|
+
sage: d2 = d * d
|
|
2488
|
+
sage: all(d2(b) == 0 for b in E.basis())
|
|
2489
|
+
True
|
|
2490
|
+
|
|
2491
|
+
Another example: the Lie algebra `\mathfrak{sl}_2`, which has a
|
|
2492
|
+
basis `e,f,h` satisfying `[h,e] = 2e`, `[h,f] = -2f`, and `[e,f] = h`::
|
|
2493
|
+
|
|
2494
|
+
sage: E.<e,f,h> = ExteriorAlgebra(QQ)
|
|
2495
|
+
sage: d = E.coboundary({(0,1): h, (2,1): -2*f, (2,0): 2*e})
|
|
2496
|
+
sage: d(E.zero())
|
|
2497
|
+
0
|
|
2498
|
+
sage: d(e)
|
|
2499
|
+
-2*e*h
|
|
2500
|
+
sage: d(f)
|
|
2501
|
+
2*f*h
|
|
2502
|
+
sage: d(h)
|
|
2503
|
+
e*f
|
|
2504
|
+
sage: d(e*f)
|
|
2505
|
+
0
|
|
2506
|
+
sage: d(f*h)
|
|
2507
|
+
0
|
|
2508
|
+
sage: d(e*h)
|
|
2509
|
+
0
|
|
2510
|
+
sage: C = d.chain_complex(); C
|
|
2511
|
+
Chain complex with at most 4 nonzero terms over Rational Field
|
|
2512
|
+
sage: ascii_art(C)
|
|
2513
|
+
[ 0 0 1] [0]
|
|
2514
|
+
[-2 0 0] [0]
|
|
2515
|
+
[0 0 0] [ 0 2 0] [0]
|
|
2516
|
+
0 <-- C_3 <-------- C_2 <----------- C_1 <---- C_0 <-- 0
|
|
2517
|
+
sage: C.homology()
|
|
2518
|
+
{0: Vector space of dimension 1 over Rational Field,
|
|
2519
|
+
1: Vector space of dimension 0 over Rational Field,
|
|
2520
|
+
2: Vector space of dimension 0 over Rational Field,
|
|
2521
|
+
3: Vector space of dimension 1 over Rational Field}
|
|
2522
|
+
|
|
2523
|
+
Over the integers::
|
|
2524
|
+
|
|
2525
|
+
sage: C = d.chain_complex(R=ZZ); C
|
|
2526
|
+
Chain complex with at most 4 nonzero terms over Integer Ring
|
|
2527
|
+
sage: ascii_art(C)
|
|
2528
|
+
[ 0 0 1] [0]
|
|
2529
|
+
[-2 0 0] [0]
|
|
2530
|
+
[0 0 0] [ 0 2 0] [0]
|
|
2531
|
+
0 <-- C_3 <-------- C_2 <----------- C_1 <---- C_0 <-- 0
|
|
2532
|
+
sage: C.homology() # needs sage.libs.pari
|
|
2533
|
+
{0: Z, 1: 0, 2: C2 x C2, 3: Z}
|
|
2534
|
+
|
|
2535
|
+
REFERENCES:
|
|
2536
|
+
|
|
2537
|
+
- :wikipedia:`Exterior_algebra#Differential_geometry`
|
|
2538
|
+
"""
|
|
2539
|
+
def __init__(self, E, s_coeff):
|
|
2540
|
+
"""
|
|
2541
|
+
Initialize ``self``.
|
|
2542
|
+
|
|
2543
|
+
EXAMPLES::
|
|
2544
|
+
|
|
2545
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
2546
|
+
sage: d = E.coboundary({(0,1): z, (1,2):x, (2,0):y})
|
|
2547
|
+
sage: TestSuite(d).run() # known bug - morphisms are properly in a category
|
|
2548
|
+
"""
|
|
2549
|
+
# Construct the dictionary of costructure coefficients, i.e. given
|
|
2550
|
+
# [x_j, x_k] = \sum_i s_{jk}^i x_i, we get x^i |-> \sum_{j<k} s_{jk}^i x^j x^k.
|
|
2551
|
+
# This dictionary might contain 0 values and might also be missing
|
|
2552
|
+
# some keys (both times meaning that the respective `s_{jk}^i` are
|
|
2553
|
+
# zero for all `j` and `k`).
|
|
2554
|
+
self._cos_coeff = {}
|
|
2555
|
+
zero = E.zero()
|
|
2556
|
+
B = E.basis()
|
|
2557
|
+
for k, v in dict(s_coeff).items():
|
|
2558
|
+
if k[0] > k[1]: # k will have length 2
|
|
2559
|
+
k = sorted(k)
|
|
2560
|
+
v = -v
|
|
2561
|
+
|
|
2562
|
+
k = B[FrozenBitset(k)]
|
|
2563
|
+
for m, c in v:
|
|
2564
|
+
self._cos_coeff[m] = self._cos_coeff.get(m, zero) + c * k
|
|
2565
|
+
ExteriorAlgebraDifferential.__init__(self, E, s_coeff)
|
|
2566
|
+
|
|
2567
|
+
def _repr_type(self):
|
|
2568
|
+
"""
|
|
2569
|
+
TESTS::
|
|
2570
|
+
|
|
2571
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
2572
|
+
sage: d = E.coboundary({(0,1): z, (1,2): x, (2,0): y})
|
|
2573
|
+
sage: d._repr_type()
|
|
2574
|
+
'Coboundary'
|
|
2575
|
+
"""
|
|
2576
|
+
return "Coboundary"
|
|
2577
|
+
|
|
2578
|
+
def _on_basis(self, m):
|
|
2579
|
+
r"""
|
|
2580
|
+
Return the differential on the basis element indexed by ``m``.
|
|
2581
|
+
|
|
2582
|
+
EXAMPLES:
|
|
2583
|
+
|
|
2584
|
+
The vector space `\RR^3` made into a Lie algebra using the
|
|
2585
|
+
cross product::
|
|
2586
|
+
|
|
2587
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
2588
|
+
sage: d = E.coboundary({(0,1): z, (1,2): x, (0,2): -y})
|
|
2589
|
+
sage: d._on_basis(())
|
|
2590
|
+
0
|
|
2591
|
+
sage: d._on_basis((0,))
|
|
2592
|
+
y*z
|
|
2593
|
+
sage: d._on_basis((1,))
|
|
2594
|
+
-x*z
|
|
2595
|
+
sage: d._on_basis((2,))
|
|
2596
|
+
x*y
|
|
2597
|
+
sage: d._on_basis((0,1))
|
|
2598
|
+
0
|
|
2599
|
+
sage: d._on_basis((0,2))
|
|
2600
|
+
0
|
|
2601
|
+
sage: d._on_basis((0,1,2))
|
|
2602
|
+
0
|
|
2603
|
+
"""
|
|
2604
|
+
E = self.domain()
|
|
2605
|
+
cc = self._cos_coeff
|
|
2606
|
+
|
|
2607
|
+
tot = E.zero()
|
|
2608
|
+
|
|
2609
|
+
for sgn, i in enumerate(m):
|
|
2610
|
+
k = FrozenBitset((i,))
|
|
2611
|
+
if k in cc:
|
|
2612
|
+
below = tuple([j for j in m if j < i])
|
|
2613
|
+
above = tuple([j for j in m if j > i])
|
|
2614
|
+
|
|
2615
|
+
# a hack to deal with empty bitsets
|
|
2616
|
+
if not below:
|
|
2617
|
+
below = E.one()
|
|
2618
|
+
else:
|
|
2619
|
+
below = E.monomial(FrozenBitset(below))
|
|
2620
|
+
if not above:
|
|
2621
|
+
above = E.one()
|
|
2622
|
+
else:
|
|
2623
|
+
above = E.monomial(FrozenBitset(above))
|
|
2624
|
+
|
|
2625
|
+
tot += (-1)**sgn * below * cc[k] * above
|
|
2626
|
+
|
|
2627
|
+
return tot
|
|
2628
|
+
|
|
2629
|
+
@cached_method
|
|
2630
|
+
def chain_complex(self, R=None):
|
|
2631
|
+
"""
|
|
2632
|
+
Return the chain complex over ``R`` determined by ``self``.
|
|
2633
|
+
|
|
2634
|
+
INPUT:
|
|
2635
|
+
|
|
2636
|
+
- ``R`` -- the base ring; the default is the base ring of
|
|
2637
|
+
the exterior algebra
|
|
2638
|
+
|
|
2639
|
+
EXAMPLES::
|
|
2640
|
+
|
|
2641
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
2642
|
+
sage: d = E.coboundary({(0,1): z, (1,2): x, (2,0): y})
|
|
2643
|
+
sage: C = d.chain_complex(); C
|
|
2644
|
+
Chain complex with at most 4 nonzero terms over Rational Field
|
|
2645
|
+
sage: ascii_art(C)
|
|
2646
|
+
[ 0 0 1] [0]
|
|
2647
|
+
[ 0 -1 0] [0]
|
|
2648
|
+
[0 0 0] [ 1 0 0] [0]
|
|
2649
|
+
0 <-- C_3 <-------- C_2 <----------- C_1 <---- C_0 <-- 0
|
|
2650
|
+
|
|
2651
|
+
TESTS:
|
|
2652
|
+
|
|
2653
|
+
This still works in degree `1`::
|
|
2654
|
+
|
|
2655
|
+
sage: E.<x> = ExteriorAlgebra(QQ)
|
|
2656
|
+
sage: d = E.coboundary({})
|
|
2657
|
+
sage: C = d.chain_complex(); C
|
|
2658
|
+
Chain complex with at most 2 nonzero terms over Rational Field
|
|
2659
|
+
sage: ascii_art(C)
|
|
2660
|
+
[0]
|
|
2661
|
+
0 <-- C_1 <---- C_0 <-- 0
|
|
2662
|
+
|
|
2663
|
+
Also in degree `0`::
|
|
2664
|
+
|
|
2665
|
+
sage: E = ExteriorAlgebra(QQ, 0)
|
|
2666
|
+
sage: d = E.coboundary({})
|
|
2667
|
+
sage: C = d.chain_complex(); C
|
|
2668
|
+
Chain complex with at most 1 nonzero terms over Rational Field
|
|
2669
|
+
sage: ascii_art(C)
|
|
2670
|
+
0 <-- C_0 <-- 0
|
|
2671
|
+
"""
|
|
2672
|
+
from sage.homology.chain_complex import ChainComplex
|
|
2673
|
+
from sage.matrix.constructor import Matrix
|
|
2674
|
+
E = self.domain()
|
|
2675
|
+
n = E.ngens()
|
|
2676
|
+
if R is None:
|
|
2677
|
+
R = E.base_ring()
|
|
2678
|
+
|
|
2679
|
+
if n == 0:
|
|
2680
|
+
# Special case because there are no matrices and thus the
|
|
2681
|
+
# ChainComplex constructor needs the dimension of the
|
|
2682
|
+
# 0th degree space explicitly given.
|
|
2683
|
+
return ChainComplex({-1: Matrix(R, [[]])}, degree=1)
|
|
2684
|
+
# If you are reading this because you changed something about
|
|
2685
|
+
# the ChainComplex constructor and the doctests are failing:
|
|
2686
|
+
# This should return a chain complex with degree 1 and
|
|
2687
|
+
# only one nontrivial module, namely a free module of rank 1,
|
|
2688
|
+
# situated in degree 0.
|
|
2689
|
+
|
|
2690
|
+
# Group the basis into degrees
|
|
2691
|
+
basis_by_deg = {deg: [] for deg in range(n+1)}
|
|
2692
|
+
for b in E.basis().keys():
|
|
2693
|
+
basis_by_deg[len(b)].append(b)
|
|
2694
|
+
|
|
2695
|
+
# Construct the transition matrices
|
|
2696
|
+
data = {}
|
|
2697
|
+
basis = basis_by_deg[0]
|
|
2698
|
+
for deg in range(n):
|
|
2699
|
+
# Make sure within each basis we're sorted by lex
|
|
2700
|
+
next_basis = sorted(basis_by_deg[deg+1])
|
|
2701
|
+
mat = []
|
|
2702
|
+
for b in basis:
|
|
2703
|
+
ret = self._on_basis(b)
|
|
2704
|
+
try:
|
|
2705
|
+
mat.append([ret.coefficient(p) for p in next_basis])
|
|
2706
|
+
except AttributeError: # if ret is in E.base_ring()
|
|
2707
|
+
mat.append([E.base_ring()(ret)]*len(next_basis))
|
|
2708
|
+
data[deg] = Matrix(mat).transpose().change_ring(R)
|
|
2709
|
+
basis = next_basis
|
|
2710
|
+
|
|
2711
|
+
return ChainComplex(data, degree=1)
|
|
2712
|
+
|
|
2713
|
+
|
|
2714
|
+
@richcmp_method
|
|
2715
|
+
class ExteriorAlgebraIdeal(Ideal_nc):
|
|
2716
|
+
"""
|
|
2717
|
+
An ideal of the exterior algebra.
|
|
2718
|
+
|
|
2719
|
+
EXAMPLES::
|
|
2720
|
+
|
|
2721
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
2722
|
+
sage: I = E.ideal(x*y); I
|
|
2723
|
+
Twosided Ideal (x*y) of The exterior algebra of rank 3 over Rational Field
|
|
2724
|
+
|
|
2725
|
+
We can also use it to build a quotient::
|
|
2726
|
+
|
|
2727
|
+
sage: Q = E.quotient(I); Q
|
|
2728
|
+
Quotient of The exterior algebra of rank 3 over Rational Field by the ideal (x*y)
|
|
2729
|
+
sage: Q.inject_variables()
|
|
2730
|
+
Defining xbar, ybar, zbar
|
|
2731
|
+
sage: xbar * ybar
|
|
2732
|
+
0
|
|
2733
|
+
"""
|
|
2734
|
+
def __init__(self, ring, gens, coerce=True, side='twosided'):
|
|
2735
|
+
"""
|
|
2736
|
+
Initialize ``self``.
|
|
2737
|
+
|
|
2738
|
+
EXAMPLES:
|
|
2739
|
+
|
|
2740
|
+
We skip the category test because the ideals are not a proper
|
|
2741
|
+
element class of the monoid of all ideals::
|
|
2742
|
+
|
|
2743
|
+
sage: E.<y, x> = ExteriorAlgebra(QQ)
|
|
2744
|
+
sage: I = E.ideal([x*y - x, x*y - 1])
|
|
2745
|
+
sage: TestSuite(I).run(skip='_test_category')
|
|
2746
|
+
|
|
2747
|
+
sage: I = E.ideal([x*y - 3, 0, 2*3])
|
|
2748
|
+
sage: TestSuite(I).run(skip='_test_category')
|
|
2749
|
+
|
|
2750
|
+
sage: I = E.ideal([])
|
|
2751
|
+
sage: TestSuite(I).run(skip='_test_category')
|
|
2752
|
+
"""
|
|
2753
|
+
self._groebner_strategy = None
|
|
2754
|
+
self._reduced = False
|
|
2755
|
+
self._homogeneous = all(x.is_super_homogeneous() for x in gens if x)
|
|
2756
|
+
if self._homogeneous:
|
|
2757
|
+
side = "twosided"
|
|
2758
|
+
Ideal_nc.__init__(self, ring, gens, coerce, side)
|
|
2759
|
+
|
|
2760
|
+
def reduce(self, f):
|
|
2761
|
+
"""
|
|
2762
|
+
Reduce ``f`` modulo ``self``.
|
|
2763
|
+
|
|
2764
|
+
EXAMPLES::
|
|
2765
|
+
|
|
2766
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
2767
|
+
sage: I = E.ideal(x*y);
|
|
2768
|
+
sage: I.reduce(x*y + x*y*z + z)
|
|
2769
|
+
z
|
|
2770
|
+
sage: I.reduce(x*y + x + y)
|
|
2771
|
+
x + y
|
|
2772
|
+
sage: I.reduce(x*y + x*y*z)
|
|
2773
|
+
0
|
|
2774
|
+
|
|
2775
|
+
sage: E.<a,b,c,d> = ExteriorAlgebra(QQ)
|
|
2776
|
+
sage: I = E.ideal([a+b*c])
|
|
2777
|
+
sage: I.reduce(I.gen(0) * d)
|
|
2778
|
+
0
|
|
2779
|
+
"""
|
|
2780
|
+
if self._groebner_strategy is None:
|
|
2781
|
+
self.groebner_basis()
|
|
2782
|
+
R = self.ring()
|
|
2783
|
+
return self._groebner_strategy.reduce(R(f))
|
|
2784
|
+
|
|
2785
|
+
def _contains_(self, f):
|
|
2786
|
+
r"""
|
|
2787
|
+
Return ``True`` if ``f`` is in this ideal,
|
|
2788
|
+
``False`` otherwise.
|
|
2789
|
+
|
|
2790
|
+
EXAMPLES::
|
|
2791
|
+
|
|
2792
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
2793
|
+
sage: I = E.ideal([x, x*y*z + 2*x*z + 3*y*z], side='left')
|
|
2794
|
+
sage: I.groebner_basis()
|
|
2795
|
+
(x, y*z)
|
|
2796
|
+
sage: x in I
|
|
2797
|
+
True
|
|
2798
|
+
sage: y*z in I
|
|
2799
|
+
True
|
|
2800
|
+
sage: x + 3*y*z in I
|
|
2801
|
+
True
|
|
2802
|
+
sage: x + 3*y in I
|
|
2803
|
+
False
|
|
2804
|
+
sage: x*y in I
|
|
2805
|
+
True
|
|
2806
|
+
sage: x + x*y + y*z + x*z in I
|
|
2807
|
+
True
|
|
2808
|
+
|
|
2809
|
+
.. NOTE::
|
|
2810
|
+
|
|
2811
|
+
Requires computation of a Groebner basis, which can be a very
|
|
2812
|
+
expensive operation.
|
|
2813
|
+
"""
|
|
2814
|
+
return not self.reduce(f)
|
|
2815
|
+
|
|
2816
|
+
def __richcmp__(self, other, op):
|
|
2817
|
+
"""
|
|
2818
|
+
Compare ``self`` and ``other``.
|
|
2819
|
+
|
|
2820
|
+
EXAMPLES::
|
|
2821
|
+
|
|
2822
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
2823
|
+
sage: I = E.ideal([x, x*y*z + 2*x*z + 3*y*z])
|
|
2824
|
+
sage: I == I
|
|
2825
|
+
True
|
|
2826
|
+
sage: Ip = E.ideal([x, y*z])
|
|
2827
|
+
sage: Ip == I
|
|
2828
|
+
True
|
|
2829
|
+
sage: Ip <= I
|
|
2830
|
+
True
|
|
2831
|
+
sage: Ip < I
|
|
2832
|
+
False
|
|
2833
|
+
sage: Ip >= I
|
|
2834
|
+
True
|
|
2835
|
+
sage: Ip > I
|
|
2836
|
+
False
|
|
2837
|
+
sage: E.ideal([x]) < I
|
|
2838
|
+
True
|
|
2839
|
+
sage: E.ideal([x]) <= I
|
|
2840
|
+
True
|
|
2841
|
+
sage: I <= E.ideal([x])
|
|
2842
|
+
False
|
|
2843
|
+
|
|
2844
|
+
sage: E.<a,b,c,d> = ExteriorAlgebra(QQ)
|
|
2845
|
+
sage: p = a + b*c
|
|
2846
|
+
sage: IT = E.ideal([p], side='twosided')
|
|
2847
|
+
sage: IR = E.ideal([p], side='right')
|
|
2848
|
+
sage: IL = E.ideal([p], side='left')
|
|
2849
|
+
sage: IR == IL
|
|
2850
|
+
False
|
|
2851
|
+
sage: IR <= IL
|
|
2852
|
+
False
|
|
2853
|
+
sage: IR >= IL
|
|
2854
|
+
False
|
|
2855
|
+
sage: IL.reduce(p * d)
|
|
2856
|
+
2*a*d
|
|
2857
|
+
sage: IR.reduce(d * p)
|
|
2858
|
+
-2*a*d
|
|
2859
|
+
|
|
2860
|
+
sage: IR <= IT
|
|
2861
|
+
True
|
|
2862
|
+
sage: IL <= IT
|
|
2863
|
+
True
|
|
2864
|
+
sage: IT <= IL
|
|
2865
|
+
False
|
|
2866
|
+
sage: IT <= IR
|
|
2867
|
+
False
|
|
2868
|
+
"""
|
|
2869
|
+
if not isinstance(other, ExteriorAlgebraIdeal):
|
|
2870
|
+
if op == op_EQ:
|
|
2871
|
+
return False
|
|
2872
|
+
if op == op_NE:
|
|
2873
|
+
return True
|
|
2874
|
+
return NotImplemented
|
|
2875
|
+
|
|
2876
|
+
if self is other:
|
|
2877
|
+
return rich_to_bool(op, 0)
|
|
2878
|
+
|
|
2879
|
+
# comparison for >= and > : swap the arguments
|
|
2880
|
+
if op == op_GE:
|
|
2881
|
+
return other.__richcmp__(self, op_LE)
|
|
2882
|
+
elif op == op_GT:
|
|
2883
|
+
return other.__richcmp__(self, op_LT)
|
|
2884
|
+
|
|
2885
|
+
s_gens = {g for g in self.gens() if g}
|
|
2886
|
+
o_gens = {g for g in other.gens() if g}
|
|
2887
|
+
|
|
2888
|
+
if self.side() != other.side():
|
|
2889
|
+
if other.side() == "right":
|
|
2890
|
+
X = {t * f for t in self.ring().basis() for f in s_gens}
|
|
2891
|
+
s_gens.update(X)
|
|
2892
|
+
elif other.side() == "left":
|
|
2893
|
+
X = {f * t for t in self.ring().basis() for f in s_gens}
|
|
2894
|
+
s_gens.update(X)
|
|
2895
|
+
|
|
2896
|
+
if set(s_gens) == set(o_gens):
|
|
2897
|
+
return rich_to_bool(op, 0)
|
|
2898
|
+
|
|
2899
|
+
contained = all(f in other for f in s_gens)
|
|
2900
|
+
if op == op_LE:
|
|
2901
|
+
return contained
|
|
2902
|
+
if op == op_NE and not contained:
|
|
2903
|
+
return True
|
|
2904
|
+
|
|
2905
|
+
if self.side() != other.side():
|
|
2906
|
+
if self.side() == "right":
|
|
2907
|
+
X = {t * f for t in self.ring().basis() for f in o_gens}
|
|
2908
|
+
s_gens.update(X)
|
|
2909
|
+
elif self.side() == "left":
|
|
2910
|
+
X = {f * t for t in self.ring().basis() for f in o_gens}
|
|
2911
|
+
s_gens.update(X)
|
|
2912
|
+
|
|
2913
|
+
contains = all(f in self for f in o_gens)
|
|
2914
|
+
if op == op_EQ:
|
|
2915
|
+
return contained and contains
|
|
2916
|
+
if op == op_NE:
|
|
2917
|
+
return not (contained and contains)
|
|
2918
|
+
# remaining case <
|
|
2919
|
+
return contained and not contains
|
|
2920
|
+
|
|
2921
|
+
def __mul__(self, other):
|
|
2922
|
+
"""
|
|
2923
|
+
Return the product of ``self`` with ``other``.
|
|
2924
|
+
|
|
2925
|
+
.. WARNING::
|
|
2926
|
+
|
|
2927
|
+
If ``self`` is a right ideal and ``other`` is a left ideal,
|
|
2928
|
+
this returns a submodule rather than an ideal.
|
|
2929
|
+
|
|
2930
|
+
EXAMPLES::
|
|
2931
|
+
|
|
2932
|
+
sage: E.<a,b,c,d> = ExteriorAlgebra(QQ)
|
|
2933
|
+
|
|
2934
|
+
sage: I = E.ideal([a + 1], side='left')
|
|
2935
|
+
sage: J = I * I; J
|
|
2936
|
+
Left Ideal (2*a + 1, a, b, c, d, a*b, a*c, a*d, 2*a*b*c + b*c, 2*a*b*d + b*d,
|
|
2937
|
+
2*a*c*d + c*d, a*b*c, a*b*d, a*c*d, b*c*d, a*b*c*d)
|
|
2938
|
+
of The exterior algebra of rank 4 over Rational Field
|
|
2939
|
+
sage: J.groebner_basis()
|
|
2940
|
+
(1,)
|
|
2941
|
+
sage: I.gen(0)^2
|
|
2942
|
+
2*a + 1
|
|
2943
|
+
|
|
2944
|
+
sage: J = E.ideal([b+c])
|
|
2945
|
+
sage: I * J
|
|
2946
|
+
Twosided Ideal (a*b + a*c + b + c) of The exterior algebra of rank 4 over Rational Field
|
|
2947
|
+
sage: J * I
|
|
2948
|
+
Left Ideal (-a*b - a*c + b + c) of The exterior algebra of rank 4 over Rational Field
|
|
2949
|
+
|
|
2950
|
+
sage: K = J * I
|
|
2951
|
+
sage: K
|
|
2952
|
+
Left Ideal (-a*b - a*c + b + c) of The exterior algebra of rank 4 over Rational Field
|
|
2953
|
+
sage: E.ideal([J.gen(0) * d * I.gen(0)], side='left') <= K
|
|
2954
|
+
True
|
|
2955
|
+
|
|
2956
|
+
sage: J = E.ideal([b + c*d], side='right')
|
|
2957
|
+
sage: I * J
|
|
2958
|
+
Twosided Ideal (a*c*d + a*b + c*d + b) of The exterior algebra of rank 4 over Rational Field
|
|
2959
|
+
sage: X = J * I; X
|
|
2960
|
+
Free module generated by {0, 1, 2, 3, 4, 5, 6, 7} over Rational Field
|
|
2961
|
+
sage: [X.lift(b) for b in X.basis()]
|
|
2962
|
+
[c*d + b, -a*c*d + a*b, b*c, b*d, a*b*c, a*b*d, b*c*d, a*b*c*d]
|
|
2963
|
+
sage: p = X.lift(X.basis()[0])
|
|
2964
|
+
sage: p
|
|
2965
|
+
c*d + b
|
|
2966
|
+
sage: a * p # not a left ideal
|
|
2967
|
+
a*c*d + a*b
|
|
2968
|
+
|
|
2969
|
+
sage: I = E.ideal([a + 1], side='right')
|
|
2970
|
+
sage: E.ideal([1]) * I
|
|
2971
|
+
Twosided Ideal (a + 1) of The exterior algebra of rank 4 over Rational Field
|
|
2972
|
+
sage: I * E.ideal([1])
|
|
2973
|
+
Right Ideal (a + 1) of The exterior algebra of rank 4 over Rational Field
|
|
2974
|
+
"""
|
|
2975
|
+
if not isinstance(other, ExteriorAlgebraIdeal) or self.ring() != other.ring():
|
|
2976
|
+
return super().__mul__(other)
|
|
2977
|
+
|
|
2978
|
+
if self._homogeneous or other._homogeneous or (self.side() == "left" and other.side() == "right"):
|
|
2979
|
+
gens = (x * y for x in self.gens() for y in other.gens())
|
|
2980
|
+
else:
|
|
2981
|
+
gens = (x * t * y for t in self.ring().basis() for x in self.gens() for y in other.gens())
|
|
2982
|
+
gens = [z for z in gens if z]
|
|
2983
|
+
|
|
2984
|
+
if self.side() == "right" and other.side() == "left":
|
|
2985
|
+
return self.ring().submodule(gens)
|
|
2986
|
+
|
|
2987
|
+
if self.side() == "left" or self.side() == "twosided":
|
|
2988
|
+
if other.side() == "right" or other.side() == "twosided":
|
|
2989
|
+
return self.ring().ideal(gens, side='twosided')
|
|
2990
|
+
return self.ring().ideal(gens, side='left')
|
|
2991
|
+
return self.ring().ideal(gens, side='right')
|
|
2992
|
+
|
|
2993
|
+
def groebner_basis(self, term_order=None, reduced=True):
|
|
2994
|
+
r"""
|
|
2995
|
+
Return the (reduced) Gröbner basis of ``self``.
|
|
2996
|
+
|
|
2997
|
+
INPUT:
|
|
2998
|
+
|
|
2999
|
+
- ``term_order`` -- the term order used to compute the Gröbner basis;
|
|
3000
|
+
must be one of the following:
|
|
3001
|
+
|
|
3002
|
+
* ``'neglex'`` -- (default) negative (read right-to-left) lex order
|
|
3003
|
+
* ``'degrevlex'`` -- degree reverse lex order
|
|
3004
|
+
* ``'deglex'`` -- degree lex order
|
|
3005
|
+
|
|
3006
|
+
- ``reduced`` -- boolean (default: ``True``); whether or not to return
|
|
3007
|
+
the reduced Gröbner basis
|
|
3008
|
+
|
|
3009
|
+
EXAMPLES:
|
|
3010
|
+
|
|
3011
|
+
We compute an example::
|
|
3012
|
+
|
|
3013
|
+
sage: E.<a,b,c,d,e> = ExteriorAlgebra(QQ)
|
|
3014
|
+
sage: rels = [c*d*e - b*d*e + b*c*e - b*c*d,
|
|
3015
|
+
....: c*d*e - a*d*e + a*c*e - a*c*d,
|
|
3016
|
+
....: b*d*e - a*d*e + a*b*e - a*b*d,
|
|
3017
|
+
....: b*c*e - a*c*e + a*b*e - a*b*c,
|
|
3018
|
+
....: b*c*d - a*c*d + a*b*d - a*b*c]
|
|
3019
|
+
sage: I = E.ideal(rels)
|
|
3020
|
+
sage: I.groebner_basis()
|
|
3021
|
+
(-a*b*c + a*b*d - a*c*d + b*c*d,
|
|
3022
|
+
-a*b*c + a*b*e - a*c*e + b*c*e,
|
|
3023
|
+
-a*b*d + a*b*e - a*d*e + b*d*e,
|
|
3024
|
+
-a*c*d + a*c*e - a*d*e + c*d*e)
|
|
3025
|
+
|
|
3026
|
+
With different term orders::
|
|
3027
|
+
|
|
3028
|
+
sage: I.groebner_basis("degrevlex")
|
|
3029
|
+
(b*c*d - b*c*e + b*d*e - c*d*e,
|
|
3030
|
+
a*c*d - a*c*e + a*d*e - c*d*e,
|
|
3031
|
+
a*b*d - a*b*e + a*d*e - b*d*e,
|
|
3032
|
+
a*b*c - a*b*e + a*c*e - b*c*e)
|
|
3033
|
+
|
|
3034
|
+
sage: I.groebner_basis("deglex")
|
|
3035
|
+
(-a*b*c + a*b*d - a*c*d + b*c*d,
|
|
3036
|
+
-a*b*c + a*b*e - a*c*e + b*c*e,
|
|
3037
|
+
-a*b*d + a*b*e - a*d*e + b*d*e,
|
|
3038
|
+
-a*c*d + a*c*e - a*d*e + c*d*e)
|
|
3039
|
+
|
|
3040
|
+
The example above was computed first using M2, which agrees with
|
|
3041
|
+
the ``'degrevlex'`` ordering::
|
|
3042
|
+
|
|
3043
|
+
E = QQ[a..e, SkewCommutative => true]
|
|
3044
|
+
I = ideal( c*d*e - b*d*e + b*c*e - b*c*d,
|
|
3045
|
+
c*d*e - a*d*e + a*c*e - a*c*d,
|
|
3046
|
+
b*d*e - a*d*e + a*b*e - a*b*d,
|
|
3047
|
+
b*c*e - a*c*e + a*b*e - a*b*c,
|
|
3048
|
+
b*c*d - a*c*d + a*b*d - a*b*c)
|
|
3049
|
+
groebnerBasis(I)
|
|
3050
|
+
|
|
3051
|
+
returns:
|
|
3052
|
+
o3 = | bcd-bce+bde-cde acd-ace+ade-cde abd-abe+ade-bde abc-abe+ace-bce |
|
|
3053
|
+
|
|
3054
|
+
By default, the Gröbner basis is reduced, but we can get non-reduced
|
|
3055
|
+
Gröber bases (which are not unique)::
|
|
3056
|
+
|
|
3057
|
+
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
|
|
3058
|
+
sage: I = E.ideal([x+y*z])
|
|
3059
|
+
sage: I.groebner_basis(reduced=False)
|
|
3060
|
+
(x*y, x*z, y*z + x, x*y*z)
|
|
3061
|
+
sage: I.groebner_basis(reduced=True)
|
|
3062
|
+
(x*y, x*z, y*z + x)
|
|
3063
|
+
|
|
3064
|
+
However, if we have already computed a reduced Gröbner basis (with
|
|
3065
|
+
a given term order), then we return that::
|
|
3066
|
+
|
|
3067
|
+
sage: I = E.ideal([x+y*z]) # A fresh ideal
|
|
3068
|
+
sage: I.groebner_basis()
|
|
3069
|
+
(x*y, x*z, y*z + x)
|
|
3070
|
+
sage: I.groebner_basis(reduced=False)
|
|
3071
|
+
(x*y, x*z, y*z + x)
|
|
3072
|
+
|
|
3073
|
+
TESTS::
|
|
3074
|
+
|
|
3075
|
+
sage: E.<a,b,c,d,e> = ExteriorAlgebra(ZZ)
|
|
3076
|
+
sage: I = E.ideal([a+1, b*c+d])
|
|
3077
|
+
sage: I.groebner_basis()
|
|
3078
|
+
Traceback (most recent call last):
|
|
3079
|
+
...
|
|
3080
|
+
NotImplementedError: only implemented over fields
|
|
3081
|
+
"""
|
|
3082
|
+
if self.ring().base_ring() not in Fields():
|
|
3083
|
+
raise NotImplementedError("only implemented over fields")
|
|
3084
|
+
if term_order is None:
|
|
3085
|
+
if self._groebner_strategy is not None:
|
|
3086
|
+
strategy = type(self._groebner_strategy)
|
|
3087
|
+
else:
|
|
3088
|
+
from sage.algebras.exterior_algebra_groebner import GroebnerStrategyNegLex as strategy
|
|
3089
|
+
else:
|
|
3090
|
+
if term_order == "neglex":
|
|
3091
|
+
from sage.algebras.exterior_algebra_groebner import GroebnerStrategyNegLex as strategy
|
|
3092
|
+
elif term_order == "degrevlex":
|
|
3093
|
+
from sage.algebras.exterior_algebra_groebner import GroebnerStrategyDegRevLex as strategy
|
|
3094
|
+
elif term_order == "deglex":
|
|
3095
|
+
from sage.algebras.exterior_algebra_groebner import GroebnerStrategyDegLex as strategy
|
|
3096
|
+
else:
|
|
3097
|
+
raise ValueError("invalid term order")
|
|
3098
|
+
if isinstance(self._groebner_strategy, strategy):
|
|
3099
|
+
if self._reduced or not reduced:
|
|
3100
|
+
return self._groebner_strategy.groebner_basis
|
|
3101
|
+
self._reduced = reduced
|
|
3102
|
+
self._groebner_strategy.reduce_computed_gb()
|
|
3103
|
+
return self._groebner_strategy.groebner_basis
|
|
3104
|
+
self._groebner_strategy = strategy(self)
|
|
3105
|
+
self._groebner_strategy.compute_groebner(reduced=reduced)
|
|
3106
|
+
self._reduced = reduced
|
|
3107
|
+
return self._groebner_strategy.groebner_basis
|