passagemath-modules 10.6.31rc3__cp314-cp314-musllinux_1_2_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-modules might be problematic. Click here for more details.
- passagemath_modules-10.6.31rc3.dist-info/METADATA +281 -0
- passagemath_modules-10.6.31rc3.dist-info/RECORD +808 -0
- passagemath_modules-10.6.31rc3.dist-info/WHEEL +5 -0
- passagemath_modules-10.6.31rc3.dist-info/top_level.txt +2 -0
- passagemath_modules.libs/libgcc_s-0cd532bd.so.1 +0 -0
- passagemath_modules.libs/libgfortran-2c33b284.so.5.0.0 +0 -0
- passagemath_modules.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
- passagemath_modules.libs/libgsl-42cda06f.so.28.0.0 +0 -0
- passagemath_modules.libs/libmpc-d8ebe4b5.so.3.3.1 +0 -0
- passagemath_modules.libs/libmpfr-aaecbfc0.so.6.2.1 +0 -0
- passagemath_modules.libs/libopenblasp-r0-905cb27d.3.29.so +0 -0
- passagemath_modules.libs/libquadmath-bb76a5fc.so.0.0.0 +0 -0
- sage/algebras/all__sagemath_modules.py +20 -0
- sage/algebras/catalog.py +148 -0
- sage/algebras/clifford_algebra.py +3107 -0
- sage/algebras/clifford_algebra_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/algebras/clifford_algebra_element.pxd +16 -0
- sage/algebras/clifford_algebra_element.pyx +997 -0
- sage/algebras/commutative_dga.py +4252 -0
- sage/algebras/exterior_algebra_groebner.cpython-314-x86_64-linux-musl.so +0 -0
- sage/algebras/exterior_algebra_groebner.pxd +55 -0
- sage/algebras/exterior_algebra_groebner.pyx +727 -0
- sage/algebras/finite_dimensional_algebras/all.py +2 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +1029 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pxd +12 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx +706 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py +196 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py +255 -0
- sage/algebras/finite_gca.py +528 -0
- sage/algebras/group_algebra.py +232 -0
- sage/algebras/lie_algebras/abelian.py +197 -0
- sage/algebras/lie_algebras/affine_lie_algebra.py +1213 -0
- sage/algebras/lie_algebras/all.py +25 -0
- sage/algebras/lie_algebras/all__sagemath_modules.py +1 -0
- sage/algebras/lie_algebras/bch.py +177 -0
- sage/algebras/lie_algebras/bgg_dual_module.py +1184 -0
- sage/algebras/lie_algebras/bgg_resolution.py +232 -0
- sage/algebras/lie_algebras/center_uea.py +767 -0
- sage/algebras/lie_algebras/classical_lie_algebra.py +2516 -0
- sage/algebras/lie_algebras/examples.py +683 -0
- sage/algebras/lie_algebras/free_lie_algebra.py +973 -0
- sage/algebras/lie_algebras/heisenberg.py +820 -0
- sage/algebras/lie_algebras/lie_algebra.py +1562 -0
- sage/algebras/lie_algebras/lie_algebra_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/algebras/lie_algebras/lie_algebra_element.pxd +68 -0
- sage/algebras/lie_algebras/lie_algebra_element.pyx +2122 -0
- sage/algebras/lie_algebras/morphism.py +661 -0
- sage/algebras/lie_algebras/nilpotent_lie_algebra.py +457 -0
- sage/algebras/lie_algebras/onsager.py +1324 -0
- sage/algebras/lie_algebras/poincare_birkhoff_witt.py +816 -0
- sage/algebras/lie_algebras/quotient.py +462 -0
- sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py +355 -0
- sage/algebras/lie_algebras/representation.py +1040 -0
- sage/algebras/lie_algebras/structure_coefficients.py +459 -0
- sage/algebras/lie_algebras/subalgebra.py +967 -0
- sage/algebras/lie_algebras/symplectic_derivation.py +289 -0
- sage/algebras/lie_algebras/verma_module.py +1630 -0
- sage/algebras/lie_algebras/virasoro.py +1186 -0
- sage/algebras/octonion_algebra.cpython-314-x86_64-linux-musl.so +0 -0
- sage/algebras/octonion_algebra.pxd +20 -0
- sage/algebras/octonion_algebra.pyx +987 -0
- sage/algebras/orlik_solomon.py +907 -0
- sage/algebras/orlik_terao.py +779 -0
- sage/algebras/steenrod/all.py +7 -0
- sage/algebras/steenrod/steenrod_algebra.py +4258 -0
- sage/algebras/steenrod/steenrod_algebra_bases.py +1179 -0
- sage/algebras/steenrod/steenrod_algebra_misc.py +1167 -0
- sage/algebras/steenrod/steenrod_algebra_mult.py +954 -0
- sage/algebras/weyl_algebra.py +1126 -0
- sage/all__sagemath_modules.py +62 -0
- sage/calculus/all__sagemath_modules.py +19 -0
- sage/calculus/expr.py +205 -0
- sage/calculus/integration.cpython-314-x86_64-linux-musl.so +0 -0
- sage/calculus/integration.pyx +698 -0
- sage/calculus/interpolation.cpython-314-x86_64-linux-musl.so +0 -0
- sage/calculus/interpolation.pxd +13 -0
- sage/calculus/interpolation.pyx +387 -0
- sage/calculus/interpolators.cpython-314-x86_64-linux-musl.so +0 -0
- sage/calculus/interpolators.pyx +326 -0
- sage/calculus/ode.cpython-314-x86_64-linux-musl.so +0 -0
- sage/calculus/ode.pxd +5 -0
- sage/calculus/ode.pyx +610 -0
- sage/calculus/riemann.cpython-314-x86_64-linux-musl.so +0 -0
- sage/calculus/riemann.pyx +1521 -0
- sage/calculus/test_sympy.py +201 -0
- sage/calculus/transforms/all.py +7 -0
- sage/calculus/transforms/dft.py +844 -0
- sage/calculus/transforms/dwt.cpython-314-x86_64-linux-musl.so +0 -0
- sage/calculus/transforms/dwt.pxd +7 -0
- sage/calculus/transforms/dwt.pyx +160 -0
- sage/calculus/transforms/fft.cpython-314-x86_64-linux-musl.so +0 -0
- sage/calculus/transforms/fft.pxd +12 -0
- sage/calculus/transforms/fft.pyx +487 -0
- sage/calculus/wester.py +662 -0
- sage/coding/abstract_code.py +1108 -0
- sage/coding/ag_code.py +868 -0
- sage/coding/ag_code_decoders.cpython-314-x86_64-linux-musl.so +0 -0
- sage/coding/ag_code_decoders.pyx +2639 -0
- sage/coding/all.py +15 -0
- sage/coding/bch_code.py +494 -0
- sage/coding/binary_code.cpython-314-x86_64-linux-musl.so +0 -0
- sage/coding/binary_code.pxd +124 -0
- sage/coding/binary_code.pyx +4139 -0
- sage/coding/bounds_catalog.py +43 -0
- sage/coding/channel.py +819 -0
- sage/coding/channels_catalog.py +29 -0
- sage/coding/code_bounds.py +755 -0
- sage/coding/code_constructions.py +804 -0
- sage/coding/codes_catalog.py +111 -0
- sage/coding/cyclic_code.py +1329 -0
- sage/coding/databases.py +316 -0
- sage/coding/decoder.py +373 -0
- sage/coding/decoders_catalog.py +88 -0
- sage/coding/delsarte_bounds.py +709 -0
- sage/coding/encoder.py +390 -0
- sage/coding/encoders_catalog.py +64 -0
- sage/coding/extended_code.py +468 -0
- sage/coding/gabidulin_code.py +1058 -0
- sage/coding/golay_code.py +404 -0
- sage/coding/goppa_code.py +441 -0
- sage/coding/grs_code.py +2371 -0
- sage/coding/guava.py +107 -0
- sage/coding/guruswami_sudan/all.py +1 -0
- sage/coding/guruswami_sudan/gs_decoder.py +897 -0
- sage/coding/guruswami_sudan/interpolation.py +409 -0
- sage/coding/guruswami_sudan/utils.py +176 -0
- sage/coding/hamming_code.py +176 -0
- sage/coding/information_set_decoder.py +1032 -0
- sage/coding/kasami_codes.cpython-314-x86_64-linux-musl.so +0 -0
- sage/coding/kasami_codes.pyx +351 -0
- sage/coding/linear_code.py +3067 -0
- sage/coding/linear_code_no_metric.py +1354 -0
- sage/coding/linear_rank_metric.py +961 -0
- sage/coding/parity_check_code.py +353 -0
- sage/coding/punctured_code.py +719 -0
- sage/coding/reed_muller_code.py +999 -0
- sage/coding/self_dual_codes.py +942 -0
- sage/coding/source_coding/all.py +2 -0
- sage/coding/source_coding/huffman.py +553 -0
- sage/coding/subfield_subcode.py +423 -0
- sage/coding/two_weight_db.py +399 -0
- sage/combinat/all__sagemath_modules.py +7 -0
- sage/combinat/cartesian_product.py +347 -0
- sage/combinat/family.py +11 -0
- sage/combinat/free_module.py +1977 -0
- sage/combinat/root_system/all.py +147 -0
- sage/combinat/root_system/ambient_space.py +527 -0
- sage/combinat/root_system/associahedron.py +471 -0
- sage/combinat/root_system/braid_move_calculator.py +143 -0
- sage/combinat/root_system/braid_orbit.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/root_system/braid_orbit.pyx +144 -0
- sage/combinat/root_system/branching_rules.py +2301 -0
- sage/combinat/root_system/cartan_matrix.py +1245 -0
- sage/combinat/root_system/cartan_type.py +3069 -0
- sage/combinat/root_system/coxeter_group.py +162 -0
- sage/combinat/root_system/coxeter_matrix.py +1261 -0
- sage/combinat/root_system/coxeter_type.py +681 -0
- sage/combinat/root_system/dynkin_diagram.py +900 -0
- sage/combinat/root_system/extended_affine_weyl_group.py +2993 -0
- sage/combinat/root_system/fundamental_group.py +795 -0
- sage/combinat/root_system/hecke_algebra_representation.py +1203 -0
- sage/combinat/root_system/integrable_representations.py +1227 -0
- sage/combinat/root_system/non_symmetric_macdonald_polynomials.py +1965 -0
- sage/combinat/root_system/pieri_factors.py +1147 -0
- sage/combinat/root_system/plot.py +1615 -0
- sage/combinat/root_system/root_lattice_realization_algebras.py +1214 -0
- sage/combinat/root_system/root_lattice_realizations.py +4628 -0
- sage/combinat/root_system/root_space.py +487 -0
- sage/combinat/root_system/root_system.py +882 -0
- sage/combinat/root_system/type_A.py +348 -0
- sage/combinat/root_system/type_A_affine.py +227 -0
- sage/combinat/root_system/type_A_infinity.py +241 -0
- sage/combinat/root_system/type_B.py +347 -0
- sage/combinat/root_system/type_BC_affine.py +287 -0
- sage/combinat/root_system/type_B_affine.py +216 -0
- sage/combinat/root_system/type_C.py +317 -0
- sage/combinat/root_system/type_C_affine.py +188 -0
- sage/combinat/root_system/type_D.py +357 -0
- sage/combinat/root_system/type_D_affine.py +208 -0
- sage/combinat/root_system/type_E.py +641 -0
- sage/combinat/root_system/type_E_affine.py +231 -0
- sage/combinat/root_system/type_F.py +387 -0
- sage/combinat/root_system/type_F_affine.py +137 -0
- sage/combinat/root_system/type_G.py +293 -0
- sage/combinat/root_system/type_G_affine.py +132 -0
- sage/combinat/root_system/type_H.py +105 -0
- sage/combinat/root_system/type_I.py +110 -0
- sage/combinat/root_system/type_Q.py +150 -0
- sage/combinat/root_system/type_affine.py +509 -0
- sage/combinat/root_system/type_dual.py +704 -0
- sage/combinat/root_system/type_folded.py +301 -0
- sage/combinat/root_system/type_marked.py +748 -0
- sage/combinat/root_system/type_reducible.py +601 -0
- sage/combinat/root_system/type_relabel.py +730 -0
- sage/combinat/root_system/type_super_A.py +837 -0
- sage/combinat/root_system/weight_lattice_realizations.py +1188 -0
- sage/combinat/root_system/weight_space.py +639 -0
- sage/combinat/root_system/weyl_characters.py +2238 -0
- sage/crypto/__init__.py +4 -0
- sage/crypto/all.py +28 -0
- sage/crypto/block_cipher/all.py +7 -0
- sage/crypto/block_cipher/des.py +1065 -0
- sage/crypto/block_cipher/miniaes.py +2171 -0
- sage/crypto/block_cipher/present.py +909 -0
- sage/crypto/block_cipher/sdes.py +1527 -0
- sage/crypto/boolean_function.cpython-314-x86_64-linux-musl.so +0 -0
- sage/crypto/boolean_function.pxd +10 -0
- sage/crypto/boolean_function.pyx +1487 -0
- sage/crypto/cipher.py +78 -0
- sage/crypto/classical.py +3668 -0
- sage/crypto/classical_cipher.py +569 -0
- sage/crypto/cryptosystem.py +387 -0
- sage/crypto/key_exchange/all.py +7 -0
- sage/crypto/key_exchange/catalog.py +24 -0
- sage/crypto/key_exchange/diffie_hellman.py +323 -0
- sage/crypto/key_exchange/key_exchange_scheme.py +107 -0
- sage/crypto/lattice.py +312 -0
- sage/crypto/lfsr.py +295 -0
- sage/crypto/lwe.py +840 -0
- sage/crypto/mq/__init__.py +4 -0
- sage/crypto/mq/mpolynomialsystemgenerator.py +204 -0
- sage/crypto/mq/rijndael_gf.py +2345 -0
- sage/crypto/mq/sbox.py +7 -0
- sage/crypto/mq/sr.py +3344 -0
- sage/crypto/public_key/all.py +5 -0
- sage/crypto/public_key/blum_goldwasser.py +776 -0
- sage/crypto/sbox.cpython-314-x86_64-linux-musl.so +0 -0
- sage/crypto/sbox.pyx +2090 -0
- sage/crypto/sboxes.py +2090 -0
- sage/crypto/stream.py +390 -0
- sage/crypto/stream_cipher.py +297 -0
- sage/crypto/util.py +519 -0
- sage/ext/all__sagemath_modules.py +1 -0
- sage/ext/interpreters/__init__.py +1 -0
- sage/ext/interpreters/all__sagemath_modules.py +2 -0
- sage/ext/interpreters/wrapper_cc.cpython-314-x86_64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_cc.pxd +30 -0
- sage/ext/interpreters/wrapper_cc.pyx +252 -0
- sage/ext/interpreters/wrapper_cdf.cpython-314-x86_64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_cdf.pxd +26 -0
- sage/ext/interpreters/wrapper_cdf.pyx +245 -0
- sage/ext/interpreters/wrapper_rdf.cpython-314-x86_64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_rdf.pxd +23 -0
- sage/ext/interpreters/wrapper_rdf.pyx +221 -0
- sage/ext/interpreters/wrapper_rr.cpython-314-x86_64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_rr.pxd +28 -0
- sage/ext/interpreters/wrapper_rr.pyx +335 -0
- sage/geometry/all__sagemath_modules.py +5 -0
- sage/geometry/toric_lattice.py +1745 -0
- sage/geometry/toric_lattice_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/toric_lattice_element.pyx +432 -0
- sage/groups/abelian_gps/abelian_group.py +1925 -0
- sage/groups/abelian_gps/abelian_group_element.py +164 -0
- sage/groups/abelian_gps/all__sagemath_modules.py +5 -0
- sage/groups/abelian_gps/dual_abelian_group.py +421 -0
- sage/groups/abelian_gps/dual_abelian_group_element.py +179 -0
- sage/groups/abelian_gps/element_base.py +341 -0
- sage/groups/abelian_gps/values.py +488 -0
- sage/groups/additive_abelian/additive_abelian_group.py +476 -0
- sage/groups/additive_abelian/additive_abelian_wrapper.py +857 -0
- sage/groups/additive_abelian/all.py +4 -0
- sage/groups/additive_abelian/qmodnz.py +231 -0
- sage/groups/additive_abelian/qmodnz_element.py +349 -0
- sage/groups/affine_gps/affine_group.py +535 -0
- sage/groups/affine_gps/all.py +1 -0
- sage/groups/affine_gps/catalog.py +17 -0
- sage/groups/affine_gps/euclidean_group.py +246 -0
- sage/groups/affine_gps/group_element.py +562 -0
- sage/groups/all__sagemath_modules.py +12 -0
- sage/groups/galois_group.py +479 -0
- sage/groups/matrix_gps/all.py +4 -0
- sage/groups/matrix_gps/all__sagemath_modules.py +13 -0
- sage/groups/matrix_gps/catalog.py +26 -0
- sage/groups/matrix_gps/coxeter_group.py +927 -0
- sage/groups/matrix_gps/finitely_generated.py +487 -0
- sage/groups/matrix_gps/group_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/groups/matrix_gps/group_element.pxd +11 -0
- sage/groups/matrix_gps/group_element.pyx +431 -0
- sage/groups/matrix_gps/linear.py +440 -0
- sage/groups/matrix_gps/matrix_group.py +617 -0
- sage/groups/matrix_gps/named_group.py +296 -0
- sage/groups/matrix_gps/orthogonal.py +544 -0
- sage/groups/matrix_gps/symplectic.py +251 -0
- sage/groups/matrix_gps/unitary.py +436 -0
- sage/groups/misc_gps/all__sagemath_modules.py +1 -0
- sage/groups/misc_gps/argument_groups.py +1905 -0
- sage/groups/misc_gps/imaginary_groups.py +479 -0
- sage/groups/perm_gps/all__sagemath_modules.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_modules.py +1 -0
- sage/groups/perm_gps/partn_ref/refinement_binary.cpython-314-x86_64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_binary.pxd +41 -0
- sage/groups/perm_gps/partn_ref/refinement_binary.pyx +1167 -0
- sage/groups/perm_gps/partn_ref/refinement_matrices.cpython-314-x86_64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_matrices.pxd +31 -0
- sage/groups/perm_gps/partn_ref/refinement_matrices.pyx +385 -0
- sage/homology/algebraic_topological_model.py +595 -0
- sage/homology/all.py +2 -0
- sage/homology/all__sagemath_modules.py +8 -0
- sage/homology/chain_complex.py +2148 -0
- sage/homology/chain_complex_homspace.py +165 -0
- sage/homology/chain_complex_morphism.py +629 -0
- sage/homology/chain_homotopy.py +604 -0
- sage/homology/chains.py +653 -0
- sage/homology/free_resolution.py +923 -0
- sage/homology/graded_resolution.py +567 -0
- sage/homology/hochschild_complex.py +756 -0
- sage/homology/homology_group.py +188 -0
- sage/homology/homology_morphism.py +422 -0
- sage/homology/homology_vector_space_with_basis.py +1454 -0
- sage/homology/koszul_complex.py +169 -0
- sage/homology/matrix_utils.py +205 -0
- sage/libs/all__sagemath_modules.py +1 -0
- sage/libs/gsl/__init__.py +1 -0
- sage/libs/gsl/airy.pxd +56 -0
- sage/libs/gsl/all.pxd +66 -0
- sage/libs/gsl/array.cpython-314-x86_64-linux-musl.so +0 -0
- sage/libs/gsl/array.pxd +5 -0
- sage/libs/gsl/array.pyx +102 -0
- sage/libs/gsl/bessel.pxd +208 -0
- sage/libs/gsl/blas.pxd +116 -0
- sage/libs/gsl/blas_types.pxd +34 -0
- sage/libs/gsl/block.pxd +52 -0
- sage/libs/gsl/chebyshev.pxd +37 -0
- sage/libs/gsl/clausen.pxd +12 -0
- sage/libs/gsl/combination.pxd +47 -0
- sage/libs/gsl/complex.pxd +151 -0
- sage/libs/gsl/coulomb.pxd +30 -0
- sage/libs/gsl/coupling.pxd +21 -0
- sage/libs/gsl/dawson.pxd +12 -0
- sage/libs/gsl/debye.pxd +24 -0
- sage/libs/gsl/dilog.pxd +14 -0
- sage/libs/gsl/eigen.pxd +46 -0
- sage/libs/gsl/elementary.pxd +12 -0
- sage/libs/gsl/ellint.pxd +48 -0
- sage/libs/gsl/elljac.pxd +8 -0
- sage/libs/gsl/erf.pxd +32 -0
- sage/libs/gsl/errno.pxd +26 -0
- sage/libs/gsl/exp.pxd +44 -0
- sage/libs/gsl/expint.pxd +44 -0
- sage/libs/gsl/fermi_dirac.pxd +44 -0
- sage/libs/gsl/fft.pxd +121 -0
- sage/libs/gsl/fit.pxd +50 -0
- sage/libs/gsl/gamma.pxd +94 -0
- sage/libs/gsl/gegenbauer.pxd +26 -0
- sage/libs/gsl/histogram.pxd +176 -0
- sage/libs/gsl/hyperg.pxd +52 -0
- sage/libs/gsl/integration.pxd +69 -0
- sage/libs/gsl/interp.pxd +109 -0
- sage/libs/gsl/laguerre.pxd +24 -0
- sage/libs/gsl/lambert.pxd +16 -0
- sage/libs/gsl/legendre.pxd +90 -0
- sage/libs/gsl/linalg.pxd +185 -0
- sage/libs/gsl/log.pxd +26 -0
- sage/libs/gsl/math.pxd +43 -0
- sage/libs/gsl/matrix.pxd +143 -0
- sage/libs/gsl/matrix_complex.pxd +130 -0
- sage/libs/gsl/min.pxd +67 -0
- sage/libs/gsl/monte.pxd +56 -0
- sage/libs/gsl/ntuple.pxd +32 -0
- sage/libs/gsl/odeiv.pxd +70 -0
- sage/libs/gsl/permutation.pxd +78 -0
- sage/libs/gsl/poly.pxd +40 -0
- sage/libs/gsl/pow_int.pxd +12 -0
- sage/libs/gsl/psi.pxd +28 -0
- sage/libs/gsl/qrng.pxd +29 -0
- sage/libs/gsl/random.pxd +257 -0
- sage/libs/gsl/rng.pxd +100 -0
- sage/libs/gsl/roots.pxd +72 -0
- sage/libs/gsl/sort.pxd +36 -0
- sage/libs/gsl/statistics.pxd +59 -0
- sage/libs/gsl/sum.pxd +55 -0
- sage/libs/gsl/synchrotron.pxd +16 -0
- sage/libs/gsl/transport.pxd +24 -0
- sage/libs/gsl/trig.pxd +58 -0
- sage/libs/gsl/types.pxd +137 -0
- sage/libs/gsl/vector.pxd +101 -0
- sage/libs/gsl/vector_complex.pxd +83 -0
- sage/libs/gsl/wavelet.pxd +49 -0
- sage/libs/gsl/zeta.pxd +28 -0
- sage/libs/mpc/__init__.pxd +114 -0
- sage/libs/mpc/types.pxd +28 -0
- sage/libs/mpfr/__init__.pxd +299 -0
- sage/libs/mpfr/types.pxd +26 -0
- sage/libs/mpmath/__init__.py +1 -0
- sage/libs/mpmath/all.py +27 -0
- sage/libs/mpmath/all__sagemath_modules.py +1 -0
- sage/libs/mpmath/utils.cpython-314-x86_64-linux-musl.so +0 -0
- sage/libs/mpmath/utils.pxd +4 -0
- sage/libs/mpmath/utils.pyx +319 -0
- sage/matrix/action.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/action.pxd +26 -0
- sage/matrix/action.pyx +596 -0
- sage/matrix/all.py +9 -0
- sage/matrix/args.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/args.pxd +144 -0
- sage/matrix/args.pyx +1668 -0
- sage/matrix/benchmark.py +1258 -0
- sage/matrix/berlekamp_massey.py +95 -0
- sage/matrix/compute_J_ideal.py +926 -0
- sage/matrix/constructor.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/constructor.pyx +750 -0
- sage/matrix/docs.py +430 -0
- sage/matrix/echelon_matrix.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/echelon_matrix.pyx +155 -0
- sage/matrix/matrix.pxd +2 -0
- sage/matrix/matrix0.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix0.pxd +68 -0
- sage/matrix/matrix0.pyx +6324 -0
- sage/matrix/matrix1.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix1.pxd +8 -0
- sage/matrix/matrix1.pyx +2851 -0
- sage/matrix/matrix2.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix2.pxd +25 -0
- sage/matrix/matrix2.pyx +20181 -0
- sage/matrix/matrix_cdv.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_cdv.pxd +4 -0
- sage/matrix/matrix_cdv.pyx +93 -0
- sage/matrix/matrix_complex_double_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_complex_double_dense.pxd +5 -0
- sage/matrix/matrix_complex_double_dense.pyx +98 -0
- sage/matrix/matrix_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_dense.pxd +5 -0
- sage/matrix/matrix_dense.pyx +343 -0
- sage/matrix/matrix_domain_dense.pxd +5 -0
- sage/matrix/matrix_domain_sparse.pxd +5 -0
- sage/matrix/matrix_double_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_double_dense.pxd +7 -0
- sage/matrix/matrix_double_dense.pyx +3906 -0
- sage/matrix/matrix_double_sparse.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_double_sparse.pxd +6 -0
- sage/matrix/matrix_double_sparse.pyx +248 -0
- sage/matrix/matrix_generic_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_generic_dense.pxd +7 -0
- sage/matrix/matrix_generic_dense.pyx +354 -0
- sage/matrix/matrix_generic_sparse.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_generic_sparse.pxd +7 -0
- sage/matrix/matrix_generic_sparse.pyx +461 -0
- sage/matrix/matrix_laurent_mpolynomial_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_laurent_mpolynomial_dense.pxd +5 -0
- sage/matrix/matrix_laurent_mpolynomial_dense.pyx +115 -0
- sage/matrix/matrix_misc.py +313 -0
- sage/matrix/matrix_numpy_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_numpy_dense.pxd +14 -0
- sage/matrix/matrix_numpy_dense.pyx +450 -0
- sage/matrix/matrix_numpy_integer_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_numpy_integer_dense.pxd +7 -0
- sage/matrix/matrix_numpy_integer_dense.pyx +59 -0
- sage/matrix/matrix_polynomial_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_polynomial_dense.pxd +5 -0
- sage/matrix/matrix_polynomial_dense.pyx +5341 -0
- sage/matrix/matrix_real_double_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_real_double_dense.pxd +7 -0
- sage/matrix/matrix_real_double_dense.pyx +122 -0
- sage/matrix/matrix_space.py +2848 -0
- sage/matrix/matrix_sparse.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_sparse.pxd +5 -0
- sage/matrix/matrix_sparse.pyx +1222 -0
- sage/matrix/matrix_window.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_window.pxd +37 -0
- sage/matrix/matrix_window.pyx +242 -0
- sage/matrix/misc_mpfr.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/misc_mpfr.pyx +80 -0
- sage/matrix/operation_table.py +1182 -0
- sage/matrix/special.py +3666 -0
- sage/matrix/strassen.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/strassen.pyx +851 -0
- sage/matrix/symplectic_basis.py +541 -0
- sage/matrix/template.pxd +6 -0
- sage/matrix/tests.py +71 -0
- sage/matroids/advanced.py +77 -0
- sage/matroids/all.py +13 -0
- sage/matroids/basis_exchange_matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/basis_exchange_matroid.pxd +96 -0
- sage/matroids/basis_exchange_matroid.pyx +2344 -0
- sage/matroids/basis_matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/basis_matroid.pxd +45 -0
- sage/matroids/basis_matroid.pyx +1217 -0
- sage/matroids/catalog.py +44 -0
- sage/matroids/chow_ring.py +473 -0
- sage/matroids/chow_ring_ideal.py +849 -0
- sage/matroids/circuit_closures_matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/circuit_closures_matroid.pxd +16 -0
- sage/matroids/circuit_closures_matroid.pyx +559 -0
- sage/matroids/circuits_matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/circuits_matroid.pxd +38 -0
- sage/matroids/circuits_matroid.pyx +947 -0
- sage/matroids/constructor.py +1086 -0
- sage/matroids/database_collections.py +365 -0
- sage/matroids/database_matroids.py +5338 -0
- sage/matroids/dual_matroid.py +583 -0
- sage/matroids/extension.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/extension.pxd +34 -0
- sage/matroids/extension.pyx +519 -0
- sage/matroids/flats_matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/flats_matroid.pxd +28 -0
- sage/matroids/flats_matroid.pyx +715 -0
- sage/matroids/gammoid.py +600 -0
- sage/matroids/graphic_matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/graphic_matroid.pxd +39 -0
- sage/matroids/graphic_matroid.pyx +2024 -0
- sage/matroids/lean_matrix.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/lean_matrix.pxd +126 -0
- sage/matroids/lean_matrix.pyx +3667 -0
- sage/matroids/linear_matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/linear_matroid.pxd +180 -0
- sage/matroids/linear_matroid.pyx +6649 -0
- sage/matroids/matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/matroid.pxd +243 -0
- sage/matroids/matroid.pyx +8759 -0
- sage/matroids/matroids_catalog.py +190 -0
- sage/matroids/matroids_plot_helpers.py +890 -0
- sage/matroids/minor_matroid.py +480 -0
- sage/matroids/minorfix.h +9 -0
- sage/matroids/named_matroids.py +5 -0
- sage/matroids/rank_matroid.py +268 -0
- sage/matroids/set_system.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/set_system.pxd +38 -0
- sage/matroids/set_system.pyx +800 -0
- sage/matroids/transversal_matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/transversal_matroid.pxd +14 -0
- sage/matroids/transversal_matroid.pyx +893 -0
- sage/matroids/union_matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/union_matroid.pxd +20 -0
- sage/matroids/union_matroid.pyx +331 -0
- sage/matroids/unpickling.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/unpickling.pyx +843 -0
- sage/matroids/utilities.py +809 -0
- sage/misc/all__sagemath_modules.py +20 -0
- sage/misc/c3.cpython-314-x86_64-linux-musl.so +0 -0
- sage/misc/c3.pyx +238 -0
- sage/misc/compat.py +87 -0
- sage/misc/element_with_label.py +173 -0
- sage/misc/func_persist.py +79 -0
- sage/misc/pickle_old.cpython-314-x86_64-linux-musl.so +0 -0
- sage/misc/pickle_old.pyx +19 -0
- sage/misc/proof.py +7 -0
- sage/misc/replace_dot_all.py +472 -0
- sage/misc/sagedoc_conf.py +168 -0
- sage/misc/sphinxify.py +167 -0
- sage/misc/test_class_pickling.py +85 -0
- sage/modules/all.py +42 -0
- sage/modules/complex_double_vector.py +25 -0
- sage/modules/diamond_cutting.py +380 -0
- sage/modules/fg_pid/all.py +1 -0
- sage/modules/fg_pid/fgp_element.py +456 -0
- sage/modules/fg_pid/fgp_module.py +2091 -0
- sage/modules/fg_pid/fgp_morphism.py +550 -0
- sage/modules/filtered_vector_space.py +1271 -0
- sage/modules/finite_submodule_iter.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/finite_submodule_iter.pxd +27 -0
- sage/modules/finite_submodule_iter.pyx +452 -0
- sage/modules/fp_graded/all.py +1 -0
- sage/modules/fp_graded/element.py +346 -0
- sage/modules/fp_graded/free_element.py +298 -0
- sage/modules/fp_graded/free_homspace.py +53 -0
- sage/modules/fp_graded/free_module.py +1060 -0
- sage/modules/fp_graded/free_morphism.py +217 -0
- sage/modules/fp_graded/homspace.py +563 -0
- sage/modules/fp_graded/module.py +1340 -0
- sage/modules/fp_graded/morphism.py +1990 -0
- sage/modules/fp_graded/steenrod/all.py +1 -0
- sage/modules/fp_graded/steenrod/homspace.py +65 -0
- sage/modules/fp_graded/steenrod/module.py +477 -0
- sage/modules/fp_graded/steenrod/morphism.py +404 -0
- sage/modules/fp_graded/steenrod/profile.py +241 -0
- sage/modules/free_module.py +8447 -0
- sage/modules/free_module_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/free_module_element.pxd +22 -0
- sage/modules/free_module_element.pyx +5445 -0
- sage/modules/free_module_homspace.py +369 -0
- sage/modules/free_module_integer.py +896 -0
- sage/modules/free_module_morphism.py +823 -0
- sage/modules/free_module_pseudohomspace.py +352 -0
- sage/modules/free_module_pseudomorphism.py +578 -0
- sage/modules/free_quadratic_module.py +1706 -0
- sage/modules/free_quadratic_module_integer_symmetric.py +1790 -0
- sage/modules/matrix_morphism.py +1745 -0
- sage/modules/misc.py +103 -0
- sage/modules/module_functors.py +192 -0
- sage/modules/multi_filtered_vector_space.py +719 -0
- sage/modules/ore_module.py +2208 -0
- sage/modules/ore_module_element.py +178 -0
- sage/modules/ore_module_homspace.py +147 -0
- sage/modules/ore_module_morphism.py +968 -0
- sage/modules/quotient_module.py +699 -0
- sage/modules/real_double_vector.py +22 -0
- sage/modules/submodule.py +255 -0
- sage/modules/tensor_operations.py +567 -0
- sage/modules/torsion_quadratic_module.py +1352 -0
- sage/modules/tutorial_free_modules.py +248 -0
- sage/modules/vector_complex_double_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_complex_double_dense.pxd +6 -0
- sage/modules/vector_complex_double_dense.pyx +117 -0
- sage/modules/vector_double_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_double_dense.pxd +6 -0
- sage/modules/vector_double_dense.pyx +604 -0
- sage/modules/vector_integer_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_integer_dense.pxd +15 -0
- sage/modules/vector_integer_dense.pyx +361 -0
- sage/modules/vector_integer_sparse.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_integer_sparse.pxd +29 -0
- sage/modules/vector_integer_sparse.pyx +406 -0
- sage/modules/vector_modn_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_modn_dense.pxd +12 -0
- sage/modules/vector_modn_dense.pyx +394 -0
- sage/modules/vector_modn_sparse.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_modn_sparse.pxd +21 -0
- sage/modules/vector_modn_sparse.pyx +298 -0
- sage/modules/vector_numpy_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_numpy_dense.pxd +15 -0
- sage/modules/vector_numpy_dense.pyx +304 -0
- sage/modules/vector_numpy_integer_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_numpy_integer_dense.pxd +7 -0
- sage/modules/vector_numpy_integer_dense.pyx +54 -0
- sage/modules/vector_rational_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_rational_dense.pxd +15 -0
- sage/modules/vector_rational_dense.pyx +387 -0
- sage/modules/vector_rational_sparse.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_rational_sparse.pxd +30 -0
- sage/modules/vector_rational_sparse.pyx +413 -0
- sage/modules/vector_real_double_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_real_double_dense.pxd +6 -0
- sage/modules/vector_real_double_dense.pyx +126 -0
- sage/modules/vector_space_homspace.py +430 -0
- sage/modules/vector_space_morphism.py +989 -0
- sage/modules/with_basis/all.py +15 -0
- sage/modules/with_basis/cell_module.py +494 -0
- sage/modules/with_basis/indexed_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/with_basis/indexed_element.pxd +13 -0
- sage/modules/with_basis/indexed_element.pyx +1058 -0
- sage/modules/with_basis/invariant.py +1075 -0
- sage/modules/with_basis/morphism.py +1636 -0
- sage/modules/with_basis/representation.py +2939 -0
- sage/modules/with_basis/subquotient.py +685 -0
- sage/numerical/all__sagemath_modules.py +6 -0
- sage/numerical/gauss_legendre.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/gauss_legendre.pyx +381 -0
- sage/numerical/optimize.py +910 -0
- sage/probability/all.py +10 -0
- sage/probability/probability_distribution.cpython-314-x86_64-linux-musl.so +0 -0
- sage/probability/probability_distribution.pyx +1242 -0
- sage/probability/random_variable.py +411 -0
- sage/quadratic_forms/all.py +4 -0
- sage/quadratic_forms/all__sagemath_modules.py +15 -0
- sage/quadratic_forms/binary_qf.py +2042 -0
- sage/quadratic_forms/bqf_class_group.py +748 -0
- sage/quadratic_forms/constructions.py +93 -0
- sage/quadratic_forms/count_local_2.cpython-314-x86_64-linux-musl.so +0 -0
- sage/quadratic_forms/count_local_2.pyx +365 -0
- sage/quadratic_forms/extras.py +195 -0
- sage/quadratic_forms/quadratic_form.py +1753 -0
- sage/quadratic_forms/quadratic_form__count_local_2.py +221 -0
- sage/quadratic_forms/quadratic_form__equivalence_testing.py +708 -0
- sage/quadratic_forms/quadratic_form__evaluate.cpython-314-x86_64-linux-musl.so +0 -0
- sage/quadratic_forms/quadratic_form__evaluate.pyx +139 -0
- sage/quadratic_forms/quadratic_form__local_density_congruence.py +977 -0
- sage/quadratic_forms/quadratic_form__local_field_invariants.py +1072 -0
- sage/quadratic_forms/quadratic_form__neighbors.py +424 -0
- sage/quadratic_forms/quadratic_form__reduction_theory.py +488 -0
- sage/quadratic_forms/quadratic_form__split_local_covering.py +416 -0
- sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +657 -0
- sage/quadratic_forms/quadratic_form__theta.py +352 -0
- sage/quadratic_forms/quadratic_form__variable_substitutions.py +370 -0
- sage/quadratic_forms/random_quadraticform.py +209 -0
- sage/quadratic_forms/ternary.cpython-314-x86_64-linux-musl.so +0 -0
- sage/quadratic_forms/ternary.pyx +1154 -0
- sage/quadratic_forms/ternary_qf.py +2027 -0
- sage/rings/all__sagemath_modules.py +28 -0
- sage/rings/asymptotic/all__sagemath_modules.py +1 -0
- sage/rings/asymptotic/misc.py +1252 -0
- sage/rings/cc.py +4 -0
- sage/rings/cfinite_sequence.py +1306 -0
- sage/rings/complex_conversion.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/complex_conversion.pxd +8 -0
- sage/rings/complex_conversion.pyx +23 -0
- sage/rings/complex_double.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/complex_double.pxd +21 -0
- sage/rings/complex_double.pyx +2654 -0
- sage/rings/complex_mpc.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/complex_mpc.pxd +21 -0
- sage/rings/complex_mpc.pyx +2576 -0
- sage/rings/complex_mpfr.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/complex_mpfr.pxd +18 -0
- sage/rings/complex_mpfr.pyx +3602 -0
- sage/rings/derivation.py +2334 -0
- sage/rings/finite_rings/all__sagemath_modules.py +1 -0
- sage/rings/finite_rings/maps_finite_field.py +191 -0
- sage/rings/function_field/all__sagemath_modules.py +8 -0
- sage/rings/function_field/derivations.py +102 -0
- sage/rings/function_field/derivations_rational.py +132 -0
- sage/rings/function_field/differential.py +853 -0
- sage/rings/function_field/divisor.py +1107 -0
- sage/rings/function_field/drinfeld_modules/action.py +199 -0
- sage/rings/function_field/drinfeld_modules/all.py +1 -0
- sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py +673 -0
- sage/rings/function_field/drinfeld_modules/drinfeld_module.py +2087 -0
- sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py +1131 -0
- sage/rings/function_field/drinfeld_modules/homset.py +420 -0
- sage/rings/function_field/drinfeld_modules/morphism.py +820 -0
- sage/rings/function_field/hermite_form_polynomial.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/function_field/hermite_form_polynomial.pyx +188 -0
- sage/rings/function_field/khuri_makdisi.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/function_field/khuri_makdisi.pyx +935 -0
- sage/rings/invariants/all.py +4 -0
- sage/rings/invariants/invariant_theory.py +4597 -0
- sage/rings/invariants/reconstruction.py +395 -0
- sage/rings/polynomial/all__sagemath_modules.py +17 -0
- sage/rings/polynomial/integer_valued_polynomials.py +1230 -0
- sage/rings/polynomial/laurent_polynomial_mpair.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/polynomial/laurent_polynomial_mpair.pxd +15 -0
- sage/rings/polynomial/laurent_polynomial_mpair.pyx +2023 -0
- sage/rings/polynomial/ore_function_element.py +952 -0
- sage/rings/polynomial/ore_function_field.py +1028 -0
- sage/rings/polynomial/ore_polynomial_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/polynomial/ore_polynomial_element.pxd +48 -0
- sage/rings/polynomial/ore_polynomial_element.pyx +3145 -0
- sage/rings/polynomial/ore_polynomial_ring.py +1334 -0
- sage/rings/polynomial/polynomial_real_mpfr_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +788 -0
- sage/rings/polynomial/q_integer_valued_polynomials.py +1264 -0
- sage/rings/polynomial/skew_polynomial_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/polynomial/skew_polynomial_element.pxd +9 -0
- sage/rings/polynomial/skew_polynomial_element.pyx +684 -0
- sage/rings/polynomial/skew_polynomial_finite_field.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/polynomial/skew_polynomial_finite_field.pxd +19 -0
- sage/rings/polynomial/skew_polynomial_finite_field.pyx +1093 -0
- sage/rings/polynomial/skew_polynomial_finite_order.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/polynomial/skew_polynomial_finite_order.pxd +10 -0
- sage/rings/polynomial/skew_polynomial_finite_order.pyx +567 -0
- sage/rings/polynomial/skew_polynomial_ring.py +908 -0
- sage/rings/real_double_element_gsl.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/real_double_element_gsl.pxd +8 -0
- sage/rings/real_double_element_gsl.pyx +794 -0
- sage/rings/real_field.py +58 -0
- sage/rings/real_mpfr.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/real_mpfr.pxd +29 -0
- sage/rings/real_mpfr.pyx +6122 -0
- sage/rings/ring_extension.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/ring_extension.pxd +42 -0
- sage/rings/ring_extension.pyx +2779 -0
- sage/rings/ring_extension_conversion.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/ring_extension_conversion.pxd +16 -0
- sage/rings/ring_extension_conversion.pyx +462 -0
- sage/rings/ring_extension_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/ring_extension_element.pxd +21 -0
- sage/rings/ring_extension_element.pyx +1635 -0
- sage/rings/ring_extension_homset.py +64 -0
- sage/rings/ring_extension_morphism.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/ring_extension_morphism.pxd +35 -0
- sage/rings/ring_extension_morphism.pyx +920 -0
- sage/schemes/all__sagemath_modules.py +1 -0
- sage/schemes/projective/all__sagemath_modules.py +1 -0
- sage/schemes/projective/coherent_sheaf.py +300 -0
- sage/schemes/projective/cohomology.py +510 -0
- sage/stats/all.py +15 -0
- sage/stats/basic_stats.py +489 -0
- sage/stats/distributions/all.py +7 -0
- sage/stats/distributions/catalog.py +34 -0
- sage/stats/distributions/dgs.h +50 -0
- sage/stats/distributions/dgs.pxd +111 -0
- sage/stats/distributions/dgs_bern.h +400 -0
- sage/stats/distributions/dgs_gauss.h +614 -0
- sage/stats/distributions/dgs_misc.h +104 -0
- sage/stats/distributions/discrete_gaussian_integer.cpython-314-x86_64-linux-musl.so +0 -0
- sage/stats/distributions/discrete_gaussian_integer.pxd +14 -0
- sage/stats/distributions/discrete_gaussian_integer.pyx +498 -0
- sage/stats/distributions/discrete_gaussian_lattice.py +908 -0
- sage/stats/distributions/discrete_gaussian_polynomial.py +141 -0
- sage/stats/hmm/all.py +15 -0
- sage/stats/hmm/chmm.cpython-314-x86_64-linux-musl.so +0 -0
- sage/stats/hmm/chmm.pyx +1595 -0
- sage/stats/hmm/distributions.cpython-314-x86_64-linux-musl.so +0 -0
- sage/stats/hmm/distributions.pxd +29 -0
- sage/stats/hmm/distributions.pyx +531 -0
- sage/stats/hmm/hmm.cpython-314-x86_64-linux-musl.so +0 -0
- sage/stats/hmm/hmm.pxd +17 -0
- sage/stats/hmm/hmm.pyx +1388 -0
- sage/stats/hmm/util.cpython-314-x86_64-linux-musl.so +0 -0
- sage/stats/hmm/util.pxd +7 -0
- sage/stats/hmm/util.pyx +165 -0
- sage/stats/intlist.cpython-314-x86_64-linux-musl.so +0 -0
- sage/stats/intlist.pxd +14 -0
- sage/stats/intlist.pyx +588 -0
- sage/stats/r.py +49 -0
- sage/stats/time_series.cpython-314-x86_64-linux-musl.so +0 -0
- sage/stats/time_series.pxd +6 -0
- sage/stats/time_series.pyx +2546 -0
- sage/tensor/all.py +2 -0
- sage/tensor/modules/all.py +8 -0
- sage/tensor/modules/alternating_contr_tensor.py +761 -0
- sage/tensor/modules/comp.py +5598 -0
- sage/tensor/modules/ext_pow_free_module.py +824 -0
- sage/tensor/modules/finite_rank_free_module.py +3589 -0
- sage/tensor/modules/format_utilities.py +333 -0
- sage/tensor/modules/free_module_alt_form.py +858 -0
- sage/tensor/modules/free_module_automorphism.py +1207 -0
- sage/tensor/modules/free_module_basis.py +1074 -0
- sage/tensor/modules/free_module_element.py +284 -0
- sage/tensor/modules/free_module_homset.py +652 -0
- sage/tensor/modules/free_module_linear_group.py +564 -0
- sage/tensor/modules/free_module_morphism.py +1581 -0
- sage/tensor/modules/free_module_tensor.py +3289 -0
- sage/tensor/modules/reflexive_module.py +386 -0
- sage/tensor/modules/tensor_free_module.py +780 -0
- sage/tensor/modules/tensor_free_submodule.py +538 -0
- sage/tensor/modules/tensor_free_submodule_basis.py +140 -0
- sage/tensor/modules/tensor_with_indices.py +1043 -0
|
@@ -0,0 +1,4597 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-modules
|
|
2
|
+
r"""
|
|
3
|
+
Classical Invariant Theory
|
|
4
|
+
|
|
5
|
+
This module lists classical invariants and covariants of homogeneous
|
|
6
|
+
polynomials (also called algebraic forms) under the action of the
|
|
7
|
+
special linear group. That is, we are dealing with polynomials of
|
|
8
|
+
degree `d` in `n` variables. The special linear group `SL(n,\CC)` acts
|
|
9
|
+
on the variables `(x_1,\dots, x_n)` linearly,
|
|
10
|
+
|
|
11
|
+
.. MATH::
|
|
12
|
+
|
|
13
|
+
(x_1,\dots, x_n)^t \to A (x_1,\dots, x_n)^t
|
|
14
|
+
,\qquad
|
|
15
|
+
A \in SL(n,\CC)
|
|
16
|
+
|
|
17
|
+
The linear action on the variables transforms a polynomial `p`
|
|
18
|
+
generally into a different polynomial `gp`. We can think of it as an
|
|
19
|
+
action on the space of coefficients in `p`. An invariant is a
|
|
20
|
+
polynomial in the coefficients that is invariant under this action. A
|
|
21
|
+
covariant is a polynomial in the coefficients and the variables
|
|
22
|
+
`(x_1,\dots, x_n)` that is invariant under the combined action.
|
|
23
|
+
|
|
24
|
+
For example, the binary quadratic `p(x,y) = a x^2 + b x y + c y^2`
|
|
25
|
+
has as its invariant the discriminant `\mathop{disc}(p) = b^2 - 4 a
|
|
26
|
+
c`. This means that for any `SL(2,\CC)` coordinate change
|
|
27
|
+
|
|
28
|
+
.. MATH::
|
|
29
|
+
|
|
30
|
+
\begin{pmatrix} x' \\ y' \end{pmatrix}
|
|
31
|
+
=
|
|
32
|
+
\begin{pmatrix} \alpha & \beta \\ \gamma & \delta \end{pmatrix}
|
|
33
|
+
\begin{pmatrix} x \\ y \end{pmatrix}
|
|
34
|
+
\qquad
|
|
35
|
+
\alpha\delta-\beta\gamma=1
|
|
36
|
+
|
|
37
|
+
the discriminant is invariant, `\mathop{disc}\big(p(x',y')\big) =
|
|
38
|
+
\mathop{disc}\big(p(x,y)\big)`.
|
|
39
|
+
|
|
40
|
+
To use this module, you should use the factory object
|
|
41
|
+
:class:`invariant_theory <InvariantTheoryFactory>`. For example, take
|
|
42
|
+
the quartic::
|
|
43
|
+
|
|
44
|
+
sage: R.<x,y> = QQ[]
|
|
45
|
+
sage: q = x^4 + y^4
|
|
46
|
+
sage: quartic = invariant_theory.binary_quartic(q); quartic
|
|
47
|
+
Binary quartic with coefficients (1, 0, 0, 0, 1)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
One invariant of a quartic is known as the Eisenstein
|
|
51
|
+
D-invariant. Since it is an invariant, it is a polynomial in the
|
|
52
|
+
coefficients (which are integers in this example)::
|
|
53
|
+
|
|
54
|
+
sage: quartic.EisensteinD()
|
|
55
|
+
1
|
|
56
|
+
|
|
57
|
+
One example of a covariant of a quartic is the so-called g-covariant
|
|
58
|
+
(actually, the Hessian). As with all covariants, it is a polynomial in
|
|
59
|
+
`x`, `y` and the coefficients::
|
|
60
|
+
|
|
61
|
+
sage: quartic.g_covariant()
|
|
62
|
+
-x^2*y^2
|
|
63
|
+
|
|
64
|
+
As usual, use tab completion and the online help to discover the
|
|
65
|
+
implemented invariants and covariants.
|
|
66
|
+
|
|
67
|
+
In general, the variables of the defining polynomial cannot be
|
|
68
|
+
guessed. For example, the zero polynomial can be thought of as a
|
|
69
|
+
homogeneous polynomial of any degree. Also, since we also want to
|
|
70
|
+
allow polynomial coefficients we cannot just take all variables of the
|
|
71
|
+
polynomial ring as the variables of the form. This is why you will
|
|
72
|
+
have to specify the variables explicitly if there is any potential
|
|
73
|
+
ambiguity. For example::
|
|
74
|
+
|
|
75
|
+
sage: invariant_theory.binary_quartic(R.zero(), [x,y])
|
|
76
|
+
Binary quartic with coefficients (0, 0, 0, 0, 0)
|
|
77
|
+
|
|
78
|
+
sage: invariant_theory.binary_quartic(x^4, [x,y])
|
|
79
|
+
Binary quartic with coefficients (0, 0, 0, 0, 1)
|
|
80
|
+
|
|
81
|
+
sage: R.<x,y,t> = QQ[]
|
|
82
|
+
sage: invariant_theory.binary_quartic(x^4 + y^4 + t*x^2*y^2, [x,y])
|
|
83
|
+
Binary quartic with coefficients (1, 0, t, 0, 1)
|
|
84
|
+
|
|
85
|
+
Finally, it is often convenient to use inhomogeneous polynomials where
|
|
86
|
+
it is understood that one wants to homogenize them. This is also
|
|
87
|
+
supported, just define the form with an inhomogeneous polynomial and
|
|
88
|
+
specify one less variable::
|
|
89
|
+
|
|
90
|
+
sage: R.<x,t> = QQ[]
|
|
91
|
+
sage: invariant_theory.binary_quartic(x^4 + 1 + t*x^2, [x])
|
|
92
|
+
Binary quartic with coefficients (1, 0, t, 0, 1)
|
|
93
|
+
|
|
94
|
+
REFERENCES:
|
|
95
|
+
|
|
96
|
+
- :wikipedia:`Glossary_of_invariant_theory`
|
|
97
|
+
|
|
98
|
+
AUTHORS:
|
|
99
|
+
|
|
100
|
+
- Volker Braun (2013-01-24): initial version
|
|
101
|
+
- Jesper Noordsij (2018-05-18): support for binary quintics added
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
# ****************************************************************************
|
|
105
|
+
# Copyright (C) 2012 Volker Braun <vbraun.name@gmail.com>
|
|
106
|
+
#
|
|
107
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
108
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
109
|
+
# the License, or (at your option) any later version.
|
|
110
|
+
# https://www.gnu.org/licenses/
|
|
111
|
+
# ****************************************************************************
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
from sage.matrix.constructor import matrix
|
|
115
|
+
from sage.structure.sage_object import SageObject
|
|
116
|
+
from sage.structure.richcmp import richcmp_method, richcmp
|
|
117
|
+
from sage.misc.cachefunc import cached_method
|
|
118
|
+
import sage.rings.invariants.reconstruction as reconstruction
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
######################################################################
|
|
122
|
+
def _guess_variables(polynomial, *args) -> tuple:
|
|
123
|
+
"""
|
|
124
|
+
Return the polynomial variables.
|
|
125
|
+
|
|
126
|
+
INPUT:
|
|
127
|
+
|
|
128
|
+
- ``polynomial`` -- a polynomial, or a list/tuple of polynomials
|
|
129
|
+
in the same polynomial ring
|
|
130
|
+
|
|
131
|
+
- ``*args`` -- the variables. If none are specified, all variables
|
|
132
|
+
in ``polynomial`` are returned. If a list or tuple is passed,
|
|
133
|
+
the content is returned. If multiple arguments are passed, they
|
|
134
|
+
are returned.
|
|
135
|
+
|
|
136
|
+
OUTPUT:
|
|
137
|
+
|
|
138
|
+
A tuple of variables in the parent ring of the polynomial(s).
|
|
139
|
+
|
|
140
|
+
EXAMPLES::
|
|
141
|
+
|
|
142
|
+
sage: from sage.rings.invariants.invariant_theory import _guess_variables
|
|
143
|
+
sage: R.<x,y> = QQ[]
|
|
144
|
+
sage: _guess_variables(x^2 + y^2)
|
|
145
|
+
(x, y)
|
|
146
|
+
sage: _guess_variables([x^2, y^2])
|
|
147
|
+
(x, y)
|
|
148
|
+
sage: _guess_variables(x^2 + y^2, x)
|
|
149
|
+
(x,)
|
|
150
|
+
sage: _guess_variables(x^2 + y^2, x, y)
|
|
151
|
+
(x, y)
|
|
152
|
+
sage: _guess_variables(x^2 + y^2, [x,y])
|
|
153
|
+
(x, y)
|
|
154
|
+
"""
|
|
155
|
+
if isinstance(polynomial, (list, tuple)):
|
|
156
|
+
R = polynomial[0].parent()
|
|
157
|
+
if not all(p.parent() is R for p in polynomial):
|
|
158
|
+
raise ValueError('all input polynomials must be in the same ring')
|
|
159
|
+
if not args or (len(args) == 1 and args[0] is None):
|
|
160
|
+
if isinstance(polynomial, (list, tuple)):
|
|
161
|
+
variables = tuple()
|
|
162
|
+
for p in polynomial:
|
|
163
|
+
for var in p.variables():
|
|
164
|
+
if var not in variables:
|
|
165
|
+
variables += (var,)
|
|
166
|
+
return variables
|
|
167
|
+
else:
|
|
168
|
+
return polynomial.variables()
|
|
169
|
+
elif len(args) == 1 and isinstance(args[0], (tuple, list)):
|
|
170
|
+
return tuple(args[0])
|
|
171
|
+
else:
|
|
172
|
+
return tuple(args)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def transvectant(f, g, h=1, scale='default'):
|
|
176
|
+
r"""
|
|
177
|
+
Return the h-th transvectant of f and g.
|
|
178
|
+
|
|
179
|
+
INPUT:
|
|
180
|
+
|
|
181
|
+
- ``f``, ``g`` -- two homogeneous binary forms in the same polynomial ring
|
|
182
|
+
|
|
183
|
+
- ``h`` -- the order of the transvectant; if it is not specified,
|
|
184
|
+
the first transvectant is returned
|
|
185
|
+
|
|
186
|
+
- ``scale`` -- the scaling factor applied to the result. Possible values
|
|
187
|
+
are ``'default'`` and ``'none'``. The ``'default'`` scaling factor is
|
|
188
|
+
the one that appears in the output statement below, if the scaling
|
|
189
|
+
factor is ``'none'`` the quotient of factorials is left out.
|
|
190
|
+
|
|
191
|
+
OUTPUT:
|
|
192
|
+
|
|
193
|
+
The h-th transvectant of the listed forms `f` and `g`:
|
|
194
|
+
|
|
195
|
+
.. MATH::
|
|
196
|
+
|
|
197
|
+
(f,g)_h = \frac{(d_f-h)! \cdot (d_g-h)!}{d_f! \cdot d_g!}\left(
|
|
198
|
+
\left(\frac{\partial}{\partial x}\frac{\partial}{\partial z'}
|
|
199
|
+
- \frac{\partial}{\partial x'}\frac{\partial}{\partial z}
|
|
200
|
+
\right)^h \left(f(x,z) \cdot g(x',z')\right)
|
|
201
|
+
\right)_{(x',z')=(x,z)}
|
|
202
|
+
|
|
203
|
+
EXAMPLES::
|
|
204
|
+
|
|
205
|
+
sage: from sage.rings.invariants.invariant_theory import AlgebraicForm, transvectant
|
|
206
|
+
sage: R.<x,y> = QQ[]
|
|
207
|
+
sage: f = AlgebraicForm(2, 5, x^5 + 5*x^4*y + 5*x*y^4 + y^5)
|
|
208
|
+
sage: transvectant(f, f, 4)
|
|
209
|
+
Binary quadratic given by 2*x^2 - 4*x*y + 2*y^2
|
|
210
|
+
sage: transvectant(f, f, 8)
|
|
211
|
+
Binary form of degree -6 given by 0
|
|
212
|
+
|
|
213
|
+
The default scaling will yield an error for fields of positive
|
|
214
|
+
characteristic below `d_f!` or `d_g!` as the denominator of the scaling
|
|
215
|
+
factor will not be invertible in that case. The scale argument ``'none'``
|
|
216
|
+
can be used to compute the transvectant in this case::
|
|
217
|
+
|
|
218
|
+
sage: # needs sage.rings.finite_rings
|
|
219
|
+
sage: R.<a0,a1,a2,a3,a4,a5,x0,x1> = GF(5)[]
|
|
220
|
+
sage: f = AlgebraicForm(2, 5, a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2
|
|
221
|
+
....: + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5, x0, x1)
|
|
222
|
+
sage: transvectant(f, f, 4)
|
|
223
|
+
Traceback (most recent call last):
|
|
224
|
+
...
|
|
225
|
+
ZeroDivisionError
|
|
226
|
+
sage: transvectant(f, f, 4, scale='none')
|
|
227
|
+
Binary quadratic given by -a3^2*x0^2 + a2*a4*x0^2 + a2*a3*x0*x1
|
|
228
|
+
- a1*a4*x0*x1 - a2^2*x1^2 + a1*a3*x1^2
|
|
229
|
+
|
|
230
|
+
The additional factors that appear when ``scale='none'`` is used can be
|
|
231
|
+
seen if we consider the same transvectant over the rationals and compare
|
|
232
|
+
it to the scaled version::
|
|
233
|
+
|
|
234
|
+
sage: R.<a0,a1,a2,a3,a4,a5,x0,x1> = QQ[]
|
|
235
|
+
sage: f = AlgebraicForm(2, 5, a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2
|
|
236
|
+
....: + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5, x0, x1)
|
|
237
|
+
sage: transvectant(f, f, 4)
|
|
238
|
+
Binary quadratic given by 3/50*a3^2*x0^2 - 4/25*a2*a4*x0^2
|
|
239
|
+
+ 2/5*a1*a5*x0^2 + 1/25*a2*a3*x0*x1 - 6/25*a1*a4*x0*x1 + 2*a0*a5*x0*x1
|
|
240
|
+
+ 3/50*a2^2*x1^2 - 4/25*a1*a3*x1^2 + 2/5*a0*a4*x1^2
|
|
241
|
+
sage: transvectant(f, f, 4, scale='none')
|
|
242
|
+
Binary quadratic given by 864*a3^2*x0^2 - 2304*a2*a4*x0^2
|
|
243
|
+
+ 5760*a1*a5*x0^2 + 576*a2*a3*x0*x1 - 3456*a1*a4*x0*x1
|
|
244
|
+
+ 28800*a0*a5*x0*x1 + 864*a2^2*x1^2 - 2304*a1*a3*x1^2 + 5760*a0*a4*x1^2
|
|
245
|
+
|
|
246
|
+
If the forms are given as inhomogeneous polynomials, the homogenisation
|
|
247
|
+
might fail if the polynomial ring has multiple variables. You can
|
|
248
|
+
circumvent this by making sure the base ring of the polynomial has only
|
|
249
|
+
one variable::
|
|
250
|
+
|
|
251
|
+
sage: R.<x,y> = QQ[]
|
|
252
|
+
sage: quintic = invariant_theory.binary_quintic(x^5 + x^3 + 2*x^2 + y^5, x)
|
|
253
|
+
sage: transvectant(quintic, quintic, 2)
|
|
254
|
+
Traceback (most recent call last):
|
|
255
|
+
...
|
|
256
|
+
ValueError: polynomial is not homogeneous
|
|
257
|
+
sage: R.<y> = QQ[]
|
|
258
|
+
sage: S.<x> = R[]
|
|
259
|
+
sage: quintic = invariant_theory.binary_quintic(x^5 + x^3 + 2*x^2 + y^5, x)
|
|
260
|
+
sage: transvectant(quintic, quintic, 2)
|
|
261
|
+
Binary sextic given by 1/5*x^6 + 6/5*x^5*h - 3/25*x^4*h^2
|
|
262
|
+
+ (50*y^5 - 8)/25*x^3*h^3 - 12/25*x^2*h^4 + (3*y^5)/5*x*h^5
|
|
263
|
+
+ (2*y^5)/5*h^6
|
|
264
|
+
"""
|
|
265
|
+
f = f.homogenized()
|
|
266
|
+
g = g.homogenized()
|
|
267
|
+
R = f._ring
|
|
268
|
+
if g._ring is not R:
|
|
269
|
+
raise ValueError('all input forms must be in the same polynomial ring')
|
|
270
|
+
x = f._variables[0]
|
|
271
|
+
y = f._variables[1]
|
|
272
|
+
degree = f._d + g._d - 2*h
|
|
273
|
+
if h > f._d or h > g._d:
|
|
274
|
+
tv = R(0)
|
|
275
|
+
else:
|
|
276
|
+
from sage.functions.other import binomial, factorial
|
|
277
|
+
if scale == 'default':
|
|
278
|
+
scalar = factorial(f._d-h) * factorial(g._d-h) \
|
|
279
|
+
* R(factorial(f._d)*factorial(g._d))**(-1)
|
|
280
|
+
elif scale == 'none':
|
|
281
|
+
scalar = 1
|
|
282
|
+
else:
|
|
283
|
+
raise ValueError('unknown scale type: %s' % scale)
|
|
284
|
+
|
|
285
|
+
def diff(j):
|
|
286
|
+
df = f.form().derivative(x, j).derivative(y, h-j)
|
|
287
|
+
dg = g.form().derivative(x, h-j).derivative(y, j)
|
|
288
|
+
return (-1)**j * binomial(h, j) * df * dg
|
|
289
|
+
tv = scalar * sum([diff(j) for j in range(h+1)])
|
|
290
|
+
if tv.parent() is not R:
|
|
291
|
+
S = tv.parent()
|
|
292
|
+
x = S(x)
|
|
293
|
+
y = S(y)
|
|
294
|
+
return AlgebraicForm(2, degree, tv, x, y)
|
|
295
|
+
|
|
296
|
+
######################################################################
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
@richcmp_method
|
|
300
|
+
class FormsBase(SageObject):
|
|
301
|
+
"""
|
|
302
|
+
The common base class of :class:`AlgebraicForm` and
|
|
303
|
+
:class:`SeveralAlgebraicForms`.
|
|
304
|
+
|
|
305
|
+
This is an abstract base class to provide common methods. It does
|
|
306
|
+
not make much sense to instantiate it.
|
|
307
|
+
|
|
308
|
+
TESTS::
|
|
309
|
+
|
|
310
|
+
sage: from sage.rings.invariants.invariant_theory import FormsBase
|
|
311
|
+
sage: FormsBase(None, None, None, None)
|
|
312
|
+
<sage.rings.invariants.invariant_theory.FormsBase object at ...>
|
|
313
|
+
"""
|
|
314
|
+
|
|
315
|
+
def __init__(self, n, homogeneous, ring, variables):
|
|
316
|
+
"""
|
|
317
|
+
The Python constructor.
|
|
318
|
+
|
|
319
|
+
TESTS::
|
|
320
|
+
|
|
321
|
+
sage: from sage.rings.invariants.invariant_theory import FormsBase
|
|
322
|
+
sage: FormsBase(None, None, None, None)
|
|
323
|
+
<sage.rings.invariants.invariant_theory.FormsBase object at ...>
|
|
324
|
+
"""
|
|
325
|
+
self._n = n
|
|
326
|
+
self._homogeneous = homogeneous
|
|
327
|
+
self._ring = ring
|
|
328
|
+
self._variables = variables
|
|
329
|
+
|
|
330
|
+
def _jacobian_determinant(self, *args):
|
|
331
|
+
"""
|
|
332
|
+
Return the Jacobian determinant.
|
|
333
|
+
|
|
334
|
+
INPUT:
|
|
335
|
+
|
|
336
|
+
- ``*args`` -- list of pairs of a polynomial and its
|
|
337
|
+
homogeneous degree. Must be a covariant, that is, polynomial
|
|
338
|
+
in the given :meth:`variables`
|
|
339
|
+
|
|
340
|
+
OUTPUT: the Jacobian determinant with respect to the variables
|
|
341
|
+
|
|
342
|
+
EXAMPLES::
|
|
343
|
+
|
|
344
|
+
sage: R.<x,y> = QQ[]
|
|
345
|
+
sage: from sage.rings.invariants.invariant_theory import FormsBase
|
|
346
|
+
sage: f = FormsBase(2, True, R, (x, y))
|
|
347
|
+
sage: f._jacobian_determinant((x^2+y^2, 2), (x*y, 2))
|
|
348
|
+
2*x^2 - 2*y^2
|
|
349
|
+
sage: f = FormsBase(2, False, R, (x, y))
|
|
350
|
+
sage: f._jacobian_determinant((x^2+1, 2), (x, 2))
|
|
351
|
+
2*x^2 - 2
|
|
352
|
+
|
|
353
|
+
sage: R.<x,y> = QQ[]
|
|
354
|
+
sage: cubic = invariant_theory.ternary_cubic(x^3+y^3+1)
|
|
355
|
+
sage: cubic.J_covariant()
|
|
356
|
+
x^6*y^3 - x^3*y^6 - x^6 + y^6 + x^3 - y^3
|
|
357
|
+
sage: 1 / 9 * cubic._jacobian_determinant(
|
|
358
|
+
....: [cubic.form(), 3], [cubic.Hessian(), 3], [cubic.Theta_covariant(), 6])
|
|
359
|
+
x^6*y^3 - x^3*y^6 - x^6 + y^6 + x^3 - y^3
|
|
360
|
+
"""
|
|
361
|
+
if self._homogeneous:
|
|
362
|
+
def diff(p, d):
|
|
363
|
+
return [p.derivative(x) for x in self._variables]
|
|
364
|
+
else:
|
|
365
|
+
def diff(p, d):
|
|
366
|
+
variables = self._variables[0:-1]
|
|
367
|
+
grad = [p.derivative(x) for x in variables]
|
|
368
|
+
dp_dz = d*p - sum(x*dp_dx for x, dp_dx in zip(variables, grad))
|
|
369
|
+
grad.append(dp_dz)
|
|
370
|
+
return grad
|
|
371
|
+
jac = [diff(p, d) for p, d in args]
|
|
372
|
+
return matrix(self._ring, jac).det()
|
|
373
|
+
|
|
374
|
+
def ring(self):
|
|
375
|
+
"""
|
|
376
|
+
Return the polynomial ring.
|
|
377
|
+
|
|
378
|
+
OUTPUT:
|
|
379
|
+
|
|
380
|
+
A polynomial ring. This is where the defining polynomial(s)
|
|
381
|
+
live. Note that the polynomials may be homogeneous or
|
|
382
|
+
inhomogeneous, depending on how the user constructed the
|
|
383
|
+
object.
|
|
384
|
+
|
|
385
|
+
EXAMPLES::
|
|
386
|
+
|
|
387
|
+
sage: R.<x,y,t> = QQ[]
|
|
388
|
+
sage: quartic = invariant_theory.binary_quartic(x^4 + y^4 + t*x^2*y^2, [x,y])
|
|
389
|
+
sage: quartic.ring()
|
|
390
|
+
Multivariate Polynomial Ring in x, y, t over Rational Field
|
|
391
|
+
|
|
392
|
+
sage: R.<x,y,t> = QQ[]
|
|
393
|
+
sage: quartic = invariant_theory.binary_quartic(x^4 + 1 + t*x^2, [x])
|
|
394
|
+
sage: quartic.ring()
|
|
395
|
+
Multivariate Polynomial Ring in x, y, t over Rational Field
|
|
396
|
+
"""
|
|
397
|
+
return self._ring
|
|
398
|
+
|
|
399
|
+
def variables(self):
|
|
400
|
+
"""
|
|
401
|
+
Return the variables of the form.
|
|
402
|
+
|
|
403
|
+
OUTPUT:
|
|
404
|
+
|
|
405
|
+
A tuple of variables. If inhomogeneous notation is used for the
|
|
406
|
+
defining polynomial then the last entry will be ``None``.
|
|
407
|
+
|
|
408
|
+
EXAMPLES::
|
|
409
|
+
|
|
410
|
+
sage: R.<x,y,t> = QQ[]
|
|
411
|
+
sage: quartic = invariant_theory.binary_quartic(x^4 + y^4 + t*x^2*y^2, [x,y])
|
|
412
|
+
sage: quartic.variables()
|
|
413
|
+
(x, y)
|
|
414
|
+
|
|
415
|
+
sage: R.<x,y,t> = QQ[]
|
|
416
|
+
sage: quartic = invariant_theory.binary_quartic(x^4 + 1 + t*x^2, [x])
|
|
417
|
+
sage: quartic.variables()
|
|
418
|
+
(x, None)
|
|
419
|
+
"""
|
|
420
|
+
return self._variables
|
|
421
|
+
|
|
422
|
+
def is_homogeneous(self):
|
|
423
|
+
"""
|
|
424
|
+
Return whether the forms were defined by homogeneous polynomials.
|
|
425
|
+
|
|
426
|
+
OUTPUT: boolean; whether the user originally defined the form via
|
|
427
|
+
homogeneous variables
|
|
428
|
+
|
|
429
|
+
EXAMPLES::
|
|
430
|
+
|
|
431
|
+
sage: R.<x,y,t> = QQ[]
|
|
432
|
+
sage: quartic = invariant_theory.binary_quartic(x^4 + y^4 + t*x^2*y^2, [x,y])
|
|
433
|
+
sage: quartic.is_homogeneous()
|
|
434
|
+
True
|
|
435
|
+
sage: quartic.form()
|
|
436
|
+
x^2*y^2*t + x^4 + y^4
|
|
437
|
+
|
|
438
|
+
sage: R.<x,y,t> = QQ[]
|
|
439
|
+
sage: quartic = invariant_theory.binary_quartic(x^4 + 1 + t*x^2, [x])
|
|
440
|
+
sage: quartic.is_homogeneous()
|
|
441
|
+
False
|
|
442
|
+
sage: quartic.form()
|
|
443
|
+
x^4 + x^2*t + 1
|
|
444
|
+
"""
|
|
445
|
+
return self._homogeneous
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
######################################################################
|
|
449
|
+
|
|
450
|
+
class AlgebraicForm(FormsBase):
|
|
451
|
+
"""
|
|
452
|
+
The base class of algebraic forms (i.e. homogeneous polynomials).
|
|
453
|
+
|
|
454
|
+
You should only instantiate the derived classes of this base
|
|
455
|
+
class.
|
|
456
|
+
|
|
457
|
+
Derived classes must implement ``coeffs()`` and
|
|
458
|
+
``scaled_coeffs()``
|
|
459
|
+
|
|
460
|
+
INPUT:
|
|
461
|
+
|
|
462
|
+
- ``n`` -- the number of variables
|
|
463
|
+
|
|
464
|
+
- ``d`` -- the degree of the polynomial
|
|
465
|
+
|
|
466
|
+
- ``polynomial`` -- the polynomial
|
|
467
|
+
|
|
468
|
+
- ``*args`` -- the variables, as a single list/tuple, multiple
|
|
469
|
+
arguments, or ``None`` to use all variables of the polynomial
|
|
470
|
+
|
|
471
|
+
Derived classes must implement the same arguments for the
|
|
472
|
+
constructor.
|
|
473
|
+
|
|
474
|
+
EXAMPLES::
|
|
475
|
+
|
|
476
|
+
sage: from sage.rings.invariants.invariant_theory import AlgebraicForm
|
|
477
|
+
sage: R.<x,y> = QQ[]
|
|
478
|
+
sage: p = x^2 + y^2
|
|
479
|
+
sage: AlgebraicForm(2, 2, p).variables()
|
|
480
|
+
(x, y)
|
|
481
|
+
sage: AlgebraicForm(2, 2, p, None).variables()
|
|
482
|
+
(x, y)
|
|
483
|
+
sage: AlgebraicForm(3, 2, p).variables()
|
|
484
|
+
(x, y, None)
|
|
485
|
+
sage: AlgebraicForm(3, 2, p, None).variables()
|
|
486
|
+
(x, y, None)
|
|
487
|
+
|
|
488
|
+
sage: from sage.rings.invariants.invariant_theory import AlgebraicForm
|
|
489
|
+
sage: R.<x,y,s,t> = QQ[]
|
|
490
|
+
sage: p = s*x^2 + t*y^2
|
|
491
|
+
sage: AlgebraicForm(2, 2, p, [x,y]).variables()
|
|
492
|
+
(x, y)
|
|
493
|
+
sage: AlgebraicForm(2, 2, p, x,y).variables()
|
|
494
|
+
(x, y)
|
|
495
|
+
|
|
496
|
+
sage: AlgebraicForm(3, 2, p, [x,y,None]).variables()
|
|
497
|
+
(x, y, None)
|
|
498
|
+
sage: AlgebraicForm(3, 2, p, x,y,None).variables()
|
|
499
|
+
(x, y, None)
|
|
500
|
+
|
|
501
|
+
sage: AlgebraicForm(2, 1, p, [x,y]).variables()
|
|
502
|
+
Traceback (most recent call last):
|
|
503
|
+
...
|
|
504
|
+
ValueError: polynomial is of the wrong degree
|
|
505
|
+
|
|
506
|
+
sage: AlgebraicForm(2, 2, x^2 + y, [x,y]).variables()
|
|
507
|
+
Traceback (most recent call last):
|
|
508
|
+
...
|
|
509
|
+
ValueError: polynomial is not homogeneous
|
|
510
|
+
"""
|
|
511
|
+
|
|
512
|
+
def __init__(self, n, d, polynomial, *args, **kwds):
|
|
513
|
+
"""
|
|
514
|
+
The Python constructor.
|
|
515
|
+
|
|
516
|
+
INPUT:
|
|
517
|
+
|
|
518
|
+
See the class documentation.
|
|
519
|
+
|
|
520
|
+
TESTS::
|
|
521
|
+
|
|
522
|
+
sage: from sage.rings.invariants.invariant_theory import AlgebraicForm
|
|
523
|
+
sage: R.<x,y> = QQ[]
|
|
524
|
+
sage: form = AlgebraicForm(2, 2, x^2 + y^2)
|
|
525
|
+
"""
|
|
526
|
+
self._d = d
|
|
527
|
+
self._polynomial = polynomial
|
|
528
|
+
variables = _guess_variables(polynomial, *args)
|
|
529
|
+
if len(variables) == n:
|
|
530
|
+
pass
|
|
531
|
+
elif len(variables) == n-1:
|
|
532
|
+
variables = variables + (None,)
|
|
533
|
+
else:
|
|
534
|
+
raise ValueError('need '+str(n)+' or ' +
|
|
535
|
+
str(n-1)+' variables, got '+str(variables))
|
|
536
|
+
ring = polynomial.parent()
|
|
537
|
+
homogeneous = variables[-1] is not None
|
|
538
|
+
super().__init__(n, homogeneous, ring, variables)
|
|
539
|
+
self._check()
|
|
540
|
+
|
|
541
|
+
def _check(self):
|
|
542
|
+
"""
|
|
543
|
+
Check that the input is of the correct degree and number of
|
|
544
|
+
variables.
|
|
545
|
+
|
|
546
|
+
EXAMPLES::
|
|
547
|
+
|
|
548
|
+
sage: from sage.rings.invariants.invariant_theory import AlgebraicForm
|
|
549
|
+
sage: R.<x,y,t> = QQ[]
|
|
550
|
+
sage: p = x^2 + y^2
|
|
551
|
+
sage: inv = AlgebraicForm(3, 2, p, [x,y,None])
|
|
552
|
+
sage: inv._check()
|
|
553
|
+
"""
|
|
554
|
+
degrees = set()
|
|
555
|
+
R = self._ring
|
|
556
|
+
if R.ngens() == 1:
|
|
557
|
+
degrees.update(self._polynomial.exponents())
|
|
558
|
+
else:
|
|
559
|
+
for e in self._polynomial.exponents():
|
|
560
|
+
deg = sum([ e[R.gens().index(x)]
|
|
561
|
+
for x in self._variables if x is not None ])
|
|
562
|
+
degrees.add(deg)
|
|
563
|
+
if self._homogeneous and len(degrees) > 1:
|
|
564
|
+
raise ValueError('polynomial is not homogeneous')
|
|
565
|
+
if degrees == set() or \
|
|
566
|
+
(self._homogeneous and degrees == set([self._d])) or \
|
|
567
|
+
(not self._homogeneous and max(degrees) <= self._d):
|
|
568
|
+
return
|
|
569
|
+
else:
|
|
570
|
+
raise ValueError('polynomial is of the wrong degree')
|
|
571
|
+
|
|
572
|
+
def _check_covariant(self, method_name, g=None, invariant=False):
|
|
573
|
+
r"""
|
|
574
|
+
Test whether ``method_name`` actually returns a covariant.
|
|
575
|
+
|
|
576
|
+
INPUT:
|
|
577
|
+
|
|
578
|
+
- ``method_name`` -- string; the name of the method that
|
|
579
|
+
returns the invariant / covariant to test
|
|
580
|
+
|
|
581
|
+
- ``g`` -- an `SL(n,\CC)` matrix or ``None`` (default). The
|
|
582
|
+
test will be to check that the covariant transforms
|
|
583
|
+
correctly under this special linear group element acting on
|
|
584
|
+
the homogeneous variables. If ``None``, a random matrix will
|
|
585
|
+
be picked.
|
|
586
|
+
|
|
587
|
+
- ``invariant`` -- boolean; whether to additionally test that
|
|
588
|
+
it is an invariant
|
|
589
|
+
|
|
590
|
+
EXAMPLES::
|
|
591
|
+
|
|
592
|
+
sage: R.<a0, a1, a2, a3, a4, x0, x1> = QQ[]
|
|
593
|
+
sage: p = a0*x1^4 + a1*x1^3*x0 + a2*x1^2*x0^2 + a3*x1*x0^3 + a4*x0^4
|
|
594
|
+
sage: quartic = invariant_theory.binary_quartic(p, x0, x1)
|
|
595
|
+
|
|
596
|
+
sage: quartic._check_covariant('EisensteinE', invariant=True)
|
|
597
|
+
sage: quartic._check_covariant('h_covariant')
|
|
598
|
+
|
|
599
|
+
sage: quartic._check_covariant('h_covariant', invariant=True) # not tested, known bug (see :issue:`32118`)
|
|
600
|
+
Traceback (most recent call last):
|
|
601
|
+
...
|
|
602
|
+
AssertionError: not invariant
|
|
603
|
+
"""
|
|
604
|
+
assert self._homogeneous
|
|
605
|
+
from sage.matrix.constructor import vector, random_matrix
|
|
606
|
+
if g is None:
|
|
607
|
+
F = self._ring.base_ring()
|
|
608
|
+
g = random_matrix(F, self._n, algorithm='unimodular')
|
|
609
|
+
v = vector(self.variables())
|
|
610
|
+
g_v = g * v
|
|
611
|
+
transform = {v[i]: g_v[i] for i in range(self._n)}
|
|
612
|
+
# The covariant of the transformed polynomial
|
|
613
|
+
g_self = self.__class__(self._n, self._d, self.form().subs(transform), self.variables())
|
|
614
|
+
cov_g = getattr(g_self, method_name)()
|
|
615
|
+
# The transform of the covariant
|
|
616
|
+
g_cov = getattr(self, method_name)().subs(transform)
|
|
617
|
+
# they must be the same
|
|
618
|
+
assert (g_cov - cov_g).is_zero(), 'not covariant'
|
|
619
|
+
if invariant:
|
|
620
|
+
cov = getattr(self, method_name)()
|
|
621
|
+
assert (cov - cov_g).is_zero(), 'not invariant'
|
|
622
|
+
|
|
623
|
+
def __richcmp__(self, other, op):
|
|
624
|
+
"""
|
|
625
|
+
Compare ``self`` with ``other``.
|
|
626
|
+
|
|
627
|
+
EXAMPLES::
|
|
628
|
+
|
|
629
|
+
sage: R.<x,y> = QQ[]
|
|
630
|
+
sage: quartic = invariant_theory.binary_quartic(x^4+y^4)
|
|
631
|
+
sage: quartic == 'foo'
|
|
632
|
+
False
|
|
633
|
+
sage: quartic == quartic
|
|
634
|
+
True
|
|
635
|
+
"""
|
|
636
|
+
if type(self) is not type(other):
|
|
637
|
+
return NotImplemented
|
|
638
|
+
return richcmp(self.coeffs(), other.coeffs(), op)
|
|
639
|
+
|
|
640
|
+
def _repr_(self):
|
|
641
|
+
"""
|
|
642
|
+
Return a string representation.
|
|
643
|
+
|
|
644
|
+
OUTPUT: string
|
|
645
|
+
|
|
646
|
+
EXAMPLES::
|
|
647
|
+
|
|
648
|
+
sage: R.<x,y> = QQ[]
|
|
649
|
+
sage: quartic = invariant_theory.binary_quartic(x^4 + y^4)
|
|
650
|
+
sage: quartic._repr_()
|
|
651
|
+
'Binary quartic with coefficients (1, 0, 0, 0, 1)'
|
|
652
|
+
|
|
653
|
+
sage: from sage.rings.invariants.invariant_theory import AlgebraicForm
|
|
654
|
+
sage: form = AlgebraicForm(2, 5, x^5 + y^5)
|
|
655
|
+
sage: form._repr_()
|
|
656
|
+
'Binary quintic given by x^5 + y^5'
|
|
657
|
+
"""
|
|
658
|
+
s = ''
|
|
659
|
+
ary = ['Unary', 'Binary', 'Ternary', 'Quaternary', 'Quinary',
|
|
660
|
+
'Senary', 'Septenary', 'Octonary', 'Nonary', 'Denary']
|
|
661
|
+
try:
|
|
662
|
+
s += ary[self._n-1]
|
|
663
|
+
except IndexError:
|
|
664
|
+
s += 'Algebraic'
|
|
665
|
+
ic = ['constant form', 'monic', 'quadratic', 'cubic', 'quartic', 'quintic',
|
|
666
|
+
'sextic', 'septimic', 'octavic', 'nonic', 'decimic',
|
|
667
|
+
'undecimic', 'duodecimic']
|
|
668
|
+
s += ' '
|
|
669
|
+
if self._d < 0:
|
|
670
|
+
s += 'form of degree {}'.format(self._d)
|
|
671
|
+
else:
|
|
672
|
+
try:
|
|
673
|
+
s += ic[self._d]
|
|
674
|
+
except IndexError:
|
|
675
|
+
s += 'form'
|
|
676
|
+
try:
|
|
677
|
+
s += ' with coefficients ' + str(self.coeffs())
|
|
678
|
+
except AttributeError:
|
|
679
|
+
s += ' given by ' + str(self.form())
|
|
680
|
+
return s
|
|
681
|
+
|
|
682
|
+
def form(self):
|
|
683
|
+
"""
|
|
684
|
+
Return the defining polynomial.
|
|
685
|
+
|
|
686
|
+
OUTPUT: the polynomial used to define the algebraic form
|
|
687
|
+
|
|
688
|
+
EXAMPLES::
|
|
689
|
+
|
|
690
|
+
sage: R.<x,y> = QQ[]
|
|
691
|
+
sage: quartic = invariant_theory.binary_quartic(x^4 + y^4)
|
|
692
|
+
sage: quartic.form()
|
|
693
|
+
x^4 + y^4
|
|
694
|
+
sage: quartic.polynomial()
|
|
695
|
+
x^4 + y^4
|
|
696
|
+
"""
|
|
697
|
+
return self._polynomial
|
|
698
|
+
|
|
699
|
+
polynomial = form
|
|
700
|
+
|
|
701
|
+
def homogenized(self, var='h'):
|
|
702
|
+
"""
|
|
703
|
+
Return form as defined by a homogeneous polynomial.
|
|
704
|
+
|
|
705
|
+
INPUT:
|
|
706
|
+
|
|
707
|
+
- ``var`` -- either a variable name, variable index or a
|
|
708
|
+
variable (default: ``'h'``)
|
|
709
|
+
|
|
710
|
+
OUTPUT:
|
|
711
|
+
|
|
712
|
+
The same algebraic form, but defined by a homogeneous
|
|
713
|
+
polynomial.
|
|
714
|
+
|
|
715
|
+
EXAMPLES::
|
|
716
|
+
|
|
717
|
+
sage: T.<t> = QQ[]
|
|
718
|
+
sage: quadratic = invariant_theory.binary_quadratic(t^2 + 2*t + 3)
|
|
719
|
+
sage: quadratic
|
|
720
|
+
Binary quadratic with coefficients (1, 3, 2)
|
|
721
|
+
sage: quadratic.homogenized()
|
|
722
|
+
Binary quadratic with coefficients (1, 3, 2)
|
|
723
|
+
sage: quadratic == quadratic.homogenized()
|
|
724
|
+
True
|
|
725
|
+
sage: quadratic.form()
|
|
726
|
+
t^2 + 2*t + 3
|
|
727
|
+
sage: quadratic.homogenized().form()
|
|
728
|
+
t^2 + 2*t*h + 3*h^2
|
|
729
|
+
|
|
730
|
+
sage: R.<x,y,z> = QQ[]
|
|
731
|
+
sage: quadratic = invariant_theory.ternary_quadratic(x^2 + 1, [x,y])
|
|
732
|
+
sage: quadratic.homogenized().form()
|
|
733
|
+
x^2 + h^2
|
|
734
|
+
|
|
735
|
+
sage: R.<x> = QQ[]
|
|
736
|
+
sage: quintic = invariant_theory.binary_quintic(x^4 + 1, x)
|
|
737
|
+
sage: quintic.homogenized().form()
|
|
738
|
+
x^4*h + h^5
|
|
739
|
+
"""
|
|
740
|
+
if self._homogeneous:
|
|
741
|
+
return self
|
|
742
|
+
try:
|
|
743
|
+
polynomial = self._polynomial.homogenize(var)
|
|
744
|
+
R = polynomial.parent()
|
|
745
|
+
variables = [R(_) for _ in self._variables[0:-1]] + [R(var)]
|
|
746
|
+
except AttributeError:
|
|
747
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
748
|
+
R = PolynomialRing(self._ring.base_ring(), [str(self._ring.gen(0)), str(var)])
|
|
749
|
+
polynomial = R(self._polynomial).homogenize(var)
|
|
750
|
+
variables = R.gens()
|
|
751
|
+
if polynomial.total_degree() < self._d:
|
|
752
|
+
k = self._d - polynomial.total_degree()
|
|
753
|
+
polynomial = polynomial * R(var)**k
|
|
754
|
+
return self.__class__(self._n, self._d, polynomial, variables)
|
|
755
|
+
|
|
756
|
+
def _extract_coefficients(self, monomials):
|
|
757
|
+
"""
|
|
758
|
+
Return the coefficients of ``monomials``.
|
|
759
|
+
|
|
760
|
+
INPUT:
|
|
761
|
+
|
|
762
|
+
- ``polynomial`` -- the input polynomial
|
|
763
|
+
|
|
764
|
+
- ``monomials`` -- list of all the monomials in the polynomial
|
|
765
|
+
ring; if less monomials are passed, an exception is thrown
|
|
766
|
+
|
|
767
|
+
OUTPUT:
|
|
768
|
+
|
|
769
|
+
A tuple containing the coefficients of the monomials in the given
|
|
770
|
+
polynomial.
|
|
771
|
+
|
|
772
|
+
EXAMPLES::
|
|
773
|
+
|
|
774
|
+
sage: from sage.rings.invariants.invariant_theory import AlgebraicForm
|
|
775
|
+
sage: R.<x,y,z,a30,a21,a12,a03,a20,a11,a02,a10,a01,a00> = QQ[]
|
|
776
|
+
sage: p = ( a30*x^3 + a21*x^2*y + a12*x*y^2 + a03*y^3 + a20*x^2*z +
|
|
777
|
+
....: a11*x*y*z + a02*y^2*z + a10*x*z^2 + a01*y*z^2 + a00*z^3 )
|
|
778
|
+
sage: base = AlgebraicForm(3, 3, p, [x,y,z])
|
|
779
|
+
sage: m = [x^3, y^3, z^3, x^2*y, x^2*z, x*y^2, y^2*z, x*z^2, y*z^2, x*y*z]
|
|
780
|
+
sage: base._extract_coefficients(m)
|
|
781
|
+
(a30, a03, a00, a21, a20, a12, a02, a10, a01, a11)
|
|
782
|
+
|
|
783
|
+
sage: base = AlgebraicForm(3, 3, p.subs(z=1), [x,y])
|
|
784
|
+
sage: m = [x^3, y^3, 1, x^2*y, x^2, x*y^2, y^2, x, y, x*y]
|
|
785
|
+
sage: base._extract_coefficients(m)
|
|
786
|
+
(a30, a03, a00, a21, a20, a12, a02, a10, a01, a11)
|
|
787
|
+
|
|
788
|
+
sage: T.<t> = QQ[]
|
|
789
|
+
sage: univariate = AlgebraicForm(2, 3, t^3 + 2*t^2 + 3*t + 4)
|
|
790
|
+
sage: m = [t^3, 1, t, t^2]
|
|
791
|
+
sage: univariate._extract_coefficients(m)
|
|
792
|
+
(1, 4, 3, 2)
|
|
793
|
+
sage: univariate._extract_coefficients(m[1:])
|
|
794
|
+
Traceback (most recent call last):
|
|
795
|
+
...
|
|
796
|
+
ValueError: less monomials were passed than the form actually has
|
|
797
|
+
|
|
798
|
+
TESTS:
|
|
799
|
+
|
|
800
|
+
Check for :issue:`30035`::
|
|
801
|
+
|
|
802
|
+
sage: R.<a,b,c> = QQ[]
|
|
803
|
+
sage: f = 3*a**3 + b**3 + a*b*c
|
|
804
|
+
sage: T = invariant_theory.ternary_cubic(f)
|
|
805
|
+
sage: T.S_invariant().parent()
|
|
806
|
+
Rational Field
|
|
807
|
+
"""
|
|
808
|
+
R = self._ring
|
|
809
|
+
Rgens = R.gens()
|
|
810
|
+
BR = R.base_ring()
|
|
811
|
+
if self._homogeneous:
|
|
812
|
+
variables = self._variables
|
|
813
|
+
else:
|
|
814
|
+
variables = self._variables[:-1]
|
|
815
|
+
indices = [Rgens.index(x) for x in variables]
|
|
816
|
+
|
|
817
|
+
if len(indices) == len(Rgens):
|
|
818
|
+
coeff_ring = BR
|
|
819
|
+
else:
|
|
820
|
+
coeff_ring = R
|
|
821
|
+
|
|
822
|
+
coeffs = {}
|
|
823
|
+
if len(Rgens) == 1:
|
|
824
|
+
# Univariate polynomials
|
|
825
|
+
|
|
826
|
+
def mono_to_tuple(mono):
|
|
827
|
+
return (R(mono).exponents()[0],)
|
|
828
|
+
|
|
829
|
+
def coeff_tuple_iter():
|
|
830
|
+
for i, c in enumerate(self._polynomial):
|
|
831
|
+
yield (c, (i,))
|
|
832
|
+
else:
|
|
833
|
+
# Multivariate polynomials, mixing variables and coefficients !
|
|
834
|
+
def mono_to_tuple(mono):
|
|
835
|
+
# mono is any monomial in the ring R
|
|
836
|
+
# keep only the exponents of true variables
|
|
837
|
+
mono = R(mono).exponents()[0]
|
|
838
|
+
return tuple(mono[i] for i in indices)
|
|
839
|
+
|
|
840
|
+
def mono_to_tuple_and_coeff(mono):
|
|
841
|
+
# mono is any monomial in the ring R
|
|
842
|
+
# separate the exponents of true variables
|
|
843
|
+
# and one coefficient monomial
|
|
844
|
+
mono = mono.exponents()[0]
|
|
845
|
+
true_mono = tuple(mono[i] for i in indices)
|
|
846
|
+
coeff_mono = list(mono)
|
|
847
|
+
for i in indices:
|
|
848
|
+
coeff_mono[i] = 0
|
|
849
|
+
return true_mono, R.monomial(*coeff_mono)
|
|
850
|
+
|
|
851
|
+
def coeff_tuple_iter():
|
|
852
|
+
for c, m in self._polynomial:
|
|
853
|
+
mono, coeff = mono_to_tuple_and_coeff(m)
|
|
854
|
+
yield coeff_ring(c * coeff), mono
|
|
855
|
+
|
|
856
|
+
for c, i in coeff_tuple_iter():
|
|
857
|
+
coeffs[i] = c + coeffs.pop(i, coeff_ring.zero())
|
|
858
|
+
result = tuple(coeffs.pop(mono_to_tuple(m), coeff_ring.zero()) for m in monomials)
|
|
859
|
+
if coeffs:
|
|
860
|
+
raise ValueError('less monomials were passed than the form actually has')
|
|
861
|
+
return result
|
|
862
|
+
|
|
863
|
+
def coefficients(self):
|
|
864
|
+
"""
|
|
865
|
+
Alias for ``coeffs()``.
|
|
866
|
+
|
|
867
|
+
See the documentation for ``coeffs()`` for details.
|
|
868
|
+
|
|
869
|
+
EXAMPLES::
|
|
870
|
+
|
|
871
|
+
sage: R.<a,b,c,d,e,f,g, x,y,z> = QQ[]
|
|
872
|
+
sage: p = a*x^2 + b*y^2 + c*z^2 + d*x*y + e*x*z + f*y*z
|
|
873
|
+
sage: q = invariant_theory.quadratic_form(p, x,y,z)
|
|
874
|
+
sage: q.coefficients()
|
|
875
|
+
(a, b, c, d, e, f)
|
|
876
|
+
sage: q.coeffs()
|
|
877
|
+
(a, b, c, d, e, f)
|
|
878
|
+
"""
|
|
879
|
+
return self.coeffs()
|
|
880
|
+
|
|
881
|
+
def transformed(self, g):
|
|
882
|
+
r"""
|
|
883
|
+
Return the image under a linear transformation of the variables.
|
|
884
|
+
|
|
885
|
+
INPUT:
|
|
886
|
+
|
|
887
|
+
- ``g`` -- a `GL(n,\CC)` matrix or a dictionary with the
|
|
888
|
+
variables as keys. A matrix is used to define the linear
|
|
889
|
+
transformation of homogeneous variables, a dictionary acts
|
|
890
|
+
by substitution of the variables.
|
|
891
|
+
|
|
892
|
+
OUTPUT:
|
|
893
|
+
|
|
894
|
+
A new instance of a subclass of :class:`AlgebraicForm`
|
|
895
|
+
obtained by replacing the variables of the homogeneous
|
|
896
|
+
polynomial by their image under ``g``.
|
|
897
|
+
|
|
898
|
+
EXAMPLES::
|
|
899
|
+
|
|
900
|
+
sage: R.<x,y,z> = QQ[]
|
|
901
|
+
sage: cubic = invariant_theory.ternary_cubic(x^3 + 2*y^3 + 3*z^3 + 4*x*y*z)
|
|
902
|
+
sage: cubic.transformed({x: y, y: z, z: x}).form()
|
|
903
|
+
3*x^3 + y^3 + 4*x*y*z + 2*z^3
|
|
904
|
+
sage: cyc = matrix([[0,1,0], [0,0,1], [1,0,0]])
|
|
905
|
+
sage: cubic.transformed(cyc) == cubic.transformed({x:y, y:z, z:x})
|
|
906
|
+
True
|
|
907
|
+
sage: g = matrix(QQ, [[1, 0, 0], [-1, 1, -3], [-5, -5, 16]])
|
|
908
|
+
sage: cubic.transformed(g)
|
|
909
|
+
Ternary cubic with coefficients (-356, -373, 12234, -1119, 3578, -1151,
|
|
910
|
+
3582, -11766, -11466, 7360)
|
|
911
|
+
sage: cubic.transformed(g).transformed(g.inverse()) == cubic
|
|
912
|
+
True
|
|
913
|
+
"""
|
|
914
|
+
if isinstance(g, dict):
|
|
915
|
+
transform = g
|
|
916
|
+
else:
|
|
917
|
+
from sage.modules.free_module_element import vector
|
|
918
|
+
v = vector(self._ring, self._variables)
|
|
919
|
+
g_v = vector(self._ring, g*v)
|
|
920
|
+
transform = {v[i]: g_v[i] for i in range(self._n)}
|
|
921
|
+
# The covariant of the transformed polynomial
|
|
922
|
+
return self.__class__(self._n, self._d,
|
|
923
|
+
self.form().subs(transform), self.variables())
|
|
924
|
+
|
|
925
|
+
|
|
926
|
+
######################################################################
|
|
927
|
+
|
|
928
|
+
class QuadraticForm(AlgebraicForm):
|
|
929
|
+
"""
|
|
930
|
+
Invariant theory of a multivariate quadratic form.
|
|
931
|
+
|
|
932
|
+
You should use the :class:`invariant_theory
|
|
933
|
+
<InvariantTheoryFactory>` factory object to construct instances
|
|
934
|
+
of this class. See :meth:`~InvariantTheoryFactory.quadratic_form`
|
|
935
|
+
for details.
|
|
936
|
+
|
|
937
|
+
TESTS::
|
|
938
|
+
|
|
939
|
+
sage: R.<a,b,c,d,e,f,g, x,y,z> = QQ[]
|
|
940
|
+
sage: p = a*x^2 + b*y^2 + c*z^2 + d*x*y + e*x*z + f*y*z
|
|
941
|
+
sage: invariant_theory.quadratic_form(p, x,y,z)
|
|
942
|
+
Ternary quadratic with coefficients (a, b, c, d, e, f)
|
|
943
|
+
sage: type(_)
|
|
944
|
+
<class 'sage.rings.invariants.invariant_theory.TernaryQuadratic'>
|
|
945
|
+
|
|
946
|
+
sage: R.<a,b,c,d,e,f,g, x,y,z> = QQ[]
|
|
947
|
+
sage: p = a*x^2 + b*y^2 + c*z^2 + d*x*y + e*x*z + f*y*z
|
|
948
|
+
sage: invariant_theory.quadratic_form(p, x,y,z)
|
|
949
|
+
Ternary quadratic with coefficients (a, b, c, d, e, f)
|
|
950
|
+
sage: type(_)
|
|
951
|
+
<class 'sage.rings.invariants.invariant_theory.TernaryQuadratic'>
|
|
952
|
+
|
|
953
|
+
Since we cannot always decide whether the form is homogeneous or
|
|
954
|
+
not based on the number of variables, you need to explicitly
|
|
955
|
+
specify it if you want the variables to be treated as
|
|
956
|
+
inhomogeneous::
|
|
957
|
+
|
|
958
|
+
sage: invariant_theory.inhomogeneous_quadratic_form(p.subs(z=1), x,y)
|
|
959
|
+
Ternary quadratic with coefficients (a, b, c, d, e, f)
|
|
960
|
+
"""
|
|
961
|
+
|
|
962
|
+
def __init__(self, n, d, polynomial, *args):
|
|
963
|
+
"""
|
|
964
|
+
The Python constructor.
|
|
965
|
+
|
|
966
|
+
TESTS::
|
|
967
|
+
|
|
968
|
+
sage: R.<x,y> = QQ[]
|
|
969
|
+
sage: from sage.rings.invariants.invariant_theory import QuadraticForm
|
|
970
|
+
sage: form = QuadraticForm(2, 2, x^2 + 2*y^2 + 3*x*y)
|
|
971
|
+
sage: form
|
|
972
|
+
Binary quadratic with coefficients (1, 2, 3)
|
|
973
|
+
sage: form._check_covariant('discriminant', invariant=True)
|
|
974
|
+
sage: QuadraticForm(3, 2, x^2 + y^2)
|
|
975
|
+
Ternary quadratic with coefficients (1, 1, 0, 0, 0, 0)
|
|
976
|
+
"""
|
|
977
|
+
assert d == 2
|
|
978
|
+
super().__init__(n, 2, polynomial, *args)
|
|
979
|
+
|
|
980
|
+
@classmethod
|
|
981
|
+
def from_invariants(cls, discriminant, x, z, *args, **kwargs):
|
|
982
|
+
"""
|
|
983
|
+
Construct a binary quadratic from its discriminant.
|
|
984
|
+
|
|
985
|
+
This function constructs a binary quadratic whose discriminant equal
|
|
986
|
+
the one provided as argument up to scaling.
|
|
987
|
+
|
|
988
|
+
INPUT:
|
|
989
|
+
|
|
990
|
+
- ``discriminant`` -- value of the discriminant used to reconstruct
|
|
991
|
+
the binary quadratic
|
|
992
|
+
|
|
993
|
+
OUTPUT: a QuadraticForm with 2 variables
|
|
994
|
+
|
|
995
|
+
EXAMPLES::
|
|
996
|
+
|
|
997
|
+
sage: R.<x,y> = QQ[]
|
|
998
|
+
sage: from sage.rings.invariants.invariant_theory import QuadraticForm
|
|
999
|
+
sage: QuadraticForm.from_invariants(1, x, y)
|
|
1000
|
+
Binary quadratic with coefficients (1, -1/4, 0)
|
|
1001
|
+
"""
|
|
1002
|
+
coeffs = reconstruction.binary_quadratic_coefficients_from_invariants(discriminant, *args, **kwargs)
|
|
1003
|
+
polynomial = sum([coeffs[i]*x**(2-i)*z**i for i in range(3)])
|
|
1004
|
+
return cls(2, 2, polynomial, *args)
|
|
1005
|
+
|
|
1006
|
+
@cached_method
|
|
1007
|
+
def monomials(self):
|
|
1008
|
+
"""
|
|
1009
|
+
List the basis monomials in the form.
|
|
1010
|
+
|
|
1011
|
+
OUTPUT:
|
|
1012
|
+
|
|
1013
|
+
A tuple of monomials. They are in the same order as
|
|
1014
|
+
:meth:`coeffs`.
|
|
1015
|
+
|
|
1016
|
+
EXAMPLES::
|
|
1017
|
+
|
|
1018
|
+
sage: R.<x,y> = QQ[]
|
|
1019
|
+
sage: quadratic = invariant_theory.quadratic_form(x^2 + y^2)
|
|
1020
|
+
sage: quadratic.monomials()
|
|
1021
|
+
(x^2, y^2, x*y)
|
|
1022
|
+
|
|
1023
|
+
sage: quadratic = invariant_theory.inhomogeneous_quadratic_form(x^2 + y^2)
|
|
1024
|
+
sage: quadratic.monomials()
|
|
1025
|
+
(x^2, y^2, 1, x*y, x, y)
|
|
1026
|
+
"""
|
|
1027
|
+
var = self._variables
|
|
1028
|
+
|
|
1029
|
+
def prod(a, b):
|
|
1030
|
+
if a is None and b is None:
|
|
1031
|
+
return self._ring.one()
|
|
1032
|
+
if a is None:
|
|
1033
|
+
return b
|
|
1034
|
+
if b is None:
|
|
1035
|
+
return a
|
|
1036
|
+
return a * b
|
|
1037
|
+
|
|
1038
|
+
squares = tuple(prod(x, x) for x in var)
|
|
1039
|
+
mixed = tuple([prod(var[i], var[j]) for i in range(self._n)
|
|
1040
|
+
for j in range(i + 1, self._n)])
|
|
1041
|
+
return squares + mixed
|
|
1042
|
+
|
|
1043
|
+
@cached_method
|
|
1044
|
+
def coeffs(self):
|
|
1045
|
+
r"""
|
|
1046
|
+
The coefficients of a quadratic form.
|
|
1047
|
+
|
|
1048
|
+
Given
|
|
1049
|
+
|
|
1050
|
+
.. MATH::
|
|
1051
|
+
|
|
1052
|
+
f(x) = \sum_{0\leq i<n} a_i x_i^2 + \sum_{0\leq j <k<n}
|
|
1053
|
+
a_{jk} x_j x_k
|
|
1054
|
+
|
|
1055
|
+
this function returns `a = (a_0, \dots, a_n, a_{00}, a_{01}, \dots, a_{n-1,n})`
|
|
1056
|
+
|
|
1057
|
+
EXAMPLES::
|
|
1058
|
+
|
|
1059
|
+
sage: R.<a,b,c,d,e,f,g, x,y,z> = QQ[]
|
|
1060
|
+
sage: p = a*x^2 + b*y^2 + c*z^2 + d*x*y + e*x*z + f*y*z
|
|
1061
|
+
sage: inv = invariant_theory.quadratic_form(p, x,y,z); inv
|
|
1062
|
+
Ternary quadratic with coefficients (a, b, c, d, e, f)
|
|
1063
|
+
sage: inv.coeffs()
|
|
1064
|
+
(a, b, c, d, e, f)
|
|
1065
|
+
sage: inv.scaled_coeffs()
|
|
1066
|
+
(a, b, c, 1/2*d, 1/2*e, 1/2*f)
|
|
1067
|
+
"""
|
|
1068
|
+
return self._extract_coefficients(self.monomials())
|
|
1069
|
+
|
|
1070
|
+
def scaled_coeffs(self):
|
|
1071
|
+
r"""
|
|
1072
|
+
The scaled coefficients of a quadratic form.
|
|
1073
|
+
|
|
1074
|
+
Given
|
|
1075
|
+
|
|
1076
|
+
.. MATH::
|
|
1077
|
+
|
|
1078
|
+
f(x) = \sum_{0\leq i<n} a_i x_i^2 + \sum_{0\leq j <k<n}
|
|
1079
|
+
2 a_{jk} x_j x_k
|
|
1080
|
+
|
|
1081
|
+
this function returns `a = (a_0, \cdots, a_n, a_{00}, a_{01}, \dots, a_{n-1,n})`
|
|
1082
|
+
|
|
1083
|
+
EXAMPLES::
|
|
1084
|
+
|
|
1085
|
+
sage: R.<a,b,c,d,e,f,g, x,y,z> = QQ[]
|
|
1086
|
+
sage: p = a*x^2 + b*y^2 + c*z^2 + d*x*y + e*x*z + f*y*z
|
|
1087
|
+
sage: inv = invariant_theory.quadratic_form(p, x,y,z); inv
|
|
1088
|
+
Ternary quadratic with coefficients (a, b, c, d, e, f)
|
|
1089
|
+
sage: inv.coeffs()
|
|
1090
|
+
(a, b, c, d, e, f)
|
|
1091
|
+
sage: inv.scaled_coeffs()
|
|
1092
|
+
(a, b, c, 1/2*d, 1/2*e, 1/2*f)
|
|
1093
|
+
"""
|
|
1094
|
+
coeff = self.coeffs()
|
|
1095
|
+
squares = coeff[0:self._n]
|
|
1096
|
+
mixed = tuple( c/2 for c in coeff[self._n:] )
|
|
1097
|
+
return squares + mixed
|
|
1098
|
+
|
|
1099
|
+
@cached_method
|
|
1100
|
+
def matrix(self):
|
|
1101
|
+
r"""
|
|
1102
|
+
Return the quadratic form as a symmetric matrix.
|
|
1103
|
+
|
|
1104
|
+
OUTPUT:
|
|
1105
|
+
|
|
1106
|
+
This method returns a symmetric matrix `A` such that the
|
|
1107
|
+
quadratic `Q` equals
|
|
1108
|
+
|
|
1109
|
+
.. MATH::
|
|
1110
|
+
|
|
1111
|
+
Q(x,y,z,\dots) = (x,y,\dots) A (x,y,\dots)^t
|
|
1112
|
+
|
|
1113
|
+
EXAMPLES::
|
|
1114
|
+
|
|
1115
|
+
sage: R.<x,y,z> = QQ[]
|
|
1116
|
+
sage: quadratic = invariant_theory.ternary_quadratic(x^2+y^2+z^2+x*y)
|
|
1117
|
+
sage: matrix(quadratic)
|
|
1118
|
+
[ 1 1/2 0]
|
|
1119
|
+
[1/2 1 0]
|
|
1120
|
+
[ 0 0 1]
|
|
1121
|
+
sage: quadratic._matrix_() == matrix(quadratic)
|
|
1122
|
+
True
|
|
1123
|
+
"""
|
|
1124
|
+
coeff = self.scaled_coeffs()
|
|
1125
|
+
A = matrix(self._ring, self._n)
|
|
1126
|
+
for i in range(self._n):
|
|
1127
|
+
A[i, i] = coeff[i]
|
|
1128
|
+
ij = self._n
|
|
1129
|
+
for i in range(self._n):
|
|
1130
|
+
for j in range(i+1, self._n):
|
|
1131
|
+
A[i, j] = coeff[ij]
|
|
1132
|
+
A[j, i] = coeff[ij]
|
|
1133
|
+
ij += 1
|
|
1134
|
+
return A
|
|
1135
|
+
|
|
1136
|
+
_matrix_ = matrix
|
|
1137
|
+
|
|
1138
|
+
def discriminant(self):
|
|
1139
|
+
"""
|
|
1140
|
+
Return the discriminant of the quadratic form.
|
|
1141
|
+
|
|
1142
|
+
Up to an overall constant factor, this is just the determinant
|
|
1143
|
+
of the defining matrix, see :meth:`matrix`. For a quadratic
|
|
1144
|
+
form in `n` variables, the overall constant is `2^{n-1}` if
|
|
1145
|
+
`n` is odd and `(-1)^{n/2} 2^n` if `n` is even.
|
|
1146
|
+
|
|
1147
|
+
EXAMPLES::
|
|
1148
|
+
|
|
1149
|
+
sage: R.<a,b,c, x,y> = QQ[]
|
|
1150
|
+
sage: p = a*x^2 + b*x*y + c*y^2
|
|
1151
|
+
sage: quadratic = invariant_theory.quadratic_form(p, x,y)
|
|
1152
|
+
sage: quadratic.discriminant()
|
|
1153
|
+
b^2 - 4*a*c
|
|
1154
|
+
|
|
1155
|
+
sage: R.<a,b,c,d,e,f,g, x,y,z> = QQ[]
|
|
1156
|
+
sage: p = a*x^2 + b*y^2 + c*z^2 + d*x*y + e*x*z + f*y*z
|
|
1157
|
+
sage: quadratic = invariant_theory.quadratic_form(p, x,y,z)
|
|
1158
|
+
sage: quadratic.discriminant()
|
|
1159
|
+
4*a*b*c - c*d^2 - b*e^2 + d*e*f - a*f^2
|
|
1160
|
+
"""
|
|
1161
|
+
from sage.misc.functional import is_odd
|
|
1162
|
+
A = 2*self._matrix_()
|
|
1163
|
+
if is_odd(self._n):
|
|
1164
|
+
return A.det() / 2
|
|
1165
|
+
else:
|
|
1166
|
+
return (-1)**(self._n//2) * A.det()
|
|
1167
|
+
|
|
1168
|
+
@cached_method
|
|
1169
|
+
def invariants(self, type='discriminant'):
|
|
1170
|
+
"""
|
|
1171
|
+
Return a tuple of invariants of a binary quadratic.
|
|
1172
|
+
|
|
1173
|
+
INPUT:
|
|
1174
|
+
|
|
1175
|
+
- ``type`` -- the type of invariants to return; the default choice
|
|
1176
|
+
is to return the discriminant
|
|
1177
|
+
|
|
1178
|
+
OUTPUT: the invariants of the binary quadratic
|
|
1179
|
+
|
|
1180
|
+
EXAMPLES::
|
|
1181
|
+
|
|
1182
|
+
sage: R.<x0, x1> = QQ[]
|
|
1183
|
+
sage: p = 2*x1^2 + 5*x0*x1 + 3*x0^2
|
|
1184
|
+
sage: quadratic = invariant_theory.binary_quadratic(p, x0, x1)
|
|
1185
|
+
sage: quadratic.invariants()
|
|
1186
|
+
(1,)
|
|
1187
|
+
sage: quadratic.invariants('unknown')
|
|
1188
|
+
Traceback (most recent call last):
|
|
1189
|
+
...
|
|
1190
|
+
ValueError: unknown type of invariants unknown for a binary quadratic
|
|
1191
|
+
"""
|
|
1192
|
+
if type == 'discriminant':
|
|
1193
|
+
return (self.discriminant(),)
|
|
1194
|
+
else:
|
|
1195
|
+
raise ValueError('unknown type of invariants {} for a binary'
|
|
1196
|
+
' quadratic'.format(type))
|
|
1197
|
+
|
|
1198
|
+
@cached_method
|
|
1199
|
+
def dual(self):
|
|
1200
|
+
"""
|
|
1201
|
+
Return the dual quadratic form.
|
|
1202
|
+
|
|
1203
|
+
OUTPUT:
|
|
1204
|
+
|
|
1205
|
+
A new quadratic form (with the same number of variables)
|
|
1206
|
+
defined by the adjoint matrix.
|
|
1207
|
+
|
|
1208
|
+
EXAMPLES::
|
|
1209
|
+
|
|
1210
|
+
sage: R.<a,b,c,x,y,z> = QQ[]
|
|
1211
|
+
sage: cubic = x^2+y^2+z^2
|
|
1212
|
+
sage: quadratic = invariant_theory.ternary_quadratic(a*x^2+b*y^2+c*z^2, [x,y,z])
|
|
1213
|
+
sage: quadratic.form()
|
|
1214
|
+
a*x^2 + b*y^2 + c*z^2
|
|
1215
|
+
sage: quadratic.dual().form()
|
|
1216
|
+
b*c*x^2 + a*c*y^2 + a*b*z^2
|
|
1217
|
+
|
|
1218
|
+
sage: R.<x,y,z, t> = QQ[]
|
|
1219
|
+
sage: cubic = x^2+y^2+z^2
|
|
1220
|
+
sage: quadratic = invariant_theory.ternary_quadratic(x^2+y^2+z^2 + t*x*y, [x,y,z])
|
|
1221
|
+
sage: quadratic.dual()
|
|
1222
|
+
Ternary quadratic with coefficients (1, 1, -1/4*t^2 + 1, -t, 0, 0)
|
|
1223
|
+
|
|
1224
|
+
sage: R.<x,y, t> = QQ[]
|
|
1225
|
+
sage: quadratic = invariant_theory.ternary_quadratic(x^2+y^2+1 + t*x*y, [x,y])
|
|
1226
|
+
sage: quadratic.dual()
|
|
1227
|
+
Ternary quadratic with coefficients (1, 1, -1/4*t^2 + 1, -t, 0, 0)
|
|
1228
|
+
|
|
1229
|
+
TESTS::
|
|
1230
|
+
|
|
1231
|
+
sage: R = PolynomialRing(QQ, 'a20,a11,a02,a10,a01,a00,x,y,z', order='lex')
|
|
1232
|
+
sage: R.inject_variables()
|
|
1233
|
+
Defining a20, a11, a02, a10, a01, a00, x, y, z
|
|
1234
|
+
sage: p = ( a20*x^2 + a11*x*y + a02*y^2 +
|
|
1235
|
+
....: a10*x*z + a01*y*z + a00*z^2 )
|
|
1236
|
+
sage: quadratic = invariant_theory.ternary_quadratic(p, x,y,z)
|
|
1237
|
+
sage: quadratic.dual().dual().form().factor()
|
|
1238
|
+
(1/4) *
|
|
1239
|
+
(a20*x^2 + a11*x*y + a02*y^2 + a10*x*z + a01*y*z + a00*z^2) *
|
|
1240
|
+
(4*a20*a02*a00 - a20*a01^2 - a11^2*a00 + a11*a10*a01 - a02*a10^2)
|
|
1241
|
+
|
|
1242
|
+
sage: R.<w,x,y,z> = QQ[]
|
|
1243
|
+
sage: q = invariant_theory.quaternary_quadratic(w^2+2*x^2+3*y^2+4*z^2+x*y+5*w*z)
|
|
1244
|
+
sage: q.form()
|
|
1245
|
+
w^2 + 2*x^2 + x*y + 3*y^2 + 5*w*z + 4*z^2
|
|
1246
|
+
sage: q.dual().dual().form().factor()
|
|
1247
|
+
(42849/256) * (w^2 + 2*x^2 + x*y + 3*y^2 + 5*w*z + 4*z^2)
|
|
1248
|
+
|
|
1249
|
+
sage: R.<x,y,z> = QQ[]
|
|
1250
|
+
sage: q = invariant_theory.quaternary_quadratic(1+2*x^2+3*y^2+4*z^2+x*y+5*z)
|
|
1251
|
+
sage: q.form()
|
|
1252
|
+
2*x^2 + x*y + 3*y^2 + 4*z^2 + 5*z + 1
|
|
1253
|
+
sage: q.dual().dual().form().factor()
|
|
1254
|
+
(42849/256) * (2*x^2 + x*y + 3*y^2 + 4*z^2 + 5*z + 1)
|
|
1255
|
+
"""
|
|
1256
|
+
A = self.matrix()
|
|
1257
|
+
Aadj = A.adjugate()
|
|
1258
|
+
if self._homogeneous:
|
|
1259
|
+
var = self._variables
|
|
1260
|
+
else:
|
|
1261
|
+
var = self._variables[0:-1] + (1, )
|
|
1262
|
+
n = self._n
|
|
1263
|
+
p = sum(Aadj[i, j] * var[i] * var[j] for i in range(n) for j in range(n))
|
|
1264
|
+
return invariant_theory.quadratic_form(p, self.variables())
|
|
1265
|
+
|
|
1266
|
+
def as_QuadraticForm(self):
|
|
1267
|
+
"""
|
|
1268
|
+
Convert into a :class:`~sage.quadratic_forms.quadratic_form.QuadraticForm`.
|
|
1269
|
+
|
|
1270
|
+
OUTPUT:
|
|
1271
|
+
|
|
1272
|
+
Sage has a special quadratic forms subsystem. This method
|
|
1273
|
+
converts ``self`` into this
|
|
1274
|
+
:class:`~sage.quadratic_forms.quadratic_form.QuadraticForm`
|
|
1275
|
+
representation.
|
|
1276
|
+
|
|
1277
|
+
EXAMPLES::
|
|
1278
|
+
|
|
1279
|
+
sage: R.<x,y,z> = QQ[]
|
|
1280
|
+
sage: p = x^2 + y^2 + z^2 + 2*x*y + 3*x*z
|
|
1281
|
+
sage: quadratic = invariant_theory.ternary_quadratic(p)
|
|
1282
|
+
sage: matrix(quadratic)
|
|
1283
|
+
[ 1 1 3/2]
|
|
1284
|
+
[ 1 1 0]
|
|
1285
|
+
[3/2 0 1]
|
|
1286
|
+
sage: quadratic.as_QuadraticForm()
|
|
1287
|
+
Quadratic form in 3 variables over Multivariate Polynomial
|
|
1288
|
+
Ring in x, y, z over Rational Field with coefficients:
|
|
1289
|
+
[ 1 2 3 ]
|
|
1290
|
+
[ * 1 0 ]
|
|
1291
|
+
[ * * 1 ]
|
|
1292
|
+
sage: _.polynomial('X,Y,Z')
|
|
1293
|
+
X^2 + 2*X*Y + Y^2 + 3*X*Z + Z^2
|
|
1294
|
+
"""
|
|
1295
|
+
R = self._ring
|
|
1296
|
+
B = 2*self._matrix_()
|
|
1297
|
+
import sage.quadratic_forms.quadratic_form
|
|
1298
|
+
return sage.quadratic_forms.quadratic_form.QuadraticForm(R, B)
|
|
1299
|
+
|
|
1300
|
+
|
|
1301
|
+
######################################################################
|
|
1302
|
+
|
|
1303
|
+
class BinaryQuartic(AlgebraicForm):
|
|
1304
|
+
"""
|
|
1305
|
+
Invariant theory of a binary quartic.
|
|
1306
|
+
|
|
1307
|
+
You should use the :class:`invariant_theory
|
|
1308
|
+
<InvariantTheoryFactory>` factory object to construct instances
|
|
1309
|
+
of this class. See :meth:`~InvariantTheoryFactory.binary_quartic`
|
|
1310
|
+
for details.
|
|
1311
|
+
|
|
1312
|
+
TESTS::
|
|
1313
|
+
|
|
1314
|
+
sage: R.<a0, a1, a2, a3, a4, x0, x1> = QQ[]
|
|
1315
|
+
sage: p = a0*x1^4 + a1*x1^3*x0 + a2*x1^2*x0^2 + a3*x1*x0^3 + a4*x0^4
|
|
1316
|
+
sage: quartic = invariant_theory.binary_quartic(p, x0, x1)
|
|
1317
|
+
sage: quartic._check_covariant('form')
|
|
1318
|
+
sage: quartic._check_covariant('EisensteinD', invariant=True)
|
|
1319
|
+
sage: quartic._check_covariant('EisensteinE', invariant=True)
|
|
1320
|
+
sage: quartic._check_covariant('g_covariant')
|
|
1321
|
+
sage: quartic._check_covariant('h_covariant')
|
|
1322
|
+
sage: TestSuite(quartic).run()
|
|
1323
|
+
"""
|
|
1324
|
+
|
|
1325
|
+
def __init__(self, n, d, polynomial, *args):
|
|
1326
|
+
"""
|
|
1327
|
+
The Python constructor.
|
|
1328
|
+
|
|
1329
|
+
TESTS::
|
|
1330
|
+
|
|
1331
|
+
sage: R.<x,y> = QQ[]
|
|
1332
|
+
sage: from sage.rings.invariants.invariant_theory import BinaryQuartic
|
|
1333
|
+
sage: BinaryQuartic(2, 4, x^4 + y^4)
|
|
1334
|
+
Binary quartic with coefficients (1, 0, 0, 0, 1)
|
|
1335
|
+
"""
|
|
1336
|
+
assert n == 2 and d == 4
|
|
1337
|
+
super().__init__(2, 4, polynomial, *args)
|
|
1338
|
+
self._x = self._variables[0]
|
|
1339
|
+
self._y = self._variables[1]
|
|
1340
|
+
|
|
1341
|
+
@cached_method
|
|
1342
|
+
def monomials(self):
|
|
1343
|
+
"""
|
|
1344
|
+
List the basis monomials in the form.
|
|
1345
|
+
|
|
1346
|
+
OUTPUT:
|
|
1347
|
+
|
|
1348
|
+
A tuple of monomials. They are in the same order as
|
|
1349
|
+
:meth:`coeffs`.
|
|
1350
|
+
|
|
1351
|
+
EXAMPLES::
|
|
1352
|
+
|
|
1353
|
+
sage: R.<x,y> = QQ[]
|
|
1354
|
+
sage: quartic = invariant_theory.binary_quartic(x^4 + y^4)
|
|
1355
|
+
sage: quartic.monomials()
|
|
1356
|
+
(y^4, x*y^3, x^2*y^2, x^3*y, x^4)
|
|
1357
|
+
"""
|
|
1358
|
+
x0 = self._x
|
|
1359
|
+
x1 = self._y
|
|
1360
|
+
if self._homogeneous:
|
|
1361
|
+
return (x1**4, x1**3*x0, x1**2*x0**2, x1*x0**3, x0**4)
|
|
1362
|
+
else:
|
|
1363
|
+
return (self._ring.one(), x0, x0**2, x0**3, x0**4)
|
|
1364
|
+
|
|
1365
|
+
@cached_method
|
|
1366
|
+
def coeffs(self):
|
|
1367
|
+
"""
|
|
1368
|
+
The coefficients of a binary quartic.
|
|
1369
|
+
|
|
1370
|
+
Given
|
|
1371
|
+
|
|
1372
|
+
.. MATH::
|
|
1373
|
+
|
|
1374
|
+
f(x) = a_0 x_1^4 + a_1 x_0 x_1^3 + a_2 x_0^2 x_1^2 +
|
|
1375
|
+
a_3 x_0^3 x_1 + a_4 x_0^4
|
|
1376
|
+
|
|
1377
|
+
this function returns `a = (a_0, a_1, a_2, a_3, a_4)`
|
|
1378
|
+
|
|
1379
|
+
EXAMPLES::
|
|
1380
|
+
|
|
1381
|
+
sage: R.<a0, a1, a2, a3, a4, x0, x1> = QQ[]
|
|
1382
|
+
sage: p = a0*x1^4 + a1*x1^3*x0 + a2*x1^2*x0^2 + a3*x1*x0^3 + a4*x0^4
|
|
1383
|
+
sage: quartic = invariant_theory.binary_quartic(p, x0, x1)
|
|
1384
|
+
sage: quartic.coeffs()
|
|
1385
|
+
(a0, a1, a2, a3, a4)
|
|
1386
|
+
|
|
1387
|
+
sage: R.<a0, a1, a2, a3, a4, x> = QQ[]
|
|
1388
|
+
sage: p = a0 + a1*x + a2*x^2 + a3*x^3 + a4*x^4
|
|
1389
|
+
sage: quartic = invariant_theory.binary_quartic(p, x)
|
|
1390
|
+
sage: quartic.coeffs()
|
|
1391
|
+
(a0, a1, a2, a3, a4)
|
|
1392
|
+
"""
|
|
1393
|
+
return self._extract_coefficients(self.monomials())
|
|
1394
|
+
|
|
1395
|
+
def scaled_coeffs(self):
|
|
1396
|
+
"""
|
|
1397
|
+
The coefficients of a binary quartic.
|
|
1398
|
+
|
|
1399
|
+
Given
|
|
1400
|
+
|
|
1401
|
+
.. MATH::
|
|
1402
|
+
|
|
1403
|
+
f(x) = a_0 x_1^4 + 4 a_1 x_0 x_1^3 + 6 a_2 x_0^2 x_1^2 +
|
|
1404
|
+
4 a_3 x_0^3 x_1 + a_4 x_0^4
|
|
1405
|
+
|
|
1406
|
+
this function returns `a = (a_0, a_1, a_2, a_3, a_4)`
|
|
1407
|
+
|
|
1408
|
+
EXAMPLES::
|
|
1409
|
+
|
|
1410
|
+
sage: R.<a0, a1, a2, a3, a4, x0, x1> = QQ[]
|
|
1411
|
+
sage: quartic = a0*x1^4 + 4*a1*x1^3*x0 + 6*a2*x1^2*x0^2 + 4*a3*x1*x0^3 + a4*x0^4
|
|
1412
|
+
sage: inv = invariant_theory.binary_quartic(quartic, x0, x1)
|
|
1413
|
+
sage: inv.scaled_coeffs()
|
|
1414
|
+
(a0, a1, a2, a3, a4)
|
|
1415
|
+
|
|
1416
|
+
sage: R.<a0, a1, a2, a3, a4, x> = QQ[]
|
|
1417
|
+
sage: quartic = a0 + 4*a1*x + 6*a2*x^2 + 4*a3*x^3 + a4*x^4
|
|
1418
|
+
sage: inv = invariant_theory.binary_quartic(quartic, x)
|
|
1419
|
+
sage: inv.scaled_coeffs()
|
|
1420
|
+
(a0, a1, a2, a3, a4)
|
|
1421
|
+
"""
|
|
1422
|
+
coeff = self.coeffs()
|
|
1423
|
+
return (coeff[0], coeff[1]/4, coeff[2]/6, coeff[3]/4, coeff[4])
|
|
1424
|
+
|
|
1425
|
+
@cached_method
|
|
1426
|
+
def EisensteinD(self):
|
|
1427
|
+
r"""
|
|
1428
|
+
One of the Eisenstein invariants of a binary quartic.
|
|
1429
|
+
|
|
1430
|
+
OUTPUT: the Eisenstein D-invariant of the quartic
|
|
1431
|
+
|
|
1432
|
+
.. MATH::
|
|
1433
|
+
|
|
1434
|
+
f(x) = a_0 x_1^4 + 4 a_1 x_0 x_1^3 + 6 a_2 x_0^2 x_1^2 +
|
|
1435
|
+
4 a_3 x_0^3 x_1 + a_4 x_0^4
|
|
1436
|
+
\\
|
|
1437
|
+
\Rightarrow
|
|
1438
|
+
D(f) = a_0 a_4+3 a_2^2-4 a_1 a_3
|
|
1439
|
+
|
|
1440
|
+
EXAMPLES::
|
|
1441
|
+
|
|
1442
|
+
sage: R.<a0, a1, a2, a3, a4, x0, x1> = QQ[]
|
|
1443
|
+
sage: f = a0*x1^4 + 4*a1*x0*x1^3 + 6*a2*x0^2*x1^2 + 4*a3*x0^3*x1 + a4*x0^4
|
|
1444
|
+
sage: inv = invariant_theory.binary_quartic(f, x0, x1)
|
|
1445
|
+
sage: inv.EisensteinD()
|
|
1446
|
+
3*a2^2 - 4*a1*a3 + a0*a4
|
|
1447
|
+
"""
|
|
1448
|
+
a = self.scaled_coeffs()
|
|
1449
|
+
assert len(a) == 5
|
|
1450
|
+
return a[0]*a[4]+3*a[2]**2-4*a[1]*a[3]
|
|
1451
|
+
|
|
1452
|
+
@cached_method
|
|
1453
|
+
def EisensteinE(self):
|
|
1454
|
+
r"""
|
|
1455
|
+
One of the Eisenstein invariants of a binary quartic.
|
|
1456
|
+
|
|
1457
|
+
OUTPUT: the Eisenstein E-invariant of the quartic
|
|
1458
|
+
|
|
1459
|
+
.. MATH::
|
|
1460
|
+
|
|
1461
|
+
f(x) = a_0 x_1^4 + 4 a_1 x_0 x_1^3 + 6 a_2 x_0^2 x_1^2 +
|
|
1462
|
+
4 a_3 x_0^3 x_1 + a_4 x_0^4
|
|
1463
|
+
\\ \Rightarrow
|
|
1464
|
+
E(f) = a_0 a_3^2 +a_1^2 a_4 -a_0 a_2 a_4
|
|
1465
|
+
-2 a_1 a_2 a_3 + a_2^3
|
|
1466
|
+
|
|
1467
|
+
EXAMPLES::
|
|
1468
|
+
|
|
1469
|
+
sage: R.<a0, a1, a2, a3, a4, x0, x1> = QQ[]
|
|
1470
|
+
sage: f = a0*x1^4 + 4*a1*x0*x1^3 + 6*a2*x0^2*x1^2 + 4*a3*x0^3*x1 + a4*x0^4
|
|
1471
|
+
sage: inv = invariant_theory.binary_quartic(f, x0, x1)
|
|
1472
|
+
sage: inv.EisensteinE()
|
|
1473
|
+
a2^3 - 2*a1*a2*a3 + a0*a3^2 + a1^2*a4 - a0*a2*a4
|
|
1474
|
+
"""
|
|
1475
|
+
a = self.scaled_coeffs()
|
|
1476
|
+
assert len(a) == 5
|
|
1477
|
+
return a[0]*a[3]**2 + a[1]**2*a[4] - a[0]*a[2]*a[4] - 2*a[1]*a[2]*a[3] + a[2]**3
|
|
1478
|
+
|
|
1479
|
+
@cached_method
|
|
1480
|
+
def g_covariant(self):
|
|
1481
|
+
r"""
|
|
1482
|
+
The g-covariant of a binary quartic.
|
|
1483
|
+
|
|
1484
|
+
OUTPUT: the g-covariant of the quartic
|
|
1485
|
+
|
|
1486
|
+
.. MATH::
|
|
1487
|
+
|
|
1488
|
+
f(x) = a_0 x_1^4 + 4 a_1 x_0 x_1^3 + 6 a_2 x_0^2 x_1^2 +
|
|
1489
|
+
4 a_3 x_0^3 x_1 + a_4 x_0^4
|
|
1490
|
+
\\
|
|
1491
|
+
\Rightarrow
|
|
1492
|
+
D(f) = \frac{1}{144}
|
|
1493
|
+
\begin{pmatrix}
|
|
1494
|
+
\frac{\partial^2 f}{\partial x \partial x}
|
|
1495
|
+
\end{pmatrix}
|
|
1496
|
+
|
|
1497
|
+
EXAMPLES::
|
|
1498
|
+
|
|
1499
|
+
sage: R.<a0, a1, a2, a3, a4, x, y> = QQ[]
|
|
1500
|
+
sage: p = a0*x^4 + 4*a1*x^3*y + 6*a2*x^2*y^2 + 4*a3*x*y^3 + a4*y^4
|
|
1501
|
+
sage: inv = invariant_theory.binary_quartic(p, x, y)
|
|
1502
|
+
sage: g = inv.g_covariant(); g
|
|
1503
|
+
a1^2*x^4 - a0*a2*x^4 + 2*a1*a2*x^3*y - 2*a0*a3*x^3*y + 3*a2^2*x^2*y^2
|
|
1504
|
+
- 2*a1*a3*x^2*y^2 - a0*a4*x^2*y^2 + 2*a2*a3*x*y^3
|
|
1505
|
+
- 2*a1*a4*x*y^3 + a3^2*y^4 - a2*a4*y^4
|
|
1506
|
+
|
|
1507
|
+
sage: inv_inhomogeneous = invariant_theory.binary_quartic(p.subs(y=1), x)
|
|
1508
|
+
sage: inv_inhomogeneous.g_covariant()
|
|
1509
|
+
a1^2*x^4 - a0*a2*x^4 + 2*a1*a2*x^3 - 2*a0*a3*x^3 + 3*a2^2*x^2
|
|
1510
|
+
- 2*a1*a3*x^2 - a0*a4*x^2 + 2*a2*a3*x - 2*a1*a4*x + a3^2 - a2*a4
|
|
1511
|
+
|
|
1512
|
+
sage: g == 1/144 * (p.derivative(x,y)^2 - p.derivative(x,x)*p.derivative(y,y))
|
|
1513
|
+
True
|
|
1514
|
+
"""
|
|
1515
|
+
a4, a3, a2, a1, a0 = self.scaled_coeffs()
|
|
1516
|
+
x0 = self._x
|
|
1517
|
+
x1 = self._y
|
|
1518
|
+
if self._homogeneous:
|
|
1519
|
+
xpow = [x0**4, x0**3 * x1, x0**2 * x1**2, x0 * x1**3, x1**4]
|
|
1520
|
+
else:
|
|
1521
|
+
xpow = [x0**4, x0**3, x0**2, x0, self._ring.one()]
|
|
1522
|
+
return (a1**2 - a0*a2)*xpow[0] + \
|
|
1523
|
+
(2*a1*a2 - 2*a0*a3)*xpow[1] + \
|
|
1524
|
+
(3*a2**2 - 2*a1*a3 - a0*a4)*xpow[2] + \
|
|
1525
|
+
(2*a2*a3 - 2*a1*a4)*xpow[3] + \
|
|
1526
|
+
(a3**2 - a2*a4)*xpow[4]
|
|
1527
|
+
|
|
1528
|
+
@cached_method
|
|
1529
|
+
def h_covariant(self):
|
|
1530
|
+
r"""
|
|
1531
|
+
The h-covariant of a binary quartic.
|
|
1532
|
+
|
|
1533
|
+
OUTPUT: the h-covariant of the quartic
|
|
1534
|
+
|
|
1535
|
+
.. MATH::
|
|
1536
|
+
|
|
1537
|
+
f(x) = a_0 x_1^4 + 4 a_1 x_0 x_1^3 + 6 a_2 x_0^2 x_1^2 +
|
|
1538
|
+
4 a_3 x_0^3 x_1 + a_4 x_0^4
|
|
1539
|
+
\\
|
|
1540
|
+
\Rightarrow
|
|
1541
|
+
D(f) = \frac{1}{144}
|
|
1542
|
+
\begin{pmatrix}
|
|
1543
|
+
\frac{\partial^2 f}{\partial x \partial x}
|
|
1544
|
+
\end{pmatrix}
|
|
1545
|
+
|
|
1546
|
+
EXAMPLES::
|
|
1547
|
+
|
|
1548
|
+
sage: R.<a0, a1, a2, a3, a4, x, y> = QQ[]
|
|
1549
|
+
sage: p = a0*x^4 + 4*a1*x^3*y + 6*a2*x^2*y^2 + 4*a3*x*y^3 + a4*y^4
|
|
1550
|
+
sage: inv = invariant_theory.binary_quartic(p, x, y)
|
|
1551
|
+
sage: h = inv.h_covariant(); h
|
|
1552
|
+
-2*a1^3*x^6 + 3*a0*a1*a2*x^6 - a0^2*a3*x^6 - 6*a1^2*a2*x^5*y + 9*a0*a2^2*x^5*y
|
|
1553
|
+
- 2*a0*a1*a3*x^5*y - a0^2*a4*x^5*y - 10*a1^2*a3*x^4*y^2 + 15*a0*a2*a3*x^4*y^2
|
|
1554
|
+
- 5*a0*a1*a4*x^4*y^2 + 10*a0*a3^2*x^3*y^3 - 10*a1^2*a4*x^3*y^3
|
|
1555
|
+
+ 10*a1*a3^2*x^2*y^4 - 15*a1*a2*a4*x^2*y^4 + 5*a0*a3*a4*x^2*y^4
|
|
1556
|
+
+ 6*a2*a3^2*x*y^5 - 9*a2^2*a4*x*y^5 + 2*a1*a3*a4*x*y^5 + a0*a4^2*x*y^5
|
|
1557
|
+
+ 2*a3^3*y^6 - 3*a2*a3*a4*y^6 + a1*a4^2*y^6
|
|
1558
|
+
|
|
1559
|
+
sage: inv_inhomogeneous = invariant_theory.binary_quartic(p.subs(y=1), x)
|
|
1560
|
+
sage: inv_inhomogeneous.h_covariant()
|
|
1561
|
+
-2*a1^3*x^6 + 3*a0*a1*a2*x^6 - a0^2*a3*x^6 - 6*a1^2*a2*x^5 + 9*a0*a2^2*x^5
|
|
1562
|
+
- 2*a0*a1*a3*x^5 - a0^2*a4*x^5 - 10*a1^2*a3*x^4 + 15*a0*a2*a3*x^4
|
|
1563
|
+
- 5*a0*a1*a4*x^4 + 10*a0*a3^2*x^3 - 10*a1^2*a4*x^3 + 10*a1*a3^2*x^2
|
|
1564
|
+
- 15*a1*a2*a4*x^2 + 5*a0*a3*a4*x^2 + 6*a2*a3^2*x - 9*a2^2*a4*x
|
|
1565
|
+
+ 2*a1*a3*a4*x + a0*a4^2*x + 2*a3^3 - 3*a2*a3*a4 + a1*a4^2
|
|
1566
|
+
|
|
1567
|
+
sage: g = inv.g_covariant()
|
|
1568
|
+
sage: h == 1/8 * (p.derivative(x)*g.derivative(y) - p.derivative(y)*g.derivative(x))
|
|
1569
|
+
True
|
|
1570
|
+
"""
|
|
1571
|
+
a0, a1, a2, a3, a4 = self.scaled_coeffs()
|
|
1572
|
+
x0 = self._x
|
|
1573
|
+
x1 = self._y
|
|
1574
|
+
if self._homogeneous:
|
|
1575
|
+
xpow = [x0**6, x0**5 * x1, x0**4 * x1**2, x0**3 * x1**3,
|
|
1576
|
+
x0**2 * x1**4, x0 * x1**5, x1**6]
|
|
1577
|
+
else:
|
|
1578
|
+
xpow = [x0**6, x0**5, x0**4, x0**3, x0**2, x0, x0.parent().one()]
|
|
1579
|
+
return (-2*a3**3 + 3*a2*a3*a4 - a1*a4**2) * xpow[0] + \
|
|
1580
|
+
(-6*a2*a3**2 + 9*a2**2*a4 - 2*a1*a3*a4 - a0*a4**2) * xpow[1] + \
|
|
1581
|
+
5 * (-2*a1*a3**2 + 3*a1*a2*a4 - a0*a3*a4) * xpow[2] + \
|
|
1582
|
+
10 * (-a0*a3**2 + a1**2*a4) * xpow[3] + \
|
|
1583
|
+
5 * (2*a1**2*a3 - 3*a0*a2*a3 + a0*a1*a4) * xpow[4] + \
|
|
1584
|
+
(6*a1**2*a2 - 9*a0*a2**2 + 2*a0*a1*a3 + a0**2*a4) * xpow[5] + \
|
|
1585
|
+
(2*a1**3 - 3*a0*a1*a2 + a0**2*a3) * xpow[6]
|
|
1586
|
+
|
|
1587
|
+
|
|
1588
|
+
######################################################################
|
|
1589
|
+
|
|
1590
|
+
class BinaryQuintic(AlgebraicForm):
|
|
1591
|
+
"""
|
|
1592
|
+
Invariant theory of a binary quintic form.
|
|
1593
|
+
|
|
1594
|
+
You should use the :class:`invariant_theory
|
|
1595
|
+
<InvariantTheoryFactory>` factory object to construct instances
|
|
1596
|
+
of this class. See :meth:`~InvariantTheoryFactory.binary_quintic`
|
|
1597
|
+
for details.
|
|
1598
|
+
|
|
1599
|
+
REFERENCES:
|
|
1600
|
+
|
|
1601
|
+
For a description of all invariants and covariants of a binary
|
|
1602
|
+
quintic, see section 73 of [Cle1872]_.
|
|
1603
|
+
|
|
1604
|
+
TESTS::
|
|
1605
|
+
|
|
1606
|
+
sage: R.<a0, a1, a2, a3, a4, a5, x0, x1> = QQ[]
|
|
1607
|
+
sage: p = a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5
|
|
1608
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
1609
|
+
sage: quintic._check_covariant('form')
|
|
1610
|
+
sage: quintic._check_covariant('A_invariant', invariant=True)
|
|
1611
|
+
sage: quintic._check_covariant('B_invariant', invariant=True)
|
|
1612
|
+
sage: quintic._check_covariant('C_invariant', invariant=True)
|
|
1613
|
+
sage: quintic._check_covariant('R_invariant', invariant=True)
|
|
1614
|
+
sage: quintic._check_covariant('H_covariant')
|
|
1615
|
+
sage: quintic._check_covariant('i_covariant')
|
|
1616
|
+
sage: quintic._check_covariant('T_covariant')
|
|
1617
|
+
sage: quintic._check_covariant('j_covariant')
|
|
1618
|
+
sage: quintic._check_covariant('tau_covariant')
|
|
1619
|
+
sage: quintic._check_covariant('theta_covariant')
|
|
1620
|
+
sage: quintic._check_covariant('alpha_covariant')
|
|
1621
|
+
sage: quintic._check_covariant('beta_covariant')
|
|
1622
|
+
sage: quintic._check_covariant('gamma_covariant')
|
|
1623
|
+
sage: quintic._check_covariant('delta_covariant')
|
|
1624
|
+
sage: TestSuite(quintic).run()
|
|
1625
|
+
|
|
1626
|
+
Testing that more general coefficient rings also work as expected::
|
|
1627
|
+
|
|
1628
|
+
sage: R.<a0,a1,a2,a3,a4,a5> = QQ[]
|
|
1629
|
+
sage: S.<x,y> = R[]
|
|
1630
|
+
sage: p = a0*x^5+a1*x^4*y+a2*x^3*y^2+a3*x^2*y^3+a4*x*y^4+a5*y^5
|
|
1631
|
+
sage: quintic = invariant_theory.binary_quintic(p)
|
|
1632
|
+
sage: quintic.i_covariant()
|
|
1633
|
+
(3/50*a2^2 - 4/25*a1*a3 + 2/5*a0*a4)*x^2 + (1/25*a2*a3 - 6/25*a1*a4
|
|
1634
|
+
+ 2*a0*a5)*x*y + (3/50*a3^2 - 4/25*a2*a4 + 2/5*a1*a5)*y^2
|
|
1635
|
+
"""
|
|
1636
|
+
|
|
1637
|
+
def __init__(self, n, d, polynomial, *args):
|
|
1638
|
+
"""
|
|
1639
|
+
The Python constructor.
|
|
1640
|
+
|
|
1641
|
+
TESTS::
|
|
1642
|
+
|
|
1643
|
+
sage: R.<x,y> = QQ[]
|
|
1644
|
+
sage: from sage.rings.invariants.invariant_theory import BinaryQuintic
|
|
1645
|
+
sage: BinaryQuintic(2, 5, x^5+2*x^3*y^2+3*x*y^4)
|
|
1646
|
+
Binary quintic with coefficients (0, 3, 0, 2, 0, 1)
|
|
1647
|
+
"""
|
|
1648
|
+
assert n == 2 and d == 5
|
|
1649
|
+
super().__init__(2, 5, polynomial, *args)
|
|
1650
|
+
self._x = self._variables[0]
|
|
1651
|
+
self._y = self._variables[1]
|
|
1652
|
+
|
|
1653
|
+
@classmethod
|
|
1654
|
+
def from_invariants(cls, invariants, x, z, *args, **kwargs):
|
|
1655
|
+
"""
|
|
1656
|
+
Construct a binary quintic from its invariants.
|
|
1657
|
+
|
|
1658
|
+
This function constructs a binary quintic whose invariants equal
|
|
1659
|
+
the ones provided as argument up to scaling.
|
|
1660
|
+
|
|
1661
|
+
INPUT:
|
|
1662
|
+
|
|
1663
|
+
- ``invariants`` -- list or tuple of invariants that are used to
|
|
1664
|
+
reconstruct the binary quintic
|
|
1665
|
+
|
|
1666
|
+
OUTPUT: a BinaryQuintic
|
|
1667
|
+
|
|
1668
|
+
EXAMPLES::
|
|
1669
|
+
|
|
1670
|
+
sage: R.<x,y> = QQ[]
|
|
1671
|
+
sage: from sage.rings.invariants.invariant_theory import BinaryQuintic
|
|
1672
|
+
sage: BinaryQuintic.from_invariants([3,6,12], x, y)
|
|
1673
|
+
Binary quintic with coefficients (0, 1, 0, 0, 1, 0)
|
|
1674
|
+
"""
|
|
1675
|
+
coeffs = reconstruction.binary_quintic_coefficients_from_invariants(invariants, *args, **kwargs)
|
|
1676
|
+
polynomial = sum([coeffs[i]*x**i*z**(5-i) for i in range(6)])
|
|
1677
|
+
return cls(2, 5, polynomial, *args)
|
|
1678
|
+
|
|
1679
|
+
@cached_method
|
|
1680
|
+
def monomials(self):
|
|
1681
|
+
"""
|
|
1682
|
+
List the basis monomials of the form.
|
|
1683
|
+
|
|
1684
|
+
This function lists a basis of monomials of the space of binary
|
|
1685
|
+
quintics of which this form is an element.
|
|
1686
|
+
|
|
1687
|
+
OUTPUT:
|
|
1688
|
+
|
|
1689
|
+
A tuple of monomials. They are in the same order as
|
|
1690
|
+
:meth:`coeffs`.
|
|
1691
|
+
|
|
1692
|
+
EXAMPLES::
|
|
1693
|
+
|
|
1694
|
+
sage: R.<x,y> = QQ[]
|
|
1695
|
+
sage: quintic = invariant_theory.binary_quintic(x^5 + y^5)
|
|
1696
|
+
sage: quintic.monomials()
|
|
1697
|
+
(y^5, x*y^4, x^2*y^3, x^3*y^2, x^4*y, x^5)
|
|
1698
|
+
"""
|
|
1699
|
+
x0 = self._x
|
|
1700
|
+
x1 = self._y
|
|
1701
|
+
if self._homogeneous:
|
|
1702
|
+
return (x1**5, x1**4*x0, x1**3*x0**2, x1**2*x0**3, x1*x0**4, x0**5)
|
|
1703
|
+
else:
|
|
1704
|
+
return (self._ring.one(), x0, x0**2, x0**3, x0**4, x0**5)
|
|
1705
|
+
|
|
1706
|
+
@cached_method
|
|
1707
|
+
def coeffs(self):
|
|
1708
|
+
"""
|
|
1709
|
+
The coefficients of a binary quintic.
|
|
1710
|
+
|
|
1711
|
+
Given
|
|
1712
|
+
|
|
1713
|
+
.. MATH::
|
|
1714
|
+
|
|
1715
|
+
f(x) = a_0 x_1^5 + a_1 x_0 x_1^4 + a_2 x_0^2 x_1^3 +
|
|
1716
|
+
a_3 x_0^3 x_1^2 + a_4 x_0^4 x_1 + a_5 x_1^5
|
|
1717
|
+
|
|
1718
|
+
this function returns `a = (a_0, a_1, a_2, a_3, a_4, a_5)`
|
|
1719
|
+
|
|
1720
|
+
EXAMPLES::
|
|
1721
|
+
|
|
1722
|
+
sage: R.<a0, a1, a2, a3, a4, a5, x0, x1> = QQ[]
|
|
1723
|
+
sage: p = a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5
|
|
1724
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
1725
|
+
sage: quintic.coeffs()
|
|
1726
|
+
(a0, a1, a2, a3, a4, a5)
|
|
1727
|
+
|
|
1728
|
+
sage: R.<a0, a1, a2, a3, a4, a5, x> = QQ[]
|
|
1729
|
+
sage: p = a0 + a1*x + a2*x^2 + a3*x^3 + a4*x^4 + a5*x^5
|
|
1730
|
+
sage: quintic = invariant_theory.binary_quintic(p, x)
|
|
1731
|
+
sage: quintic.coeffs()
|
|
1732
|
+
(a0, a1, a2, a3, a4, a5)
|
|
1733
|
+
"""
|
|
1734
|
+
return self._extract_coefficients(self.monomials())
|
|
1735
|
+
|
|
1736
|
+
def scaled_coeffs(self):
|
|
1737
|
+
"""
|
|
1738
|
+
The coefficients of a binary quintic.
|
|
1739
|
+
|
|
1740
|
+
Given
|
|
1741
|
+
|
|
1742
|
+
.. MATH::
|
|
1743
|
+
|
|
1744
|
+
f(x) = a_0 x_1^5 + 5 a_1 x_0 x_1^4 + 10 a_2 x_0^2 x_1^3 +
|
|
1745
|
+
10 a_3 x_0^3 x_1^2 + 5 a_4 x_0^4 x_1 + a_5 x_1^5
|
|
1746
|
+
|
|
1747
|
+
this function returns `a = (a_0, a_1, a_2, a_3, a_4, a_5)`
|
|
1748
|
+
|
|
1749
|
+
EXAMPLES::
|
|
1750
|
+
|
|
1751
|
+
sage: R.<a0, a1, a2, a3, a4, a5, x0, x1> = QQ[]
|
|
1752
|
+
sage: p = a0*x1^5 + 5*a1*x1^4*x0 + 10*a2*x1^3*x0^2 + 10*a3*x1^2*x0^3 + 5*a4*x1*x0^4 + a5*x0^5
|
|
1753
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
1754
|
+
sage: quintic.scaled_coeffs()
|
|
1755
|
+
(a0, a1, a2, a3, a4, a5)
|
|
1756
|
+
|
|
1757
|
+
sage: R.<a0, a1, a2, a3, a4, a5, x> = QQ[]
|
|
1758
|
+
sage: p = a0 + 5*a1*x + 10*a2*x^2 + 10*a3*x^3 + 5*a4*x^4 + a5*x^5
|
|
1759
|
+
sage: quintic = invariant_theory.binary_quintic(p, x)
|
|
1760
|
+
sage: quintic.scaled_coeffs()
|
|
1761
|
+
(a0, a1, a2, a3, a4, a5)
|
|
1762
|
+
"""
|
|
1763
|
+
coeff = self.coeffs()
|
|
1764
|
+
return (coeff[0], coeff[1] / 5, coeff[2] / 10, coeff[3] / 10,
|
|
1765
|
+
coeff[4] / 5, coeff[5])
|
|
1766
|
+
|
|
1767
|
+
@cached_method
|
|
1768
|
+
def H_covariant(self, as_form=False):
|
|
1769
|
+
"""
|
|
1770
|
+
Return the covariant `H` of a binary quintic.
|
|
1771
|
+
|
|
1772
|
+
INPUT:
|
|
1773
|
+
|
|
1774
|
+
- ``as_form`` -- if ``as_form`` is ``False``, the result will be returned
|
|
1775
|
+
as polynomial (default). If it is ``True`` the result is returned as
|
|
1776
|
+
an object of the class :class:`AlgebraicForm`.
|
|
1777
|
+
|
|
1778
|
+
OUTPUT: the `H`-covariant of the binary quintic as polynomial or as binary form
|
|
1779
|
+
|
|
1780
|
+
EXAMPLES::
|
|
1781
|
+
|
|
1782
|
+
sage: R.<a0, a1, a2, a3, a4, a5, x0, x1> = QQ[]
|
|
1783
|
+
sage: p = a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5
|
|
1784
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
1785
|
+
sage: quintic.H_covariant()
|
|
1786
|
+
-2/25*a4^2*x0^6 + 1/5*a3*a5*x0^6 - 3/25*a3*a4*x0^5*x1
|
|
1787
|
+
+ 3/5*a2*a5*x0^5*x1 - 3/25*a3^2*x0^4*x1^2 + 3/25*a2*a4*x0^4*x1^2
|
|
1788
|
+
+ 6/5*a1*a5*x0^4*x1^2 - 4/25*a2*a3*x0^3*x1^3 + 14/25*a1*a4*x0^3*x1^3
|
|
1789
|
+
+ 2*a0*a5*x0^3*x1^3 - 3/25*a2^2*x0^2*x1^4 + 3/25*a1*a3*x0^2*x1^4
|
|
1790
|
+
+ 6/5*a0*a4*x0^2*x1^4 - 3/25*a1*a2*x0*x1^5 + 3/5*a0*a3*x0*x1^5
|
|
1791
|
+
- 2/25*a1^2*x1^6 + 1/5*a0*a2*x1^6
|
|
1792
|
+
|
|
1793
|
+
sage: quintic.H_covariant(as_form=True)
|
|
1794
|
+
Binary sextic given by ...
|
|
1795
|
+
"""
|
|
1796
|
+
cov = transvectant(self, self, 2)
|
|
1797
|
+
if as_form:
|
|
1798
|
+
return cov
|
|
1799
|
+
else:
|
|
1800
|
+
return cov.polynomial()
|
|
1801
|
+
|
|
1802
|
+
@cached_method
|
|
1803
|
+
def i_covariant(self, as_form=False):
|
|
1804
|
+
"""
|
|
1805
|
+
Return the covariant `i` of a binary quintic.
|
|
1806
|
+
|
|
1807
|
+
INPUT:
|
|
1808
|
+
|
|
1809
|
+
- ``as_form`` -- if ``as_form`` is ``False``, the result will be returned
|
|
1810
|
+
as polynomial (default). If it is ``True`` the result is returned as
|
|
1811
|
+
an object of the class :class:`AlgebraicForm`.
|
|
1812
|
+
|
|
1813
|
+
OUTPUT: the `i`-covariant of the binary quintic as polynomial or as binary form
|
|
1814
|
+
|
|
1815
|
+
EXAMPLES::
|
|
1816
|
+
|
|
1817
|
+
sage: R.<a0, a1, a2, a3, a4, a5, x0, x1> = QQ[]
|
|
1818
|
+
sage: p = a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5
|
|
1819
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
1820
|
+
sage: quintic.i_covariant()
|
|
1821
|
+
3/50*a3^2*x0^2 - 4/25*a2*a4*x0^2 + 2/5*a1*a5*x0^2 + 1/25*a2*a3*x0*x1
|
|
1822
|
+
- 6/25*a1*a4*x0*x1 + 2*a0*a5*x0*x1 + 3/50*a2^2*x1^2 - 4/25*a1*a3*x1^2
|
|
1823
|
+
+ 2/5*a0*a4*x1^2
|
|
1824
|
+
|
|
1825
|
+
sage: quintic.i_covariant(as_form=True)
|
|
1826
|
+
Binary quadratic given by ...
|
|
1827
|
+
"""
|
|
1828
|
+
cov = transvectant(self, self, 4)
|
|
1829
|
+
if as_form:
|
|
1830
|
+
return cov
|
|
1831
|
+
else:
|
|
1832
|
+
return cov.polynomial()
|
|
1833
|
+
|
|
1834
|
+
@cached_method
|
|
1835
|
+
def T_covariant(self, as_form=False):
|
|
1836
|
+
"""
|
|
1837
|
+
Return the covariant `T` of a binary quintic.
|
|
1838
|
+
|
|
1839
|
+
INPUT:
|
|
1840
|
+
|
|
1841
|
+
- ``as_form`` -- if ``as_form`` is ``False``, the result will be returned
|
|
1842
|
+
as polynomial (default). If it is ``True`` the result is returned as
|
|
1843
|
+
an object of the class :class:`AlgebraicForm`.
|
|
1844
|
+
|
|
1845
|
+
OUTPUT: the `T`-covariant of the binary quintic as polynomial or as binary form
|
|
1846
|
+
|
|
1847
|
+
EXAMPLES::
|
|
1848
|
+
|
|
1849
|
+
sage: R.<a0, a1, a2, a3, a4, a5, x0, x1> = QQ[]
|
|
1850
|
+
sage: p = a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5
|
|
1851
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
1852
|
+
sage: quintic.T_covariant()
|
|
1853
|
+
2/125*a4^3*x0^9 - 3/50*a3*a4*a5*x0^9 + 1/10*a2*a5^2*x0^9
|
|
1854
|
+
+ 9/250*a3*a4^2*x0^8*x1 - 3/25*a3^2*a5*x0^8*x1 + 1/50*a2*a4*a5*x0^8*x1
|
|
1855
|
+
+ 2/5*a1*a5^2*x0^8*x1 + 3/250*a3^2*a4*x0^7*x1^2 + 8/125*a2*a4^2*x0^7*x1^2
|
|
1856
|
+
...
|
|
1857
|
+
11/25*a0*a1*a4*x0^2*x1^7 - a0^2*a5*x0^2*x1^7 - 9/250*a1^2*a2*x0*x1^8
|
|
1858
|
+
+ 3/25*a0*a2^2*x0*x1^8 - 1/50*a0*a1*a3*x0*x1^8 - 2/5*a0^2*a4*x0*x1^8
|
|
1859
|
+
- 2/125*a1^3*x1^9 + 3/50*a0*a1*a2*x1^9 - 1/10*a0^2*a3*x1^9
|
|
1860
|
+
|
|
1861
|
+
sage: quintic.T_covariant(as_form=True)
|
|
1862
|
+
Binary nonic given by ...
|
|
1863
|
+
"""
|
|
1864
|
+
H = self.H_covariant(as_form=True)
|
|
1865
|
+
cov = transvectant(H, self, 1)
|
|
1866
|
+
if as_form:
|
|
1867
|
+
return cov
|
|
1868
|
+
else:
|
|
1869
|
+
return cov.polynomial()
|
|
1870
|
+
|
|
1871
|
+
@cached_method
|
|
1872
|
+
def j_covariant(self, as_form=False):
|
|
1873
|
+
"""
|
|
1874
|
+
Return the covariant `j` of a binary quintic.
|
|
1875
|
+
|
|
1876
|
+
INPUT:
|
|
1877
|
+
|
|
1878
|
+
- ``as_form`` -- if ``as_form`` is ``False``, the result will be returned
|
|
1879
|
+
as polynomial (default). If it is ``True`` the result is returned as
|
|
1880
|
+
an object of the class :class:`AlgebraicForm`.
|
|
1881
|
+
|
|
1882
|
+
OUTPUT: the `j`-covariant of the binary quintic as polynomial or as binary form
|
|
1883
|
+
|
|
1884
|
+
EXAMPLES::
|
|
1885
|
+
|
|
1886
|
+
sage: R.<a0, a1, a2, a3, a4, a5, x0, x1> = QQ[]
|
|
1887
|
+
sage: p = a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5
|
|
1888
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
1889
|
+
sage: quintic.j_covariant()
|
|
1890
|
+
-3/500*a3^3*x0^3 + 3/125*a2*a3*a4*x0^3 - 6/125*a1*a4^2*x0^3
|
|
1891
|
+
- 3/50*a2^2*a5*x0^3 + 3/25*a1*a3*a5*x0^3 - 3/500*a2*a3^2*x0^2*x1
|
|
1892
|
+
+ 3/250*a2^2*a4*x0^2*x1 + 3/125*a1*a3*a4*x0^2*x1 - 6/25*a0*a4^2*x0^2*x1
|
|
1893
|
+
- 3/25*a1*a2*a5*x0^2*x1 + 3/5*a0*a3*a5*x0^2*x1 - 3/500*a2^2*a3*x0*x1^2
|
|
1894
|
+
+ 3/250*a1*a3^2*x0*x1^2 + 3/125*a1*a2*a4*x0*x1^2 - 3/25*a0*a3*a4*x0*x1^2
|
|
1895
|
+
- 6/25*a1^2*a5*x0*x1^2 + 3/5*a0*a2*a5*x0*x1^2 - 3/500*a2^3*x1^3
|
|
1896
|
+
+ 3/125*a1*a2*a3*x1^3 - 3/50*a0*a3^2*x1^3 - 6/125*a1^2*a4*x1^3
|
|
1897
|
+
+ 3/25*a0*a2*a4*x1^3
|
|
1898
|
+
|
|
1899
|
+
sage: quintic.j_covariant(as_form=True)
|
|
1900
|
+
Binary cubic given by ...
|
|
1901
|
+
"""
|
|
1902
|
+
x0 = self._x
|
|
1903
|
+
x1 = self._y
|
|
1904
|
+
i = self.i_covariant()
|
|
1905
|
+
minusi = AlgebraicForm(2, 2, -i, x0, x1)
|
|
1906
|
+
cov = transvectant(minusi, self, 2)
|
|
1907
|
+
if as_form:
|
|
1908
|
+
return cov
|
|
1909
|
+
else:
|
|
1910
|
+
return cov.polynomial()
|
|
1911
|
+
|
|
1912
|
+
@cached_method
|
|
1913
|
+
def tau_covariant(self, as_form=False):
|
|
1914
|
+
r"""
|
|
1915
|
+
Return the covariant `\tau` of a binary quintic.
|
|
1916
|
+
|
|
1917
|
+
INPUT:
|
|
1918
|
+
|
|
1919
|
+
- ``as_form`` -- if ``as_form`` is ``False``, the result will be returned
|
|
1920
|
+
as polynomial (default). If it is ``True`` the result is returned as
|
|
1921
|
+
an object of the class :class:`AlgebraicForm`.
|
|
1922
|
+
|
|
1923
|
+
OUTPUT:
|
|
1924
|
+
|
|
1925
|
+
The `\tau`-covariant of the binary quintic as polynomial or as binary form.
|
|
1926
|
+
|
|
1927
|
+
EXAMPLES::
|
|
1928
|
+
|
|
1929
|
+
sage: R.<a0, a1, a2, a3, a4, a5, x0, x1> = QQ[]
|
|
1930
|
+
sage: p = a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5
|
|
1931
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
1932
|
+
sage: quintic.tau_covariant()
|
|
1933
|
+
1/62500*a2^2*a3^4*x0^2 - 3/62500*a1*a3^5*x0^2
|
|
1934
|
+
- 1/15625*a2^3*a3^2*a4*x0^2 + 1/6250*a1*a2*a3^3*a4*x0^2
|
|
1935
|
+
+ 3/6250*a0*a3^4*a4*x0^2 - 1/31250*a2^4*a4^2*x0^2
|
|
1936
|
+
...
|
|
1937
|
+
- 2/125*a0*a1*a2^2*a4*a5*x1^2 - 4/125*a0*a1^2*a3*a4*a5*x1^2
|
|
1938
|
+
+ 2/25*a0^2*a2*a3*a4*a5*x1^2 - 8/625*a1^4*a5^2*x1^2
|
|
1939
|
+
+ 8/125*a0*a1^2*a2*a5^2*x1^2 - 2/25*a0^2*a2^2*a5^2*x1^2
|
|
1940
|
+
|
|
1941
|
+
sage: quintic.tau_covariant(as_form=True)
|
|
1942
|
+
Binary quadratic given by ...
|
|
1943
|
+
"""
|
|
1944
|
+
j = self.j_covariant(as_form=True)
|
|
1945
|
+
cov = transvectant(j, j, 2)
|
|
1946
|
+
if as_form:
|
|
1947
|
+
return cov
|
|
1948
|
+
else:
|
|
1949
|
+
return cov.polynomial()
|
|
1950
|
+
|
|
1951
|
+
@cached_method
|
|
1952
|
+
def theta_covariant(self, as_form=False):
|
|
1953
|
+
r"""
|
|
1954
|
+
Return the covariant `\theta` of a binary quintic.
|
|
1955
|
+
|
|
1956
|
+
INPUT:
|
|
1957
|
+
|
|
1958
|
+
- ``as_form`` -- if ``as_form`` is ``False``, the result will be returned
|
|
1959
|
+
as polynomial (default). If it is ``True`` the result is returned as
|
|
1960
|
+
an object of the class :class:`AlgebraicForm`.
|
|
1961
|
+
|
|
1962
|
+
OUTPUT:
|
|
1963
|
+
|
|
1964
|
+
The `\theta`-covariant of the binary quintic as polynomial or as binary form.
|
|
1965
|
+
|
|
1966
|
+
EXAMPLES::
|
|
1967
|
+
|
|
1968
|
+
sage: R.<a0, a1, a2, a3, a4, a5, x0, x1> = QQ[]
|
|
1969
|
+
sage: p = a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5
|
|
1970
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
1971
|
+
sage: quintic.theta_covariant()
|
|
1972
|
+
-1/625000*a2^3*a3^5*x0^2 + 9/1250000*a1*a2*a3^6*x0^2
|
|
1973
|
+
- 27/1250000*a0*a3^7*x0^2 + 3/250000*a2^4*a3^3*a4*x0^2
|
|
1974
|
+
- 7/125000*a1*a2^2*a3^4*a4*x0^2 - 3/312500*a1^2*a3^5*a4*x0^2
|
|
1975
|
+
...
|
|
1976
|
+
+ 6/625*a0^2*a1*a2^2*a4*a5^2*x1^2 + 24/625*a0^2*a1^2*a3*a4*a5^2*x1^2
|
|
1977
|
+
- 12/125*a0^3*a2*a3*a4*a5^2*x1^2 + 8/625*a0*a1^4*a5^3*x1^2
|
|
1978
|
+
- 8/125*a0^2*a1^2*a2*a5^3*x1^2 + 2/25*a0^3*a2^2*a5^3*x1^2
|
|
1979
|
+
|
|
1980
|
+
sage: quintic.theta_covariant(as_form=True)
|
|
1981
|
+
Binary quadratic given by ...
|
|
1982
|
+
"""
|
|
1983
|
+
i = self.i_covariant(as_form=True)
|
|
1984
|
+
tau = self.tau_covariant(as_form=True)
|
|
1985
|
+
cov = transvectant(i, tau, 1)
|
|
1986
|
+
if as_form:
|
|
1987
|
+
return cov
|
|
1988
|
+
else:
|
|
1989
|
+
return cov.polynomial()
|
|
1990
|
+
|
|
1991
|
+
@cached_method
|
|
1992
|
+
def alpha_covariant(self, as_form=False):
|
|
1993
|
+
r"""
|
|
1994
|
+
Return the covariant `\alpha` of a binary quintic.
|
|
1995
|
+
|
|
1996
|
+
INPUT:
|
|
1997
|
+
|
|
1998
|
+
- ``as_form`` -- if ``as_form`` is ``False``, the result will be returned
|
|
1999
|
+
as polynomial (default). If it is ``True`` the result is returned as
|
|
2000
|
+
an object of the class :class:`AlgebraicForm`.
|
|
2001
|
+
|
|
2002
|
+
OUTPUT:
|
|
2003
|
+
|
|
2004
|
+
The `\alpha`-covariant of the binary quintic as polynomial or as binary form.
|
|
2005
|
+
|
|
2006
|
+
EXAMPLES::
|
|
2007
|
+
|
|
2008
|
+
sage: R.<a0, a1, a2, a3, a4, a5, x0, x1> = QQ[]
|
|
2009
|
+
sage: p = a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5
|
|
2010
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
2011
|
+
sage: quintic.alpha_covariant()
|
|
2012
|
+
1/2500*a2^2*a3^3*x0 - 3/2500*a1*a3^4*x0 - 1/625*a2^3*a3*a4*x0
|
|
2013
|
+
+ 3/625*a1*a2*a3^2*a4*x0 + 3/625*a0*a3^3*a4*x0 + 2/625*a1*a2^2*a4^2*x0
|
|
2014
|
+
- 6/625*a1^2*a3*a4^2*x0 - 12/625*a0*a2*a3*a4^2*x0 + 24/625*a0*a1*a4^3*x0
|
|
2015
|
+
...
|
|
2016
|
+
- 12/625*a1^2*a2*a3*a5*x1 - 1/125*a0*a2^2*a3*a5*x1
|
|
2017
|
+
+ 8/125*a0*a1*a3^2*a5*x1 + 24/625*a1^3*a4*a5*x1 - 8/125*a0*a1*a2*a4*a5*x1
|
|
2018
|
+
- 4/25*a0^2*a3*a4*a5*x1 - 4/25*a0*a1^2*a5^2*x1 + 2/5*a0^2*a2*a5^2*x1
|
|
2019
|
+
|
|
2020
|
+
sage: quintic.alpha_covariant(as_form=True)
|
|
2021
|
+
Binary monic given by ...
|
|
2022
|
+
"""
|
|
2023
|
+
i = self.i_covariant()
|
|
2024
|
+
x0 = self._x
|
|
2025
|
+
x1 = self._y
|
|
2026
|
+
i2 = AlgebraicForm(2, 4, i**2, x0, x1)
|
|
2027
|
+
cov = transvectant(i2, self, 4)
|
|
2028
|
+
if as_form:
|
|
2029
|
+
return cov
|
|
2030
|
+
else:
|
|
2031
|
+
return cov.polynomial()
|
|
2032
|
+
|
|
2033
|
+
@cached_method
|
|
2034
|
+
def beta_covariant(self, as_form=False):
|
|
2035
|
+
r"""
|
|
2036
|
+
Return the covariant `\beta` of a binary quintic.
|
|
2037
|
+
|
|
2038
|
+
INPUT:
|
|
2039
|
+
|
|
2040
|
+
- ``as_form`` -- if ``as_form`` is ``False``, the result will be returned
|
|
2041
|
+
as polynomial (default). If it is ``True`` the result is returned as
|
|
2042
|
+
an object of the class :class:`AlgebraicForm`.
|
|
2043
|
+
|
|
2044
|
+
OUTPUT:
|
|
2045
|
+
|
|
2046
|
+
The `\beta`-covariant of the binary quintic as polynomial or as binary form.
|
|
2047
|
+
|
|
2048
|
+
EXAMPLES::
|
|
2049
|
+
|
|
2050
|
+
sage: R.<a0, a1, a2, a3, a4, a5, x0, x1> = QQ[]
|
|
2051
|
+
sage: p = a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5
|
|
2052
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
2053
|
+
sage: quintic.beta_covariant()
|
|
2054
|
+
-1/62500*a2^3*a3^4*x0 + 9/125000*a1*a2*a3^5*x0 - 27/125000*a0*a3^6*x0
|
|
2055
|
+
+ 13/125000*a2^4*a3^2*a4*x0 - 31/62500*a1*a2^2*a3^3*a4*x0
|
|
2056
|
+
- 3/62500*a1^2*a3^4*a4*x0 + 27/15625*a0*a2*a3^4*a4*x0
|
|
2057
|
+
...
|
|
2058
|
+
- 16/125*a0^2*a1*a3^2*a5^2*x1 - 28/625*a0*a1^3*a4*a5^2*x1
|
|
2059
|
+
+ 6/125*a0^2*a1*a2*a4*a5^2*x1 + 8/25*a0^3*a3*a4*a5^2*x1
|
|
2060
|
+
+ 4/25*a0^2*a1^2*a5^3*x1 - 2/5*a0^3*a2*a5^3*x1
|
|
2061
|
+
|
|
2062
|
+
sage: quintic.beta_covariant(as_form=True)
|
|
2063
|
+
Binary monic given by ...
|
|
2064
|
+
"""
|
|
2065
|
+
i = self.i_covariant(as_form=True)
|
|
2066
|
+
alpha = self.alpha_covariant(as_form=True)
|
|
2067
|
+
cov = transvectant(i, alpha, 1)
|
|
2068
|
+
if as_form:
|
|
2069
|
+
return cov
|
|
2070
|
+
else:
|
|
2071
|
+
return cov.polynomial()
|
|
2072
|
+
|
|
2073
|
+
@cached_method
|
|
2074
|
+
def gamma_covariant(self, as_form=False):
|
|
2075
|
+
r"""
|
|
2076
|
+
Return the covariant `\gamma` of a binary quintic.
|
|
2077
|
+
|
|
2078
|
+
INPUT:
|
|
2079
|
+
|
|
2080
|
+
- ``as_form`` -- if ``as_form`` is ``False``, the result will be returned
|
|
2081
|
+
as polynomial (default). If it is ``True`` the result is returned as
|
|
2082
|
+
an object of the class :class:`AlgebraicForm`.
|
|
2083
|
+
|
|
2084
|
+
OUTPUT:
|
|
2085
|
+
|
|
2086
|
+
The `\gamma`-covariant of the binary quintic as polynomial or as binary form.
|
|
2087
|
+
|
|
2088
|
+
EXAMPLES::
|
|
2089
|
+
|
|
2090
|
+
sage: R.<a0, a1, a2, a3, a4, a5, x0, x1> = QQ[]
|
|
2091
|
+
sage: p = a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5
|
|
2092
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
2093
|
+
sage: quintic.gamma_covariant()
|
|
2094
|
+
1/156250000*a2^5*a3^6*x0 - 3/62500000*a1*a2^3*a3^7*x0
|
|
2095
|
+
+ 27/312500000*a1^2*a2*a3^8*x0 + 27/312500000*a0*a2^2*a3^8*x0
|
|
2096
|
+
- 81/312500000*a0*a1*a3^9*x0 - 19/312500000*a2^6*a3^4*a4*x0
|
|
2097
|
+
...
|
|
2098
|
+
- 32/3125*a0^2*a1^3*a2^2*a5^4*x1 + 6/625*a0^3*a1*a2^3*a5^4*x1
|
|
2099
|
+
- 8/3125*a0^2*a1^4*a3*a5^4*x1 + 8/625*a0^3*a1^2*a2*a3*a5^4*x1
|
|
2100
|
+
- 2/125*a0^4*a2^2*a3*a5^4*x1
|
|
2101
|
+
|
|
2102
|
+
sage: quintic.gamma_covariant(as_form=True)
|
|
2103
|
+
Binary monic given by ...
|
|
2104
|
+
"""
|
|
2105
|
+
alpha = self.alpha_covariant(as_form=True)
|
|
2106
|
+
tau = self.tau_covariant(as_form=True)
|
|
2107
|
+
cov = transvectant(tau, alpha, 1)
|
|
2108
|
+
if as_form:
|
|
2109
|
+
return cov
|
|
2110
|
+
else:
|
|
2111
|
+
return cov.polynomial()
|
|
2112
|
+
|
|
2113
|
+
@cached_method
|
|
2114
|
+
def delta_covariant(self, as_form=False):
|
|
2115
|
+
r"""
|
|
2116
|
+
Return the covariant `\delta` of a binary quintic.
|
|
2117
|
+
|
|
2118
|
+
INPUT:
|
|
2119
|
+
|
|
2120
|
+
- ``as_form`` -- if ``as_form`` is ``False``, the result will be returned
|
|
2121
|
+
as polynomial (default). If it is ``True`` the result is returned as
|
|
2122
|
+
an object of the class :class:`AlgebraicForm`.
|
|
2123
|
+
|
|
2124
|
+
OUTPUT:
|
|
2125
|
+
|
|
2126
|
+
The `\delta`-covariant of the binary quintic as polynomial or as binary form.
|
|
2127
|
+
|
|
2128
|
+
EXAMPLES::
|
|
2129
|
+
|
|
2130
|
+
sage: R.<a0, a1, a2, a3, a4, a5, x0, x1> = QQ[]
|
|
2131
|
+
sage: p = a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5
|
|
2132
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
2133
|
+
sage: quintic.delta_covariant()
|
|
2134
|
+
1/1562500000*a2^6*a3^7*x0 - 9/1562500000*a1*a2^4*a3^8*x0
|
|
2135
|
+
+ 9/625000000*a1^2*a2^2*a3^9*x0 + 9/781250000*a0*a2^3*a3^9*x0
|
|
2136
|
+
- 9/1562500000*a1^3*a3^10*x0 - 81/1562500000*a0*a1*a2*a3^10*x0
|
|
2137
|
+
...
|
|
2138
|
+
+ 64/3125*a0^3*a1^3*a2^2*a5^5*x1 - 12/625*a0^4*a1*a2^3*a5^5*x1
|
|
2139
|
+
+ 16/3125*a0^3*a1^4*a3*a5^5*x1 - 16/625*a0^4*a1^2*a2*a3*a5^5*x1
|
|
2140
|
+
+ 4/125*a0^5*a2^2*a3*a5^5*x1
|
|
2141
|
+
|
|
2142
|
+
sage: quintic.delta_covariant(as_form=True)
|
|
2143
|
+
Binary monic given by ...
|
|
2144
|
+
"""
|
|
2145
|
+
alpha = self.alpha_covariant(as_form=True)
|
|
2146
|
+
theta = self.theta_covariant(as_form=True)
|
|
2147
|
+
cov = transvectant(theta, alpha, 1)
|
|
2148
|
+
if as_form:
|
|
2149
|
+
return cov
|
|
2150
|
+
else:
|
|
2151
|
+
return cov.polynomial()
|
|
2152
|
+
|
|
2153
|
+
@cached_method
|
|
2154
|
+
def A_invariant(self):
|
|
2155
|
+
"""
|
|
2156
|
+
Return the invariant `A` of a binary quintic.
|
|
2157
|
+
|
|
2158
|
+
OUTPUT: the `A`-invariant of the binary quintic
|
|
2159
|
+
|
|
2160
|
+
EXAMPLES::
|
|
2161
|
+
|
|
2162
|
+
sage: R.<a0, a1, a2, a3, a4, a5, x0, x1> = QQ[]
|
|
2163
|
+
sage: p = a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5
|
|
2164
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
2165
|
+
sage: quintic.A_invariant()
|
|
2166
|
+
4/625*a2^2*a3^2 - 12/625*a1*a3^3 - 12/625*a2^3*a4
|
|
2167
|
+
+ 38/625*a1*a2*a3*a4 + 6/125*a0*a3^2*a4 - 18/625*a1^2*a4^2
|
|
2168
|
+
- 16/125*a0*a2*a4^2 + 6/125*a1*a2^2*a5 - 16/125*a1^2*a3*a5
|
|
2169
|
+
- 2/25*a0*a2*a3*a5 + 4/5*a0*a1*a4*a5 - 2*a0^2*a5^2
|
|
2170
|
+
"""
|
|
2171
|
+
i = self.i_covariant(as_form=True)
|
|
2172
|
+
A = transvectant(i, i, 2).polynomial()
|
|
2173
|
+
try:
|
|
2174
|
+
K = self._ring.base_ring()
|
|
2175
|
+
return K(A)
|
|
2176
|
+
except TypeError:
|
|
2177
|
+
return A
|
|
2178
|
+
|
|
2179
|
+
@cached_method
|
|
2180
|
+
def B_invariant(self):
|
|
2181
|
+
"""
|
|
2182
|
+
Return the invariant `B` of a binary quintic.
|
|
2183
|
+
|
|
2184
|
+
OUTPUT: the `B`-invariant of the binary quintic
|
|
2185
|
+
|
|
2186
|
+
EXAMPLES::
|
|
2187
|
+
|
|
2188
|
+
sage: R.<a0, a1, a2, a3, a4, a5, x0, x1> = QQ[]
|
|
2189
|
+
sage: p = a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5
|
|
2190
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
2191
|
+
sage: quintic.B_invariant()
|
|
2192
|
+
1/1562500*a2^4*a3^4 - 3/781250*a1*a2^2*a3^5 + 9/1562500*a1^2*a3^6
|
|
2193
|
+
- 3/781250*a2^5*a3^2*a4 + 37/1562500*a1*a2^3*a3^3*a4
|
|
2194
|
+
- 57/1562500*a1^2*a2*a3^4*a4 + 3/312500*a0*a2^2*a3^4*a4
|
|
2195
|
+
...
|
|
2196
|
+
+ 8/625*a0^2*a1^2*a4^2*a5^2 - 4/125*a0^3*a2*a4^2*a5^2 - 16/3125*a1^5*a5^3
|
|
2197
|
+
+ 4/125*a0*a1^3*a2*a5^3 - 6/125*a0^2*a1*a2^2*a5^3
|
|
2198
|
+
- 4/125*a0^2*a1^2*a3*a5^3 + 2/25*a0^3*a2*a3*a5^3
|
|
2199
|
+
"""
|
|
2200
|
+
i = self.i_covariant(as_form=True)
|
|
2201
|
+
tau = self.tau_covariant(as_form=True)
|
|
2202
|
+
B = transvectant(i, tau, 2).polynomial()
|
|
2203
|
+
try:
|
|
2204
|
+
K = self._ring.base_ring()
|
|
2205
|
+
return K(B)
|
|
2206
|
+
except TypeError:
|
|
2207
|
+
return B
|
|
2208
|
+
|
|
2209
|
+
@cached_method
|
|
2210
|
+
def C_invariant(self):
|
|
2211
|
+
"""
|
|
2212
|
+
Return the invariant `C` of a binary quintic.
|
|
2213
|
+
|
|
2214
|
+
OUTPUT: the `C`-invariant of the binary quintic
|
|
2215
|
+
|
|
2216
|
+
EXAMPLES::
|
|
2217
|
+
|
|
2218
|
+
sage: R.<a0, a1, a2, a3, a4, a5, x0, x1> = QQ[]
|
|
2219
|
+
sage: p = a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5
|
|
2220
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
2221
|
+
sage: quintic.C_invariant()
|
|
2222
|
+
-3/1953125000*a2^6*a3^6 + 27/1953125000*a1*a2^4*a3^7
|
|
2223
|
+
- 249/7812500000*a1^2*a2^2*a3^8 - 3/78125000*a0*a2^3*a3^8
|
|
2224
|
+
+ 3/976562500*a1^3*a3^9 + 27/156250000*a0*a1*a2*a3^9
|
|
2225
|
+
...
|
|
2226
|
+
+ 192/15625*a0^2*a1^3*a2^2*a3*a5^4 - 36/3125*a0^3*a1*a2^3*a3*a5^4
|
|
2227
|
+
+ 24/15625*a0^2*a1^4*a3^2*a5^4 - 24/3125*a0^3*a1^2*a2*a3^2*a5^4
|
|
2228
|
+
+ 6/625*a0^4*a2^2*a3^2*a5^4
|
|
2229
|
+
"""
|
|
2230
|
+
tau = self.tau_covariant(as_form=True)
|
|
2231
|
+
C = transvectant(tau, tau, 2).polynomial()
|
|
2232
|
+
try:
|
|
2233
|
+
K = self._ring.base_ring()
|
|
2234
|
+
return K(C)
|
|
2235
|
+
except TypeError:
|
|
2236
|
+
return C
|
|
2237
|
+
|
|
2238
|
+
@cached_method
|
|
2239
|
+
def R_invariant(self):
|
|
2240
|
+
"""
|
|
2241
|
+
Return the invariant `R` of a binary quintic.
|
|
2242
|
+
|
|
2243
|
+
OUTPUT: the `R`-invariant of the binary quintic
|
|
2244
|
+
|
|
2245
|
+
EXAMPLES::
|
|
2246
|
+
|
|
2247
|
+
sage: R.<a0, a1, a2, a3, a4, a5, x0, x1> = QQ[]
|
|
2248
|
+
sage: p = a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5
|
|
2249
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
2250
|
+
sage: quintic.R_invariant()
|
|
2251
|
+
3/3906250000000*a1^2*a2^5*a3^11 - 3/976562500000*a0*a2^6*a3^11
|
|
2252
|
+
- 51/7812500000000*a1^3*a2^3*a3^12 + 27/976562500000*a0*a1*a2^4*a3^12
|
|
2253
|
+
+ 27/1953125000000*a1^4*a2*a3^13 - 81/1562500000000*a0*a1^2*a2^2*a3^13
|
|
2254
|
+
...
|
|
2255
|
+
+ 384/9765625*a0*a1^10*a5^7 - 192/390625*a0^2*a1^8*a2*a5^7
|
|
2256
|
+
+ 192/78125*a0^3*a1^6*a2^2*a5^7 - 96/15625*a0^4*a1^4*a2^3*a5^7
|
|
2257
|
+
+ 24/3125*a0^5*a1^2*a2^4*a5^7 - 12/3125*a0^6*a2^5*a5^7
|
|
2258
|
+
"""
|
|
2259
|
+
beta = self.beta_covariant(as_form=True)
|
|
2260
|
+
gamma = self.gamma_covariant(as_form=True)
|
|
2261
|
+
R = transvectant(beta, gamma, 1).polynomial()
|
|
2262
|
+
try:
|
|
2263
|
+
K = self._ring.base_ring()
|
|
2264
|
+
return K(R)
|
|
2265
|
+
except TypeError:
|
|
2266
|
+
return R
|
|
2267
|
+
|
|
2268
|
+
@cached_method
|
|
2269
|
+
def invariants(self, type='clebsch'):
|
|
2270
|
+
"""
|
|
2271
|
+
Return a tuple of invariants of a binary quintic.
|
|
2272
|
+
|
|
2273
|
+
INPUT:
|
|
2274
|
+
|
|
2275
|
+
- ``type`` -- the type of invariants to return; the default choice
|
|
2276
|
+
is to return the Clebsch invariants
|
|
2277
|
+
|
|
2278
|
+
OUTPUT: the invariants of the binary quintic
|
|
2279
|
+
|
|
2280
|
+
EXAMPLES::
|
|
2281
|
+
|
|
2282
|
+
sage: R.<x0, x1> = QQ[]
|
|
2283
|
+
sage: p = 2*x1^5 + 4*x1^4*x0 + 5*x1^3*x0^2 + 7*x1^2*x0^3 - 11*x1*x0^4 + x0^5
|
|
2284
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
2285
|
+
sage: quintic.invariants()
|
|
2286
|
+
(-276032/625,
|
|
2287
|
+
4983526016/390625,
|
|
2288
|
+
-247056495846408/244140625,
|
|
2289
|
+
-148978972828696847376/30517578125)
|
|
2290
|
+
sage: quintic.invariants('unknown')
|
|
2291
|
+
Traceback (most recent call last):
|
|
2292
|
+
...
|
|
2293
|
+
ValueError: unknown type of invariants unknown for a binary quintic
|
|
2294
|
+
"""
|
|
2295
|
+
if type == 'clebsch':
|
|
2296
|
+
return self.clebsch_invariants(as_tuple=True)
|
|
2297
|
+
elif type == 'arithmetic':
|
|
2298
|
+
return self.arithmetic_invariants(as_tuple=True)
|
|
2299
|
+
else:
|
|
2300
|
+
raise ValueError('unknown type of invariants {} for a binary'
|
|
2301
|
+
' quintic'.format(type))
|
|
2302
|
+
|
|
2303
|
+
@cached_method
|
|
2304
|
+
def clebsch_invariants(self, as_tuple=False):
|
|
2305
|
+
"""
|
|
2306
|
+
Return the invariants of a binary quintic as described by Clebsch.
|
|
2307
|
+
|
|
2308
|
+
The following invariants are returned: `A`, `B`, `C` and `R`.
|
|
2309
|
+
|
|
2310
|
+
OUTPUT: the Clebsch invariants of the binary quintic
|
|
2311
|
+
|
|
2312
|
+
EXAMPLES::
|
|
2313
|
+
|
|
2314
|
+
sage: R.<x0, x1> = QQ[]
|
|
2315
|
+
sage: p = 2*x1^5 + 4*x1^4*x0 + 5*x1^3*x0^2 + 7*x1^2*x0^3 - 11*x1*x0^4 + x0^5
|
|
2316
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
2317
|
+
sage: quintic.clebsch_invariants()
|
|
2318
|
+
{'A': -276032/625,
|
|
2319
|
+
'B': 4983526016/390625,
|
|
2320
|
+
'C': -247056495846408/244140625,
|
|
2321
|
+
'R': -148978972828696847376/30517578125}
|
|
2322
|
+
|
|
2323
|
+
sage: quintic.clebsch_invariants(as_tuple=True)
|
|
2324
|
+
(-276032/625,
|
|
2325
|
+
4983526016/390625,
|
|
2326
|
+
-247056495846408/244140625,
|
|
2327
|
+
-148978972828696847376/30517578125)
|
|
2328
|
+
"""
|
|
2329
|
+
if self._ring.characteristic() in [2, 3, 5]:
|
|
2330
|
+
raise NotImplementedError('no invariants implemented for fields '
|
|
2331
|
+
'of characteristic 2, 3 or 5')
|
|
2332
|
+
# todo: add support
|
|
2333
|
+
else:
|
|
2334
|
+
invariants = {}
|
|
2335
|
+
invariants['A'] = self.A_invariant()
|
|
2336
|
+
invariants['B'] = self.B_invariant()
|
|
2337
|
+
invariants['C'] = self.C_invariant()
|
|
2338
|
+
invariants['R'] = self.R_invariant()
|
|
2339
|
+
if as_tuple:
|
|
2340
|
+
return (invariants['A'], invariants['B'], invariants['C'],
|
|
2341
|
+
invariants['R'])
|
|
2342
|
+
else:
|
|
2343
|
+
return invariants
|
|
2344
|
+
|
|
2345
|
+
@cached_method
|
|
2346
|
+
def arithmetic_invariants(self):
|
|
2347
|
+
r"""
|
|
2348
|
+
Return a set of generating arithmetic invariants of a binary quintic.
|
|
2349
|
+
|
|
2350
|
+
An arithmetic invariants is an invariant whose coefficients are
|
|
2351
|
+
integers for a general binary quintic. They are linear combinations
|
|
2352
|
+
of the Clebsch invariants, such that they still generate the ring of
|
|
2353
|
+
invariants.
|
|
2354
|
+
|
|
2355
|
+
OUTPUT: the arithmetic invariants of the binary quintic. They are given by
|
|
2356
|
+
|
|
2357
|
+
.. MATH::
|
|
2358
|
+
|
|
2359
|
+
\begin{aligned}
|
|
2360
|
+
I_4 & = 2^{-1} \cdot 5^4 \cdot A \\
|
|
2361
|
+
I_8 & = 5^5 \cdot (2^{-1} \cdot 47 \cdot A^2 - 2^2 \cdot B) \\
|
|
2362
|
+
I_{12} & = 5^{10} \cdot (2^{-1} \cdot 3 \cdot A^3
|
|
2363
|
+
- 2^5 \cdot 3^{-1} \cdot C) \\
|
|
2364
|
+
I_{18} & = 2^8 \cdot 3^{-1} \cdot 5^{15} \cdot R \\
|
|
2365
|
+
\end{aligned}
|
|
2366
|
+
|
|
2367
|
+
where `A`, `B`, `C` and `R` are the
|
|
2368
|
+
:meth:`BinaryQuintic.clebsch_invariants`.
|
|
2369
|
+
|
|
2370
|
+
EXAMPLES::
|
|
2371
|
+
|
|
2372
|
+
sage: R.<x0, x1> = QQ[]
|
|
2373
|
+
sage: p = 2*x1^5 + 4*x1^4*x0 + 5*x1^3*x0^2 + 7*x1^2*x0^3 - 11*x1*x0^4 + x0^5
|
|
2374
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
2375
|
+
sage: quintic.arithmetic_invariants()
|
|
2376
|
+
{'I12': -1156502613073152,
|
|
2377
|
+
'I18': -12712872348048797642752,
|
|
2378
|
+
'I4': -138016,
|
|
2379
|
+
'I8': 14164936192}
|
|
2380
|
+
|
|
2381
|
+
We can check that the coefficients of the invariants have no common divisor
|
|
2382
|
+
for a general quintic form::
|
|
2383
|
+
|
|
2384
|
+
sage: R.<a0,a1,a2,a3,a4,a5,x0,x1> = QQ[]
|
|
2385
|
+
sage: p = a0*x1^5 + a1*x1^4*x0 + a2*x1^3*x0^2 + a3*x1^2*x0^3 + a4*x1*x0^4 + a5*x0^5
|
|
2386
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
2387
|
+
sage: invs = quintic.arithmetic_invariants()
|
|
2388
|
+
sage: [invs[x].content() for x in invs]
|
|
2389
|
+
[1, 1, 1, 1]
|
|
2390
|
+
"""
|
|
2391
|
+
R = self._ring
|
|
2392
|
+
clebsch = self.clebsch_invariants()
|
|
2393
|
+
invariants = {}
|
|
2394
|
+
invariants['I4'] = R(2)**-1*5**4*clebsch['A']
|
|
2395
|
+
invariants['I8'] = 5**5 * (R(2)**-1*47*clebsch['A']**2
|
|
2396
|
+
- 2**2*clebsch['B'])
|
|
2397
|
+
invariants['I12'] = 5**10 * (R(2)**-1*3*clebsch['A']**3
|
|
2398
|
+
- 2**5*R(3)**-1*clebsch['C'])
|
|
2399
|
+
invariants['I18'] = 2**8*R(3)**-1*5**15 * clebsch['R']
|
|
2400
|
+
return invariants
|
|
2401
|
+
|
|
2402
|
+
@cached_method
|
|
2403
|
+
def canonical_form(self, reduce_gcd=False):
|
|
2404
|
+
r"""
|
|
2405
|
+
Return a canonical representative of the quintic.
|
|
2406
|
+
|
|
2407
|
+
Given a binary quintic `f` with coefficients in a field `K`, returns a
|
|
2408
|
+
canonical representative of the `GL(2,\bar{K})`-orbit of the quintic,
|
|
2409
|
+
where `\bar{K}` is an algebraic closure of `K`. This means that two
|
|
2410
|
+
binary quintics `f` and `g` are `GL(2,\bar{K})`-equivalent if and only
|
|
2411
|
+
if their canonical forms are the same.
|
|
2412
|
+
|
|
2413
|
+
INPUT:
|
|
2414
|
+
|
|
2415
|
+
- ``reduce_gcd`` -- if set to ``True``, then a variant of this canonical
|
|
2416
|
+
form is computed where the coefficients are coprime integers. The
|
|
2417
|
+
obtained form is then unique up to multiplication by a unit. See also
|
|
2418
|
+
:meth:`~sage.rings.invariants.reconstruction.binary_quintic_from_invariants`'.
|
|
2419
|
+
|
|
2420
|
+
OUTPUT:
|
|
2421
|
+
|
|
2422
|
+
A canonical `GL(2,\bar{K})`-equivalent binary quintic.
|
|
2423
|
+
|
|
2424
|
+
EXAMPLES::
|
|
2425
|
+
|
|
2426
|
+
sage: R.<x0, x1> = QQ[]
|
|
2427
|
+
sage: p = 2*x1^5 + 4*x1^4*x0 + 5*x1^3*x0^2 + 7*x1^2*x0^3 - 11*x1*x0^4 + x0^5
|
|
2428
|
+
sage: f = invariant_theory.binary_quintic(p, x0, x1)
|
|
2429
|
+
sage: g = matrix(QQ, [[11,5],[7,2]])
|
|
2430
|
+
sage: gf = f.transformed(g)
|
|
2431
|
+
sage: f.canonical_form() == gf.canonical_form()
|
|
2432
|
+
True
|
|
2433
|
+
sage: h = f.canonical_form(reduce_gcd=True) # needs sage.libs.pari
|
|
2434
|
+
sage: gcd(h.coeffs()) # needs sage.libs.pari
|
|
2435
|
+
1
|
|
2436
|
+
"""
|
|
2437
|
+
clebsch = self.clebsch_invariants(as_tuple=True)
|
|
2438
|
+
if reduce_gcd:
|
|
2439
|
+
return invariant_theory.binary_form_from_invariants(5, clebsch,
|
|
2440
|
+
variables=self.variables(), scaling='coprime')
|
|
2441
|
+
else:
|
|
2442
|
+
return invariant_theory.binary_form_from_invariants(5, clebsch,
|
|
2443
|
+
variables=self.variables(), scaling='normalized')
|
|
2444
|
+
|
|
2445
|
+
|
|
2446
|
+
######################################################################
|
|
2447
|
+
|
|
2448
|
+
|
|
2449
|
+
def _covariant_conic(A_scaled_coeffs, B_scaled_coeffs, monomials):
|
|
2450
|
+
"""
|
|
2451
|
+
Helper function for :meth:`TernaryQuadratic.covariant_conic`.
|
|
2452
|
+
|
|
2453
|
+
INPUT:
|
|
2454
|
+
|
|
2455
|
+
- ``A_scaled_coeffs``, ``B_scaled_coeffs`` -- the scaled
|
|
2456
|
+
coefficients of the two ternary quadratics
|
|
2457
|
+
|
|
2458
|
+
- ``monomials`` -- the monomials :meth:`~TernaryQuadratic.monomials`
|
|
2459
|
+
|
|
2460
|
+
OUTPUT:
|
|
2461
|
+
|
|
2462
|
+
The so-called covariant conic, a ternary quadratic. It is
|
|
2463
|
+
symmetric under exchange of ``A`` and ``B``.
|
|
2464
|
+
|
|
2465
|
+
EXAMPLES::
|
|
2466
|
+
|
|
2467
|
+
sage: ring.<x,y,z> = QQ[]
|
|
2468
|
+
sage: A = invariant_theory.ternary_quadratic(x^2+y^2+z^2)
|
|
2469
|
+
sage: B = invariant_theory.ternary_quadratic(x*y+x*z+y*z)
|
|
2470
|
+
sage: from sage.rings.invariants.invariant_theory import _covariant_conic
|
|
2471
|
+
sage: _covariant_conic(A.scaled_coeffs(), B.scaled_coeffs(), A.monomials())
|
|
2472
|
+
-x*y - x*z - y*z
|
|
2473
|
+
"""
|
|
2474
|
+
a0, b0, c0, h0, g0, f0 = A_scaled_coeffs
|
|
2475
|
+
a1, b1, c1, h1, g1, f1 = B_scaled_coeffs
|
|
2476
|
+
return (
|
|
2477
|
+
(b0*c1+c0*b1-2*f0*f1) * monomials[0] +
|
|
2478
|
+
(a0*c1+c0*a1-2*g0*g1) * monomials[1] +
|
|
2479
|
+
(a0*b1+b0*a1-2*h0*h1) * monomials[2] +
|
|
2480
|
+
2*(f0*g1+g0*f1 - c0*h1-h0*c1) * monomials[3] +
|
|
2481
|
+
2*(h0*f1+f0*h1 - b0*g1-g0*b1) * monomials[4] +
|
|
2482
|
+
2*(g0*h1+h0*g1 - a0*f1-f0*a1) * monomials[5] )
|
|
2483
|
+
|
|
2484
|
+
|
|
2485
|
+
######################################################################
|
|
2486
|
+
class TernaryQuadratic(QuadraticForm):
|
|
2487
|
+
"""
|
|
2488
|
+
Invariant theory of a ternary quadratic.
|
|
2489
|
+
|
|
2490
|
+
You should use the :class:`invariant_theory
|
|
2491
|
+
<InvariantTheoryFactory>` factory object to construct instances
|
|
2492
|
+
of this class. See
|
|
2493
|
+
:meth:`~InvariantTheoryFactory.ternary_quadratic` for details.
|
|
2494
|
+
|
|
2495
|
+
TESTS::
|
|
2496
|
+
|
|
2497
|
+
sage: R.<x,y,z> = QQ[]
|
|
2498
|
+
sage: quadratic = invariant_theory.ternary_quadratic(x^2+y^2+z^2)
|
|
2499
|
+
sage: quadratic
|
|
2500
|
+
Ternary quadratic with coefficients (1, 1, 1, 0, 0, 0)
|
|
2501
|
+
sage: TestSuite(quadratic).run()
|
|
2502
|
+
"""
|
|
2503
|
+
|
|
2504
|
+
def __init__(self, n, d, polynomial, *args):
|
|
2505
|
+
"""
|
|
2506
|
+
The Python constructor.
|
|
2507
|
+
|
|
2508
|
+
INPUT:
|
|
2509
|
+
|
|
2510
|
+
See :meth:`~InvariantTheoryFactory.ternary_quadratic`.
|
|
2511
|
+
|
|
2512
|
+
TESTS::
|
|
2513
|
+
|
|
2514
|
+
sage: R.<x,y,z> = QQ[]
|
|
2515
|
+
sage: from sage.rings.invariants.invariant_theory import TernaryQuadratic
|
|
2516
|
+
sage: TernaryQuadratic(3, 2, x^2+y^2+z^2)
|
|
2517
|
+
Ternary quadratic with coefficients (1, 1, 1, 0, 0, 0)
|
|
2518
|
+
"""
|
|
2519
|
+
assert n == 3 and d == 2
|
|
2520
|
+
super().__init__(3, 2, polynomial, *args)
|
|
2521
|
+
self._x = self._variables[0]
|
|
2522
|
+
self._y = self._variables[1]
|
|
2523
|
+
self._z = self._variables[2]
|
|
2524
|
+
|
|
2525
|
+
@cached_method
|
|
2526
|
+
def monomials(self):
|
|
2527
|
+
"""
|
|
2528
|
+
List the basis monomials of the form.
|
|
2529
|
+
|
|
2530
|
+
OUTPUT:
|
|
2531
|
+
|
|
2532
|
+
A tuple of monomials. They are in the same order as
|
|
2533
|
+
:meth:`coeffs`.
|
|
2534
|
+
|
|
2535
|
+
EXAMPLES::
|
|
2536
|
+
|
|
2537
|
+
sage: R.<x,y,z> = QQ[]
|
|
2538
|
+
sage: quadratic = invariant_theory.ternary_quadratic(x^2 + y*z)
|
|
2539
|
+
sage: quadratic.monomials()
|
|
2540
|
+
(x^2, y^2, z^2, x*y, x*z, y*z)
|
|
2541
|
+
"""
|
|
2542
|
+
R = self._ring
|
|
2543
|
+
x, y, z = self._x, self._y, self._z
|
|
2544
|
+
if self._homogeneous:
|
|
2545
|
+
return (x**2, y**2, z**2, x*y, x*z, y*z)
|
|
2546
|
+
else:
|
|
2547
|
+
return (x**2, y**2, R.one(), x*y, x, y)
|
|
2548
|
+
|
|
2549
|
+
@cached_method
|
|
2550
|
+
def coeffs(self):
|
|
2551
|
+
r"""
|
|
2552
|
+
Return the coefficients of a quadratic.
|
|
2553
|
+
|
|
2554
|
+
Given
|
|
2555
|
+
|
|
2556
|
+
.. MATH::
|
|
2557
|
+
|
|
2558
|
+
p(x,y) =&\;
|
|
2559
|
+
a_{20} x^{2} + a_{11} x y + a_{02} y^{2} +
|
|
2560
|
+
a_{10} x + a_{01} y + a_{00}
|
|
2561
|
+
|
|
2562
|
+
this function returns
|
|
2563
|
+
`a = (a_{20}, a_{02}, a_{00}, a_{11}, a_{10}, a_{01} )`
|
|
2564
|
+
|
|
2565
|
+
EXAMPLES::
|
|
2566
|
+
|
|
2567
|
+
sage: R.<x,y,z,a20,a11,a02,a10,a01,a00> = QQ[]
|
|
2568
|
+
sage: p = ( a20*x^2 + a11*x*y + a02*y^2 +
|
|
2569
|
+
....: a10*x*z + a01*y*z + a00*z^2 )
|
|
2570
|
+
sage: invariant_theory.ternary_quadratic(p, x,y,z).coeffs()
|
|
2571
|
+
(a20, a02, a00, a11, a10, a01)
|
|
2572
|
+
sage: invariant_theory.ternary_quadratic(p.subs(z=1), x, y).coeffs()
|
|
2573
|
+
(a20, a02, a00, a11, a10, a01)
|
|
2574
|
+
"""
|
|
2575
|
+
return self._extract_coefficients(self.monomials())
|
|
2576
|
+
|
|
2577
|
+
def scaled_coeffs(self):
|
|
2578
|
+
r"""
|
|
2579
|
+
Return the scaled coefficients of a quadratic.
|
|
2580
|
+
|
|
2581
|
+
Given
|
|
2582
|
+
|
|
2583
|
+
.. MATH::
|
|
2584
|
+
|
|
2585
|
+
p(x,y) =&\;
|
|
2586
|
+
a_{20} x^{2} + a_{11} x y + a_{02} y^{2} +
|
|
2587
|
+
a_{10} x + a_{01} y + a_{00}
|
|
2588
|
+
|
|
2589
|
+
this function returns
|
|
2590
|
+
`a = (a_{20}, a_{02}, a_{00}, a_{11}/2, a_{10}/2, a_{01}/2, )`
|
|
2591
|
+
|
|
2592
|
+
EXAMPLES::
|
|
2593
|
+
|
|
2594
|
+
sage: R.<x,y,z,a20,a11,a02,a10,a01,a00> = QQ[]
|
|
2595
|
+
sage: p = ( a20*x^2 + a11*x*y + a02*y^2 +
|
|
2596
|
+
....: a10*x*z + a01*y*z + a00*z^2 )
|
|
2597
|
+
sage: invariant_theory.ternary_quadratic(p, x,y,z).scaled_coeffs()
|
|
2598
|
+
(a20, a02, a00, 1/2*a11, 1/2*a10, 1/2*a01)
|
|
2599
|
+
sage: invariant_theory.ternary_quadratic(p.subs(z=1), x, y).scaled_coeffs()
|
|
2600
|
+
(a20, a02, a00, 1/2*a11, 1/2*a10, 1/2*a01)
|
|
2601
|
+
"""
|
|
2602
|
+
F = self._ring.base_ring()
|
|
2603
|
+
a200, a020, a002, a110, a101, a011 = self.coeffs()
|
|
2604
|
+
return (a200, a020, a002, a110/F(2), a101/F(2), a011/F(2))
|
|
2605
|
+
|
|
2606
|
+
def covariant_conic(self, other):
|
|
2607
|
+
"""
|
|
2608
|
+
Return the ternary quadratic covariant to ``self`` and ``other``.
|
|
2609
|
+
|
|
2610
|
+
INPUT:
|
|
2611
|
+
|
|
2612
|
+
- ``other`` -- another ternary quadratic
|
|
2613
|
+
|
|
2614
|
+
OUTPUT:
|
|
2615
|
+
|
|
2616
|
+
The so-called covariant conic, a ternary quadratic. It is
|
|
2617
|
+
symmetric under exchange of ``self`` and ``other``.
|
|
2618
|
+
|
|
2619
|
+
EXAMPLES::
|
|
2620
|
+
|
|
2621
|
+
sage: ring.<x,y,z> = QQ[]
|
|
2622
|
+
sage: Q = invariant_theory.ternary_quadratic(x^2 + y^2 + z^2)
|
|
2623
|
+
sage: R = invariant_theory.ternary_quadratic(x*y + x*z + y*z)
|
|
2624
|
+
sage: Q.covariant_conic(R)
|
|
2625
|
+
-x*y - x*z - y*z
|
|
2626
|
+
sage: R.covariant_conic(Q)
|
|
2627
|
+
-x*y - x*z - y*z
|
|
2628
|
+
|
|
2629
|
+
TESTS::
|
|
2630
|
+
|
|
2631
|
+
sage: R.<a,a_,b,b_,c,c_,f,f_,g,g_,h,h_,x,y,z> = QQ[]
|
|
2632
|
+
sage: p = ( a*x^2 + 2*h*x*y + b*y^2 +
|
|
2633
|
+
....: 2*g*x*z + 2*f*y*z + c*z^2 )
|
|
2634
|
+
sage: Q = invariant_theory.ternary_quadratic(p, [x,y,z])
|
|
2635
|
+
sage: Q.matrix()
|
|
2636
|
+
[a h g]
|
|
2637
|
+
[h b f]
|
|
2638
|
+
[g f c]
|
|
2639
|
+
sage: p = ( a_*x^2 + 2*h_*x*y + b_*y^2 +
|
|
2640
|
+
....: 2*g_*x*z + 2*f_*y*z + c_*z^2 )
|
|
2641
|
+
sage: Q_ = invariant_theory.ternary_quadratic(p, [x,y,z])
|
|
2642
|
+
sage: Q_.matrix()
|
|
2643
|
+
[a_ h_ g_]
|
|
2644
|
+
[h_ b_ f_]
|
|
2645
|
+
[g_ f_ c_]
|
|
2646
|
+
sage: QQ_ = Q.covariant_conic(Q_)
|
|
2647
|
+
sage: invariant_theory.ternary_quadratic(QQ_, [x,y,z]).matrix()
|
|
2648
|
+
[ b_*c + b*c_ - 2*f*f_ f_*g + f*g_ - c_*h - c*h_ -b_*g - b*g_ + f_*h + f*h_]
|
|
2649
|
+
[ f_*g + f*g_ - c_*h - c*h_ a_*c + a*c_ - 2*g*g_ -a_*f - a*f_ + g_*h + g*h_]
|
|
2650
|
+
[-b_*g - b*g_ + f_*h + f*h_ -a_*f - a*f_ + g_*h + g*h_ a_*b + a*b_ - 2*h*h_]
|
|
2651
|
+
"""
|
|
2652
|
+
return _covariant_conic(self.scaled_coeffs(), other.scaled_coeffs(),
|
|
2653
|
+
self.monomials())
|
|
2654
|
+
|
|
2655
|
+
|
|
2656
|
+
######################################################################
|
|
2657
|
+
|
|
2658
|
+
class TernaryCubic(AlgebraicForm):
|
|
2659
|
+
"""
|
|
2660
|
+
Invariant theory of a ternary cubic.
|
|
2661
|
+
|
|
2662
|
+
You should use the :class:`invariant_theory
|
|
2663
|
+
<InvariantTheoryFactory>` factory object to construct instances
|
|
2664
|
+
of this class. See :meth:`~InvariantTheoryFactory.ternary_cubic`
|
|
2665
|
+
for details.
|
|
2666
|
+
|
|
2667
|
+
TESTS::
|
|
2668
|
+
|
|
2669
|
+
sage: R.<x,y,z> = QQ[]
|
|
2670
|
+
sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + z^3)
|
|
2671
|
+
sage: cubic
|
|
2672
|
+
Ternary cubic with coefficients (1, 1, 1, 0, 0, 0, 0, 0, 0, 0)
|
|
2673
|
+
sage: TestSuite(cubic).run()
|
|
2674
|
+
"""
|
|
2675
|
+
|
|
2676
|
+
def __init__(self, n, d, polynomial, *args):
|
|
2677
|
+
"""
|
|
2678
|
+
The Python constructor.
|
|
2679
|
+
|
|
2680
|
+
TESTS::
|
|
2681
|
+
|
|
2682
|
+
sage: R.<x,y,z> = QQ[]
|
|
2683
|
+
sage: p = 2837*x^3 + 1363*x^2*y + 6709*x^2*z + \
|
|
2684
|
+
....: 5147*x*y^2 + 2769*x*y*z + 912*x*z^2 + 4976*y^3 + \
|
|
2685
|
+
....: 2017*y^2*z + 4589*y*z^2 + 9681*z^3
|
|
2686
|
+
sage: cubic = invariant_theory.ternary_cubic(p)
|
|
2687
|
+
sage: cubic._check_covariant('S_invariant', invariant=True)
|
|
2688
|
+
sage: cubic._check_covariant('T_invariant', invariant=True)
|
|
2689
|
+
sage: cubic._check_covariant('form')
|
|
2690
|
+
sage: cubic._check_covariant('Hessian')
|
|
2691
|
+
sage: cubic._check_covariant('Theta_covariant')
|
|
2692
|
+
sage: cubic._check_covariant('J_covariant')
|
|
2693
|
+
"""
|
|
2694
|
+
assert n == d == 3
|
|
2695
|
+
super().__init__(3, 3, polynomial, *args)
|
|
2696
|
+
self._x = self._variables[0]
|
|
2697
|
+
self._y = self._variables[1]
|
|
2698
|
+
self._z = self._variables[2]
|
|
2699
|
+
|
|
2700
|
+
@cached_method
|
|
2701
|
+
def monomials(self):
|
|
2702
|
+
"""
|
|
2703
|
+
List the basis monomials of the form.
|
|
2704
|
+
|
|
2705
|
+
OUTPUT:
|
|
2706
|
+
|
|
2707
|
+
A tuple of monomials. They are in the same order as
|
|
2708
|
+
:meth:`coeffs`.
|
|
2709
|
+
|
|
2710
|
+
EXAMPLES::
|
|
2711
|
+
|
|
2712
|
+
sage: R.<x,y,z> = QQ[]
|
|
2713
|
+
sage: cubic = invariant_theory.ternary_cubic(x^3+y*z^2)
|
|
2714
|
+
sage: cubic.monomials()
|
|
2715
|
+
(x^3, y^3, z^3, x^2*y, x^2*z, x*y^2, y^2*z, x*z^2, y*z^2, x*y*z)
|
|
2716
|
+
"""
|
|
2717
|
+
R = self._ring
|
|
2718
|
+
x, y, z = self._x, self._y, self._z
|
|
2719
|
+
if self._homogeneous:
|
|
2720
|
+
return (x**3, y**3, z**3, x**2*y, x**2*z, x*y**2,
|
|
2721
|
+
y**2*z, x*z**2, y*z**2, x*y*z)
|
|
2722
|
+
else:
|
|
2723
|
+
return (x**3, y**3, R.one(), x**2*y, x**2, x*y**2,
|
|
2724
|
+
y**2, x, y, x*y)
|
|
2725
|
+
|
|
2726
|
+
@cached_method
|
|
2727
|
+
def coeffs(self):
|
|
2728
|
+
r"""
|
|
2729
|
+
Return the coefficients of a cubic.
|
|
2730
|
+
|
|
2731
|
+
Given
|
|
2732
|
+
|
|
2733
|
+
.. MATH::
|
|
2734
|
+
|
|
2735
|
+
\begin{split}
|
|
2736
|
+
p(x,y) =&\;
|
|
2737
|
+
a_{30} x^{3} + a_{21} x^{2} y + a_{12} x y^{2} +
|
|
2738
|
+
a_{03} y^{3} + a_{20} x^{2} +
|
|
2739
|
+
\\ &\;
|
|
2740
|
+
a_{11} x y +
|
|
2741
|
+
a_{02} y^{2} + a_{10} x + a_{01} y + a_{00}
|
|
2742
|
+
\end{split}
|
|
2743
|
+
|
|
2744
|
+
this function returns
|
|
2745
|
+
`a = (a_{30}, a_{03}, a_{00}, a_{21}, a_{20}, a_{12}, a_{02}, a_{10}, a_{01}, a_{11})`
|
|
2746
|
+
|
|
2747
|
+
EXAMPLES::
|
|
2748
|
+
|
|
2749
|
+
sage: R.<x,y,z,a30,a21,a12,a03,a20,a11,a02,a10,a01,a00> = QQ[]
|
|
2750
|
+
sage: p = ( a30*x^3 + a21*x^2*y + a12*x*y^2 + a03*y^3 + a20*x^2*z +
|
|
2751
|
+
....: a11*x*y*z + a02*y^2*z + a10*x*z^2 + a01*y*z^2 + a00*z^3 )
|
|
2752
|
+
sage: invariant_theory.ternary_cubic(p, x,y,z).coeffs()
|
|
2753
|
+
(a30, a03, a00, a21, a20, a12, a02, a10, a01, a11)
|
|
2754
|
+
sage: invariant_theory.ternary_cubic(p.subs(z=1), x, y).coeffs()
|
|
2755
|
+
(a30, a03, a00, a21, a20, a12, a02, a10, a01, a11)
|
|
2756
|
+
"""
|
|
2757
|
+
return self._extract_coefficients(self.monomials())
|
|
2758
|
+
|
|
2759
|
+
def scaled_coeffs(self):
|
|
2760
|
+
r"""
|
|
2761
|
+
Return the coefficients of a cubic.
|
|
2762
|
+
|
|
2763
|
+
Compared to :meth:`coeffs`, this method returns rescaled
|
|
2764
|
+
coefficients that are often used in invariant theory.
|
|
2765
|
+
|
|
2766
|
+
Given
|
|
2767
|
+
|
|
2768
|
+
.. MATH::
|
|
2769
|
+
|
|
2770
|
+
\begin{split}
|
|
2771
|
+
p(x,y) =&\;
|
|
2772
|
+
a_{30} x^{3} + a_{21} x^{2} y + a_{12} x y^{2} +
|
|
2773
|
+
a_{03} y^{3} + a_{20} x^{2} +
|
|
2774
|
+
\\ &\;
|
|
2775
|
+
a_{11} x y +
|
|
2776
|
+
a_{02} y^{2} + a_{10} x + a_{01} y + a_{00}
|
|
2777
|
+
\end{split}
|
|
2778
|
+
|
|
2779
|
+
this function returns
|
|
2780
|
+
`a = (a_{30}, a_{03}, a_{00}, a_{21}/3, a_{20}/3, a_{12}/3, a_{02}/3, a_{10}/3, a_{01}/3, a_{11}/6)`
|
|
2781
|
+
|
|
2782
|
+
EXAMPLES::
|
|
2783
|
+
|
|
2784
|
+
sage: R.<x,y,z,a30,a21,a12,a03,a20,a11,a02,a10,a01,a00> = QQ[]
|
|
2785
|
+
sage: p = ( a30*x^3 + a21*x^2*y + a12*x*y^2 + a03*y^3 + a20*x^2*z +
|
|
2786
|
+
....: a11*x*y*z + a02*y^2*z + a10*x*z^2 + a01*y*z^2 + a00*z^3 )
|
|
2787
|
+
sage: invariant_theory.ternary_cubic(p, x,y,z).scaled_coeffs()
|
|
2788
|
+
(a30, a03, a00, 1/3*a21, 1/3*a20, 1/3*a12, 1/3*a02, 1/3*a10, 1/3*a01, 1/6*a11)
|
|
2789
|
+
"""
|
|
2790
|
+
a = self.coeffs()
|
|
2791
|
+
F = self._ring.base_ring()
|
|
2792
|
+
return (a[0], a[1], a[2],
|
|
2793
|
+
1/F(3)*a[3], 1/F(3)*a[4], 1/F(3)*a[5],
|
|
2794
|
+
1/F(3)*a[6], 1/F(3)*a[7], 1/F(3)*a[8],
|
|
2795
|
+
1/F(6)*a[9])
|
|
2796
|
+
|
|
2797
|
+
def S_invariant(self):
|
|
2798
|
+
"""
|
|
2799
|
+
Return the S-invariant.
|
|
2800
|
+
|
|
2801
|
+
EXAMPLES::
|
|
2802
|
+
|
|
2803
|
+
sage: R.<x,y,z> = QQ[]
|
|
2804
|
+
sage: cubic = invariant_theory.ternary_cubic(x^2*y + y^3 + z^3 + x*y*z)
|
|
2805
|
+
sage: cubic.S_invariant()
|
|
2806
|
+
-1/1296
|
|
2807
|
+
"""
|
|
2808
|
+
a, b, c, a2, a3, b1, b3, c1, c2, m = self.scaled_coeffs()
|
|
2809
|
+
S = (a*b*c*m-(b*c*a2*a3+c*a*b1*b3+a*b*c1*c2)
|
|
2810
|
+
- m*(a*b3*c2+b*c1*a3+c*a2*b1)
|
|
2811
|
+
+ (a*b1*c2**2+a*c1*b3**2+b*a2*c1**2+b*c2*a3**2+c*b3*a2**2+c*a3*b1**2)
|
|
2812
|
+
- m**4+2*m**2*(b1*c1+c2*a2+a3*b3)
|
|
2813
|
+
- 3*m*(a2*b3*c1+a3*b1*c2)
|
|
2814
|
+
- (b1**2*c1**2+c2**2*a2**2+a3**2*b3**2)
|
|
2815
|
+
+ (c2*a2*a3*b3+a3*b3*b1*c1+b1*c1*c2*a2))
|
|
2816
|
+
return S
|
|
2817
|
+
|
|
2818
|
+
def T_invariant(self):
|
|
2819
|
+
"""
|
|
2820
|
+
Return the T-invariant.
|
|
2821
|
+
|
|
2822
|
+
EXAMPLES::
|
|
2823
|
+
|
|
2824
|
+
sage: R.<x,y,z> = QQ[]
|
|
2825
|
+
sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + z^3)
|
|
2826
|
+
sage: cubic.T_invariant()
|
|
2827
|
+
1
|
|
2828
|
+
|
|
2829
|
+
sage: R.<x,y,z,t> = GF(7)[]
|
|
2830
|
+
sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + z^3 + t*x*y*z, [x,y,z])
|
|
2831
|
+
sage: cubic.T_invariant()
|
|
2832
|
+
-t^6 - t^3 + 1
|
|
2833
|
+
"""
|
|
2834
|
+
a, b, c, a2, a3, b1, b3, c1, c2, m = self.scaled_coeffs()
|
|
2835
|
+
T = (a**2*b**2*c**2-6*a*b*c*(a*b3*c2+b*c1*a3+c*a2*b1)
|
|
2836
|
+
- 20*a*b*c*m**3+12*a*b*c*m*(b1*c1+c2*a2+a3*b3)
|
|
2837
|
+
+ 6*a*b*c*(a2*b3*c1+a3*b1*c2) +
|
|
2838
|
+
4*(a**2*b*c2**3+a**2*c*b3**3+b**2*c*a3**3 +
|
|
2839
|
+
b**2*a*c1**3+c**2*a*b1**3+c**2*b*a2**3)
|
|
2840
|
+
+ 36*m**2*(b*c*a2*a3+c*a*b1*b3+a*b*c1*c2)
|
|
2841
|
+
- 24*m*(b*c*b1*a3**2+b*c*c1*a2**2+c*a*c2*b1**2+c*a*a2*b3**2+a*b*a3*c2**2 +
|
|
2842
|
+
a*b*b3*c1**2)
|
|
2843
|
+
- 3*(a**2*b3**2*c2**2+b**2*c1**2*a3**2+c**2*a2**2*b1**2) +
|
|
2844
|
+
18*(b*c*b1*c1*a2*a3+c*a*c2*a2*b3*b1+a*b*a3*b3*c1*c2)
|
|
2845
|
+
- 12*(b*c*c2*a3*a2**2+b*c*b3*a2*a3**2+c*a*c1*b3*b1**2 +
|
|
2846
|
+
c*a*a3*b1*b3**2+a*b*a2*c1*c2**2+a*b*b1*c2*c1**2)
|
|
2847
|
+
- 12*m**3*(a*b3*c2+b*c1*a3+c*a2*b1)
|
|
2848
|
+
+ 12*m**2*(a*b1*c2**2+a*c1*b3**2+b*a2*c1**2 +
|
|
2849
|
+
b*c2*a3**2+c*b3*a2**2+c*a3*b1**2)
|
|
2850
|
+
- 60*m*(a*b1*b3*c1*c2+b*c1*c2*a2*a3+c*a2*a3*b1*b3)
|
|
2851
|
+
+ 12*m*(a*a2*b3*c2**2+a*a3*c2*b3**2+b*b3*c1*a3**2 +
|
|
2852
|
+
b*b1*a3*c1**2+c*c1*a2*b1**2+c*c2*b1*a2**2)
|
|
2853
|
+
+ 6*(a*b3*c2+b*c1*a3+c*a2*b1)*(a2*b3*c1+a3*b1*c2)
|
|
2854
|
+
+ 24*(a*b1*b3**2*c1**2+a*c1*c2**2*b1**2+b*c2*c1**2*a2**2
|
|
2855
|
+
+ b*a2*a3**2*c2**2+c*a3*a2**2*b3**2+c*b3*b1**2*a3**2)
|
|
2856
|
+
- 12*(a*a2*b1*c2**3+a*a3*c1*b3**3+b*b3*c2*a3**3+b*b1*a2*c1**3
|
|
2857
|
+
+ c*c1*a3*b1**3+c*c2*b3*a2**3)
|
|
2858
|
+
- 8*m**6+24*m**4*(b1*c1+c2*a2+a3*b3)-36*m**3*(a2*b3*c1+a3*b1*c2)
|
|
2859
|
+
- 12*m**2*(b1*c1*c2*a2+c2*a2*a3*b3+a3*b3*b1*c1)
|
|
2860
|
+
- 24*m**2*(b1**2*c1**2+c2**2*a2**2+a3**2*b3**2)
|
|
2861
|
+
+ 36*m*(a2*b3*c1+a3*b1*c2)*(b1*c1+c2*a2+a3*b3)
|
|
2862
|
+
+ 8*(b1**3*c1**3+c2**3*a2**3+a3**3*b3**3)
|
|
2863
|
+
- 27*(a2**2*b3**2*c1**2+a3**2*b1**2*c2**2)-6*b1*c1*c2*a2*a3*b3
|
|
2864
|
+
- 12*(b1**2*c1**2*c2*a2+b1**2*c1**2*a3*b3+c2**2*a2**2*a3*b3 +
|
|
2865
|
+
c2**2*a2**2*b1*c1+a3**2*b3**2*b1*c1+a3**2*b3**2*c2*a2))
|
|
2866
|
+
return T
|
|
2867
|
+
|
|
2868
|
+
@cached_method
|
|
2869
|
+
def polar_conic(self):
|
|
2870
|
+
r"""
|
|
2871
|
+
Return the polar conic of the cubic.
|
|
2872
|
+
|
|
2873
|
+
OUTPUT:
|
|
2874
|
+
|
|
2875
|
+
Given the ternary cubic `f(X,Y,Z)`, this method returns the
|
|
2876
|
+
symmetric matrix `A(x,y,z)` defined by
|
|
2877
|
+
|
|
2878
|
+
.. MATH::
|
|
2879
|
+
|
|
2880
|
+
x f_X + y f_Y + z f_Z = (X,Y,Z) \cdot A(x,y,z) \cdot (X,Y,Z)^t
|
|
2881
|
+
|
|
2882
|
+
EXAMPLES::
|
|
2883
|
+
|
|
2884
|
+
sage: R.<x,y,z,X,Y,Z,a30,a21,a12,a03,a20,a11,a02,a10,a01,a00> = QQ[]
|
|
2885
|
+
sage: p = ( a30*x^3 + a21*x^2*y + a12*x*y^2 + a03*y^3 + a20*x^2*z +
|
|
2886
|
+
....: a11*x*y*z + a02*y^2*z + a10*x*z^2 + a01*y*z^2 + a00*z^3 )
|
|
2887
|
+
sage: cubic = invariant_theory.ternary_cubic(p, x,y,z)
|
|
2888
|
+
sage: cubic.polar_conic()
|
|
2889
|
+
[ 3*x*a30 + y*a21 + z*a20 x*a21 + y*a12 + 1/2*z*a11 x*a20 + 1/2*y*a11 + z*a10]
|
|
2890
|
+
[x*a21 + y*a12 + 1/2*z*a11 x*a12 + 3*y*a03 + z*a02 1/2*x*a11 + y*a02 + z*a01]
|
|
2891
|
+
[x*a20 + 1/2*y*a11 + z*a10 1/2*x*a11 + y*a02 + z*a01 x*a10 + y*a01 + 3*z*a00]
|
|
2892
|
+
|
|
2893
|
+
sage: polar_eqn = X*p.derivative(x) + Y*p.derivative(y) + Z*p.derivative(z)
|
|
2894
|
+
sage: polar = invariant_theory.ternary_quadratic(polar_eqn, [x,y,z])
|
|
2895
|
+
sage: polar.matrix().subs(X=x,Y=y,Z=z) == cubic.polar_conic()
|
|
2896
|
+
True
|
|
2897
|
+
"""
|
|
2898
|
+
a30, a03, a00, a21, a20, a12, a02, a10, a01, a11 = self.coeffs()
|
|
2899
|
+
if self._homogeneous:
|
|
2900
|
+
x, y, z = self.variables()
|
|
2901
|
+
else:
|
|
2902
|
+
x, y, z = (self._x, self._y, 1)
|
|
2903
|
+
F = self._ring.base_ring()
|
|
2904
|
+
A00 = 3*x*a30 + y*a21 + z*a20
|
|
2905
|
+
A11 = x*a12 + 3*y*a03 + z*a02
|
|
2906
|
+
A22 = x*a10 + y*a01 + 3*z*a00
|
|
2907
|
+
A01 = x*a21 + y*a12 + 1/F(2)*z*a11
|
|
2908
|
+
A02 = x*a20 + 1/F(2)*y*a11 + z*a10
|
|
2909
|
+
A12 = 1/F(2)*x*a11 + y*a02 + z*a01
|
|
2910
|
+
return matrix(self._ring, [[A00, A01, A02], [A01, A11, A12], [A02, A12, A22]])
|
|
2911
|
+
|
|
2912
|
+
@cached_method
|
|
2913
|
+
def Hessian(self):
|
|
2914
|
+
"""
|
|
2915
|
+
Return the Hessian covariant.
|
|
2916
|
+
|
|
2917
|
+
OUTPUT:
|
|
2918
|
+
|
|
2919
|
+
The Hessian matrix multiplied with the conventional
|
|
2920
|
+
normalization factor `1/216`.
|
|
2921
|
+
|
|
2922
|
+
EXAMPLES::
|
|
2923
|
+
|
|
2924
|
+
sage: R.<x,y,z> = QQ[]
|
|
2925
|
+
sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + z^3)
|
|
2926
|
+
sage: cubic.Hessian()
|
|
2927
|
+
x*y*z
|
|
2928
|
+
|
|
2929
|
+
sage: R.<x,y> = QQ[]
|
|
2930
|
+
sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + 1)
|
|
2931
|
+
sage: cubic.Hessian()
|
|
2932
|
+
x*y
|
|
2933
|
+
"""
|
|
2934
|
+
a30, a03, a00, a21, a20, a12, a02, a10, a01, a11 = self.coeffs()
|
|
2935
|
+
if self._homogeneous:
|
|
2936
|
+
x, y, z = self.variables()
|
|
2937
|
+
else:
|
|
2938
|
+
x, y, z = self._x, self._y, 1
|
|
2939
|
+
Uxx = 6*x*a30 + 2*y*a21 + 2*z*a20
|
|
2940
|
+
Uxy = 2*x*a21 + 2*y*a12 + z*a11
|
|
2941
|
+
Uxz = 2*x*a20 + y*a11 + 2*z*a10
|
|
2942
|
+
Uyy = 2*x*a12 + 6*y*a03 + 2*z*a02
|
|
2943
|
+
Uyz = x*a11 + 2*y*a02 + 2*z*a01
|
|
2944
|
+
Uzz = 2*x*a10 + 2*y*a01 + 6*z*a00
|
|
2945
|
+
H = matrix(self._ring, [[Uxx, Uxy, Uxz],
|
|
2946
|
+
[Uxy, Uyy, Uyz],
|
|
2947
|
+
[Uxz, Uyz, Uzz]])
|
|
2948
|
+
F = self._ring.base_ring()
|
|
2949
|
+
return 1/F(216) * H.det()
|
|
2950
|
+
|
|
2951
|
+
def Theta_covariant(self):
|
|
2952
|
+
r"""
|
|
2953
|
+
Return the `\Theta` covariant.
|
|
2954
|
+
|
|
2955
|
+
EXAMPLES::
|
|
2956
|
+
|
|
2957
|
+
sage: R.<x,y,z> = QQ[]
|
|
2958
|
+
sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + z^3)
|
|
2959
|
+
sage: cubic.Theta_covariant()
|
|
2960
|
+
-x^3*y^3 - x^3*z^3 - y^3*z^3
|
|
2961
|
+
|
|
2962
|
+
sage: R.<x,y> = QQ[]
|
|
2963
|
+
sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + 1)
|
|
2964
|
+
sage: cubic.Theta_covariant()
|
|
2965
|
+
-x^3*y^3 - x^3 - y^3
|
|
2966
|
+
|
|
2967
|
+
sage: R.<x,y,z,a30,a21,a12,a03,a20,a11,a02,a10,a01,a00> = QQ[]
|
|
2968
|
+
sage: p = ( a30*x^3 + a21*x^2*y + a12*x*y^2 + a03*y^3 + a20*x^2*z +
|
|
2969
|
+
....: a11*x*y*z + a02*y^2*z + a10*x*z^2 + a01*y*z^2 + a00*z^3 )
|
|
2970
|
+
sage: cubic = invariant_theory.ternary_cubic(p, x,y,z)
|
|
2971
|
+
sage: len(list(cubic.Theta_covariant()))
|
|
2972
|
+
6952
|
|
2973
|
+
"""
|
|
2974
|
+
U_conic = self.polar_conic().adjugate()
|
|
2975
|
+
U_coeffs = (U_conic[0, 0], U_conic[1, 1], U_conic[2, 2],
|
|
2976
|
+
U_conic[0, 1], U_conic[0, 2], U_conic[1, 2])
|
|
2977
|
+
H_conic = TernaryCubic(3, 3, self.Hessian(), self.variables()).polar_conic().adjugate()
|
|
2978
|
+
H_coeffs = (H_conic[0, 0], H_conic[1, 1], H_conic[2, 2],
|
|
2979
|
+
H_conic[0, 1], H_conic[0, 2], H_conic[1, 2])
|
|
2980
|
+
quadratic = TernaryQuadratic(3, 2, self._ring.zero(), self.variables())
|
|
2981
|
+
F = self._ring.base_ring()
|
|
2982
|
+
return 1/F(9) * _covariant_conic(U_coeffs, H_coeffs, quadratic.monomials())
|
|
2983
|
+
|
|
2984
|
+
def J_covariant(self):
|
|
2985
|
+
"""
|
|
2986
|
+
Return the J-covariant of the ternary cubic.
|
|
2987
|
+
|
|
2988
|
+
EXAMPLES::
|
|
2989
|
+
|
|
2990
|
+
sage: R.<x,y,z> = QQ[]
|
|
2991
|
+
sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + z^3)
|
|
2992
|
+
sage: cubic.J_covariant()
|
|
2993
|
+
x^6*y^3 - x^3*y^6 - x^6*z^3 + y^6*z^3 + x^3*z^6 - y^3*z^6
|
|
2994
|
+
|
|
2995
|
+
sage: R.<x,y> = QQ[]
|
|
2996
|
+
sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + 1)
|
|
2997
|
+
sage: cubic.J_covariant()
|
|
2998
|
+
x^6*y^3 - x^3*y^6 - x^6 + y^6 + x^3 - y^3
|
|
2999
|
+
"""
|
|
3000
|
+
F = self._ring.base_ring()
|
|
3001
|
+
return 1 / F(9) * self._jacobian_determinant(
|
|
3002
|
+
[self.form(), 3],
|
|
3003
|
+
[self.Hessian(), 3],
|
|
3004
|
+
[self.Theta_covariant(), 6])
|
|
3005
|
+
|
|
3006
|
+
def syzygy(self, U, S, T, H, Theta, J):
|
|
3007
|
+
r"""
|
|
3008
|
+
Return the syzygy of the cubic evaluated on the invariants
|
|
3009
|
+
and covariants.
|
|
3010
|
+
|
|
3011
|
+
INPUT:
|
|
3012
|
+
|
|
3013
|
+
- ``U``, ``S``, ``T``, ``H``, ``Theta``, ``J`` --
|
|
3014
|
+
polynomials from the same polynomial ring.
|
|
3015
|
+
|
|
3016
|
+
OUTPUT:
|
|
3017
|
+
|
|
3018
|
+
0 if evaluated for the form, the S invariant, the T invariant,
|
|
3019
|
+
the Hessian, the `\Theta` covariant and the J-covariant
|
|
3020
|
+
of a ternary cubic.
|
|
3021
|
+
|
|
3022
|
+
EXAMPLES::
|
|
3023
|
+
|
|
3024
|
+
sage: R.<x,y,z> = QQ[]
|
|
3025
|
+
sage: monomials = (x^3, y^3, z^3, x^2*y, x^2*z, x*y^2,
|
|
3026
|
+
....: y^2*z, x*z^2, y*z^2, x*y*z)
|
|
3027
|
+
sage: random_poly = sum([ randint(0,10000) * m for m in monomials ])
|
|
3028
|
+
sage: cubic = invariant_theory.ternary_cubic(random_poly)
|
|
3029
|
+
sage: U = cubic.form()
|
|
3030
|
+
sage: S = cubic.S_invariant()
|
|
3031
|
+
sage: T = cubic.T_invariant()
|
|
3032
|
+
sage: H = cubic.Hessian()
|
|
3033
|
+
sage: Theta = cubic.Theta_covariant()
|
|
3034
|
+
sage: J = cubic.J_covariant()
|
|
3035
|
+
sage: cubic.syzygy(U, S, T, H, Theta, J)
|
|
3036
|
+
0
|
|
3037
|
+
"""
|
|
3038
|
+
return ( -J**2 + 4*Theta**3 + T*U**2*Theta**2 +
|
|
3039
|
+
Theta*(-4*S**3*U**4 + 2*S*T*U**3*H - 72*S**2*U**2*H**2
|
|
3040
|
+
- 18*T*U*H**3 + 108*S*H**4)
|
|
3041
|
+
- 16*S**4*U**5*H - 11*S**2*T*U**4*H**2 - 4*T**2*U**3*H**3
|
|
3042
|
+
+ 54*S*T*U**2*H**4 - 432*S**2*U*H**5 - 27*T*H**6 )
|
|
3043
|
+
|
|
3044
|
+
|
|
3045
|
+
######################################################################
|
|
3046
|
+
|
|
3047
|
+
class SeveralAlgebraicForms(FormsBase):
|
|
3048
|
+
"""
|
|
3049
|
+
The base class of multiple algebraic forms (i.e. homogeneous polynomials).
|
|
3050
|
+
|
|
3051
|
+
You should only instantiate the derived classes of this base
|
|
3052
|
+
class.
|
|
3053
|
+
|
|
3054
|
+
See :class:`AlgebraicForm` for the base class of a single
|
|
3055
|
+
algebraic form.
|
|
3056
|
+
|
|
3057
|
+
INPUT:
|
|
3058
|
+
|
|
3059
|
+
- ``forms`` -- list/tuple/iterable of at least one
|
|
3060
|
+
:class:`AlgebraicForm` object, all with the same number of
|
|
3061
|
+
variables. Interpreted as multiple homogeneous polynomials in a
|
|
3062
|
+
common polynomial ring.
|
|
3063
|
+
|
|
3064
|
+
EXAMPLES::
|
|
3065
|
+
|
|
3066
|
+
sage: from sage.rings.invariants.invariant_theory import AlgebraicForm, SeveralAlgebraicForms
|
|
3067
|
+
sage: R.<x,y> = QQ[]
|
|
3068
|
+
sage: p = AlgebraicForm(2, 2, x^2, (x,y))
|
|
3069
|
+
sage: q = AlgebraicForm(2, 2, y^2, (x,y))
|
|
3070
|
+
sage: pq = SeveralAlgebraicForms([p, q])
|
|
3071
|
+
"""
|
|
3072
|
+
|
|
3073
|
+
def __init__(self, forms):
|
|
3074
|
+
"""
|
|
3075
|
+
The Python constructor.
|
|
3076
|
+
|
|
3077
|
+
TESTS::
|
|
3078
|
+
|
|
3079
|
+
sage: from sage.rings.invariants.invariant_theory import AlgebraicForm, SeveralAlgebraicForms
|
|
3080
|
+
sage: R.<x,y,z> = QQ[]
|
|
3081
|
+
sage: p = AlgebraicForm(2, 2, x^2 + y^2)
|
|
3082
|
+
sage: q = AlgebraicForm(2, 3, x^3 + y^3)
|
|
3083
|
+
sage: r = AlgebraicForm(3, 3, x^3 + y^3 + z^3)
|
|
3084
|
+
sage: pq = SeveralAlgebraicForms([p, q])
|
|
3085
|
+
sage: pr = SeveralAlgebraicForms([p, r])
|
|
3086
|
+
Traceback (most recent call last):
|
|
3087
|
+
...
|
|
3088
|
+
ValueError: all forms must be in the same variables
|
|
3089
|
+
"""
|
|
3090
|
+
forms = tuple(forms)
|
|
3091
|
+
f = forms[0]
|
|
3092
|
+
super().__init__(f._n, f._homogeneous, f._ring, f._variables)
|
|
3093
|
+
s = set(f._variables)
|
|
3094
|
+
if not all(set(f._variables) == s for f in forms):
|
|
3095
|
+
raise ValueError('all forms must be in the same variables')
|
|
3096
|
+
self._forms = forms
|
|
3097
|
+
|
|
3098
|
+
def __richcmp__(self, other, op):
|
|
3099
|
+
"""
|
|
3100
|
+
Compare ``self`` with ``other``.
|
|
3101
|
+
|
|
3102
|
+
EXAMPLES::
|
|
3103
|
+
|
|
3104
|
+
sage: R.<x,y> = QQ[]
|
|
3105
|
+
sage: q1 = invariant_theory.quadratic_form(x^2 + y^2)
|
|
3106
|
+
sage: q2 = invariant_theory.quadratic_form(x*y)
|
|
3107
|
+
sage: from sage.rings.invariants.invariant_theory import SeveralAlgebraicForms
|
|
3108
|
+
sage: two_inv = SeveralAlgebraicForms([q1, q2])
|
|
3109
|
+
sage: two_inv == 'foo'
|
|
3110
|
+
False
|
|
3111
|
+
sage: two_inv == two_inv
|
|
3112
|
+
True
|
|
3113
|
+
"""
|
|
3114
|
+
if type(self) is not type(other):
|
|
3115
|
+
return NotImplemented
|
|
3116
|
+
return richcmp(self._forms, other._forms, op)
|
|
3117
|
+
|
|
3118
|
+
def _repr_(self):
|
|
3119
|
+
"""
|
|
3120
|
+
Return a string representation.
|
|
3121
|
+
|
|
3122
|
+
EXAMPLES::
|
|
3123
|
+
|
|
3124
|
+
sage: R.<x,y> = QQ[]
|
|
3125
|
+
sage: q1 = invariant_theory.quadratic_form(x^2 + y^2)
|
|
3126
|
+
sage: q2 = invariant_theory.quadratic_form(x*y)
|
|
3127
|
+
sage: q3 = invariant_theory.quadratic_form((x + y)^2)
|
|
3128
|
+
sage: from sage.rings.invariants.invariant_theory import SeveralAlgebraicForms
|
|
3129
|
+
sage: SeveralAlgebraicForms([q1]) # indirect doctest
|
|
3130
|
+
Binary quadratic with coefficients (1, 1, 0)
|
|
3131
|
+
sage: SeveralAlgebraicForms([q1, q2]) # indirect doctest
|
|
3132
|
+
Joint binary quadratic with coefficients (1, 1, 0) and binary
|
|
3133
|
+
quadratic with coefficients (0, 0, 1)
|
|
3134
|
+
sage: SeveralAlgebraicForms([q1, q2, q3]) # indirect doctest
|
|
3135
|
+
Joint binary quadratic with coefficients (1, 1, 0), binary
|
|
3136
|
+
quadratic with coefficients (0, 0, 1), and binary quadratic
|
|
3137
|
+
with coefficients (1, 1, 2)
|
|
3138
|
+
"""
|
|
3139
|
+
if self.n_forms() == 1:
|
|
3140
|
+
return self.get_form(0)._repr_()
|
|
3141
|
+
if self.n_forms() == 2:
|
|
3142
|
+
return 'Joint ' + self.get_form(0)._repr_().lower() + \
|
|
3143
|
+
' and ' + self.get_form(1)._repr_().lower()
|
|
3144
|
+
s = 'Joint '
|
|
3145
|
+
for i in range(self.n_forms()-1):
|
|
3146
|
+
s += self.get_form(i)._repr_().lower() + ', '
|
|
3147
|
+
s += 'and ' + self.get_form(-1)._repr_().lower()
|
|
3148
|
+
return s
|
|
3149
|
+
|
|
3150
|
+
def n_forms(self):
|
|
3151
|
+
"""
|
|
3152
|
+
Return the number of forms.
|
|
3153
|
+
|
|
3154
|
+
EXAMPLES::
|
|
3155
|
+
|
|
3156
|
+
sage: R.<x,y> = QQ[]
|
|
3157
|
+
sage: q1 = invariant_theory.quadratic_form(x^2 + y^2)
|
|
3158
|
+
sage: q2 = invariant_theory.quadratic_form(x*y)
|
|
3159
|
+
sage: from sage.rings.invariants.invariant_theory import SeveralAlgebraicForms
|
|
3160
|
+
sage: q12 = SeveralAlgebraicForms([q1, q2])
|
|
3161
|
+
sage: q12.n_forms()
|
|
3162
|
+
2
|
|
3163
|
+
sage: len(q12) == q12.n_forms() # syntactic sugar
|
|
3164
|
+
True
|
|
3165
|
+
"""
|
|
3166
|
+
return len(self._forms)
|
|
3167
|
+
|
|
3168
|
+
__len__ = n_forms
|
|
3169
|
+
|
|
3170
|
+
def get_form(self, i):
|
|
3171
|
+
"""
|
|
3172
|
+
Return the `i`-th form.
|
|
3173
|
+
|
|
3174
|
+
EXAMPLES::
|
|
3175
|
+
|
|
3176
|
+
sage: R.<x,y> = QQ[]
|
|
3177
|
+
sage: q1 = invariant_theory.quadratic_form(x^2 + y^2)
|
|
3178
|
+
sage: q2 = invariant_theory.quadratic_form(x*y)
|
|
3179
|
+
sage: from sage.rings.invariants.invariant_theory import SeveralAlgebraicForms
|
|
3180
|
+
sage: q12 = SeveralAlgebraicForms([q1, q2])
|
|
3181
|
+
sage: q12.get_form(0) is q1
|
|
3182
|
+
True
|
|
3183
|
+
sage: q12.get_form(1) is q2
|
|
3184
|
+
True
|
|
3185
|
+
sage: q12[0] is q12.get_form(0) # syntactic sugar
|
|
3186
|
+
True
|
|
3187
|
+
sage: q12[1] is q12.get_form(1) # syntactic sugar
|
|
3188
|
+
True
|
|
3189
|
+
"""
|
|
3190
|
+
return self._forms[i]
|
|
3191
|
+
|
|
3192
|
+
__getitem__ = get_form
|
|
3193
|
+
|
|
3194
|
+
def homogenized(self, var='h'):
|
|
3195
|
+
"""
|
|
3196
|
+
Return form as defined by a homogeneous polynomial.
|
|
3197
|
+
|
|
3198
|
+
INPUT:
|
|
3199
|
+
|
|
3200
|
+
- ``var`` -- either a variable name, variable index or a
|
|
3201
|
+
variable (default: ``'h'``)
|
|
3202
|
+
|
|
3203
|
+
OUTPUT:
|
|
3204
|
+
|
|
3205
|
+
The same algebraic form, but defined by a homogeneous
|
|
3206
|
+
polynomial.
|
|
3207
|
+
|
|
3208
|
+
EXAMPLES::
|
|
3209
|
+
|
|
3210
|
+
sage: R.<x,y,z> = QQ[]
|
|
3211
|
+
sage: q = invariant_theory.quaternary_biquadratic(x^2 + 1, y^2 + 1, [x,y,z])
|
|
3212
|
+
sage: q
|
|
3213
|
+
Joint quaternary quadratic with coefficients (1, 0, 0, 1, 0, 0, 0, 0, 0, 0)
|
|
3214
|
+
and quaternary quadratic with coefficients (0, 1, 0, 1, 0, 0, 0, 0, 0, 0)
|
|
3215
|
+
sage: q.homogenized()
|
|
3216
|
+
Joint quaternary quadratic with coefficients (1, 0, 0, 1, 0, 0, 0, 0, 0, 0)
|
|
3217
|
+
and quaternary quadratic with coefficients (0, 1, 0, 1, 0, 0, 0, 0, 0, 0)
|
|
3218
|
+
sage: type(q) is type(q.homogenized())
|
|
3219
|
+
True
|
|
3220
|
+
"""
|
|
3221
|
+
if self._homogeneous:
|
|
3222
|
+
return self
|
|
3223
|
+
forms = [f.homogenized(var=var) for f in self._forms]
|
|
3224
|
+
return self.__class__(forms)
|
|
3225
|
+
|
|
3226
|
+
def _check_covariant(self, method_name, g=None, invariant=False):
|
|
3227
|
+
r"""
|
|
3228
|
+
Test whether ``method_name`` actually returns a covariant.
|
|
3229
|
+
|
|
3230
|
+
INPUT:
|
|
3231
|
+
|
|
3232
|
+
- ``method_name`` -- string; the name of the method that
|
|
3233
|
+
returns the invariant / covariant to test
|
|
3234
|
+
|
|
3235
|
+
- ``g`` -- a `SL(n,\CC)` matrix or ``None`` (default). The
|
|
3236
|
+
test will be to check that the covariant transforms
|
|
3237
|
+
correctly under this special linear group element acting on
|
|
3238
|
+
the homogeneous variables. If ``None``, a random matrix will
|
|
3239
|
+
be picked.
|
|
3240
|
+
|
|
3241
|
+
- ``invariant`` -- boolean; whether to additionally test that
|
|
3242
|
+
it is an invariant
|
|
3243
|
+
|
|
3244
|
+
EXAMPLES::
|
|
3245
|
+
|
|
3246
|
+
sage: R.<x,y,z,w> = QQ[]
|
|
3247
|
+
sage: q = invariant_theory.quaternary_biquadratic(x^2+y^2+z^2+w^2, x*y+y*z+z*w+x*w)
|
|
3248
|
+
sage: q._check_covariant('Delta_invariant', invariant=True)
|
|
3249
|
+
sage: q._check_covariant('T_prime_covariant')
|
|
3250
|
+
sage: q._check_covariant('T_prime_covariant', invariant=True)
|
|
3251
|
+
Traceback (most recent call last):
|
|
3252
|
+
...
|
|
3253
|
+
AssertionError: not invariant
|
|
3254
|
+
"""
|
|
3255
|
+
assert self._homogeneous
|
|
3256
|
+
from sage.matrix.constructor import vector, random_matrix
|
|
3257
|
+
if g is None:
|
|
3258
|
+
F = self._ring.base_ring()
|
|
3259
|
+
g = random_matrix(F, self._n, algorithm='unimodular')
|
|
3260
|
+
v = vector(self.variables())
|
|
3261
|
+
g_v = g*v
|
|
3262
|
+
transform = {v[i]: g_v[i] for i in range(self._n)}
|
|
3263
|
+
# The covariant of the transformed form
|
|
3264
|
+
transformed = [f.transformed(transform) for f in self._forms]
|
|
3265
|
+
g_self = self.__class__(transformed)
|
|
3266
|
+
cov_g = getattr(g_self, method_name)()
|
|
3267
|
+
# The transform of the covariant
|
|
3268
|
+
g_cov = getattr(self, method_name)().subs(transform)
|
|
3269
|
+
# they must be the same
|
|
3270
|
+
assert (g_cov - cov_g).is_zero(), 'not covariant'
|
|
3271
|
+
if invariant:
|
|
3272
|
+
cov = getattr(self, method_name)()
|
|
3273
|
+
assert (cov - cov_g).is_zero(), 'not invariant'
|
|
3274
|
+
|
|
3275
|
+
|
|
3276
|
+
######################################################################
|
|
3277
|
+
|
|
3278
|
+
class TwoAlgebraicForms(SeveralAlgebraicForms):
|
|
3279
|
+
|
|
3280
|
+
def first(self):
|
|
3281
|
+
"""
|
|
3282
|
+
Return the first of the two forms.
|
|
3283
|
+
|
|
3284
|
+
OUTPUT: the first algebraic form used in the definition
|
|
3285
|
+
|
|
3286
|
+
EXAMPLES::
|
|
3287
|
+
|
|
3288
|
+
sage: R.<x,y> = QQ[]
|
|
3289
|
+
sage: q0 = invariant_theory.quadratic_form(x^2 + y^2)
|
|
3290
|
+
sage: q1 = invariant_theory.quadratic_form(x*y)
|
|
3291
|
+
sage: from sage.rings.invariants.invariant_theory import TwoAlgebraicForms
|
|
3292
|
+
sage: q = TwoAlgebraicForms([q0, q1])
|
|
3293
|
+
sage: q.first() is q0
|
|
3294
|
+
True
|
|
3295
|
+
sage: q.get_form(0) is q0
|
|
3296
|
+
True
|
|
3297
|
+
sage: q.first().polynomial()
|
|
3298
|
+
x^2 + y^2
|
|
3299
|
+
"""
|
|
3300
|
+
return self._forms[0]
|
|
3301
|
+
|
|
3302
|
+
def second(self):
|
|
3303
|
+
"""
|
|
3304
|
+
Return the second of the two forms.
|
|
3305
|
+
|
|
3306
|
+
OUTPUT: the second form used in the definition
|
|
3307
|
+
|
|
3308
|
+
EXAMPLES::
|
|
3309
|
+
|
|
3310
|
+
sage: R.<x,y> = QQ[]
|
|
3311
|
+
sage: q0 = invariant_theory.quadratic_form(x^2 + y^2)
|
|
3312
|
+
sage: q1 = invariant_theory.quadratic_form(x*y)
|
|
3313
|
+
sage: from sage.rings.invariants.invariant_theory import TwoAlgebraicForms
|
|
3314
|
+
sage: q = TwoAlgebraicForms([q0, q1])
|
|
3315
|
+
sage: q.second() is q1
|
|
3316
|
+
True
|
|
3317
|
+
sage: q.get_form(1) is q1
|
|
3318
|
+
True
|
|
3319
|
+
sage: q.second().polynomial()
|
|
3320
|
+
x*y
|
|
3321
|
+
"""
|
|
3322
|
+
return self._forms[1]
|
|
3323
|
+
|
|
3324
|
+
|
|
3325
|
+
######################################################################
|
|
3326
|
+
|
|
3327
|
+
class TwoTernaryQuadratics(TwoAlgebraicForms):
|
|
3328
|
+
"""
|
|
3329
|
+
Invariant theory of two ternary quadratics.
|
|
3330
|
+
|
|
3331
|
+
You should use the :class:`invariant_theory
|
|
3332
|
+
<InvariantTheoryFactory>` factory object to construct instances
|
|
3333
|
+
of this class. See
|
|
3334
|
+
:meth:`~InvariantTheoryFactory.ternary_biquadratics` for
|
|
3335
|
+
details.
|
|
3336
|
+
|
|
3337
|
+
REFERENCES:
|
|
3338
|
+
|
|
3339
|
+
- Section on "Invariants and Covariants of Systems of Conics",
|
|
3340
|
+
Art. 388 (a) in [Sal1954]_
|
|
3341
|
+
|
|
3342
|
+
TESTS::
|
|
3343
|
+
|
|
3344
|
+
sage: R.<x,y,z> = QQ[]
|
|
3345
|
+
sage: inv = invariant_theory.ternary_biquadratic(x^2 + y^2 + z^2,
|
|
3346
|
+
....: x*y + y*z + x*z, [x, y, z])
|
|
3347
|
+
sage: inv
|
|
3348
|
+
Joint ternary quadratic with coefficients (1, 1, 1, 0, 0, 0) and ternary
|
|
3349
|
+
quadratic with coefficients (0, 0, 0, 1, 1, 1)
|
|
3350
|
+
sage: TestSuite(inv).run()
|
|
3351
|
+
|
|
3352
|
+
sage: q1 = 73*x^2 + 96*x*y - 11*y^2 + 4*x + 63*y + 57
|
|
3353
|
+
sage: q2 = 61*x^2 - 100*x*y - 72*y^2 - 81*x + 39*y - 7
|
|
3354
|
+
sage: biquadratic = invariant_theory.ternary_biquadratic(q1, q2, [x,y]).homogenized()
|
|
3355
|
+
sage: biquadratic._check_covariant('Delta_invariant', invariant=True)
|
|
3356
|
+
sage: biquadratic._check_covariant('Delta_prime_invariant', invariant=True)
|
|
3357
|
+
sage: biquadratic._check_covariant('Theta_invariant', invariant=True)
|
|
3358
|
+
sage: biquadratic._check_covariant('Theta_prime_invariant', invariant=True)
|
|
3359
|
+
sage: biquadratic._check_covariant('F_covariant')
|
|
3360
|
+
sage: biquadratic._check_covariant('J_covariant')
|
|
3361
|
+
"""
|
|
3362
|
+
|
|
3363
|
+
def Delta_invariant(self):
|
|
3364
|
+
r"""
|
|
3365
|
+
Return the `\Delta` invariant.
|
|
3366
|
+
|
|
3367
|
+
EXAMPLES::
|
|
3368
|
+
|
|
3369
|
+
sage: R.<a00, a01, a11, a02, a12, a22, b00, b01, b11, b02, b12, b22, y0, y1, y2, t> = QQ[]
|
|
3370
|
+
sage: p1 = a00*y0^2 + 2*a01*y0*y1 + a11*y1^2 + 2*a02*y0*y2 + 2*a12*y1*y2 + a22*y2^2
|
|
3371
|
+
sage: p2 = b00*y0^2 + 2*b01*y0*y1 + b11*y1^2 + 2*b02*y0*y2 + 2*b12*y1*y2 + b22*y2^2
|
|
3372
|
+
sage: q = invariant_theory.ternary_biquadratic(p1, p2, [y0, y1, y2])
|
|
3373
|
+
sage: coeffs = det(t * q[0].matrix() + q[1].matrix()).polynomial(t).coefficients(sparse=False)
|
|
3374
|
+
sage: q.Delta_invariant() == coeffs[3]
|
|
3375
|
+
True
|
|
3376
|
+
"""
|
|
3377
|
+
return self.get_form(0).matrix().det()
|
|
3378
|
+
|
|
3379
|
+
def Delta_prime_invariant(self):
|
|
3380
|
+
r"""
|
|
3381
|
+
Return the `\Delta'` invariant.
|
|
3382
|
+
|
|
3383
|
+
EXAMPLES::
|
|
3384
|
+
|
|
3385
|
+
sage: R.<a00, a01, a11, a02, a12, a22, b00, b01, b11, b02, b12, b22, y0, y1, y2, t> = QQ[]
|
|
3386
|
+
sage: p1 = a00*y0^2 + 2*a01*y0*y1 + a11*y1^2 + 2*a02*y0*y2 + 2*a12*y1*y2 + a22*y2^2
|
|
3387
|
+
sage: p2 = b00*y0^2 + 2*b01*y0*y1 + b11*y1^2 + 2*b02*y0*y2 + 2*b12*y1*y2 + b22*y2^2
|
|
3388
|
+
sage: q = invariant_theory.ternary_biquadratic(p1, p2, [y0, y1, y2])
|
|
3389
|
+
sage: coeffs = det(t * q[0].matrix() + q[1].matrix()).polynomial(t).coefficients(sparse=False)
|
|
3390
|
+
sage: q.Delta_prime_invariant() == coeffs[0]
|
|
3391
|
+
True
|
|
3392
|
+
"""
|
|
3393
|
+
return self.get_form(1).matrix().det()
|
|
3394
|
+
|
|
3395
|
+
def _Theta_helper(self, scaled_coeffs_1, scaled_coeffs_2):
|
|
3396
|
+
"""
|
|
3397
|
+
Internal helper method for :meth:`Theta_invariant` and
|
|
3398
|
+
:meth:`Theta_prime_invariant`.
|
|
3399
|
+
|
|
3400
|
+
TESTS::
|
|
3401
|
+
|
|
3402
|
+
sage: R.<x,y,z> = QQ[]
|
|
3403
|
+
sage: inv = invariant_theory.ternary_biquadratic(x^2 + y*z, x*y + z^2, x, y, z)
|
|
3404
|
+
sage: inv._Theta_helper([1]*6, [2]*6)
|
|
3405
|
+
0
|
|
3406
|
+
"""
|
|
3407
|
+
a00, a11, a22, a01, a02, a12 = scaled_coeffs_1
|
|
3408
|
+
b00, b11, b22, b01, b02, b12 = scaled_coeffs_2
|
|
3409
|
+
return -a12**2*b00 + a11*a22*b00 + 2*a02*a12*b01 - 2*a01*a22*b01 - \
|
|
3410
|
+
a02**2*b11 + a00*a22*b11 - 2*a11*a02*b02 + 2*a01*a12*b02 + \
|
|
3411
|
+
2*a01*a02*b12 - 2*a00*a12*b12 - a01**2*b22 + a00*a11*b22
|
|
3412
|
+
|
|
3413
|
+
def Theta_invariant(self):
|
|
3414
|
+
r"""
|
|
3415
|
+
Return the `\Theta` invariant.
|
|
3416
|
+
|
|
3417
|
+
EXAMPLES::
|
|
3418
|
+
|
|
3419
|
+
sage: R.<a00, a01, a11, a02, a12, a22, b00, b01, b11, b02, b12, b22, y0, y1, y2, t> = QQ[]
|
|
3420
|
+
sage: p1 = a00*y0^2 + 2*a01*y0*y1 + a11*y1^2 + 2*a02*y0*y2 + 2*a12*y1*y2 + a22*y2^2
|
|
3421
|
+
sage: p2 = b00*y0^2 + 2*b01*y0*y1 + b11*y1^2 + 2*b02*y0*y2 + 2*b12*y1*y2 + b22*y2^2
|
|
3422
|
+
sage: q = invariant_theory.ternary_biquadratic(p1, p2, [y0, y1, y2])
|
|
3423
|
+
sage: coeffs = det(t * q[0].matrix() + q[1].matrix()).polynomial(t).coefficients(sparse=False)
|
|
3424
|
+
sage: q.Theta_invariant() == coeffs[2]
|
|
3425
|
+
True
|
|
3426
|
+
"""
|
|
3427
|
+
return self._Theta_helper(self.get_form(0).scaled_coeffs(), self.get_form(1).scaled_coeffs())
|
|
3428
|
+
|
|
3429
|
+
def Theta_prime_invariant(self):
|
|
3430
|
+
r"""
|
|
3431
|
+
Return the `\Theta'` invariant.
|
|
3432
|
+
|
|
3433
|
+
EXAMPLES::
|
|
3434
|
+
|
|
3435
|
+
sage: R.<a00, a01, a11, a02, a12, a22, b00, b01, b11, b02, b12, b22, y0, y1, y2, t> = QQ[]
|
|
3436
|
+
sage: p1 = a00*y0^2 + 2*a01*y0*y1 + a11*y1^2 + 2*a02*y0*y2 + 2*a12*y1*y2 + a22*y2^2
|
|
3437
|
+
sage: p2 = b00*y0^2 + 2*b01*y0*y1 + b11*y1^2 + 2*b02*y0*y2 + 2*b12*y1*y2 + b22*y2^2
|
|
3438
|
+
sage: q = invariant_theory.ternary_biquadratic(p1, p2, [y0, y1, y2])
|
|
3439
|
+
sage: coeffs = det(t * q[0].matrix() + q[1].matrix()).polynomial(t).coefficients(sparse=False)
|
|
3440
|
+
sage: q.Theta_prime_invariant() == coeffs[1]
|
|
3441
|
+
True
|
|
3442
|
+
"""
|
|
3443
|
+
return self._Theta_helper(self.get_form(1).scaled_coeffs(), self.get_form(0).scaled_coeffs())
|
|
3444
|
+
|
|
3445
|
+
def F_covariant(self):
|
|
3446
|
+
r"""
|
|
3447
|
+
Return the `F` covariant.
|
|
3448
|
+
|
|
3449
|
+
EXAMPLES::
|
|
3450
|
+
|
|
3451
|
+
sage: R.<a00, a01, a11, a02, a12, a22, b00, b01, b11, b02, b12, b22, x, y> = QQ[]
|
|
3452
|
+
sage: p1 = 73*x^2 + 96*x*y - 11*y^2 + 4*x + 63*y + 57
|
|
3453
|
+
sage: p2 = 61*x^2 - 100*x*y - 72*y^2 - 81*x + 39*y - 7
|
|
3454
|
+
sage: q = invariant_theory.ternary_biquadratic(p1, p2, [x, y])
|
|
3455
|
+
sage: q.F_covariant()
|
|
3456
|
+
-32566577*x^2 + 29060637/2*x*y + 20153633/4*y^2 -
|
|
3457
|
+
30250497/2*x - 241241273/4*y - 323820473/16
|
|
3458
|
+
"""
|
|
3459
|
+
C = self.first().covariant_conic(self.second())
|
|
3460
|
+
CI = TernaryQuadratic(3, 2, C, *self.variables())
|
|
3461
|
+
return CI.dual().polynomial()
|
|
3462
|
+
|
|
3463
|
+
def J_covariant(self):
|
|
3464
|
+
r"""
|
|
3465
|
+
Return the `J` covariant.
|
|
3466
|
+
|
|
3467
|
+
EXAMPLES::
|
|
3468
|
+
|
|
3469
|
+
sage: R.<a00, a01, a11, a02, a12, a22, b00, b01, b11, b02, b12, b22, x, y> = QQ[]
|
|
3470
|
+
sage: p1 = 73*x^2 + 96*x*y - 11*y^2 + 4*x + 63*y + 57
|
|
3471
|
+
sage: p2 = 61*x^2 - 100*x*y - 72*y^2 - 81*x + 39*y - 7
|
|
3472
|
+
sage: q = invariant_theory.ternary_biquadratic(p1, p2, [x, y])
|
|
3473
|
+
sage: q.J_covariant()
|
|
3474
|
+
1057324024445*x^3 + 1209531088209*x^2*y + 942116599708*x*y^2 +
|
|
3475
|
+
984553030871*y^3 + 543715345505/2*x^2 - 3065093506021/2*x*y +
|
|
3476
|
+
755263948570*y^2 - 1118430692650*x - 509948695327/4*y + 3369951531745/8
|
|
3477
|
+
"""
|
|
3478
|
+
return self._jacobian_determinant(
|
|
3479
|
+
(self.first().polynomial(), 2),
|
|
3480
|
+
(self.second().polynomial(), 2),
|
|
3481
|
+
(self.F_covariant(), 2))
|
|
3482
|
+
|
|
3483
|
+
def syzygy(self, Delta, Theta, Theta_prime, Delta_prime, S, S_prime, F, J):
|
|
3484
|
+
"""
|
|
3485
|
+
Return the syzygy evaluated on the invariants and covariants.
|
|
3486
|
+
|
|
3487
|
+
INPUT:
|
|
3488
|
+
|
|
3489
|
+
- ``Delta``, ``Theta``, ``Theta_prime``, ``Delta_prime``,
|
|
3490
|
+
``S``, ``S_prime``, ``F``, ``J`` -- polynomials from the
|
|
3491
|
+
same polynomial ring.
|
|
3492
|
+
|
|
3493
|
+
OUTPUT:
|
|
3494
|
+
|
|
3495
|
+
Zero if ``S`` is the first polynomial, ``S_prime`` the
|
|
3496
|
+
second polynomial, and the remaining input are the invariants
|
|
3497
|
+
and covariants of a ternary biquadratic.
|
|
3498
|
+
|
|
3499
|
+
EXAMPLES::
|
|
3500
|
+
|
|
3501
|
+
sage: R.<x,y,z> = QQ[]
|
|
3502
|
+
sage: monomials = [x^2, x*y, y^2, x*z, y*z, z^2]
|
|
3503
|
+
sage: def q_rnd(): return sum(randint(-1000, 1000)*m for m in monomials)
|
|
3504
|
+
sage: biquadratic = invariant_theory.ternary_biquadratic(q_rnd(), q_rnd(), [x,y,z])
|
|
3505
|
+
sage: Delta = biquadratic.Delta_invariant()
|
|
3506
|
+
sage: Theta = biquadratic.Theta_invariant()
|
|
3507
|
+
sage: Theta_prime = biquadratic.Theta_prime_invariant()
|
|
3508
|
+
sage: Delta_prime = biquadratic.Delta_prime_invariant()
|
|
3509
|
+
sage: S = biquadratic.first().polynomial()
|
|
3510
|
+
sage: S_prime = biquadratic.second().polynomial()
|
|
3511
|
+
sage: F = biquadratic.F_covariant()
|
|
3512
|
+
sage: J = biquadratic.J_covariant()
|
|
3513
|
+
sage: biquadratic.syzygy(Delta, Theta, Theta_prime, Delta_prime, S, S_prime, F, J)
|
|
3514
|
+
0
|
|
3515
|
+
|
|
3516
|
+
If the arguments are not the invariants and covariants then
|
|
3517
|
+
the output is some (generically nonzero) polynomial::
|
|
3518
|
+
|
|
3519
|
+
sage: biquadratic.syzygy(1, 1, 1, 1, 1, 1, 1, x)
|
|
3520
|
+
1/64*x^2 + 1
|
|
3521
|
+
"""
|
|
3522
|
+
R = self._ring.base_ring()
|
|
3523
|
+
return (J**2 / R(64)
|
|
3524
|
+
+ F**3
|
|
3525
|
+
- 2 * F**2 * Theta*S_prime
|
|
3526
|
+
- 2 * F**2 * Theta_prime*S
|
|
3527
|
+
+ F * S**2 * (Delta_prime * Theta + Theta_prime**2)
|
|
3528
|
+
+ F * S_prime**2 * (Delta * Theta_prime + Theta**2)
|
|
3529
|
+
+ 3 * F * S * S_prime * (Theta*Theta_prime - Delta*Delta_prime)
|
|
3530
|
+
+ S**3 * (Delta_prime**2 * Delta - Theta * Theta_prime * Delta_prime)
|
|
3531
|
+
+ S_prime**3 * (Delta**2 * Delta_prime - Theta_prime * Theta * Delta)
|
|
3532
|
+
+ S**2 * S_prime * (
|
|
3533
|
+
Delta_prime * Delta * Theta_prime - Theta * Theta_prime**2)
|
|
3534
|
+
+ S * S_prime**2 * (
|
|
3535
|
+
Delta * Delta_prime * Theta - Theta_prime * Theta**2)
|
|
3536
|
+
)
|
|
3537
|
+
|
|
3538
|
+
|
|
3539
|
+
######################################################################
|
|
3540
|
+
|
|
3541
|
+
class TwoQuaternaryQuadratics(TwoAlgebraicForms):
|
|
3542
|
+
"""
|
|
3543
|
+
Invariant theory of two quaternary quadratics.
|
|
3544
|
+
|
|
3545
|
+
You should use the :class:`invariant_theory
|
|
3546
|
+
<InvariantTheoryFactory>` factory object to construct instances
|
|
3547
|
+
of this class. See
|
|
3548
|
+
:meth:`~InvariantTheoryFactory.quaternary_biquadratics` for
|
|
3549
|
+
details.
|
|
3550
|
+
|
|
3551
|
+
REFERENCES:
|
|
3552
|
+
|
|
3553
|
+
- section on "Invariants and Covariants of
|
|
3554
|
+
Systems of Quadrics" in [Sal1958]_, [Sal1965]_
|
|
3555
|
+
|
|
3556
|
+
TESTS::
|
|
3557
|
+
|
|
3558
|
+
sage: R.<w,x,y,z> = QQ[]
|
|
3559
|
+
sage: inv = invariant_theory.quaternary_biquadratic(w^2 + x^2, y^2 + z^2, w, x, y, z)
|
|
3560
|
+
sage: inv
|
|
3561
|
+
Joint quaternary quadratic with coefficients (1, 1, 0, 0, 0, 0, 0, 0, 0, 0) and
|
|
3562
|
+
quaternary quadratic with coefficients (0, 0, 1, 1, 0, 0, 0, 0, 0, 0)
|
|
3563
|
+
sage: TestSuite(inv).run()
|
|
3564
|
+
|
|
3565
|
+
sage: q1 = 73*x^2 + 96*x*y - 11*y^2 - 74*x*z - 10*y*z + 66*z^2 + 4*x + 63*y - 11*z + 57
|
|
3566
|
+
sage: q2 = 61*x^2 - 100*x*y - 72*y^2 - 38*x*z + 85*y*z + 95*z^2 - 81*x + 39*y + 23*z - 7
|
|
3567
|
+
sage: biquadratic = invariant_theory.quaternary_biquadratic(q1, q2, [x,y,z]).homogenized()
|
|
3568
|
+
sage: biquadratic._check_covariant('Delta_invariant', invariant=True)
|
|
3569
|
+
sage: biquadratic._check_covariant('Delta_prime_invariant', invariant=True)
|
|
3570
|
+
sage: biquadratic._check_covariant('Theta_invariant', invariant=True)
|
|
3571
|
+
sage: biquadratic._check_covariant('Theta_prime_invariant', invariant=True)
|
|
3572
|
+
sage: biquadratic._check_covariant('Phi_invariant', invariant=True)
|
|
3573
|
+
sage: biquadratic._check_covariant('T_covariant')
|
|
3574
|
+
sage: biquadratic._check_covariant('T_prime_covariant')
|
|
3575
|
+
sage: biquadratic._check_covariant('J_covariant')
|
|
3576
|
+
"""
|
|
3577
|
+
|
|
3578
|
+
def Delta_invariant(self):
|
|
3579
|
+
r"""
|
|
3580
|
+
Return the `\Delta` invariant.
|
|
3581
|
+
|
|
3582
|
+
EXAMPLES::
|
|
3583
|
+
|
|
3584
|
+
sage: R.<x,y,z,t,a0,a1,a2,a3,b0,b1,b2,b3,b4,b5,A0,A1,A2,A3,B0,B1,B2,B3,B4,B5> = QQ[]
|
|
3585
|
+
sage: p1 = a0*x^2 + a1*y^2 + a2*z^2 + a3
|
|
3586
|
+
sage: p1 += b0*x*y + b1*x*z + b2*x + b3*y*z + b4*y + b5*z
|
|
3587
|
+
sage: p2 = A0*x^2 + A1*y^2 + A2*z^2 + A3
|
|
3588
|
+
sage: p2 += B0*x*y + B1*x*z + B2*x + B3*y*z + B4*y + B5*z
|
|
3589
|
+
sage: q = invariant_theory.quaternary_biquadratic(p1, p2, [x, y, z])
|
|
3590
|
+
sage: coeffs = det(t * q[0].matrix() + q[1].matrix()).polynomial(t).coefficients(sparse=False)
|
|
3591
|
+
sage: q.Delta_invariant() == coeffs[4]
|
|
3592
|
+
True
|
|
3593
|
+
"""
|
|
3594
|
+
return self.get_form(0).matrix().det()
|
|
3595
|
+
|
|
3596
|
+
def Delta_prime_invariant(self):
|
|
3597
|
+
r"""
|
|
3598
|
+
Return the `\Delta'` invariant.
|
|
3599
|
+
|
|
3600
|
+
EXAMPLES::
|
|
3601
|
+
|
|
3602
|
+
sage: R.<x,y,z,t,a0,a1,a2,a3,b0,b1,b2,b3,b4,b5,A0,A1,A2,A3,B0,B1,B2,B3,B4,B5> = QQ[]
|
|
3603
|
+
sage: p1 = a0*x^2 + a1*y^2 + a2*z^2 + a3
|
|
3604
|
+
sage: p1 += b0*x*y + b1*x*z + b2*x + b3*y*z + b4*y + b5*z
|
|
3605
|
+
sage: p2 = A0*x^2 + A1*y^2 + A2*z^2 + A3
|
|
3606
|
+
sage: p2 += B0*x*y + B1*x*z + B2*x + B3*y*z + B4*y + B5*z
|
|
3607
|
+
sage: q = invariant_theory.quaternary_biquadratic(p1, p2, [x, y, z])
|
|
3608
|
+
sage: coeffs = det(t * q[0].matrix() + q[1].matrix()).polynomial(t).coefficients(sparse=False)
|
|
3609
|
+
sage: q.Delta_prime_invariant() == coeffs[0]
|
|
3610
|
+
True
|
|
3611
|
+
"""
|
|
3612
|
+
return self.get_form(1).matrix().det()
|
|
3613
|
+
|
|
3614
|
+
def _Theta_helper(self, scaled_coeffs_1, scaled_coeffs_2):
|
|
3615
|
+
"""
|
|
3616
|
+
Internal helper method for :meth:`Theta_invariant` and
|
|
3617
|
+
:meth:`Theta_prime_invariant`.
|
|
3618
|
+
|
|
3619
|
+
TESTS::
|
|
3620
|
+
|
|
3621
|
+
sage: R.<w,x,y,z> = QQ[]
|
|
3622
|
+
sage: inv = invariant_theory.quaternary_biquadratic(w^2 + x^2, y^2 + z^2, w, x, y, z)
|
|
3623
|
+
sage: inv._Theta_helper([1]*10, [2]*10)
|
|
3624
|
+
0
|
|
3625
|
+
"""
|
|
3626
|
+
a0, a1, a2, a3, b0, b1, b2, b3, b4, b5 = scaled_coeffs_1
|
|
3627
|
+
A0, A1, A2, A3, B0, B1, B2, B3, B4, B5 = scaled_coeffs_2
|
|
3628
|
+
return a1*a2*a3*A0 - a3*b3**2*A0 - a2*b4**2*A0 + 2*b3*b4*b5*A0 - a1*b5**2*A0 \
|
|
3629
|
+
+ a0*a2*a3*A1 - a3*b1**2*A1 - a2*b2**2*A1 + 2*b1*b2*b5*A1 - a0*b5**2*A1 \
|
|
3630
|
+
+ a0*a1*a3*A2 - a3*b0**2*A2 - a1*b2**2*A2 + 2*b0*b2*b4*A2 - a0*b4**2*A2 \
|
|
3631
|
+
+ a0*a1*a2*A3 - a2*b0**2*A3 - a1*b1**2*A3 + 2*b0*b1*b3*A3 - a0*b3**2*A3 \
|
|
3632
|
+
- 2*a2*a3*b0*B0 + 2*a3*b1*b3*B0 + 2*a2*b2*b4*B0 - 2*b2*b3*b5*B0 \
|
|
3633
|
+
- 2*b1*b4*b5*B0 + 2*b0*b5**2*B0 - 2*a1*a3*b1*B1 + 2*a3*b0*b3*B1 \
|
|
3634
|
+
- 2*b2*b3*b4*B1 + 2*b1*b4**2*B1 + 2*a1*b2*b5*B1 - 2*b0*b4*b5*B1 \
|
|
3635
|
+
- 2*a1*a2*b2*B2 + 2*b2*b3**2*B2 + 2*a2*b0*b4*B2 - 2*b1*b3*b4*B2 \
|
|
3636
|
+
+ 2*a1*b1*b5*B2 - 2*b0*b3*b5*B2 + 2*a3*b0*b1*B3 - 2*a0*a3*b3*B3 \
|
|
3637
|
+
+ 2*b2**2*b3*B3 - 2*b1*b2*b4*B3 - 2*b0*b2*b5*B3 + 2*a0*b4*b5*B3 \
|
|
3638
|
+
+ 2*a2*b0*b2*B4 - 2*b1*b2*b3*B4 - 2*a0*a2*b4*B4 + 2*b1**2*b4*B4 \
|
|
3639
|
+
- 2*b0*b1*b5*B4 + 2*a0*b3*b5*B4 + 2*a1*b1*b2*B5 - 2*b0*b2*b3*B5 \
|
|
3640
|
+
- 2*b0*b1*b4*B5 + 2*a0*b3*b4*B5 - 2*a0*a1*b5*B5 + 2*b0**2*b5*B5
|
|
3641
|
+
|
|
3642
|
+
def Theta_invariant(self):
|
|
3643
|
+
r"""
|
|
3644
|
+
Return the `\Theta` invariant.
|
|
3645
|
+
|
|
3646
|
+
EXAMPLES::
|
|
3647
|
+
|
|
3648
|
+
sage: R.<x,y,z,t,a0,a1,a2,a3,b0,b1,b2,b3,b4,b5,A0,A1,A2,A3,B0,B1,B2,B3,B4,B5> = QQ[]
|
|
3649
|
+
sage: p1 = a0*x^2 + a1*y^2 + a2*z^2 + a3
|
|
3650
|
+
sage: p1 += b0*x*y + b1*x*z + b2*x + b3*y*z + b4*y + b5*z
|
|
3651
|
+
sage: p2 = A0*x^2 + A1*y^2 + A2*z^2 + A3
|
|
3652
|
+
sage: p2 += B0*x*y + B1*x*z + B2*x + B3*y*z + B4*y + B5*z
|
|
3653
|
+
sage: q = invariant_theory.quaternary_biquadratic(p1, p2, [x, y, z])
|
|
3654
|
+
sage: coeffs = det(t * q[0].matrix() + q[1].matrix()).polynomial(t).coefficients(sparse=False)
|
|
3655
|
+
sage: q.Theta_invariant() == coeffs[3]
|
|
3656
|
+
True
|
|
3657
|
+
"""
|
|
3658
|
+
return self._Theta_helper(self.get_form(0).scaled_coeffs(), self.get_form(1).scaled_coeffs())
|
|
3659
|
+
|
|
3660
|
+
def Theta_prime_invariant(self):
|
|
3661
|
+
r"""
|
|
3662
|
+
Return the `\Theta'` invariant.
|
|
3663
|
+
|
|
3664
|
+
EXAMPLES::
|
|
3665
|
+
|
|
3666
|
+
sage: R.<x,y,z,t,a0,a1,a2,a3,b0,b1,b2,b3,b4,b5,A0,A1,A2,A3,B0,B1,B2,B3,B4,B5> = QQ[]
|
|
3667
|
+
sage: p1 = a0*x^2 + a1*y^2 + a2*z^2 + a3
|
|
3668
|
+
sage: p1 += b0*x*y + b1*x*z + b2*x + b3*y*z + b4*y + b5*z
|
|
3669
|
+
sage: p2 = A0*x^2 + A1*y^2 + A2*z^2 + A3
|
|
3670
|
+
sage: p2 += B0*x*y + B1*x*z + B2*x + B3*y*z + B4*y + B5*z
|
|
3671
|
+
sage: q = invariant_theory.quaternary_biquadratic(p1, p2, [x, y, z])
|
|
3672
|
+
sage: coeffs = det(t * q[0].matrix() + q[1].matrix()).polynomial(t).coefficients(sparse=False)
|
|
3673
|
+
sage: q.Theta_prime_invariant() == coeffs[1]
|
|
3674
|
+
True
|
|
3675
|
+
"""
|
|
3676
|
+
return self._Theta_helper(self.get_form(1).scaled_coeffs(), self.get_form(0).scaled_coeffs())
|
|
3677
|
+
|
|
3678
|
+
def Phi_invariant(self):
|
|
3679
|
+
r"""
|
|
3680
|
+
Return the `\Phi'` invariant.
|
|
3681
|
+
|
|
3682
|
+
EXAMPLES::
|
|
3683
|
+
|
|
3684
|
+
sage: R.<x,y,z,t,a0,a1,a2,a3,b0,b1,b2,b3,b4,b5,A0,A1,A2,A3,B0,B1,B2,B3,B4,B5> = QQ[]
|
|
3685
|
+
sage: p1 = a0*x^2 + a1*y^2 + a2*z^2 + a3
|
|
3686
|
+
sage: p1 += b0*x*y + b1*x*z + b2*x + b3*y*z + b4*y + b5*z
|
|
3687
|
+
sage: p2 = A0*x^2 + A1*y^2 + A2*z^2 + A3
|
|
3688
|
+
sage: p2 += B0*x*y + B1*x*z + B2*x + B3*y*z + B4*y + B5*z
|
|
3689
|
+
sage: q = invariant_theory.quaternary_biquadratic(p1, p2, [x, y, z])
|
|
3690
|
+
sage: coeffs = det(t * q[0].matrix() + q[1].matrix()).polynomial(t).coefficients(sparse=False)
|
|
3691
|
+
sage: q.Phi_invariant() == coeffs[2]
|
|
3692
|
+
True
|
|
3693
|
+
"""
|
|
3694
|
+
a0, a1, a2, a3, b0, b1, b2, b3, b4, b5 = self.get_form(0).scaled_coeffs()
|
|
3695
|
+
A0, A1, A2, A3, B0, B1, B2, B3, B4, B5 = self.get_form(1).scaled_coeffs()
|
|
3696
|
+
return a2*a3*A0*A1 - b5**2*A0*A1 + a1*a3*A0*A2 - b4**2*A0*A2 + a0*a3*A1*A2 \
|
|
3697
|
+
- b2**2*A1*A2 + a1*a2*A0*A3 - b3**2*A0*A3 + a0*a2*A1*A3 - b1**2*A1*A3 \
|
|
3698
|
+
+ a0*a1*A2*A3 - b0**2*A2*A3 - 2*a3*b0*A2*B0 + 2*b2*b4*A2*B0 - 2*a2*b0*A3*B0 \
|
|
3699
|
+
+ 2*b1*b3*A3*B0 - a2*a3*B0**2 + b5**2*B0**2 - 2*a3*b1*A1*B1 + 2*b2*b5*A1*B1 \
|
|
3700
|
+
- 2*a1*b1*A3*B1 + 2*b0*b3*A3*B1 + 2*a3*b3*B0*B1 - 2*b4*b5*B0*B1 - a1*a3*B1**2 \
|
|
3701
|
+
+ b4**2*B1**2 - 2*a2*b2*A1*B2 + 2*b1*b5*A1*B2 - 2*a1*b2*A2*B2 + 2*b0*b4*A2*B2 \
|
|
3702
|
+
+ 2*a2*b4*B0*B2 - 2*b3*b5*B0*B2 - 2*b3*b4*B1*B2 + 2*a1*b5*B1*B2 - a1*a2*B2**2 \
|
|
3703
|
+
+ b3**2*B2**2 - 2*a3*b3*A0*B3 + 2*b4*b5*A0*B3 + 2*b0*b1*A3*B3 - 2*a0*b3*A3*B3 \
|
|
3704
|
+
+ 2*a3*b1*B0*B3 - 2*b2*b5*B0*B3 + 2*a3*b0*B1*B3 - 2*b2*b4*B1*B3 \
|
|
3705
|
+
+ 4*b2*b3*B2*B3 - 2*b1*b4*B2*B3 - 2*b0*b5*B2*B3 - a0*a3*B3**2 + b2**2*B3**2 \
|
|
3706
|
+
- 2*a2*b4*A0*B4 + 2*b3*b5*A0*B4 + 2*b0*b2*A2*B4 - 2*a0*b4*A2*B4 \
|
|
3707
|
+
+ 2*a2*b2*B0*B4 - 2*b1*b5*B0*B4 - 2*b2*b3*B1*B4 + 4*b1*b4*B1*B4 \
|
|
3708
|
+
- 2*b0*b5*B1*B4 + 2*a2*b0*B2*B4 - 2*b1*b3*B2*B4 - 2*b1*b2*B3*B4 \
|
|
3709
|
+
+ 2*a0*b5*B3*B4 - a0*a2*B4**2 + b1**2*B4**2 + 2*b3*b4*A0*B5 - 2*a1*b5*A0*B5 \
|
|
3710
|
+
+ 2*b1*b2*A1*B5 - 2*a0*b5*A1*B5 - 2*b2*b3*B0*B5 - 2*b1*b4*B0*B5 \
|
|
3711
|
+
+ 4*b0*b5*B0*B5 + 2*a1*b2*B1*B5 - 2*b0*b4*B1*B5 + 2*a1*b1*B2*B5 \
|
|
3712
|
+
- 2*b0*b3*B2*B5 - 2*b0*b2*B3*B5 + 2*a0*b4*B3*B5 - 2*b0*b1*B4*B5 \
|
|
3713
|
+
+ 2*a0*b3*B4*B5 - a0*a1*B5**2 + b0**2*B5**2
|
|
3714
|
+
|
|
3715
|
+
def _T_helper(self, scaled_coeffs_1, scaled_coeffs_2):
|
|
3716
|
+
"""
|
|
3717
|
+
Internal helper method for :meth:`T_covariant` and
|
|
3718
|
+
:meth:`T_prime_covariant`.
|
|
3719
|
+
|
|
3720
|
+
TESTS::
|
|
3721
|
+
|
|
3722
|
+
sage: R.<w,x,y,z> = QQ[]
|
|
3723
|
+
sage: inv = invariant_theory.quaternary_biquadratic(w^2+x^2, y^2+z^2, w, x, y, z)
|
|
3724
|
+
sage: inv._T_helper([1]*10, [2]*10)
|
|
3725
|
+
0
|
|
3726
|
+
"""
|
|
3727
|
+
a0, a1, a2, a3, b0, b1, b2, b3, b4, b5 = scaled_coeffs_1
|
|
3728
|
+
A0, A1, A2, A3, B0, B1, B2, B3, B4, B5 = scaled_coeffs_2
|
|
3729
|
+
# Construct the entries of the 4x4 matrix T using symmetries:
|
|
3730
|
+
# cyclic: a0 -> a1 -> a2 -> a3 -> a0, b0->b3->b5->b2->b0, b1->b4->b1
|
|
3731
|
+
# flip: a0<->a1, b1<->b3, b2<->b4
|
|
3732
|
+
|
|
3733
|
+
def T00(a0, a1, a2, a3, b0, b1, b2, b3, b4, b5, A0, A1, A2, A3, B0, B1, B2, B3, B4, B5):
|
|
3734
|
+
return a0*a3*A0*A1*A2 - b2**2*A0*A1*A2 + a0*a2*A0*A1*A3 - b1**2*A0*A1*A3 \
|
|
3735
|
+
+ a0*a1*A0*A2*A3 - b0**2*A0*A2*A3 - a0*a3*A2*B0**2 + b2**2*A2*B0**2 \
|
|
3736
|
+
- a0*a2*A3*B0**2 + b1**2*A3*B0**2 - 2*b0*b1*A3*B0*B1 + 2*a0*b3*A3*B0*B1 \
|
|
3737
|
+
- a0*a3*A1*B1**2 + b2**2*A1*B1**2 - a0*a1*A3*B1**2 + b0**2*A3*B1**2 \
|
|
3738
|
+
- 2*b0*b2*A2*B0*B2 + 2*a0*b4*A2*B0*B2 - 2*b1*b2*A1*B1*B2 + 2*a0*b5*A1*B1*B2 \
|
|
3739
|
+
- a0*a2*A1*B2**2 + b1**2*A1*B2**2 - a0*a1*A2*B2**2 + b0**2*A2*B2**2 \
|
|
3740
|
+
+ 2*b0*b1*A0*A3*B3 - 2*a0*b3*A0*A3*B3 + 2*a0*a3*B0*B1*B3 - 2*b2**2*B0*B1*B3 \
|
|
3741
|
+
+ 2*b1*b2*B0*B2*B3 - 2*a0*b5*B0*B2*B3 + 2*b0*b2*B1*B2*B3 - 2*a0*b4*B1*B2*B3 \
|
|
3742
|
+
- 2*b0*b1*B2**2*B3 + 2*a0*b3*B2**2*B3 - a0*a3*A0*B3**2 + b2**2*A0*B3**2 \
|
|
3743
|
+
+ 2*b0*b2*A0*A2*B4 - 2*a0*b4*A0*A2*B4 + 2*b1*b2*B0*B1*B4 - 2*a0*b5*B0*B1*B4 \
|
|
3744
|
+
- 2*b0*b2*B1**2*B4 + 2*a0*b4*B1**2*B4 + 2*a0*a2*B0*B2*B4 - 2*b1**2*B0*B2*B4 \
|
|
3745
|
+
+ 2*b0*b1*B1*B2*B4 - 2*a0*b3*B1*B2*B4 - 2*b1*b2*A0*B3*B4 + 2*a0*b5*A0*B3*B4 \
|
|
3746
|
+
- a0*a2*A0*B4**2 + b1**2*A0*B4**2 + 2*b1*b2*A0*A1*B5 - 2*a0*b5*A0*A1*B5 \
|
|
3747
|
+
- 2*b1*b2*B0**2*B5 + 2*a0*b5*B0**2*B5 + 2*b0*b2*B0*B1*B5 - 2*a0*b4*B0*B1*B5 \
|
|
3748
|
+
+ 2*b0*b1*B0*B2*B5 - 2*a0*b3*B0*B2*B5 + 2*a0*a1*B1*B2*B5 - 2*b0**2*B1*B2*B5 \
|
|
3749
|
+
- 2*b0*b2*A0*B3*B5 + 2*a0*b4*A0*B3*B5 - 2*b0*b1*A0*B4*B5 + 2*a0*b3*A0*B4*B5 \
|
|
3750
|
+
- a0*a1*A0*B5**2 + b0**2*A0*B5**2
|
|
3751
|
+
|
|
3752
|
+
def T01(a0, a1, a2, a3, b0, b1, b2, b3, b4, b5, A0, A1, A2, A3, B0, B1, B2, B3, B4, B5):
|
|
3753
|
+
return a3*b0*A0*A1*A2 - b2*b4*A0*A1*A2 + a2*b0*A0*A1*A3 - b1*b3*A0*A1*A3 \
|
|
3754
|
+
+ a0*a1*A2*A3*B0 - b0**2*A2*A3*B0 - a3*b0*A2*B0**2 + b2*b4*A2*B0**2 \
|
|
3755
|
+
- a2*b0*A3*B0**2 + b1*b3*A3*B0**2 - b0*b1*A1*A3*B1 + a0*b3*A1*A3*B1 \
|
|
3756
|
+
- a1*b1*A3*B0*B1 + b0*b3*A3*B0*B1 - a3*b0*A1*B1**2 + b2*b4*A1*B1**2 \
|
|
3757
|
+
- b0*b2*A1*A2*B2 + a0*b4*A1*A2*B2 - a1*b2*A2*B0*B2 + b0*b4*A2*B0*B2 \
|
|
3758
|
+
- b2*b3*A1*B1*B2 - b1*b4*A1*B1*B2 + 2*b0*b5*A1*B1*B2 - a2*b0*A1*B2**2 \
|
|
3759
|
+
+ b1*b3*A1*B2**2 + a1*b1*A0*A3*B3 - b0*b3*A0*A3*B3 + b0*b1*A3*B0*B3 \
|
|
3760
|
+
- a0*b3*A3*B0*B3 - a0*a1*A3*B1*B3 + b0**2*A3*B1*B3 + 2*a3*b0*B0*B1*B3 \
|
|
3761
|
+
- 2*b2*b4*B0*B1*B3 + b2*b3*B0*B2*B3 + b1*b4*B0*B2*B3 - 2*b0*b5*B0*B2*B3 \
|
|
3762
|
+
+ a1*b2*B1*B2*B3 - b0*b4*B1*B2*B3 - a1*b1*B2**2*B3 + b0*b3*B2**2*B3 \
|
|
3763
|
+
- a3*b0*A0*B3**2 + b2*b4*A0*B3**2 + b0*b2*B2*B3**2 - a0*b4*B2*B3**2 \
|
|
3764
|
+
+ a1*b2*A0*A2*B4 - b0*b4*A0*A2*B4 + b0*b2*A2*B0*B4 - a0*b4*A2*B0*B4 \
|
|
3765
|
+
+ b2*b3*B0*B1*B4 + b1*b4*B0*B1*B4 - 2*b0*b5*B0*B1*B4 - a1*b2*B1**2*B4 \
|
|
3766
|
+
+ b0*b4*B1**2*B4 - a0*a1*A2*B2*B4 + b0**2*A2*B2*B4 + 2*a2*b0*B0*B2*B4 \
|
|
3767
|
+
- 2*b1*b3*B0*B2*B4 + a1*b1*B1*B2*B4 - b0*b3*B1*B2*B4 - b2*b3*A0*B3*B4 \
|
|
3768
|
+
- b1*b4*A0*B3*B4 + 2*b0*b5*A0*B3*B4 - b0*b2*B1*B3*B4 + a0*b4*B1*B3*B4 \
|
|
3769
|
+
- b0*b1*B2*B3*B4 + a0*b3*B2*B3*B4 - a2*b0*A0*B4**2 + b1*b3*A0*B4**2 \
|
|
3770
|
+
+ b0*b1*B1*B4**2 - a0*b3*B1*B4**2 + b2*b3*A0*A1*B5 + b1*b4*A0*A1*B5 \
|
|
3771
|
+
- 2*b0*b5*A0*A1*B5 - b2*b3*B0**2*B5 - b1*b4*B0**2*B5 + 2*b0*b5*B0**2*B5 \
|
|
3772
|
+
+ b0*b2*A1*B1*B5 - a0*b4*A1*B1*B5 + a1*b2*B0*B1*B5 - b0*b4*B0*B1*B5 \
|
|
3773
|
+
+ b0*b1*A1*B2*B5 - a0*b3*A1*B2*B5 + a1*b1*B0*B2*B5 - b0*b3*B0*B2*B5 \
|
|
3774
|
+
- a1*b2*A0*B3*B5 + b0*b4*A0*B3*B5 - b0*b2*B0*B3*B5 + a0*b4*B0*B3*B5 \
|
|
3775
|
+
+ a0*a1*B2*B3*B5 - b0**2*B2*B3*B5 - a1*b1*A0*B4*B5 + b0*b3*A0*B4*B5 \
|
|
3776
|
+
- b0*b1*B0*B4*B5 + a0*b3*B0*B4*B5 + a0*a1*B1*B4*B5 - b0**2*B1*B4*B5 \
|
|
3777
|
+
- a0*a1*B0*B5**2 + b0**2*B0*B5**2
|
|
3778
|
+
|
|
3779
|
+
t00 = T00(a0, a1, a2, a3, b0, b1, b2, b3, b4, b5, A0, A1, A2, A3, B0, B1, B2, B3, B4, B5)
|
|
3780
|
+
t11 = T00(a1, a2, a3, a0, b3, b4, b0, b5, b1, b2, A1, A2, A3, A0, B3, B4, B0, B5, B1, B2)
|
|
3781
|
+
t22 = T00(a2, a3, a0, a1, b5, b1, b3, b2, b4, b0, A2, A3, A0, A1, B5, B1, B3, B2, B4, B0)
|
|
3782
|
+
t33 = T00(a3, a0, a1, a2, b2, b4, b5, b0, b1, b3, A3, A0, A1, A2, B2, B4, B5, B0, B1, B3)
|
|
3783
|
+
t01 = T01(a0, a1, a2, a3, b0, b1, b2, b3, b4, b5, A0, A1, A2, A3, B0, B1, B2, B3, B4, B5)
|
|
3784
|
+
t12 = T01(a1, a2, a3, a0, b3, b4, b0, b5, b1, b2, A1, A2, A3, A0, B3, B4, B0, B5, B1, B2)
|
|
3785
|
+
t23 = T01(a2, a3, a0, a1, b5, b1, b3, b2, b4, b0, A2, A3, A0, A1, B5, B1, B3, B2, B4, B0)
|
|
3786
|
+
t30 = T01(a3, a0, a1, a2, b2, b4, b5, b0, b1, b3, A3, A0, A1, A2, B2, B4, B5, B0, B1, B3)
|
|
3787
|
+
t02 = T01(a0, a2, a3, a1, b1, b2, b0, b5, b3, b4, A0, A2, A3, A1, B1, B2, B0, B5, B3, B4)
|
|
3788
|
+
t13 = T01(a1, a3, a0, a2, b4, b0, b3, b2, b5, b1, A1, A3, A0, A2, B4, B0, B3, B2, B5, B1)
|
|
3789
|
+
if self._homogeneous:
|
|
3790
|
+
w, x, y, z = self._variables
|
|
3791
|
+
else:
|
|
3792
|
+
w, x, y = self._variables[0:3]
|
|
3793
|
+
z = self._ring.one()
|
|
3794
|
+
return t00*w*w + 2*t01*w*x + 2*t02*w*y + 2*t30*w*z + t11*x*x + 2*t12*x*y \
|
|
3795
|
+
+ 2*t13*x*z + t22*y*y + 2*t23*y*z + t33*z*z
|
|
3796
|
+
|
|
3797
|
+
def T_covariant(self):
|
|
3798
|
+
"""
|
|
3799
|
+
The `T`-covariant.
|
|
3800
|
+
|
|
3801
|
+
EXAMPLES::
|
|
3802
|
+
|
|
3803
|
+
sage: R.<x,y,z,t,a0,a1,a2,a3,b0,b1,b2,b3,b4,b5,A0,A1,A2,A3,B0,B1,B2,B3,B4,B5> = QQ[]
|
|
3804
|
+
sage: p1 = a0*x^2 + a1*y^2 + a2*z^2 + a3
|
|
3805
|
+
sage: p1 += b0*x*y + b1*x*z + b2*x + b3*y*z + b4*y + b5*z
|
|
3806
|
+
sage: p2 = A0*x^2 + A1*y^2 + A2*z^2 + A3
|
|
3807
|
+
sage: p2 += B0*x*y + B1*x*z + B2*x + B3*y*z + B4*y + B5*z
|
|
3808
|
+
sage: q = invariant_theory.quaternary_biquadratic(p1, p2, [x, y, z])
|
|
3809
|
+
sage: T = invariant_theory.quaternary_quadratic(q.T_covariant(), [x,y,z]).matrix()
|
|
3810
|
+
sage: M = q[0].matrix().adjugate() + t*q[1].matrix().adjugate()
|
|
3811
|
+
sage: M = M.adjugate().apply_map( # long time (4s on my thinkpad W530)
|
|
3812
|
+
....: lambda m: m.coefficient(t))
|
|
3813
|
+
sage: M == q.Delta_invariant()*T # long time
|
|
3814
|
+
True
|
|
3815
|
+
"""
|
|
3816
|
+
return self._T_helper(self.get_form(0).scaled_coeffs(), self.get_form(1).scaled_coeffs())
|
|
3817
|
+
|
|
3818
|
+
def T_prime_covariant(self):
|
|
3819
|
+
"""
|
|
3820
|
+
The `T'`-covariant.
|
|
3821
|
+
|
|
3822
|
+
EXAMPLES::
|
|
3823
|
+
|
|
3824
|
+
sage: R.<x,y,z,t,a0,a1,a2,a3,b0,b1,b2,b3,b4,b5,A0,A1,A2,A3,B0,B1,B2,B3,B4,B5> = QQ[]
|
|
3825
|
+
sage: p1 = a0*x^2 + a1*y^2 + a2*z^2 + a3
|
|
3826
|
+
sage: p1 += b0*x*y + b1*x*z + b2*x + b3*y*z + b4*y + b5*z
|
|
3827
|
+
sage: p2 = A0*x^2 + A1*y^2 + A2*z^2 + A3
|
|
3828
|
+
sage: p2 += B0*x*y + B1*x*z + B2*x + B3*y*z + B4*y + B5*z
|
|
3829
|
+
sage: q = invariant_theory.quaternary_biquadratic(p1, p2, [x, y, z])
|
|
3830
|
+
sage: Tprime = invariant_theory.quaternary_quadratic(
|
|
3831
|
+
....: q.T_prime_covariant(), [x,y,z]).matrix()
|
|
3832
|
+
sage: M = q[0].matrix().adjugate() + t*q[1].matrix().adjugate()
|
|
3833
|
+
sage: M = M.adjugate().apply_map( # long time (4s on my thinkpad W530)
|
|
3834
|
+
....: lambda m: m.coefficient(t^2))
|
|
3835
|
+
sage: M == q.Delta_prime_invariant() * Tprime # long time
|
|
3836
|
+
True
|
|
3837
|
+
"""
|
|
3838
|
+
return self._T_helper(self.get_form(1).scaled_coeffs(), self.get_form(0).scaled_coeffs())
|
|
3839
|
+
|
|
3840
|
+
def J_covariant(self):
|
|
3841
|
+
"""
|
|
3842
|
+
The `J`-covariant.
|
|
3843
|
+
|
|
3844
|
+
This is the Jacobian determinant of the two biquadratics, the
|
|
3845
|
+
`T`-covariant, and the `T'`-covariant with respect to the four
|
|
3846
|
+
homogeneous variables.
|
|
3847
|
+
|
|
3848
|
+
EXAMPLES::
|
|
3849
|
+
|
|
3850
|
+
sage: R.<w,x,y,z,a0,a1,a2,a3,A0,A1,A2,A3> = QQ[]
|
|
3851
|
+
sage: p1 = a0*x^2 + a1*y^2 + a2*z^2 + a3*w^2
|
|
3852
|
+
sage: p2 = A0*x^2 + A1*y^2 + A2*z^2 + A3*w^2
|
|
3853
|
+
sage: q = invariant_theory.quaternary_biquadratic(p1, p2, [w, x, y, z])
|
|
3854
|
+
sage: q.J_covariant().factor()
|
|
3855
|
+
z * y * x * w * (-a1*A0 + a0*A1) * (-a2*A0 + a0*A2) * (-a2*A1 + a1*A2)
|
|
3856
|
+
* (a3*A2 - a2*A3) * (a3*A1 - a1*A3) * (a3*A0 - a0*A3)
|
|
3857
|
+
"""
|
|
3858
|
+
F = self._ring.base_ring()
|
|
3859
|
+
return 1/F(16) * self._jacobian_determinant(
|
|
3860
|
+
[self.first().form(), 2],
|
|
3861
|
+
[self.second().form(), 2],
|
|
3862
|
+
[self.T_covariant(), 4],
|
|
3863
|
+
[self.T_prime_covariant(), 4])
|
|
3864
|
+
|
|
3865
|
+
def syzygy(self, Delta, Theta, Phi, Theta_prime, Delta_prime, U, V, T, T_prime, J):
|
|
3866
|
+
"""
|
|
3867
|
+
Return the syzygy evaluated on the invariants and covariants.
|
|
3868
|
+
|
|
3869
|
+
INPUT:
|
|
3870
|
+
|
|
3871
|
+
- ``Delta``, ``Theta``, ``Phi``, ``Theta_prime``,
|
|
3872
|
+
``Delta_prime``, ``U``, ``V``, ``T``, ``T_prime``, ``J`` --
|
|
3873
|
+
polynomials from the same polynomial ring.
|
|
3874
|
+
|
|
3875
|
+
OUTPUT:
|
|
3876
|
+
|
|
3877
|
+
Zero if the ``U`` is the first polynomial, ``V`` the second
|
|
3878
|
+
polynomial, and the remaining input are the invariants and
|
|
3879
|
+
covariants of a quaternary biquadratic.
|
|
3880
|
+
|
|
3881
|
+
EXAMPLES::
|
|
3882
|
+
|
|
3883
|
+
sage: R.<w,x,y,z> = QQ[]
|
|
3884
|
+
sage: monomials = [x^2, x*y, y^2, x*z, y*z, z^2, x*w, y*w, z*w, w^2]
|
|
3885
|
+
sage: def q_rnd(): return sum(randint(-1000, 1000)*m for m in monomials)
|
|
3886
|
+
sage: biquadratic = invariant_theory.quaternary_biquadratic(q_rnd(), q_rnd())
|
|
3887
|
+
sage: Delta = biquadratic.Delta_invariant()
|
|
3888
|
+
sage: Theta = biquadratic.Theta_invariant()
|
|
3889
|
+
sage: Phi = biquadratic.Phi_invariant()
|
|
3890
|
+
sage: Theta_prime = biquadratic.Theta_prime_invariant()
|
|
3891
|
+
sage: Delta_prime = biquadratic.Delta_prime_invariant()
|
|
3892
|
+
sage: U = biquadratic.first().polynomial()
|
|
3893
|
+
sage: V = biquadratic.second().polynomial()
|
|
3894
|
+
sage: T = biquadratic.T_covariant()
|
|
3895
|
+
sage: T_prime = biquadratic.T_prime_covariant()
|
|
3896
|
+
sage: J = biquadratic.J_covariant()
|
|
3897
|
+
sage: biquadratic.syzygy(Delta, Theta, Phi, Theta_prime, Delta_prime, U, V, T, T_prime, J)
|
|
3898
|
+
0
|
|
3899
|
+
|
|
3900
|
+
If the arguments are not the invariants and covariants then
|
|
3901
|
+
the output is some (generically nonzero) polynomial::
|
|
3902
|
+
|
|
3903
|
+
sage: biquadratic.syzygy(1, 1, 1, 1, 1, 1, 1, 1, 1, x)
|
|
3904
|
+
-x^2 + 1
|
|
3905
|
+
"""
|
|
3906
|
+
return -J**2 + \
|
|
3907
|
+
Delta * T**4 - Theta * T**3*T_prime + Phi * T**2*T_prime**2 \
|
|
3908
|
+
- Theta_prime * T*T_prime**3 + Delta_prime * T_prime**4 + \
|
|
3909
|
+
( (Theta_prime**2 - 2*Delta_prime*Phi) * T_prime**3 -
|
|
3910
|
+
(Theta_prime*Phi - 3*Theta*Delta_prime) * T_prime**2*T +
|
|
3911
|
+
(Theta*Theta_prime - 4*Delta*Delta_prime) * T_prime*T**2 -
|
|
3912
|
+
(Delta*Theta_prime) * T**3
|
|
3913
|
+
) * U + \
|
|
3914
|
+
( (Theta**2 - 2*Delta*Phi)*T**3 -
|
|
3915
|
+
(Theta*Phi - 3*Theta_prime*Delta)*T**2*T_prime +
|
|
3916
|
+
(Theta*Theta_prime - 4*Delta*Delta_prime)*T*T_prime**2 -
|
|
3917
|
+
(Delta_prime*Theta)*T_prime**3
|
|
3918
|
+
) * V + \
|
|
3919
|
+
( (Delta*Phi*Delta_prime) * T**2 +
|
|
3920
|
+
(3*Delta*Theta_prime*Delta_prime - Theta*Phi*Delta_prime) * T*T_prime +
|
|
3921
|
+
(2*Delta*Delta_prime**2 - 2*Theta*Theta_prime*Delta_prime
|
|
3922
|
+
+ Phi**2*Delta_prime) * T_prime**2
|
|
3923
|
+
) * U**2 + \
|
|
3924
|
+
( (Delta*Theta*Delta_prime + 2*Delta*Phi*Theta_prime - Theta**2*Theta_prime) * T**2 +
|
|
3925
|
+
(4*Delta*Phi*Delta_prime - 3*Theta**2*Delta_prime
|
|
3926
|
+
- 3*Delta*Theta_prime**2 + Theta*Phi*Theta_prime) * T*T_prime +
|
|
3927
|
+
(Delta*Theta_prime*Delta_prime + 2*Delta_prime*Phi*Theta
|
|
3928
|
+
- Theta*Theta_prime**2) * T_prime**2
|
|
3929
|
+
) * U*V + \
|
|
3930
|
+
( (2*Delta**2*Delta_prime - 2*Delta*Theta*Theta_prime + Delta*Phi**2) * T**2 +
|
|
3931
|
+
(3*Delta*Theta*Delta_prime - Delta*Phi*Theta_prime) * T*T_prime +
|
|
3932
|
+
Delta*Phi*Delta_prime * T_prime**2
|
|
3933
|
+
) * V**2 + \
|
|
3934
|
+
( (-Delta*Theta*Delta_prime**2) * T +
|
|
3935
|
+
(-2*Delta*Phi*Delta_prime**2 + Theta**2*Delta_prime**2) * T_prime
|
|
3936
|
+
) * U**3 + \
|
|
3937
|
+
( (4*Delta**2*Delta_prime**2 - Delta*Theta*Theta_prime*Delta_prime
|
|
3938
|
+
- 2*Delta*Phi**2*Delta_prime + Theta**2*Phi*Delta_prime) * T +
|
|
3939
|
+
(-5*Delta*Theta*Delta_prime**2 + Delta*Phi*Theta_prime*Delta_prime
|
|
3940
|
+
+ 2*Theta**2*Theta_prime*Delta_prime - Theta*Phi**2*Delta_prime) * T_prime
|
|
3941
|
+
) * U**2*V + \
|
|
3942
|
+
( (-5*Delta**2*Theta_prime*Delta_prime + Delta*Theta*Phi*Delta_prime
|
|
3943
|
+
+ 2*Delta*Theta*Theta_prime**2 - Delta*Phi**2*Theta_prime) * T +
|
|
3944
|
+
(4*Delta**2*Delta_prime**2 - Delta*Theta*Theta_prime*Delta_prime
|
|
3945
|
+
- 2*Delta*Phi**2*Delta_prime + Delta*Phi*Theta_prime**2) * T_prime
|
|
3946
|
+
) * U*V**2 + \
|
|
3947
|
+
( (-2*Delta**2*Phi*Delta_prime + Delta**2*Theta_prime**2) * T +
|
|
3948
|
+
(-Delta**2*Theta_prime*Delta_prime) * T_prime
|
|
3949
|
+
) * V**3 + \
|
|
3950
|
+
(Delta**2*Delta_prime**3) * U**4 + \
|
|
3951
|
+
(-3*Delta**2*Theta_prime*Delta_prime**2 + 3*Delta*Theta*Phi*Delta_prime**2
|
|
3952
|
+
- Theta**3*Delta_prime**2) * U**3*V + \
|
|
3953
|
+
(-3*Delta**2*Phi*Delta_prime**2 + 3*Delta*Theta**2*Delta_prime**2
|
|
3954
|
+
+ 3*Delta**2*Theta_prime**2*Delta_prime
|
|
3955
|
+
- 3*Delta*Theta*Phi*Theta_prime*Delta_prime
|
|
3956
|
+
+ Delta*Phi**3*Delta_prime) * U**2*V**2 + \
|
|
3957
|
+
(-3*Delta**2*Theta*Delta_prime**2 + 3*Delta**2*Phi*Theta_prime*Delta_prime
|
|
3958
|
+
- Delta**2*Theta_prime**3) * U*V**3 + \
|
|
3959
|
+
(Delta**3*Delta_prime**2) * V**4
|
|
3960
|
+
|
|
3961
|
+
|
|
3962
|
+
######################################################################
|
|
3963
|
+
|
|
3964
|
+
class InvariantTheoryFactory:
|
|
3965
|
+
"""
|
|
3966
|
+
Factory object for invariants of multilinear forms.
|
|
3967
|
+
|
|
3968
|
+
Use the invariant_theory object to construct algebraic forms. These
|
|
3969
|
+
can then be queried for invariant and covariants.
|
|
3970
|
+
|
|
3971
|
+
EXAMPLES::
|
|
3972
|
+
|
|
3973
|
+
sage: R.<x,y,z> = QQ[]
|
|
3974
|
+
sage: invariant_theory.ternary_cubic(x^3 + y^3 + z^3)
|
|
3975
|
+
Ternary cubic with coefficients (1, 1, 1, 0, 0, 0, 0, 0, 0, 0)
|
|
3976
|
+
|
|
3977
|
+
sage: invariant_theory.ternary_cubic(x^3 + y^3 + z^3).J_covariant()
|
|
3978
|
+
x^6*y^3 - x^3*y^6 - x^6*z^3 + y^6*z^3 + x^3*z^6 - y^3*z^6
|
|
3979
|
+
"""
|
|
3980
|
+
|
|
3981
|
+
def __repr__(self):
|
|
3982
|
+
"""
|
|
3983
|
+
Return a string representation.
|
|
3984
|
+
|
|
3985
|
+
OUTPUT: string
|
|
3986
|
+
|
|
3987
|
+
EXAMPLES::
|
|
3988
|
+
|
|
3989
|
+
sage: invariant_theory
|
|
3990
|
+
InvariantTheoryFactory
|
|
3991
|
+
"""
|
|
3992
|
+
return "InvariantTheoryFactory"
|
|
3993
|
+
|
|
3994
|
+
def quadratic_form(self, polynomial, *args):
|
|
3995
|
+
"""
|
|
3996
|
+
Invariants of a homogeneous quadratic form.
|
|
3997
|
+
|
|
3998
|
+
INPUT:
|
|
3999
|
+
|
|
4000
|
+
- ``polynomial`` -- a homogeneous or inhomogeneous quadratic form
|
|
4001
|
+
|
|
4002
|
+
- ``*args`` -- the variables as multiple arguments, or as a
|
|
4003
|
+
single list/tuple. If the last argument is ``None``, the
|
|
4004
|
+
cubic is assumed to be inhomogeneous.
|
|
4005
|
+
|
|
4006
|
+
EXAMPLES::
|
|
4007
|
+
|
|
4008
|
+
sage: R.<x,y,z> = QQ[]
|
|
4009
|
+
sage: quadratic = x^2 + y^2 + z^2
|
|
4010
|
+
sage: inv = invariant_theory.quadratic_form(quadratic)
|
|
4011
|
+
sage: type(inv)
|
|
4012
|
+
<class 'sage.rings.invariants.invariant_theory.TernaryQuadratic'>
|
|
4013
|
+
|
|
4014
|
+
If some of the ring variables are to be treated as coefficients
|
|
4015
|
+
you need to specify the polynomial variables::
|
|
4016
|
+
|
|
4017
|
+
sage: R.<x,y,z, a,b> = QQ[]
|
|
4018
|
+
sage: quadratic = a*x^2 + b*y^2 + z^2 + 2*y*z
|
|
4019
|
+
sage: invariant_theory.quadratic_form(quadratic, x,y,z)
|
|
4020
|
+
Ternary quadratic with coefficients (a, b, 1, 0, 0, 2)
|
|
4021
|
+
sage: invariant_theory.quadratic_form(quadratic, [x,y,z]) # alternate syntax
|
|
4022
|
+
Ternary quadratic with coefficients (a, b, 1, 0, 0, 2)
|
|
4023
|
+
|
|
4024
|
+
Inhomogeneous quadratic forms (see also
|
|
4025
|
+
:meth:`inhomogeneous_quadratic_form`) can be specified by
|
|
4026
|
+
passing ``None`` as the last variable::
|
|
4027
|
+
|
|
4028
|
+
sage: inhom = quadratic.subs(z=1)
|
|
4029
|
+
sage: invariant_theory.quadratic_form(inhom, x,y,None)
|
|
4030
|
+
Ternary quadratic with coefficients (a, b, 1, 0, 0, 2)
|
|
4031
|
+
"""
|
|
4032
|
+
variables = _guess_variables(polynomial, *args)
|
|
4033
|
+
n = len(variables)
|
|
4034
|
+
if n == 3:
|
|
4035
|
+
return TernaryQuadratic(3, 2, polynomial, *args)
|
|
4036
|
+
else:
|
|
4037
|
+
return QuadraticForm(n, 2, polynomial, *args)
|
|
4038
|
+
|
|
4039
|
+
def inhomogeneous_quadratic_form(self, polynomial, *args):
|
|
4040
|
+
"""
|
|
4041
|
+
Invariants of an inhomogeneous quadratic form.
|
|
4042
|
+
|
|
4043
|
+
INPUT:
|
|
4044
|
+
|
|
4045
|
+
- ``polynomial`` -- an inhomogeneous quadratic form
|
|
4046
|
+
|
|
4047
|
+
- ``*args`` -- the variables as multiple arguments, or as a
|
|
4048
|
+
single list/tuple
|
|
4049
|
+
|
|
4050
|
+
EXAMPLES::
|
|
4051
|
+
|
|
4052
|
+
sage: R.<x,y,z> = QQ[]
|
|
4053
|
+
sage: quadratic = x^2 + 2*y^2 + 3*x*y + 4*x + 5*y + 6
|
|
4054
|
+
sage: inv3 = invariant_theory.inhomogeneous_quadratic_form(quadratic)
|
|
4055
|
+
sage: type(inv3)
|
|
4056
|
+
<class 'sage.rings.invariants.invariant_theory.TernaryQuadratic'>
|
|
4057
|
+
sage: inv4 = invariant_theory.inhomogeneous_quadratic_form(x^2 + y^2 + z^2)
|
|
4058
|
+
sage: type(inv4)
|
|
4059
|
+
<class 'sage.rings.invariants.invariant_theory.QuadraticForm'>
|
|
4060
|
+
"""
|
|
4061
|
+
variables = _guess_variables(polynomial, *args)
|
|
4062
|
+
n = len(variables) + 1
|
|
4063
|
+
if n == 3:
|
|
4064
|
+
return TernaryQuadratic(3, 2, polynomial, *args)
|
|
4065
|
+
else:
|
|
4066
|
+
return QuadraticForm(n, 2, polynomial, *args)
|
|
4067
|
+
|
|
4068
|
+
def binary_quadratic(self, quadratic, *args):
|
|
4069
|
+
"""
|
|
4070
|
+
Invariant theory of a quadratic in two variables.
|
|
4071
|
+
|
|
4072
|
+
INPUT:
|
|
4073
|
+
|
|
4074
|
+
- ``quadratic`` -- a quadratic form
|
|
4075
|
+
|
|
4076
|
+
- ``x``, ``y`` -- the homogeneous variables. If ``y`` is
|
|
4077
|
+
``None``, the quadratic is assumed to be inhomogeneous.
|
|
4078
|
+
|
|
4079
|
+
REFERENCES:
|
|
4080
|
+
|
|
4081
|
+
- :wikipedia:`Invariant_of_a_binary_form`
|
|
4082
|
+
|
|
4083
|
+
EXAMPLES::
|
|
4084
|
+
|
|
4085
|
+
sage: R.<x,y> = QQ[]
|
|
4086
|
+
sage: invariant_theory.binary_quadratic(x^2 + y^2)
|
|
4087
|
+
Binary quadratic with coefficients (1, 1, 0)
|
|
4088
|
+
|
|
4089
|
+
sage: T.<t> = QQ[]
|
|
4090
|
+
sage: invariant_theory.binary_quadratic(t^2 + 2*t + 1, [t])
|
|
4091
|
+
Binary quadratic with coefficients (1, 1, 2)
|
|
4092
|
+
"""
|
|
4093
|
+
return QuadraticForm(2, 2, quadratic, *args)
|
|
4094
|
+
|
|
4095
|
+
def quaternary_quadratic(self, quadratic, *args):
|
|
4096
|
+
"""
|
|
4097
|
+
Invariant theory of a quadratic in four variables.
|
|
4098
|
+
|
|
4099
|
+
INPUT:
|
|
4100
|
+
|
|
4101
|
+
- ``quadratic`` -- a quadratic form
|
|
4102
|
+
|
|
4103
|
+
- ``w``, ``x``, ``y``, ``z`` -- the homogeneous variables. If
|
|
4104
|
+
``z`` is ``None``, the quadratic is assumed to be inhomogeneous.
|
|
4105
|
+
|
|
4106
|
+
REFERENCES:
|
|
4107
|
+
|
|
4108
|
+
- :wikipedia:`Invariant_of_a_binary_form`
|
|
4109
|
+
|
|
4110
|
+
EXAMPLES::
|
|
4111
|
+
|
|
4112
|
+
sage: R.<w,x,y,z> = QQ[]
|
|
4113
|
+
sage: invariant_theory.quaternary_quadratic(w^2 + x^2 + y^2 + z^2)
|
|
4114
|
+
Quaternary quadratic with coefficients (1, 1, 1, 1, 0, 0, 0, 0, 0, 0)
|
|
4115
|
+
|
|
4116
|
+
sage: R.<x,y,z> = QQ[]
|
|
4117
|
+
sage: invariant_theory.quaternary_quadratic(1 + x^2 + y^2 + z^2)
|
|
4118
|
+
Quaternary quadratic with coefficients (1, 1, 1, 1, 0, 0, 0, 0, 0, 0)
|
|
4119
|
+
"""
|
|
4120
|
+
return QuadraticForm(4, 2, quadratic, *args)
|
|
4121
|
+
|
|
4122
|
+
def binary_quartic(self, quartic, *args, **kwds):
|
|
4123
|
+
"""
|
|
4124
|
+
Invariant theory of a quartic in two variables.
|
|
4125
|
+
|
|
4126
|
+
The algebra of invariants of a quartic form is generated by
|
|
4127
|
+
invariants `i`, `j` of degrees 2, 3. This ring is naturally
|
|
4128
|
+
isomorphic to the ring of modular forms of level 1, with the
|
|
4129
|
+
two generators corresponding to the Eisenstein series `E_4`
|
|
4130
|
+
(see
|
|
4131
|
+
:meth:`~sage.rings.invariants.invariant_theory.BinaryQuartic.EisensteinD`)
|
|
4132
|
+
and `E_6` (see
|
|
4133
|
+
:meth:`~sage.rings.invariants.invariant_theory.BinaryQuartic.EisensteinE`). The
|
|
4134
|
+
algebra of covariants is generated by these two invariants
|
|
4135
|
+
together with the form `f` of degree 1 and order 4, the
|
|
4136
|
+
Hessian `g` (see :meth:`~BinaryQuartic.g_covariant`) of degree
|
|
4137
|
+
2 and order 4, and a covariant `h` (see
|
|
4138
|
+
:meth:`~BinaryQuartic.h_covariant`) of degree 3 and order
|
|
4139
|
+
6. They are related by a syzygy
|
|
4140
|
+
|
|
4141
|
+
.. MATH::
|
|
4142
|
+
|
|
4143
|
+
j f^3 - g f^2 i + 4 g^3 + h^2 = 0
|
|
4144
|
+
|
|
4145
|
+
of degree 6 and order 12.
|
|
4146
|
+
|
|
4147
|
+
INPUT:
|
|
4148
|
+
|
|
4149
|
+
- ``quartic`` -- a quartic
|
|
4150
|
+
|
|
4151
|
+
- ``x``, ``y`` -- the homogeneous variables. If ``y`` is
|
|
4152
|
+
``None``, the quartic is assumed to be inhomogeneous.
|
|
4153
|
+
|
|
4154
|
+
REFERENCES:
|
|
4155
|
+
|
|
4156
|
+
- :wikipedia:`Invariant_of_a_binary_form`
|
|
4157
|
+
|
|
4158
|
+
EXAMPLES::
|
|
4159
|
+
|
|
4160
|
+
sage: R.<x,y> = QQ[]
|
|
4161
|
+
sage: quartic = invariant_theory.binary_quartic(x^4 + y^4)
|
|
4162
|
+
sage: quartic
|
|
4163
|
+
Binary quartic with coefficients (1, 0, 0, 0, 1)
|
|
4164
|
+
sage: type(quartic)
|
|
4165
|
+
<class 'sage.rings.invariants.invariant_theory.BinaryQuartic'>
|
|
4166
|
+
"""
|
|
4167
|
+
return BinaryQuartic(2, 4, quartic, *args, **kwds)
|
|
4168
|
+
|
|
4169
|
+
def binary_quintic(self, quintic, *args, **kwds):
|
|
4170
|
+
"""
|
|
4171
|
+
Create a binary quintic for computing invariants.
|
|
4172
|
+
|
|
4173
|
+
A binary quintic is a homogeneous polynomial of degree 5 in two
|
|
4174
|
+
variables. The algebra of invariants of a binary quintic is generated
|
|
4175
|
+
by the invariants `A`, `B` and `C` of respective degrees 4, 8 and 12
|
|
4176
|
+
(see :meth:`~BinaryQuintic.A_invariant`,
|
|
4177
|
+
:meth:`~BinaryQuintic.B_invariant` and
|
|
4178
|
+
:meth:`~BinaryQuintic.C_invariant`).
|
|
4179
|
+
|
|
4180
|
+
INPUT:
|
|
4181
|
+
|
|
4182
|
+
- ``quintic`` -- a homogeneous polynomial of degree five in two
|
|
4183
|
+
variables or a (possibly inhomogeneous) polynomial of degree at most
|
|
4184
|
+
five in one variable.
|
|
4185
|
+
|
|
4186
|
+
- ``*args`` -- the two homogeneous variables. If only one variable is
|
|
4187
|
+
given, the polynomial ``quintic`` is assumed to be univariate. If
|
|
4188
|
+
no variables are given, they are guessed.
|
|
4189
|
+
|
|
4190
|
+
REFERENCES:
|
|
4191
|
+
|
|
4192
|
+
- :wikipedia:`Invariant_of_a_binary_form`
|
|
4193
|
+
- [Cle1872]_
|
|
4194
|
+
|
|
4195
|
+
EXAMPLES:
|
|
4196
|
+
|
|
4197
|
+
If no variables are provided, they will be guessed::
|
|
4198
|
+
|
|
4199
|
+
sage: R.<x,y> = QQ[]
|
|
4200
|
+
sage: quintic = invariant_theory.binary_quintic(x^5 + y^5)
|
|
4201
|
+
sage: quintic
|
|
4202
|
+
Binary quintic with coefficients (1, 0, 0, 0, 0, 1)
|
|
4203
|
+
|
|
4204
|
+
If only one variable is given, the quintic is the homogenisation of
|
|
4205
|
+
the provided polynomial::
|
|
4206
|
+
|
|
4207
|
+
sage: quintic = invariant_theory.binary_quintic(x^5 + y^5, x)
|
|
4208
|
+
sage: quintic
|
|
4209
|
+
Binary quintic with coefficients (y^5, 0, 0, 0, 0, 1)
|
|
4210
|
+
sage: quintic.is_homogeneous()
|
|
4211
|
+
False
|
|
4212
|
+
|
|
4213
|
+
If the polynomial has three or more variables, the variables should be
|
|
4214
|
+
specified::
|
|
4215
|
+
|
|
4216
|
+
sage: R.<x,y,z> = QQ[]
|
|
4217
|
+
sage: quintic = invariant_theory.binary_quintic(x^5 + z*y^5)
|
|
4218
|
+
Traceback (most recent call last):
|
|
4219
|
+
...
|
|
4220
|
+
ValueError: need 2 or 1 variables, got (x, y, z)
|
|
4221
|
+
sage: quintic = invariant_theory.binary_quintic(x^5 + z*y^5, x, y)
|
|
4222
|
+
sage: quintic
|
|
4223
|
+
Binary quintic with coefficients (z, 0, 0, 0, 0, 1)
|
|
4224
|
+
|
|
4225
|
+
sage: type(quintic)
|
|
4226
|
+
<class 'sage.rings.invariants.invariant_theory.BinaryQuintic'>
|
|
4227
|
+
"""
|
|
4228
|
+
return BinaryQuintic(2, 5, quintic, *args, **kwds)
|
|
4229
|
+
|
|
4230
|
+
def binary_form_from_invariants(self, degree, invariants, variables=None, as_form=True, *args, **kwargs):
|
|
4231
|
+
r"""
|
|
4232
|
+
Reconstruct a binary form from the values of its invariants.
|
|
4233
|
+
|
|
4234
|
+
INPUT:
|
|
4235
|
+
|
|
4236
|
+
- ``degree`` -- the degree of the binary form
|
|
4237
|
+
|
|
4238
|
+
- ``invariants`` -- list or tuple of values of the invariants of the
|
|
4239
|
+
binary form
|
|
4240
|
+
|
|
4241
|
+
- ``variables`` -- list or tuple of two variables that are used for
|
|
4242
|
+
the resulting form (only if ``as_form`` is ``True``). If no variables
|
|
4243
|
+
are provided, two abstract variables ``x`` and ``z`` will be used.
|
|
4244
|
+
|
|
4245
|
+
- ``as_form`` -- boolean; if ``False``, the function will return a tuple
|
|
4246
|
+
of coefficients of a binary form
|
|
4247
|
+
|
|
4248
|
+
OUTPUT:
|
|
4249
|
+
|
|
4250
|
+
A binary form or a tuple of its coefficients, whose invariants are equal
|
|
4251
|
+
to the given ``invariants`` up to a scaling.
|
|
4252
|
+
|
|
4253
|
+
EXAMPLES:
|
|
4254
|
+
|
|
4255
|
+
In the case of binary quadratics and cubics, the form is reconstructed
|
|
4256
|
+
based on the value of the discriminant. See also
|
|
4257
|
+
:meth:`binary_quadratic_coefficients_from_invariants` and
|
|
4258
|
+
:meth:`binary_cubic_coefficients_from_invariants`. These methods will always return the
|
|
4259
|
+
same result if the discriminant is nonzero::
|
|
4260
|
+
|
|
4261
|
+
sage: discriminant = 1
|
|
4262
|
+
sage: invariant_theory.binary_form_from_invariants(2, [discriminant])
|
|
4263
|
+
Binary quadratic with coefficients (1, -1/4, 0)
|
|
4264
|
+
sage: invariant_theory.binary_form_from_invariants(3, [discriminant], as_form=false)
|
|
4265
|
+
(0, 1, -1, 0)
|
|
4266
|
+
|
|
4267
|
+
For binary cubics, there is no class implemented yet, so ``as_form=True``
|
|
4268
|
+
will yield a :exc:`NotImplementedError`::
|
|
4269
|
+
|
|
4270
|
+
sage: invariant_theory.binary_form_from_invariants(3, [discriminant])
|
|
4271
|
+
Traceback (most recent call last):
|
|
4272
|
+
...
|
|
4273
|
+
NotImplementedError: no class for binary cubics implemented
|
|
4274
|
+
|
|
4275
|
+
For binary quintics, the three Clebsch invariants of the form should be
|
|
4276
|
+
provided to reconstruct the form. For more details about these invariants,
|
|
4277
|
+
see :meth:`~sage.rings.invariants.invariant_theory.BinaryQuintic.clebsch_invariants`::
|
|
4278
|
+
|
|
4279
|
+
sage: invariants = [1, 0, 0]
|
|
4280
|
+
sage: invariant_theory.binary_form_from_invariants(5, invariants)
|
|
4281
|
+
Binary quintic with coefficients (1, 0, 0, 0, 0, 1)
|
|
4282
|
+
|
|
4283
|
+
An optional ``scaling`` argument may be provided in order to scale the
|
|
4284
|
+
resulting quintic. For more details, see :meth:`binary_quintic_coefficients_from_invariants`::
|
|
4285
|
+
|
|
4286
|
+
sage: invariants = [3, 4, 7]
|
|
4287
|
+
sage: invariant_theory.binary_form_from_invariants(5, invariants)
|
|
4288
|
+
Binary quintic with coefficients (-37725479487783/1048576,
|
|
4289
|
+
565882192316745/8388608, 0, 1033866765362693115/67108864,
|
|
4290
|
+
12849486940936328715/268435456, -23129076493685391687/2147483648)
|
|
4291
|
+
sage: invariant_theory.binary_form_from_invariants(5, invariants,
|
|
4292
|
+
....: scaling='normalized')
|
|
4293
|
+
Binary quintic with coefficients (24389/892616806656,
|
|
4294
|
+
4205/11019960576, 0, 1015/209952, -145/1296, -3/16)
|
|
4295
|
+
sage: invariant_theory.binary_form_from_invariants(5, invariants,
|
|
4296
|
+
....: scaling='coprime')
|
|
4297
|
+
Binary quintic with coefficients (-2048, 3840, 0, 876960, 2724840, -613089)
|
|
4298
|
+
|
|
4299
|
+
The invariants can also be computed using the invariants of a given binary
|
|
4300
|
+
quintic. The resulting form has the same invariants up to scaling, is
|
|
4301
|
+
`GL(2,\QQ)`-equivalent to the provided form and hence has the same
|
|
4302
|
+
canonical form (see
|
|
4303
|
+
:meth:`~sage.rings.invariants.invariant_theory.BinaryQuintic.canonical_form`)::
|
|
4304
|
+
|
|
4305
|
+
sage: R.<x0, x1> = QQ[]
|
|
4306
|
+
sage: p = 3*x1^5 + 6*x1^4*x0 + 3*x1^3*x0^2 + 4*x1^2*x0^3 - 5*x1*x0^4 + 4*x0^5
|
|
4307
|
+
sage: quintic = invariant_theory.binary_quintic(p, x0, x1)
|
|
4308
|
+
sage: invariants = quintic.clebsch_invariants(as_tuple=True)
|
|
4309
|
+
sage: newquintic = invariant_theory.binary_form_from_invariants(
|
|
4310
|
+
....: 5, invariants, variables=quintic.variables())
|
|
4311
|
+
sage: newquintic
|
|
4312
|
+
Binary quintic with coefficients (9592267437341790539005557/244140625000000,
|
|
4313
|
+
2149296928207625556323004064707/610351562500000000,
|
|
4314
|
+
11149651890347700974453304786783/76293945312500000,
|
|
4315
|
+
122650775751894638395648891202734239/47683715820312500000,
|
|
4316
|
+
323996630945706528474286334593218447/11920928955078125000,
|
|
4317
|
+
1504506503644608395841632538558481466127/14901161193847656250000)
|
|
4318
|
+
sage: quintic.canonical_form() == newquintic.canonical_form()
|
|
4319
|
+
True
|
|
4320
|
+
|
|
4321
|
+
For binary forms of other degrees, no reconstruction has been
|
|
4322
|
+
implemented yet. For forms of degree 6, see :issue:`26462`::
|
|
4323
|
+
|
|
4324
|
+
sage: invariant_theory.binary_form_from_invariants(6, invariants)
|
|
4325
|
+
Traceback (most recent call last):
|
|
4326
|
+
...
|
|
4327
|
+
NotImplementedError: no reconstruction for binary forms of degree 6 implemented
|
|
4328
|
+
|
|
4329
|
+
TESTS::
|
|
4330
|
+
|
|
4331
|
+
sage: invariant_theory.binary_form_from_invariants(2, [1,2])
|
|
4332
|
+
Traceback (most recent call last):
|
|
4333
|
+
...
|
|
4334
|
+
ValueError: incorrect number of invariants provided, only one invariant should be provided
|
|
4335
|
+
sage: invariant_theory.binary_form_from_invariants(2, [1], invariant_choice='unknown')
|
|
4336
|
+
Traceback (most recent call last):
|
|
4337
|
+
...
|
|
4338
|
+
ValueError: unknown choice of invariants unknown for a binary quadratic
|
|
4339
|
+
sage: invariant_theory.binary_form_from_invariants(3, [1,2])
|
|
4340
|
+
Traceback (most recent call last):
|
|
4341
|
+
...
|
|
4342
|
+
ValueError: incorrect number of invariants provided, only one invariant should be provided
|
|
4343
|
+
sage: invariant_theory.binary_form_from_invariants(3, [1], as_form=false, invariant_choice='unknown')
|
|
4344
|
+
Traceback (most recent call last):
|
|
4345
|
+
...
|
|
4346
|
+
ValueError: unknown choice of invariants unknown for a binary cubic
|
|
4347
|
+
sage: invariant_theory.binary_form_from_invariants(5, [1,2,3], invariant_choice='unknown')
|
|
4348
|
+
Traceback (most recent call last):
|
|
4349
|
+
...
|
|
4350
|
+
ValueError: unknown choice of invariants unknown for a binary quintic
|
|
4351
|
+
sage: invariant_theory.binary_form_from_invariants(42, invariants)
|
|
4352
|
+
Traceback (most recent call last):
|
|
4353
|
+
...
|
|
4354
|
+
NotImplementedError: no reconstruction for binary forms of degree 42 implemented
|
|
4355
|
+
"""
|
|
4356
|
+
if as_form:
|
|
4357
|
+
from sage.rings.fraction_field import FractionField
|
|
4358
|
+
from sage.structure.sequence import Sequence
|
|
4359
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
4360
|
+
K = FractionField(Sequence(list(invariants)).universe())
|
|
4361
|
+
if variables is None:
|
|
4362
|
+
x, z = PolynomialRing(K, 'x,z').gens()
|
|
4363
|
+
elif len(variables) == 2:
|
|
4364
|
+
x, z = variables
|
|
4365
|
+
else:
|
|
4366
|
+
raise ValueError('incorrect number of variables provided, '
|
|
4367
|
+
'exactly two variables should be provided')
|
|
4368
|
+
if degree == 2:
|
|
4369
|
+
if len(invariants) == 1:
|
|
4370
|
+
if as_form:
|
|
4371
|
+
return QuadraticForm.from_invariants(invariants[0], x, z,
|
|
4372
|
+
*args, **kwargs)
|
|
4373
|
+
else:
|
|
4374
|
+
return reconstruction.binary_quadratic_coefficients_from_invariants(
|
|
4375
|
+
invariants[0], *args, **kwargs)
|
|
4376
|
+
else:
|
|
4377
|
+
raise ValueError('incorrect number of invariants provided, '
|
|
4378
|
+
'only one invariant should be provided')
|
|
4379
|
+
elif degree == 3:
|
|
4380
|
+
if len(invariants) == 1:
|
|
4381
|
+
if as_form:
|
|
4382
|
+
raise NotImplementedError('no class for binary cubics implemented')
|
|
4383
|
+
else:
|
|
4384
|
+
return reconstruction.binary_cubic_coefficients_from_invariants(
|
|
4385
|
+
invariants[0], *args, **kwargs)
|
|
4386
|
+
else:
|
|
4387
|
+
raise ValueError('incorrect number of invariants provided, only '
|
|
4388
|
+
'one invariant should be provided')
|
|
4389
|
+
elif degree == 5:
|
|
4390
|
+
if as_form:
|
|
4391
|
+
return BinaryQuintic.from_invariants(invariants, x, z,
|
|
4392
|
+
*args, **kwargs)
|
|
4393
|
+
else:
|
|
4394
|
+
return reconstruction.binary_quintic_coefficients_from_invariants(
|
|
4395
|
+
invariants, *args, **kwargs)
|
|
4396
|
+
else:
|
|
4397
|
+
raise NotImplementedError('no reconstruction for binary forms of '
|
|
4398
|
+
'degree {} implemented'.format(degree))
|
|
4399
|
+
|
|
4400
|
+
def ternary_quadratic(self, quadratic, *args, **kwds):
|
|
4401
|
+
"""
|
|
4402
|
+
Invariants of a quadratic in three variables.
|
|
4403
|
+
|
|
4404
|
+
INPUT:
|
|
4405
|
+
|
|
4406
|
+
- ``quadratic`` -- a homogeneous quadratic in 3 homogeneous
|
|
4407
|
+
variables, or an inhomogeneous quadratic in 2 variables
|
|
4408
|
+
|
|
4409
|
+
- ``x``, ``y``, ``z`` -- the variables. If ``z`` is ``None``,
|
|
4410
|
+
the quadratic is assumed to be inhomogeneous.
|
|
4411
|
+
|
|
4412
|
+
REFERENCES:
|
|
4413
|
+
|
|
4414
|
+
- :wikipedia:`Invariant_of_a_binary_form`
|
|
4415
|
+
|
|
4416
|
+
EXAMPLES::
|
|
4417
|
+
|
|
4418
|
+
sage: R.<x,y,z> = QQ[]
|
|
4419
|
+
sage: invariant_theory.ternary_quadratic(x^2 + y^2 + z^2)
|
|
4420
|
+
Ternary quadratic with coefficients (1, 1, 1, 0, 0, 0)
|
|
4421
|
+
|
|
4422
|
+
sage: T.<u, v> = QQ[]
|
|
4423
|
+
sage: invariant_theory.ternary_quadratic(1 + u^2 + v^2)
|
|
4424
|
+
Ternary quadratic with coefficients (1, 1, 1, 0, 0, 0)
|
|
4425
|
+
|
|
4426
|
+
sage: quadratic = x^2 + y^2 + z^2
|
|
4427
|
+
sage: inv = invariant_theory.ternary_quadratic(quadratic)
|
|
4428
|
+
sage: type(inv)
|
|
4429
|
+
<class 'sage.rings.invariants.invariant_theory.TernaryQuadratic'>
|
|
4430
|
+
"""
|
|
4431
|
+
return TernaryQuadratic(3, 2, quadratic, *args, **kwds)
|
|
4432
|
+
|
|
4433
|
+
def ternary_cubic(self, cubic, *args, **kwds):
|
|
4434
|
+
r"""
|
|
4435
|
+
Invariants of a cubic in three variables.
|
|
4436
|
+
|
|
4437
|
+
The algebra of invariants of a ternary cubic under `SL_3(\CC)`
|
|
4438
|
+
is a polynomial algebra generated by two invariants `S` (see
|
|
4439
|
+
:meth:`~sage.rings.invariants.invariant_theory.TernaryCubic.S_invariant`)
|
|
4440
|
+
and T (see
|
|
4441
|
+
:meth:`~sage.rings.invariants.invariant_theory.TernaryCubic.T_invariant`)
|
|
4442
|
+
of degrees 4 and 6, called Aronhold invariants.
|
|
4443
|
+
|
|
4444
|
+
The ring of covariants is given as follows. The identity
|
|
4445
|
+
covariant U of a ternary cubic has degree 1 and order 3. The
|
|
4446
|
+
Hessian `H` (see
|
|
4447
|
+
:meth:`~sage.rings.invariants.invariant_theory.TernaryCubic.Hessian`)
|
|
4448
|
+
is a covariant of ternary cubics of degree 3 and order 3.
|
|
4449
|
+
There is a covariant `\Theta` (see
|
|
4450
|
+
:meth:`~sage.rings.invariants.invariant_theory.TernaryCubic.Theta_covariant`)
|
|
4451
|
+
of ternary cubics of degree 8 and order 6 that vanishes on
|
|
4452
|
+
points `x` lying on the Salmon conic of the polar of `x` with
|
|
4453
|
+
respect to the curve and its Hessian curve. The Brioschi
|
|
4454
|
+
covariant `J` (see
|
|
4455
|
+
:meth:`~sage.rings.invariants.invariant_theory.TernaryCubic.J_covariant`)
|
|
4456
|
+
is the Jacobian of `U`, `\Theta`, and `H` of degree 12, order
|
|
4457
|
+
9. The algebra of covariants of a ternary cubic is generated
|
|
4458
|
+
over the ring of invariants by `U`, `\Theta`, `H`, and `J`,
|
|
4459
|
+
with a relation
|
|
4460
|
+
|
|
4461
|
+
.. MATH::
|
|
4462
|
+
|
|
4463
|
+
\begin{split}
|
|
4464
|
+
J^2 =& 4 \Theta^3 + T U^2 \Theta^2 +
|
|
4465
|
+
\Theta (-4 S^3 U^4 + 2 S T U^3 H
|
|
4466
|
+
- 72 S^2 U^2 H^2
|
|
4467
|
+
\\ &
|
|
4468
|
+
- 18 T U H^3 + 108 S H^4)
|
|
4469
|
+
-16 S^4 U^5 H - 11 S^2 T U^4 H^2
|
|
4470
|
+
\\ &
|
|
4471
|
+
-4 T^2 U^3 H^3
|
|
4472
|
+
+54 S T U^2 H^4 -432 S^2 U H^5 -27 T H^6
|
|
4473
|
+
\end{split}
|
|
4474
|
+
|
|
4475
|
+
|
|
4476
|
+
REFERENCES:
|
|
4477
|
+
|
|
4478
|
+
- :wikipedia:`Ternary_cubic`
|
|
4479
|
+
|
|
4480
|
+
INPUT:
|
|
4481
|
+
|
|
4482
|
+
- ``cubic`` -- a homogeneous cubic in 3 homogeneous variables,
|
|
4483
|
+
or an inhomogeneous cubic in 2 variables
|
|
4484
|
+
|
|
4485
|
+
- ``x``, ``y``, ``z`` -- the variables. If ``z`` is ``None``, the
|
|
4486
|
+
cubic is assumed to be inhomogeneous.
|
|
4487
|
+
|
|
4488
|
+
EXAMPLES::
|
|
4489
|
+
|
|
4490
|
+
sage: R.<x,y,z> = QQ[]
|
|
4491
|
+
sage: cubic = invariant_theory.ternary_cubic(x^3 + y^3 + z^3)
|
|
4492
|
+
sage: type(cubic)
|
|
4493
|
+
<class 'sage.rings.invariants.invariant_theory.TernaryCubic'>
|
|
4494
|
+
"""
|
|
4495
|
+
return TernaryCubic(3, 3, cubic, *args, **kwds)
|
|
4496
|
+
|
|
4497
|
+
def ternary_biquadratic(self, quadratic1, quadratic2, *args, **kwds):
|
|
4498
|
+
"""
|
|
4499
|
+
Invariants of two quadratics in three variables.
|
|
4500
|
+
|
|
4501
|
+
INPUT:
|
|
4502
|
+
|
|
4503
|
+
- ``quadratic1``, ``quadratic2`` -- two polynomials. Either
|
|
4504
|
+
homogeneous quadratic in 3 homogeneous variables, or
|
|
4505
|
+
inhomogeneous quadratic in 2 variables.
|
|
4506
|
+
|
|
4507
|
+
- ``x``, ``y``, ``z`` -- the variables. If ``z`` is ``None``,
|
|
4508
|
+
the quadratics are assumed to be inhomogeneous.
|
|
4509
|
+
|
|
4510
|
+
EXAMPLES::
|
|
4511
|
+
|
|
4512
|
+
sage: R.<x,y,z> = QQ[]
|
|
4513
|
+
sage: q1 = x^2 + y^2 + z^2
|
|
4514
|
+
sage: q2 = x*y + y*z + x*z
|
|
4515
|
+
sage: inv = invariant_theory.ternary_biquadratic(q1, q2)
|
|
4516
|
+
sage: type(inv)
|
|
4517
|
+
<class 'sage.rings.invariants.invariant_theory.TwoTernaryQuadratics'>
|
|
4518
|
+
|
|
4519
|
+
Distance between two circles::
|
|
4520
|
+
|
|
4521
|
+
sage: R.<x,y, a,b, r1,r2> = QQ[]
|
|
4522
|
+
sage: S1 = -r1^2 + x^2 + y^2
|
|
4523
|
+
sage: S2 = -r2^2 + (x-a)^2 + (y-b)^2
|
|
4524
|
+
sage: inv = invariant_theory.ternary_biquadratic(S1, S2, [x, y])
|
|
4525
|
+
sage: inv.Delta_invariant()
|
|
4526
|
+
-r1^2
|
|
4527
|
+
sage: inv.Delta_prime_invariant()
|
|
4528
|
+
-r2^2
|
|
4529
|
+
sage: inv.Theta_invariant()
|
|
4530
|
+
a^2 + b^2 - 2*r1^2 - r2^2
|
|
4531
|
+
sage: inv.Theta_prime_invariant()
|
|
4532
|
+
a^2 + b^2 - r1^2 - 2*r2^2
|
|
4533
|
+
sage: inv.F_covariant()
|
|
4534
|
+
2*x^2*a^2 + y^2*a^2 - 2*x*a^3 + a^4 + 2*x*y*a*b - 2*y*a^2*b + x^2*b^2 +
|
|
4535
|
+
2*y^2*b^2 - 2*x*a*b^2 + 2*a^2*b^2 - 2*y*b^3 + b^4 - 2*x^2*r1^2 - 2*y^2*r1^2 +
|
|
4536
|
+
2*x*a*r1^2 - 2*a^2*r1^2 + 2*y*b*r1^2 - 2*b^2*r1^2 + r1^4 - 2*x^2*r2^2 -
|
|
4537
|
+
2*y^2*r2^2 + 2*x*a*r2^2 - 2*a^2*r2^2 + 2*y*b*r2^2 - 2*b^2*r2^2 + 2*r1^2*r2^2 +
|
|
4538
|
+
r2^4
|
|
4539
|
+
sage: inv.J_covariant()
|
|
4540
|
+
-8*x^2*y*a^3 + 8*x*y*a^4 + 8*x^3*a^2*b - 16*x*y^2*a^2*b - 8*x^2*a^3*b +
|
|
4541
|
+
8*y^2*a^3*b + 16*x^2*y*a*b^2 - 8*y^3*a*b^2 + 8*x*y^2*b^3 - 8*x^2*a*b^3 +
|
|
4542
|
+
8*y^2*a*b^3 - 8*x*y*b^4 + 8*x*y*a^2*r1^2 - 8*y*a^3*r1^2 - 8*x^2*a*b*r1^2 +
|
|
4543
|
+
8*y^2*a*b*r1^2 + 8*x*a^2*b*r1^2 - 8*x*y*b^2*r1^2 - 8*y*a*b^2*r1^2 + 8*x*b^3*r1^2 -
|
|
4544
|
+
8*x*y*a^2*r2^2 + 8*x^2*a*b*r2^2 - 8*y^2*a*b*r2^2 + 8*x*y*b^2*r2^2
|
|
4545
|
+
"""
|
|
4546
|
+
q1 = TernaryQuadratic(3, 2, quadratic1, *args, **kwds)
|
|
4547
|
+
q2 = TernaryQuadratic(3, 2, quadratic2, *args, **kwds)
|
|
4548
|
+
return TwoTernaryQuadratics([q1, q2])
|
|
4549
|
+
|
|
4550
|
+
def quaternary_biquadratic(self, quadratic1, quadratic2, *args, **kwds):
|
|
4551
|
+
"""
|
|
4552
|
+
Invariants of two quadratics in four variables.
|
|
4553
|
+
|
|
4554
|
+
INPUT:
|
|
4555
|
+
|
|
4556
|
+
- ``quadratic1``, ``quadratic2`` -- two polynomials.
|
|
4557
|
+
Either homogeneous quadratic
|
|
4558
|
+
in 4 homogeneous variables, or inhomogeneous quadratic
|
|
4559
|
+
in 3 variables.
|
|
4560
|
+
|
|
4561
|
+
- ``w``, ``x``, ``y``, ``z`` -- the variables. If ``z`` is
|
|
4562
|
+
``None``, the quadratics are assumed to be inhomogeneous.
|
|
4563
|
+
|
|
4564
|
+
EXAMPLES::
|
|
4565
|
+
|
|
4566
|
+
sage: R.<w,x,y,z> = QQ[]
|
|
4567
|
+
sage: q1 = w^2 + x^2 + y^2 + z^2
|
|
4568
|
+
sage: q2 = w*x + y*z
|
|
4569
|
+
sage: inv = invariant_theory.quaternary_biquadratic(q1, q2)
|
|
4570
|
+
sage: type(inv)
|
|
4571
|
+
<class 'sage.rings.invariants.invariant_theory.TwoQuaternaryQuadratics'>
|
|
4572
|
+
|
|
4573
|
+
Distance between two spheres [Sal1958]_, [Sal1965]_ ::
|
|
4574
|
+
|
|
4575
|
+
sage: R.<x,y,z, a,b,c, r1,r2> = QQ[]
|
|
4576
|
+
sage: S1 = -r1^2 + x^2 + y^2 + z^2
|
|
4577
|
+
sage: S2 = -r2^2 + (x-a)^2 + (y-b)^2 + (z-c)^2
|
|
4578
|
+
sage: inv = invariant_theory.quaternary_biquadratic(S1, S2, [x, y, z])
|
|
4579
|
+
sage: inv.Delta_invariant()
|
|
4580
|
+
-r1^2
|
|
4581
|
+
sage: inv.Delta_prime_invariant()
|
|
4582
|
+
-r2^2
|
|
4583
|
+
sage: inv.Theta_invariant()
|
|
4584
|
+
a^2 + b^2 + c^2 - 3*r1^2 - r2^2
|
|
4585
|
+
sage: inv.Theta_prime_invariant()
|
|
4586
|
+
a^2 + b^2 + c^2 - r1^2 - 3*r2^2
|
|
4587
|
+
sage: inv.Phi_invariant()
|
|
4588
|
+
2*a^2 + 2*b^2 + 2*c^2 - 3*r1^2 - 3*r2^2
|
|
4589
|
+
sage: inv.J_covariant()
|
|
4590
|
+
0
|
|
4591
|
+
"""
|
|
4592
|
+
q1 = QuadraticForm(4, 2, quadratic1, *args, **kwds)
|
|
4593
|
+
q2 = QuadraticForm(4, 2, quadratic2, *args, **kwds)
|
|
4594
|
+
return TwoQuaternaryQuadratics([q1, q2])
|
|
4595
|
+
|
|
4596
|
+
|
|
4597
|
+
invariant_theory = InvariantTheoryFactory()
|