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.

Files changed (808) hide show
  1. passagemath_modules-10.6.31rc3.dist-info/METADATA +281 -0
  2. passagemath_modules-10.6.31rc3.dist-info/RECORD +808 -0
  3. passagemath_modules-10.6.31rc3.dist-info/WHEEL +5 -0
  4. passagemath_modules-10.6.31rc3.dist-info/top_level.txt +2 -0
  5. passagemath_modules.libs/libgcc_s-0cd532bd.so.1 +0 -0
  6. passagemath_modules.libs/libgfortran-2c33b284.so.5.0.0 +0 -0
  7. passagemath_modules.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
  8. passagemath_modules.libs/libgsl-42cda06f.so.28.0.0 +0 -0
  9. passagemath_modules.libs/libmpc-d8ebe4b5.so.3.3.1 +0 -0
  10. passagemath_modules.libs/libmpfr-aaecbfc0.so.6.2.1 +0 -0
  11. passagemath_modules.libs/libopenblasp-r0-905cb27d.3.29.so +0 -0
  12. passagemath_modules.libs/libquadmath-bb76a5fc.so.0.0.0 +0 -0
  13. sage/algebras/all__sagemath_modules.py +20 -0
  14. sage/algebras/catalog.py +148 -0
  15. sage/algebras/clifford_algebra.py +3107 -0
  16. sage/algebras/clifford_algebra_element.cpython-314-x86_64-linux-musl.so +0 -0
  17. sage/algebras/clifford_algebra_element.pxd +16 -0
  18. sage/algebras/clifford_algebra_element.pyx +997 -0
  19. sage/algebras/commutative_dga.py +4252 -0
  20. sage/algebras/exterior_algebra_groebner.cpython-314-x86_64-linux-musl.so +0 -0
  21. sage/algebras/exterior_algebra_groebner.pxd +55 -0
  22. sage/algebras/exterior_algebra_groebner.pyx +727 -0
  23. sage/algebras/finite_dimensional_algebras/all.py +2 -0
  24. sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +1029 -0
  25. sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.cpython-314-x86_64-linux-musl.so +0 -0
  26. sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pxd +12 -0
  27. sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx +706 -0
  28. sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py +196 -0
  29. sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py +255 -0
  30. sage/algebras/finite_gca.py +528 -0
  31. sage/algebras/group_algebra.py +232 -0
  32. sage/algebras/lie_algebras/abelian.py +197 -0
  33. sage/algebras/lie_algebras/affine_lie_algebra.py +1213 -0
  34. sage/algebras/lie_algebras/all.py +25 -0
  35. sage/algebras/lie_algebras/all__sagemath_modules.py +1 -0
  36. sage/algebras/lie_algebras/bch.py +177 -0
  37. sage/algebras/lie_algebras/bgg_dual_module.py +1184 -0
  38. sage/algebras/lie_algebras/bgg_resolution.py +232 -0
  39. sage/algebras/lie_algebras/center_uea.py +767 -0
  40. sage/algebras/lie_algebras/classical_lie_algebra.py +2516 -0
  41. sage/algebras/lie_algebras/examples.py +683 -0
  42. sage/algebras/lie_algebras/free_lie_algebra.py +973 -0
  43. sage/algebras/lie_algebras/heisenberg.py +820 -0
  44. sage/algebras/lie_algebras/lie_algebra.py +1562 -0
  45. sage/algebras/lie_algebras/lie_algebra_element.cpython-314-x86_64-linux-musl.so +0 -0
  46. sage/algebras/lie_algebras/lie_algebra_element.pxd +68 -0
  47. sage/algebras/lie_algebras/lie_algebra_element.pyx +2122 -0
  48. sage/algebras/lie_algebras/morphism.py +661 -0
  49. sage/algebras/lie_algebras/nilpotent_lie_algebra.py +457 -0
  50. sage/algebras/lie_algebras/onsager.py +1324 -0
  51. sage/algebras/lie_algebras/poincare_birkhoff_witt.py +816 -0
  52. sage/algebras/lie_algebras/quotient.py +462 -0
  53. sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py +355 -0
  54. sage/algebras/lie_algebras/representation.py +1040 -0
  55. sage/algebras/lie_algebras/structure_coefficients.py +459 -0
  56. sage/algebras/lie_algebras/subalgebra.py +967 -0
  57. sage/algebras/lie_algebras/symplectic_derivation.py +289 -0
  58. sage/algebras/lie_algebras/verma_module.py +1630 -0
  59. sage/algebras/lie_algebras/virasoro.py +1186 -0
  60. sage/algebras/octonion_algebra.cpython-314-x86_64-linux-musl.so +0 -0
  61. sage/algebras/octonion_algebra.pxd +20 -0
  62. sage/algebras/octonion_algebra.pyx +987 -0
  63. sage/algebras/orlik_solomon.py +907 -0
  64. sage/algebras/orlik_terao.py +779 -0
  65. sage/algebras/steenrod/all.py +7 -0
  66. sage/algebras/steenrod/steenrod_algebra.py +4258 -0
  67. sage/algebras/steenrod/steenrod_algebra_bases.py +1179 -0
  68. sage/algebras/steenrod/steenrod_algebra_misc.py +1167 -0
  69. sage/algebras/steenrod/steenrod_algebra_mult.py +954 -0
  70. sage/algebras/weyl_algebra.py +1126 -0
  71. sage/all__sagemath_modules.py +62 -0
  72. sage/calculus/all__sagemath_modules.py +19 -0
  73. sage/calculus/expr.py +205 -0
  74. sage/calculus/integration.cpython-314-x86_64-linux-musl.so +0 -0
  75. sage/calculus/integration.pyx +698 -0
  76. sage/calculus/interpolation.cpython-314-x86_64-linux-musl.so +0 -0
  77. sage/calculus/interpolation.pxd +13 -0
  78. sage/calculus/interpolation.pyx +387 -0
  79. sage/calculus/interpolators.cpython-314-x86_64-linux-musl.so +0 -0
  80. sage/calculus/interpolators.pyx +326 -0
  81. sage/calculus/ode.cpython-314-x86_64-linux-musl.so +0 -0
  82. sage/calculus/ode.pxd +5 -0
  83. sage/calculus/ode.pyx +610 -0
  84. sage/calculus/riemann.cpython-314-x86_64-linux-musl.so +0 -0
  85. sage/calculus/riemann.pyx +1521 -0
  86. sage/calculus/test_sympy.py +201 -0
  87. sage/calculus/transforms/all.py +7 -0
  88. sage/calculus/transforms/dft.py +844 -0
  89. sage/calculus/transforms/dwt.cpython-314-x86_64-linux-musl.so +0 -0
  90. sage/calculus/transforms/dwt.pxd +7 -0
  91. sage/calculus/transforms/dwt.pyx +160 -0
  92. sage/calculus/transforms/fft.cpython-314-x86_64-linux-musl.so +0 -0
  93. sage/calculus/transforms/fft.pxd +12 -0
  94. sage/calculus/transforms/fft.pyx +487 -0
  95. sage/calculus/wester.py +662 -0
  96. sage/coding/abstract_code.py +1108 -0
  97. sage/coding/ag_code.py +868 -0
  98. sage/coding/ag_code_decoders.cpython-314-x86_64-linux-musl.so +0 -0
  99. sage/coding/ag_code_decoders.pyx +2639 -0
  100. sage/coding/all.py +15 -0
  101. sage/coding/bch_code.py +494 -0
  102. sage/coding/binary_code.cpython-314-x86_64-linux-musl.so +0 -0
  103. sage/coding/binary_code.pxd +124 -0
  104. sage/coding/binary_code.pyx +4139 -0
  105. sage/coding/bounds_catalog.py +43 -0
  106. sage/coding/channel.py +819 -0
  107. sage/coding/channels_catalog.py +29 -0
  108. sage/coding/code_bounds.py +755 -0
  109. sage/coding/code_constructions.py +804 -0
  110. sage/coding/codes_catalog.py +111 -0
  111. sage/coding/cyclic_code.py +1329 -0
  112. sage/coding/databases.py +316 -0
  113. sage/coding/decoder.py +373 -0
  114. sage/coding/decoders_catalog.py +88 -0
  115. sage/coding/delsarte_bounds.py +709 -0
  116. sage/coding/encoder.py +390 -0
  117. sage/coding/encoders_catalog.py +64 -0
  118. sage/coding/extended_code.py +468 -0
  119. sage/coding/gabidulin_code.py +1058 -0
  120. sage/coding/golay_code.py +404 -0
  121. sage/coding/goppa_code.py +441 -0
  122. sage/coding/grs_code.py +2371 -0
  123. sage/coding/guava.py +107 -0
  124. sage/coding/guruswami_sudan/all.py +1 -0
  125. sage/coding/guruswami_sudan/gs_decoder.py +897 -0
  126. sage/coding/guruswami_sudan/interpolation.py +409 -0
  127. sage/coding/guruswami_sudan/utils.py +176 -0
  128. sage/coding/hamming_code.py +176 -0
  129. sage/coding/information_set_decoder.py +1032 -0
  130. sage/coding/kasami_codes.cpython-314-x86_64-linux-musl.so +0 -0
  131. sage/coding/kasami_codes.pyx +351 -0
  132. sage/coding/linear_code.py +3067 -0
  133. sage/coding/linear_code_no_metric.py +1354 -0
  134. sage/coding/linear_rank_metric.py +961 -0
  135. sage/coding/parity_check_code.py +353 -0
  136. sage/coding/punctured_code.py +719 -0
  137. sage/coding/reed_muller_code.py +999 -0
  138. sage/coding/self_dual_codes.py +942 -0
  139. sage/coding/source_coding/all.py +2 -0
  140. sage/coding/source_coding/huffman.py +553 -0
  141. sage/coding/subfield_subcode.py +423 -0
  142. sage/coding/two_weight_db.py +399 -0
  143. sage/combinat/all__sagemath_modules.py +7 -0
  144. sage/combinat/cartesian_product.py +347 -0
  145. sage/combinat/family.py +11 -0
  146. sage/combinat/free_module.py +1977 -0
  147. sage/combinat/root_system/all.py +147 -0
  148. sage/combinat/root_system/ambient_space.py +527 -0
  149. sage/combinat/root_system/associahedron.py +471 -0
  150. sage/combinat/root_system/braid_move_calculator.py +143 -0
  151. sage/combinat/root_system/braid_orbit.cpython-314-x86_64-linux-musl.so +0 -0
  152. sage/combinat/root_system/braid_orbit.pyx +144 -0
  153. sage/combinat/root_system/branching_rules.py +2301 -0
  154. sage/combinat/root_system/cartan_matrix.py +1245 -0
  155. sage/combinat/root_system/cartan_type.py +3069 -0
  156. sage/combinat/root_system/coxeter_group.py +162 -0
  157. sage/combinat/root_system/coxeter_matrix.py +1261 -0
  158. sage/combinat/root_system/coxeter_type.py +681 -0
  159. sage/combinat/root_system/dynkin_diagram.py +900 -0
  160. sage/combinat/root_system/extended_affine_weyl_group.py +2993 -0
  161. sage/combinat/root_system/fundamental_group.py +795 -0
  162. sage/combinat/root_system/hecke_algebra_representation.py +1203 -0
  163. sage/combinat/root_system/integrable_representations.py +1227 -0
  164. sage/combinat/root_system/non_symmetric_macdonald_polynomials.py +1965 -0
  165. sage/combinat/root_system/pieri_factors.py +1147 -0
  166. sage/combinat/root_system/plot.py +1615 -0
  167. sage/combinat/root_system/root_lattice_realization_algebras.py +1214 -0
  168. sage/combinat/root_system/root_lattice_realizations.py +4628 -0
  169. sage/combinat/root_system/root_space.py +487 -0
  170. sage/combinat/root_system/root_system.py +882 -0
  171. sage/combinat/root_system/type_A.py +348 -0
  172. sage/combinat/root_system/type_A_affine.py +227 -0
  173. sage/combinat/root_system/type_A_infinity.py +241 -0
  174. sage/combinat/root_system/type_B.py +347 -0
  175. sage/combinat/root_system/type_BC_affine.py +287 -0
  176. sage/combinat/root_system/type_B_affine.py +216 -0
  177. sage/combinat/root_system/type_C.py +317 -0
  178. sage/combinat/root_system/type_C_affine.py +188 -0
  179. sage/combinat/root_system/type_D.py +357 -0
  180. sage/combinat/root_system/type_D_affine.py +208 -0
  181. sage/combinat/root_system/type_E.py +641 -0
  182. sage/combinat/root_system/type_E_affine.py +231 -0
  183. sage/combinat/root_system/type_F.py +387 -0
  184. sage/combinat/root_system/type_F_affine.py +137 -0
  185. sage/combinat/root_system/type_G.py +293 -0
  186. sage/combinat/root_system/type_G_affine.py +132 -0
  187. sage/combinat/root_system/type_H.py +105 -0
  188. sage/combinat/root_system/type_I.py +110 -0
  189. sage/combinat/root_system/type_Q.py +150 -0
  190. sage/combinat/root_system/type_affine.py +509 -0
  191. sage/combinat/root_system/type_dual.py +704 -0
  192. sage/combinat/root_system/type_folded.py +301 -0
  193. sage/combinat/root_system/type_marked.py +748 -0
  194. sage/combinat/root_system/type_reducible.py +601 -0
  195. sage/combinat/root_system/type_relabel.py +730 -0
  196. sage/combinat/root_system/type_super_A.py +837 -0
  197. sage/combinat/root_system/weight_lattice_realizations.py +1188 -0
  198. sage/combinat/root_system/weight_space.py +639 -0
  199. sage/combinat/root_system/weyl_characters.py +2238 -0
  200. sage/crypto/__init__.py +4 -0
  201. sage/crypto/all.py +28 -0
  202. sage/crypto/block_cipher/all.py +7 -0
  203. sage/crypto/block_cipher/des.py +1065 -0
  204. sage/crypto/block_cipher/miniaes.py +2171 -0
  205. sage/crypto/block_cipher/present.py +909 -0
  206. sage/crypto/block_cipher/sdes.py +1527 -0
  207. sage/crypto/boolean_function.cpython-314-x86_64-linux-musl.so +0 -0
  208. sage/crypto/boolean_function.pxd +10 -0
  209. sage/crypto/boolean_function.pyx +1487 -0
  210. sage/crypto/cipher.py +78 -0
  211. sage/crypto/classical.py +3668 -0
  212. sage/crypto/classical_cipher.py +569 -0
  213. sage/crypto/cryptosystem.py +387 -0
  214. sage/crypto/key_exchange/all.py +7 -0
  215. sage/crypto/key_exchange/catalog.py +24 -0
  216. sage/crypto/key_exchange/diffie_hellman.py +323 -0
  217. sage/crypto/key_exchange/key_exchange_scheme.py +107 -0
  218. sage/crypto/lattice.py +312 -0
  219. sage/crypto/lfsr.py +295 -0
  220. sage/crypto/lwe.py +840 -0
  221. sage/crypto/mq/__init__.py +4 -0
  222. sage/crypto/mq/mpolynomialsystemgenerator.py +204 -0
  223. sage/crypto/mq/rijndael_gf.py +2345 -0
  224. sage/crypto/mq/sbox.py +7 -0
  225. sage/crypto/mq/sr.py +3344 -0
  226. sage/crypto/public_key/all.py +5 -0
  227. sage/crypto/public_key/blum_goldwasser.py +776 -0
  228. sage/crypto/sbox.cpython-314-x86_64-linux-musl.so +0 -0
  229. sage/crypto/sbox.pyx +2090 -0
  230. sage/crypto/sboxes.py +2090 -0
  231. sage/crypto/stream.py +390 -0
  232. sage/crypto/stream_cipher.py +297 -0
  233. sage/crypto/util.py +519 -0
  234. sage/ext/all__sagemath_modules.py +1 -0
  235. sage/ext/interpreters/__init__.py +1 -0
  236. sage/ext/interpreters/all__sagemath_modules.py +2 -0
  237. sage/ext/interpreters/wrapper_cc.cpython-314-x86_64-linux-musl.so +0 -0
  238. sage/ext/interpreters/wrapper_cc.pxd +30 -0
  239. sage/ext/interpreters/wrapper_cc.pyx +252 -0
  240. sage/ext/interpreters/wrapper_cdf.cpython-314-x86_64-linux-musl.so +0 -0
  241. sage/ext/interpreters/wrapper_cdf.pxd +26 -0
  242. sage/ext/interpreters/wrapper_cdf.pyx +245 -0
  243. sage/ext/interpreters/wrapper_rdf.cpython-314-x86_64-linux-musl.so +0 -0
  244. sage/ext/interpreters/wrapper_rdf.pxd +23 -0
  245. sage/ext/interpreters/wrapper_rdf.pyx +221 -0
  246. sage/ext/interpreters/wrapper_rr.cpython-314-x86_64-linux-musl.so +0 -0
  247. sage/ext/interpreters/wrapper_rr.pxd +28 -0
  248. sage/ext/interpreters/wrapper_rr.pyx +335 -0
  249. sage/geometry/all__sagemath_modules.py +5 -0
  250. sage/geometry/toric_lattice.py +1745 -0
  251. sage/geometry/toric_lattice_element.cpython-314-x86_64-linux-musl.so +0 -0
  252. sage/geometry/toric_lattice_element.pyx +432 -0
  253. sage/groups/abelian_gps/abelian_group.py +1925 -0
  254. sage/groups/abelian_gps/abelian_group_element.py +164 -0
  255. sage/groups/abelian_gps/all__sagemath_modules.py +5 -0
  256. sage/groups/abelian_gps/dual_abelian_group.py +421 -0
  257. sage/groups/abelian_gps/dual_abelian_group_element.py +179 -0
  258. sage/groups/abelian_gps/element_base.py +341 -0
  259. sage/groups/abelian_gps/values.py +488 -0
  260. sage/groups/additive_abelian/additive_abelian_group.py +476 -0
  261. sage/groups/additive_abelian/additive_abelian_wrapper.py +857 -0
  262. sage/groups/additive_abelian/all.py +4 -0
  263. sage/groups/additive_abelian/qmodnz.py +231 -0
  264. sage/groups/additive_abelian/qmodnz_element.py +349 -0
  265. sage/groups/affine_gps/affine_group.py +535 -0
  266. sage/groups/affine_gps/all.py +1 -0
  267. sage/groups/affine_gps/catalog.py +17 -0
  268. sage/groups/affine_gps/euclidean_group.py +246 -0
  269. sage/groups/affine_gps/group_element.py +562 -0
  270. sage/groups/all__sagemath_modules.py +12 -0
  271. sage/groups/galois_group.py +479 -0
  272. sage/groups/matrix_gps/all.py +4 -0
  273. sage/groups/matrix_gps/all__sagemath_modules.py +13 -0
  274. sage/groups/matrix_gps/catalog.py +26 -0
  275. sage/groups/matrix_gps/coxeter_group.py +927 -0
  276. sage/groups/matrix_gps/finitely_generated.py +487 -0
  277. sage/groups/matrix_gps/group_element.cpython-314-x86_64-linux-musl.so +0 -0
  278. sage/groups/matrix_gps/group_element.pxd +11 -0
  279. sage/groups/matrix_gps/group_element.pyx +431 -0
  280. sage/groups/matrix_gps/linear.py +440 -0
  281. sage/groups/matrix_gps/matrix_group.py +617 -0
  282. sage/groups/matrix_gps/named_group.py +296 -0
  283. sage/groups/matrix_gps/orthogonal.py +544 -0
  284. sage/groups/matrix_gps/symplectic.py +251 -0
  285. sage/groups/matrix_gps/unitary.py +436 -0
  286. sage/groups/misc_gps/all__sagemath_modules.py +1 -0
  287. sage/groups/misc_gps/argument_groups.py +1905 -0
  288. sage/groups/misc_gps/imaginary_groups.py +479 -0
  289. sage/groups/perm_gps/all__sagemath_modules.py +1 -0
  290. sage/groups/perm_gps/partn_ref/all__sagemath_modules.py +1 -0
  291. sage/groups/perm_gps/partn_ref/refinement_binary.cpython-314-x86_64-linux-musl.so +0 -0
  292. sage/groups/perm_gps/partn_ref/refinement_binary.pxd +41 -0
  293. sage/groups/perm_gps/partn_ref/refinement_binary.pyx +1167 -0
  294. sage/groups/perm_gps/partn_ref/refinement_matrices.cpython-314-x86_64-linux-musl.so +0 -0
  295. sage/groups/perm_gps/partn_ref/refinement_matrices.pxd +31 -0
  296. sage/groups/perm_gps/partn_ref/refinement_matrices.pyx +385 -0
  297. sage/homology/algebraic_topological_model.py +595 -0
  298. sage/homology/all.py +2 -0
  299. sage/homology/all__sagemath_modules.py +8 -0
  300. sage/homology/chain_complex.py +2148 -0
  301. sage/homology/chain_complex_homspace.py +165 -0
  302. sage/homology/chain_complex_morphism.py +629 -0
  303. sage/homology/chain_homotopy.py +604 -0
  304. sage/homology/chains.py +653 -0
  305. sage/homology/free_resolution.py +923 -0
  306. sage/homology/graded_resolution.py +567 -0
  307. sage/homology/hochschild_complex.py +756 -0
  308. sage/homology/homology_group.py +188 -0
  309. sage/homology/homology_morphism.py +422 -0
  310. sage/homology/homology_vector_space_with_basis.py +1454 -0
  311. sage/homology/koszul_complex.py +169 -0
  312. sage/homology/matrix_utils.py +205 -0
  313. sage/libs/all__sagemath_modules.py +1 -0
  314. sage/libs/gsl/__init__.py +1 -0
  315. sage/libs/gsl/airy.pxd +56 -0
  316. sage/libs/gsl/all.pxd +66 -0
  317. sage/libs/gsl/array.cpython-314-x86_64-linux-musl.so +0 -0
  318. sage/libs/gsl/array.pxd +5 -0
  319. sage/libs/gsl/array.pyx +102 -0
  320. sage/libs/gsl/bessel.pxd +208 -0
  321. sage/libs/gsl/blas.pxd +116 -0
  322. sage/libs/gsl/blas_types.pxd +34 -0
  323. sage/libs/gsl/block.pxd +52 -0
  324. sage/libs/gsl/chebyshev.pxd +37 -0
  325. sage/libs/gsl/clausen.pxd +12 -0
  326. sage/libs/gsl/combination.pxd +47 -0
  327. sage/libs/gsl/complex.pxd +151 -0
  328. sage/libs/gsl/coulomb.pxd +30 -0
  329. sage/libs/gsl/coupling.pxd +21 -0
  330. sage/libs/gsl/dawson.pxd +12 -0
  331. sage/libs/gsl/debye.pxd +24 -0
  332. sage/libs/gsl/dilog.pxd +14 -0
  333. sage/libs/gsl/eigen.pxd +46 -0
  334. sage/libs/gsl/elementary.pxd +12 -0
  335. sage/libs/gsl/ellint.pxd +48 -0
  336. sage/libs/gsl/elljac.pxd +8 -0
  337. sage/libs/gsl/erf.pxd +32 -0
  338. sage/libs/gsl/errno.pxd +26 -0
  339. sage/libs/gsl/exp.pxd +44 -0
  340. sage/libs/gsl/expint.pxd +44 -0
  341. sage/libs/gsl/fermi_dirac.pxd +44 -0
  342. sage/libs/gsl/fft.pxd +121 -0
  343. sage/libs/gsl/fit.pxd +50 -0
  344. sage/libs/gsl/gamma.pxd +94 -0
  345. sage/libs/gsl/gegenbauer.pxd +26 -0
  346. sage/libs/gsl/histogram.pxd +176 -0
  347. sage/libs/gsl/hyperg.pxd +52 -0
  348. sage/libs/gsl/integration.pxd +69 -0
  349. sage/libs/gsl/interp.pxd +109 -0
  350. sage/libs/gsl/laguerre.pxd +24 -0
  351. sage/libs/gsl/lambert.pxd +16 -0
  352. sage/libs/gsl/legendre.pxd +90 -0
  353. sage/libs/gsl/linalg.pxd +185 -0
  354. sage/libs/gsl/log.pxd +26 -0
  355. sage/libs/gsl/math.pxd +43 -0
  356. sage/libs/gsl/matrix.pxd +143 -0
  357. sage/libs/gsl/matrix_complex.pxd +130 -0
  358. sage/libs/gsl/min.pxd +67 -0
  359. sage/libs/gsl/monte.pxd +56 -0
  360. sage/libs/gsl/ntuple.pxd +32 -0
  361. sage/libs/gsl/odeiv.pxd +70 -0
  362. sage/libs/gsl/permutation.pxd +78 -0
  363. sage/libs/gsl/poly.pxd +40 -0
  364. sage/libs/gsl/pow_int.pxd +12 -0
  365. sage/libs/gsl/psi.pxd +28 -0
  366. sage/libs/gsl/qrng.pxd +29 -0
  367. sage/libs/gsl/random.pxd +257 -0
  368. sage/libs/gsl/rng.pxd +100 -0
  369. sage/libs/gsl/roots.pxd +72 -0
  370. sage/libs/gsl/sort.pxd +36 -0
  371. sage/libs/gsl/statistics.pxd +59 -0
  372. sage/libs/gsl/sum.pxd +55 -0
  373. sage/libs/gsl/synchrotron.pxd +16 -0
  374. sage/libs/gsl/transport.pxd +24 -0
  375. sage/libs/gsl/trig.pxd +58 -0
  376. sage/libs/gsl/types.pxd +137 -0
  377. sage/libs/gsl/vector.pxd +101 -0
  378. sage/libs/gsl/vector_complex.pxd +83 -0
  379. sage/libs/gsl/wavelet.pxd +49 -0
  380. sage/libs/gsl/zeta.pxd +28 -0
  381. sage/libs/mpc/__init__.pxd +114 -0
  382. sage/libs/mpc/types.pxd +28 -0
  383. sage/libs/mpfr/__init__.pxd +299 -0
  384. sage/libs/mpfr/types.pxd +26 -0
  385. sage/libs/mpmath/__init__.py +1 -0
  386. sage/libs/mpmath/all.py +27 -0
  387. sage/libs/mpmath/all__sagemath_modules.py +1 -0
  388. sage/libs/mpmath/utils.cpython-314-x86_64-linux-musl.so +0 -0
  389. sage/libs/mpmath/utils.pxd +4 -0
  390. sage/libs/mpmath/utils.pyx +319 -0
  391. sage/matrix/action.cpython-314-x86_64-linux-musl.so +0 -0
  392. sage/matrix/action.pxd +26 -0
  393. sage/matrix/action.pyx +596 -0
  394. sage/matrix/all.py +9 -0
  395. sage/matrix/args.cpython-314-x86_64-linux-musl.so +0 -0
  396. sage/matrix/args.pxd +144 -0
  397. sage/matrix/args.pyx +1668 -0
  398. sage/matrix/benchmark.py +1258 -0
  399. sage/matrix/berlekamp_massey.py +95 -0
  400. sage/matrix/compute_J_ideal.py +926 -0
  401. sage/matrix/constructor.cpython-314-x86_64-linux-musl.so +0 -0
  402. sage/matrix/constructor.pyx +750 -0
  403. sage/matrix/docs.py +430 -0
  404. sage/matrix/echelon_matrix.cpython-314-x86_64-linux-musl.so +0 -0
  405. sage/matrix/echelon_matrix.pyx +155 -0
  406. sage/matrix/matrix.pxd +2 -0
  407. sage/matrix/matrix0.cpython-314-x86_64-linux-musl.so +0 -0
  408. sage/matrix/matrix0.pxd +68 -0
  409. sage/matrix/matrix0.pyx +6324 -0
  410. sage/matrix/matrix1.cpython-314-x86_64-linux-musl.so +0 -0
  411. sage/matrix/matrix1.pxd +8 -0
  412. sage/matrix/matrix1.pyx +2851 -0
  413. sage/matrix/matrix2.cpython-314-x86_64-linux-musl.so +0 -0
  414. sage/matrix/matrix2.pxd +25 -0
  415. sage/matrix/matrix2.pyx +20181 -0
  416. sage/matrix/matrix_cdv.cpython-314-x86_64-linux-musl.so +0 -0
  417. sage/matrix/matrix_cdv.pxd +4 -0
  418. sage/matrix/matrix_cdv.pyx +93 -0
  419. sage/matrix/matrix_complex_double_dense.cpython-314-x86_64-linux-musl.so +0 -0
  420. sage/matrix/matrix_complex_double_dense.pxd +5 -0
  421. sage/matrix/matrix_complex_double_dense.pyx +98 -0
  422. sage/matrix/matrix_dense.cpython-314-x86_64-linux-musl.so +0 -0
  423. sage/matrix/matrix_dense.pxd +5 -0
  424. sage/matrix/matrix_dense.pyx +343 -0
  425. sage/matrix/matrix_domain_dense.pxd +5 -0
  426. sage/matrix/matrix_domain_sparse.pxd +5 -0
  427. sage/matrix/matrix_double_dense.cpython-314-x86_64-linux-musl.so +0 -0
  428. sage/matrix/matrix_double_dense.pxd +7 -0
  429. sage/matrix/matrix_double_dense.pyx +3906 -0
  430. sage/matrix/matrix_double_sparse.cpython-314-x86_64-linux-musl.so +0 -0
  431. sage/matrix/matrix_double_sparse.pxd +6 -0
  432. sage/matrix/matrix_double_sparse.pyx +248 -0
  433. sage/matrix/matrix_generic_dense.cpython-314-x86_64-linux-musl.so +0 -0
  434. sage/matrix/matrix_generic_dense.pxd +7 -0
  435. sage/matrix/matrix_generic_dense.pyx +354 -0
  436. sage/matrix/matrix_generic_sparse.cpython-314-x86_64-linux-musl.so +0 -0
  437. sage/matrix/matrix_generic_sparse.pxd +7 -0
  438. sage/matrix/matrix_generic_sparse.pyx +461 -0
  439. sage/matrix/matrix_laurent_mpolynomial_dense.cpython-314-x86_64-linux-musl.so +0 -0
  440. sage/matrix/matrix_laurent_mpolynomial_dense.pxd +5 -0
  441. sage/matrix/matrix_laurent_mpolynomial_dense.pyx +115 -0
  442. sage/matrix/matrix_misc.py +313 -0
  443. sage/matrix/matrix_numpy_dense.cpython-314-x86_64-linux-musl.so +0 -0
  444. sage/matrix/matrix_numpy_dense.pxd +14 -0
  445. sage/matrix/matrix_numpy_dense.pyx +450 -0
  446. sage/matrix/matrix_numpy_integer_dense.cpython-314-x86_64-linux-musl.so +0 -0
  447. sage/matrix/matrix_numpy_integer_dense.pxd +7 -0
  448. sage/matrix/matrix_numpy_integer_dense.pyx +59 -0
  449. sage/matrix/matrix_polynomial_dense.cpython-314-x86_64-linux-musl.so +0 -0
  450. sage/matrix/matrix_polynomial_dense.pxd +5 -0
  451. sage/matrix/matrix_polynomial_dense.pyx +5341 -0
  452. sage/matrix/matrix_real_double_dense.cpython-314-x86_64-linux-musl.so +0 -0
  453. sage/matrix/matrix_real_double_dense.pxd +7 -0
  454. sage/matrix/matrix_real_double_dense.pyx +122 -0
  455. sage/matrix/matrix_space.py +2848 -0
  456. sage/matrix/matrix_sparse.cpython-314-x86_64-linux-musl.so +0 -0
  457. sage/matrix/matrix_sparse.pxd +5 -0
  458. sage/matrix/matrix_sparse.pyx +1222 -0
  459. sage/matrix/matrix_window.cpython-314-x86_64-linux-musl.so +0 -0
  460. sage/matrix/matrix_window.pxd +37 -0
  461. sage/matrix/matrix_window.pyx +242 -0
  462. sage/matrix/misc_mpfr.cpython-314-x86_64-linux-musl.so +0 -0
  463. sage/matrix/misc_mpfr.pyx +80 -0
  464. sage/matrix/operation_table.py +1182 -0
  465. sage/matrix/special.py +3666 -0
  466. sage/matrix/strassen.cpython-314-x86_64-linux-musl.so +0 -0
  467. sage/matrix/strassen.pyx +851 -0
  468. sage/matrix/symplectic_basis.py +541 -0
  469. sage/matrix/template.pxd +6 -0
  470. sage/matrix/tests.py +71 -0
  471. sage/matroids/advanced.py +77 -0
  472. sage/matroids/all.py +13 -0
  473. sage/matroids/basis_exchange_matroid.cpython-314-x86_64-linux-musl.so +0 -0
  474. sage/matroids/basis_exchange_matroid.pxd +96 -0
  475. sage/matroids/basis_exchange_matroid.pyx +2344 -0
  476. sage/matroids/basis_matroid.cpython-314-x86_64-linux-musl.so +0 -0
  477. sage/matroids/basis_matroid.pxd +45 -0
  478. sage/matroids/basis_matroid.pyx +1217 -0
  479. sage/matroids/catalog.py +44 -0
  480. sage/matroids/chow_ring.py +473 -0
  481. sage/matroids/chow_ring_ideal.py +849 -0
  482. sage/matroids/circuit_closures_matroid.cpython-314-x86_64-linux-musl.so +0 -0
  483. sage/matroids/circuit_closures_matroid.pxd +16 -0
  484. sage/matroids/circuit_closures_matroid.pyx +559 -0
  485. sage/matroids/circuits_matroid.cpython-314-x86_64-linux-musl.so +0 -0
  486. sage/matroids/circuits_matroid.pxd +38 -0
  487. sage/matroids/circuits_matroid.pyx +947 -0
  488. sage/matroids/constructor.py +1086 -0
  489. sage/matroids/database_collections.py +365 -0
  490. sage/matroids/database_matroids.py +5338 -0
  491. sage/matroids/dual_matroid.py +583 -0
  492. sage/matroids/extension.cpython-314-x86_64-linux-musl.so +0 -0
  493. sage/matroids/extension.pxd +34 -0
  494. sage/matroids/extension.pyx +519 -0
  495. sage/matroids/flats_matroid.cpython-314-x86_64-linux-musl.so +0 -0
  496. sage/matroids/flats_matroid.pxd +28 -0
  497. sage/matroids/flats_matroid.pyx +715 -0
  498. sage/matroids/gammoid.py +600 -0
  499. sage/matroids/graphic_matroid.cpython-314-x86_64-linux-musl.so +0 -0
  500. sage/matroids/graphic_matroid.pxd +39 -0
  501. sage/matroids/graphic_matroid.pyx +2024 -0
  502. sage/matroids/lean_matrix.cpython-314-x86_64-linux-musl.so +0 -0
  503. sage/matroids/lean_matrix.pxd +126 -0
  504. sage/matroids/lean_matrix.pyx +3667 -0
  505. sage/matroids/linear_matroid.cpython-314-x86_64-linux-musl.so +0 -0
  506. sage/matroids/linear_matroid.pxd +180 -0
  507. sage/matroids/linear_matroid.pyx +6649 -0
  508. sage/matroids/matroid.cpython-314-x86_64-linux-musl.so +0 -0
  509. sage/matroids/matroid.pxd +243 -0
  510. sage/matroids/matroid.pyx +8759 -0
  511. sage/matroids/matroids_catalog.py +190 -0
  512. sage/matroids/matroids_plot_helpers.py +890 -0
  513. sage/matroids/minor_matroid.py +480 -0
  514. sage/matroids/minorfix.h +9 -0
  515. sage/matroids/named_matroids.py +5 -0
  516. sage/matroids/rank_matroid.py +268 -0
  517. sage/matroids/set_system.cpython-314-x86_64-linux-musl.so +0 -0
  518. sage/matroids/set_system.pxd +38 -0
  519. sage/matroids/set_system.pyx +800 -0
  520. sage/matroids/transversal_matroid.cpython-314-x86_64-linux-musl.so +0 -0
  521. sage/matroids/transversal_matroid.pxd +14 -0
  522. sage/matroids/transversal_matroid.pyx +893 -0
  523. sage/matroids/union_matroid.cpython-314-x86_64-linux-musl.so +0 -0
  524. sage/matroids/union_matroid.pxd +20 -0
  525. sage/matroids/union_matroid.pyx +331 -0
  526. sage/matroids/unpickling.cpython-314-x86_64-linux-musl.so +0 -0
  527. sage/matroids/unpickling.pyx +843 -0
  528. sage/matroids/utilities.py +809 -0
  529. sage/misc/all__sagemath_modules.py +20 -0
  530. sage/misc/c3.cpython-314-x86_64-linux-musl.so +0 -0
  531. sage/misc/c3.pyx +238 -0
  532. sage/misc/compat.py +87 -0
  533. sage/misc/element_with_label.py +173 -0
  534. sage/misc/func_persist.py +79 -0
  535. sage/misc/pickle_old.cpython-314-x86_64-linux-musl.so +0 -0
  536. sage/misc/pickle_old.pyx +19 -0
  537. sage/misc/proof.py +7 -0
  538. sage/misc/replace_dot_all.py +472 -0
  539. sage/misc/sagedoc_conf.py +168 -0
  540. sage/misc/sphinxify.py +167 -0
  541. sage/misc/test_class_pickling.py +85 -0
  542. sage/modules/all.py +42 -0
  543. sage/modules/complex_double_vector.py +25 -0
  544. sage/modules/diamond_cutting.py +380 -0
  545. sage/modules/fg_pid/all.py +1 -0
  546. sage/modules/fg_pid/fgp_element.py +456 -0
  547. sage/modules/fg_pid/fgp_module.py +2091 -0
  548. sage/modules/fg_pid/fgp_morphism.py +550 -0
  549. sage/modules/filtered_vector_space.py +1271 -0
  550. sage/modules/finite_submodule_iter.cpython-314-x86_64-linux-musl.so +0 -0
  551. sage/modules/finite_submodule_iter.pxd +27 -0
  552. sage/modules/finite_submodule_iter.pyx +452 -0
  553. sage/modules/fp_graded/all.py +1 -0
  554. sage/modules/fp_graded/element.py +346 -0
  555. sage/modules/fp_graded/free_element.py +298 -0
  556. sage/modules/fp_graded/free_homspace.py +53 -0
  557. sage/modules/fp_graded/free_module.py +1060 -0
  558. sage/modules/fp_graded/free_morphism.py +217 -0
  559. sage/modules/fp_graded/homspace.py +563 -0
  560. sage/modules/fp_graded/module.py +1340 -0
  561. sage/modules/fp_graded/morphism.py +1990 -0
  562. sage/modules/fp_graded/steenrod/all.py +1 -0
  563. sage/modules/fp_graded/steenrod/homspace.py +65 -0
  564. sage/modules/fp_graded/steenrod/module.py +477 -0
  565. sage/modules/fp_graded/steenrod/morphism.py +404 -0
  566. sage/modules/fp_graded/steenrod/profile.py +241 -0
  567. sage/modules/free_module.py +8447 -0
  568. sage/modules/free_module_element.cpython-314-x86_64-linux-musl.so +0 -0
  569. sage/modules/free_module_element.pxd +22 -0
  570. sage/modules/free_module_element.pyx +5445 -0
  571. sage/modules/free_module_homspace.py +369 -0
  572. sage/modules/free_module_integer.py +896 -0
  573. sage/modules/free_module_morphism.py +823 -0
  574. sage/modules/free_module_pseudohomspace.py +352 -0
  575. sage/modules/free_module_pseudomorphism.py +578 -0
  576. sage/modules/free_quadratic_module.py +1706 -0
  577. sage/modules/free_quadratic_module_integer_symmetric.py +1790 -0
  578. sage/modules/matrix_morphism.py +1745 -0
  579. sage/modules/misc.py +103 -0
  580. sage/modules/module_functors.py +192 -0
  581. sage/modules/multi_filtered_vector_space.py +719 -0
  582. sage/modules/ore_module.py +2208 -0
  583. sage/modules/ore_module_element.py +178 -0
  584. sage/modules/ore_module_homspace.py +147 -0
  585. sage/modules/ore_module_morphism.py +968 -0
  586. sage/modules/quotient_module.py +699 -0
  587. sage/modules/real_double_vector.py +22 -0
  588. sage/modules/submodule.py +255 -0
  589. sage/modules/tensor_operations.py +567 -0
  590. sage/modules/torsion_quadratic_module.py +1352 -0
  591. sage/modules/tutorial_free_modules.py +248 -0
  592. sage/modules/vector_complex_double_dense.cpython-314-x86_64-linux-musl.so +0 -0
  593. sage/modules/vector_complex_double_dense.pxd +6 -0
  594. sage/modules/vector_complex_double_dense.pyx +117 -0
  595. sage/modules/vector_double_dense.cpython-314-x86_64-linux-musl.so +0 -0
  596. sage/modules/vector_double_dense.pxd +6 -0
  597. sage/modules/vector_double_dense.pyx +604 -0
  598. sage/modules/vector_integer_dense.cpython-314-x86_64-linux-musl.so +0 -0
  599. sage/modules/vector_integer_dense.pxd +15 -0
  600. sage/modules/vector_integer_dense.pyx +361 -0
  601. sage/modules/vector_integer_sparse.cpython-314-x86_64-linux-musl.so +0 -0
  602. sage/modules/vector_integer_sparse.pxd +29 -0
  603. sage/modules/vector_integer_sparse.pyx +406 -0
  604. sage/modules/vector_modn_dense.cpython-314-x86_64-linux-musl.so +0 -0
  605. sage/modules/vector_modn_dense.pxd +12 -0
  606. sage/modules/vector_modn_dense.pyx +394 -0
  607. sage/modules/vector_modn_sparse.cpython-314-x86_64-linux-musl.so +0 -0
  608. sage/modules/vector_modn_sparse.pxd +21 -0
  609. sage/modules/vector_modn_sparse.pyx +298 -0
  610. sage/modules/vector_numpy_dense.cpython-314-x86_64-linux-musl.so +0 -0
  611. sage/modules/vector_numpy_dense.pxd +15 -0
  612. sage/modules/vector_numpy_dense.pyx +304 -0
  613. sage/modules/vector_numpy_integer_dense.cpython-314-x86_64-linux-musl.so +0 -0
  614. sage/modules/vector_numpy_integer_dense.pxd +7 -0
  615. sage/modules/vector_numpy_integer_dense.pyx +54 -0
  616. sage/modules/vector_rational_dense.cpython-314-x86_64-linux-musl.so +0 -0
  617. sage/modules/vector_rational_dense.pxd +15 -0
  618. sage/modules/vector_rational_dense.pyx +387 -0
  619. sage/modules/vector_rational_sparse.cpython-314-x86_64-linux-musl.so +0 -0
  620. sage/modules/vector_rational_sparse.pxd +30 -0
  621. sage/modules/vector_rational_sparse.pyx +413 -0
  622. sage/modules/vector_real_double_dense.cpython-314-x86_64-linux-musl.so +0 -0
  623. sage/modules/vector_real_double_dense.pxd +6 -0
  624. sage/modules/vector_real_double_dense.pyx +126 -0
  625. sage/modules/vector_space_homspace.py +430 -0
  626. sage/modules/vector_space_morphism.py +989 -0
  627. sage/modules/with_basis/all.py +15 -0
  628. sage/modules/with_basis/cell_module.py +494 -0
  629. sage/modules/with_basis/indexed_element.cpython-314-x86_64-linux-musl.so +0 -0
  630. sage/modules/with_basis/indexed_element.pxd +13 -0
  631. sage/modules/with_basis/indexed_element.pyx +1058 -0
  632. sage/modules/with_basis/invariant.py +1075 -0
  633. sage/modules/with_basis/morphism.py +1636 -0
  634. sage/modules/with_basis/representation.py +2939 -0
  635. sage/modules/with_basis/subquotient.py +685 -0
  636. sage/numerical/all__sagemath_modules.py +6 -0
  637. sage/numerical/gauss_legendre.cpython-314-x86_64-linux-musl.so +0 -0
  638. sage/numerical/gauss_legendre.pyx +381 -0
  639. sage/numerical/optimize.py +910 -0
  640. sage/probability/all.py +10 -0
  641. sage/probability/probability_distribution.cpython-314-x86_64-linux-musl.so +0 -0
  642. sage/probability/probability_distribution.pyx +1242 -0
  643. sage/probability/random_variable.py +411 -0
  644. sage/quadratic_forms/all.py +4 -0
  645. sage/quadratic_forms/all__sagemath_modules.py +15 -0
  646. sage/quadratic_forms/binary_qf.py +2042 -0
  647. sage/quadratic_forms/bqf_class_group.py +748 -0
  648. sage/quadratic_forms/constructions.py +93 -0
  649. sage/quadratic_forms/count_local_2.cpython-314-x86_64-linux-musl.so +0 -0
  650. sage/quadratic_forms/count_local_2.pyx +365 -0
  651. sage/quadratic_forms/extras.py +195 -0
  652. sage/quadratic_forms/quadratic_form.py +1753 -0
  653. sage/quadratic_forms/quadratic_form__count_local_2.py +221 -0
  654. sage/quadratic_forms/quadratic_form__equivalence_testing.py +708 -0
  655. sage/quadratic_forms/quadratic_form__evaluate.cpython-314-x86_64-linux-musl.so +0 -0
  656. sage/quadratic_forms/quadratic_form__evaluate.pyx +139 -0
  657. sage/quadratic_forms/quadratic_form__local_density_congruence.py +977 -0
  658. sage/quadratic_forms/quadratic_form__local_field_invariants.py +1072 -0
  659. sage/quadratic_forms/quadratic_form__neighbors.py +424 -0
  660. sage/quadratic_forms/quadratic_form__reduction_theory.py +488 -0
  661. sage/quadratic_forms/quadratic_form__split_local_covering.py +416 -0
  662. sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +657 -0
  663. sage/quadratic_forms/quadratic_form__theta.py +352 -0
  664. sage/quadratic_forms/quadratic_form__variable_substitutions.py +370 -0
  665. sage/quadratic_forms/random_quadraticform.py +209 -0
  666. sage/quadratic_forms/ternary.cpython-314-x86_64-linux-musl.so +0 -0
  667. sage/quadratic_forms/ternary.pyx +1154 -0
  668. sage/quadratic_forms/ternary_qf.py +2027 -0
  669. sage/rings/all__sagemath_modules.py +28 -0
  670. sage/rings/asymptotic/all__sagemath_modules.py +1 -0
  671. sage/rings/asymptotic/misc.py +1252 -0
  672. sage/rings/cc.py +4 -0
  673. sage/rings/cfinite_sequence.py +1306 -0
  674. sage/rings/complex_conversion.cpython-314-x86_64-linux-musl.so +0 -0
  675. sage/rings/complex_conversion.pxd +8 -0
  676. sage/rings/complex_conversion.pyx +23 -0
  677. sage/rings/complex_double.cpython-314-x86_64-linux-musl.so +0 -0
  678. sage/rings/complex_double.pxd +21 -0
  679. sage/rings/complex_double.pyx +2654 -0
  680. sage/rings/complex_mpc.cpython-314-x86_64-linux-musl.so +0 -0
  681. sage/rings/complex_mpc.pxd +21 -0
  682. sage/rings/complex_mpc.pyx +2576 -0
  683. sage/rings/complex_mpfr.cpython-314-x86_64-linux-musl.so +0 -0
  684. sage/rings/complex_mpfr.pxd +18 -0
  685. sage/rings/complex_mpfr.pyx +3602 -0
  686. sage/rings/derivation.py +2334 -0
  687. sage/rings/finite_rings/all__sagemath_modules.py +1 -0
  688. sage/rings/finite_rings/maps_finite_field.py +191 -0
  689. sage/rings/function_field/all__sagemath_modules.py +8 -0
  690. sage/rings/function_field/derivations.py +102 -0
  691. sage/rings/function_field/derivations_rational.py +132 -0
  692. sage/rings/function_field/differential.py +853 -0
  693. sage/rings/function_field/divisor.py +1107 -0
  694. sage/rings/function_field/drinfeld_modules/action.py +199 -0
  695. sage/rings/function_field/drinfeld_modules/all.py +1 -0
  696. sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py +673 -0
  697. sage/rings/function_field/drinfeld_modules/drinfeld_module.py +2087 -0
  698. sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py +1131 -0
  699. sage/rings/function_field/drinfeld_modules/homset.py +420 -0
  700. sage/rings/function_field/drinfeld_modules/morphism.py +820 -0
  701. sage/rings/function_field/hermite_form_polynomial.cpython-314-x86_64-linux-musl.so +0 -0
  702. sage/rings/function_field/hermite_form_polynomial.pyx +188 -0
  703. sage/rings/function_field/khuri_makdisi.cpython-314-x86_64-linux-musl.so +0 -0
  704. sage/rings/function_field/khuri_makdisi.pyx +935 -0
  705. sage/rings/invariants/all.py +4 -0
  706. sage/rings/invariants/invariant_theory.py +4597 -0
  707. sage/rings/invariants/reconstruction.py +395 -0
  708. sage/rings/polynomial/all__sagemath_modules.py +17 -0
  709. sage/rings/polynomial/integer_valued_polynomials.py +1230 -0
  710. sage/rings/polynomial/laurent_polynomial_mpair.cpython-314-x86_64-linux-musl.so +0 -0
  711. sage/rings/polynomial/laurent_polynomial_mpair.pxd +15 -0
  712. sage/rings/polynomial/laurent_polynomial_mpair.pyx +2023 -0
  713. sage/rings/polynomial/ore_function_element.py +952 -0
  714. sage/rings/polynomial/ore_function_field.py +1028 -0
  715. sage/rings/polynomial/ore_polynomial_element.cpython-314-x86_64-linux-musl.so +0 -0
  716. sage/rings/polynomial/ore_polynomial_element.pxd +48 -0
  717. sage/rings/polynomial/ore_polynomial_element.pyx +3145 -0
  718. sage/rings/polynomial/ore_polynomial_ring.py +1334 -0
  719. sage/rings/polynomial/polynomial_real_mpfr_dense.cpython-314-x86_64-linux-musl.so +0 -0
  720. sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +788 -0
  721. sage/rings/polynomial/q_integer_valued_polynomials.py +1264 -0
  722. sage/rings/polynomial/skew_polynomial_element.cpython-314-x86_64-linux-musl.so +0 -0
  723. sage/rings/polynomial/skew_polynomial_element.pxd +9 -0
  724. sage/rings/polynomial/skew_polynomial_element.pyx +684 -0
  725. sage/rings/polynomial/skew_polynomial_finite_field.cpython-314-x86_64-linux-musl.so +0 -0
  726. sage/rings/polynomial/skew_polynomial_finite_field.pxd +19 -0
  727. sage/rings/polynomial/skew_polynomial_finite_field.pyx +1093 -0
  728. sage/rings/polynomial/skew_polynomial_finite_order.cpython-314-x86_64-linux-musl.so +0 -0
  729. sage/rings/polynomial/skew_polynomial_finite_order.pxd +10 -0
  730. sage/rings/polynomial/skew_polynomial_finite_order.pyx +567 -0
  731. sage/rings/polynomial/skew_polynomial_ring.py +908 -0
  732. sage/rings/real_double_element_gsl.cpython-314-x86_64-linux-musl.so +0 -0
  733. sage/rings/real_double_element_gsl.pxd +8 -0
  734. sage/rings/real_double_element_gsl.pyx +794 -0
  735. sage/rings/real_field.py +58 -0
  736. sage/rings/real_mpfr.cpython-314-x86_64-linux-musl.so +0 -0
  737. sage/rings/real_mpfr.pxd +29 -0
  738. sage/rings/real_mpfr.pyx +6122 -0
  739. sage/rings/ring_extension.cpython-314-x86_64-linux-musl.so +0 -0
  740. sage/rings/ring_extension.pxd +42 -0
  741. sage/rings/ring_extension.pyx +2779 -0
  742. sage/rings/ring_extension_conversion.cpython-314-x86_64-linux-musl.so +0 -0
  743. sage/rings/ring_extension_conversion.pxd +16 -0
  744. sage/rings/ring_extension_conversion.pyx +462 -0
  745. sage/rings/ring_extension_element.cpython-314-x86_64-linux-musl.so +0 -0
  746. sage/rings/ring_extension_element.pxd +21 -0
  747. sage/rings/ring_extension_element.pyx +1635 -0
  748. sage/rings/ring_extension_homset.py +64 -0
  749. sage/rings/ring_extension_morphism.cpython-314-x86_64-linux-musl.so +0 -0
  750. sage/rings/ring_extension_morphism.pxd +35 -0
  751. sage/rings/ring_extension_morphism.pyx +920 -0
  752. sage/schemes/all__sagemath_modules.py +1 -0
  753. sage/schemes/projective/all__sagemath_modules.py +1 -0
  754. sage/schemes/projective/coherent_sheaf.py +300 -0
  755. sage/schemes/projective/cohomology.py +510 -0
  756. sage/stats/all.py +15 -0
  757. sage/stats/basic_stats.py +489 -0
  758. sage/stats/distributions/all.py +7 -0
  759. sage/stats/distributions/catalog.py +34 -0
  760. sage/stats/distributions/dgs.h +50 -0
  761. sage/stats/distributions/dgs.pxd +111 -0
  762. sage/stats/distributions/dgs_bern.h +400 -0
  763. sage/stats/distributions/dgs_gauss.h +614 -0
  764. sage/stats/distributions/dgs_misc.h +104 -0
  765. sage/stats/distributions/discrete_gaussian_integer.cpython-314-x86_64-linux-musl.so +0 -0
  766. sage/stats/distributions/discrete_gaussian_integer.pxd +14 -0
  767. sage/stats/distributions/discrete_gaussian_integer.pyx +498 -0
  768. sage/stats/distributions/discrete_gaussian_lattice.py +908 -0
  769. sage/stats/distributions/discrete_gaussian_polynomial.py +141 -0
  770. sage/stats/hmm/all.py +15 -0
  771. sage/stats/hmm/chmm.cpython-314-x86_64-linux-musl.so +0 -0
  772. sage/stats/hmm/chmm.pyx +1595 -0
  773. sage/stats/hmm/distributions.cpython-314-x86_64-linux-musl.so +0 -0
  774. sage/stats/hmm/distributions.pxd +29 -0
  775. sage/stats/hmm/distributions.pyx +531 -0
  776. sage/stats/hmm/hmm.cpython-314-x86_64-linux-musl.so +0 -0
  777. sage/stats/hmm/hmm.pxd +17 -0
  778. sage/stats/hmm/hmm.pyx +1388 -0
  779. sage/stats/hmm/util.cpython-314-x86_64-linux-musl.so +0 -0
  780. sage/stats/hmm/util.pxd +7 -0
  781. sage/stats/hmm/util.pyx +165 -0
  782. sage/stats/intlist.cpython-314-x86_64-linux-musl.so +0 -0
  783. sage/stats/intlist.pxd +14 -0
  784. sage/stats/intlist.pyx +588 -0
  785. sage/stats/r.py +49 -0
  786. sage/stats/time_series.cpython-314-x86_64-linux-musl.so +0 -0
  787. sage/stats/time_series.pxd +6 -0
  788. sage/stats/time_series.pyx +2546 -0
  789. sage/tensor/all.py +2 -0
  790. sage/tensor/modules/all.py +8 -0
  791. sage/tensor/modules/alternating_contr_tensor.py +761 -0
  792. sage/tensor/modules/comp.py +5598 -0
  793. sage/tensor/modules/ext_pow_free_module.py +824 -0
  794. sage/tensor/modules/finite_rank_free_module.py +3589 -0
  795. sage/tensor/modules/format_utilities.py +333 -0
  796. sage/tensor/modules/free_module_alt_form.py +858 -0
  797. sage/tensor/modules/free_module_automorphism.py +1207 -0
  798. sage/tensor/modules/free_module_basis.py +1074 -0
  799. sage/tensor/modules/free_module_element.py +284 -0
  800. sage/tensor/modules/free_module_homset.py +652 -0
  801. sage/tensor/modules/free_module_linear_group.py +564 -0
  802. sage/tensor/modules/free_module_morphism.py +1581 -0
  803. sage/tensor/modules/free_module_tensor.py +3289 -0
  804. sage/tensor/modules/reflexive_module.py +386 -0
  805. sage/tensor/modules/tensor_free_module.py +780 -0
  806. sage/tensor/modules/tensor_free_submodule.py +538 -0
  807. sage/tensor/modules/tensor_free_submodule_basis.py +140 -0
  808. 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()