passagemath-modules 10.6.31rc3__cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-modules might be problematic. Click here for more details.
- passagemath_modules-10.6.31rc3.dist-info/METADATA +281 -0
- passagemath_modules-10.6.31rc3.dist-info/RECORD +806 -0
- passagemath_modules-10.6.31rc3.dist-info/WHEEL +6 -0
- passagemath_modules-10.6.31rc3.dist-info/top_level.txt +2 -0
- passagemath_modules.libs/libgfortran-e1b7dfc8.so.5.0.0 +0 -0
- passagemath_modules.libs/libgmp-93ebf16a.so.10.5.0 +0 -0
- passagemath_modules.libs/libgsl-e3525837.so.28.0.0 +0 -0
- passagemath_modules.libs/libmpc-c5c421e1.so.3.3.1 +0 -0
- passagemath_modules.libs/libmpfr-e0f11cf3.so.6.2.1 +0 -0
- passagemath_modules.libs/libopenblasp-r0-4c5b64b1.3.29.so +0 -0
- sage/algebras/all__sagemath_modules.py +20 -0
- sage/algebras/catalog.py +148 -0
- sage/algebras/clifford_algebra.py +3107 -0
- sage/algebras/clifford_algebra_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/algebras/clifford_algebra_element.pxd +16 -0
- sage/algebras/clifford_algebra_element.pyx +997 -0
- sage/algebras/commutative_dga.py +4252 -0
- sage/algebras/exterior_algebra_groebner.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/algebras/exterior_algebra_groebner.pxd +55 -0
- sage/algebras/exterior_algebra_groebner.pyx +727 -0
- sage/algebras/finite_dimensional_algebras/all.py +2 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +1029 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pxd +12 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx +706 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py +196 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py +255 -0
- sage/algebras/finite_gca.py +528 -0
- sage/algebras/group_algebra.py +232 -0
- sage/algebras/lie_algebras/abelian.py +197 -0
- sage/algebras/lie_algebras/affine_lie_algebra.py +1213 -0
- sage/algebras/lie_algebras/all.py +25 -0
- sage/algebras/lie_algebras/all__sagemath_modules.py +1 -0
- sage/algebras/lie_algebras/bch.py +177 -0
- sage/algebras/lie_algebras/bgg_dual_module.py +1184 -0
- sage/algebras/lie_algebras/bgg_resolution.py +232 -0
- sage/algebras/lie_algebras/center_uea.py +767 -0
- sage/algebras/lie_algebras/classical_lie_algebra.py +2516 -0
- sage/algebras/lie_algebras/examples.py +683 -0
- sage/algebras/lie_algebras/free_lie_algebra.py +973 -0
- sage/algebras/lie_algebras/heisenberg.py +820 -0
- sage/algebras/lie_algebras/lie_algebra.py +1562 -0
- sage/algebras/lie_algebras/lie_algebra_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/algebras/lie_algebras/lie_algebra_element.pxd +68 -0
- sage/algebras/lie_algebras/lie_algebra_element.pyx +2122 -0
- sage/algebras/lie_algebras/morphism.py +661 -0
- sage/algebras/lie_algebras/nilpotent_lie_algebra.py +457 -0
- sage/algebras/lie_algebras/onsager.py +1324 -0
- sage/algebras/lie_algebras/poincare_birkhoff_witt.py +816 -0
- sage/algebras/lie_algebras/quotient.py +462 -0
- sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py +355 -0
- sage/algebras/lie_algebras/representation.py +1040 -0
- sage/algebras/lie_algebras/structure_coefficients.py +459 -0
- sage/algebras/lie_algebras/subalgebra.py +967 -0
- sage/algebras/lie_algebras/symplectic_derivation.py +289 -0
- sage/algebras/lie_algebras/verma_module.py +1630 -0
- sage/algebras/lie_algebras/virasoro.py +1186 -0
- sage/algebras/octonion_algebra.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/algebras/octonion_algebra.pxd +20 -0
- sage/algebras/octonion_algebra.pyx +987 -0
- sage/algebras/orlik_solomon.py +907 -0
- sage/algebras/orlik_terao.py +779 -0
- sage/algebras/steenrod/all.py +7 -0
- sage/algebras/steenrod/steenrod_algebra.py +4258 -0
- sage/algebras/steenrod/steenrod_algebra_bases.py +1179 -0
- sage/algebras/steenrod/steenrod_algebra_misc.py +1167 -0
- sage/algebras/steenrod/steenrod_algebra_mult.py +954 -0
- sage/algebras/weyl_algebra.py +1126 -0
- sage/all__sagemath_modules.py +62 -0
- sage/calculus/all__sagemath_modules.py +19 -0
- sage/calculus/expr.py +205 -0
- sage/calculus/integration.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/calculus/integration.pyx +698 -0
- sage/calculus/interpolation.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/calculus/interpolation.pxd +13 -0
- sage/calculus/interpolation.pyx +387 -0
- sage/calculus/interpolators.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/calculus/interpolators.pyx +326 -0
- sage/calculus/ode.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/calculus/ode.pxd +5 -0
- sage/calculus/ode.pyx +610 -0
- sage/calculus/riemann.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/calculus/riemann.pyx +1521 -0
- sage/calculus/test_sympy.py +201 -0
- sage/calculus/transforms/all.py +7 -0
- sage/calculus/transforms/dft.py +844 -0
- sage/calculus/transforms/dwt.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/calculus/transforms/dwt.pxd +7 -0
- sage/calculus/transforms/dwt.pyx +160 -0
- sage/calculus/transforms/fft.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/calculus/transforms/fft.pxd +12 -0
- sage/calculus/transforms/fft.pyx +487 -0
- sage/calculus/wester.py +662 -0
- sage/coding/abstract_code.py +1108 -0
- sage/coding/ag_code.py +868 -0
- sage/coding/ag_code_decoders.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/coding/ag_code_decoders.pyx +2639 -0
- sage/coding/all.py +15 -0
- sage/coding/bch_code.py +494 -0
- sage/coding/binary_code.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/coding/binary_code.pxd +124 -0
- sage/coding/binary_code.pyx +4139 -0
- sage/coding/bounds_catalog.py +43 -0
- sage/coding/channel.py +819 -0
- sage/coding/channels_catalog.py +29 -0
- sage/coding/code_bounds.py +755 -0
- sage/coding/code_constructions.py +804 -0
- sage/coding/codes_catalog.py +111 -0
- sage/coding/cyclic_code.py +1329 -0
- sage/coding/databases.py +316 -0
- sage/coding/decoder.py +373 -0
- sage/coding/decoders_catalog.py +88 -0
- sage/coding/delsarte_bounds.py +709 -0
- sage/coding/encoder.py +390 -0
- sage/coding/encoders_catalog.py +64 -0
- sage/coding/extended_code.py +468 -0
- sage/coding/gabidulin_code.py +1058 -0
- sage/coding/golay_code.py +404 -0
- sage/coding/goppa_code.py +441 -0
- sage/coding/grs_code.py +2371 -0
- sage/coding/guava.py +107 -0
- sage/coding/guruswami_sudan/all.py +1 -0
- sage/coding/guruswami_sudan/gs_decoder.py +897 -0
- sage/coding/guruswami_sudan/interpolation.py +409 -0
- sage/coding/guruswami_sudan/utils.py +176 -0
- sage/coding/hamming_code.py +176 -0
- sage/coding/information_set_decoder.py +1032 -0
- sage/coding/kasami_codes.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/coding/kasami_codes.pyx +351 -0
- sage/coding/linear_code.py +3067 -0
- sage/coding/linear_code_no_metric.py +1354 -0
- sage/coding/linear_rank_metric.py +961 -0
- sage/coding/parity_check_code.py +353 -0
- sage/coding/punctured_code.py +719 -0
- sage/coding/reed_muller_code.py +999 -0
- sage/coding/self_dual_codes.py +942 -0
- sage/coding/source_coding/all.py +2 -0
- sage/coding/source_coding/huffman.py +553 -0
- sage/coding/subfield_subcode.py +423 -0
- sage/coding/two_weight_db.py +399 -0
- sage/combinat/all__sagemath_modules.py +7 -0
- sage/combinat/cartesian_product.py +347 -0
- sage/combinat/family.py +11 -0
- sage/combinat/free_module.py +1977 -0
- sage/combinat/root_system/all.py +147 -0
- sage/combinat/root_system/ambient_space.py +527 -0
- sage/combinat/root_system/associahedron.py +471 -0
- sage/combinat/root_system/braid_move_calculator.py +143 -0
- sage/combinat/root_system/braid_orbit.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/combinat/root_system/braid_orbit.pyx +144 -0
- sage/combinat/root_system/branching_rules.py +2301 -0
- sage/combinat/root_system/cartan_matrix.py +1245 -0
- sage/combinat/root_system/cartan_type.py +3069 -0
- sage/combinat/root_system/coxeter_group.py +162 -0
- sage/combinat/root_system/coxeter_matrix.py +1261 -0
- sage/combinat/root_system/coxeter_type.py +681 -0
- sage/combinat/root_system/dynkin_diagram.py +900 -0
- sage/combinat/root_system/extended_affine_weyl_group.py +2993 -0
- sage/combinat/root_system/fundamental_group.py +795 -0
- sage/combinat/root_system/hecke_algebra_representation.py +1203 -0
- sage/combinat/root_system/integrable_representations.py +1227 -0
- sage/combinat/root_system/non_symmetric_macdonald_polynomials.py +1965 -0
- sage/combinat/root_system/pieri_factors.py +1147 -0
- sage/combinat/root_system/plot.py +1615 -0
- sage/combinat/root_system/root_lattice_realization_algebras.py +1214 -0
- sage/combinat/root_system/root_lattice_realizations.py +4628 -0
- sage/combinat/root_system/root_space.py +487 -0
- sage/combinat/root_system/root_system.py +882 -0
- sage/combinat/root_system/type_A.py +348 -0
- sage/combinat/root_system/type_A_affine.py +227 -0
- sage/combinat/root_system/type_A_infinity.py +241 -0
- sage/combinat/root_system/type_B.py +347 -0
- sage/combinat/root_system/type_BC_affine.py +287 -0
- sage/combinat/root_system/type_B_affine.py +216 -0
- sage/combinat/root_system/type_C.py +317 -0
- sage/combinat/root_system/type_C_affine.py +188 -0
- sage/combinat/root_system/type_D.py +357 -0
- sage/combinat/root_system/type_D_affine.py +208 -0
- sage/combinat/root_system/type_E.py +641 -0
- sage/combinat/root_system/type_E_affine.py +231 -0
- sage/combinat/root_system/type_F.py +387 -0
- sage/combinat/root_system/type_F_affine.py +137 -0
- sage/combinat/root_system/type_G.py +293 -0
- sage/combinat/root_system/type_G_affine.py +132 -0
- sage/combinat/root_system/type_H.py +105 -0
- sage/combinat/root_system/type_I.py +110 -0
- sage/combinat/root_system/type_Q.py +150 -0
- sage/combinat/root_system/type_affine.py +509 -0
- sage/combinat/root_system/type_dual.py +704 -0
- sage/combinat/root_system/type_folded.py +301 -0
- sage/combinat/root_system/type_marked.py +748 -0
- sage/combinat/root_system/type_reducible.py +601 -0
- sage/combinat/root_system/type_relabel.py +730 -0
- sage/combinat/root_system/type_super_A.py +837 -0
- sage/combinat/root_system/weight_lattice_realizations.py +1188 -0
- sage/combinat/root_system/weight_space.py +639 -0
- sage/combinat/root_system/weyl_characters.py +2238 -0
- sage/crypto/__init__.py +4 -0
- sage/crypto/all.py +28 -0
- sage/crypto/block_cipher/all.py +7 -0
- sage/crypto/block_cipher/des.py +1065 -0
- sage/crypto/block_cipher/miniaes.py +2171 -0
- sage/crypto/block_cipher/present.py +909 -0
- sage/crypto/block_cipher/sdes.py +1527 -0
- sage/crypto/boolean_function.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/crypto/boolean_function.pxd +10 -0
- sage/crypto/boolean_function.pyx +1487 -0
- sage/crypto/cipher.py +78 -0
- sage/crypto/classical.py +3668 -0
- sage/crypto/classical_cipher.py +569 -0
- sage/crypto/cryptosystem.py +387 -0
- sage/crypto/key_exchange/all.py +7 -0
- sage/crypto/key_exchange/catalog.py +24 -0
- sage/crypto/key_exchange/diffie_hellman.py +323 -0
- sage/crypto/key_exchange/key_exchange_scheme.py +107 -0
- sage/crypto/lattice.py +312 -0
- sage/crypto/lfsr.py +295 -0
- sage/crypto/lwe.py +840 -0
- sage/crypto/mq/__init__.py +4 -0
- sage/crypto/mq/mpolynomialsystemgenerator.py +204 -0
- sage/crypto/mq/rijndael_gf.py +2345 -0
- sage/crypto/mq/sbox.py +7 -0
- sage/crypto/mq/sr.py +3344 -0
- sage/crypto/public_key/all.py +5 -0
- sage/crypto/public_key/blum_goldwasser.py +776 -0
- sage/crypto/sbox.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/crypto/sbox.pyx +2090 -0
- sage/crypto/sboxes.py +2090 -0
- sage/crypto/stream.py +390 -0
- sage/crypto/stream_cipher.py +297 -0
- sage/crypto/util.py +519 -0
- sage/ext/all__sagemath_modules.py +1 -0
- sage/ext/interpreters/__init__.py +1 -0
- sage/ext/interpreters/all__sagemath_modules.py +2 -0
- sage/ext/interpreters/wrapper_cc.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/ext/interpreters/wrapper_cc.pxd +30 -0
- sage/ext/interpreters/wrapper_cc.pyx +252 -0
- sage/ext/interpreters/wrapper_cdf.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/ext/interpreters/wrapper_cdf.pxd +26 -0
- sage/ext/interpreters/wrapper_cdf.pyx +245 -0
- sage/ext/interpreters/wrapper_rdf.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/ext/interpreters/wrapper_rdf.pxd +23 -0
- sage/ext/interpreters/wrapper_rdf.pyx +221 -0
- sage/ext/interpreters/wrapper_rr.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/ext/interpreters/wrapper_rr.pxd +28 -0
- sage/ext/interpreters/wrapper_rr.pyx +335 -0
- sage/geometry/all__sagemath_modules.py +5 -0
- sage/geometry/toric_lattice.py +1745 -0
- sage/geometry/toric_lattice_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/geometry/toric_lattice_element.pyx +432 -0
- sage/groups/abelian_gps/abelian_group.py +1925 -0
- sage/groups/abelian_gps/abelian_group_element.py +164 -0
- sage/groups/abelian_gps/all__sagemath_modules.py +5 -0
- sage/groups/abelian_gps/dual_abelian_group.py +421 -0
- sage/groups/abelian_gps/dual_abelian_group_element.py +179 -0
- sage/groups/abelian_gps/element_base.py +341 -0
- sage/groups/abelian_gps/values.py +488 -0
- sage/groups/additive_abelian/additive_abelian_group.py +476 -0
- sage/groups/additive_abelian/additive_abelian_wrapper.py +857 -0
- sage/groups/additive_abelian/all.py +4 -0
- sage/groups/additive_abelian/qmodnz.py +231 -0
- sage/groups/additive_abelian/qmodnz_element.py +349 -0
- sage/groups/affine_gps/affine_group.py +535 -0
- sage/groups/affine_gps/all.py +1 -0
- sage/groups/affine_gps/catalog.py +17 -0
- sage/groups/affine_gps/euclidean_group.py +246 -0
- sage/groups/affine_gps/group_element.py +562 -0
- sage/groups/all__sagemath_modules.py +12 -0
- sage/groups/galois_group.py +479 -0
- sage/groups/matrix_gps/all.py +4 -0
- sage/groups/matrix_gps/all__sagemath_modules.py +13 -0
- sage/groups/matrix_gps/catalog.py +26 -0
- sage/groups/matrix_gps/coxeter_group.py +927 -0
- sage/groups/matrix_gps/finitely_generated.py +487 -0
- sage/groups/matrix_gps/group_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/groups/matrix_gps/group_element.pxd +11 -0
- sage/groups/matrix_gps/group_element.pyx +431 -0
- sage/groups/matrix_gps/linear.py +440 -0
- sage/groups/matrix_gps/matrix_group.py +617 -0
- sage/groups/matrix_gps/named_group.py +296 -0
- sage/groups/matrix_gps/orthogonal.py +544 -0
- sage/groups/matrix_gps/symplectic.py +251 -0
- sage/groups/matrix_gps/unitary.py +436 -0
- sage/groups/misc_gps/all__sagemath_modules.py +1 -0
- sage/groups/misc_gps/argument_groups.py +1905 -0
- sage/groups/misc_gps/imaginary_groups.py +479 -0
- sage/groups/perm_gps/all__sagemath_modules.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_modules.py +1 -0
- sage/groups/perm_gps/partn_ref/refinement_binary.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_binary.pxd +41 -0
- sage/groups/perm_gps/partn_ref/refinement_binary.pyx +1167 -0
- sage/groups/perm_gps/partn_ref/refinement_matrices.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_matrices.pxd +31 -0
- sage/groups/perm_gps/partn_ref/refinement_matrices.pyx +385 -0
- sage/homology/algebraic_topological_model.py +595 -0
- sage/homology/all.py +2 -0
- sage/homology/all__sagemath_modules.py +8 -0
- sage/homology/chain_complex.py +2148 -0
- sage/homology/chain_complex_homspace.py +165 -0
- sage/homology/chain_complex_morphism.py +629 -0
- sage/homology/chain_homotopy.py +604 -0
- sage/homology/chains.py +653 -0
- sage/homology/free_resolution.py +923 -0
- sage/homology/graded_resolution.py +567 -0
- sage/homology/hochschild_complex.py +756 -0
- sage/homology/homology_group.py +188 -0
- sage/homology/homology_morphism.py +422 -0
- sage/homology/homology_vector_space_with_basis.py +1454 -0
- sage/homology/koszul_complex.py +169 -0
- sage/homology/matrix_utils.py +205 -0
- sage/libs/all__sagemath_modules.py +1 -0
- sage/libs/gsl/__init__.py +1 -0
- sage/libs/gsl/airy.pxd +56 -0
- sage/libs/gsl/all.pxd +66 -0
- sage/libs/gsl/array.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/gsl/array.pxd +5 -0
- sage/libs/gsl/array.pyx +102 -0
- sage/libs/gsl/bessel.pxd +208 -0
- sage/libs/gsl/blas.pxd +116 -0
- sage/libs/gsl/blas_types.pxd +34 -0
- sage/libs/gsl/block.pxd +52 -0
- sage/libs/gsl/chebyshev.pxd +37 -0
- sage/libs/gsl/clausen.pxd +12 -0
- sage/libs/gsl/combination.pxd +47 -0
- sage/libs/gsl/complex.pxd +151 -0
- sage/libs/gsl/coulomb.pxd +30 -0
- sage/libs/gsl/coupling.pxd +21 -0
- sage/libs/gsl/dawson.pxd +12 -0
- sage/libs/gsl/debye.pxd +24 -0
- sage/libs/gsl/dilog.pxd +14 -0
- sage/libs/gsl/eigen.pxd +46 -0
- sage/libs/gsl/elementary.pxd +12 -0
- sage/libs/gsl/ellint.pxd +48 -0
- sage/libs/gsl/elljac.pxd +8 -0
- sage/libs/gsl/erf.pxd +32 -0
- sage/libs/gsl/errno.pxd +26 -0
- sage/libs/gsl/exp.pxd +44 -0
- sage/libs/gsl/expint.pxd +44 -0
- sage/libs/gsl/fermi_dirac.pxd +44 -0
- sage/libs/gsl/fft.pxd +121 -0
- sage/libs/gsl/fit.pxd +50 -0
- sage/libs/gsl/gamma.pxd +94 -0
- sage/libs/gsl/gegenbauer.pxd +26 -0
- sage/libs/gsl/histogram.pxd +176 -0
- sage/libs/gsl/hyperg.pxd +52 -0
- sage/libs/gsl/integration.pxd +69 -0
- sage/libs/gsl/interp.pxd +109 -0
- sage/libs/gsl/laguerre.pxd +24 -0
- sage/libs/gsl/lambert.pxd +16 -0
- sage/libs/gsl/legendre.pxd +90 -0
- sage/libs/gsl/linalg.pxd +185 -0
- sage/libs/gsl/log.pxd +26 -0
- sage/libs/gsl/math.pxd +43 -0
- sage/libs/gsl/matrix.pxd +143 -0
- sage/libs/gsl/matrix_complex.pxd +130 -0
- sage/libs/gsl/min.pxd +67 -0
- sage/libs/gsl/monte.pxd +56 -0
- sage/libs/gsl/ntuple.pxd +32 -0
- sage/libs/gsl/odeiv.pxd +70 -0
- sage/libs/gsl/permutation.pxd +78 -0
- sage/libs/gsl/poly.pxd +40 -0
- sage/libs/gsl/pow_int.pxd +12 -0
- sage/libs/gsl/psi.pxd +28 -0
- sage/libs/gsl/qrng.pxd +29 -0
- sage/libs/gsl/random.pxd +257 -0
- sage/libs/gsl/rng.pxd +100 -0
- sage/libs/gsl/roots.pxd +72 -0
- sage/libs/gsl/sort.pxd +36 -0
- sage/libs/gsl/statistics.pxd +59 -0
- sage/libs/gsl/sum.pxd +55 -0
- sage/libs/gsl/synchrotron.pxd +16 -0
- sage/libs/gsl/transport.pxd +24 -0
- sage/libs/gsl/trig.pxd +58 -0
- sage/libs/gsl/types.pxd +137 -0
- sage/libs/gsl/vector.pxd +101 -0
- sage/libs/gsl/vector_complex.pxd +83 -0
- sage/libs/gsl/wavelet.pxd +49 -0
- sage/libs/gsl/zeta.pxd +28 -0
- sage/libs/mpc/__init__.pxd +114 -0
- sage/libs/mpc/types.pxd +28 -0
- sage/libs/mpfr/__init__.pxd +299 -0
- sage/libs/mpfr/types.pxd +26 -0
- sage/libs/mpmath/__init__.py +1 -0
- sage/libs/mpmath/all.py +27 -0
- sage/libs/mpmath/all__sagemath_modules.py +1 -0
- sage/libs/mpmath/utils.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/libs/mpmath/utils.pxd +4 -0
- sage/libs/mpmath/utils.pyx +319 -0
- sage/matrix/action.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/action.pxd +26 -0
- sage/matrix/action.pyx +596 -0
- sage/matrix/all.py +9 -0
- sage/matrix/args.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/args.pxd +144 -0
- sage/matrix/args.pyx +1668 -0
- sage/matrix/benchmark.py +1258 -0
- sage/matrix/berlekamp_massey.py +95 -0
- sage/matrix/compute_J_ideal.py +926 -0
- sage/matrix/constructor.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/constructor.pyx +750 -0
- sage/matrix/docs.py +430 -0
- sage/matrix/echelon_matrix.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/echelon_matrix.pyx +155 -0
- sage/matrix/matrix.pxd +2 -0
- sage/matrix/matrix0.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix0.pxd +68 -0
- sage/matrix/matrix0.pyx +6324 -0
- sage/matrix/matrix1.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix1.pxd +8 -0
- sage/matrix/matrix1.pyx +2851 -0
- sage/matrix/matrix2.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix2.pxd +25 -0
- sage/matrix/matrix2.pyx +20181 -0
- sage/matrix/matrix_cdv.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_cdv.pxd +4 -0
- sage/matrix/matrix_cdv.pyx +93 -0
- sage/matrix/matrix_complex_double_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_complex_double_dense.pxd +5 -0
- sage/matrix/matrix_complex_double_dense.pyx +98 -0
- sage/matrix/matrix_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_dense.pxd +5 -0
- sage/matrix/matrix_dense.pyx +343 -0
- sage/matrix/matrix_domain_dense.pxd +5 -0
- sage/matrix/matrix_domain_sparse.pxd +5 -0
- sage/matrix/matrix_double_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_double_dense.pxd +7 -0
- sage/matrix/matrix_double_dense.pyx +3906 -0
- sage/matrix/matrix_double_sparse.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_double_sparse.pxd +6 -0
- sage/matrix/matrix_double_sparse.pyx +248 -0
- sage/matrix/matrix_generic_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_generic_dense.pxd +7 -0
- sage/matrix/matrix_generic_dense.pyx +354 -0
- sage/matrix/matrix_generic_sparse.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_generic_sparse.pxd +7 -0
- sage/matrix/matrix_generic_sparse.pyx +461 -0
- sage/matrix/matrix_laurent_mpolynomial_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_laurent_mpolynomial_dense.pxd +5 -0
- sage/matrix/matrix_laurent_mpolynomial_dense.pyx +115 -0
- sage/matrix/matrix_misc.py +313 -0
- sage/matrix/matrix_numpy_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_numpy_dense.pxd +14 -0
- sage/matrix/matrix_numpy_dense.pyx +450 -0
- sage/matrix/matrix_numpy_integer_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_numpy_integer_dense.pxd +7 -0
- sage/matrix/matrix_numpy_integer_dense.pyx +59 -0
- sage/matrix/matrix_polynomial_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_polynomial_dense.pxd +5 -0
- sage/matrix/matrix_polynomial_dense.pyx +5341 -0
- sage/matrix/matrix_real_double_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_real_double_dense.pxd +7 -0
- sage/matrix/matrix_real_double_dense.pyx +122 -0
- sage/matrix/matrix_space.py +2848 -0
- sage/matrix/matrix_sparse.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_sparse.pxd +5 -0
- sage/matrix/matrix_sparse.pyx +1222 -0
- sage/matrix/matrix_window.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_window.pxd +37 -0
- sage/matrix/matrix_window.pyx +242 -0
- sage/matrix/misc_mpfr.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/misc_mpfr.pyx +80 -0
- sage/matrix/operation_table.py +1182 -0
- sage/matrix/special.py +3666 -0
- sage/matrix/strassen.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matrix/strassen.pyx +851 -0
- sage/matrix/symplectic_basis.py +541 -0
- sage/matrix/template.pxd +6 -0
- sage/matrix/tests.py +71 -0
- sage/matroids/advanced.py +77 -0
- sage/matroids/all.py +13 -0
- sage/matroids/basis_exchange_matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/basis_exchange_matroid.pxd +96 -0
- sage/matroids/basis_exchange_matroid.pyx +2344 -0
- sage/matroids/basis_matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/basis_matroid.pxd +45 -0
- sage/matroids/basis_matroid.pyx +1217 -0
- sage/matroids/catalog.py +44 -0
- sage/matroids/chow_ring.py +473 -0
- sage/matroids/chow_ring_ideal.py +849 -0
- sage/matroids/circuit_closures_matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/circuit_closures_matroid.pxd +16 -0
- sage/matroids/circuit_closures_matroid.pyx +559 -0
- sage/matroids/circuits_matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/circuits_matroid.pxd +38 -0
- sage/matroids/circuits_matroid.pyx +947 -0
- sage/matroids/constructor.py +1086 -0
- sage/matroids/database_collections.py +365 -0
- sage/matroids/database_matroids.py +5338 -0
- sage/matroids/dual_matroid.py +583 -0
- sage/matroids/extension.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/extension.pxd +34 -0
- sage/matroids/extension.pyx +519 -0
- sage/matroids/flats_matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/flats_matroid.pxd +28 -0
- sage/matroids/flats_matroid.pyx +715 -0
- sage/matroids/gammoid.py +600 -0
- sage/matroids/graphic_matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/graphic_matroid.pxd +39 -0
- sage/matroids/graphic_matroid.pyx +2024 -0
- sage/matroids/lean_matrix.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/lean_matrix.pxd +126 -0
- sage/matroids/lean_matrix.pyx +3667 -0
- sage/matroids/linear_matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/linear_matroid.pxd +180 -0
- sage/matroids/linear_matroid.pyx +6649 -0
- sage/matroids/matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/matroid.pxd +243 -0
- sage/matroids/matroid.pyx +8759 -0
- sage/matroids/matroids_catalog.py +190 -0
- sage/matroids/matroids_plot_helpers.py +890 -0
- sage/matroids/minor_matroid.py +480 -0
- sage/matroids/minorfix.h +9 -0
- sage/matroids/named_matroids.py +5 -0
- sage/matroids/rank_matroid.py +268 -0
- sage/matroids/set_system.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/set_system.pxd +38 -0
- sage/matroids/set_system.pyx +800 -0
- sage/matroids/transversal_matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/transversal_matroid.pxd +14 -0
- sage/matroids/transversal_matroid.pyx +893 -0
- sage/matroids/union_matroid.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/union_matroid.pxd +20 -0
- sage/matroids/union_matroid.pyx +331 -0
- sage/matroids/unpickling.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/matroids/unpickling.pyx +843 -0
- sage/matroids/utilities.py +809 -0
- sage/misc/all__sagemath_modules.py +20 -0
- sage/misc/c3.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/misc/c3.pyx +238 -0
- sage/misc/compat.py +87 -0
- sage/misc/element_with_label.py +173 -0
- sage/misc/func_persist.py +79 -0
- sage/misc/pickle_old.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/misc/pickle_old.pyx +19 -0
- sage/misc/proof.py +7 -0
- sage/misc/replace_dot_all.py +472 -0
- sage/misc/sagedoc_conf.py +168 -0
- sage/misc/sphinxify.py +167 -0
- sage/misc/test_class_pickling.py +85 -0
- sage/modules/all.py +42 -0
- sage/modules/complex_double_vector.py +25 -0
- sage/modules/diamond_cutting.py +380 -0
- sage/modules/fg_pid/all.py +1 -0
- sage/modules/fg_pid/fgp_element.py +456 -0
- sage/modules/fg_pid/fgp_module.py +2091 -0
- sage/modules/fg_pid/fgp_morphism.py +550 -0
- sage/modules/filtered_vector_space.py +1271 -0
- sage/modules/finite_submodule_iter.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/finite_submodule_iter.pxd +27 -0
- sage/modules/finite_submodule_iter.pyx +452 -0
- sage/modules/fp_graded/all.py +1 -0
- sage/modules/fp_graded/element.py +346 -0
- sage/modules/fp_graded/free_element.py +298 -0
- sage/modules/fp_graded/free_homspace.py +53 -0
- sage/modules/fp_graded/free_module.py +1060 -0
- sage/modules/fp_graded/free_morphism.py +217 -0
- sage/modules/fp_graded/homspace.py +563 -0
- sage/modules/fp_graded/module.py +1340 -0
- sage/modules/fp_graded/morphism.py +1990 -0
- sage/modules/fp_graded/steenrod/all.py +1 -0
- sage/modules/fp_graded/steenrod/homspace.py +65 -0
- sage/modules/fp_graded/steenrod/module.py +477 -0
- sage/modules/fp_graded/steenrod/morphism.py +404 -0
- sage/modules/fp_graded/steenrod/profile.py +241 -0
- sage/modules/free_module.py +8447 -0
- sage/modules/free_module_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/free_module_element.pxd +22 -0
- sage/modules/free_module_element.pyx +5445 -0
- sage/modules/free_module_homspace.py +369 -0
- sage/modules/free_module_integer.py +896 -0
- sage/modules/free_module_morphism.py +823 -0
- sage/modules/free_module_pseudohomspace.py +352 -0
- sage/modules/free_module_pseudomorphism.py +578 -0
- sage/modules/free_quadratic_module.py +1706 -0
- sage/modules/free_quadratic_module_integer_symmetric.py +1790 -0
- sage/modules/matrix_morphism.py +1745 -0
- sage/modules/misc.py +103 -0
- sage/modules/module_functors.py +192 -0
- sage/modules/multi_filtered_vector_space.py +719 -0
- sage/modules/ore_module.py +2208 -0
- sage/modules/ore_module_element.py +178 -0
- sage/modules/ore_module_homspace.py +147 -0
- sage/modules/ore_module_morphism.py +968 -0
- sage/modules/quotient_module.py +699 -0
- sage/modules/real_double_vector.py +22 -0
- sage/modules/submodule.py +255 -0
- sage/modules/tensor_operations.py +567 -0
- sage/modules/torsion_quadratic_module.py +1352 -0
- sage/modules/tutorial_free_modules.py +248 -0
- sage/modules/vector_complex_double_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_complex_double_dense.pxd +6 -0
- sage/modules/vector_complex_double_dense.pyx +117 -0
- sage/modules/vector_double_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_double_dense.pxd +6 -0
- sage/modules/vector_double_dense.pyx +604 -0
- sage/modules/vector_integer_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_integer_dense.pxd +15 -0
- sage/modules/vector_integer_dense.pyx +361 -0
- sage/modules/vector_integer_sparse.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_integer_sparse.pxd +29 -0
- sage/modules/vector_integer_sparse.pyx +406 -0
- sage/modules/vector_modn_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_modn_dense.pxd +12 -0
- sage/modules/vector_modn_dense.pyx +394 -0
- sage/modules/vector_modn_sparse.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_modn_sparse.pxd +21 -0
- sage/modules/vector_modn_sparse.pyx +298 -0
- sage/modules/vector_numpy_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_numpy_dense.pxd +15 -0
- sage/modules/vector_numpy_dense.pyx +304 -0
- sage/modules/vector_numpy_integer_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_numpy_integer_dense.pxd +7 -0
- sage/modules/vector_numpy_integer_dense.pyx +54 -0
- sage/modules/vector_rational_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_rational_dense.pxd +15 -0
- sage/modules/vector_rational_dense.pyx +387 -0
- sage/modules/vector_rational_sparse.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_rational_sparse.pxd +30 -0
- sage/modules/vector_rational_sparse.pyx +413 -0
- sage/modules/vector_real_double_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/vector_real_double_dense.pxd +6 -0
- sage/modules/vector_real_double_dense.pyx +126 -0
- sage/modules/vector_space_homspace.py +430 -0
- sage/modules/vector_space_morphism.py +989 -0
- sage/modules/with_basis/all.py +15 -0
- sage/modules/with_basis/cell_module.py +494 -0
- sage/modules/with_basis/indexed_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/modules/with_basis/indexed_element.pxd +13 -0
- sage/modules/with_basis/indexed_element.pyx +1058 -0
- sage/modules/with_basis/invariant.py +1075 -0
- sage/modules/with_basis/morphism.py +1636 -0
- sage/modules/with_basis/representation.py +2939 -0
- sage/modules/with_basis/subquotient.py +685 -0
- sage/numerical/all__sagemath_modules.py +6 -0
- sage/numerical/gauss_legendre.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/numerical/gauss_legendre.pyx +381 -0
- sage/numerical/optimize.py +910 -0
- sage/probability/all.py +10 -0
- sage/probability/probability_distribution.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/probability/probability_distribution.pyx +1242 -0
- sage/probability/random_variable.py +411 -0
- sage/quadratic_forms/all.py +4 -0
- sage/quadratic_forms/all__sagemath_modules.py +15 -0
- sage/quadratic_forms/binary_qf.py +2042 -0
- sage/quadratic_forms/bqf_class_group.py +748 -0
- sage/quadratic_forms/constructions.py +93 -0
- sage/quadratic_forms/count_local_2.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/quadratic_forms/count_local_2.pyx +365 -0
- sage/quadratic_forms/extras.py +195 -0
- sage/quadratic_forms/quadratic_form.py +1753 -0
- sage/quadratic_forms/quadratic_form__count_local_2.py +221 -0
- sage/quadratic_forms/quadratic_form__equivalence_testing.py +708 -0
- sage/quadratic_forms/quadratic_form__evaluate.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/quadratic_forms/quadratic_form__evaluate.pyx +139 -0
- sage/quadratic_forms/quadratic_form__local_density_congruence.py +977 -0
- sage/quadratic_forms/quadratic_form__local_field_invariants.py +1072 -0
- sage/quadratic_forms/quadratic_form__neighbors.py +424 -0
- sage/quadratic_forms/quadratic_form__reduction_theory.py +488 -0
- sage/quadratic_forms/quadratic_form__split_local_covering.py +416 -0
- sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +657 -0
- sage/quadratic_forms/quadratic_form__theta.py +352 -0
- sage/quadratic_forms/quadratic_form__variable_substitutions.py +370 -0
- sage/quadratic_forms/random_quadraticform.py +209 -0
- sage/quadratic_forms/ternary.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/quadratic_forms/ternary.pyx +1154 -0
- sage/quadratic_forms/ternary_qf.py +2027 -0
- sage/rings/all__sagemath_modules.py +28 -0
- sage/rings/asymptotic/all__sagemath_modules.py +1 -0
- sage/rings/asymptotic/misc.py +1252 -0
- sage/rings/cc.py +4 -0
- sage/rings/cfinite_sequence.py +1306 -0
- sage/rings/complex_conversion.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/complex_conversion.pxd +8 -0
- sage/rings/complex_conversion.pyx +23 -0
- sage/rings/complex_double.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/complex_double.pxd +21 -0
- sage/rings/complex_double.pyx +2654 -0
- sage/rings/complex_mpc.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/complex_mpc.pxd +21 -0
- sage/rings/complex_mpc.pyx +2576 -0
- sage/rings/complex_mpfr.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/complex_mpfr.pxd +18 -0
- sage/rings/complex_mpfr.pyx +3602 -0
- sage/rings/derivation.py +2334 -0
- sage/rings/finite_rings/all__sagemath_modules.py +1 -0
- sage/rings/finite_rings/maps_finite_field.py +191 -0
- sage/rings/function_field/all__sagemath_modules.py +8 -0
- sage/rings/function_field/derivations.py +102 -0
- sage/rings/function_field/derivations_rational.py +132 -0
- sage/rings/function_field/differential.py +853 -0
- sage/rings/function_field/divisor.py +1107 -0
- sage/rings/function_field/drinfeld_modules/action.py +199 -0
- sage/rings/function_field/drinfeld_modules/all.py +1 -0
- sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py +673 -0
- sage/rings/function_field/drinfeld_modules/drinfeld_module.py +2087 -0
- sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py +1131 -0
- sage/rings/function_field/drinfeld_modules/homset.py +420 -0
- sage/rings/function_field/drinfeld_modules/morphism.py +820 -0
- sage/rings/function_field/hermite_form_polynomial.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/function_field/hermite_form_polynomial.pyx +188 -0
- sage/rings/function_field/khuri_makdisi.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/function_field/khuri_makdisi.pyx +935 -0
- sage/rings/invariants/all.py +4 -0
- sage/rings/invariants/invariant_theory.py +4597 -0
- sage/rings/invariants/reconstruction.py +395 -0
- sage/rings/polynomial/all__sagemath_modules.py +17 -0
- sage/rings/polynomial/integer_valued_polynomials.py +1230 -0
- sage/rings/polynomial/laurent_polynomial_mpair.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/laurent_polynomial_mpair.pxd +15 -0
- sage/rings/polynomial/laurent_polynomial_mpair.pyx +2023 -0
- sage/rings/polynomial/ore_function_element.py +952 -0
- sage/rings/polynomial/ore_function_field.py +1028 -0
- sage/rings/polynomial/ore_polynomial_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/ore_polynomial_element.pxd +48 -0
- sage/rings/polynomial/ore_polynomial_element.pyx +3145 -0
- sage/rings/polynomial/ore_polynomial_ring.py +1334 -0
- sage/rings/polynomial/polynomial_real_mpfr_dense.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +788 -0
- sage/rings/polynomial/q_integer_valued_polynomials.py +1264 -0
- sage/rings/polynomial/skew_polynomial_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/skew_polynomial_element.pxd +9 -0
- sage/rings/polynomial/skew_polynomial_element.pyx +684 -0
- sage/rings/polynomial/skew_polynomial_finite_field.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/skew_polynomial_finite_field.pxd +19 -0
- sage/rings/polynomial/skew_polynomial_finite_field.pyx +1093 -0
- sage/rings/polynomial/skew_polynomial_finite_order.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/skew_polynomial_finite_order.pxd +10 -0
- sage/rings/polynomial/skew_polynomial_finite_order.pyx +567 -0
- sage/rings/polynomial/skew_polynomial_ring.py +908 -0
- sage/rings/real_double_element_gsl.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/real_double_element_gsl.pxd +8 -0
- sage/rings/real_double_element_gsl.pyx +794 -0
- sage/rings/real_field.py +58 -0
- sage/rings/real_mpfr.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/real_mpfr.pxd +29 -0
- sage/rings/real_mpfr.pyx +6122 -0
- sage/rings/ring_extension.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/ring_extension.pxd +42 -0
- sage/rings/ring_extension.pyx +2779 -0
- sage/rings/ring_extension_conversion.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/ring_extension_conversion.pxd +16 -0
- sage/rings/ring_extension_conversion.pyx +462 -0
- sage/rings/ring_extension_element.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/ring_extension_element.pxd +21 -0
- sage/rings/ring_extension_element.pyx +1635 -0
- sage/rings/ring_extension_homset.py +64 -0
- sage/rings/ring_extension_morphism.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/rings/ring_extension_morphism.pxd +35 -0
- sage/rings/ring_extension_morphism.pyx +920 -0
- sage/schemes/all__sagemath_modules.py +1 -0
- sage/schemes/projective/all__sagemath_modules.py +1 -0
- sage/schemes/projective/coherent_sheaf.py +300 -0
- sage/schemes/projective/cohomology.py +510 -0
- sage/stats/all.py +15 -0
- sage/stats/basic_stats.py +489 -0
- sage/stats/distributions/all.py +7 -0
- sage/stats/distributions/catalog.py +34 -0
- sage/stats/distributions/dgs.h +50 -0
- sage/stats/distributions/dgs.pxd +111 -0
- sage/stats/distributions/dgs_bern.h +400 -0
- sage/stats/distributions/dgs_gauss.h +614 -0
- sage/stats/distributions/dgs_misc.h +104 -0
- sage/stats/distributions/discrete_gaussian_integer.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/stats/distributions/discrete_gaussian_integer.pxd +14 -0
- sage/stats/distributions/discrete_gaussian_integer.pyx +498 -0
- sage/stats/distributions/discrete_gaussian_lattice.py +908 -0
- sage/stats/distributions/discrete_gaussian_polynomial.py +141 -0
- sage/stats/hmm/all.py +15 -0
- sage/stats/hmm/chmm.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/stats/hmm/chmm.pyx +1595 -0
- sage/stats/hmm/distributions.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/stats/hmm/distributions.pxd +29 -0
- sage/stats/hmm/distributions.pyx +531 -0
- sage/stats/hmm/hmm.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/stats/hmm/hmm.pxd +17 -0
- sage/stats/hmm/hmm.pyx +1388 -0
- sage/stats/hmm/util.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/stats/hmm/util.pxd +7 -0
- sage/stats/hmm/util.pyx +165 -0
- sage/stats/intlist.cpython-314-aarch64-linux-gnu.so +0 -0
- sage/stats/intlist.pxd +14 -0
- sage/stats/intlist.pyx +588 -0
- sage/stats/r.py +49 -0
- sage/stats/time_series.cpython-314-aarch64-linux-gnu.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,3289 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-modules
|
|
2
|
+
r"""
|
|
3
|
+
Tensors on free modules
|
|
4
|
+
|
|
5
|
+
The class :class:`FreeModuleTensor` implements tensors on a free module `M`
|
|
6
|
+
of finite rank over a commutative ring. A *tensor of type* `(k,l)` on `M`
|
|
7
|
+
is a multilinear map:
|
|
8
|
+
|
|
9
|
+
.. MATH::
|
|
10
|
+
|
|
11
|
+
\underbrace{M^*\times\cdots\times M^*}_{k\ \; \mbox{times}}
|
|
12
|
+
\times \underbrace{M\times\cdots\times M}_{l\ \; \mbox{times}}
|
|
13
|
+
\longrightarrow R
|
|
14
|
+
|
|
15
|
+
where `R` is the commutative ring over which the free module `M` is defined
|
|
16
|
+
and `M^* = \mathrm{Hom}_R(M,R)` is the dual of `M`. The integer `k + l` is
|
|
17
|
+
called the *tensor rank*. The set `T^{(k,l)}(M)` of tensors of type `(k,l)`
|
|
18
|
+
on `M` is a free module of finite rank over `R`, described by the
|
|
19
|
+
class :class:`~sage.tensor.modules.tensor_free_module.TensorFreeModule`.
|
|
20
|
+
|
|
21
|
+
Various derived classes of :class:`FreeModuleTensor` are devoted to specific
|
|
22
|
+
tensors:
|
|
23
|
+
|
|
24
|
+
* :class:`~sage.tensor.modules.alternating_contr_tensor.AlternatingContrTensor`
|
|
25
|
+
for fully antisymmetric type-`(k, 0)` tensors *(alternating contravariant
|
|
26
|
+
tensors)*;
|
|
27
|
+
|
|
28
|
+
- :class:`~sage.tensor.modules.free_module_element.FiniteRankFreeModuleElement`
|
|
29
|
+
for elements of `M`, considered as type-`(1,0)` tensors thanks to the
|
|
30
|
+
canonical identification `M^{**}=M` (which holds since `M` is a free module
|
|
31
|
+
of finite rank);
|
|
32
|
+
|
|
33
|
+
* :class:`~sage.tensor.modules.free_module_alt_form.FreeModuleAltForm` for
|
|
34
|
+
fully antisymmetric type-`(0, l)` tensors *(alternating forms)*;
|
|
35
|
+
|
|
36
|
+
* :class:`~sage.tensor.modules.free_module_automorphism.FreeModuleAutomorphism`
|
|
37
|
+
for type-`(1,1)` tensors representing invertible endomorphisms.
|
|
38
|
+
|
|
39
|
+
Each of these classes is a Sage *element* class, the corresponding *parent*
|
|
40
|
+
class being:
|
|
41
|
+
|
|
42
|
+
* :class:`~sage.tensor.modules.tensor_free_module.TensorFreeModule` for
|
|
43
|
+
:class:`FreeModuleTensor`;
|
|
44
|
+
* :class:`~sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule`
|
|
45
|
+
for :class:`~sage.tensor.modules.free_module_element.FiniteRankFreeModuleElement`;
|
|
46
|
+
* :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerFreeModule` for
|
|
47
|
+
:class:`~sage.tensor.modules.alternating_contr_tensor.AlternatingContrTensor`;
|
|
48
|
+
* :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerDualFreeModule` for
|
|
49
|
+
:class:`~sage.tensor.modules.free_module_alt_form.FreeModuleAltForm`;
|
|
50
|
+
* :class:`~sage.tensor.modules.free_module_linear_group.FreeModuleLinearGroup`
|
|
51
|
+
for
|
|
52
|
+
:class:`~sage.tensor.modules.free_module_automorphism.FreeModuleAutomorphism`.
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
AUTHORS:
|
|
56
|
+
|
|
57
|
+
- Eric Gourgoulhon, Michal Bejger (2014-2015): initial version
|
|
58
|
+
- Michael Jung (2019): improve treatment of the zero element; add method
|
|
59
|
+
``copy_from``
|
|
60
|
+
|
|
61
|
+
REFERENCES:
|
|
62
|
+
|
|
63
|
+
- Chap. 21 of R. Godement : *Algebra* [God1968]_
|
|
64
|
+
- Chap. 12 of J. M. Lee: *Introduction to Smooth Manifolds* [Lee2013]_ (only
|
|
65
|
+
when the free module is a vector space)
|
|
66
|
+
- Chap. 2 of B. O'Neill: *Semi-Riemannian Geometry* [ONe1983]_
|
|
67
|
+
|
|
68
|
+
EXAMPLES:
|
|
69
|
+
|
|
70
|
+
A tensor of type `(1, 1)` on a rank-3 free module over `\ZZ`::
|
|
71
|
+
|
|
72
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
73
|
+
sage: t = M.tensor((1,1), name='t') ; t
|
|
74
|
+
Type-(1,1) tensor t on the Rank-3 free module M over the Integer Ring
|
|
75
|
+
sage: t.parent()
|
|
76
|
+
Free module of type-(1,1) tensors on the Rank-3 free module M
|
|
77
|
+
over the Integer Ring
|
|
78
|
+
sage: t.parent() is M.tensor_module(1,1)
|
|
79
|
+
True
|
|
80
|
+
sage: t in M.tensor_module(1,1)
|
|
81
|
+
True
|
|
82
|
+
|
|
83
|
+
Setting some component of the tensor in a given basis::
|
|
84
|
+
|
|
85
|
+
sage: e = M.basis('e') ; e
|
|
86
|
+
Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring
|
|
87
|
+
sage: t.set_comp(e)[0,0] = -3 # the component [0,0] w.r.t. basis e is set to -3
|
|
88
|
+
|
|
89
|
+
The unset components are assumed to be zero::
|
|
90
|
+
|
|
91
|
+
sage: t.comp(e)[:] # list of all components w.r.t. basis e
|
|
92
|
+
[-3 0 0]
|
|
93
|
+
[ 0 0 0]
|
|
94
|
+
[ 0 0 0]
|
|
95
|
+
sage: t.display(e) # displays the expansion of t on the basis e_i⊗e^j of T^(1,1)(M)
|
|
96
|
+
t = -3 e_0⊗e^0
|
|
97
|
+
|
|
98
|
+
The commands ``t.set_comp(e)`` and ``t.comp(e)`` can be abridged by providing
|
|
99
|
+
the basis as the first argument in the square brackets::
|
|
100
|
+
|
|
101
|
+
sage: t[e,0,0] = -3
|
|
102
|
+
sage: t[e,:]
|
|
103
|
+
[-3 0 0]
|
|
104
|
+
[ 0 0 0]
|
|
105
|
+
[ 0 0 0]
|
|
106
|
+
|
|
107
|
+
Actually, since ``e`` is ``M``'s default basis, the mention of ``e``
|
|
108
|
+
can be omitted::
|
|
109
|
+
|
|
110
|
+
sage: t[0,0] = -3
|
|
111
|
+
sage: t[:]
|
|
112
|
+
[-3 0 0]
|
|
113
|
+
[ 0 0 0]
|
|
114
|
+
[ 0 0 0]
|
|
115
|
+
|
|
116
|
+
For tensors of rank 2, the matrix of components w.r.t. a given basis is
|
|
117
|
+
obtained via the function ``matrix``::
|
|
118
|
+
|
|
119
|
+
sage: matrix(t.comp(e))
|
|
120
|
+
[-3 0 0]
|
|
121
|
+
[ 0 0 0]
|
|
122
|
+
[ 0 0 0]
|
|
123
|
+
sage: matrix(t.comp(e)).parent()
|
|
124
|
+
Full MatrixSpace of 3 by 3 dense matrices over Integer Ring
|
|
125
|
+
|
|
126
|
+
Tensor components can be modified (reset) at any time::
|
|
127
|
+
|
|
128
|
+
sage: t[0,0] = 0
|
|
129
|
+
sage: t[:]
|
|
130
|
+
[0 0 0]
|
|
131
|
+
[0 0 0]
|
|
132
|
+
[0 0 0]
|
|
133
|
+
|
|
134
|
+
Checking that ``t`` is zero::
|
|
135
|
+
|
|
136
|
+
sage: t.is_zero()
|
|
137
|
+
True
|
|
138
|
+
sage: t == 0
|
|
139
|
+
True
|
|
140
|
+
sage: t == M.tensor_module(1,1).zero() # the zero element of the module of all type-(1,1) tensors on M
|
|
141
|
+
True
|
|
142
|
+
|
|
143
|
+
The components are managed by the class
|
|
144
|
+
:class:`~sage.tensor.modules.comp.Components`::
|
|
145
|
+
|
|
146
|
+
sage: type(t.comp(e))
|
|
147
|
+
<class 'sage.tensor.modules.comp.Components'>
|
|
148
|
+
|
|
149
|
+
Only nonzero components are actually stored, in the dictionary :attr:`_comp`
|
|
150
|
+
of class :class:`~sage.tensor.modules.comp.Components`, whose keys are
|
|
151
|
+
the indices::
|
|
152
|
+
|
|
153
|
+
sage: t.comp(e)._comp
|
|
154
|
+
{}
|
|
155
|
+
sage: t.set_comp(e)[0,0] = -3 ; t.set_comp(e)[1,2] = 2
|
|
156
|
+
sage: t.comp(e)._comp # random output order (dictionary)
|
|
157
|
+
{(0, 0): -3, (1, 2): 2}
|
|
158
|
+
sage: t.display(e)
|
|
159
|
+
t = -3 e_0⊗e^0 + 2 e_1⊗e^2
|
|
160
|
+
|
|
161
|
+
Further tests of the comparison operator::
|
|
162
|
+
|
|
163
|
+
sage: t.is_zero()
|
|
164
|
+
False
|
|
165
|
+
sage: t == 0
|
|
166
|
+
False
|
|
167
|
+
sage: t == M.tensor_module(1,1).zero()
|
|
168
|
+
False
|
|
169
|
+
sage: t1 = t.copy()
|
|
170
|
+
sage: t1 == t
|
|
171
|
+
True
|
|
172
|
+
sage: t1[2,0] = 4
|
|
173
|
+
sage: t1 == t
|
|
174
|
+
False
|
|
175
|
+
|
|
176
|
+
As a multilinear map `M^* \times M \rightarrow \ZZ`, the type-`(1,1)`
|
|
177
|
+
tensor ``t`` acts on pairs formed by a linear form and a module element::
|
|
178
|
+
|
|
179
|
+
sage: a = M.linear_form(name='a') ; a[:] = (2, 1, -3) ; a
|
|
180
|
+
Linear form a on the Rank-3 free module M over the Integer Ring
|
|
181
|
+
sage: b = M([1,-6,2], name='b') ; b
|
|
182
|
+
Element b of the Rank-3 free module M over the Integer Ring
|
|
183
|
+
sage: t(a,b)
|
|
184
|
+
-2
|
|
185
|
+
"""
|
|
186
|
+
# *****************************************************************************
|
|
187
|
+
# Copyright (C) 2015 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
|
|
188
|
+
# Copyright (C) 2015 Michal Bejger <bejger@camk.edu.pl>
|
|
189
|
+
#
|
|
190
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
191
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
192
|
+
# the License, or (at your option) any later version.
|
|
193
|
+
# https://www.gnu.org/licenses/
|
|
194
|
+
# *****************************************************************************
|
|
195
|
+
from __future__ import annotations
|
|
196
|
+
|
|
197
|
+
from typing import TYPE_CHECKING, Optional, Union
|
|
198
|
+
|
|
199
|
+
from sage.parallel.decorate import parallel
|
|
200
|
+
from sage.parallel.parallelism import Parallelism
|
|
201
|
+
from sage.rings.integer import Integer
|
|
202
|
+
from sage.structure.element import ModuleElementWithMutability
|
|
203
|
+
from sage.tensor.modules.comp import (
|
|
204
|
+
CompFullyAntiSym,
|
|
205
|
+
CompFullySym,
|
|
206
|
+
Components,
|
|
207
|
+
CompWithSym,
|
|
208
|
+
)
|
|
209
|
+
from sage.tensor.modules.tensor_with_indices import TensorWithIndices
|
|
210
|
+
|
|
211
|
+
if TYPE_CHECKING:
|
|
212
|
+
from sage.symbolic.expression import Expression
|
|
213
|
+
from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule
|
|
214
|
+
from sage.tensor.modules.free_module_basis import FreeModuleBasis
|
|
215
|
+
from sage.manifolds.differentiable.metric import PseudoRiemannianMetric
|
|
216
|
+
from sage.manifolds.differentiable.poisson_tensor import PoissonTensorField
|
|
217
|
+
from sage.manifolds.differentiable.symplectic_form import SymplecticForm
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class FreeModuleTensor(ModuleElementWithMutability):
|
|
221
|
+
r"""
|
|
222
|
+
Tensor over a free module of finite rank over a commutative ring.
|
|
223
|
+
|
|
224
|
+
This is a Sage *element* class, the corresponding *parent* class being
|
|
225
|
+
:class:`~sage.tensor.modules.tensor_free_module.TensorFreeModule`.
|
|
226
|
+
|
|
227
|
+
INPUT:
|
|
228
|
+
|
|
229
|
+
- ``fmodule`` -- free module `M` of finite rank over a commutative ring
|
|
230
|
+
`R`, as an instance of
|
|
231
|
+
:class:`~sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule`
|
|
232
|
+
- ``tensor_type`` -- pair ``(k, l)`` with ``k`` being the contravariant
|
|
233
|
+
rank and ``l`` the covariant rank
|
|
234
|
+
- ``name`` -- (default: ``None``) name given to the tensor
|
|
235
|
+
- ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the tensor;
|
|
236
|
+
if none is provided, the LaTeX symbol is set to ``name``
|
|
237
|
+
- ``sym`` -- (default: ``None``) a symmetry or a list of symmetries among
|
|
238
|
+
the tensor arguments: each symmetry is described by a tuple containing
|
|
239
|
+
the positions of the involved arguments, with the convention
|
|
240
|
+
``position=0`` for the first argument. For instance:
|
|
241
|
+
|
|
242
|
+
* ``sym = (0,1)`` for a symmetry between the 1st and 2nd arguments;
|
|
243
|
+
* ``sym = [(0,2), (1,3,4)]`` for a symmetry between the 1st and 3rd
|
|
244
|
+
arguments and a symmetry between the 2nd, 4th and 5th arguments.
|
|
245
|
+
|
|
246
|
+
- ``antisym`` -- (default: ``None``) antisymmetry or list of antisymmetries
|
|
247
|
+
among the arguments, with the same convention as for ``sym``
|
|
248
|
+
- ``parent`` -- (default: ``None``) some specific parent (e.g. exterior
|
|
249
|
+
power for alternating forms); if ``None``, ``fmodule.tensor_module(k,l)``
|
|
250
|
+
is used
|
|
251
|
+
|
|
252
|
+
EXAMPLES:
|
|
253
|
+
|
|
254
|
+
A tensor of type `(1,1)` on a rank-3 free module over `\ZZ`::
|
|
255
|
+
|
|
256
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
257
|
+
sage: t = M.tensor((1,1), name='t') ; t
|
|
258
|
+
Type-(1,1) tensor t on the Rank-3 free module M over the Integer Ring
|
|
259
|
+
|
|
260
|
+
Tensors are *Element* objects whose parents are tensor free modules::
|
|
261
|
+
|
|
262
|
+
sage: t.parent()
|
|
263
|
+
Free module of type-(1,1) tensors on the
|
|
264
|
+
Rank-3 free module M over the Integer Ring
|
|
265
|
+
sage: t.parent() is M.tensor_module(1,1)
|
|
266
|
+
True
|
|
267
|
+
"""
|
|
268
|
+
_fmodule: FiniteRankFreeModule
|
|
269
|
+
|
|
270
|
+
def __init__(
|
|
271
|
+
self,
|
|
272
|
+
fmodule: FiniteRankFreeModule,
|
|
273
|
+
tensor_type,
|
|
274
|
+
name: Optional[str] = None,
|
|
275
|
+
latex_name: Optional[str] = None,
|
|
276
|
+
sym=None,
|
|
277
|
+
antisym=None,
|
|
278
|
+
parent=None,
|
|
279
|
+
):
|
|
280
|
+
r"""
|
|
281
|
+
TESTS::
|
|
282
|
+
|
|
283
|
+
sage: from sage.tensor.modules.free_module_tensor import FreeModuleTensor
|
|
284
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
285
|
+
sage: e = M.basis('e')
|
|
286
|
+
sage: t = FreeModuleTensor(M, (2,1), name='t', latex_name=r'\tau', sym=(0,1))
|
|
287
|
+
sage: t[e,0,0,0] = -3
|
|
288
|
+
sage: TestSuite(t).run(skip='_test_category') # see below
|
|
289
|
+
|
|
290
|
+
In the above test suite, _test_category fails because t is not an
|
|
291
|
+
instance of t.parent().category().element_class. Actually tensors
|
|
292
|
+
must be constructed via TensorFreeModule.element_class and
|
|
293
|
+
not by a direct call to FreeModuleTensor::
|
|
294
|
+
|
|
295
|
+
sage: t1 = M.tensor_module(2,1).element_class(M, (2,1), name='t',
|
|
296
|
+
....: latex_name=r'\tau',
|
|
297
|
+
....: sym=(0,1))
|
|
298
|
+
sage: t1[e,0,0,0] = -3
|
|
299
|
+
sage: TestSuite(t1).run()
|
|
300
|
+
"""
|
|
301
|
+
if parent is None:
|
|
302
|
+
parent = fmodule.tensor_module(*tensor_type)
|
|
303
|
+
ModuleElementWithMutability.__init__(self, parent)
|
|
304
|
+
self._fmodule = fmodule
|
|
305
|
+
self._tensor_type = tuple(tensor_type)
|
|
306
|
+
self._tensor_rank = self._tensor_type[0] + self._tensor_type[1]
|
|
307
|
+
self._is_zero = False # a priori, may be changed below or via
|
|
308
|
+
# method __bool__()
|
|
309
|
+
self._name = name
|
|
310
|
+
if latex_name is None:
|
|
311
|
+
self._latex_name = self._name
|
|
312
|
+
else:
|
|
313
|
+
self._latex_name = latex_name
|
|
314
|
+
self._components: dict[FreeModuleBasis, Components] = {} # dict. of the sets of components on various
|
|
315
|
+
# bases, with the bases as keys (initially empty)
|
|
316
|
+
|
|
317
|
+
# Treatment of symmetry declarations:
|
|
318
|
+
self._sym, self._antisym = CompWithSym._canonicalize_sym_antisym(
|
|
319
|
+
self._tensor_rank, sym, antisym)
|
|
320
|
+
|
|
321
|
+
# Initialization of derived quantities:
|
|
322
|
+
FreeModuleTensor._init_derived(self)
|
|
323
|
+
|
|
324
|
+
####### Required methods for ModuleElement (beside arithmetic) #######
|
|
325
|
+
|
|
326
|
+
def __bool__(self):
|
|
327
|
+
r"""
|
|
328
|
+
Return ``True`` if ``self`` is nonzero and ``False`` otherwise.
|
|
329
|
+
|
|
330
|
+
This method is called by ``self.is_zero()``.
|
|
331
|
+
|
|
332
|
+
EXAMPLES::
|
|
333
|
+
|
|
334
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
335
|
+
sage: e = M.basis('e')
|
|
336
|
+
sage: t = M.tensor((2,1))
|
|
337
|
+
sage: t.add_comp(e)
|
|
338
|
+
3-indices components w.r.t. Basis (e_0,e_1,e_2) on the
|
|
339
|
+
Rank-3 free module M over the Integer Ring
|
|
340
|
+
sage: bool(t) # uninitialized components are zero
|
|
341
|
+
False
|
|
342
|
+
sage: t == 0
|
|
343
|
+
True
|
|
344
|
+
sage: t[e,1,0,2] = 4 # setting a nonzero component in basis e
|
|
345
|
+
sage: t.display()
|
|
346
|
+
4 e_1⊗e_0⊗e^2
|
|
347
|
+
sage: bool(t)
|
|
348
|
+
True
|
|
349
|
+
sage: t == 0
|
|
350
|
+
False
|
|
351
|
+
sage: t[e,1,0,2] = 0
|
|
352
|
+
sage: t.display()
|
|
353
|
+
0
|
|
354
|
+
sage: bool(t)
|
|
355
|
+
False
|
|
356
|
+
sage: t == 0
|
|
357
|
+
True
|
|
358
|
+
"""
|
|
359
|
+
basis = self.pick_a_basis()
|
|
360
|
+
if not self._components[basis].is_zero():
|
|
361
|
+
self._is_zero = False
|
|
362
|
+
return True
|
|
363
|
+
self._is_zero = True
|
|
364
|
+
return False
|
|
365
|
+
|
|
366
|
+
##### End of required methods for ModuleElement (beside arithmetic) #####
|
|
367
|
+
|
|
368
|
+
def _repr_(self):
|
|
369
|
+
r"""
|
|
370
|
+
Return a string representation of ``self``.
|
|
371
|
+
|
|
372
|
+
EXAMPLES::
|
|
373
|
+
|
|
374
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
375
|
+
sage: t = M.tensor((2,1), name='t')
|
|
376
|
+
sage: t
|
|
377
|
+
Type-(2,1) tensor t on the Rank-3 free module M over the Integer Ring
|
|
378
|
+
"""
|
|
379
|
+
# Special cases
|
|
380
|
+
if self._tensor_type == (0,2) and self._sym == ((0,1),):
|
|
381
|
+
description = "Symmetric bilinear form "
|
|
382
|
+
else:
|
|
383
|
+
# Generic case
|
|
384
|
+
description = "Type-({},{}) tensor".format(
|
|
385
|
+
self._tensor_type[0], self._tensor_type[1])
|
|
386
|
+
if self._name is not None:
|
|
387
|
+
description += " " + self._name
|
|
388
|
+
description += " on the {}".format(self._fmodule)
|
|
389
|
+
return description
|
|
390
|
+
|
|
391
|
+
def _latex_(self):
|
|
392
|
+
r"""
|
|
393
|
+
LaTeX representation of the object.
|
|
394
|
+
|
|
395
|
+
EXAMPLES::
|
|
396
|
+
|
|
397
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
398
|
+
sage: t = M.tensor((2,1), name='t')
|
|
399
|
+
sage: t._latex_()
|
|
400
|
+
't'
|
|
401
|
+
sage: latex(t)
|
|
402
|
+
t
|
|
403
|
+
sage: t = M.tensor((2,1), name='t', latex_name=r'\tau')
|
|
404
|
+
sage: t._latex_()
|
|
405
|
+
'\\tau'
|
|
406
|
+
sage: latex(t)
|
|
407
|
+
\tau
|
|
408
|
+
sage: t = M.tensor((2,1)) # unnamed tensor
|
|
409
|
+
sage: t._latex_()
|
|
410
|
+
'\\mbox{Type-(2,1) tensor on the Rank-3 free module M over the Integer Ring}'
|
|
411
|
+
"""
|
|
412
|
+
if self._latex_name is None:
|
|
413
|
+
return r'\mbox{' + str(self) + r'}'
|
|
414
|
+
return self._latex_name
|
|
415
|
+
|
|
416
|
+
def _init_derived(self):
|
|
417
|
+
r"""
|
|
418
|
+
Initialize the derived quantities.
|
|
419
|
+
|
|
420
|
+
EXAMPLES::
|
|
421
|
+
|
|
422
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
423
|
+
sage: t = M.tensor((2,1), name='t')
|
|
424
|
+
sage: t._init_derived()
|
|
425
|
+
"""
|
|
426
|
+
pass # no derived quantities
|
|
427
|
+
|
|
428
|
+
def _del_derived(self):
|
|
429
|
+
r"""
|
|
430
|
+
Delete the derived quantities.
|
|
431
|
+
|
|
432
|
+
EXAMPLES::
|
|
433
|
+
|
|
434
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
435
|
+
sage: t = M.tensor((2,1), name='t')
|
|
436
|
+
sage: t._del_derived()
|
|
437
|
+
"""
|
|
438
|
+
pass # no derived quantities
|
|
439
|
+
|
|
440
|
+
#### Simple accessors ####
|
|
441
|
+
|
|
442
|
+
def tensor_type(self):
|
|
443
|
+
r"""
|
|
444
|
+
Return the tensor type of ``self``.
|
|
445
|
+
|
|
446
|
+
OUTPUT:
|
|
447
|
+
|
|
448
|
+
- pair ``(k, l)``, where ``k`` is the contravariant rank and ``l``
|
|
449
|
+
is the covariant rank
|
|
450
|
+
|
|
451
|
+
EXAMPLES::
|
|
452
|
+
|
|
453
|
+
sage: M = FiniteRankFreeModule(ZZ, 3)
|
|
454
|
+
sage: M.an_element().tensor_type()
|
|
455
|
+
(1, 0)
|
|
456
|
+
sage: t = M.tensor((2,1))
|
|
457
|
+
sage: t.tensor_type()
|
|
458
|
+
(2, 1)
|
|
459
|
+
"""
|
|
460
|
+
return self._tensor_type
|
|
461
|
+
|
|
462
|
+
def tensor_rank(self):
|
|
463
|
+
r"""
|
|
464
|
+
Return the tensor rank of ``self``.
|
|
465
|
+
|
|
466
|
+
OUTPUT:
|
|
467
|
+
|
|
468
|
+
- integer ``k+l``, where ``k`` is the contravariant rank and ``l``
|
|
469
|
+
is the covariant rank
|
|
470
|
+
|
|
471
|
+
EXAMPLES::
|
|
472
|
+
|
|
473
|
+
sage: M = FiniteRankFreeModule(ZZ, 3)
|
|
474
|
+
sage: M.an_element().tensor_rank()
|
|
475
|
+
1
|
|
476
|
+
sage: t = M.tensor((2,1))
|
|
477
|
+
sage: t.tensor_rank()
|
|
478
|
+
3
|
|
479
|
+
"""
|
|
480
|
+
return self._tensor_rank
|
|
481
|
+
|
|
482
|
+
def base_module(self):
|
|
483
|
+
r"""
|
|
484
|
+
Return the module on which ``self`` is defined.
|
|
485
|
+
|
|
486
|
+
OUTPUT:
|
|
487
|
+
|
|
488
|
+
- instance of :class:`FiniteRankFreeModule` representing the free
|
|
489
|
+
module on which the tensor is defined.
|
|
490
|
+
|
|
491
|
+
EXAMPLES::
|
|
492
|
+
|
|
493
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
494
|
+
sage: M.an_element().base_module()
|
|
495
|
+
Rank-3 free module M over the Integer Ring
|
|
496
|
+
sage: t = M.tensor((2,1))
|
|
497
|
+
sage: t.base_module()
|
|
498
|
+
Rank-3 free module M over the Integer Ring
|
|
499
|
+
sage: t.base_module() is M
|
|
500
|
+
True
|
|
501
|
+
"""
|
|
502
|
+
return self._fmodule
|
|
503
|
+
|
|
504
|
+
def symmetries(self):
|
|
505
|
+
r"""
|
|
506
|
+
Print the list of symmetries and antisymmetries of ``self``.
|
|
507
|
+
|
|
508
|
+
EXAMPLES:
|
|
509
|
+
|
|
510
|
+
Various symmetries / antisymmetries for a rank-4 tensor::
|
|
511
|
+
|
|
512
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
513
|
+
sage: t = M.tensor((4,0), name='T') # no symmetry declared
|
|
514
|
+
sage: t.symmetries()
|
|
515
|
+
no symmetry; no antisymmetry
|
|
516
|
+
sage: t = M.tensor((4,0), name='T', sym=(0,1))
|
|
517
|
+
sage: t.symmetries()
|
|
518
|
+
symmetry: (0, 1); no antisymmetry
|
|
519
|
+
sage: t = M.tensor((4,0), name='T', sym=[(0,1), (2,3)])
|
|
520
|
+
sage: t.symmetries()
|
|
521
|
+
symmetries: [(0, 1), (2, 3)]; no antisymmetry
|
|
522
|
+
sage: t = M.tensor((4,0), name='T', sym=(0,1), antisym=(2,3))
|
|
523
|
+
sage: t.symmetries()
|
|
524
|
+
symmetry: (0, 1); antisymmetry: (2, 3)
|
|
525
|
+
"""
|
|
526
|
+
if len(self._sym) == 0:
|
|
527
|
+
s = "no symmetry; "
|
|
528
|
+
elif len(self._sym) == 1:
|
|
529
|
+
s = "symmetry: {}; ".format(self._sym[0])
|
|
530
|
+
else:
|
|
531
|
+
s = "symmetries: {}; ".format(list(self._sym))
|
|
532
|
+
if len(self._antisym) == 0:
|
|
533
|
+
a = "no antisymmetry"
|
|
534
|
+
elif len(self._antisym) == 1:
|
|
535
|
+
a = "antisymmetry: {}".format(self._antisym[0])
|
|
536
|
+
else:
|
|
537
|
+
a = "antisymmetries: {}".format(list(self._antisym))
|
|
538
|
+
print(s+a)
|
|
539
|
+
|
|
540
|
+
#### End of simple accessors #####
|
|
541
|
+
|
|
542
|
+
def _preparse_display(self, basis=None, format_spec=None):
|
|
543
|
+
r"""
|
|
544
|
+
Helper function for display (to be used in the derived classes
|
|
545
|
+
FreeModuleAltForm and AlternatingContrTensor as well)
|
|
546
|
+
|
|
547
|
+
TESTS::
|
|
548
|
+
|
|
549
|
+
sage: M = FiniteRankFreeModule(ZZ, 2, name='M')
|
|
550
|
+
sage: e = M.basis('e')
|
|
551
|
+
sage: f = M.basis('f')
|
|
552
|
+
sage: v = M([1,-2])
|
|
553
|
+
sage: v._preparse_display()
|
|
554
|
+
(Basis (e_0,e_1) on the Rank-2 free module M over the Integer Ring, None)
|
|
555
|
+
sage: v._preparse_display(f)
|
|
556
|
+
(Basis (f_0,f_1) on the Rank-2 free module M over the Integer Ring, None)
|
|
557
|
+
sage: v._preparse_display(e, 10)
|
|
558
|
+
(Basis (e_0,e_1) on the Rank-2 free module M over the Integer Ring, 10)
|
|
559
|
+
sage: v._preparse_display(format_spec=10)
|
|
560
|
+
(Basis (e_0,e_1) on the Rank-2 free module M over the Integer Ring, 10)
|
|
561
|
+
"""
|
|
562
|
+
if basis is None:
|
|
563
|
+
basis = self._fmodule._def_basis
|
|
564
|
+
return (basis, format_spec)
|
|
565
|
+
|
|
566
|
+
def display(self, basis=None, format_spec=None):
|
|
567
|
+
r"""
|
|
568
|
+
Display ``self`` in terms of its expansion w.r.t. a given module basis.
|
|
569
|
+
|
|
570
|
+
The expansion is actually performed onto tensor products of elements
|
|
571
|
+
of the given basis and of elements of its dual basis (see examples
|
|
572
|
+
below).
|
|
573
|
+
The output is either text-formatted (console mode) or LaTeX-formatted
|
|
574
|
+
(notebook mode).
|
|
575
|
+
|
|
576
|
+
INPUT:
|
|
577
|
+
|
|
578
|
+
- ``basis`` -- (default: ``None``) basis of the free module with
|
|
579
|
+
respect to which the tensor is expanded; if none is provided,
|
|
580
|
+
the module's default basis is assumed
|
|
581
|
+
- ``format_spec`` -- (default: ``None``) format specification passed
|
|
582
|
+
to ``self._fmodule._output_formatter`` to format the output
|
|
583
|
+
|
|
584
|
+
EXAMPLES:
|
|
585
|
+
|
|
586
|
+
Display of a module element (type-`(1,0)` tensor)::
|
|
587
|
+
|
|
588
|
+
sage: M = FiniteRankFreeModule(QQ, 2, name='M', start_index=1)
|
|
589
|
+
sage: e = M.basis('e') ; e
|
|
590
|
+
Basis (e_1,e_2) on the 2-dimensional vector space M over the
|
|
591
|
+
Rational Field
|
|
592
|
+
sage: v = M([1/3,-2], name='v')
|
|
593
|
+
sage: v.display(e)
|
|
594
|
+
v = 1/3 e_1 - 2 e_2
|
|
595
|
+
sage: v.display() # a shortcut since e is M's default basis
|
|
596
|
+
v = 1/3 e_1 - 2 e_2
|
|
597
|
+
sage: latex(v.display()) # display in the notebook
|
|
598
|
+
v = \frac{1}{3} e_{1} -2 e_{2}
|
|
599
|
+
|
|
600
|
+
A shortcut is ``disp()``::
|
|
601
|
+
|
|
602
|
+
sage: v.disp()
|
|
603
|
+
v = 1/3 e_1 - 2 e_2
|
|
604
|
+
|
|
605
|
+
Display of a linear form (type-`(0,1)` tensor)::
|
|
606
|
+
|
|
607
|
+
sage: de = e.dual_basis() ; de
|
|
608
|
+
Dual basis (e^1,e^2) on the 2-dimensional vector space M over the
|
|
609
|
+
Rational Field
|
|
610
|
+
sage: w = - 3/4 * de[1] + de[2] ; w
|
|
611
|
+
Linear form on the 2-dimensional vector space M over the Rational
|
|
612
|
+
Field
|
|
613
|
+
sage: w.set_name('w', latex_name='\\omega')
|
|
614
|
+
sage: w.display()
|
|
615
|
+
w = -3/4 e^1 + e^2
|
|
616
|
+
sage: latex(w.display()) # display in the notebook
|
|
617
|
+
\omega = -\frac{3}{4} e^{1} +e^{2}
|
|
618
|
+
|
|
619
|
+
Display of a type-`(1,1)` tensor::
|
|
620
|
+
|
|
621
|
+
sage: t = v*w ; t # the type-(1,1) is formed as the tensor product of v by w
|
|
622
|
+
Type-(1,1) tensor v⊗w on the 2-dimensional vector space M over the
|
|
623
|
+
Rational Field
|
|
624
|
+
sage: t.display()
|
|
625
|
+
v⊗w = -1/4 e_1⊗e^1 + 1/3 e_1⊗e^2 + 3/2 e_2⊗e^1 - 2 e_2⊗e^2
|
|
626
|
+
sage: latex(t.display()) # display in the notebook
|
|
627
|
+
v\otimes \omega = -\frac{1}{4} e_{1}\otimes e^{1} +
|
|
628
|
+
\frac{1}{3} e_{1}\otimes e^{2} + \frac{3}{2} e_{2}\otimes e^{1}
|
|
629
|
+
-2 e_{2}\otimes e^{2}
|
|
630
|
+
|
|
631
|
+
Display in a basis which is not the default one::
|
|
632
|
+
|
|
633
|
+
sage: a = M.automorphism(matrix=[[1,2],[3,4]], basis=e)
|
|
634
|
+
sage: f = e.new_basis(a, 'f')
|
|
635
|
+
sage: v.display(f) # the components w.r.t basis f are first computed via the change-of-basis formula defined by a
|
|
636
|
+
v = -8/3 f_1 + 3/2 f_2
|
|
637
|
+
sage: w.display(f)
|
|
638
|
+
w = 9/4 f^1 + 5/2 f^2
|
|
639
|
+
sage: t.display(f)
|
|
640
|
+
v⊗w = -6 f_1⊗f^1 - 20/3 f_1⊗f^2 + 27/8 f_2⊗f^1 + 15/4 f_2⊗f^2
|
|
641
|
+
|
|
642
|
+
Parallel computation::
|
|
643
|
+
|
|
644
|
+
sage: Parallelism().set('tensor', nproc=2)
|
|
645
|
+
sage: t2 = v*w
|
|
646
|
+
sage: t2.display(f)
|
|
647
|
+
v⊗w = -6 f_1⊗f^1 - 20/3 f_1⊗f^2 + 27/8 f_2⊗f^1 + 15/4 f_2⊗f^2
|
|
648
|
+
sage: t2[f,:] == t[f,:] # check of the parallel computation
|
|
649
|
+
True
|
|
650
|
+
sage: Parallelism().set('tensor', nproc=1) # switch off parallelization
|
|
651
|
+
|
|
652
|
+
The output format can be set via the argument ``output_formatter``
|
|
653
|
+
passed at the module construction::
|
|
654
|
+
|
|
655
|
+
sage: N = FiniteRankFreeModule(QQ, 2, name='N', start_index=1,
|
|
656
|
+
....: output_formatter=Rational.numerical_approx)
|
|
657
|
+
sage: e = N.basis('e')
|
|
658
|
+
sage: v = N([1/3,-2], name='v')
|
|
659
|
+
sage: v.display() # default format (53 bits of precision)
|
|
660
|
+
v = 0.333333333333333 e_1 - 2.00000000000000 e_2
|
|
661
|
+
sage: latex(v.display())
|
|
662
|
+
v = 0.333333333333333 e_{1} -2.00000000000000 e_{2}
|
|
663
|
+
|
|
664
|
+
The output format is then controlled by the argument ``format_spec`` of
|
|
665
|
+
the method :meth:`display`::
|
|
666
|
+
|
|
667
|
+
sage: v.display(format_spec=10) # 10 bits of precision
|
|
668
|
+
v = 0.33 e_1 - 2.0 e_2
|
|
669
|
+
|
|
670
|
+
Check that the bug reported in :issue:`22520` is fixed::
|
|
671
|
+
|
|
672
|
+
sage: # needs sage.symbolic
|
|
673
|
+
sage: M = FiniteRankFreeModule(SR, 3, name='M')
|
|
674
|
+
sage: e = M.basis('e')
|
|
675
|
+
sage: t = SR.var('t', domain='real')
|
|
676
|
+
sage: (t*e[0]).display()
|
|
677
|
+
t e_0
|
|
678
|
+
"""
|
|
679
|
+
from sage.misc.latex import latex
|
|
680
|
+
from sage.typeset.unicode_characters import unicode_otimes
|
|
681
|
+
from .format_utilities import is_atomic, FormattedExpansion
|
|
682
|
+
basis, format_spec = self._preparse_display(basis=basis,
|
|
683
|
+
format_spec=format_spec)
|
|
684
|
+
cobasis = basis.dual_basis()
|
|
685
|
+
comp = self.comp(basis)
|
|
686
|
+
terms_txt = []
|
|
687
|
+
terms_latex = []
|
|
688
|
+
n_con = self._tensor_type[0]
|
|
689
|
+
for ind in comp.index_generator():
|
|
690
|
+
ind_arg = ind + (format_spec,)
|
|
691
|
+
coef = comp[ind_arg]
|
|
692
|
+
# Check whether the coefficient is zero, preferably via
|
|
693
|
+
# the fast method is_trivial_zero():
|
|
694
|
+
if hasattr(coef, 'is_trivial_zero'):
|
|
695
|
+
zero_coef = coef.is_trivial_zero()
|
|
696
|
+
else:
|
|
697
|
+
zero_coef = coef == 0
|
|
698
|
+
if not zero_coef:
|
|
699
|
+
bases_txt = []
|
|
700
|
+
bases_latex = []
|
|
701
|
+
for k in range(n_con):
|
|
702
|
+
bases_txt.append(basis[ind[k]]._name)
|
|
703
|
+
bases_latex.append(latex(basis[ind[k]]))
|
|
704
|
+
for k in range(n_con, self._tensor_rank):
|
|
705
|
+
bases_txt.append(cobasis[ind[k]]._name)
|
|
706
|
+
bases_latex.append(latex(cobasis[ind[k]]))
|
|
707
|
+
basis_term_txt = unicode_otimes.join(bases_txt)
|
|
708
|
+
basis_term_latex = r'\otimes '.join(bases_latex)
|
|
709
|
+
coef_txt = repr(coef)
|
|
710
|
+
if coef_txt == '1':
|
|
711
|
+
terms_txt.append(basis_term_txt)
|
|
712
|
+
terms_latex.append(basis_term_latex)
|
|
713
|
+
elif coef_txt == '-1':
|
|
714
|
+
terms_txt.append('-' + basis_term_txt)
|
|
715
|
+
terms_latex.append('-' + basis_term_latex)
|
|
716
|
+
else:
|
|
717
|
+
coef_latex = latex(coef)
|
|
718
|
+
if is_atomic(coef_txt):
|
|
719
|
+
terms_txt.append(coef_txt + ' ' + basis_term_txt)
|
|
720
|
+
else:
|
|
721
|
+
terms_txt.append('(' + coef_txt + ') ' +
|
|
722
|
+
basis_term_txt)
|
|
723
|
+
if is_atomic(coef_latex):
|
|
724
|
+
terms_latex.append(coef_latex + basis_term_latex)
|
|
725
|
+
else:
|
|
726
|
+
terms_latex.append(r'\left(' + coef_latex +
|
|
727
|
+
r'\right)' + basis_term_latex)
|
|
728
|
+
if terms_txt == []:
|
|
729
|
+
expansion_txt = '0'
|
|
730
|
+
else:
|
|
731
|
+
expansion_txt = terms_txt[0]
|
|
732
|
+
for term in terms_txt[1:]:
|
|
733
|
+
if term[0] == '-':
|
|
734
|
+
expansion_txt += ' - ' + term[1:]
|
|
735
|
+
else:
|
|
736
|
+
expansion_txt += ' + ' + term
|
|
737
|
+
if terms_latex == []:
|
|
738
|
+
expansion_latex = '0'
|
|
739
|
+
else:
|
|
740
|
+
expansion_latex = terms_latex[0]
|
|
741
|
+
for term in terms_latex[1:]:
|
|
742
|
+
if term[0] == '-':
|
|
743
|
+
expansion_latex += term
|
|
744
|
+
else:
|
|
745
|
+
expansion_latex += '+' + term
|
|
746
|
+
if self._name is None:
|
|
747
|
+
resu_txt = expansion_txt
|
|
748
|
+
else:
|
|
749
|
+
resu_txt = self._name + ' = ' + expansion_txt
|
|
750
|
+
if self._latex_name is None:
|
|
751
|
+
resu_latex = expansion_latex
|
|
752
|
+
else:
|
|
753
|
+
resu_latex = latex(self) + ' = ' + expansion_latex
|
|
754
|
+
return FormattedExpansion(resu_txt, resu_latex)
|
|
755
|
+
|
|
756
|
+
disp = display
|
|
757
|
+
|
|
758
|
+
def display_comp(self, basis=None, format_spec=None, symbol=None,
|
|
759
|
+
latex_symbol=None, index_labels=None,
|
|
760
|
+
index_latex_labels=None, only_nonzero=True,
|
|
761
|
+
only_nonredundant=False):
|
|
762
|
+
r"""
|
|
763
|
+
Display the tensor components with respect to a given module
|
|
764
|
+
basis, one per line.
|
|
765
|
+
|
|
766
|
+
The output is either text-formatted (console mode) or LaTeX-formatted
|
|
767
|
+
(notebook mode).
|
|
768
|
+
|
|
769
|
+
INPUT:
|
|
770
|
+
|
|
771
|
+
- ``basis`` -- (default: ``None``) basis of the free module with
|
|
772
|
+
respect to which the tensor components are defined; if ``None``,
|
|
773
|
+
the module's default basis is assumed
|
|
774
|
+
- ``format_spec`` -- (default: ``None``) format specification passed
|
|
775
|
+
to ``self._fmodule._output_formatter`` to format the output
|
|
776
|
+
- ``symbol`` -- (default: ``None``) string (typically a single letter)
|
|
777
|
+
specifying the symbol for the components; if ``None``, the tensor
|
|
778
|
+
name is used if it has been set, otherwise ``'X'`` is used
|
|
779
|
+
- ``latex_symbol`` -- (default: ``None``) string specifying the LaTeX
|
|
780
|
+
symbol for the components; if ``None``, the tensor LaTeX name
|
|
781
|
+
is used if it has been set, otherwise ``'X'`` is used
|
|
782
|
+
- ``index_labels`` -- (default: ``None``) list of strings representing
|
|
783
|
+
the labels of each of the individual indices; if ``None``, integer
|
|
784
|
+
labels are used
|
|
785
|
+
- ``index_latex_labels`` -- (default: ``None``) list of strings
|
|
786
|
+
representing the LaTeX labels of each of the individual indices; if
|
|
787
|
+
``None``, integers labels are used
|
|
788
|
+
- ``only_nonzero`` -- boolean (default: ``True``); if ``True``, only
|
|
789
|
+
nonzero components are displayed
|
|
790
|
+
- ``only_nonredundant`` -- boolean (default: ``False``); if ``True``,
|
|
791
|
+
only nonredundant components are displayed in case of symmetries
|
|
792
|
+
|
|
793
|
+
EXAMPLES:
|
|
794
|
+
|
|
795
|
+
Display of the components of a type-`(2,1)` tensor on a rank 2
|
|
796
|
+
vector space over `\QQ`::
|
|
797
|
+
|
|
798
|
+
sage: FiniteRankFreeModule._clear_cache_() # for doctests only
|
|
799
|
+
sage: M = FiniteRankFreeModule(QQ, 2, name='M', start_index=1)
|
|
800
|
+
sage: e = M.basis('e')
|
|
801
|
+
sage: t = M.tensor((2,1), name='T', sym=(0,1))
|
|
802
|
+
sage: t[1,2,1], t[1,2,2], t[2,2,2] = 2/3, -1/4, 3
|
|
803
|
+
sage: t.display()
|
|
804
|
+
T = 2/3 e_1⊗e_2⊗e^1 - 1/4 e_1⊗e_2⊗e^2 + 2/3 e_2⊗e_1⊗e^1
|
|
805
|
+
- 1/4 e_2⊗e_1⊗e^2 + 3 e_2⊗e_2⊗e^2
|
|
806
|
+
sage: t.display_comp()
|
|
807
|
+
T^12_1 = 2/3
|
|
808
|
+
T^12_2 = -1/4
|
|
809
|
+
T^21_1 = 2/3
|
|
810
|
+
T^21_2 = -1/4
|
|
811
|
+
T^22_2 = 3
|
|
812
|
+
|
|
813
|
+
The LaTeX output for the notebook::
|
|
814
|
+
|
|
815
|
+
sage: latex(t.display_comp())
|
|
816
|
+
\begin{array}{lcl} {T}_{\phantom{\, 1}\phantom{\, 2}\,1}^{\,1\,2\phantom{\, 1}}
|
|
817
|
+
& = & \frac{2}{3} \\ {T}_{\phantom{\, 1}\phantom{\, 2}\,2}^{\,1\,2\phantom{\, 2}}
|
|
818
|
+
& = & -\frac{1}{4} \\ {T}_{\phantom{\, 2}\phantom{\, 1}\,1}^{\,2\,1\phantom{\, 1}}
|
|
819
|
+
& = & \frac{2}{3} \\ {T}_{\phantom{\, 2}\phantom{\, 1}\,2}^{\,2\,1\phantom{\, 2}}
|
|
820
|
+
& = & -\frac{1}{4} \\ {T}_{\phantom{\, 2}\phantom{\, 2}\,2}^{\,2\,2\phantom{\, 2}}
|
|
821
|
+
& = & 3 \end{array}
|
|
822
|
+
|
|
823
|
+
By default, only the non-vanishing components are displayed; to see
|
|
824
|
+
all the components, the argument ``only_nonzero`` must be set to
|
|
825
|
+
``False``::
|
|
826
|
+
|
|
827
|
+
sage: t.display_comp(only_nonzero=False)
|
|
828
|
+
T^11_1 = 0
|
|
829
|
+
T^11_2 = 0
|
|
830
|
+
T^12_1 = 2/3
|
|
831
|
+
T^12_2 = -1/4
|
|
832
|
+
T^21_1 = 2/3
|
|
833
|
+
T^21_2 = -1/4
|
|
834
|
+
T^22_1 = 0
|
|
835
|
+
T^22_2 = 3
|
|
836
|
+
|
|
837
|
+
``t`` being symmetric w.r.t. to its first two indices, one may ask to
|
|
838
|
+
skip the components that can be deduced by symmetry::
|
|
839
|
+
|
|
840
|
+
sage: t.display_comp(only_nonredundant=True)
|
|
841
|
+
T^12_1 = 2/3
|
|
842
|
+
T^12_2 = -1/4
|
|
843
|
+
T^22_2 = 3
|
|
844
|
+
|
|
845
|
+
The index symbols can be customized::
|
|
846
|
+
|
|
847
|
+
sage: t.display_comp(index_labels=['x', 'y'])
|
|
848
|
+
T^xy_x = 2/3
|
|
849
|
+
T^xy_y = -1/4
|
|
850
|
+
T^yx_x = 2/3
|
|
851
|
+
T^yx_y = -1/4
|
|
852
|
+
T^yy_y = 3
|
|
853
|
+
|
|
854
|
+
Display of the components w.r.t. a basis different from the
|
|
855
|
+
default one::
|
|
856
|
+
|
|
857
|
+
sage: f = M.basis('f', from_family=(-e[1]+e[2], e[1]+e[2]))
|
|
858
|
+
sage: t.display_comp(basis=f)
|
|
859
|
+
T^11_1 = 29/24
|
|
860
|
+
T^11_2 = 13/24
|
|
861
|
+
T^12_1 = 3/4
|
|
862
|
+
T^12_2 = 3/4
|
|
863
|
+
T^21_1 = 3/4
|
|
864
|
+
T^21_2 = 3/4
|
|
865
|
+
T^22_1 = 7/24
|
|
866
|
+
T^22_2 = 23/24
|
|
867
|
+
"""
|
|
868
|
+
if basis is None:
|
|
869
|
+
basis = self._fmodule._def_basis
|
|
870
|
+
if symbol is None:
|
|
871
|
+
if self._name is not None:
|
|
872
|
+
symbol = self._name
|
|
873
|
+
else:
|
|
874
|
+
symbol = 'X'
|
|
875
|
+
if latex_symbol is None:
|
|
876
|
+
if self._latex_name is not None:
|
|
877
|
+
latex_symbol = r'{' + self._latex_name + r'}'
|
|
878
|
+
else:
|
|
879
|
+
latex_symbol = 'X'
|
|
880
|
+
index_positions = self._tensor_type[0]*'u' + self._tensor_type[1]*'d'
|
|
881
|
+
return self.comp(basis).display(symbol,
|
|
882
|
+
latex_symbol=latex_symbol,
|
|
883
|
+
index_positions=index_positions,
|
|
884
|
+
index_labels=index_labels,
|
|
885
|
+
index_latex_labels=index_latex_labels,
|
|
886
|
+
format_spec=format_spec,
|
|
887
|
+
only_nonzero=only_nonzero,
|
|
888
|
+
only_nonredundant=only_nonredundant)
|
|
889
|
+
|
|
890
|
+
def set_name(self, name: Optional[str] = None, latex_name: Optional[str] = None):
|
|
891
|
+
r"""
|
|
892
|
+
Set (or change) the text name and LaTeX name of ``self``.
|
|
893
|
+
|
|
894
|
+
INPUT:
|
|
895
|
+
|
|
896
|
+
- ``name`` -- (default: ``None``) string; name given to the tensor
|
|
897
|
+
- ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote
|
|
898
|
+
the tensor; if None while ``name`` is provided, the LaTeX symbol
|
|
899
|
+
is set to ``name``
|
|
900
|
+
|
|
901
|
+
EXAMPLES::
|
|
902
|
+
|
|
903
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
904
|
+
sage: t = M.tensor((2,1)) ; t
|
|
905
|
+
Type-(2,1) tensor on the Rank-3 free module M over the Integer Ring
|
|
906
|
+
sage: t.set_name('t') ; t
|
|
907
|
+
Type-(2,1) tensor t on the Rank-3 free module M over the Integer Ring
|
|
908
|
+
sage: latex(t)
|
|
909
|
+
t
|
|
910
|
+
sage: t.set_name(latex_name=r'\tau') ; t
|
|
911
|
+
Type-(2,1) tensor t on the Rank-3 free module M over the Integer Ring
|
|
912
|
+
sage: latex(t)
|
|
913
|
+
\tau
|
|
914
|
+
"""
|
|
915
|
+
if name is not None:
|
|
916
|
+
self._name = name
|
|
917
|
+
if latex_name is None:
|
|
918
|
+
self._latex_name = self._name
|
|
919
|
+
if latex_name is not None:
|
|
920
|
+
self._latex_name = latex_name
|
|
921
|
+
|
|
922
|
+
def _new_instance(self):
|
|
923
|
+
r"""
|
|
924
|
+
Create a tensor of the same tensor type and with the same symmetries
|
|
925
|
+
as ``self``.
|
|
926
|
+
|
|
927
|
+
EXAMPLES::
|
|
928
|
+
|
|
929
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
930
|
+
sage: t = M.tensor((2,1), name='t')
|
|
931
|
+
sage: t._new_instance()
|
|
932
|
+
Type-(2,1) tensor on the Rank-3 free module M over the Integer Ring
|
|
933
|
+
sage: t._new_instance().parent() is t.parent()
|
|
934
|
+
True
|
|
935
|
+
"""
|
|
936
|
+
return self.__class__(self._fmodule, self._tensor_type, sym=self._sym,
|
|
937
|
+
antisym=self._antisym)
|
|
938
|
+
|
|
939
|
+
def _new_comp(self, basis):
|
|
940
|
+
r"""
|
|
941
|
+
Create some (uninitialized) components of ``self`` w.r.t a given
|
|
942
|
+
module basis.
|
|
943
|
+
|
|
944
|
+
This method, to be called by :meth:`comp`, must be redefined by derived
|
|
945
|
+
classes to adapt the output to the relevant subclass of
|
|
946
|
+
:class:`~sage.tensor.modules.comp.Components`.
|
|
947
|
+
|
|
948
|
+
INPUT:
|
|
949
|
+
|
|
950
|
+
- ``basis`` -- basis of the free module on which ``self`` is defined
|
|
951
|
+
|
|
952
|
+
OUTPUT:
|
|
953
|
+
|
|
954
|
+
- an instance of :class:`~sage.tensor.modules.comp.Components`
|
|
955
|
+
(or of one of its subclasses)
|
|
956
|
+
|
|
957
|
+
EXAMPLES::
|
|
958
|
+
|
|
959
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
960
|
+
sage: t = M.tensor((2,1), name='t')
|
|
961
|
+
sage: e = M.basis('e')
|
|
962
|
+
sage: t._new_comp(e)
|
|
963
|
+
3-indices components w.r.t. Basis (e_0,e_1,e_2) on the
|
|
964
|
+
Rank-3 free module M over the Integer Ring
|
|
965
|
+
sage: a = M.tensor((2,1), name='a', sym=(0,1))
|
|
966
|
+
sage: a._new_comp(e)
|
|
967
|
+
3-indices components w.r.t. Basis (e_0,e_1,e_2) on the
|
|
968
|
+
Rank-3 free module M over the Integer Ring,
|
|
969
|
+
with symmetry on the index positions (0, 1)
|
|
970
|
+
"""
|
|
971
|
+
fmodule = self._fmodule # the base free module
|
|
972
|
+
if not self._sym and not self._antisym:
|
|
973
|
+
return Components(fmodule._ring, basis, self._tensor_rank,
|
|
974
|
+
start_index=fmodule._sindex,
|
|
975
|
+
output_formatter=fmodule._output_formatter)
|
|
976
|
+
for isym in self._sym:
|
|
977
|
+
if len(isym) == self._tensor_rank:
|
|
978
|
+
return CompFullySym(fmodule._ring, basis, self._tensor_rank,
|
|
979
|
+
start_index=fmodule._sindex,
|
|
980
|
+
output_formatter=fmodule._output_formatter)
|
|
981
|
+
for isym in self._antisym:
|
|
982
|
+
if len(isym) == self._tensor_rank:
|
|
983
|
+
return CompFullyAntiSym(fmodule._ring, basis, self._tensor_rank,
|
|
984
|
+
start_index=fmodule._sindex,
|
|
985
|
+
output_formatter=fmodule._output_formatter)
|
|
986
|
+
return CompWithSym(fmodule._ring, basis, self._tensor_rank,
|
|
987
|
+
start_index=fmodule._sindex,
|
|
988
|
+
output_formatter=fmodule._output_formatter,
|
|
989
|
+
sym=self._sym, antisym=self._antisym)
|
|
990
|
+
|
|
991
|
+
def components(self, basis=None, from_basis=None) -> Components:
|
|
992
|
+
r"""
|
|
993
|
+
Return the components of ``self`` w.r.t to a given module basis.
|
|
994
|
+
|
|
995
|
+
If the components are not known already, they are computed by the
|
|
996
|
+
tensor change-of-basis formula from components in another basis.
|
|
997
|
+
|
|
998
|
+
INPUT:
|
|
999
|
+
|
|
1000
|
+
- ``basis`` -- (default: ``None``) basis in which the components are
|
|
1001
|
+
required; if none is provided, the components are assumed to refer
|
|
1002
|
+
to the module's default basis
|
|
1003
|
+
- ``from_basis`` -- (default: ``None``) basis from which the
|
|
1004
|
+
required components are computed, via the tensor change-of-basis
|
|
1005
|
+
formula, if they are not known already in the basis ``basis``;
|
|
1006
|
+
if none, a basis from which both the components and a change-of-basis
|
|
1007
|
+
to ``basis`` are known is selected.
|
|
1008
|
+
|
|
1009
|
+
OUTPUT:
|
|
1010
|
+
|
|
1011
|
+
- components in the basis ``basis``, as an instance of the
|
|
1012
|
+
class :class:`~sage.tensor.modules.comp.Components`
|
|
1013
|
+
|
|
1014
|
+
EXAMPLES:
|
|
1015
|
+
|
|
1016
|
+
Components of a tensor of type-`(1,1)`::
|
|
1017
|
+
|
|
1018
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M', start_index=1)
|
|
1019
|
+
sage: e = M.basis('e')
|
|
1020
|
+
sage: t = M.tensor((1,1), name='t')
|
|
1021
|
+
sage: t[1,2] = -3 ; t[3,3] = 2
|
|
1022
|
+
sage: t.components()
|
|
1023
|
+
2-indices components w.r.t. Basis (e_1,e_2,e_3)
|
|
1024
|
+
on the Rank-3 free module M over the Integer Ring
|
|
1025
|
+
sage: t.components() is t.components(e) # since e is M's default basis
|
|
1026
|
+
True
|
|
1027
|
+
sage: t.components()[:]
|
|
1028
|
+
[ 0 -3 0]
|
|
1029
|
+
[ 0 0 0]
|
|
1030
|
+
[ 0 0 2]
|
|
1031
|
+
|
|
1032
|
+
A shortcut is ``t.comp()``::
|
|
1033
|
+
|
|
1034
|
+
sage: t.comp() is t.components()
|
|
1035
|
+
True
|
|
1036
|
+
|
|
1037
|
+
A direct access to the components w.r.t. the module's default basis is
|
|
1038
|
+
provided by the square brackets applied to the tensor itself::
|
|
1039
|
+
|
|
1040
|
+
sage: t[1,2] is t.comp(e)[1,2]
|
|
1041
|
+
True
|
|
1042
|
+
sage: t[:]
|
|
1043
|
+
[ 0 -3 0]
|
|
1044
|
+
[ 0 0 0]
|
|
1045
|
+
[ 0 0 2]
|
|
1046
|
+
|
|
1047
|
+
Components computed via a change-of-basis formula::
|
|
1048
|
+
|
|
1049
|
+
sage: a = M.automorphism()
|
|
1050
|
+
sage: a[:] = [[0,0,1], [1,0,0], [0,-1,0]]
|
|
1051
|
+
sage: f = e.new_basis(a, 'f')
|
|
1052
|
+
sage: t.comp(f)
|
|
1053
|
+
2-indices components w.r.t. Basis (f_1,f_2,f_3)
|
|
1054
|
+
on the Rank-3 free module M over the Integer Ring
|
|
1055
|
+
sage: t.comp(f)[:]
|
|
1056
|
+
[ 0 0 0]
|
|
1057
|
+
[ 0 2 0]
|
|
1058
|
+
[-3 0 0]
|
|
1059
|
+
"""
|
|
1060
|
+
fmodule = self._fmodule
|
|
1061
|
+
if basis is None:
|
|
1062
|
+
basis = fmodule._def_basis
|
|
1063
|
+
try:
|
|
1064
|
+
# Standard bases of tensor modules are keyed to the base module's basis,
|
|
1065
|
+
# not to the TensorFreeSubmoduleBasis_comp instance.
|
|
1066
|
+
basis = basis._base_module_basis
|
|
1067
|
+
except AttributeError:
|
|
1068
|
+
pass
|
|
1069
|
+
if basis not in self._components:
|
|
1070
|
+
# The components must be computed from
|
|
1071
|
+
# those in the basis from_basis
|
|
1072
|
+
if from_basis is None:
|
|
1073
|
+
for known_basis in self._components:
|
|
1074
|
+
if (known_basis, basis) in self._fmodule._basis_changes \
|
|
1075
|
+
and (basis, known_basis) in self._fmodule._basis_changes:
|
|
1076
|
+
from_basis = known_basis
|
|
1077
|
+
break
|
|
1078
|
+
if from_basis is None:
|
|
1079
|
+
raise ValueError("no basis could be found for computing " +
|
|
1080
|
+
"the components in the {}".format(basis))
|
|
1081
|
+
elif from_basis not in self._components:
|
|
1082
|
+
raise ValueError("the tensor components are not known in " +
|
|
1083
|
+
"the {}".format(from_basis))
|
|
1084
|
+
(n_con, n_cov) = self._tensor_type
|
|
1085
|
+
pp = None
|
|
1086
|
+
if n_cov > 0:
|
|
1087
|
+
if (from_basis, basis) not in fmodule._basis_changes:
|
|
1088
|
+
raise ValueError("the change-of-basis matrix from the " +
|
|
1089
|
+
"{} to the {}".format(from_basis, basis)
|
|
1090
|
+
+ " has not been set")
|
|
1091
|
+
pp = \
|
|
1092
|
+
fmodule._basis_changes[(from_basis, basis)].comp(from_basis)
|
|
1093
|
+
# pp not used if n_cov = 0 (pure contravariant tensor)
|
|
1094
|
+
ppinv = None
|
|
1095
|
+
if n_con > 0:
|
|
1096
|
+
if (basis, from_basis) not in fmodule._basis_changes:
|
|
1097
|
+
raise ValueError("the change-of-basis matrix from the " +
|
|
1098
|
+
"{} to the {}".format(basis, from_basis) +
|
|
1099
|
+
" has not been set")
|
|
1100
|
+
ppinv = \
|
|
1101
|
+
fmodule._basis_changes[(basis, from_basis)].comp(from_basis)
|
|
1102
|
+
# ppinv not used if n_con = 0 (pure covariant tensor)
|
|
1103
|
+
old_comp = self._components[from_basis]
|
|
1104
|
+
new_comp = self._new_comp(basis)
|
|
1105
|
+
rank = self._tensor_rank
|
|
1106
|
+
# loop on the new components:
|
|
1107
|
+
nproc = Parallelism().get('tensor')
|
|
1108
|
+
|
|
1109
|
+
if nproc != 1:
|
|
1110
|
+
# Parallel computation
|
|
1111
|
+
lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)]
|
|
1112
|
+
ind_list = list(new_comp.non_redundant_index_generator())
|
|
1113
|
+
ind_step = max(1, int(len(ind_list)/nproc/2))
|
|
1114
|
+
local_list = lol(ind_list, ind_step)
|
|
1115
|
+
# list of input parameters
|
|
1116
|
+
listParalInput = [(old_comp, ppinv, pp, n_con, rank, ii) for ii in local_list]
|
|
1117
|
+
|
|
1118
|
+
@parallel(p_iter='multiprocessing', ncpus=nproc)
|
|
1119
|
+
def paral_newcomp(old_comp, ppinv, pp, n_con, rank, local_list_ind):
|
|
1120
|
+
partial = []
|
|
1121
|
+
for ind in local_list_ind:
|
|
1122
|
+
res = 0
|
|
1123
|
+
# Summation on the old components multiplied by the proper
|
|
1124
|
+
# change-of-basis matrix elements (tensor formula):
|
|
1125
|
+
for ind_old in old_comp.index_generator():
|
|
1126
|
+
t = old_comp[[ind_old]]
|
|
1127
|
+
for i in range(n_con): # loop on contravariant indices
|
|
1128
|
+
t *= ppinv[[ind[i], ind_old[i]]]
|
|
1129
|
+
for i in range(n_con,rank): # loop on covariant indices
|
|
1130
|
+
t *= pp[[ind_old[i], ind[i]]]
|
|
1131
|
+
res += t
|
|
1132
|
+
partial.append([ind,res])
|
|
1133
|
+
return partial
|
|
1134
|
+
|
|
1135
|
+
for ii,val in paral_newcomp(listParalInput):
|
|
1136
|
+
for jj in val:
|
|
1137
|
+
new_comp[[jj[0]]] = jj[1]
|
|
1138
|
+
|
|
1139
|
+
else:
|
|
1140
|
+
# Sequential computation
|
|
1141
|
+
for ind_new in new_comp.non_redundant_index_generator():
|
|
1142
|
+
# Summation on the old components multiplied by the proper
|
|
1143
|
+
# change-of-basis matrix elements (tensor formula):
|
|
1144
|
+
res = 0
|
|
1145
|
+
for ind_old in old_comp.index_generator():
|
|
1146
|
+
t = old_comp[[ind_old]]
|
|
1147
|
+
for i in range(n_con): # loop on contravariant indices
|
|
1148
|
+
t *= ppinv[[ind_new[i], ind_old[i]]]
|
|
1149
|
+
for i in range(n_con,rank): # loop on covariant indices
|
|
1150
|
+
t *= pp[[ind_old[i], ind_new[i]]]
|
|
1151
|
+
res += t
|
|
1152
|
+
new_comp[ind_new] = res
|
|
1153
|
+
|
|
1154
|
+
self._components[basis] = new_comp
|
|
1155
|
+
# end of case where the computation was necessary
|
|
1156
|
+
return self._components[basis]
|
|
1157
|
+
|
|
1158
|
+
comp = components
|
|
1159
|
+
|
|
1160
|
+
def _set_comp_unsafe(self, basis=None):
|
|
1161
|
+
r"""
|
|
1162
|
+
Return the components of ``self`` w.r.t. a given module basis for
|
|
1163
|
+
assignment. This private method invokes no security check. Use
|
|
1164
|
+
this method at your own risk.
|
|
1165
|
+
|
|
1166
|
+
The components with respect to other bases are deleted, in order to
|
|
1167
|
+
avoid any inconsistency. To keep them, use the method
|
|
1168
|
+
:meth:`_add_comp_unsafe` instead.
|
|
1169
|
+
|
|
1170
|
+
INPUT:
|
|
1171
|
+
|
|
1172
|
+
- ``basis`` -- (default: ``None``) basis in which the components are
|
|
1173
|
+
defined; if none is provided, the components are assumed to refer to
|
|
1174
|
+
the module's default basis
|
|
1175
|
+
|
|
1176
|
+
OUTPUT:
|
|
1177
|
+
|
|
1178
|
+
- components in the given basis, as an instance of the
|
|
1179
|
+
class :class:`~sage.tensor.modules.comp.Components`; if such
|
|
1180
|
+
components did not exist previously, they are created.
|
|
1181
|
+
|
|
1182
|
+
TESTS:
|
|
1183
|
+
|
|
1184
|
+
Setting components of a type-`(1,1)` tensor::
|
|
1185
|
+
|
|
1186
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
1187
|
+
sage: e = M.basis('e')
|
|
1188
|
+
sage: t = M.tensor((1,1), name='t')
|
|
1189
|
+
sage: t._set_comp_unsafe()[0,1] = -3
|
|
1190
|
+
sage: t.display()
|
|
1191
|
+
t = -3 e_0⊗e^1
|
|
1192
|
+
sage: t._set_comp_unsafe()[1,2] = 2
|
|
1193
|
+
sage: t.display()
|
|
1194
|
+
t = -3 e_0⊗e^1 + 2 e_1⊗e^2
|
|
1195
|
+
sage: t._set_comp_unsafe(e)
|
|
1196
|
+
2-indices components w.r.t. Basis (e_0,e_1,e_2) on the
|
|
1197
|
+
Rank-3 free module M over the Integer Ring
|
|
1198
|
+
|
|
1199
|
+
Setting components in a new basis::
|
|
1200
|
+
|
|
1201
|
+
sage: f = M.basis('f')
|
|
1202
|
+
sage: t._set_comp_unsafe(f)[0,1] = 4
|
|
1203
|
+
sage: list(t._components) # the components w.r.t. basis e have been deleted
|
|
1204
|
+
[Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring]
|
|
1205
|
+
sage: t.display(f)
|
|
1206
|
+
t = 4 f_0⊗f^1
|
|
1207
|
+
|
|
1208
|
+
The components w.r.t. basis e can be deduced from those w.r.t. basis f,
|
|
1209
|
+
once a relation between the two bases has been set::
|
|
1210
|
+
|
|
1211
|
+
sage: a = M.automorphism()
|
|
1212
|
+
sage: a[:] = [[0,0,1], [1,0,0], [0,-1,0]]
|
|
1213
|
+
sage: M.set_change_of_basis(e, f, a)
|
|
1214
|
+
sage: t.display(e)
|
|
1215
|
+
t = -4 e_1⊗e^2
|
|
1216
|
+
sage: sorted(t._components, key=repr)
|
|
1217
|
+
[Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring,
|
|
1218
|
+
Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring]
|
|
1219
|
+
"""
|
|
1220
|
+
if basis is None:
|
|
1221
|
+
basis = self._fmodule._def_basis
|
|
1222
|
+
if basis not in self._components:
|
|
1223
|
+
if basis not in self._fmodule._known_bases:
|
|
1224
|
+
raise ValueError("the {} has not been ".format(basis) +
|
|
1225
|
+
"defined on the {}".format(self._fmodule))
|
|
1226
|
+
self._components[basis] = self._new_comp(basis)
|
|
1227
|
+
self._del_derived() # deletes the derived quantities
|
|
1228
|
+
self.del_other_comp(basis)
|
|
1229
|
+
return self._components[basis]
|
|
1230
|
+
|
|
1231
|
+
def set_comp(self, basis=None):
|
|
1232
|
+
r"""
|
|
1233
|
+
Return the components of ``self`` w.r.t. a given module basis for
|
|
1234
|
+
assignment.
|
|
1235
|
+
|
|
1236
|
+
The components with respect to other bases are deleted, in order to
|
|
1237
|
+
avoid any inconsistency. To keep them, use the method :meth:`add_comp`
|
|
1238
|
+
instead.
|
|
1239
|
+
|
|
1240
|
+
INPUT:
|
|
1241
|
+
|
|
1242
|
+
- ``basis`` -- (default: ``None``) basis in which the components are
|
|
1243
|
+
defined; if none is provided, the components are assumed to refer to
|
|
1244
|
+
the module's default basis
|
|
1245
|
+
|
|
1246
|
+
OUTPUT:
|
|
1247
|
+
|
|
1248
|
+
- components in the given basis, as an instance of the
|
|
1249
|
+
class :class:`~sage.tensor.modules.comp.Components`; if such
|
|
1250
|
+
components did not exist previously, they are created.
|
|
1251
|
+
|
|
1252
|
+
EXAMPLES:
|
|
1253
|
+
|
|
1254
|
+
Setting components of a type-`(1,1)` tensor::
|
|
1255
|
+
|
|
1256
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
1257
|
+
sage: e = M.basis('e')
|
|
1258
|
+
sage: t = M.tensor((1,1), name='t')
|
|
1259
|
+
sage: t.set_comp()[0,1] = -3
|
|
1260
|
+
sage: t.display()
|
|
1261
|
+
t = -3 e_0⊗e^1
|
|
1262
|
+
sage: t.set_comp()[1,2] = 2
|
|
1263
|
+
sage: t.display()
|
|
1264
|
+
t = -3 e_0⊗e^1 + 2 e_1⊗e^2
|
|
1265
|
+
sage: t.set_comp(e)
|
|
1266
|
+
2-indices components w.r.t. Basis (e_0,e_1,e_2) on the
|
|
1267
|
+
Rank-3 free module M over the Integer Ring
|
|
1268
|
+
|
|
1269
|
+
Setting components in a new basis::
|
|
1270
|
+
|
|
1271
|
+
sage: f = M.basis('f')
|
|
1272
|
+
sage: t.set_comp(f)[0,1] = 4
|
|
1273
|
+
sage: list(t._components) # the components w.r.t. basis e have been deleted
|
|
1274
|
+
[Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring]
|
|
1275
|
+
sage: t.display(f)
|
|
1276
|
+
t = 4 f_0⊗f^1
|
|
1277
|
+
|
|
1278
|
+
The components w.r.t. basis e can be deduced from those w.r.t. basis f,
|
|
1279
|
+
once a relation between the two bases has been set::
|
|
1280
|
+
|
|
1281
|
+
sage: a = M.automorphism()
|
|
1282
|
+
sage: a[:] = [[0,0,1], [1,0,0], [0,-1,0]]
|
|
1283
|
+
sage: M.set_change_of_basis(e, f, a)
|
|
1284
|
+
sage: t.display(e)
|
|
1285
|
+
t = -4 e_1⊗e^2
|
|
1286
|
+
sage: sorted(t._components, key=repr)
|
|
1287
|
+
[Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring,
|
|
1288
|
+
Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring]
|
|
1289
|
+
|
|
1290
|
+
Since zero is an immutable element, its components cannot be changed::
|
|
1291
|
+
|
|
1292
|
+
sage: z = M.tensor_module(1, 1).zero()
|
|
1293
|
+
sage: z.set_comp(e)[0,1] = 1
|
|
1294
|
+
Traceback (most recent call last):
|
|
1295
|
+
...
|
|
1296
|
+
ValueError: the components of an immutable element cannot be changed
|
|
1297
|
+
"""
|
|
1298
|
+
if self.is_immutable():
|
|
1299
|
+
raise ValueError("the components of an immutable element "
|
|
1300
|
+
"cannot be changed")
|
|
1301
|
+
self._is_zero = False # a priori
|
|
1302
|
+
return self._set_comp_unsafe(basis)
|
|
1303
|
+
|
|
1304
|
+
def _add_comp_unsafe(self, basis=None):
|
|
1305
|
+
r"""
|
|
1306
|
+
Return the components of ``self`` w.r.t. a given module basis for
|
|
1307
|
+
assignment, keeping the components w.r.t. other bases. This private
|
|
1308
|
+
method invokes no security check. Use this method at your own risk.
|
|
1309
|
+
|
|
1310
|
+
To delete the components w.r.t. other bases, use the method
|
|
1311
|
+
:meth:`_set_comp_unsafe` instead.
|
|
1312
|
+
|
|
1313
|
+
INPUT:
|
|
1314
|
+
|
|
1315
|
+
- ``basis`` -- (default: ``None``) basis in which the components are
|
|
1316
|
+
defined; if none is provided, the components are assumed to refer to
|
|
1317
|
+
the module's default basis
|
|
1318
|
+
|
|
1319
|
+
OUTPUT:
|
|
1320
|
+
|
|
1321
|
+
- components in the given basis, as an instance of the
|
|
1322
|
+
class :class:`~sage.tensor.modules.comp.Components`;
|
|
1323
|
+
if such components did not exist previously, they are created
|
|
1324
|
+
|
|
1325
|
+
TESTS:
|
|
1326
|
+
|
|
1327
|
+
Setting components of a type-`(1,1)` tensor::
|
|
1328
|
+
|
|
1329
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
1330
|
+
sage: e = M.basis('e')
|
|
1331
|
+
sage: t = M.tensor((1,1), name='t')
|
|
1332
|
+
sage: t._add_comp_unsafe()[0,1] = -3
|
|
1333
|
+
sage: t.display()
|
|
1334
|
+
t = -3 e_0⊗e^1
|
|
1335
|
+
sage: t._add_comp_unsafe()[1,2] = 2
|
|
1336
|
+
sage: t.display()
|
|
1337
|
+
t = -3 e_0⊗e^1 + 2 e_1⊗e^2
|
|
1338
|
+
sage: t._add_comp_unsafe(e)
|
|
1339
|
+
2-indices components w.r.t. Basis (e_0,e_1,e_2) on the
|
|
1340
|
+
Rank-3 free module M over the Integer Ring
|
|
1341
|
+
|
|
1342
|
+
Adding components in a new basis::
|
|
1343
|
+
|
|
1344
|
+
sage: f = M.basis('f')
|
|
1345
|
+
sage: t._add_comp_unsafe(f)[0,1] = 4
|
|
1346
|
+
|
|
1347
|
+
The components w.r.t. basis e have been kept::
|
|
1348
|
+
|
|
1349
|
+
sage: sorted(t._components, key=repr)
|
|
1350
|
+
[Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring,
|
|
1351
|
+
Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring]
|
|
1352
|
+
sage: t.display(f)
|
|
1353
|
+
t = 4 f_0⊗f^1
|
|
1354
|
+
sage: t.display(e)
|
|
1355
|
+
t = -3 e_0⊗e^1 + 2 e_1⊗e^2
|
|
1356
|
+
"""
|
|
1357
|
+
if basis is None:
|
|
1358
|
+
basis = self._fmodule._def_basis
|
|
1359
|
+
if basis not in self._components:
|
|
1360
|
+
if basis not in self._fmodule._known_bases:
|
|
1361
|
+
raise ValueError("the {} has not been ".format(basis) +
|
|
1362
|
+
"defined on the {}".format(self._fmodule))
|
|
1363
|
+
self._components[basis] = self._new_comp(basis)
|
|
1364
|
+
self._del_derived() # deletes the derived quantities
|
|
1365
|
+
return self._components[basis]
|
|
1366
|
+
|
|
1367
|
+
def add_comp(self, basis=None):
|
|
1368
|
+
r"""
|
|
1369
|
+
Return the components of ``self`` w.r.t. a given module basis for
|
|
1370
|
+
assignment, keeping the components w.r.t. other bases.
|
|
1371
|
+
|
|
1372
|
+
To delete the components w.r.t. other bases, use the method
|
|
1373
|
+
:meth:`set_comp` instead.
|
|
1374
|
+
|
|
1375
|
+
INPUT:
|
|
1376
|
+
|
|
1377
|
+
- ``basis`` -- (default: ``None``) basis in which the components are
|
|
1378
|
+
defined; if none is provided, the components are assumed to refer to
|
|
1379
|
+
the module's default basis
|
|
1380
|
+
|
|
1381
|
+
.. WARNING::
|
|
1382
|
+
|
|
1383
|
+
If the tensor has already components in other bases, it
|
|
1384
|
+
is the user's responsibility to make sure that the components
|
|
1385
|
+
to be added are consistent with them.
|
|
1386
|
+
|
|
1387
|
+
OUTPUT:
|
|
1388
|
+
|
|
1389
|
+
- components in the given basis, as an instance of the
|
|
1390
|
+
class :class:`~sage.tensor.modules.comp.Components`;
|
|
1391
|
+
if such components did not exist previously, they are created
|
|
1392
|
+
|
|
1393
|
+
EXAMPLES:
|
|
1394
|
+
|
|
1395
|
+
Setting components of a type-`(1,1)` tensor::
|
|
1396
|
+
|
|
1397
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
1398
|
+
sage: e = M.basis('e')
|
|
1399
|
+
sage: t = M.tensor((1,1), name='t')
|
|
1400
|
+
sage: t.add_comp()[0,1] = -3
|
|
1401
|
+
sage: t.display()
|
|
1402
|
+
t = -3 e_0⊗e^1
|
|
1403
|
+
sage: t.add_comp()[1,2] = 2
|
|
1404
|
+
sage: t.display()
|
|
1405
|
+
t = -3 e_0⊗e^1 + 2 e_1⊗e^2
|
|
1406
|
+
sage: t.add_comp(e)
|
|
1407
|
+
2-indices components w.r.t. Basis (e_0,e_1,e_2) on the
|
|
1408
|
+
Rank-3 free module M over the Integer Ring
|
|
1409
|
+
|
|
1410
|
+
Adding components in a new basis::
|
|
1411
|
+
|
|
1412
|
+
sage: f = M.basis('f')
|
|
1413
|
+
sage: t.add_comp(f)[0,1] = 4
|
|
1414
|
+
|
|
1415
|
+
The components w.r.t. basis e have been kept::
|
|
1416
|
+
|
|
1417
|
+
sage: sorted(t._components, key=repr)
|
|
1418
|
+
[Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring,
|
|
1419
|
+
Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring]
|
|
1420
|
+
sage: t.display(f)
|
|
1421
|
+
t = 4 f_0⊗f^1
|
|
1422
|
+
sage: t.display(e)
|
|
1423
|
+
t = -3 e_0⊗e^1 + 2 e_1⊗e^2
|
|
1424
|
+
|
|
1425
|
+
Since zero is an immutable element, its components cannot be changed::
|
|
1426
|
+
|
|
1427
|
+
sage: z = M.tensor_module(1, 1).zero()
|
|
1428
|
+
sage: z.add_comp(e)[0,1] = 1
|
|
1429
|
+
Traceback (most recent call last):
|
|
1430
|
+
...
|
|
1431
|
+
ValueError: the components of an immutable element cannot be changed
|
|
1432
|
+
"""
|
|
1433
|
+
if self.is_immutable():
|
|
1434
|
+
raise ValueError("the components of an immutable element "
|
|
1435
|
+
"cannot be changed")
|
|
1436
|
+
self._is_zero = False # a priori
|
|
1437
|
+
return self._add_comp_unsafe(basis)
|
|
1438
|
+
|
|
1439
|
+
def del_other_comp(self, basis=None):
|
|
1440
|
+
r"""
|
|
1441
|
+
Delete all the components but those corresponding to ``basis``.
|
|
1442
|
+
|
|
1443
|
+
INPUT:
|
|
1444
|
+
|
|
1445
|
+
- ``basis`` -- (default: ``None``) basis in which the components are
|
|
1446
|
+
kept; if none the module's default basis is assumed
|
|
1447
|
+
|
|
1448
|
+
EXAMPLES:
|
|
1449
|
+
|
|
1450
|
+
Deleting components of a module element::
|
|
1451
|
+
|
|
1452
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M', start_index=1)
|
|
1453
|
+
sage: e = M.basis('e')
|
|
1454
|
+
sage: u = M([2,1,-5])
|
|
1455
|
+
sage: f = M.basis('f')
|
|
1456
|
+
sage: u.add_comp(f)[:] = [0,4,2]
|
|
1457
|
+
sage: sorted(u._components, key=repr)
|
|
1458
|
+
[Basis (e_1,e_2,e_3) on the Rank-3 free module M over the Integer Ring,
|
|
1459
|
+
Basis (f_1,f_2,f_3) on the Rank-3 free module M over the Integer Ring]
|
|
1460
|
+
sage: u.del_other_comp(f)
|
|
1461
|
+
sage: list(u._components)
|
|
1462
|
+
[Basis (f_1,f_2,f_3) on the Rank-3 free module M over the Integer Ring]
|
|
1463
|
+
|
|
1464
|
+
Let us restore the components w.r.t. e and delete those w.r.t. f::
|
|
1465
|
+
|
|
1466
|
+
sage: u.add_comp(e)[:] = [2,1,-5]
|
|
1467
|
+
sage: sorted(u._components, key=repr)
|
|
1468
|
+
[Basis (e_1,e_2,e_3) on the Rank-3 free module M over the Integer Ring,
|
|
1469
|
+
Basis (f_1,f_2,f_3) on the Rank-3 free module M over the Integer Ring]
|
|
1470
|
+
sage: u.del_other_comp() # default argument: basis = e
|
|
1471
|
+
sage: list(u._components)
|
|
1472
|
+
[Basis (e_1,e_2,e_3) on the Rank-3 free module M over the Integer Ring]
|
|
1473
|
+
"""
|
|
1474
|
+
if basis is None:
|
|
1475
|
+
basis = self._fmodule._def_basis
|
|
1476
|
+
if basis not in self._components:
|
|
1477
|
+
raise ValueError(f"the components w.r.t. the {basis}"
|
|
1478
|
+
" have not been defined")
|
|
1479
|
+
to_be_deleted = [other_basis for other_basis in self._components
|
|
1480
|
+
if other_basis != basis]
|
|
1481
|
+
for other_basis in to_be_deleted:
|
|
1482
|
+
del self._components[other_basis]
|
|
1483
|
+
|
|
1484
|
+
def __getitem__(self, args) -> Components:
|
|
1485
|
+
r"""
|
|
1486
|
+
Return a component w.r.t. some basis.
|
|
1487
|
+
|
|
1488
|
+
NB: if ``args`` is a string, this method acts as a shortcut for
|
|
1489
|
+
tensor contractions and symmetrizations, the string containing
|
|
1490
|
+
abstract indices.
|
|
1491
|
+
|
|
1492
|
+
INPUT:
|
|
1493
|
+
|
|
1494
|
+
- ``args`` -- list of indices defining the component; if ``[:]`` is
|
|
1495
|
+
provided, all the components are returned. The basis can be passed
|
|
1496
|
+
as the first item of ``args``; if not, the free module's default
|
|
1497
|
+
basis is assumed.
|
|
1498
|
+
|
|
1499
|
+
EXAMPLES::
|
|
1500
|
+
|
|
1501
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
1502
|
+
sage: t = M.tensor((2,1), name='t')
|
|
1503
|
+
sage: e = M.basis('e')
|
|
1504
|
+
sage: t.add_comp(e)
|
|
1505
|
+
3-indices components w.r.t. Basis (e_0,e_1,e_2) on the
|
|
1506
|
+
Rank-3 free module M over the Integer Ring
|
|
1507
|
+
sage: t.__getitem__((1,2,0)) # uninitialized components are zero
|
|
1508
|
+
0
|
|
1509
|
+
sage: t.__getitem__((e,1,2,0)) # same as above since e in the default basis
|
|
1510
|
+
0
|
|
1511
|
+
sage: t[1,2,0] = -4
|
|
1512
|
+
sage: t.__getitem__((e,1,2,0))
|
|
1513
|
+
-4
|
|
1514
|
+
sage: v = M([3,-5,2])
|
|
1515
|
+
sage: v.__getitem__(slice(None))
|
|
1516
|
+
[3, -5, 2]
|
|
1517
|
+
sage: v.__getitem__(slice(None)) == v[:]
|
|
1518
|
+
True
|
|
1519
|
+
sage: v.__getitem__((e, slice(None)))
|
|
1520
|
+
[3, -5, 2]
|
|
1521
|
+
"""
|
|
1522
|
+
if isinstance(args, str): # tensor with specified indices
|
|
1523
|
+
return TensorWithIndices(self, args).update()
|
|
1524
|
+
if isinstance(args, list): # case of [[...]] syntax
|
|
1525
|
+
if isinstance(args[0], (int, Integer, slice)):
|
|
1526
|
+
basis = self._fmodule._def_basis
|
|
1527
|
+
else:
|
|
1528
|
+
basis = args[0]
|
|
1529
|
+
args = args[1:]
|
|
1530
|
+
else:
|
|
1531
|
+
if isinstance(args, (int, Integer, slice)):
|
|
1532
|
+
basis = self._fmodule._def_basis
|
|
1533
|
+
elif not isinstance(args[0], (int, Integer, slice)):
|
|
1534
|
+
basis = args[0]
|
|
1535
|
+
args = args[1:]
|
|
1536
|
+
if len(args) == 1:
|
|
1537
|
+
args = args[0] # to accommodate for [e,:] syntax
|
|
1538
|
+
else:
|
|
1539
|
+
basis = self._fmodule._def_basis
|
|
1540
|
+
return self.comp(basis)[args]
|
|
1541
|
+
|
|
1542
|
+
def __setitem__(self, args, value):
|
|
1543
|
+
r"""
|
|
1544
|
+
Set a component w.r.t. some basis.
|
|
1545
|
+
|
|
1546
|
+
INPUT:
|
|
1547
|
+
|
|
1548
|
+
- ``args`` -- list of indices defining the component; if ``[:]`` is
|
|
1549
|
+
provided, all the components are set. The basis can be passed
|
|
1550
|
+
as the first item of ``args``; if not, the free module's default
|
|
1551
|
+
basis is assumed
|
|
1552
|
+
- ``value`` -- the value to be set or a list of values if
|
|
1553
|
+
``args = [:]``
|
|
1554
|
+
|
|
1555
|
+
EXAMPLES::
|
|
1556
|
+
|
|
1557
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
1558
|
+
sage: t = M.tensor((0,2), name='t')
|
|
1559
|
+
sage: e = M.basis('e')
|
|
1560
|
+
sage: t.__setitem__((e,0,1), 5)
|
|
1561
|
+
sage: t.display()
|
|
1562
|
+
t = 5 e^0⊗e^1
|
|
1563
|
+
sage: t.__setitem__((0,1), 5) # equivalent to above since e is the default basis
|
|
1564
|
+
sage: t.display()
|
|
1565
|
+
t = 5 e^0⊗e^1
|
|
1566
|
+
sage: t[0,1] = 5 # end-user usage
|
|
1567
|
+
sage: t.display()
|
|
1568
|
+
t = 5 e^0⊗e^1
|
|
1569
|
+
sage: t.__setitem__(slice(None), [[1,-2,3], [-4,5,-6], [7,-8,9]])
|
|
1570
|
+
sage: t[:]
|
|
1571
|
+
[ 1 -2 3]
|
|
1572
|
+
[-4 5 -6]
|
|
1573
|
+
[ 7 -8 9]
|
|
1574
|
+
"""
|
|
1575
|
+
if isinstance(args, list): # case of [[...]] syntax
|
|
1576
|
+
if isinstance(args[0], (int, Integer, slice, tuple)):
|
|
1577
|
+
basis = self._fmodule._def_basis
|
|
1578
|
+
else:
|
|
1579
|
+
basis = args[0]
|
|
1580
|
+
args = args[1:]
|
|
1581
|
+
else:
|
|
1582
|
+
if isinstance(args, (int, Integer, slice)):
|
|
1583
|
+
basis = self._fmodule._def_basis
|
|
1584
|
+
elif not isinstance(args[0], (int, Integer, slice)):
|
|
1585
|
+
basis = args[0]
|
|
1586
|
+
args = args[1:]
|
|
1587
|
+
if len(args) == 1:
|
|
1588
|
+
args = args[0] # to accommodate for [e,:] syntax
|
|
1589
|
+
else:
|
|
1590
|
+
basis = self._fmodule._def_basis
|
|
1591
|
+
self.set_comp(basis)[args] = value
|
|
1592
|
+
|
|
1593
|
+
def copy_from(self, other):
|
|
1594
|
+
r"""
|
|
1595
|
+
Make ``self`` to a copy from ``other``.
|
|
1596
|
+
|
|
1597
|
+
INPUT:
|
|
1598
|
+
|
|
1599
|
+
- ``other`` -- other tensor in the very same module from which
|
|
1600
|
+
``self`` should be a copy of
|
|
1601
|
+
|
|
1602
|
+
.. WARNING::
|
|
1603
|
+
|
|
1604
|
+
All previous defined components will be deleted!
|
|
1605
|
+
|
|
1606
|
+
EXAMPLES::
|
|
1607
|
+
|
|
1608
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M', start_index=1)
|
|
1609
|
+
sage: e = M.basis('e')
|
|
1610
|
+
sage: t = M.tensor((1,1), name='t')
|
|
1611
|
+
sage: t[1,2] = -3 ; t[3,3] = 2
|
|
1612
|
+
sage: s = M.tensor((1,1), name='s')
|
|
1613
|
+
sage: s.copy_from(t)
|
|
1614
|
+
sage: s[:]
|
|
1615
|
+
[ 0 -3 0]
|
|
1616
|
+
[ 0 0 0]
|
|
1617
|
+
[ 0 0 2]
|
|
1618
|
+
sage: s == t
|
|
1619
|
+
True
|
|
1620
|
+
|
|
1621
|
+
If the original tensor is modified, the copy is not::
|
|
1622
|
+
|
|
1623
|
+
sage: t[2,2] = 4
|
|
1624
|
+
sage: s[:]
|
|
1625
|
+
[ 0 -3 0]
|
|
1626
|
+
[ 0 0 0]
|
|
1627
|
+
[ 0 0 2]
|
|
1628
|
+
sage: s == t
|
|
1629
|
+
False
|
|
1630
|
+
"""
|
|
1631
|
+
if self.is_immutable():
|
|
1632
|
+
raise ValueError("the components of an immutable element "
|
|
1633
|
+
"cannot be changed")
|
|
1634
|
+
if other not in self.parent():
|
|
1635
|
+
raise TypeError("the original must be an element "
|
|
1636
|
+
+ "of {}".format(self.parent()))
|
|
1637
|
+
self._del_derived()
|
|
1638
|
+
self._components.clear()
|
|
1639
|
+
for basis, comp in other._components.items():
|
|
1640
|
+
self._components[basis] = comp.copy()
|
|
1641
|
+
self._is_zero = other._is_zero
|
|
1642
|
+
|
|
1643
|
+
def copy(self, name=None, latex_name=None):
|
|
1644
|
+
r"""
|
|
1645
|
+
Return an exact copy of ``self``.
|
|
1646
|
+
|
|
1647
|
+
The name and the derived quantities are not copied.
|
|
1648
|
+
|
|
1649
|
+
INPUT:
|
|
1650
|
+
|
|
1651
|
+
- ``name`` -- (default: ``None``) name given to the copy
|
|
1652
|
+
- ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
|
|
1653
|
+
copy; if none is provided, the LaTeX symbol is set to ``name``
|
|
1654
|
+
|
|
1655
|
+
EXAMPLES:
|
|
1656
|
+
|
|
1657
|
+
Copy of a tensor of type `(1,1)`::
|
|
1658
|
+
|
|
1659
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M', start_index=1)
|
|
1660
|
+
sage: e = M.basis('e')
|
|
1661
|
+
sage: t = M.tensor((1,1), name='t')
|
|
1662
|
+
sage: t[1,2] = -3 ; t[3,3] = 2
|
|
1663
|
+
sage: t1 = t.copy()
|
|
1664
|
+
sage: t1[:]
|
|
1665
|
+
[ 0 -3 0]
|
|
1666
|
+
[ 0 0 0]
|
|
1667
|
+
[ 0 0 2]
|
|
1668
|
+
sage: t1 == t
|
|
1669
|
+
True
|
|
1670
|
+
|
|
1671
|
+
If the original tensor is modified, the copy is not::
|
|
1672
|
+
|
|
1673
|
+
sage: t[2,2] = 4
|
|
1674
|
+
sage: t1[:]
|
|
1675
|
+
[ 0 -3 0]
|
|
1676
|
+
[ 0 0 0]
|
|
1677
|
+
[ 0 0 2]
|
|
1678
|
+
sage: t1 == t
|
|
1679
|
+
False
|
|
1680
|
+
"""
|
|
1681
|
+
resu = self._new_instance()
|
|
1682
|
+
resu.set_name(name=name, latex_name=latex_name)
|
|
1683
|
+
for basis, comp in self._components.items():
|
|
1684
|
+
resu._components[basis] = comp.copy()
|
|
1685
|
+
resu._is_zero = self._is_zero
|
|
1686
|
+
return resu
|
|
1687
|
+
|
|
1688
|
+
def common_basis(self, other):
|
|
1689
|
+
r"""
|
|
1690
|
+
Find a common basis for the components of ``self`` and ``other``.
|
|
1691
|
+
|
|
1692
|
+
In case of multiple common bases, the free module's default basis is
|
|
1693
|
+
privileged. If the current components of ``self`` and ``other``
|
|
1694
|
+
are all relative to different bases, a common basis is searched
|
|
1695
|
+
by performing a component transformation, via the transformations
|
|
1696
|
+
listed in ``self._fmodule._basis_changes``, still privileging
|
|
1697
|
+
transformations to the free module's default basis.
|
|
1698
|
+
|
|
1699
|
+
INPUT:
|
|
1700
|
+
|
|
1701
|
+
- ``other`` -- a tensor (instance of :class:`FreeModuleTensor`)
|
|
1702
|
+
|
|
1703
|
+
OUTPUT:
|
|
1704
|
+
|
|
1705
|
+
- instance of
|
|
1706
|
+
:class:`~sage.tensor.modules.free_module_basis.FreeModuleBasis`
|
|
1707
|
+
representing the common basis; if no common basis is found, ``None``
|
|
1708
|
+
is returned
|
|
1709
|
+
|
|
1710
|
+
EXAMPLES:
|
|
1711
|
+
|
|
1712
|
+
Common basis for the components of two module elements::
|
|
1713
|
+
|
|
1714
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M', start_index=1)
|
|
1715
|
+
sage: e = M.basis('e')
|
|
1716
|
+
sage: u = M([2,1,-5])
|
|
1717
|
+
sage: f = M.basis('f')
|
|
1718
|
+
sage: M._basis_changes.clear() # to ensure that bases e and f are unrelated at this stage
|
|
1719
|
+
sage: v = M([0,4,2], basis=f)
|
|
1720
|
+
sage: u.common_basis(v)
|
|
1721
|
+
|
|
1722
|
+
The above result is ``None`` since ``u`` and ``v`` have been defined
|
|
1723
|
+
on different bases and no connection between these bases have
|
|
1724
|
+
been set::
|
|
1725
|
+
|
|
1726
|
+
sage: list(u._components)
|
|
1727
|
+
[Basis (e_1,e_2,e_3) on the Rank-3 free module M over the Integer Ring]
|
|
1728
|
+
sage: list(v._components)
|
|
1729
|
+
[Basis (f_1,f_2,f_3) on the Rank-3 free module M over the Integer Ring]
|
|
1730
|
+
|
|
1731
|
+
Linking bases ``e`` and ``f`` changes the result::
|
|
1732
|
+
|
|
1733
|
+
sage: a = M.automorphism()
|
|
1734
|
+
sage: a[:] = [[0,0,1], [1,0,0], [0,-1,0]]
|
|
1735
|
+
sage: M.set_change_of_basis(e, f, a)
|
|
1736
|
+
sage: u.common_basis(v)
|
|
1737
|
+
Basis (e_1,e_2,e_3) on the Rank-3 free module M over the Integer Ring
|
|
1738
|
+
|
|
1739
|
+
Indeed, v is now known in basis e::
|
|
1740
|
+
|
|
1741
|
+
sage: sorted(v._components, key=repr)
|
|
1742
|
+
[Basis (e_1,e_2,e_3) on the Rank-3 free module M over the Integer Ring,
|
|
1743
|
+
Basis (f_1,f_2,f_3) on the Rank-3 free module M over the Integer Ring]
|
|
1744
|
+
"""
|
|
1745
|
+
# Compatibility checks:
|
|
1746
|
+
if not isinstance(other, FreeModuleTensor):
|
|
1747
|
+
raise TypeError("the argument must be a tensor on a free module")
|
|
1748
|
+
fmodule = self._fmodule
|
|
1749
|
+
if other._fmodule != fmodule:
|
|
1750
|
+
raise TypeError("the two tensors are not defined on the same " +
|
|
1751
|
+
"free module")
|
|
1752
|
+
def_basis = fmodule._def_basis
|
|
1753
|
+
|
|
1754
|
+
# 1/ Search for a common basis among the existing components, i.e.
|
|
1755
|
+
# without performing any component transformation.
|
|
1756
|
+
# -------------------------------------------------------------
|
|
1757
|
+
if def_basis in self._components and def_basis in other._components:
|
|
1758
|
+
return def_basis # the module's default basis is privileged
|
|
1759
|
+
for basis1 in self._components:
|
|
1760
|
+
if basis1 in other._components:
|
|
1761
|
+
return basis1
|
|
1762
|
+
|
|
1763
|
+
# 2/ Search for a common basis via one component transformation
|
|
1764
|
+
# ----------------------------------------------------------
|
|
1765
|
+
# If this point is reached, it is indeed necessary to perform at least
|
|
1766
|
+
# one component transformation to get a common basis
|
|
1767
|
+
if def_basis in self._components:
|
|
1768
|
+
for obasis in other._components:
|
|
1769
|
+
if (obasis, def_basis) in fmodule._basis_changes:
|
|
1770
|
+
other.comp(def_basis, from_basis=obasis)
|
|
1771
|
+
return def_basis
|
|
1772
|
+
if def_basis in other._components:
|
|
1773
|
+
for sbasis in self._components:
|
|
1774
|
+
if (sbasis, def_basis) in fmodule._basis_changes:
|
|
1775
|
+
self.comp(def_basis, from_basis=sbasis)
|
|
1776
|
+
return def_basis
|
|
1777
|
+
# If this point is reached, then def_basis cannot be a common basis
|
|
1778
|
+
# via a single component transformation
|
|
1779
|
+
for sbasis in self._components:
|
|
1780
|
+
for obasis in other._components:
|
|
1781
|
+
if (obasis, sbasis) in fmodule._basis_changes:
|
|
1782
|
+
other.comp(sbasis, from_basis=obasis)
|
|
1783
|
+
return sbasis
|
|
1784
|
+
if (sbasis, obasis) in fmodule._basis_changes:
|
|
1785
|
+
self.comp(obasis, from_basis=sbasis)
|
|
1786
|
+
return obasis
|
|
1787
|
+
|
|
1788
|
+
# 3/ Search for a common basis via two component transformations
|
|
1789
|
+
# -----------------------------------------------------------
|
|
1790
|
+
# If this point is reached, it is indeed necessary to perform at two
|
|
1791
|
+
# component transformation to get a common basis
|
|
1792
|
+
for sbasis in self._components:
|
|
1793
|
+
for obasis in other._components:
|
|
1794
|
+
if (sbasis, def_basis) in fmodule._basis_changes and \
|
|
1795
|
+
(obasis, def_basis) in fmodule._basis_changes:
|
|
1796
|
+
self.comp(def_basis, from_basis=sbasis)
|
|
1797
|
+
other.comp(def_basis, from_basis=obasis)
|
|
1798
|
+
return def_basis
|
|
1799
|
+
for basis in fmodule._known_bases:
|
|
1800
|
+
if (sbasis, basis) in fmodule._basis_changes and \
|
|
1801
|
+
(obasis, basis) in fmodule._basis_changes:
|
|
1802
|
+
self.comp(basis, from_basis=sbasis)
|
|
1803
|
+
other.comp(basis, from_basis=obasis)
|
|
1804
|
+
return basis
|
|
1805
|
+
|
|
1806
|
+
# If this point is reached, no common basis could be found, even at
|
|
1807
|
+
# the price of component transformations:
|
|
1808
|
+
return None
|
|
1809
|
+
|
|
1810
|
+
def pick_a_basis(self):
|
|
1811
|
+
r"""
|
|
1812
|
+
Return a basis in which the tensor components are defined.
|
|
1813
|
+
|
|
1814
|
+
The free module's default basis is privileged.
|
|
1815
|
+
|
|
1816
|
+
OUTPUT:
|
|
1817
|
+
|
|
1818
|
+
- instance of
|
|
1819
|
+
:class:`~sage.tensor.modules.free_module_basis.FreeModuleBasis`
|
|
1820
|
+
representing the basis
|
|
1821
|
+
|
|
1822
|
+
EXAMPLES::
|
|
1823
|
+
|
|
1824
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
1825
|
+
sage: t = M.tensor((2,0), name='t')
|
|
1826
|
+
sage: e = M.basis('e')
|
|
1827
|
+
sage: t[0,1] = 4 # component set in the default basis (e)
|
|
1828
|
+
sage: t.pick_a_basis()
|
|
1829
|
+
Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring
|
|
1830
|
+
sage: f = M.basis('f')
|
|
1831
|
+
sage: t.add_comp(f)[2,1] = -4 # the components in basis e are not erased
|
|
1832
|
+
sage: t.pick_a_basis()
|
|
1833
|
+
Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring
|
|
1834
|
+
sage: t.set_comp(f)[2,1] = -4 # the components in basis e not erased
|
|
1835
|
+
sage: t.pick_a_basis()
|
|
1836
|
+
Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring
|
|
1837
|
+
"""
|
|
1838
|
+
if self._fmodule._def_basis in self._components:
|
|
1839
|
+
return self._fmodule._def_basis # the default basis is privileged
|
|
1840
|
+
else:
|
|
1841
|
+
# a basis is picked arbitrarily:
|
|
1842
|
+
return next(iter(self._components.items()))[0]
|
|
1843
|
+
|
|
1844
|
+
def __eq__(self, other):
|
|
1845
|
+
r"""
|
|
1846
|
+
Comparison (equality) operator.
|
|
1847
|
+
|
|
1848
|
+
INPUT:
|
|
1849
|
+
|
|
1850
|
+
- ``other`` -- a tensor or 0
|
|
1851
|
+
|
|
1852
|
+
OUTPUT: ``True`` if ``self`` is equal to ``other`` and ``False`` otherwise
|
|
1853
|
+
|
|
1854
|
+
EXAMPLES::
|
|
1855
|
+
|
|
1856
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
1857
|
+
sage: t = M.tensor((2,0), name='t')
|
|
1858
|
+
sage: e = M.basis('e')
|
|
1859
|
+
sage: t[0,1] = 7
|
|
1860
|
+
sage: t.__eq__(0)
|
|
1861
|
+
False
|
|
1862
|
+
sage: t[0,1] = 0
|
|
1863
|
+
sage: t.__eq__(0)
|
|
1864
|
+
True
|
|
1865
|
+
sage: a = M.tensor((0,2), name='a')
|
|
1866
|
+
sage: a[0,1] = 7
|
|
1867
|
+
sage: t[0,1] = 7
|
|
1868
|
+
sage: a[:], t[:]
|
|
1869
|
+
(
|
|
1870
|
+
[0 7 0] [0 7 0]
|
|
1871
|
+
[0 0 0] [0 0 0]
|
|
1872
|
+
[0 0 0], [0 0 0]
|
|
1873
|
+
)
|
|
1874
|
+
sage: t.__eq__(a) # False since t and a do not have the same tensor type
|
|
1875
|
+
False
|
|
1876
|
+
sage: a = M.tensor((2,0), name='a') # same tensor type as t
|
|
1877
|
+
sage: a[0,1] = 7
|
|
1878
|
+
sage: t.__eq__(a)
|
|
1879
|
+
True
|
|
1880
|
+
"""
|
|
1881
|
+
if self is other:
|
|
1882
|
+
return True
|
|
1883
|
+
|
|
1884
|
+
if self._tensor_rank == 0:
|
|
1885
|
+
raise NotImplementedError("scalar comparison not implemented")
|
|
1886
|
+
if isinstance(other, (int, Integer)): # other should be 0
|
|
1887
|
+
if other == 0:
|
|
1888
|
+
return self.is_zero()
|
|
1889
|
+
else:
|
|
1890
|
+
return False
|
|
1891
|
+
elif not isinstance(other, FreeModuleTensor):
|
|
1892
|
+
return False
|
|
1893
|
+
else: # other is another tensor
|
|
1894
|
+
if other._fmodule != self._fmodule:
|
|
1895
|
+
return False
|
|
1896
|
+
if other._tensor_type != self._tensor_type:
|
|
1897
|
+
return False
|
|
1898
|
+
basis = self.common_basis(other)
|
|
1899
|
+
if basis is None:
|
|
1900
|
+
raise ValueError("no common basis for the comparison")
|
|
1901
|
+
return bool(self._components[basis] == other._components[basis])
|
|
1902
|
+
|
|
1903
|
+
def __ne__(self, other):
|
|
1904
|
+
r"""
|
|
1905
|
+
Inequality operator.
|
|
1906
|
+
|
|
1907
|
+
INPUT:
|
|
1908
|
+
|
|
1909
|
+
- ``other`` -- a tensor or 0
|
|
1910
|
+
|
|
1911
|
+
OUTPUT:
|
|
1912
|
+
|
|
1913
|
+
- ``True`` if ``self`` is different from ``other`` and ``False``
|
|
1914
|
+
otherwise
|
|
1915
|
+
|
|
1916
|
+
EXAMPLES::
|
|
1917
|
+
|
|
1918
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
1919
|
+
sage: t = M.tensor((2,0), name='t')
|
|
1920
|
+
sage: e = M.basis('e')
|
|
1921
|
+
sage: t[0,1] = 7
|
|
1922
|
+
sage: t.__ne__(0)
|
|
1923
|
+
True
|
|
1924
|
+
sage: t[0,1] = 0
|
|
1925
|
+
sage: t.__ne__(0)
|
|
1926
|
+
False
|
|
1927
|
+
sage: a = M.tensor((2,0), name='a') # same tensor type as t
|
|
1928
|
+
sage: a[0,1] = 7
|
|
1929
|
+
sage: t.__ne__(a)
|
|
1930
|
+
True
|
|
1931
|
+
sage: t[0,1] = 7
|
|
1932
|
+
sage: t.__ne__(a)
|
|
1933
|
+
False
|
|
1934
|
+
"""
|
|
1935
|
+
return not self == other
|
|
1936
|
+
|
|
1937
|
+
def __pos__(self):
|
|
1938
|
+
r"""
|
|
1939
|
+
Unary plus operator.
|
|
1940
|
+
|
|
1941
|
+
OUTPUT: an exact copy of ``self``
|
|
1942
|
+
|
|
1943
|
+
EXAMPLES::
|
|
1944
|
+
|
|
1945
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
1946
|
+
sage: t = M.tensor((2,0), name='t')
|
|
1947
|
+
sage: e = M.basis('e')
|
|
1948
|
+
sage: t[0,1] = 7
|
|
1949
|
+
sage: p = t.__pos__() ; p
|
|
1950
|
+
Type-(2,0) tensor +t on the Rank-3 free module M over the Integer Ring
|
|
1951
|
+
sage: p.display()
|
|
1952
|
+
+t = 7 e_0⊗e_1
|
|
1953
|
+
sage: p == t
|
|
1954
|
+
True
|
|
1955
|
+
sage: p is t
|
|
1956
|
+
False
|
|
1957
|
+
"""
|
|
1958
|
+
result = self._new_instance()
|
|
1959
|
+
for basis in self._components:
|
|
1960
|
+
result._components[basis] = + self._components[basis]
|
|
1961
|
+
if self._name is not None:
|
|
1962
|
+
result._name = '+' + self._name
|
|
1963
|
+
if self._latex_name is not None:
|
|
1964
|
+
result._latex_name = '+' + self._latex_name
|
|
1965
|
+
return result
|
|
1966
|
+
|
|
1967
|
+
def __neg__(self):
|
|
1968
|
+
r"""
|
|
1969
|
+
Unary minus operator.
|
|
1970
|
+
|
|
1971
|
+
OUTPUT: the tensor `-T`, where `T` is ``self``
|
|
1972
|
+
|
|
1973
|
+
EXAMPLES::
|
|
1974
|
+
|
|
1975
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
1976
|
+
sage: t = M.tensor((2,0), name='t')
|
|
1977
|
+
sage: e = M.basis('e')
|
|
1978
|
+
sage: t[0,1], t[1,2] = 7, -4
|
|
1979
|
+
sage: t.display()
|
|
1980
|
+
t = 7 e_0⊗e_1 - 4 e_1⊗e_2
|
|
1981
|
+
sage: a = t.__neg__() ; a
|
|
1982
|
+
Type-(2,0) tensor -t on the Rank-3 free module M over the Integer Ring
|
|
1983
|
+
sage: a.display()
|
|
1984
|
+
-t = -7 e_0⊗e_1 + 4 e_1⊗e_2
|
|
1985
|
+
sage: a == -t
|
|
1986
|
+
True
|
|
1987
|
+
"""
|
|
1988
|
+
result = self._new_instance()
|
|
1989
|
+
for basis in self._components:
|
|
1990
|
+
result._components[basis] = - self._components[basis]
|
|
1991
|
+
if self._name is not None:
|
|
1992
|
+
result._name = '-' + self._name
|
|
1993
|
+
if self._latex_name is not None:
|
|
1994
|
+
result._latex_name = '-' + self._latex_name
|
|
1995
|
+
return result
|
|
1996
|
+
|
|
1997
|
+
######### ModuleElement arithmetic operators ########
|
|
1998
|
+
|
|
1999
|
+
def _add_(self, other):
|
|
2000
|
+
r"""
|
|
2001
|
+
Tensor addition.
|
|
2002
|
+
|
|
2003
|
+
INPUT:
|
|
2004
|
+
|
|
2005
|
+
- ``other`` -- a tensor, of the same type as ``self``
|
|
2006
|
+
|
|
2007
|
+
OUTPUT: the tensor resulting from the addition of ``self`` and ``other``
|
|
2008
|
+
|
|
2009
|
+
EXAMPLES::
|
|
2010
|
+
|
|
2011
|
+
sage: M = FiniteRankFreeModule(ZZ, 2, name='M')
|
|
2012
|
+
sage: e = M.basis('e')
|
|
2013
|
+
sage: a = M.tensor((2,0), name='a')
|
|
2014
|
+
sage: a[:] = [[4,0], [-2,5]]
|
|
2015
|
+
sage: b = M.tensor((2,0), name='b')
|
|
2016
|
+
sage: b[:] = [[0,1], [2,3]]
|
|
2017
|
+
sage: s = a._add_(b) ; s
|
|
2018
|
+
Type-(2,0) tensor a+b on the Rank-2 free module M over the Integer Ring
|
|
2019
|
+
sage: s[:]
|
|
2020
|
+
[4 1]
|
|
2021
|
+
[0 8]
|
|
2022
|
+
sage: a._add_(-a) == 0
|
|
2023
|
+
True
|
|
2024
|
+
sage: a._add_(a) == 2*a
|
|
2025
|
+
True
|
|
2026
|
+
"""
|
|
2027
|
+
# No need for consistency check since self and other are guaranteed
|
|
2028
|
+
# to belong to the same tensor module
|
|
2029
|
+
#
|
|
2030
|
+
# Case zero:
|
|
2031
|
+
if self._is_zero:
|
|
2032
|
+
return other
|
|
2033
|
+
if other._is_zero:
|
|
2034
|
+
return self
|
|
2035
|
+
# Generic case:
|
|
2036
|
+
basis = self.common_basis(other)
|
|
2037
|
+
if basis is None:
|
|
2038
|
+
raise ValueError("no common basis for the addition")
|
|
2039
|
+
comp_result = self._components[basis] + other._components[basis]
|
|
2040
|
+
result = self._fmodule.tensor_from_comp(self._tensor_type, comp_result)
|
|
2041
|
+
if self._name is not None and other._name is not None:
|
|
2042
|
+
result._name = self._name + '+' + other._name
|
|
2043
|
+
if self._latex_name is not None and other._latex_name is not None:
|
|
2044
|
+
result._latex_name = self._latex_name + '+' + other._latex_name
|
|
2045
|
+
return result
|
|
2046
|
+
|
|
2047
|
+
def _sub_(self, other):
|
|
2048
|
+
r"""
|
|
2049
|
+
Tensor subtraction.
|
|
2050
|
+
|
|
2051
|
+
INPUT:
|
|
2052
|
+
|
|
2053
|
+
- ``other`` -- a tensor, of the same type as ``self``
|
|
2054
|
+
|
|
2055
|
+
OUTPUT: the tensor resulting from the subtraction of ``other`` from ``self``
|
|
2056
|
+
|
|
2057
|
+
EXAMPLES::
|
|
2058
|
+
|
|
2059
|
+
sage: M = FiniteRankFreeModule(ZZ, 2, name='M')
|
|
2060
|
+
sage: e = M.basis('e')
|
|
2061
|
+
sage: a = M.tensor((2,0), name='a')
|
|
2062
|
+
sage: a[:] = [[4,0], [-2,5]]
|
|
2063
|
+
sage: b = M.tensor((2,0), name='b')
|
|
2064
|
+
sage: b[:] = [[0,1], [2,3]]
|
|
2065
|
+
sage: s = a._sub_(b) ; s
|
|
2066
|
+
Type-(2,0) tensor a-b on the Rank-2 free module M over the Integer Ring
|
|
2067
|
+
sage: s[:]
|
|
2068
|
+
[ 4 -1]
|
|
2069
|
+
[-4 2]
|
|
2070
|
+
sage: b._sub_(a) == -s
|
|
2071
|
+
True
|
|
2072
|
+
sage: a._sub_(a) == 0
|
|
2073
|
+
True
|
|
2074
|
+
sage: a._sub_(-a) == 2*a
|
|
2075
|
+
True
|
|
2076
|
+
|
|
2077
|
+
TESTS:
|
|
2078
|
+
|
|
2079
|
+
Check for when there is not a basis, but the same object::
|
|
2080
|
+
|
|
2081
|
+
sage: M = FiniteRankFreeModule(QQ, 3, name='M')
|
|
2082
|
+
sage: t = M.tensor((2,1), name='t')
|
|
2083
|
+
sage: t == t
|
|
2084
|
+
True
|
|
2085
|
+
"""
|
|
2086
|
+
# No need for consistency check since self and other are guaranteed
|
|
2087
|
+
# to belong to the same tensor module
|
|
2088
|
+
#
|
|
2089
|
+
# Case zero:
|
|
2090
|
+
if self._is_zero:
|
|
2091
|
+
return -other
|
|
2092
|
+
if other._is_zero:
|
|
2093
|
+
return self
|
|
2094
|
+
# Generic case:
|
|
2095
|
+
basis = self.common_basis(other)
|
|
2096
|
+
if basis is None:
|
|
2097
|
+
raise ValueError("no common basis for the subtraction")
|
|
2098
|
+
comp_result = self._components[basis] - other._components[basis]
|
|
2099
|
+
result = self._fmodule.tensor_from_comp(self._tensor_type, comp_result)
|
|
2100
|
+
if self._name is not None and other._name is not None:
|
|
2101
|
+
result._name = self._name + '-' + other._name
|
|
2102
|
+
if self._latex_name is not None and other._latex_name is not None:
|
|
2103
|
+
result._latex_name = self._latex_name + '-' + other._latex_name
|
|
2104
|
+
return result
|
|
2105
|
+
|
|
2106
|
+
def _rmul_(self, other):
|
|
2107
|
+
r"""
|
|
2108
|
+
Multiplication on the left by ``other``.
|
|
2109
|
+
|
|
2110
|
+
EXAMPLES::
|
|
2111
|
+
|
|
2112
|
+
sage: M = FiniteRankFreeModule(ZZ, 2, name='M')
|
|
2113
|
+
sage: e = M.basis('e')
|
|
2114
|
+
sage: a = M.tensor((2,0), name='a')
|
|
2115
|
+
sage: a[:] = [[4,0], [-2,5]]
|
|
2116
|
+
sage: s = a._rmul_(2) ; s
|
|
2117
|
+
Type-(2,0) tensor on the Rank-2 free module M over the Integer Ring
|
|
2118
|
+
sage: s[:]
|
|
2119
|
+
[ 8 0]
|
|
2120
|
+
[-4 10]
|
|
2121
|
+
sage: s == a + a
|
|
2122
|
+
True
|
|
2123
|
+
sage: a._rmul_(0)
|
|
2124
|
+
Type-(2,0) tensor on the Rank-2 free module M over the Integer Ring
|
|
2125
|
+
sage: a._rmul_(0) == 0
|
|
2126
|
+
True
|
|
2127
|
+
sage: a._rmul_(1) == a
|
|
2128
|
+
True
|
|
2129
|
+
sage: a._rmul_(-1) == -a
|
|
2130
|
+
True
|
|
2131
|
+
"""
|
|
2132
|
+
#!# The following test is probably not necessary:
|
|
2133
|
+
if isinstance(other, FreeModuleTensor):
|
|
2134
|
+
raise NotImplementedError("left tensor product not implemented")
|
|
2135
|
+
# Left multiplication by a scalar:
|
|
2136
|
+
result = self._new_instance()
|
|
2137
|
+
for basis in self._components:
|
|
2138
|
+
result._components[basis] = other * self._components[basis]
|
|
2139
|
+
# If other has a name, set the name of the result:
|
|
2140
|
+
try:
|
|
2141
|
+
from .format_utilities import format_mul_txt, format_mul_latex
|
|
2142
|
+
result_name = format_mul_txt(other._name, '*', self._name)
|
|
2143
|
+
result_latex = format_mul_latex(other._latex_name, r' \cdot ',
|
|
2144
|
+
self._latex_name)
|
|
2145
|
+
result.set_name(name=result_name, latex_name=result_latex)
|
|
2146
|
+
except AttributeError:
|
|
2147
|
+
pass
|
|
2148
|
+
return result
|
|
2149
|
+
|
|
2150
|
+
######### End of ModuleElement arithmetic operators ########
|
|
2151
|
+
|
|
2152
|
+
def __mul__(self, other):
|
|
2153
|
+
r"""
|
|
2154
|
+
Tensor product.
|
|
2155
|
+
|
|
2156
|
+
EXAMPLES::
|
|
2157
|
+
|
|
2158
|
+
sage: M = FiniteRankFreeModule(ZZ, 2, name='M')
|
|
2159
|
+
sage: e = M.basis('e')
|
|
2160
|
+
sage: a = M.tensor((2,0), name='a')
|
|
2161
|
+
sage: a[:] = [[4,0], [-2,5]]
|
|
2162
|
+
sage: b = M.tensor((0,2), name='b', antisym=(0,1))
|
|
2163
|
+
sage: b[0,1] = 3
|
|
2164
|
+
sage: s = a.__mul__(b) ; s
|
|
2165
|
+
Type-(2,2) tensor a⊗b on the Rank-2 free module M over the Integer Ring
|
|
2166
|
+
sage: s.symmetries()
|
|
2167
|
+
no symmetry; antisymmetry: (2, 3)
|
|
2168
|
+
sage: s[:]
|
|
2169
|
+
[[[[0, 12], [-12, 0]], [[0, 0], [0, 0]]],
|
|
2170
|
+
[[[0, -6], [6, 0]], [[0, 15], [-15, 0]]]]
|
|
2171
|
+
"""
|
|
2172
|
+
from sage.typeset.unicode_characters import unicode_otimes
|
|
2173
|
+
from .format_utilities import format_mul_txt, format_mul_latex
|
|
2174
|
+
if isinstance(other, FreeModuleTensor):
|
|
2175
|
+
basis = self.common_basis(other)
|
|
2176
|
+
if basis is None:
|
|
2177
|
+
raise ValueError("no common basis for the tensor product")
|
|
2178
|
+
comp_prov = self._components[basis] * other._components[basis]
|
|
2179
|
+
# Reordering of the contravariant and covariant indices:
|
|
2180
|
+
k1, l1 = self._tensor_type
|
|
2181
|
+
k2, l2 = other._tensor_type
|
|
2182
|
+
if l1 != 0:
|
|
2183
|
+
comp_result = comp_prov.swap_adjacent_indices(k1,
|
|
2184
|
+
self._tensor_rank,
|
|
2185
|
+
self._tensor_rank+k2)
|
|
2186
|
+
else:
|
|
2187
|
+
comp_result = comp_prov # no reordering is necessary
|
|
2188
|
+
result = self._fmodule.tensor_from_comp((k1+k2, l1+l2),
|
|
2189
|
+
comp_result)
|
|
2190
|
+
result._name = format_mul_txt(self._name, unicode_otimes, other._name)
|
|
2191
|
+
result._latex_name = format_mul_latex(self._latex_name,
|
|
2192
|
+
r'\otimes ', other._latex_name)
|
|
2193
|
+
return result
|
|
2194
|
+
|
|
2195
|
+
# multiplication by a scalar:
|
|
2196
|
+
return FreeModuleTensor._rmul_(self, other)
|
|
2197
|
+
|
|
2198
|
+
def __truediv__(self, other):
|
|
2199
|
+
r"""
|
|
2200
|
+
Division (by a scalar).
|
|
2201
|
+
|
|
2202
|
+
EXAMPLES::
|
|
2203
|
+
|
|
2204
|
+
sage: M = FiniteRankFreeModule(QQ, 2, name='M')
|
|
2205
|
+
sage: e = M.basis('e')
|
|
2206
|
+
sage: a = M.tensor((2,0), name='a')
|
|
2207
|
+
sage: a[:] = [[4,0], [-2,5]]
|
|
2208
|
+
sage: s = a.__truediv__(4) ; s
|
|
2209
|
+
Type-(2,0) tensor on the 2-dimensional vector space M over the
|
|
2210
|
+
Rational Field
|
|
2211
|
+
sage: s[:]
|
|
2212
|
+
[ 1 0]
|
|
2213
|
+
[-1/2 5/4]
|
|
2214
|
+
sage: 4*s == a
|
|
2215
|
+
True
|
|
2216
|
+
sage: s == a/4
|
|
2217
|
+
True
|
|
2218
|
+
"""
|
|
2219
|
+
result = self._new_instance()
|
|
2220
|
+
for basis in self._components:
|
|
2221
|
+
result._components[basis] = self._components[basis] / other
|
|
2222
|
+
return result
|
|
2223
|
+
|
|
2224
|
+
def __call__(self, *args) -> Expression:
|
|
2225
|
+
r"""
|
|
2226
|
+
The tensor acting on linear forms and module elements as a multilinear
|
|
2227
|
+
map.
|
|
2228
|
+
|
|
2229
|
+
INPUT:
|
|
2230
|
+
|
|
2231
|
+
- ``*args`` -- list of `k` linear forms and `l` module elements
|
|
2232
|
+
with ``self`` being a tensor of type `(k, l)`
|
|
2233
|
+
|
|
2234
|
+
EXAMPLES:
|
|
2235
|
+
|
|
2236
|
+
Action of a type-`(2,1)` tensor::
|
|
2237
|
+
|
|
2238
|
+
sage: M = FiniteRankFreeModule(ZZ, 2, name='M')
|
|
2239
|
+
sage: e = M.basis('e')
|
|
2240
|
+
sage: t = M.tensor((2,1), name='t', antisym=(0,1))
|
|
2241
|
+
sage: t[0,1,0], t[0,1,1] = 3, 2
|
|
2242
|
+
sage: t.display()
|
|
2243
|
+
t = 3 e_0⊗e_1⊗e^0 + 2 e_0⊗e_1⊗e^1 - 3 e_1⊗e_0⊗e^0 - 2 e_1⊗e_0⊗e^1
|
|
2244
|
+
sage: a = M.linear_form()
|
|
2245
|
+
sage: a[:] = 1, 2
|
|
2246
|
+
sage: b = M.linear_form()
|
|
2247
|
+
sage: b[:] = 3, -1
|
|
2248
|
+
sage: v = M([-2,1])
|
|
2249
|
+
sage: t.__call__(a,b,v)
|
|
2250
|
+
28
|
|
2251
|
+
sage: t(a,b,v) == t.__call__(a,b,v)
|
|
2252
|
+
True
|
|
2253
|
+
sage: t(a,b,v) == t.contract(v).contract(b).contract(a)
|
|
2254
|
+
True
|
|
2255
|
+
|
|
2256
|
+
Action of a linear form on a vector::
|
|
2257
|
+
|
|
2258
|
+
sage: a.__call__(v)
|
|
2259
|
+
0
|
|
2260
|
+
sage: a.__call__(v) == a(v)
|
|
2261
|
+
True
|
|
2262
|
+
sage: a(v) == a.contract(v)
|
|
2263
|
+
True
|
|
2264
|
+
sage: b.__call__(v)
|
|
2265
|
+
-7
|
|
2266
|
+
sage: b.__call__(v) == b(v)
|
|
2267
|
+
True
|
|
2268
|
+
sage: b(v) == b.contract(v)
|
|
2269
|
+
True
|
|
2270
|
+
|
|
2271
|
+
Action of a vector on a linear form::
|
|
2272
|
+
|
|
2273
|
+
sage: v.__call__(a)
|
|
2274
|
+
0
|
|
2275
|
+
sage: v.__call__(b)
|
|
2276
|
+
-7
|
|
2277
|
+
"""
|
|
2278
|
+
# Consistency checks:
|
|
2279
|
+
p = len(args)
|
|
2280
|
+
if p != self._tensor_rank:
|
|
2281
|
+
raise TypeError(str(self._tensor_rank) +
|
|
2282
|
+
" arguments must be provided")
|
|
2283
|
+
for i in range(self._tensor_type[0]):
|
|
2284
|
+
if not isinstance(args[i], FreeModuleTensor):
|
|
2285
|
+
raise TypeError("the argument no. " + str(i+1) +
|
|
2286
|
+
" must be a linear form")
|
|
2287
|
+
if args[i]._tensor_type != (0,1):
|
|
2288
|
+
raise TypeError("the argument no. " + str(i+1) +
|
|
2289
|
+
" must be a linear form")
|
|
2290
|
+
for i in range(self._tensor_type[0], p):
|
|
2291
|
+
if not isinstance(args[i], FreeModuleTensor):
|
|
2292
|
+
raise TypeError("the argument no. " + str(i+1) +
|
|
2293
|
+
" must be a module element")
|
|
2294
|
+
if args[i]._tensor_type != (1,0):
|
|
2295
|
+
raise TypeError("the argument no. " + str(i+1) +
|
|
2296
|
+
" must be a module element")
|
|
2297
|
+
fmodule = self._fmodule
|
|
2298
|
+
#
|
|
2299
|
+
# Specific case of a linear form acting on a vector (for efficiency):
|
|
2300
|
+
#
|
|
2301
|
+
if self._tensor_type == (0,1):
|
|
2302
|
+
vector = args[0]
|
|
2303
|
+
basis = self.common_basis(vector)
|
|
2304
|
+
if basis is None:
|
|
2305
|
+
raise ValueError("no common basis for the components")
|
|
2306
|
+
omega = self._components[basis]
|
|
2307
|
+
vv = vector._components[basis]
|
|
2308
|
+
resu = 0
|
|
2309
|
+
for i in fmodule.irange():
|
|
2310
|
+
resu += omega[[i]]*vv[[i]]
|
|
2311
|
+
# Name and LaTeX symbol of the output:
|
|
2312
|
+
if hasattr(resu, '_name'):
|
|
2313
|
+
if self._name is not None and vector._name is not None:
|
|
2314
|
+
resu._name = self._name + "(" + vector._name + ")"
|
|
2315
|
+
if hasattr(resu, '_latex_name'):
|
|
2316
|
+
if self._latex_name is not None and \
|
|
2317
|
+
vector._latex_name is not None:
|
|
2318
|
+
resu._latex_name = self._latex_name + r"\left(" + \
|
|
2319
|
+
vector._latex_name + r"\right)"
|
|
2320
|
+
return resu
|
|
2321
|
+
#
|
|
2322
|
+
# Generic case
|
|
2323
|
+
#
|
|
2324
|
+
# Search for a common basis
|
|
2325
|
+
basis = None
|
|
2326
|
+
# First try with the module's default basis
|
|
2327
|
+
def_basis = fmodule._def_basis
|
|
2328
|
+
if def_basis in self._components:
|
|
2329
|
+
basis = def_basis
|
|
2330
|
+
for arg in args:
|
|
2331
|
+
if def_basis not in arg._components:
|
|
2332
|
+
basis = None
|
|
2333
|
+
break
|
|
2334
|
+
if basis is None:
|
|
2335
|
+
# Search for another basis:
|
|
2336
|
+
for bas in self._components:
|
|
2337
|
+
basis = bas
|
|
2338
|
+
for arg in args:
|
|
2339
|
+
if bas not in arg._components:
|
|
2340
|
+
basis = None
|
|
2341
|
+
break
|
|
2342
|
+
if basis is not None: # common basis found !
|
|
2343
|
+
break
|
|
2344
|
+
if basis is None:
|
|
2345
|
+
# A last attempt to find a common basis, possibly via a
|
|
2346
|
+
# change-of-components transformation
|
|
2347
|
+
for arg in args:
|
|
2348
|
+
self.common_basis(arg) # to trigger some change of components
|
|
2349
|
+
for bas in self._components:
|
|
2350
|
+
basis = bas
|
|
2351
|
+
for arg in args:
|
|
2352
|
+
if bas not in arg._components:
|
|
2353
|
+
basis = None
|
|
2354
|
+
break
|
|
2355
|
+
if basis is not None: # common basis found !
|
|
2356
|
+
break
|
|
2357
|
+
if basis is None:
|
|
2358
|
+
raise ValueError("no common basis for the components")
|
|
2359
|
+
t = self._components[basis]
|
|
2360
|
+
v = [args[i]._components[basis] for i in range(p)]
|
|
2361
|
+
res = 0
|
|
2362
|
+
for ind in t.index_generator():
|
|
2363
|
+
prod = t[[ind]]
|
|
2364
|
+
for i in range(p):
|
|
2365
|
+
prod *= v[i][[ind[i]]]
|
|
2366
|
+
res += prod
|
|
2367
|
+
# Name of the output:
|
|
2368
|
+
if hasattr(res, '_name'):
|
|
2369
|
+
res_name = None
|
|
2370
|
+
if self._name is not None:
|
|
2371
|
+
res_name = self._name + "("
|
|
2372
|
+
for i in range(p-1):
|
|
2373
|
+
if args[i]._name is not None:
|
|
2374
|
+
res_name += args[i]._name + ","
|
|
2375
|
+
else:
|
|
2376
|
+
res_name = None
|
|
2377
|
+
break
|
|
2378
|
+
if res_name is not None:
|
|
2379
|
+
if args[p-1]._name is not None:
|
|
2380
|
+
res_name += args[p-1]._name + ")"
|
|
2381
|
+
else:
|
|
2382
|
+
res_name = None
|
|
2383
|
+
res._name = res_name
|
|
2384
|
+
# LaTeX symbol of the output:
|
|
2385
|
+
if hasattr(res, '_latex_name'):
|
|
2386
|
+
res_latex = None
|
|
2387
|
+
if self._latex_name is not None:
|
|
2388
|
+
res_latex = self._latex_name + r"\left("
|
|
2389
|
+
for i in range(p-1):
|
|
2390
|
+
if args[i]._latex_name is not None:
|
|
2391
|
+
res_latex += args[i]._latex_name + ","
|
|
2392
|
+
else:
|
|
2393
|
+
res_latex = None
|
|
2394
|
+
break
|
|
2395
|
+
if res_latex is not None:
|
|
2396
|
+
if args[p-1]._latex_name is not None:
|
|
2397
|
+
res_latex += args[p-1]._latex_name + r"\right)"
|
|
2398
|
+
else:
|
|
2399
|
+
res_latex = None
|
|
2400
|
+
res._latex_name = res_latex
|
|
2401
|
+
return res
|
|
2402
|
+
|
|
2403
|
+
def trace(
|
|
2404
|
+
self,
|
|
2405
|
+
pos1: int = 0,
|
|
2406
|
+
pos2: int = 1,
|
|
2407
|
+
using: Optional[
|
|
2408
|
+
Union[PseudoRiemannianMetric, SymplecticForm, PoissonTensorField]
|
|
2409
|
+
] = None,
|
|
2410
|
+
):
|
|
2411
|
+
r"""
|
|
2412
|
+
Trace (contraction) on two slots of the tensor.
|
|
2413
|
+
|
|
2414
|
+
If a non-degenerate form is provided, the trace of a type-`(0,2)` tensor
|
|
2415
|
+
is computed by first raising the last index.
|
|
2416
|
+
|
|
2417
|
+
INPUT:
|
|
2418
|
+
|
|
2419
|
+
- ``pos1`` -- (default: 0) position of the first index for the
|
|
2420
|
+
contraction, with the convention ``pos1=0`` for the first slot
|
|
2421
|
+
|
|
2422
|
+
- ``pos2`` -- (default: 1) position of the second index for the
|
|
2423
|
+
contraction, with the same convention as for ``pos1``; the variance
|
|
2424
|
+
type of ``pos2`` must be opposite to that of ``pos1``
|
|
2425
|
+
|
|
2426
|
+
- ``using`` -- (default: ``None``) a non-degenerate form
|
|
2427
|
+
|
|
2428
|
+
OUTPUT:
|
|
2429
|
+
|
|
2430
|
+
- tensor or scalar resulting from the ``(pos1, pos2)`` contraction
|
|
2431
|
+
|
|
2432
|
+
EXAMPLES:
|
|
2433
|
+
|
|
2434
|
+
Trace of a type-`(1,1)` tensor::
|
|
2435
|
+
|
|
2436
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
2437
|
+
sage: e = M.basis('e') ; e
|
|
2438
|
+
Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring
|
|
2439
|
+
sage: a = M.tensor((1,1), name='a') ; a
|
|
2440
|
+
Type-(1,1) tensor a on the Rank-3 free module M over the Integer Ring
|
|
2441
|
+
sage: a[:] = [[1,2,3], [4,5,6], [7,8,9]]
|
|
2442
|
+
sage: a.trace()
|
|
2443
|
+
15
|
|
2444
|
+
sage: a.trace(0,1) # equivalent to above (contraction of slot 0 with slot 1)
|
|
2445
|
+
15
|
|
2446
|
+
sage: a.trace(1,0) # the order of the slots does not matter
|
|
2447
|
+
15
|
|
2448
|
+
|
|
2449
|
+
Instead of the explicit call to the method :meth:`trace`, one
|
|
2450
|
+
may use the index notation with Einstein convention (summation over
|
|
2451
|
+
repeated indices); it suffices to pass the indices as a string inside
|
|
2452
|
+
square brackets::
|
|
2453
|
+
|
|
2454
|
+
sage: a['^i_i']
|
|
2455
|
+
15
|
|
2456
|
+
|
|
2457
|
+
The letter 'i' to denote the repeated index can be replaced by any
|
|
2458
|
+
other letter::
|
|
2459
|
+
|
|
2460
|
+
sage: a['^s_s']
|
|
2461
|
+
15
|
|
2462
|
+
|
|
2463
|
+
Moreover, the symbol ``^`` can be omitted::
|
|
2464
|
+
|
|
2465
|
+
sage: a['i_i']
|
|
2466
|
+
15
|
|
2467
|
+
|
|
2468
|
+
The contraction on two slots having the same tensor type cannot occur::
|
|
2469
|
+
|
|
2470
|
+
sage: b = M.tensor((2,0), name='b') ; b
|
|
2471
|
+
Type-(2,0) tensor b on the Rank-3 free module M over the Integer Ring
|
|
2472
|
+
sage: b[:] = [[1,2,3], [4,5,6], [7,8,9]]
|
|
2473
|
+
sage: b.trace(0,1)
|
|
2474
|
+
Traceback (most recent call last):
|
|
2475
|
+
...
|
|
2476
|
+
IndexError: contraction on two contravariant indices is not allowed
|
|
2477
|
+
|
|
2478
|
+
The contraction either preserves or destroys the symmetries::
|
|
2479
|
+
|
|
2480
|
+
sage: b = M.alternating_form(2, 'b') ; b
|
|
2481
|
+
Alternating form b of degree 2 on the Rank-3 free module M
|
|
2482
|
+
over the Integer Ring
|
|
2483
|
+
sage: b[0,1], b[0,2], b[1,2] = 3, 2, 1
|
|
2484
|
+
sage: t = a*b ; t
|
|
2485
|
+
Type-(1,3) tensor a⊗b on the Rank-3 free module M
|
|
2486
|
+
over the Integer Ring
|
|
2487
|
+
|
|
2488
|
+
By construction, ``t`` is a tensor field antisymmetric w.r.t. its
|
|
2489
|
+
last two slots::
|
|
2490
|
+
|
|
2491
|
+
sage: t.symmetries()
|
|
2492
|
+
no symmetry; antisymmetry: (2, 3)
|
|
2493
|
+
sage: s = t.trace(0,1) ; s # contraction on the first two slots
|
|
2494
|
+
Alternating form of degree 2 on the
|
|
2495
|
+
Rank-3 free module M over the Integer Ring
|
|
2496
|
+
sage: s.symmetries() # the antisymmetry is preserved
|
|
2497
|
+
no symmetry; antisymmetry: (0, 1)
|
|
2498
|
+
sage: s[:]
|
|
2499
|
+
[ 0 45 30]
|
|
2500
|
+
[-45 0 15]
|
|
2501
|
+
[-30 -15 0]
|
|
2502
|
+
sage: s == 15*b # check
|
|
2503
|
+
True
|
|
2504
|
+
sage: s = t.trace(0,2) ; s # contraction on the first and third slots
|
|
2505
|
+
Type-(0,2) tensor on the Rank-3 free module M over the Integer Ring
|
|
2506
|
+
sage: s.symmetries() # the antisymmetry has been destroyed by the above contraction:
|
|
2507
|
+
no symmetry; no antisymmetry
|
|
2508
|
+
sage: s[:] # indeed:
|
|
2509
|
+
[-26 -4 6]
|
|
2510
|
+
[-31 -2 9]
|
|
2511
|
+
[-36 0 12]
|
|
2512
|
+
sage: s[:] == matrix( [[sum(t[k,i,k,j] for k in M.irange())
|
|
2513
|
+
....: for j in M.irange()] for i in M.irange()] ) # check
|
|
2514
|
+
True
|
|
2515
|
+
|
|
2516
|
+
Use of index notation instead of :meth:`trace`::
|
|
2517
|
+
|
|
2518
|
+
sage: t['^k_kij'] == t.trace(0,1)
|
|
2519
|
+
True
|
|
2520
|
+
sage: t['^k_{kij}'] == t.trace(0,1) # LaTeX notation
|
|
2521
|
+
True
|
|
2522
|
+
sage: t['^k_ikj'] == t.trace(0,2)
|
|
2523
|
+
True
|
|
2524
|
+
sage: t['^k_ijk'] == t.trace(0,3)
|
|
2525
|
+
True
|
|
2526
|
+
|
|
2527
|
+
Index symbols not involved in the contraction may be replaced by
|
|
2528
|
+
dots::
|
|
2529
|
+
|
|
2530
|
+
sage: t['^k_k..'] == t.trace(0,1)
|
|
2531
|
+
True
|
|
2532
|
+
sage: t['^k_.k.'] == t.trace(0,2)
|
|
2533
|
+
True
|
|
2534
|
+
sage: t['^k_..k'] == t.trace(0,3)
|
|
2535
|
+
True
|
|
2536
|
+
"""
|
|
2537
|
+
if using is not None:
|
|
2538
|
+
if self.tensor_type() != (0, 2):
|
|
2539
|
+
raise ValueError(
|
|
2540
|
+
"trace with respect to a non-degenerate form is only defined for type-(0,2) tensor"
|
|
2541
|
+
)
|
|
2542
|
+
return self.up(using, 1).trace()
|
|
2543
|
+
|
|
2544
|
+
# The indices at pos1 and pos2 must be of different types:
|
|
2545
|
+
k_con = self._tensor_type[0]
|
|
2546
|
+
l_cov = self._tensor_type[1]
|
|
2547
|
+
if pos1 < k_con and pos2 < k_con:
|
|
2548
|
+
raise IndexError("contraction on two contravariant indices is " +
|
|
2549
|
+
"not allowed")
|
|
2550
|
+
if pos1 >= k_con and pos2 >= k_con:
|
|
2551
|
+
raise IndexError("contraction on two covariant indices is " +
|
|
2552
|
+
"not allowed")
|
|
2553
|
+
# Frame selection for the computation:
|
|
2554
|
+
if self._fmodule._def_basis in self._components:
|
|
2555
|
+
basis = self._fmodule._def_basis
|
|
2556
|
+
else: # a basis is picked arbitrarily:
|
|
2557
|
+
basis = self.pick_a_basis()
|
|
2558
|
+
resu_comp = self._components[basis].trace(pos1, pos2)
|
|
2559
|
+
if self._tensor_rank == 2: # result is a scalar
|
|
2560
|
+
return resu_comp
|
|
2561
|
+
else:
|
|
2562
|
+
return self._fmodule.tensor_from_comp((k_con-1, l_cov-1),
|
|
2563
|
+
resu_comp)
|
|
2564
|
+
|
|
2565
|
+
def contract(self, *args):
|
|
2566
|
+
r"""
|
|
2567
|
+
Contraction on one or more indices with another tensor.
|
|
2568
|
+
|
|
2569
|
+
INPUT:
|
|
2570
|
+
|
|
2571
|
+
- ``pos1`` -- positions of the indices in ``self`` involved in the
|
|
2572
|
+
contraction; ``pos1`` must be a sequence of integers, with 0 standing
|
|
2573
|
+
for the first index position, 1 for the second one, etc; if ``pos1``
|
|
2574
|
+
is not provided, a single contraction on the last index position of
|
|
2575
|
+
``self`` is assumed
|
|
2576
|
+
- ``other`` -- the tensor to contract with
|
|
2577
|
+
- ``pos2`` -- positions of the indices in ``other`` involved in the
|
|
2578
|
+
contraction, with the same conventions as for ``pos1``; if ``pos2``
|
|
2579
|
+
is not provided, a single contraction on the first index position of
|
|
2580
|
+
``other`` is assumed
|
|
2581
|
+
|
|
2582
|
+
OUTPUT:
|
|
2583
|
+
|
|
2584
|
+
- tensor resulting from the contraction at the positions ``pos1`` and
|
|
2585
|
+
``pos2`` of ``self`` with ``other``
|
|
2586
|
+
|
|
2587
|
+
EXAMPLES:
|
|
2588
|
+
|
|
2589
|
+
Contraction of a tensor of type `(0,1)` with a tensor of type `(1,0)`::
|
|
2590
|
+
|
|
2591
|
+
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
|
|
2592
|
+
sage: e = M.basis('e')
|
|
2593
|
+
sage: a = M.linear_form() # tensor of type (0,1) is a linear form
|
|
2594
|
+
sage: a[:] = [-3,2,1]
|
|
2595
|
+
sage: b = M([2,5,-2]) # tensor of type (1,0) is a module element
|
|
2596
|
+
sage: s = a.contract(b) ; s
|
|
2597
|
+
2
|
|
2598
|
+
sage: s in M.base_ring()
|
|
2599
|
+
True
|
|
2600
|
+
sage: s == a[0]*b[0] + a[1]*b[1] + a[2]*b[2] # check of the computation
|
|
2601
|
+
True
|
|
2602
|
+
|
|
2603
|
+
The positions of the contraction indices can be set explicitly::
|
|
2604
|
+
|
|
2605
|
+
sage: s == a.contract(0, b, 0)
|
|
2606
|
+
True
|
|
2607
|
+
sage: s == a.contract(0, b)
|
|
2608
|
+
True
|
|
2609
|
+
sage: s == a.contract(b, 0)
|
|
2610
|
+
True
|
|
2611
|
+
|
|
2612
|
+
Instead of the explicit call to the method :meth:`contract`, the index
|
|
2613
|
+
notation can be used to specify the contraction, via Einstein
|
|
2614
|
+
convention (summation on repeated indices); it suffices to pass the
|
|
2615
|
+
indices as a string inside square brackets::
|
|
2616
|
+
|
|
2617
|
+
sage: s1 = a['_i']*b['^i'] ; s1
|
|
2618
|
+
2
|
|
2619
|
+
sage: s1 == s
|
|
2620
|
+
True
|
|
2621
|
+
|
|
2622
|
+
In the present case, performing the contraction is identical to
|
|
2623
|
+
applying the linear form to the module element::
|
|
2624
|
+
|
|
2625
|
+
sage: a.contract(b) == a(b)
|
|
2626
|
+
True
|
|
2627
|
+
|
|
2628
|
+
or to applying the module element, considered as a tensor of type
|
|
2629
|
+
`(1,0)`, to the linear form::
|
|
2630
|
+
|
|
2631
|
+
sage: a.contract(b) == b(a)
|
|
2632
|
+
True
|
|
2633
|
+
|
|
2634
|
+
We have also::
|
|
2635
|
+
|
|
2636
|
+
sage: a.contract(b) == b.contract(a)
|
|
2637
|
+
True
|
|
2638
|
+
|
|
2639
|
+
Contraction of a tensor of type `(1,1)` with a tensor of type `(1,0)`::
|
|
2640
|
+
|
|
2641
|
+
sage: a = M.tensor((1,1))
|
|
2642
|
+
sage: a[:] = [[-1,2,3],[4,-5,6],[7,8,9]]
|
|
2643
|
+
sage: s = a.contract(b) ; s
|
|
2644
|
+
Element of the Rank-3 free module M over the Integer Ring
|
|
2645
|
+
sage: s.display()
|
|
2646
|
+
2 e_0 - 29 e_1 + 36 e_2
|
|
2647
|
+
|
|
2648
|
+
Since the index positions have not been specified, the contraction
|
|
2649
|
+
takes place on the last position of a (i.e. no. 1) and the first
|
|
2650
|
+
position of ``b`` (i.e. no. 0)::
|
|
2651
|
+
|
|
2652
|
+
sage: a.contract(b) == a.contract(1, b, 0)
|
|
2653
|
+
True
|
|
2654
|
+
sage: a.contract(b) == b.contract(0, a, 1)
|
|
2655
|
+
True
|
|
2656
|
+
sage: a.contract(b) == b.contract(a, 1)
|
|
2657
|
+
True
|
|
2658
|
+
|
|
2659
|
+
Using the index notation with Einstein convention::
|
|
2660
|
+
|
|
2661
|
+
sage: a['^i_j']*b['^j'] == a.contract(b)
|
|
2662
|
+
True
|
|
2663
|
+
|
|
2664
|
+
The index ``i`` can be replaced by a dot::
|
|
2665
|
+
|
|
2666
|
+
sage: a['^._j']*b['^j'] == a.contract(b)
|
|
2667
|
+
True
|
|
2668
|
+
|
|
2669
|
+
and the symbol ``^`` may be omitted, the distinction between
|
|
2670
|
+
contravariant and covariant indices being the position with respect to
|
|
2671
|
+
the symbol ``_``::
|
|
2672
|
+
|
|
2673
|
+
sage: a['._j']*b['j'] == a.contract(b)
|
|
2674
|
+
True
|
|
2675
|
+
|
|
2676
|
+
Contraction is possible only between a contravariant index and a
|
|
2677
|
+
covariant one::
|
|
2678
|
+
|
|
2679
|
+
sage: a.contract(0, b)
|
|
2680
|
+
Traceback (most recent call last):
|
|
2681
|
+
...
|
|
2682
|
+
TypeError: contraction on two contravariant indices not permitted
|
|
2683
|
+
|
|
2684
|
+
Contraction of a tensor of type `(2,1)` with a tensor of type `(0,2)`::
|
|
2685
|
+
|
|
2686
|
+
sage: a = a*b ; a
|
|
2687
|
+
Type-(2,1) tensor on the Rank-3 free module M over the Integer Ring
|
|
2688
|
+
sage: b = M.tensor((0,2))
|
|
2689
|
+
sage: b[:] = [[-2,3,1], [0,-2,3], [4,-7,6]]
|
|
2690
|
+
sage: s = a.contract(1, b, 1) ; s
|
|
2691
|
+
Type-(1,2) tensor on the Rank-3 free module M over the Integer Ring
|
|
2692
|
+
sage: s[:]
|
|
2693
|
+
[[[-9, 16, 39], [18, -32, -78], [27, -48, -117]],
|
|
2694
|
+
[[36, -64, -156], [-45, 80, 195], [54, -96, -234]],
|
|
2695
|
+
[[63, -112, -273], [72, -128, -312], [81, -144, -351]]]
|
|
2696
|
+
|
|
2697
|
+
Check of the computation::
|
|
2698
|
+
|
|
2699
|
+
sage: all(s[i,j,k] == a[i,0,j]*b[k,0]+a[i,1,j]*b[k,1]+a[i,2,j]*b[k,2]
|
|
2700
|
+
....: for i in range(3) for j in range(3) for k in range(3))
|
|
2701
|
+
True
|
|
2702
|
+
|
|
2703
|
+
Using index notation::
|
|
2704
|
+
|
|
2705
|
+
sage: a['il_j']*b['_kl'] == a.contract(1, b, 1)
|
|
2706
|
+
True
|
|
2707
|
+
|
|
2708
|
+
LaTeX notation are allowed::
|
|
2709
|
+
|
|
2710
|
+
sage: a['^{il}_j']*b['_{kl}'] == a.contract(1, b, 1)
|
|
2711
|
+
True
|
|
2712
|
+
|
|
2713
|
+
Indices not involved in the contraction may be replaced by dots::
|
|
2714
|
+
|
|
2715
|
+
sage: a['.l_.']*b['_.l'] == a.contract(1, b, 1)
|
|
2716
|
+
True
|
|
2717
|
+
|
|
2718
|
+
The two tensors do not have to be defined on the same basis for the
|
|
2719
|
+
contraction to take place, reflecting the fact that the contraction is
|
|
2720
|
+
basis-independent::
|
|
2721
|
+
|
|
2722
|
+
sage: A = M.automorphism()
|
|
2723
|
+
sage: A[:] = [[0,0,1], [1,0,0], [0,-1,0]]
|
|
2724
|
+
sage: h = e.new_basis(A, 'h')
|
|
2725
|
+
sage: b.comp(h)[:] # forces the computation of b's components w.r.t. basis h
|
|
2726
|
+
[-2 -3 0]
|
|
2727
|
+
[ 7 6 -4]
|
|
2728
|
+
[ 3 -1 -2]
|
|
2729
|
+
sage: b.del_other_comp(h) # deletes components w.r.t. basis e
|
|
2730
|
+
sage: list(b._components) # indeed:
|
|
2731
|
+
[Basis (h_0,h_1,h_2) on the Rank-3 free module M over the Integer Ring]
|
|
2732
|
+
sage: list(a._components) # while a is known only in basis e:
|
|
2733
|
+
[Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring]
|
|
2734
|
+
sage: s1 = a.contract(1, b, 1) ; s1 # yet the computation is possible
|
|
2735
|
+
Type-(1,2) tensor on the Rank-3 free module M over the Integer Ring
|
|
2736
|
+
sage: s1 == s # ... and yields the same result as previously:
|
|
2737
|
+
True
|
|
2738
|
+
|
|
2739
|
+
The contraction can be performed on more than a single index; for
|
|
2740
|
+
instance a `2`-indices contraction of a type-`(2,1)` tensor with a
|
|
2741
|
+
type-`(1,2)` one is::
|
|
2742
|
+
|
|
2743
|
+
sage: a # a is a tensor of type-(2,1)
|
|
2744
|
+
Type-(2,1) tensor on the Rank-3 free module M over the Integer Ring
|
|
2745
|
+
sage: b = M([1,-1,2])*b ; b # a tensor of type (1,2)
|
|
2746
|
+
Type-(1,2) tensor on the Rank-3 free module M over the Integer Ring
|
|
2747
|
+
sage: s = a.contract(1,2,b,1,0) ; s # the double contraction
|
|
2748
|
+
Type-(1,1) tensor on the Rank-3 free module M over the Integer Ring
|
|
2749
|
+
sage: s[:]
|
|
2750
|
+
[ -36 30 15]
|
|
2751
|
+
[-252 210 105]
|
|
2752
|
+
[-204 170 85]
|
|
2753
|
+
sage: s == a['^.k_l']*b['^l_k.'] # the same thing in index notation
|
|
2754
|
+
True
|
|
2755
|
+
"""
|
|
2756
|
+
#
|
|
2757
|
+
# Treatment of the input
|
|
2758
|
+
#
|
|
2759
|
+
nargs = len(args)
|
|
2760
|
+
for i, arg in enumerate(args):
|
|
2761
|
+
if isinstance(arg, FreeModuleTensor):
|
|
2762
|
+
other = arg
|
|
2763
|
+
it = i
|
|
2764
|
+
break
|
|
2765
|
+
else:
|
|
2766
|
+
raise TypeError("a tensor must be provided in the argument list")
|
|
2767
|
+
if it == 0:
|
|
2768
|
+
pos1 = (self._tensor_rank - 1,)
|
|
2769
|
+
else:
|
|
2770
|
+
pos1 = args[:it]
|
|
2771
|
+
if it == nargs-1:
|
|
2772
|
+
pos2 = (0,)
|
|
2773
|
+
else:
|
|
2774
|
+
pos2 = args[it+1:]
|
|
2775
|
+
ncontr = len(pos1) # number of contractions
|
|
2776
|
+
if len(pos2) != ncontr:
|
|
2777
|
+
raise TypeError("different number of indices for the contraction")
|
|
2778
|
+
k1, l1 = self._tensor_type
|
|
2779
|
+
k2, l2 = other._tensor_type
|
|
2780
|
+
for i in range(ncontr):
|
|
2781
|
+
p1 = pos1[i]
|
|
2782
|
+
p2 = pos2[i]
|
|
2783
|
+
if p1 < k1 and p2 < k2:
|
|
2784
|
+
raise TypeError("contraction on two contravariant indices " +
|
|
2785
|
+
"not permitted")
|
|
2786
|
+
if p1 >= k1 and p2 >= k2:
|
|
2787
|
+
raise TypeError("contraction on two covariant indices " +
|
|
2788
|
+
"not permitted")
|
|
2789
|
+
#
|
|
2790
|
+
# Contraction at the component level
|
|
2791
|
+
#
|
|
2792
|
+
basis = self.common_basis(other)
|
|
2793
|
+
if basis is None:
|
|
2794
|
+
raise ValueError("no common basis for the contraction")
|
|
2795
|
+
args = pos1 + (other._components[basis],) + pos2
|
|
2796
|
+
cmp_res = self._components[basis].contract(*args)
|
|
2797
|
+
if self._tensor_rank + other._tensor_rank - 2*ncontr == 0:
|
|
2798
|
+
# Case of scalar output:
|
|
2799
|
+
return cmp_res
|
|
2800
|
+
#
|
|
2801
|
+
# Reordering of the indices to have all contravariant indices first:
|
|
2802
|
+
#
|
|
2803
|
+
nb_cov_s = 0 # Number of covariant indices of self not involved in the
|
|
2804
|
+
# contraction
|
|
2805
|
+
for pos in range(k1, k1 + l1):
|
|
2806
|
+
if pos not in pos1:
|
|
2807
|
+
nb_cov_s += 1
|
|
2808
|
+
nb_con_o = 0 # Number of contravariant indices of other not involved
|
|
2809
|
+
# in the contraction
|
|
2810
|
+
for pos in range(k2):
|
|
2811
|
+
if pos not in pos2:
|
|
2812
|
+
nb_con_o += 1
|
|
2813
|
+
if nb_cov_s != 0 and nb_con_o != 0:
|
|
2814
|
+
# some reordering is necessary:
|
|
2815
|
+
p2 = k1 + l1 - ncontr
|
|
2816
|
+
p1 = p2 - nb_cov_s
|
|
2817
|
+
p3 = p2 + nb_con_o
|
|
2818
|
+
cmp_res = cmp_res.swap_adjacent_indices(p1, p2, p3)
|
|
2819
|
+
type_res = (k1+k2-ncontr, l1+l2-ncontr)
|
|
2820
|
+
return self._fmodule.tensor_from_comp(type_res, cmp_res)
|
|
2821
|
+
|
|
2822
|
+
def symmetrize(self, *pos, **kwargs):
|
|
2823
|
+
r"""
|
|
2824
|
+
Symmetrization over some arguments.
|
|
2825
|
+
|
|
2826
|
+
INPUT:
|
|
2827
|
+
|
|
2828
|
+
- ``pos`` -- list of argument positions involved in the
|
|
2829
|
+
symmetrization (with the convention ``position=0`` for the first
|
|
2830
|
+
argument); if none, the symmetrization is performed over all the
|
|
2831
|
+
arguments
|
|
2832
|
+
- ``basis`` -- (default: ``None``) module basis with respect to which
|
|
2833
|
+
the component computation is to be performed; if none, the module's
|
|
2834
|
+
default basis is used if the tensor field has already components
|
|
2835
|
+
in it; otherwise another basis w.r.t. which the tensor has
|
|
2836
|
+
components will be picked
|
|
2837
|
+
|
|
2838
|
+
OUTPUT:
|
|
2839
|
+
|
|
2840
|
+
- the symmetrized tensor (instance of :class:`FreeModuleTensor`)
|
|
2841
|
+
|
|
2842
|
+
EXAMPLES:
|
|
2843
|
+
|
|
2844
|
+
Symmetrization of a tensor of type `(2,0)`::
|
|
2845
|
+
|
|
2846
|
+
sage: M = FiniteRankFreeModule(QQ, 3, name='M')
|
|
2847
|
+
sage: e = M.basis('e')
|
|
2848
|
+
sage: t = M.tensor((2,0))
|
|
2849
|
+
sage: t[:] = [[2,1,-3],[0,-4,5],[-1,4,2]]
|
|
2850
|
+
sage: s = t.symmetrize() ; s
|
|
2851
|
+
Type-(2,0) tensor on the 3-dimensional vector space M over the
|
|
2852
|
+
Rational Field
|
|
2853
|
+
sage: t[:], s[:]
|
|
2854
|
+
(
|
|
2855
|
+
[ 2 1 -3] [ 2 1/2 -2]
|
|
2856
|
+
[ 0 -4 5] [1/2 -4 9/2]
|
|
2857
|
+
[-1 4 2], [ -2 9/2 2]
|
|
2858
|
+
)
|
|
2859
|
+
sage: s.symmetries()
|
|
2860
|
+
symmetry: (0, 1); no antisymmetry
|
|
2861
|
+
sage: all(s[i,j] == 1/2*(t[i,j]+t[j,i]) # check:
|
|
2862
|
+
....: for i in range(3) for j in range(3))
|
|
2863
|
+
True
|
|
2864
|
+
|
|
2865
|
+
Instead of invoking the method :meth:`symmetrize`, one may use the
|
|
2866
|
+
index notation with parentheses to denote the symmetrization; it
|
|
2867
|
+
suffices to pass the indices as a string inside square brackets::
|
|
2868
|
+
|
|
2869
|
+
sage: t['(ij)']
|
|
2870
|
+
Type-(2,0) tensor on the 3-dimensional vector space M over the
|
|
2871
|
+
Rational Field
|
|
2872
|
+
sage: t['(ij)'].symmetries()
|
|
2873
|
+
symmetry: (0, 1); no antisymmetry
|
|
2874
|
+
sage: t['(ij)'] == t.symmetrize()
|
|
2875
|
+
True
|
|
2876
|
+
|
|
2877
|
+
The indices names are not significant; they can even be replaced by
|
|
2878
|
+
dots::
|
|
2879
|
+
|
|
2880
|
+
sage: t['(..)'] == t.symmetrize()
|
|
2881
|
+
True
|
|
2882
|
+
|
|
2883
|
+
The LaTeX notation can be used as well::
|
|
2884
|
+
|
|
2885
|
+
sage: t['^{(ij)}'] == t.symmetrize()
|
|
2886
|
+
True
|
|
2887
|
+
|
|
2888
|
+
Symmetrization of a tensor of type `(0,3)` on the first two arguments::
|
|
2889
|
+
|
|
2890
|
+
sage: t = M.tensor((0,3))
|
|
2891
|
+
sage: t[:] = [[[1,2,3], [-4,5,6], [7,8,-9]],
|
|
2892
|
+
....: [[10,-11,12], [13,14,-15], [16,17,18]],
|
|
2893
|
+
....: [[19,-20,-21], [-22,23,24], [25,26,-27]]]
|
|
2894
|
+
sage: s = t.symmetrize(0,1) ; s # (0,1) = the first two arguments
|
|
2895
|
+
Type-(0,3) tensor on the 3-dimensional vector space M over the
|
|
2896
|
+
Rational Field
|
|
2897
|
+
sage: s.symmetries()
|
|
2898
|
+
symmetry: (0, 1); no antisymmetry
|
|
2899
|
+
sage: s[:]
|
|
2900
|
+
[[[1, 2, 3], [3, -3, 9], [13, -6, -15]],
|
|
2901
|
+
[[3, -3, 9], [13, 14, -15], [-3, 20, 21]],
|
|
2902
|
+
[[13, -6, -15], [-3, 20, 21], [25, 26, -27]]]
|
|
2903
|
+
sage: all(s[i,j,k] == 1/2*(t[i,j,k]+t[j,i,k]) # Check:
|
|
2904
|
+
....: for i in range(3) for j in range(3) for k in range(3))
|
|
2905
|
+
True
|
|
2906
|
+
sage: s.symmetrize(0,1) == s # another test
|
|
2907
|
+
True
|
|
2908
|
+
|
|
2909
|
+
Again the index notation can be used::
|
|
2910
|
+
|
|
2911
|
+
sage: t['_(ij)k'] == t.symmetrize(0,1)
|
|
2912
|
+
True
|
|
2913
|
+
sage: t['_(..).'] == t.symmetrize(0,1) # no index name
|
|
2914
|
+
True
|
|
2915
|
+
sage: t['_{(ij)k}'] == t.symmetrize(0,1) # LaTeX notation
|
|
2916
|
+
True
|
|
2917
|
+
sage: t['_{(..).}'] == t.symmetrize(0,1) # this also allowed
|
|
2918
|
+
True
|
|
2919
|
+
|
|
2920
|
+
Symmetrization of a tensor of type `(0,3)` on the first and
|
|
2921
|
+
last arguments::
|
|
2922
|
+
|
|
2923
|
+
sage: s = t.symmetrize(0,2) ; s # (0,2) = first and last arguments
|
|
2924
|
+
Type-(0,3) tensor on the 3-dimensional vector space M over the
|
|
2925
|
+
Rational Field
|
|
2926
|
+
sage: s.symmetries()
|
|
2927
|
+
symmetry: (0, 2); no antisymmetry
|
|
2928
|
+
sage: s[:]
|
|
2929
|
+
[[[1, 6, 11], [-4, 9, -8], [7, 12, 8]],
|
|
2930
|
+
[[6, -11, -4], [9, 14, 4], [12, 17, 22]],
|
|
2931
|
+
[[11, -4, -21], [-8, 4, 24], [8, 22, -27]]]
|
|
2932
|
+
sage: all(s[i,j,k] == 1/2*(t[i,j,k]+t[k,j,i])
|
|
2933
|
+
....: for i in range(3) for j in range(3) for k in range(3))
|
|
2934
|
+
True
|
|
2935
|
+
sage: s.symmetrize(0,2) == s # another test
|
|
2936
|
+
True
|
|
2937
|
+
|
|
2938
|
+
Symmetrization of a tensor of type `(0,3)` on the last two arguments::
|
|
2939
|
+
|
|
2940
|
+
sage: s = t.symmetrize(1,2) ; s # (1,2) = the last two arguments
|
|
2941
|
+
Type-(0,3) tensor on the 3-dimensional vector space M over the
|
|
2942
|
+
Rational Field
|
|
2943
|
+
sage: s.symmetries()
|
|
2944
|
+
symmetry: (1, 2); no antisymmetry
|
|
2945
|
+
sage: s[:]
|
|
2946
|
+
[[[1, -1, 5], [-1, 5, 7], [5, 7, -9]],
|
|
2947
|
+
[[10, 1, 14], [1, 14, 1], [14, 1, 18]],
|
|
2948
|
+
[[19, -21, 2], [-21, 23, 25], [2, 25, -27]]]
|
|
2949
|
+
sage: all(s[i,j,k] == 1/2*(t[i,j,k]+t[i,k,j]) # Check:
|
|
2950
|
+
....: for i in range(3) for j in range(3) for k in range(3))
|
|
2951
|
+
True
|
|
2952
|
+
sage: s.symmetrize(1,2) == s # another test
|
|
2953
|
+
True
|
|
2954
|
+
|
|
2955
|
+
Use of the index notation::
|
|
2956
|
+
|
|
2957
|
+
sage: t['_i(jk)'] == t.symmetrize(1,2)
|
|
2958
|
+
True
|
|
2959
|
+
sage: t['_.(..)'] == t.symmetrize(1,2)
|
|
2960
|
+
True
|
|
2961
|
+
sage: t['_{i(jk)}'] == t.symmetrize(1,2) # LaTeX notation
|
|
2962
|
+
True
|
|
2963
|
+
|
|
2964
|
+
Full symmetrization of a tensor of type `(0,3)`::
|
|
2965
|
+
|
|
2966
|
+
sage: s = t.symmetrize() ; s
|
|
2967
|
+
Type-(0,3) tensor on the 3-dimensional vector space M over the
|
|
2968
|
+
Rational Field
|
|
2969
|
+
sage: s.symmetries()
|
|
2970
|
+
symmetry: (0, 1, 2); no antisymmetry
|
|
2971
|
+
sage: s[:]
|
|
2972
|
+
[[[1, 8/3, 29/3], [8/3, 7/3, 0], [29/3, 0, -5/3]],
|
|
2973
|
+
[[8/3, 7/3, 0], [7/3, 14, 25/3], [0, 25/3, 68/3]],
|
|
2974
|
+
[[29/3, 0, -5/3], [0, 25/3, 68/3], [-5/3, 68/3, -27]]]
|
|
2975
|
+
sage: all(s[i,j,k] == 1/6*(t[i,j,k]+t[i,k,j]+t[j,k,i]+t[j,i,k]+t[k,i,j]+t[k,j,i]) # Check:
|
|
2976
|
+
....: for i in range(3) for j in range(3) for k in range(3))
|
|
2977
|
+
True
|
|
2978
|
+
sage: s.symmetrize() == s # another test
|
|
2979
|
+
True
|
|
2980
|
+
|
|
2981
|
+
Index notation for the full symmetrization::
|
|
2982
|
+
|
|
2983
|
+
sage: t['_(ijk)'] == t.symmetrize()
|
|
2984
|
+
True
|
|
2985
|
+
sage: t['_{(ijk)}'] == t.symmetrize() # LaTeX notation
|
|
2986
|
+
True
|
|
2987
|
+
|
|
2988
|
+
Symmetrization can be performed only on arguments on the same type::
|
|
2989
|
+
|
|
2990
|
+
sage: t = M.tensor((1,2))
|
|
2991
|
+
sage: t[:] = [[[1,2,3], [-4,5,6], [7,8,-9]],
|
|
2992
|
+
....: [[10,-11,12], [13,14,-15], [16,17,18]],
|
|
2993
|
+
....: [[19,-20,-21], [-22,23,24], [25,26,-27]]]
|
|
2994
|
+
sage: s = t.symmetrize(0,1)
|
|
2995
|
+
Traceback (most recent call last):
|
|
2996
|
+
...
|
|
2997
|
+
TypeError: 0 is a contravariant position, while 1 is a covariant position;
|
|
2998
|
+
symmetrization is meaningful only on tensor arguments of the same type
|
|
2999
|
+
sage: s = t.symmetrize(1,2) # OK: both 1 and 2 are covariant positions
|
|
3000
|
+
|
|
3001
|
+
The order of positions does not matter::
|
|
3002
|
+
|
|
3003
|
+
sage: t.symmetrize(2,1) == t.symmetrize(1,2)
|
|
3004
|
+
True
|
|
3005
|
+
|
|
3006
|
+
Use of the index notation::
|
|
3007
|
+
|
|
3008
|
+
sage: t['^i_(jk)'] == t.symmetrize(1,2)
|
|
3009
|
+
True
|
|
3010
|
+
sage: t['^._(..)'] == t.symmetrize(1,2)
|
|
3011
|
+
True
|
|
3012
|
+
|
|
3013
|
+
The character ``^`` can be skipped, the character ``_`` being
|
|
3014
|
+
sufficient to separate contravariant indices from covariant ones::
|
|
3015
|
+
|
|
3016
|
+
sage: t['i_(jk)'] == t.symmetrize(1,2)
|
|
3017
|
+
True
|
|
3018
|
+
|
|
3019
|
+
The LaTeX notation can be employed::
|
|
3020
|
+
|
|
3021
|
+
sage: t['^{i}_{(jk)}'] == t.symmetrize(1,2)
|
|
3022
|
+
True
|
|
3023
|
+
"""
|
|
3024
|
+
if not pos:
|
|
3025
|
+
pos = range(self._tensor_rank)
|
|
3026
|
+
# check whether the symmetrization is possible:
|
|
3027
|
+
pos_cov = self._tensor_type[0] # first covariant position
|
|
3028
|
+
pos0 = pos[0]
|
|
3029
|
+
if pos0 < pos_cov: # pos0 is a contravariant position
|
|
3030
|
+
for k in range(1,len(pos)):
|
|
3031
|
+
if pos[k] >= pos_cov:
|
|
3032
|
+
raise TypeError(
|
|
3033
|
+
str(pos[0]) + " is a contravariant position, while " +
|
|
3034
|
+
str(pos[k]) + " is a covariant position; \n"
|
|
3035
|
+
"symmetrization is meaningful only on tensor " +
|
|
3036
|
+
"arguments of the same type")
|
|
3037
|
+
else: # pos0 is a covariant position
|
|
3038
|
+
for k in range(1,len(pos)):
|
|
3039
|
+
if pos[k] < pos_cov:
|
|
3040
|
+
raise TypeError(
|
|
3041
|
+
str(pos[0]) + " is a covariant position, while " +
|
|
3042
|
+
str(pos[k]) + " is a contravariant position; \n"
|
|
3043
|
+
"symmetrization is meaningful only on tensor " +
|
|
3044
|
+
"arguments of the same type")
|
|
3045
|
+
if 'basis' in kwargs:
|
|
3046
|
+
basis = kwargs['basis']
|
|
3047
|
+
else:
|
|
3048
|
+
basis = self.pick_a_basis()
|
|
3049
|
+
res_comp = self._components[basis].symmetrize(*pos)
|
|
3050
|
+
return self._fmodule.tensor_from_comp(self._tensor_type, res_comp)
|
|
3051
|
+
|
|
3052
|
+
def antisymmetrize(self, *pos, **kwargs):
|
|
3053
|
+
r"""
|
|
3054
|
+
Antisymmetrization over some arguments.
|
|
3055
|
+
|
|
3056
|
+
INPUT:
|
|
3057
|
+
|
|
3058
|
+
- ``pos`` -- list of argument positions involved in the
|
|
3059
|
+
antisymmetrization (with the convention ``position=0`` for the first
|
|
3060
|
+
argument); if none, the antisymmetrization is performed over all the
|
|
3061
|
+
arguments
|
|
3062
|
+
- ``basis`` -- (default: ``None``) module basis with respect to which
|
|
3063
|
+
the component computation is to be performed; if none, the module's
|
|
3064
|
+
default basis is used if the tensor field has already components
|
|
3065
|
+
in it; otherwise another basis w.r.t. which the tensor has
|
|
3066
|
+
components will be picked
|
|
3067
|
+
|
|
3068
|
+
OUTPUT:
|
|
3069
|
+
|
|
3070
|
+
- the antisymmetrized tensor (instance of :class:`FreeModuleTensor`)
|
|
3071
|
+
|
|
3072
|
+
EXAMPLES:
|
|
3073
|
+
|
|
3074
|
+
Antisymmetrization of a tensor of type `(2,0)`::
|
|
3075
|
+
|
|
3076
|
+
sage: M = FiniteRankFreeModule(QQ, 3, name='M')
|
|
3077
|
+
sage: e = M.basis('e')
|
|
3078
|
+
sage: t = M.tensor((2,0))
|
|
3079
|
+
sage: t[:] = [[1,-2,3], [4,5,6], [7,8,-9]]
|
|
3080
|
+
sage: s = t.antisymmetrize() ; s
|
|
3081
|
+
Alternating contravariant tensor of degree 2 on the 3-dimensional
|
|
3082
|
+
vector space M over the Rational Field
|
|
3083
|
+
sage: s.symmetries()
|
|
3084
|
+
no symmetry; antisymmetry: (0, 1)
|
|
3085
|
+
sage: t[:], s[:]
|
|
3086
|
+
(
|
|
3087
|
+
[ 1 -2 3] [ 0 -3 -2]
|
|
3088
|
+
[ 4 5 6] [ 3 0 -1]
|
|
3089
|
+
[ 7 8 -9], [ 2 1 0]
|
|
3090
|
+
)
|
|
3091
|
+
sage: all(s[i,j] == 1/2*(t[i,j]-t[j,i]) # Check:
|
|
3092
|
+
....: for i in range(3) for j in range(3))
|
|
3093
|
+
True
|
|
3094
|
+
sage: s.antisymmetrize() == s # another test
|
|
3095
|
+
True
|
|
3096
|
+
sage: t.antisymmetrize() == t.antisymmetrize(0,1)
|
|
3097
|
+
True
|
|
3098
|
+
|
|
3099
|
+
Antisymmetrization of a tensor of type `(0, 3)` over the first two
|
|
3100
|
+
arguments::
|
|
3101
|
+
|
|
3102
|
+
sage: t = M.tensor((0,3))
|
|
3103
|
+
sage: t[:] = [[[1,2,3], [-4,5,6], [7,8,-9]],
|
|
3104
|
+
....: [[10,-11,12], [13,14,-15], [16,17,18]],
|
|
3105
|
+
....: [[19,-20,-21], [-22,23,24], [25,26,-27]]]
|
|
3106
|
+
sage: s = t.antisymmetrize(0,1) ; s # (0,1) = the first two arguments
|
|
3107
|
+
Type-(0,3) tensor on the 3-dimensional vector space M over the
|
|
3108
|
+
Rational Field
|
|
3109
|
+
sage: s.symmetries()
|
|
3110
|
+
no symmetry; antisymmetry: (0, 1)
|
|
3111
|
+
sage: s[:]
|
|
3112
|
+
[[[0, 0, 0], [-7, 8, -3], [-6, 14, 6]],
|
|
3113
|
+
[[7, -8, 3], [0, 0, 0], [19, -3, -3]],
|
|
3114
|
+
[[6, -14, -6], [-19, 3, 3], [0, 0, 0]]]
|
|
3115
|
+
sage: all(s[i,j,k] == 1/2*(t[i,j,k]-t[j,i,k]) # Check:
|
|
3116
|
+
....: for i in range(3) for j in range(3) for k in range(3))
|
|
3117
|
+
True
|
|
3118
|
+
sage: s.antisymmetrize(0,1) == s # another test
|
|
3119
|
+
True
|
|
3120
|
+
sage: s.symmetrize(0,1) == 0 # of course
|
|
3121
|
+
True
|
|
3122
|
+
|
|
3123
|
+
Instead of invoking the method :meth:`antisymmetrize`, one can use
|
|
3124
|
+
the index notation with square brackets denoting the
|
|
3125
|
+
antisymmetrization; it suffices to pass the indices as a string
|
|
3126
|
+
inside square brackets::
|
|
3127
|
+
|
|
3128
|
+
sage: s1 = t['_[ij]k'] ; s1
|
|
3129
|
+
Type-(0,3) tensor on the 3-dimensional vector space M over the
|
|
3130
|
+
Rational Field
|
|
3131
|
+
sage: s1.symmetries()
|
|
3132
|
+
no symmetry; antisymmetry: (0, 1)
|
|
3133
|
+
sage: s1 == s
|
|
3134
|
+
True
|
|
3135
|
+
|
|
3136
|
+
The LaTeX notation is recognized::
|
|
3137
|
+
|
|
3138
|
+
sage: t['_{[ij]k}'] == s
|
|
3139
|
+
True
|
|
3140
|
+
|
|
3141
|
+
Note that in the index notation, the name of the indices is irrelevant;
|
|
3142
|
+
they can even be replaced by dots::
|
|
3143
|
+
|
|
3144
|
+
sage: t['_[..].'] == s
|
|
3145
|
+
True
|
|
3146
|
+
|
|
3147
|
+
Antisymmetrization of a tensor of type `(0,3)` over the first and last
|
|
3148
|
+
arguments::
|
|
3149
|
+
|
|
3150
|
+
sage: s = t.antisymmetrize(0,2) ; s # (0,2) = first and last arguments
|
|
3151
|
+
Type-(0,3) tensor on the 3-dimensional vector space M over the
|
|
3152
|
+
Rational Field
|
|
3153
|
+
sage: s.symmetries()
|
|
3154
|
+
no symmetry; antisymmetry: (0, 2)
|
|
3155
|
+
sage: s[:]
|
|
3156
|
+
[[[0, -4, -8], [0, -4, 14], [0, -4, -17]],
|
|
3157
|
+
[[4, 0, 16], [4, 0, -19], [4, 0, -4]],
|
|
3158
|
+
[[8, -16, 0], [-14, 19, 0], [17, 4, 0]]]
|
|
3159
|
+
sage: all(s[i,j,k] == 1/2*(t[i,j,k]-t[k,j,i]) # Check:
|
|
3160
|
+
....: for i in range(3) for j in range(3) for k in range(3))
|
|
3161
|
+
True
|
|
3162
|
+
sage: s.antisymmetrize(0,2) == s # another test
|
|
3163
|
+
True
|
|
3164
|
+
sage: s.symmetrize(0,2) == 0 # of course
|
|
3165
|
+
True
|
|
3166
|
+
sage: s.symmetrize(0,1) == 0 # no reason for this to hold
|
|
3167
|
+
False
|
|
3168
|
+
|
|
3169
|
+
Antisymmetrization of a tensor of type `(0,3)` over the last two
|
|
3170
|
+
arguments::
|
|
3171
|
+
|
|
3172
|
+
sage: s = t.antisymmetrize(1,2) ; s # (1,2) = the last two arguments
|
|
3173
|
+
Type-(0,3) tensor on the 3-dimensional vector space M over the
|
|
3174
|
+
Rational Field
|
|
3175
|
+
sage: s.symmetries()
|
|
3176
|
+
no symmetry; antisymmetry: (1, 2)
|
|
3177
|
+
sage: s[:]
|
|
3178
|
+
[[[0, 3, -2], [-3, 0, -1], [2, 1, 0]],
|
|
3179
|
+
[[0, -12, -2], [12, 0, -16], [2, 16, 0]],
|
|
3180
|
+
[[0, 1, -23], [-1, 0, -1], [23, 1, 0]]]
|
|
3181
|
+
sage: all(s[i,j,k] == 1/2*(t[i,j,k]-t[i,k,j]) # Check:
|
|
3182
|
+
....: for i in range(3) for j in range(3) for k in range(3))
|
|
3183
|
+
True
|
|
3184
|
+
sage: s.antisymmetrize(1,2) == s # another test
|
|
3185
|
+
True
|
|
3186
|
+
sage: s.symmetrize(1,2) == 0 # of course
|
|
3187
|
+
True
|
|
3188
|
+
|
|
3189
|
+
The index notation can be used instead of the explicit call to
|
|
3190
|
+
:meth:`antisymmetrize`::
|
|
3191
|
+
|
|
3192
|
+
sage: t['_i[jk]'] == t.antisymmetrize(1,2)
|
|
3193
|
+
True
|
|
3194
|
+
|
|
3195
|
+
Full antisymmetrization of a tensor of type `(0,3)`::
|
|
3196
|
+
|
|
3197
|
+
sage: s = t.antisymmetrize() ; s
|
|
3198
|
+
Alternating form of degree 3 on the 3-dimensional vector space M
|
|
3199
|
+
over the Rational Field
|
|
3200
|
+
sage: s.symmetries()
|
|
3201
|
+
no symmetry; antisymmetry: (0, 1, 2)
|
|
3202
|
+
sage: s[:]
|
|
3203
|
+
[[[0, 0, 0], [0, 0, 2/3], [0, -2/3, 0]],
|
|
3204
|
+
[[0, 0, -2/3], [0, 0, 0], [2/3, 0, 0]],
|
|
3205
|
+
[[0, 2/3, 0], [-2/3, 0, 0], [0, 0, 0]]]
|
|
3206
|
+
sage: all(s[i,j,k] == 1/6*(t[i,j,k]-t[i,k,j]+t[j,k,i]-t[j,i,k]
|
|
3207
|
+
....: +t[k,i,j]-t[k,j,i])
|
|
3208
|
+
....: for i in range(3) for j in range(3) for k in range(3))
|
|
3209
|
+
True
|
|
3210
|
+
sage: s.antisymmetrize() == s # another test
|
|
3211
|
+
True
|
|
3212
|
+
sage: s.symmetrize(0,1) == 0 # of course
|
|
3213
|
+
True
|
|
3214
|
+
sage: s.symmetrize(0,2) == 0 # of course
|
|
3215
|
+
True
|
|
3216
|
+
sage: s.symmetrize(1,2) == 0 # of course
|
|
3217
|
+
True
|
|
3218
|
+
sage: t.antisymmetrize() == t.antisymmetrize(0,1,2)
|
|
3219
|
+
True
|
|
3220
|
+
|
|
3221
|
+
The index notation can be used instead of the explicit call to
|
|
3222
|
+
:meth:`antisymmetrize`::
|
|
3223
|
+
|
|
3224
|
+
sage: t['_[ijk]'] == t.antisymmetrize()
|
|
3225
|
+
True
|
|
3226
|
+
sage: t['_[abc]'] == t.antisymmetrize()
|
|
3227
|
+
True
|
|
3228
|
+
sage: t['_[...]'] == t.antisymmetrize()
|
|
3229
|
+
True
|
|
3230
|
+
sage: t['_{[ijk]}'] == t.antisymmetrize() # LaTeX notation
|
|
3231
|
+
True
|
|
3232
|
+
|
|
3233
|
+
Antisymmetrization can be performed only on arguments on the same type::
|
|
3234
|
+
|
|
3235
|
+
sage: t = M.tensor((1,2))
|
|
3236
|
+
sage: t[:] = [[[1,2,3], [-4,5,6], [7,8,-9]],
|
|
3237
|
+
....: [[10,-11,12], [13,14,-15], [16,17,18]],
|
|
3238
|
+
....: [[19,-20,-21], [-22,23,24], [25,26,-27]]]
|
|
3239
|
+
sage: s = t.antisymmetrize(0,1)
|
|
3240
|
+
Traceback (most recent call last):
|
|
3241
|
+
...
|
|
3242
|
+
TypeError: 0 is a contravariant position, while 1 is a covariant position;
|
|
3243
|
+
antisymmetrization is meaningful only on tensor arguments of the same type
|
|
3244
|
+
sage: s = t.antisymmetrize(1,2) # OK: both 1 and 2 are covariant positions
|
|
3245
|
+
|
|
3246
|
+
The order of positions does not matter::
|
|
3247
|
+
|
|
3248
|
+
sage: t.antisymmetrize(2,1) == t.antisymmetrize(1,2)
|
|
3249
|
+
True
|
|
3250
|
+
|
|
3251
|
+
Again, the index notation can be used::
|
|
3252
|
+
|
|
3253
|
+
sage: t['^i_[jk]'] == t.antisymmetrize(1,2)
|
|
3254
|
+
True
|
|
3255
|
+
sage: t['^i_{[jk]}'] == t.antisymmetrize(1,2) # LaTeX notation
|
|
3256
|
+
True
|
|
3257
|
+
|
|
3258
|
+
The character '^' can be skipped::
|
|
3259
|
+
|
|
3260
|
+
sage: t['i_[jk]'] == t.antisymmetrize(1,2)
|
|
3261
|
+
True
|
|
3262
|
+
"""
|
|
3263
|
+
if not pos:
|
|
3264
|
+
pos = range(self._tensor_rank)
|
|
3265
|
+
# check whether the antisymmetrization is possible:
|
|
3266
|
+
pos_cov = self._tensor_type[0] # first covariant position
|
|
3267
|
+
pos0 = pos[0]
|
|
3268
|
+
if pos0 < pos_cov: # pos0 is a contravariant position
|
|
3269
|
+
for k in range(1,len(pos)):
|
|
3270
|
+
if pos[k] >= pos_cov:
|
|
3271
|
+
raise TypeError(
|
|
3272
|
+
str(pos[0]) + " is a contravariant position, while " +
|
|
3273
|
+
str(pos[k]) + " is a covariant position; \n"
|
|
3274
|
+
"antisymmetrization is meaningful only on tensor " +
|
|
3275
|
+
"arguments of the same type")
|
|
3276
|
+
else: # pos0 is a covariant position
|
|
3277
|
+
for k in range(1,len(pos)):
|
|
3278
|
+
if pos[k] < pos_cov:
|
|
3279
|
+
raise TypeError(
|
|
3280
|
+
str(pos[0]) + " is a covariant position, while " +
|
|
3281
|
+
str(pos[k]) + " is a contravariant position; \n"
|
|
3282
|
+
"antisymmetrization is meaningful only on tensor " +
|
|
3283
|
+
"arguments of the same type")
|
|
3284
|
+
if 'basis' in kwargs:
|
|
3285
|
+
basis = kwargs['basis']
|
|
3286
|
+
else:
|
|
3287
|
+
basis = self.pick_a_basis()
|
|
3288
|
+
res_comp = self._components[basis].antisymmetrize(*pos)
|
|
3289
|
+
return self._fmodule.tensor_from_comp(self._tensor_type, res_comp)
|