passagemath-categories 10.6.32__cp314-cp314t-musllinux_1_2_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_categories-10.6.32.dist-info/METADATA +156 -0
- passagemath_categories-10.6.32.dist-info/RECORD +719 -0
- passagemath_categories-10.6.32.dist-info/WHEEL +5 -0
- passagemath_categories-10.6.32.dist-info/top_level.txt +2 -0
- passagemath_categories.libs/libgcc_s-2d945d6c.so.1 +0 -0
- passagemath_categories.libs/libgmp-28992bcb.so.10.5.0 +0 -0
- passagemath_categories.libs/libstdc++-85f2cd6d.so.6.0.33 +0 -0
- sage/all__sagemath_categories.py +28 -0
- sage/arith/all.py +38 -0
- sage/arith/constants.pxd +27 -0
- sage/arith/functions.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/functions.pxd +4 -0
- sage/arith/functions.pyx +221 -0
- sage/arith/misc.py +6552 -0
- sage/arith/multi_modular.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/multi_modular.pxd +39 -0
- sage/arith/multi_modular.pyx +994 -0
- sage/arith/rational_reconstruction.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/rational_reconstruction.pxd +4 -0
- sage/arith/rational_reconstruction.pyx +115 -0
- sage/arith/srange.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/srange.pyx +571 -0
- sage/calculus/all__sagemath_categories.py +2 -0
- sage/calculus/functional.py +481 -0
- sage/calculus/functions.py +151 -0
- sage/categories/additive_groups.py +73 -0
- sage/categories/additive_magmas.py +1044 -0
- sage/categories/additive_monoids.py +114 -0
- sage/categories/additive_semigroups.py +184 -0
- sage/categories/affine_weyl_groups.py +238 -0
- sage/categories/algebra_ideals.py +95 -0
- sage/categories/algebra_modules.py +96 -0
- sage/categories/algebras.py +349 -0
- sage/categories/algebras_with_basis.py +377 -0
- sage/categories/all.py +160 -0
- sage/categories/aperiodic_semigroups.py +29 -0
- sage/categories/associative_algebras.py +47 -0
- sage/categories/bialgebras.py +101 -0
- sage/categories/bialgebras_with_basis.py +414 -0
- sage/categories/bimodules.py +206 -0
- sage/categories/chain_complexes.py +268 -0
- sage/categories/classical_crystals.py +480 -0
- sage/categories/coalgebras.py +405 -0
- sage/categories/coalgebras_with_basis.py +232 -0
- sage/categories/coercion_methods.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/categories/coercion_methods.pyx +52 -0
- sage/categories/commutative_additive_groups.py +104 -0
- sage/categories/commutative_additive_monoids.py +45 -0
- sage/categories/commutative_additive_semigroups.py +48 -0
- sage/categories/commutative_algebra_ideals.py +87 -0
- sage/categories/commutative_algebras.py +94 -0
- sage/categories/commutative_ring_ideals.py +58 -0
- sage/categories/commutative_rings.py +736 -0
- sage/categories/complete_discrete_valuation.py +293 -0
- sage/categories/complex_reflection_groups.py +145 -0
- sage/categories/complex_reflection_or_generalized_coxeter_groups.py +1249 -0
- sage/categories/coxeter_group_algebras.py +186 -0
- sage/categories/coxeter_groups.py +3402 -0
- sage/categories/crystals.py +2628 -0
- sage/categories/cw_complexes.py +216 -0
- sage/categories/dedekind_domains.py +137 -0
- sage/categories/discrete_valuation.py +325 -0
- sage/categories/distributive_magmas_and_additive_magmas.py +100 -0
- sage/categories/division_rings.py +114 -0
- sage/categories/domains.py +95 -0
- sage/categories/drinfeld_modules.py +789 -0
- sage/categories/dual.py +42 -0
- sage/categories/enumerated_sets.py +1146 -0
- sage/categories/euclidean_domains.py +271 -0
- sage/categories/examples/algebras_with_basis.py +102 -0
- sage/categories/examples/all.py +1 -0
- sage/categories/examples/commutative_additive_monoids.py +130 -0
- sage/categories/examples/commutative_additive_semigroups.py +199 -0
- sage/categories/examples/coxeter_groups.py +8 -0
- sage/categories/examples/crystals.py +236 -0
- sage/categories/examples/cw_complexes.py +163 -0
- sage/categories/examples/facade_sets.py +187 -0
- sage/categories/examples/filtered_algebras_with_basis.py +204 -0
- sage/categories/examples/filtered_modules_with_basis.py +154 -0
- sage/categories/examples/finite_coxeter_groups.py +252 -0
- sage/categories/examples/finite_dimensional_algebras_with_basis.py +148 -0
- sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +495 -0
- sage/categories/examples/finite_enumerated_sets.py +208 -0
- sage/categories/examples/finite_monoids.py +150 -0
- sage/categories/examples/finite_semigroups.py +190 -0
- sage/categories/examples/finite_weyl_groups.py +191 -0
- sage/categories/examples/graded_connected_hopf_algebras_with_basis.py +152 -0
- sage/categories/examples/graded_modules_with_basis.py +168 -0
- sage/categories/examples/graphs.py +122 -0
- sage/categories/examples/hopf_algebras_with_basis.py +145 -0
- sage/categories/examples/infinite_enumerated_sets.py +190 -0
- sage/categories/examples/lie_algebras.py +352 -0
- sage/categories/examples/lie_algebras_with_basis.py +196 -0
- sage/categories/examples/magmas.py +162 -0
- sage/categories/examples/manifolds.py +94 -0
- sage/categories/examples/monoids.py +144 -0
- sage/categories/examples/posets.py +178 -0
- sage/categories/examples/semigroups.py +580 -0
- sage/categories/examples/semigroups_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/categories/examples/semigroups_cython.pyx +221 -0
- sage/categories/examples/semirings.py +249 -0
- sage/categories/examples/sets_cat.py +706 -0
- sage/categories/examples/sets_with_grading.py +101 -0
- sage/categories/examples/with_realizations.py +542 -0
- sage/categories/fields.py +991 -0
- sage/categories/filtered_algebras.py +63 -0
- sage/categories/filtered_algebras_with_basis.py +548 -0
- sage/categories/filtered_hopf_algebras_with_basis.py +138 -0
- sage/categories/filtered_modules.py +210 -0
- sage/categories/filtered_modules_with_basis.py +1209 -0
- sage/categories/finite_complex_reflection_groups.py +1506 -0
- sage/categories/finite_coxeter_groups.py +1138 -0
- sage/categories/finite_crystals.py +103 -0
- sage/categories/finite_dimensional_algebras_with_basis.py +1860 -0
- sage/categories/finite_dimensional_bialgebras_with_basis.py +33 -0
- sage/categories/finite_dimensional_coalgebras_with_basis.py +33 -0
- sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py +231 -0
- sage/categories/finite_dimensional_hopf_algebras_with_basis.py +38 -0
- sage/categories/finite_dimensional_lie_algebras_with_basis.py +2774 -0
- sage/categories/finite_dimensional_modules_with_basis.py +1407 -0
- sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py +167 -0
- sage/categories/finite_dimensional_semisimple_algebras_with_basis.py +270 -0
- sage/categories/finite_enumerated_sets.py +769 -0
- sage/categories/finite_fields.py +252 -0
- sage/categories/finite_groups.py +256 -0
- sage/categories/finite_lattice_posets.py +242 -0
- sage/categories/finite_monoids.py +316 -0
- sage/categories/finite_permutation_groups.py +339 -0
- sage/categories/finite_posets.py +1994 -0
- sage/categories/finite_semigroups.py +136 -0
- sage/categories/finite_sets.py +93 -0
- sage/categories/finite_weyl_groups.py +39 -0
- sage/categories/finitely_generated_lambda_bracket_algebras.py +112 -0
- sage/categories/finitely_generated_lie_conformal_algebras.py +114 -0
- sage/categories/finitely_generated_magmas.py +57 -0
- sage/categories/finitely_generated_semigroups.py +214 -0
- sage/categories/function_fields.py +76 -0
- sage/categories/g_sets.py +77 -0
- sage/categories/gcd_domains.py +65 -0
- sage/categories/generalized_coxeter_groups.py +94 -0
- sage/categories/graded_algebras.py +85 -0
- sage/categories/graded_algebras_with_basis.py +258 -0
- sage/categories/graded_bialgebras.py +32 -0
- sage/categories/graded_bialgebras_with_basis.py +32 -0
- sage/categories/graded_coalgebras.py +65 -0
- sage/categories/graded_coalgebras_with_basis.py +51 -0
- sage/categories/graded_hopf_algebras.py +41 -0
- sage/categories/graded_hopf_algebras_with_basis.py +169 -0
- sage/categories/graded_lie_algebras.py +91 -0
- sage/categories/graded_lie_algebras_with_basis.py +44 -0
- sage/categories/graded_lie_conformal_algebras.py +74 -0
- sage/categories/graded_modules.py +133 -0
- sage/categories/graded_modules_with_basis.py +329 -0
- sage/categories/graphs.py +138 -0
- sage/categories/group_algebras.py +430 -0
- sage/categories/groupoid.py +94 -0
- sage/categories/groups.py +667 -0
- sage/categories/h_trivial_semigroups.py +64 -0
- sage/categories/hecke_modules.py +185 -0
- sage/categories/highest_weight_crystals.py +980 -0
- sage/categories/hopf_algebras.py +219 -0
- sage/categories/hopf_algebras_with_basis.py +309 -0
- sage/categories/infinite_enumerated_sets.py +115 -0
- sage/categories/integral_domains.py +203 -0
- sage/categories/j_trivial_semigroups.py +29 -0
- sage/categories/kac_moody_algebras.py +82 -0
- sage/categories/kahler_algebras.py +203 -0
- sage/categories/l_trivial_semigroups.py +63 -0
- sage/categories/lambda_bracket_algebras.py +280 -0
- sage/categories/lambda_bracket_algebras_with_basis.py +107 -0
- sage/categories/lattice_posets.py +89 -0
- sage/categories/left_modules.py +49 -0
- sage/categories/lie_algebras.py +1070 -0
- sage/categories/lie_algebras_with_basis.py +261 -0
- sage/categories/lie_conformal_algebras.py +350 -0
- sage/categories/lie_conformal_algebras_with_basis.py +147 -0
- sage/categories/lie_groups.py +73 -0
- sage/categories/loop_crystals.py +1290 -0
- sage/categories/magmas.py +1189 -0
- sage/categories/magmas_and_additive_magmas.py +149 -0
- sage/categories/magmatic_algebras.py +365 -0
- sage/categories/manifolds.py +352 -0
- sage/categories/matrix_algebras.py +40 -0
- sage/categories/metric_spaces.py +387 -0
- sage/categories/modular_abelian_varieties.py +78 -0
- sage/categories/modules.py +989 -0
- sage/categories/modules_with_basis.py +2794 -0
- sage/categories/monoid_algebras.py +38 -0
- sage/categories/monoids.py +739 -0
- sage/categories/noetherian_rings.py +87 -0
- sage/categories/number_fields.py +242 -0
- sage/categories/ore_modules.py +189 -0
- sage/categories/partially_ordered_monoids.py +49 -0
- sage/categories/permutation_groups.py +63 -0
- sage/categories/pointed_sets.py +42 -0
- sage/categories/polyhedra.py +74 -0
- sage/categories/poor_man_map.py +270 -0
- sage/categories/posets.py +722 -0
- sage/categories/principal_ideal_domains.py +270 -0
- sage/categories/quantum_group_representations.py +543 -0
- sage/categories/quotient_fields.py +728 -0
- sage/categories/r_trivial_semigroups.py +45 -0
- sage/categories/regular_crystals.py +898 -0
- sage/categories/regular_supercrystals.py +170 -0
- sage/categories/right_modules.py +49 -0
- sage/categories/ring_ideals.py +74 -0
- sage/categories/rings.py +1904 -0
- sage/categories/rngs.py +175 -0
- sage/categories/schemes.py +393 -0
- sage/categories/semigroups.py +1060 -0
- sage/categories/semirings.py +71 -0
- sage/categories/semisimple_algebras.py +114 -0
- sage/categories/sets_with_grading.py +235 -0
- sage/categories/shephard_groups.py +43 -0
- sage/categories/signed_tensor.py +120 -0
- sage/categories/simplicial_complexes.py +134 -0
- sage/categories/simplicial_sets.py +1206 -0
- sage/categories/super_algebras.py +149 -0
- sage/categories/super_algebras_with_basis.py +144 -0
- sage/categories/super_hopf_algebras_with_basis.py +126 -0
- sage/categories/super_lie_conformal_algebras.py +193 -0
- sage/categories/super_modules.py +229 -0
- sage/categories/super_modules_with_basis.py +193 -0
- sage/categories/supercommutative_algebras.py +99 -0
- sage/categories/supercrystals.py +406 -0
- sage/categories/tensor.py +110 -0
- sage/categories/topological_spaces.py +170 -0
- sage/categories/triangular_kac_moody_algebras.py +439 -0
- sage/categories/tutorial.py +58 -0
- sage/categories/unique_factorization_domains.py +318 -0
- sage/categories/unital_algebras.py +426 -0
- sage/categories/vector_bundles.py +159 -0
- sage/categories/vector_spaces.py +357 -0
- sage/categories/weyl_groups.py +853 -0
- sage/combinat/all__sagemath_categories.py +34 -0
- sage/combinat/backtrack.py +180 -0
- sage/combinat/combinat.py +2269 -0
- sage/combinat/combinat_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/combinat_cython.pxd +6 -0
- sage/combinat/combinat_cython.pyx +390 -0
- sage/combinat/combination.py +796 -0
- sage/combinat/combinatorial_map.py +416 -0
- sage/combinat/composition.py +2192 -0
- sage/combinat/dlx.py +510 -0
- sage/combinat/integer_lists/__init__.py +7 -0
- sage/combinat/integer_lists/base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/integer_lists/base.pxd +16 -0
- sage/combinat/integer_lists/base.pyx +713 -0
- sage/combinat/integer_lists/invlex.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/integer_lists/invlex.pxd +4 -0
- sage/combinat/integer_lists/invlex.pyx +1650 -0
- sage/combinat/integer_lists/lists.py +328 -0
- sage/combinat/integer_lists/nn.py +48 -0
- sage/combinat/integer_vector.py +1818 -0
- sage/combinat/integer_vector_weighted.py +413 -0
- sage/combinat/matrices/all__sagemath_categories.py +5 -0
- sage/combinat/matrices/dancing_links.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/matrices/dancing_links.pyx +1159 -0
- sage/combinat/matrices/dancing_links_c.h +380 -0
- sage/combinat/matrices/dlxcpp.py +136 -0
- sage/combinat/partition.py +10070 -0
- sage/combinat/partitions.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/partitions.pyx +743 -0
- sage/combinat/permutation.py +10168 -0
- sage/combinat/permutation_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/permutation_cython.pxd +11 -0
- sage/combinat/permutation_cython.pyx +407 -0
- sage/combinat/q_analogues.py +1090 -0
- sage/combinat/ranker.py +268 -0
- sage/combinat/subset.py +1561 -0
- sage/combinat/subsets_hereditary.py +202 -0
- sage/combinat/subsets_pairwise.py +184 -0
- sage/combinat/tools.py +63 -0
- sage/combinat/tuple.py +348 -0
- sage/data_structures/all.py +2 -0
- sage/data_structures/all__sagemath_categories.py +2 -0
- sage/data_structures/binary_matrix.pxd +138 -0
- sage/data_structures/binary_search.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/binary_search.pxd +3 -0
- sage/data_structures/binary_search.pyx +66 -0
- sage/data_structures/bitset.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/bitset.pxd +40 -0
- sage/data_structures/bitset.pyx +2385 -0
- sage/data_structures/bitset_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/bitset_base.pxd +926 -0
- sage/data_structures/bitset_base.pyx +117 -0
- sage/data_structures/bitset_intrinsics.h +487 -0
- sage/data_structures/blas_dict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/blas_dict.pxd +12 -0
- sage/data_structures/blas_dict.pyx +469 -0
- sage/data_structures/list_of_pairs.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/list_of_pairs.pxd +16 -0
- sage/data_structures/list_of_pairs.pyx +122 -0
- sage/data_structures/mutable_poset.py +3312 -0
- sage/data_structures/pairing_heap.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/pairing_heap.h +346 -0
- sage/data_structures/pairing_heap.pxd +88 -0
- sage/data_structures/pairing_heap.pyx +1464 -0
- sage/data_structures/sparse_bitset.pxd +62 -0
- sage/data_structures/stream.py +5070 -0
- sage/databases/all__sagemath_categories.py +7 -0
- sage/databases/sql_db.py +2236 -0
- sage/ext/all__sagemath_categories.py +3 -0
- sage/ext/fast_callable.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/fast_callable.pxd +4 -0
- sage/ext/fast_callable.pyx +2746 -0
- sage/ext/fast_eval.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/fast_eval.pxd +1 -0
- sage/ext/fast_eval.pyx +102 -0
- sage/ext/interpreters/__init__.py +1 -0
- sage/ext/interpreters/all__sagemath_categories.py +2 -0
- sage/ext/interpreters/wrapper_el.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_el.pxd +18 -0
- sage/ext/interpreters/wrapper_el.pyx +148 -0
- sage/ext/interpreters/wrapper_py.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_py.pxd +17 -0
- sage/ext/interpreters/wrapper_py.pyx +133 -0
- sage/functions/airy.py +937 -0
- sage/functions/all.py +97 -0
- sage/functions/bessel.py +2102 -0
- sage/functions/error.py +784 -0
- sage/functions/exp_integral.py +1529 -0
- sage/functions/gamma.py +1087 -0
- sage/functions/generalized.py +672 -0
- sage/functions/hyperbolic.py +747 -0
- sage/functions/hypergeometric.py +1156 -0
- sage/functions/jacobi.py +1705 -0
- sage/functions/log.py +1402 -0
- sage/functions/min_max.py +338 -0
- sage/functions/orthogonal_polys.py +3106 -0
- sage/functions/other.py +2303 -0
- sage/functions/piecewise.py +1505 -0
- sage/functions/prime_pi.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/functions/prime_pi.pyx +262 -0
- sage/functions/special.py +1212 -0
- sage/functions/spike_function.py +278 -0
- sage/functions/transcendental.py +690 -0
- sage/functions/trig.py +1062 -0
- sage/functions/wigner.py +726 -0
- sage/geometry/abc.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/geometry/abc.pyx +82 -0
- sage/geometry/all__sagemath_categories.py +1 -0
- sage/groups/all__sagemath_categories.py +11 -0
- sage/groups/generic.py +1733 -0
- sage/groups/groups_catalog.py +113 -0
- sage/groups/perm_gps/all__sagemath_categories.py +1 -0
- sage/groups/perm_gps/partn_ref/all.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_categories.py +1 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pxd +52 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx +906 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.pxd +85 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.pyx +534 -0
- sage/groups/perm_gps/partn_ref/data_structures.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/data_structures.pxd +576 -0
- sage/groups/perm_gps/partn_ref/data_structures.pyx +1792 -0
- sage/groups/perm_gps/partn_ref/double_coset.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/double_coset.pxd +45 -0
- sage/groups/perm_gps/partn_ref/double_coset.pyx +739 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.pxd +18 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.pyx +82 -0
- sage/groups/perm_gps/partn_ref/refinement_python.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_python.pxd +16 -0
- sage/groups/perm_gps/partn_ref/refinement_python.pyx +564 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.pxd +60 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.pyx +858 -0
- sage/interfaces/abc.py +140 -0
- sage/interfaces/all.py +58 -0
- sage/interfaces/all__sagemath_categories.py +1 -0
- sage/interfaces/expect.py +1643 -0
- sage/interfaces/interface.py +1682 -0
- sage/interfaces/process.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/interfaces/process.pxd +5 -0
- sage/interfaces/process.pyx +288 -0
- sage/interfaces/quit.py +167 -0
- sage/interfaces/sage0.py +604 -0
- sage/interfaces/sagespawn.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/interfaces/sagespawn.pyx +308 -0
- sage/interfaces/tab_completion.py +101 -0
- sage/misc/all__sagemath_categories.py +78 -0
- sage/misc/allocator.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/allocator.pxd +6 -0
- sage/misc/allocator.pyx +47 -0
- sage/misc/binary_tree.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/binary_tree.pxd +29 -0
- sage/misc/binary_tree.pyx +537 -0
- sage/misc/callable_dict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/callable_dict.pyx +89 -0
- sage/misc/citation.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/citation.pyx +159 -0
- sage/misc/converting_dict.py +293 -0
- sage/misc/defaults.py +129 -0
- sage/misc/derivative.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/derivative.pyx +223 -0
- sage/misc/functional.py +2005 -0
- sage/misc/html.py +589 -0
- sage/misc/latex.py +2673 -0
- sage/misc/latex_macros.py +236 -0
- sage/misc/latex_standalone.py +1833 -0
- sage/misc/map_threaded.py +38 -0
- sage/misc/mathml.py +76 -0
- sage/misc/method_decorator.py +88 -0
- sage/misc/mrange.py +755 -0
- sage/misc/multireplace.py +41 -0
- sage/misc/object_multiplexer.py +92 -0
- sage/misc/parser.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/parser.pyx +1107 -0
- sage/misc/random_testing.py +264 -0
- sage/misc/rest_index_of_methods.py +377 -0
- sage/misc/search.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/search.pxd +2 -0
- sage/misc/search.pyx +68 -0
- sage/misc/stopgap.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/stopgap.pyx +95 -0
- sage/misc/table.py +853 -0
- sage/monoids/all__sagemath_categories.py +1 -0
- sage/monoids/indexed_free_monoid.py +1071 -0
- sage/monoids/monoid.py +82 -0
- sage/numerical/all__sagemath_categories.py +1 -0
- sage/numerical/backends/all__sagemath_categories.py +1 -0
- sage/numerical/backends/generic_backend.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/numerical/backends/generic_backend.pxd +61 -0
- sage/numerical/backends/generic_backend.pyx +1893 -0
- sage/numerical/backends/generic_sdp_backend.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/numerical/backends/generic_sdp_backend.pxd +38 -0
- sage/numerical/backends/generic_sdp_backend.pyx +755 -0
- sage/parallel/all.py +6 -0
- sage/parallel/decorate.py +575 -0
- sage/parallel/map_reduce.py +1997 -0
- sage/parallel/multiprocessing_sage.py +76 -0
- sage/parallel/ncpus.py +35 -0
- sage/parallel/parallelism.py +364 -0
- sage/parallel/reference.py +47 -0
- sage/parallel/use_fork.py +333 -0
- sage/rings/abc.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/abc.pxd +31 -0
- sage/rings/abc.pyx +526 -0
- sage/rings/algebraic_closure_finite_field.py +1154 -0
- sage/rings/all__sagemath_categories.py +91 -0
- sage/rings/big_oh.py +227 -0
- sage/rings/continued_fraction.py +2754 -0
- sage/rings/continued_fraction_gosper.py +220 -0
- sage/rings/factorint.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/factorint.pyx +295 -0
- sage/rings/fast_arith.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/fast_arith.pxd +21 -0
- sage/rings/fast_arith.pyx +535 -0
- sage/rings/finite_rings/all__sagemath_categories.py +9 -0
- sage/rings/finite_rings/conway_polynomials.py +542 -0
- sage/rings/finite_rings/element_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/element_base.pxd +12 -0
- sage/rings/finite_rings/element_base.pyx +1176 -0
- sage/rings/finite_rings/finite_field_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/finite_field_base.pxd +7 -0
- sage/rings/finite_rings/finite_field_base.pyx +2171 -0
- sage/rings/finite_rings/finite_field_constructor.py +827 -0
- sage/rings/finite_rings/finite_field_prime_modn.py +372 -0
- sage/rings/finite_rings/galois_group.py +154 -0
- sage/rings/finite_rings/hom_finite_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/hom_finite_field.pxd +23 -0
- sage/rings/finite_rings/hom_finite_field.pyx +856 -0
- sage/rings/finite_rings/hom_prime_finite_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/hom_prime_finite_field.pxd +15 -0
- sage/rings/finite_rings/hom_prime_finite_field.pyx +164 -0
- sage/rings/finite_rings/homset.py +357 -0
- sage/rings/finite_rings/integer_mod.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/integer_mod.pxd +56 -0
- sage/rings/finite_rings/integer_mod.pyx +4586 -0
- sage/rings/finite_rings/integer_mod_limits.h +11 -0
- sage/rings/finite_rings/integer_mod_ring.py +2044 -0
- sage/rings/finite_rings/residue_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/residue_field.pxd +30 -0
- sage/rings/finite_rings/residue_field.pyx +1811 -0
- sage/rings/finite_rings/stdint.pxd +19 -0
- sage/rings/fraction_field.py +1452 -0
- sage/rings/fraction_field_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/fraction_field_element.pyx +1357 -0
- sage/rings/function_field/all.py +7 -0
- sage/rings/function_field/all__sagemath_categories.py +2 -0
- sage/rings/function_field/constructor.py +218 -0
- sage/rings/function_field/element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/element.pxd +11 -0
- sage/rings/function_field/element.pyx +1008 -0
- sage/rings/function_field/element_rational.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/element_rational.pyx +513 -0
- sage/rings/function_field/extensions.py +230 -0
- sage/rings/function_field/function_field.py +1468 -0
- sage/rings/function_field/function_field_rational.py +1005 -0
- sage/rings/function_field/ideal.py +1155 -0
- sage/rings/function_field/ideal_rational.py +629 -0
- sage/rings/function_field/jacobian_base.py +826 -0
- sage/rings/function_field/jacobian_hess.py +1053 -0
- sage/rings/function_field/jacobian_khuri_makdisi.py +1027 -0
- sage/rings/function_field/maps.py +1039 -0
- sage/rings/function_field/order.py +281 -0
- sage/rings/function_field/order_basis.py +586 -0
- sage/rings/function_field/order_rational.py +576 -0
- sage/rings/function_field/place.py +426 -0
- sage/rings/function_field/place_rational.py +181 -0
- sage/rings/generic.py +320 -0
- sage/rings/homset.py +332 -0
- sage/rings/ideal.py +1885 -0
- sage/rings/ideal_monoid.py +215 -0
- sage/rings/infinity.py +1890 -0
- sage/rings/integer.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/integer.pxd +45 -0
- sage/rings/integer.pyx +7874 -0
- sage/rings/integer_ring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/integer_ring.pxd +8 -0
- sage/rings/integer_ring.pyx +1693 -0
- sage/rings/laurent_series_ring.py +931 -0
- sage/rings/laurent_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/laurent_series_ring_element.pxd +11 -0
- sage/rings/laurent_series_ring_element.pyx +1927 -0
- sage/rings/lazy_series.py +7815 -0
- sage/rings/lazy_series_ring.py +4356 -0
- sage/rings/localization.py +1043 -0
- sage/rings/morphism.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/morphism.pxd +39 -0
- sage/rings/morphism.pyx +3299 -0
- sage/rings/multi_power_series_ring.py +1145 -0
- sage/rings/multi_power_series_ring_element.py +2184 -0
- sage/rings/noncommutative_ideals.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/noncommutative_ideals.pyx +423 -0
- sage/rings/number_field/all__sagemath_categories.py +1 -0
- sage/rings/number_field/number_field_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/number_field/number_field_base.pxd +8 -0
- sage/rings/number_field/number_field_base.pyx +507 -0
- sage/rings/number_field/number_field_element_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/number_field/number_field_element_base.pxd +6 -0
- sage/rings/number_field/number_field_element_base.pyx +36 -0
- sage/rings/number_field/number_field_ideal.py +3550 -0
- sage/rings/padics/all__sagemath_categories.py +4 -0
- sage/rings/padics/local_generic.py +1670 -0
- sage/rings/padics/local_generic_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/padics/local_generic_element.pxd +5 -0
- sage/rings/padics/local_generic_element.pyx +1017 -0
- sage/rings/padics/misc.py +256 -0
- sage/rings/padics/padic_generic.py +1911 -0
- sage/rings/padics/pow_computer.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/padics/pow_computer.pxd +38 -0
- sage/rings/padics/pow_computer.pyx +671 -0
- sage/rings/padics/precision_error.py +24 -0
- sage/rings/polynomial/all__sagemath_categories.py +25 -0
- sage/rings/polynomial/commutative_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/commutative_polynomial.pxd +6 -0
- sage/rings/polynomial/commutative_polynomial.pyx +24 -0
- sage/rings/polynomial/cyclotomic.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/cyclotomic.pyx +404 -0
- sage/rings/polynomial/flatten.py +711 -0
- sage/rings/polynomial/ideal.py +102 -0
- sage/rings/polynomial/infinite_polynomial_element.py +1768 -0
- sage/rings/polynomial/infinite_polynomial_ring.py +1653 -0
- sage/rings/polynomial/laurent_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/laurent_polynomial.pxd +18 -0
- sage/rings/polynomial/laurent_polynomial.pyx +2190 -0
- sage/rings/polynomial/laurent_polynomial_ideal.py +590 -0
- sage/rings/polynomial/laurent_polynomial_ring.py +832 -0
- sage/rings/polynomial/laurent_polynomial_ring_base.py +708 -0
- sage/rings/polynomial/multi_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/multi_polynomial.pxd +12 -0
- sage/rings/polynomial/multi_polynomial.pyx +3082 -0
- sage/rings/polynomial/multi_polynomial_element.py +2570 -0
- sage/rings/polynomial/multi_polynomial_ideal.py +5771 -0
- sage/rings/polynomial/multi_polynomial_ring.py +947 -0
- sage/rings/polynomial/multi_polynomial_ring_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/multi_polynomial_ring_base.pxd +15 -0
- sage/rings/polynomial/multi_polynomial_ring_base.pyx +1855 -0
- sage/rings/polynomial/multi_polynomial_sequence.py +2204 -0
- sage/rings/polynomial/polydict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polydict.pxd +45 -0
- sage/rings/polynomial/polydict.pyx +2701 -0
- sage/rings/polynomial/polynomial_compiled.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_compiled.pxd +59 -0
- sage/rings/polynomial/polynomial_compiled.pyx +509 -0
- sage/rings/polynomial/polynomial_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_element.pxd +64 -0
- sage/rings/polynomial/polynomial_element.pyx +13255 -0
- sage/rings/polynomial/polynomial_element_generic.py +1637 -0
- sage/rings/polynomial/polynomial_fateman.py +97 -0
- sage/rings/polynomial/polynomial_quotient_ring.py +2465 -0
- sage/rings/polynomial/polynomial_quotient_ring_element.py +779 -0
- sage/rings/polynomial/polynomial_ring.py +3784 -0
- sage/rings/polynomial/polynomial_ring_constructor.py +1051 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.pxd +5 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.pyx +121 -0
- sage/rings/polynomial/polynomial_singular_interface.py +549 -0
- sage/rings/polynomial/symmetric_ideal.py +989 -0
- sage/rings/polynomial/symmetric_reduction.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/symmetric_reduction.pxd +8 -0
- sage/rings/polynomial/symmetric_reduction.pyx +669 -0
- sage/rings/polynomial/term_order.py +2279 -0
- sage/rings/polynomial/toy_buchberger.py +449 -0
- sage/rings/polynomial/toy_d_basis.py +387 -0
- sage/rings/polynomial/toy_variety.py +362 -0
- sage/rings/power_series_mpoly.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_mpoly.pxd +9 -0
- sage/rings/power_series_mpoly.pyx +161 -0
- sage/rings/power_series_poly.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_poly.pxd +10 -0
- sage/rings/power_series_poly.pyx +1317 -0
- sage/rings/power_series_ring.py +1441 -0
- sage/rings/power_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_ring_element.pxd +12 -0
- sage/rings/power_series_ring_element.pyx +3028 -0
- sage/rings/puiseux_series_ring.py +487 -0
- sage/rings/puiseux_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/puiseux_series_ring_element.pxd +7 -0
- sage/rings/puiseux_series_ring_element.pyx +1055 -0
- sage/rings/qqbar_decorators.py +167 -0
- sage/rings/quotient_ring.py +1598 -0
- sage/rings/quotient_ring_element.py +979 -0
- sage/rings/rational.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/rational.pxd +20 -0
- sage/rings/rational.pyx +4284 -0
- sage/rings/rational_field.py +1730 -0
- sage/rings/real_double.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/real_double.pxd +16 -0
- sage/rings/real_double.pyx +2218 -0
- sage/rings/real_lazy.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/real_lazy.pxd +30 -0
- sage/rings/real_lazy.pyx +1773 -0
- sage/rings/ring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/ring.pxd +30 -0
- sage/rings/ring.pyx +850 -0
- sage/rings/semirings/all.py +3 -0
- sage/rings/semirings/non_negative_integer_semiring.py +107 -0
- sage/rings/semirings/tropical_mpolynomial.py +972 -0
- sage/rings/semirings/tropical_polynomial.py +997 -0
- sage/rings/semirings/tropical_semiring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/semirings/tropical_semiring.pyx +676 -0
- sage/rings/semirings/tropical_variety.py +1701 -0
- sage/rings/sum_of_squares.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/sum_of_squares.pxd +3 -0
- sage/rings/sum_of_squares.pyx +336 -0
- sage/rings/tests.py +504 -0
- sage/schemes/affine/affine_homset.py +508 -0
- sage/schemes/affine/affine_morphism.py +1574 -0
- sage/schemes/affine/affine_point.py +460 -0
- sage/schemes/affine/affine_rational_point.py +308 -0
- sage/schemes/affine/affine_space.py +1264 -0
- sage/schemes/affine/affine_subscheme.py +592 -0
- sage/schemes/affine/all.py +25 -0
- sage/schemes/all__sagemath_categories.py +5 -0
- sage/schemes/generic/algebraic_scheme.py +2092 -0
- sage/schemes/generic/all.py +5 -0
- sage/schemes/generic/ambient_space.py +400 -0
- sage/schemes/generic/divisor.py +465 -0
- sage/schemes/generic/divisor_group.py +313 -0
- sage/schemes/generic/glue.py +84 -0
- sage/schemes/generic/homset.py +820 -0
- sage/schemes/generic/hypersurface.py +234 -0
- sage/schemes/generic/morphism.py +2107 -0
- sage/schemes/generic/point.py +237 -0
- sage/schemes/generic/scheme.py +1190 -0
- sage/schemes/generic/spec.py +199 -0
- sage/schemes/product_projective/all.py +6 -0
- sage/schemes/product_projective/homset.py +236 -0
- sage/schemes/product_projective/morphism.py +517 -0
- sage/schemes/product_projective/point.py +568 -0
- sage/schemes/product_projective/rational_point.py +550 -0
- sage/schemes/product_projective/space.py +1301 -0
- sage/schemes/product_projective/subscheme.py +466 -0
- sage/schemes/projective/all.py +24 -0
- sage/schemes/projective/proj_bdd_height.py +453 -0
- sage/schemes/projective/projective_homset.py +718 -0
- sage/schemes/projective/projective_morphism.py +2792 -0
- sage/schemes/projective/projective_point.py +1484 -0
- sage/schemes/projective/projective_rational_point.py +569 -0
- sage/schemes/projective/projective_space.py +2571 -0
- sage/schemes/projective/projective_subscheme.py +1574 -0
- sage/sets/all.py +17 -0
- sage/sets/cartesian_product.py +376 -0
- sage/sets/condition_set.py +525 -0
- sage/sets/disjoint_set.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/disjoint_set.pxd +36 -0
- sage/sets/disjoint_set.pyx +998 -0
- sage/sets/disjoint_union_enumerated_sets.py +625 -0
- sage/sets/family.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/family.pxd +12 -0
- sage/sets/family.pyx +1556 -0
- sage/sets/finite_enumerated_set.py +406 -0
- sage/sets/finite_set_map_cy.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/finite_set_map_cy.pxd +34 -0
- sage/sets/finite_set_map_cy.pyx +708 -0
- sage/sets/finite_set_maps.py +591 -0
- sage/sets/image_set.py +448 -0
- sage/sets/integer_range.py +829 -0
- sage/sets/non_negative_integers.py +241 -0
- sage/sets/positive_integers.py +93 -0
- sage/sets/primes.py +188 -0
- sage/sets/real_set.py +2760 -0
- sage/sets/recursively_enumerated_set.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/recursively_enumerated_set.pxd +31 -0
- sage/sets/recursively_enumerated_set.pyx +2082 -0
- sage/sets/set.py +2083 -0
- sage/sets/set_from_iterator.py +1021 -0
- sage/sets/totally_ordered_finite_set.py +329 -0
- sage/symbolic/all__sagemath_categories.py +1 -0
- sage/symbolic/function.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/symbolic/function.pxd +29 -0
- sage/symbolic/function.pyx +1488 -0
- sage/symbolic/symbols.py +56 -0
- sage/tests/all__sagemath_categories.py +1 -0
- sage/tests/cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/tests/cython.pyx +37 -0
- sage/tests/stl_vector.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/tests/stl_vector.pyx +171 -0
- sage/typeset/all.py +6 -0
- sage/typeset/ascii_art.py +295 -0
- sage/typeset/character_art.py +789 -0
- sage/typeset/character_art_factory.py +572 -0
- sage/typeset/symbols.py +334 -0
- sage/typeset/unicode_art.py +183 -0
- sage/typeset/unicode_characters.py +101 -0
sage/rings/morphism.pyx
ADDED
|
@@ -0,0 +1,3299 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-categories
|
|
2
|
+
r"""
|
|
3
|
+
Homomorphisms of rings
|
|
4
|
+
|
|
5
|
+
We give a large number of examples of ring homomorphisms.
|
|
6
|
+
|
|
7
|
+
EXAMPLES:
|
|
8
|
+
|
|
9
|
+
Natural inclusion `\ZZ \hookrightarrow \QQ`::
|
|
10
|
+
|
|
11
|
+
sage: H = Hom(ZZ, QQ)
|
|
12
|
+
sage: phi = H([1])
|
|
13
|
+
sage: phi(10)
|
|
14
|
+
10
|
|
15
|
+
sage: phi(3/1)
|
|
16
|
+
3
|
|
17
|
+
sage: phi(2/3)
|
|
18
|
+
Traceback (most recent call last):
|
|
19
|
+
...
|
|
20
|
+
TypeError: 2/3 fails to convert into the map's domain Integer Ring,
|
|
21
|
+
but a `pushforward` method is not properly implemented
|
|
22
|
+
|
|
23
|
+
There is no homomorphism in the other direction::
|
|
24
|
+
|
|
25
|
+
sage: H = Hom(QQ, ZZ)
|
|
26
|
+
sage: H([1])
|
|
27
|
+
Traceback (most recent call last):
|
|
28
|
+
...
|
|
29
|
+
ValueError: relations do not all (canonically) map to 0
|
|
30
|
+
under map determined by images of generators
|
|
31
|
+
|
|
32
|
+
EXAMPLES:
|
|
33
|
+
|
|
34
|
+
Reduction to finite field::
|
|
35
|
+
|
|
36
|
+
sage: # needs sage.rings.finite_rings
|
|
37
|
+
sage: H = Hom(ZZ, GF(9, 'a'))
|
|
38
|
+
sage: phi = H([1])
|
|
39
|
+
sage: phi(5)
|
|
40
|
+
2
|
|
41
|
+
sage: psi = H([4])
|
|
42
|
+
sage: psi(5)
|
|
43
|
+
2
|
|
44
|
+
|
|
45
|
+
Map from single variable polynomial ring::
|
|
46
|
+
|
|
47
|
+
sage: R.<x> = ZZ[]
|
|
48
|
+
sage: phi = R.hom([2], GF(5)); phi
|
|
49
|
+
Ring morphism:
|
|
50
|
+
From: Univariate Polynomial Ring in x over Integer Ring
|
|
51
|
+
To: Finite Field of size 5
|
|
52
|
+
Defn: x |--> 2
|
|
53
|
+
sage: phi(x + 12)
|
|
54
|
+
4
|
|
55
|
+
|
|
56
|
+
Identity map on the real numbers::
|
|
57
|
+
|
|
58
|
+
sage: # needs sage.rings.real_mpfr
|
|
59
|
+
sage: f = RR.hom([RR(1)]); f
|
|
60
|
+
Ring endomorphism of Real Field with 53 bits of precision
|
|
61
|
+
Defn: 1.00000000000000 |--> 1.00000000000000
|
|
62
|
+
sage: f(2.5)
|
|
63
|
+
2.50000000000000
|
|
64
|
+
sage: f = RR.hom([2.0])
|
|
65
|
+
Traceback (most recent call last):
|
|
66
|
+
...
|
|
67
|
+
ValueError: relations do not all (canonically) map to 0
|
|
68
|
+
under map determined by images of generators
|
|
69
|
+
|
|
70
|
+
Homomorphism from one precision of field to another.
|
|
71
|
+
|
|
72
|
+
From smaller to bigger doesn't make sense::
|
|
73
|
+
|
|
74
|
+
sage: R200 = RealField(200) # needs sage.rings.real_mpfr
|
|
75
|
+
sage: f = RR.hom( R200 ) # needs sage.rings.real_mpfr
|
|
76
|
+
Traceback (most recent call last):
|
|
77
|
+
...
|
|
78
|
+
TypeError: natural coercion morphism from Real Field with 53 bits of precision
|
|
79
|
+
to Real Field with 200 bits of precision not defined
|
|
80
|
+
|
|
81
|
+
From bigger to small does::
|
|
82
|
+
|
|
83
|
+
sage: f = RR.hom(RealField(15)) # needs sage.rings.real_mpfr
|
|
84
|
+
sage: f(2.5) # needs sage.rings.real_mpfr
|
|
85
|
+
2.500
|
|
86
|
+
sage: f(RR.pi()) # needs sage.rings.real_mpfr
|
|
87
|
+
3.142
|
|
88
|
+
|
|
89
|
+
Inclusion map from the reals to the complexes::
|
|
90
|
+
|
|
91
|
+
sage: # needs sage.rings.real_mpfr
|
|
92
|
+
sage: i = RR.hom([CC(1)]); i
|
|
93
|
+
Ring morphism:
|
|
94
|
+
From: Real Field with 53 bits of precision
|
|
95
|
+
To: Complex Field with 53 bits of precision
|
|
96
|
+
Defn: 1.00000000000000 |--> 1.00000000000000
|
|
97
|
+
sage: i(RR('3.1'))
|
|
98
|
+
3.10000000000000
|
|
99
|
+
|
|
100
|
+
A map from a multivariate polynomial ring to itself::
|
|
101
|
+
|
|
102
|
+
sage: R.<x,y,z> = PolynomialRing(QQ, 3)
|
|
103
|
+
sage: phi = R.hom([y, z, x^2]); phi
|
|
104
|
+
Ring endomorphism of Multivariate Polynomial Ring in x, y, z over Rational Field
|
|
105
|
+
Defn: x |--> y
|
|
106
|
+
y |--> z
|
|
107
|
+
z |--> x^2
|
|
108
|
+
sage: phi(x + y + z)
|
|
109
|
+
x^2 + y + z
|
|
110
|
+
|
|
111
|
+
An endomorphism of a quotient of a multi-variate polynomial ring::
|
|
112
|
+
|
|
113
|
+
sage: # needs sage.libs.singular
|
|
114
|
+
sage: R.<x,y> = PolynomialRing(QQ)
|
|
115
|
+
sage: S.<a,b> = quo(R, ideal(1 + y^2))
|
|
116
|
+
sage: phi = S.hom([a^2, -b]); phi
|
|
117
|
+
Ring endomorphism of Quotient of Multivariate Polynomial Ring in x, y
|
|
118
|
+
over Rational Field by the ideal (y^2 + 1)
|
|
119
|
+
Defn: a |--> a^2
|
|
120
|
+
b |--> -b
|
|
121
|
+
sage: phi(b)
|
|
122
|
+
-b
|
|
123
|
+
sage: phi(a^2 + b^2)
|
|
124
|
+
a^4 - 1
|
|
125
|
+
|
|
126
|
+
The reduction map from the integers to the integers modulo 8, viewed as
|
|
127
|
+
a quotient ring::
|
|
128
|
+
|
|
129
|
+
sage: R = ZZ.quo(8*ZZ)
|
|
130
|
+
sage: pi = R.cover(); pi
|
|
131
|
+
Ring morphism:
|
|
132
|
+
From: Integer Ring
|
|
133
|
+
To: Ring of integers modulo 8
|
|
134
|
+
Defn: Natural quotient map
|
|
135
|
+
sage: pi.domain()
|
|
136
|
+
Integer Ring
|
|
137
|
+
sage: pi.codomain()
|
|
138
|
+
Ring of integers modulo 8
|
|
139
|
+
sage: pi(10)
|
|
140
|
+
2
|
|
141
|
+
sage: pi.lift()
|
|
142
|
+
Set-theoretic ring morphism:
|
|
143
|
+
From: Ring of integers modulo 8
|
|
144
|
+
To: Integer Ring
|
|
145
|
+
Defn: Choice of lifting map
|
|
146
|
+
sage: pi.lift(13)
|
|
147
|
+
5
|
|
148
|
+
|
|
149
|
+
Inclusion of ``GF(2)`` into ``GF(4,'a')``::
|
|
150
|
+
|
|
151
|
+
sage: # needs sage.rings.finite_rings
|
|
152
|
+
sage: k = GF(2)
|
|
153
|
+
sage: i = k.hom(GF(4, 'a'))
|
|
154
|
+
sage: i
|
|
155
|
+
Ring morphism:
|
|
156
|
+
From: Finite Field of size 2
|
|
157
|
+
To: Finite Field in a of size 2^2
|
|
158
|
+
Defn: 1 |--> 1
|
|
159
|
+
sage: i(0)
|
|
160
|
+
0
|
|
161
|
+
sage: a = i(1); a.parent()
|
|
162
|
+
Finite Field in a of size 2^2
|
|
163
|
+
|
|
164
|
+
We next compose the inclusion with reduction from the integers to
|
|
165
|
+
``GF(2)``::
|
|
166
|
+
|
|
167
|
+
sage: # needs sage.rings.finite_rings
|
|
168
|
+
sage: pi = ZZ.hom(k); pi
|
|
169
|
+
Natural morphism:
|
|
170
|
+
From: Integer Ring
|
|
171
|
+
To: Finite Field of size 2
|
|
172
|
+
sage: f = i * pi; f
|
|
173
|
+
Composite map:
|
|
174
|
+
From: Integer Ring
|
|
175
|
+
To: Finite Field in a of size 2^2
|
|
176
|
+
Defn: Natural morphism:
|
|
177
|
+
From: Integer Ring
|
|
178
|
+
To: Finite Field of size 2
|
|
179
|
+
then
|
|
180
|
+
Ring morphism:
|
|
181
|
+
From: Finite Field of size 2
|
|
182
|
+
To: Finite Field in a of size 2^2
|
|
183
|
+
Defn: 1 |--> 1
|
|
184
|
+
sage: a = f(5); a
|
|
185
|
+
1
|
|
186
|
+
sage: a.parent()
|
|
187
|
+
Finite Field in a of size 2^2
|
|
188
|
+
|
|
189
|
+
Inclusion from `\QQ` to the 3-adic field::
|
|
190
|
+
|
|
191
|
+
sage: # needs sage.rings.padics
|
|
192
|
+
sage: phi = QQ.hom(Qp(3, print_mode='series'))
|
|
193
|
+
sage: phi
|
|
194
|
+
Ring morphism:
|
|
195
|
+
From: Rational Field
|
|
196
|
+
To: 3-adic Field with capped relative precision 20
|
|
197
|
+
sage: phi.codomain()
|
|
198
|
+
3-adic Field with capped relative precision 20
|
|
199
|
+
sage: phi(394)
|
|
200
|
+
1 + 2*3 + 3^2 + 2*3^3 + 3^4 + 3^5 + O(3^20)
|
|
201
|
+
|
|
202
|
+
An automorphism of a quotient of a univariate polynomial ring::
|
|
203
|
+
|
|
204
|
+
sage: # needs sage.libs.pari
|
|
205
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
206
|
+
sage: S.<sqrt2> = R.quo(x^2 - 2)
|
|
207
|
+
sage: sqrt2^2
|
|
208
|
+
2
|
|
209
|
+
sage: (3+sqrt2)^10
|
|
210
|
+
993054*sqrt2 + 1404491
|
|
211
|
+
sage: c = S.hom([-sqrt2])
|
|
212
|
+
sage: c(1+sqrt2)
|
|
213
|
+
-sqrt2 + 1
|
|
214
|
+
|
|
215
|
+
Note that Sage verifies that the morphism is valid::
|
|
216
|
+
|
|
217
|
+
sage: (1 - sqrt2)^2 # needs sage.libs.pari
|
|
218
|
+
-2*sqrt2 + 3
|
|
219
|
+
sage: c = S.hom([1 - sqrt2]) # this is not valid # needs sage.libs.pari
|
|
220
|
+
Traceback (most recent call last):
|
|
221
|
+
...
|
|
222
|
+
ValueError: relations do not all (canonically) map to 0
|
|
223
|
+
under map determined by images of generators
|
|
224
|
+
|
|
225
|
+
Endomorphism of power series ring::
|
|
226
|
+
|
|
227
|
+
sage: R.<t> = PowerSeriesRing(QQ, default_prec=10); R
|
|
228
|
+
Power Series Ring in t over Rational Field
|
|
229
|
+
sage: f = R.hom([t^2]); f
|
|
230
|
+
Ring endomorphism of Power Series Ring in t over Rational Field
|
|
231
|
+
Defn: t |--> t^2
|
|
232
|
+
sage: s = 1/(1 + t); s
|
|
233
|
+
1 - t + t^2 - t^3 + t^4 - t^5 + t^6 - t^7 + t^8 - t^9 + O(t^10)
|
|
234
|
+
sage: f(s)
|
|
235
|
+
1 - t^2 + t^4 - t^6 + t^8 - t^10 + t^12 - t^14 + t^16 - t^18 + O(t^20)
|
|
236
|
+
|
|
237
|
+
Frobenius on a power series ring over a finite field::
|
|
238
|
+
|
|
239
|
+
sage: R.<t> = PowerSeriesRing(GF(5))
|
|
240
|
+
sage: f = R.hom([t^5]); f
|
|
241
|
+
Ring endomorphism of Power Series Ring in t over Finite Field of size 5
|
|
242
|
+
Defn: t |--> t^5
|
|
243
|
+
sage: a = 2 + t + 3*t^2 + 4*t^3 + O(t^4)
|
|
244
|
+
sage: b = 1 + t + 2*t^2 + t^3 + O(t^5)
|
|
245
|
+
sage: f(a)
|
|
246
|
+
2 + t^5 + 3*t^10 + 4*t^15 + O(t^20)
|
|
247
|
+
sage: f(b)
|
|
248
|
+
1 + t^5 + 2*t^10 + t^15 + O(t^25)
|
|
249
|
+
sage: f(a*b)
|
|
250
|
+
2 + 3*t^5 + 3*t^10 + t^15 + O(t^20)
|
|
251
|
+
sage: f(a)*f(b)
|
|
252
|
+
2 + 3*t^5 + 3*t^10 + t^15 + O(t^20)
|
|
253
|
+
|
|
254
|
+
Homomorphism of Laurent series ring::
|
|
255
|
+
|
|
256
|
+
sage: R.<t> = LaurentSeriesRing(QQ, 10)
|
|
257
|
+
sage: f = R.hom([t^3 + t]); f
|
|
258
|
+
Ring endomorphism of Laurent Series Ring in t over Rational Field
|
|
259
|
+
Defn: t |--> t + t^3
|
|
260
|
+
sage: s = 2/t^2 + 1/(1 + t); s
|
|
261
|
+
2*t^-2 + 1 - t + t^2 - t^3 + t^4 - t^5 + t^6 - t^7 + t^8 - t^9 + O(t^10)
|
|
262
|
+
sage: f(s)
|
|
263
|
+
2*t^-2 - 3 - t + 7*t^2 - 2*t^3 - 5*t^4 - 4*t^5 + 16*t^6 - 9*t^7 + O(t^8)
|
|
264
|
+
sage: f = R.hom([t^3]); f
|
|
265
|
+
Ring endomorphism of Laurent Series Ring in t over Rational Field
|
|
266
|
+
Defn: t |--> t^3
|
|
267
|
+
sage: f(s)
|
|
268
|
+
2*t^-6 + 1 - t^3 + t^6 - t^9 + t^12 - t^15 + t^18 - t^21 + t^24 - t^27 + O(t^30)
|
|
269
|
+
|
|
270
|
+
Note that the homomorphism must result in a converging Laurent
|
|
271
|
+
series, so the valuation of the image of the generator must be
|
|
272
|
+
positive::
|
|
273
|
+
|
|
274
|
+
sage: R.hom([1/t])
|
|
275
|
+
Traceback (most recent call last):
|
|
276
|
+
...
|
|
277
|
+
ValueError: relations do not all (canonically) map to 0
|
|
278
|
+
under map determined by images of generators
|
|
279
|
+
sage: R.hom([1])
|
|
280
|
+
Traceback (most recent call last):
|
|
281
|
+
...
|
|
282
|
+
ValueError: relations do not all (canonically) map to 0
|
|
283
|
+
under map determined by images of generators
|
|
284
|
+
|
|
285
|
+
Complex conjugation on cyclotomic fields::
|
|
286
|
+
|
|
287
|
+
sage: # needs sage.rings.number_field
|
|
288
|
+
sage: K.<zeta7> = CyclotomicField(7)
|
|
289
|
+
sage: c = K.hom([1/zeta7]); c
|
|
290
|
+
Ring endomorphism of Cyclotomic Field of order 7 and degree 6
|
|
291
|
+
Defn: zeta7 |--> -zeta7^5 - zeta7^4 - zeta7^3 - zeta7^2 - zeta7 - 1
|
|
292
|
+
sage: a = (1+zeta7)^5; a
|
|
293
|
+
zeta7^5 + 5*zeta7^4 + 10*zeta7^3 + 10*zeta7^2 + 5*zeta7 + 1
|
|
294
|
+
sage: c(a)
|
|
295
|
+
5*zeta7^5 + 5*zeta7^4 - 4*zeta7^2 - 5*zeta7 - 4
|
|
296
|
+
sage: c(zeta7 + 1/zeta7) # this element is obviously fixed by inversion
|
|
297
|
+
-zeta7^5 - zeta7^4 - zeta7^3 - zeta7^2 - 1
|
|
298
|
+
sage: zeta7 + 1/zeta7
|
|
299
|
+
-zeta7^5 - zeta7^4 - zeta7^3 - zeta7^2 - 1
|
|
300
|
+
|
|
301
|
+
Embedding a number field into the reals::
|
|
302
|
+
|
|
303
|
+
sage: # needs sage.rings.number_field
|
|
304
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
305
|
+
sage: K.<beta> = NumberField(x^3 - 2)
|
|
306
|
+
sage: alpha = RR(2)^(1/3); alpha
|
|
307
|
+
1.25992104989487
|
|
308
|
+
sage: i = K.hom([alpha],check=False); i
|
|
309
|
+
Ring morphism:
|
|
310
|
+
From: Number Field in beta with defining polynomial x^3 - 2
|
|
311
|
+
To: Real Field with 53 bits of precision
|
|
312
|
+
Defn: beta |--> 1.25992104989487
|
|
313
|
+
sage: i(beta)
|
|
314
|
+
1.25992104989487
|
|
315
|
+
sage: i(beta^3)
|
|
316
|
+
2.00000000000000
|
|
317
|
+
sage: i(beta^2 + 1)
|
|
318
|
+
2.58740105196820
|
|
319
|
+
|
|
320
|
+
An example from Jim Carlson::
|
|
321
|
+
|
|
322
|
+
sage: K = QQ # by the way :-)
|
|
323
|
+
sage: R.<a,b,c,d> = K[]; R
|
|
324
|
+
Multivariate Polynomial Ring in a, b, c, d over Rational Field
|
|
325
|
+
sage: S.<u> = K[]; S
|
|
326
|
+
Univariate Polynomial Ring in u over Rational Field
|
|
327
|
+
sage: f = R.hom([0,0,0,u], S); f
|
|
328
|
+
Ring morphism:
|
|
329
|
+
From: Multivariate Polynomial Ring in a, b, c, d over Rational Field
|
|
330
|
+
To: Univariate Polynomial Ring in u over Rational Field
|
|
331
|
+
Defn: a |--> 0
|
|
332
|
+
b |--> 0
|
|
333
|
+
c |--> 0
|
|
334
|
+
d |--> u
|
|
335
|
+
sage: f(a + b + c + d)
|
|
336
|
+
u
|
|
337
|
+
sage: f((a+b+c+d)^2)
|
|
338
|
+
u^2
|
|
339
|
+
|
|
340
|
+
TESTS::
|
|
341
|
+
|
|
342
|
+
sage: H = Hom(ZZ, QQ)
|
|
343
|
+
sage: H == loads(dumps(H))
|
|
344
|
+
True
|
|
345
|
+
|
|
346
|
+
::
|
|
347
|
+
|
|
348
|
+
sage: # needs sage.rings.number_field
|
|
349
|
+
sage: K.<zeta7> = CyclotomicField(7)
|
|
350
|
+
sage: c = K.hom([1/zeta7])
|
|
351
|
+
sage: c == loads(dumps(c))
|
|
352
|
+
True
|
|
353
|
+
|
|
354
|
+
::
|
|
355
|
+
|
|
356
|
+
sage: R.<t> = PowerSeriesRing(GF(5))
|
|
357
|
+
sage: f = R.hom([t^5])
|
|
358
|
+
sage: f == loads(dumps(f))
|
|
359
|
+
True
|
|
360
|
+
|
|
361
|
+
We define the identity map in many possible ways. These should all
|
|
362
|
+
compare equal::
|
|
363
|
+
|
|
364
|
+
sage: # needs sage.rings.finite_rings
|
|
365
|
+
sage: k = GF(2)
|
|
366
|
+
sage: R.<x> = k[]
|
|
367
|
+
sage: F4.<a> = R.quo(x^2 + x + 1)
|
|
368
|
+
sage: H = End(F4)
|
|
369
|
+
sage: from sage.rings.morphism import *
|
|
370
|
+
sage: phi1 = H.identity(); phi1
|
|
371
|
+
Identity endomorphism of Univariate Quotient Polynomial Ring in a
|
|
372
|
+
over Finite Field of size 2 with modulus x^2 + x + 1
|
|
373
|
+
sage: phi2 = H([a]); phi2
|
|
374
|
+
Ring endomorphism of Univariate Quotient Polynomial Ring in a
|
|
375
|
+
over Finite Field of size 2 with modulus x^2 + x + 1
|
|
376
|
+
Defn: a |--> a
|
|
377
|
+
sage: phi3 = RingHomomorphism_from_base(H, R.hom([x])); phi3 # needs sage.libs.ntl
|
|
378
|
+
Ring endomorphism of Univariate Quotient Polynomial Ring in a
|
|
379
|
+
over Finite Field of size 2 with modulus x^2 + x + 1
|
|
380
|
+
Defn: Induced from base ring by
|
|
381
|
+
Ring endomorphism of Univariate Polynomial Ring in x
|
|
382
|
+
over Finite Field of size 2 (using GF2X)
|
|
383
|
+
Defn: x |--> x
|
|
384
|
+
sage: phi4 = RingHomomorphism_cover(H); phi4
|
|
385
|
+
Ring endomorphism of Univariate Quotient Polynomial Ring in a
|
|
386
|
+
over Finite Field of size 2 with modulus x^2 + x + 1
|
|
387
|
+
Defn: Natural quotient map
|
|
388
|
+
sage: phi5 = F4.frobenius_endomorphism() ^ 2; phi5
|
|
389
|
+
Frobenius endomorphism x |--> x^(2^2) of
|
|
390
|
+
Univariate Quotient Polynomial Ring in a
|
|
391
|
+
over Finite Field of size 2 with modulus x^2 + x + 1
|
|
392
|
+
sage: maps = [phi1, phi2, phi3, phi4, phi5] # needs sage.libs.ntl
|
|
393
|
+
sage: for f in maps: # needs sage.libs.ntl
|
|
394
|
+
....: for g in maps:
|
|
395
|
+
....: if f != g:
|
|
396
|
+
....: print("{} != {}".format(f, g))
|
|
397
|
+
"""
|
|
398
|
+
|
|
399
|
+
# ****************************************************************************
|
|
400
|
+
# Copyright (C) 2006 William Stein <wstein@gmail.com>
|
|
401
|
+
#
|
|
402
|
+
# This program is free software: you can redistribute it and/or modify
|
|
403
|
+
# it under the terms of the GNU General Public License as published by
|
|
404
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
405
|
+
# (at your option) any later version.
|
|
406
|
+
# https://www.gnu.org/licenses/
|
|
407
|
+
# ****************************************************************************
|
|
408
|
+
|
|
409
|
+
from sage.rings import ideal
|
|
410
|
+
import sage.structure.all
|
|
411
|
+
from sage.structure.richcmp cimport (richcmp, rich_to_bool)
|
|
412
|
+
from sage.misc.cachefunc import cached_method
|
|
413
|
+
from sage.categories.rings import Rings
|
|
414
|
+
from sage.categories.facade_sets import FacadeSets
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
cdef class RingMap(Morphism):
|
|
418
|
+
"""
|
|
419
|
+
Set-theoretic map between rings.
|
|
420
|
+
|
|
421
|
+
TESTS:
|
|
422
|
+
|
|
423
|
+
This is an abstract base class that is not directly instantiated,
|
|
424
|
+
but we will do so anyway as a test::
|
|
425
|
+
|
|
426
|
+
sage: f = sage.rings.morphism.RingMap(ZZ.Hom(ZZ))
|
|
427
|
+
sage: parent(f)
|
|
428
|
+
Set of Homomorphisms from Integer Ring to Integer Ring
|
|
429
|
+
sage: type(f)
|
|
430
|
+
<class 'sage.rings.morphism.RingMap'>
|
|
431
|
+
"""
|
|
432
|
+
def _repr_type(self):
|
|
433
|
+
"""
|
|
434
|
+
TESTS::
|
|
435
|
+
|
|
436
|
+
sage: f = sage.rings.morphism.RingMap(ZZ.Hom(ZZ))
|
|
437
|
+
sage: type(f)
|
|
438
|
+
<class 'sage.rings.morphism.RingMap'>
|
|
439
|
+
sage: f._repr_type()
|
|
440
|
+
'Set-theoretic ring'
|
|
441
|
+
sage: f
|
|
442
|
+
Set-theoretic ring endomorphism of Integer Ring
|
|
443
|
+
"""
|
|
444
|
+
return "Set-theoretic ring"
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
cdef class RingMap_lift(RingMap):
|
|
448
|
+
r"""
|
|
449
|
+
Given rings `R` and `S` such that for any
|
|
450
|
+
`x \in R` the function ``x.lift()`` is an
|
|
451
|
+
element that naturally coerces to `S`, this returns the
|
|
452
|
+
set-theoretic ring map `R \to S` sending `x` to
|
|
453
|
+
``x.lift()``.
|
|
454
|
+
|
|
455
|
+
EXAMPLES::
|
|
456
|
+
|
|
457
|
+
sage: R.<x,y> = QQ[]
|
|
458
|
+
sage: S.<xbar,ybar> = R.quo( (x^2 + y^2, y) ) # needs sage.libs.singular
|
|
459
|
+
sage: S.lift() # needs sage.libs.singular
|
|
460
|
+
Set-theoretic ring morphism:
|
|
461
|
+
From: Quotient of Multivariate Polynomial Ring in x, y
|
|
462
|
+
over Rational Field by the ideal (x^2 + y^2, y)
|
|
463
|
+
To: Multivariate Polynomial Ring in x, y over Rational Field
|
|
464
|
+
Defn: Choice of lifting map
|
|
465
|
+
sage: S.lift() == 0 # needs sage.libs.singular
|
|
466
|
+
False
|
|
467
|
+
|
|
468
|
+
Since :issue:`11068`, it is possible to create
|
|
469
|
+
quotient rings of non-commutative rings by two-sided
|
|
470
|
+
ideals. It was needed to modify :class:`RingMap_lift`
|
|
471
|
+
so that rings can be accepted that are no instances
|
|
472
|
+
of :class:`sage.rings.ring.Ring`, as in the following
|
|
473
|
+
example::
|
|
474
|
+
|
|
475
|
+
sage: # needs sage.modules sage.rings.finite_rings
|
|
476
|
+
sage: MS = MatrixSpace(GF(5), 2, 2)
|
|
477
|
+
sage: I = MS * [MS.0*MS.1, MS.2+MS.3] * MS
|
|
478
|
+
sage: Q = MS.quo(I)
|
|
479
|
+
sage: Q.0*Q.1 # indirect doctest
|
|
480
|
+
[0 1]
|
|
481
|
+
[0 0]
|
|
482
|
+
"""
|
|
483
|
+
def __init__(self, R, S):
|
|
484
|
+
"""
|
|
485
|
+
Create a lifting ring map.
|
|
486
|
+
|
|
487
|
+
EXAMPLES::
|
|
488
|
+
|
|
489
|
+
sage: f = Zmod(8).lift() # indirect doctest
|
|
490
|
+
sage: f(3)
|
|
491
|
+
3
|
|
492
|
+
sage: type(f(3))
|
|
493
|
+
<class 'sage.rings.integer.Integer'>
|
|
494
|
+
sage: type(f)
|
|
495
|
+
<class 'sage.rings.morphism.RingMap_lift'>
|
|
496
|
+
|
|
497
|
+
An invalid example::
|
|
498
|
+
|
|
499
|
+
sage: GF9.<one, a> = GaussianIntegers().quotient(3) # needs sage.rings.number_field
|
|
500
|
+
sage: from sage.rings.morphism import RingMap_lift
|
|
501
|
+
sage: RingMap_lift(GF9, ZZ) # needs sage.rings.number_field
|
|
502
|
+
Traceback (most recent call last):
|
|
503
|
+
...
|
|
504
|
+
TypeError: no canonical coercion from Number Field in I
|
|
505
|
+
with defining polynomial x^2 + 1 with I = 1*I to Integer Ring
|
|
506
|
+
"""
|
|
507
|
+
self.S = <Parent?>S
|
|
508
|
+
x = <Element?>R(0).lift()
|
|
509
|
+
f = self.S.coerce_map_from(x._parent)
|
|
510
|
+
if f is None:
|
|
511
|
+
raise TypeError(f"no canonical coercion from {x._parent} to {S}")
|
|
512
|
+
self.to_S = f
|
|
513
|
+
|
|
514
|
+
from sage.categories.sets_cat import Sets
|
|
515
|
+
H = R.Hom(S, Sets())
|
|
516
|
+
RingMap.__init__(self, H)
|
|
517
|
+
|
|
518
|
+
cdef _update_slots(self, dict _slots):
|
|
519
|
+
"""
|
|
520
|
+
Helper for copying and pickling.
|
|
521
|
+
|
|
522
|
+
EXAMPLES::
|
|
523
|
+
|
|
524
|
+
sage: f = Zmod(8).lift()
|
|
525
|
+
sage: g = copy(f) # indirect doctest
|
|
526
|
+
sage: g(3) == f(3)
|
|
527
|
+
True
|
|
528
|
+
sage: f == g
|
|
529
|
+
True
|
|
530
|
+
sage: f is g
|
|
531
|
+
False
|
|
532
|
+
"""
|
|
533
|
+
self.S = _slots['S']
|
|
534
|
+
self.to_S = _slots['to_S']
|
|
535
|
+
Morphism._update_slots(self, _slots)
|
|
536
|
+
|
|
537
|
+
cdef dict _extra_slots(self):
|
|
538
|
+
"""
|
|
539
|
+
Helper for copying and pickling.
|
|
540
|
+
|
|
541
|
+
EXAMPLES::
|
|
542
|
+
|
|
543
|
+
sage: f = Zmod(8).lift()
|
|
544
|
+
sage: g = copy(f) # indirect doctest
|
|
545
|
+
sage: g(3) == f(3)
|
|
546
|
+
True
|
|
547
|
+
"""
|
|
548
|
+
slots = Morphism._extra_slots(self)
|
|
549
|
+
slots['S'] = self.S
|
|
550
|
+
slots['to_S'] = self.to_S
|
|
551
|
+
return slots
|
|
552
|
+
|
|
553
|
+
cpdef _richcmp_(self, other, int op):
|
|
554
|
+
"""
|
|
555
|
+
Compare a ring lifting maps ``self`` to ``other``.
|
|
556
|
+
|
|
557
|
+
Ring lifting maps never compare equal to any other data type.
|
|
558
|
+
If ``other`` is a ring lifting maps, the parents of ``self`` and
|
|
559
|
+
``other`` are compared.
|
|
560
|
+
|
|
561
|
+
EXAMPLES::
|
|
562
|
+
|
|
563
|
+
sage: f = Zmod(8).lift()
|
|
564
|
+
sage: g = Zmod(10).lift()
|
|
565
|
+
sage: f == f
|
|
566
|
+
True
|
|
567
|
+
sage: f == g
|
|
568
|
+
False
|
|
569
|
+
|
|
570
|
+
Verify that :issue:`5758` has been fixed::
|
|
571
|
+
|
|
572
|
+
sage: Zmod(8).lift() == 1
|
|
573
|
+
False
|
|
574
|
+
"""
|
|
575
|
+
if not isinstance(other, RingMap_lift):
|
|
576
|
+
# Generic comparison
|
|
577
|
+
return RingMap._richcmp_(self, other, op)
|
|
578
|
+
# Two lifting maps with the same parent must be equal
|
|
579
|
+
return rich_to_bool(op, 0)
|
|
580
|
+
|
|
581
|
+
def __hash__(self):
|
|
582
|
+
"""
|
|
583
|
+
Return the hash of this morphism.
|
|
584
|
+
|
|
585
|
+
TESTS::
|
|
586
|
+
|
|
587
|
+
sage: f = Zmod(8).lift()
|
|
588
|
+
sage: type(f)
|
|
589
|
+
<class 'sage.rings.morphism.RingMap_lift'>
|
|
590
|
+
sage: hash(f) == hash(f)
|
|
591
|
+
True
|
|
592
|
+
sage: {f: 1}[f]
|
|
593
|
+
1
|
|
594
|
+
sage: g = Zmod(10).lift()
|
|
595
|
+
sage: hash(f) == hash(g)
|
|
596
|
+
False
|
|
597
|
+
"""
|
|
598
|
+
return hash((self.domain(), self.codomain()))
|
|
599
|
+
|
|
600
|
+
def _repr_defn(self):
|
|
601
|
+
"""
|
|
602
|
+
Used in printing out lifting maps.
|
|
603
|
+
|
|
604
|
+
EXAMPLES::
|
|
605
|
+
|
|
606
|
+
sage: f = Zmod(8).lift()
|
|
607
|
+
sage: f._repr_defn()
|
|
608
|
+
'Choice of lifting map'
|
|
609
|
+
sage: f
|
|
610
|
+
Set-theoretic ring morphism:
|
|
611
|
+
From: Ring of integers modulo 8
|
|
612
|
+
To: Integer Ring
|
|
613
|
+
Defn: Choice of lifting map
|
|
614
|
+
"""
|
|
615
|
+
return "Choice of lifting map"
|
|
616
|
+
|
|
617
|
+
cpdef Element _call_(self, x):
|
|
618
|
+
"""
|
|
619
|
+
Evaluate this function at ``x``.
|
|
620
|
+
|
|
621
|
+
EXAMPLES::
|
|
622
|
+
|
|
623
|
+
sage: f = Zmod(8).lift()
|
|
624
|
+
sage: type(f)
|
|
625
|
+
<class 'sage.rings.morphism.RingMap_lift'>
|
|
626
|
+
sage: f(-1) # indirect doctest
|
|
627
|
+
7
|
|
628
|
+
sage: type(f(-1))
|
|
629
|
+
<class 'sage.rings.integer.Integer'>
|
|
630
|
+
"""
|
|
631
|
+
return self.to_S(x.lift())
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
cdef class RingHomomorphism(RingMap):
|
|
635
|
+
"""
|
|
636
|
+
Homomorphism of rings.
|
|
637
|
+
"""
|
|
638
|
+
def __init__(self, parent):
|
|
639
|
+
"""
|
|
640
|
+
Initialize ``self``.
|
|
641
|
+
|
|
642
|
+
EXAMPLES::
|
|
643
|
+
|
|
644
|
+
sage: f = ZZ.hom(Zp(3)); f # needs sage.rings.padics
|
|
645
|
+
Ring morphism:
|
|
646
|
+
From: Integer Ring
|
|
647
|
+
To: 3-adic Ring with capped relative precision 20
|
|
648
|
+
|
|
649
|
+
TESTS::
|
|
650
|
+
|
|
651
|
+
sage: isinstance(f, sage.rings.morphism.RingHomomorphism) # needs sage.rings.padics
|
|
652
|
+
True
|
|
653
|
+
"""
|
|
654
|
+
from sage.rings.homset import RingHomset_generic
|
|
655
|
+
if not isinstance(parent, RingHomset_generic):
|
|
656
|
+
raise TypeError("parent must be a ring homset")
|
|
657
|
+
RingMap.__init__(self, parent)
|
|
658
|
+
|
|
659
|
+
def _repr_type(self):
|
|
660
|
+
"""
|
|
661
|
+
Used internally in printing this morphism.
|
|
662
|
+
|
|
663
|
+
TESTS::
|
|
664
|
+
|
|
665
|
+
sage: ZZ.hom(Zp(3))._repr_type() # needs sage.rings.padics
|
|
666
|
+
'Ring'
|
|
667
|
+
"""
|
|
668
|
+
return "Ring"
|
|
669
|
+
|
|
670
|
+
def _set_lift(self, lift):
|
|
671
|
+
r"""
|
|
672
|
+
Used internally to define a lifting map associated to
|
|
673
|
+
this homomorphism, which goes in the other direction. I.e.,
|
|
674
|
+
if ``self`` is from `R` to `S`, then the lift must be a set-theoretic
|
|
675
|
+
map from `S` to `R` such that ``self(lift(x)) == x``.
|
|
676
|
+
|
|
677
|
+
INPUT:
|
|
678
|
+
|
|
679
|
+
- ``lift`` -- a ring map
|
|
680
|
+
|
|
681
|
+
OUTPUT: changes the state of ``self``
|
|
682
|
+
|
|
683
|
+
EXAMPLES::
|
|
684
|
+
|
|
685
|
+
sage: R = ZZ.quo(3*ZZ)
|
|
686
|
+
sage: pi = R.cover() # indirect doctest
|
|
687
|
+
sage: pi.lift()
|
|
688
|
+
Set-theoretic ring morphism:
|
|
689
|
+
From: Ring of integers modulo 3
|
|
690
|
+
To: Integer Ring
|
|
691
|
+
Defn: Choice of lifting map
|
|
692
|
+
"""
|
|
693
|
+
if lift.domain() != self.codomain():
|
|
694
|
+
raise TypeError("lift must have correct domain")
|
|
695
|
+
if lift.codomain() != self.domain():
|
|
696
|
+
raise TypeError("lift must have correct codomain")
|
|
697
|
+
self._lift = lift
|
|
698
|
+
|
|
699
|
+
cdef _update_slots(self, dict _slots):
|
|
700
|
+
"""
|
|
701
|
+
Helper for copying and pickling.
|
|
702
|
+
|
|
703
|
+
EXAMPLES::
|
|
704
|
+
|
|
705
|
+
sage: f = ZZ.hom(Zmod(6))
|
|
706
|
+
sage: g = copy(f) # indirect doctest
|
|
707
|
+
sage: g == f
|
|
708
|
+
True
|
|
709
|
+
sage: g is f
|
|
710
|
+
False
|
|
711
|
+
sage: g(7)
|
|
712
|
+
1
|
|
713
|
+
"""
|
|
714
|
+
if '_lift' in _slots:
|
|
715
|
+
self._lift = _slots['_lift']
|
|
716
|
+
Morphism._update_slots(self, _slots)
|
|
717
|
+
|
|
718
|
+
cdef dict _extra_slots(self):
|
|
719
|
+
"""
|
|
720
|
+
Helper for copying and pickling.
|
|
721
|
+
|
|
722
|
+
EXAMPLES::
|
|
723
|
+
|
|
724
|
+
sage: f = ZZ.hom(Zmod(6))
|
|
725
|
+
sage: g = copy(f) # indirect doctest
|
|
726
|
+
sage: g == f
|
|
727
|
+
True
|
|
728
|
+
sage: g is f
|
|
729
|
+
False
|
|
730
|
+
sage: g(7)
|
|
731
|
+
1
|
|
732
|
+
"""
|
|
733
|
+
slots = Morphism._extra_slots(self)
|
|
734
|
+
try:
|
|
735
|
+
slots['_lift'] = self._lift
|
|
736
|
+
except AttributeError:
|
|
737
|
+
pass
|
|
738
|
+
return slots
|
|
739
|
+
|
|
740
|
+
def _composition_(self, right, homset):
|
|
741
|
+
"""
|
|
742
|
+
If ``homset`` is a homset of rings and ``right`` is a
|
|
743
|
+
ring homomorphism given by the images of generators,
|
|
744
|
+
(indirectly in the case of homomorphisms from relative
|
|
745
|
+
number fields), the composition with ``self`` will be
|
|
746
|
+
of the appropriate type.
|
|
747
|
+
|
|
748
|
+
Otherwise, a formal composite map is returned.
|
|
749
|
+
|
|
750
|
+
EXAMPLES::
|
|
751
|
+
|
|
752
|
+
sage: R.<x,y> = QQ[]
|
|
753
|
+
sage: S.<a,b> = QQ[]
|
|
754
|
+
sage: f = R.hom([a+b,a-b])
|
|
755
|
+
sage: g = S.hom(Frac(S))
|
|
756
|
+
sage: g*f # indirect doctest
|
|
757
|
+
Composite map:
|
|
758
|
+
From: Multivariate Polynomial Ring in x, y over Rational Field
|
|
759
|
+
To: Fraction Field of Multivariate Polynomial Ring in a, b over Rational Field
|
|
760
|
+
Defn: Ring morphism:
|
|
761
|
+
From: Multivariate Polynomial Ring in x, y over Rational Field
|
|
762
|
+
To: Multivariate Polynomial Ring in a, b over Rational Field
|
|
763
|
+
Defn: x |--> a + b
|
|
764
|
+
y |--> a - b
|
|
765
|
+
then
|
|
766
|
+
Coercion map:
|
|
767
|
+
From: Multivariate Polynomial Ring in a, b over Rational Field
|
|
768
|
+
To: Fraction Field of Multivariate Polynomial Ring in a, b over Rational Field
|
|
769
|
+
|
|
770
|
+
When ``right`` is defined by the images of generators, the
|
|
771
|
+
result has the type of a homomorphism between its domain and
|
|
772
|
+
codomain::
|
|
773
|
+
|
|
774
|
+
sage: C = CyclotomicField(24) # needs sage.rings.number_field
|
|
775
|
+
sage: f = End(C)[1] # needs sage.rings.number_field
|
|
776
|
+
sage: type(f*f) == type(f) # needs sage.rings.number_field
|
|
777
|
+
True
|
|
778
|
+
|
|
779
|
+
An example where the domain of ``right`` is a relative number field::
|
|
780
|
+
|
|
781
|
+
sage: PQ.<X> = QQ[]
|
|
782
|
+
sage: K.<a, b> = NumberField([X^2 - 2, X^2 - 3]) # needs sage.rings.number_field
|
|
783
|
+
sage: e, u, v, w = End(K) # needs sage.rings.number_field
|
|
784
|
+
sage: u*v # needs sage.rings.number_field
|
|
785
|
+
Relative number field endomorphism of
|
|
786
|
+
Number Field in a with defining polynomial X^2 - 2 over its base field
|
|
787
|
+
Defn: a |--> -a
|
|
788
|
+
b |--> b
|
|
789
|
+
|
|
790
|
+
An example where ``right`` is not a ring homomorphism::
|
|
791
|
+
|
|
792
|
+
sage: from sage.categories.morphism import SetMorphism
|
|
793
|
+
sage: h = SetMorphism(Hom(R,S,Rings()), lambda p: p[0])
|
|
794
|
+
sage: g*h
|
|
795
|
+
Composite map:
|
|
796
|
+
From: Multivariate Polynomial Ring in x, y over Rational Field
|
|
797
|
+
To: Fraction Field of Multivariate Polynomial Ring in a, b over Rational Field
|
|
798
|
+
Defn: Generic morphism:
|
|
799
|
+
From: Multivariate Polynomial Ring in x, y over Rational Field
|
|
800
|
+
To: Multivariate Polynomial Ring in a, b over Rational Field
|
|
801
|
+
then
|
|
802
|
+
Coercion map:
|
|
803
|
+
From: Multivariate Polynomial Ring in a, b over Rational Field
|
|
804
|
+
To: Fraction Field of
|
|
805
|
+
Multivariate Polynomial Ring in a, b over Rational Field
|
|
806
|
+
|
|
807
|
+
We check that composition works when there is a base map::
|
|
808
|
+
|
|
809
|
+
sage: # needs sage.rings.finite_rings
|
|
810
|
+
sage: R.<x> = ZZ[]
|
|
811
|
+
sage: K.<a> = GF(7^2)
|
|
812
|
+
sage: L.<u> = K.extension(x^3 - 3)
|
|
813
|
+
sage: phi = L.hom([u^7], base_map=K.frobenius_endomorphism())
|
|
814
|
+
sage: phi
|
|
815
|
+
Ring endomorphism of Univariate Quotient Polynomial Ring in u
|
|
816
|
+
over Finite Field in a of size 7^2 with modulus u^3 + 4
|
|
817
|
+
Defn: u |--> 2*u
|
|
818
|
+
with map of base ring
|
|
819
|
+
sage: psi = phi^3; psi
|
|
820
|
+
Ring endomorphism of Univariate Quotient Polynomial Ring in u
|
|
821
|
+
over Finite Field in a of size 7^2 with modulus u^3 + 4
|
|
822
|
+
Defn: u |--> u
|
|
823
|
+
with map of base ring
|
|
824
|
+
sage: psi(a) == phi(phi(phi(a)))
|
|
825
|
+
True
|
|
826
|
+
|
|
827
|
+
It also works when the image of the base map is not contained within the base ring of the codomain::
|
|
828
|
+
|
|
829
|
+
sage: S.<x> = QQ[]
|
|
830
|
+
sage: T.<y> = S[]
|
|
831
|
+
sage: cc = S.hom([x + y])
|
|
832
|
+
sage: f = T.hom([x - y], base_map=cc)
|
|
833
|
+
sage: f*f
|
|
834
|
+
Ring endomorphism of Univariate Polynomial Ring in y
|
|
835
|
+
over Univariate Polynomial Ring in x over Rational Field
|
|
836
|
+
Defn: y |--> 2*y
|
|
837
|
+
with map of base ring
|
|
838
|
+
sage: (f*f).base_map()
|
|
839
|
+
Ring morphism:
|
|
840
|
+
From: Univariate Polynomial Ring in x over Rational Field
|
|
841
|
+
To: Univariate Polynomial Ring in y over
|
|
842
|
+
Univariate Polynomial Ring in x over Rational Field
|
|
843
|
+
Defn: x |--> 2*x
|
|
844
|
+
with map of base ring
|
|
845
|
+
|
|
846
|
+
sage: S.<x> = QQ[]
|
|
847
|
+
sage: T.<y> = S[]
|
|
848
|
+
sage: cc = S.hom([x+y])
|
|
849
|
+
sage: f = T.hom([x-y], base_map=cc)
|
|
850
|
+
sage: g = T.hom([x-y])
|
|
851
|
+
sage: (f*g)(x)
|
|
852
|
+
y + x
|
|
853
|
+
sage: f(g(x))
|
|
854
|
+
y + x
|
|
855
|
+
|
|
856
|
+
AUTHORS:
|
|
857
|
+
|
|
858
|
+
- Simon King (2010-05)
|
|
859
|
+
- Francis Clarke (2011-02)
|
|
860
|
+
- David Roe (2019-10)
|
|
861
|
+
"""
|
|
862
|
+
from sage.categories.morphism import IdentityMorphism
|
|
863
|
+
from sage.categories.rings import Rings
|
|
864
|
+
if isinstance(right, IdentityMorphism):
|
|
865
|
+
return self
|
|
866
|
+
if homset.homset_category().is_subcategory(Rings()):
|
|
867
|
+
if isinstance(right, RingHomomorphism_im_gens):
|
|
868
|
+
rbm = right.base_map()
|
|
869
|
+
kwds = {'check': False}
|
|
870
|
+
if rbm is None and isinstance(self, RingHomomorphism_im_gens) and self.base_map() is not None:
|
|
871
|
+
rbm = right.codomain().coerce_map_from(right.domain().base_ring())
|
|
872
|
+
if rbm is not None:
|
|
873
|
+
kwds['base_map'] = self * rbm
|
|
874
|
+
try:
|
|
875
|
+
return homset([self(g) for g in right.im_gens()], **kwds)
|
|
876
|
+
except ValueError:
|
|
877
|
+
pass
|
|
878
|
+
try:
|
|
879
|
+
from sage.rings.number_field.morphism import RelativeNumberFieldHomomorphism_from_abs
|
|
880
|
+
except ImportError:
|
|
881
|
+
pass
|
|
882
|
+
else:
|
|
883
|
+
if isinstance(right, RelativeNumberFieldHomomorphism_from_abs):
|
|
884
|
+
try:
|
|
885
|
+
return homset(self*right.abs_hom())
|
|
886
|
+
except ValueError:
|
|
887
|
+
pass
|
|
888
|
+
return sage.categories.map.Map._composition_(self, right, homset)
|
|
889
|
+
|
|
890
|
+
def pushforward(self, I):
|
|
891
|
+
"""
|
|
892
|
+
Return the pushforward of the ideal `I` under this ring
|
|
893
|
+
homomorphism.
|
|
894
|
+
|
|
895
|
+
EXAMPLES::
|
|
896
|
+
|
|
897
|
+
sage: R.<x,y> = QQ[]; S.<xx,yy> = R.quo([x^2, y^2]); f = S.cover() # needs sage.libs.singular
|
|
898
|
+
sage: f.pushforward(R.ideal([x, 3*x + x*y + y^2])) # needs sage.libs.singular
|
|
899
|
+
Ideal (xx, xx*yy + 3*xx) of Quotient of Multivariate Polynomial Ring
|
|
900
|
+
in x, y over Rational Field by the ideal (x^2, y^2)
|
|
901
|
+
"""
|
|
902
|
+
if not isinstance(I, ideal.Ideal_generic):
|
|
903
|
+
raise TypeError("I must be an ideal")
|
|
904
|
+
R = self.codomain()
|
|
905
|
+
return R.ideal([self(y) for y in I.gens()])
|
|
906
|
+
|
|
907
|
+
def inverse_image(self, I):
|
|
908
|
+
"""
|
|
909
|
+
Return the inverse image of an ideal or an element in the codomain
|
|
910
|
+
of this ring homomorphism.
|
|
911
|
+
|
|
912
|
+
INPUT:
|
|
913
|
+
|
|
914
|
+
- ``I`` -- an ideal or element in the codomain
|
|
915
|
+
|
|
916
|
+
OUTPUT:
|
|
917
|
+
|
|
918
|
+
For an ideal `I` in the codomain, this returns the largest ideal in the
|
|
919
|
+
domain whose image is contained in `I`.
|
|
920
|
+
|
|
921
|
+
Given an element `b` in the codomain, this returns an arbitrary element
|
|
922
|
+
`a` in the domain such that ``self(a) = b`` if one such exists.
|
|
923
|
+
The element `a` is unique if this ring homomorphism is injective.
|
|
924
|
+
|
|
925
|
+
EXAMPLES::
|
|
926
|
+
|
|
927
|
+
sage: R.<x,y,z> = QQ[]
|
|
928
|
+
sage: S.<u,v> = QQ[]
|
|
929
|
+
sage: f = R.hom([u^2, u*v, v^2], S)
|
|
930
|
+
sage: I = S.ideal([u^6, u^5*v, u^4*v^2, u^3*v^3])
|
|
931
|
+
sage: J = f.inverse_image(I); J # needs sage.libs.singular
|
|
932
|
+
Ideal (y^2 - x*z, x*y*z, x^2*z, x^2*y, x^3)
|
|
933
|
+
of Multivariate Polynomial Ring in x, y, z over Rational Field
|
|
934
|
+
sage: f(J) == I # needs sage.libs.singular
|
|
935
|
+
True
|
|
936
|
+
|
|
937
|
+
Under the above homomorphism, there exists an inverse image for
|
|
938
|
+
every element that only involves monomials of even degree::
|
|
939
|
+
|
|
940
|
+
sage: [f.inverse_image(p) for p in [u^2, u^4, u*v + u^3*v^3]] # needs sage.libs.singular
|
|
941
|
+
[x, x^2, x*y*z + y]
|
|
942
|
+
sage: f.inverse_image(u*v^2) # needs sage.libs.singular
|
|
943
|
+
Traceback (most recent call last):
|
|
944
|
+
...
|
|
945
|
+
ValueError: element u*v^2 does not have preimage
|
|
946
|
+
|
|
947
|
+
The image of the inverse image ideal can be strictly smaller than the
|
|
948
|
+
original ideal::
|
|
949
|
+
|
|
950
|
+
sage: # needs sage.libs.singular sage.rings.number_field
|
|
951
|
+
sage: S.<u,v> = QQ['u,v'].quotient('v^2 - 2')
|
|
952
|
+
sage: f = QuadraticField(2).hom([v], S)
|
|
953
|
+
sage: I = S.ideal(u + v)
|
|
954
|
+
sage: J = f.inverse_image(I)
|
|
955
|
+
sage: J.is_zero()
|
|
956
|
+
True
|
|
957
|
+
sage: f(J) < I
|
|
958
|
+
True
|
|
959
|
+
|
|
960
|
+
Fractional ideals are not yet fully supported::
|
|
961
|
+
|
|
962
|
+
sage: # needs sage.rings.number_field
|
|
963
|
+
sage: K.<a> = NumberField(QQ['x']('x^2+2'))
|
|
964
|
+
sage: f = K.hom([-a], K)
|
|
965
|
+
sage: I = K.ideal([a + 1])
|
|
966
|
+
sage: f.inverse_image(I) # needs sage.libs.singular
|
|
967
|
+
Traceback (most recent call last):
|
|
968
|
+
...
|
|
969
|
+
NotImplementedError: inverse image not implemented...
|
|
970
|
+
sage: f.inverse_image(K.ideal(0)).is_zero() # needs sage.libs.singular
|
|
971
|
+
True
|
|
972
|
+
sage: f.inverse()(I) # needs sage.libs.singular sage.rings.padics
|
|
973
|
+
Fractional ideal (-a + 1)
|
|
974
|
+
|
|
975
|
+
ALGORITHM:
|
|
976
|
+
|
|
977
|
+
By default, this computes a Gröbner basis of an ideal related to the
|
|
978
|
+
graph of the ring homomorphism.
|
|
979
|
+
|
|
980
|
+
REFERENCES:
|
|
981
|
+
|
|
982
|
+
- Proposition 2.5.12 [DS2009]_
|
|
983
|
+
|
|
984
|
+
TESTS::
|
|
985
|
+
|
|
986
|
+
sage: ZZ.hom(Zp(2)).inverse_image(ZZ.ideal(2)) # needs sage.rings.padics
|
|
987
|
+
Traceback (most recent call last):
|
|
988
|
+
...
|
|
989
|
+
ValueError: not an ideal or element in codomain 2-adic Ring
|
|
990
|
+
with capped relative precision 20
|
|
991
|
+
|
|
992
|
+
::
|
|
993
|
+
|
|
994
|
+
sage: ZZ.hom(Zp(2)).inverse_image(Zp(2).ideal(2)) # needs sage.rings.padics
|
|
995
|
+
Traceback (most recent call last):
|
|
996
|
+
...
|
|
997
|
+
NotImplementedError: base rings must be equal
|
|
998
|
+
"""
|
|
999
|
+
from sage.categories.ring_ideals import RingIdeals
|
|
1000
|
+
B = self.codomain()
|
|
1001
|
+
if I in RingIdeals(B):
|
|
1002
|
+
return self._inverse_image_ideal(I)
|
|
1003
|
+
elif I in B:
|
|
1004
|
+
return self._inverse_image_element(I)
|
|
1005
|
+
else:
|
|
1006
|
+
raise ValueError("not an ideal or element in codomain %s" % B)
|
|
1007
|
+
|
|
1008
|
+
def _inverse_image_ideal(self, I):
|
|
1009
|
+
"""
|
|
1010
|
+
Return the inverse image of an ideal under this ring homomorphism.
|
|
1011
|
+
|
|
1012
|
+
EXAMPLES::
|
|
1013
|
+
|
|
1014
|
+
sage: # needs sage.rings.number_field sage.symbolic
|
|
1015
|
+
sage: R.<x,y> = QQbar[]
|
|
1016
|
+
sage: f = R.hom([x, QQbar(i) * x + y^2], R)
|
|
1017
|
+
sage: I = R.ideal(y^3)
|
|
1018
|
+
sage: J = f._inverse_image_ideal(I); J
|
|
1019
|
+
Ideal (x^2 + 2*I*x*y - y^2)
|
|
1020
|
+
of Multivariate Polynomial Ring in x, y over Algebraic Field
|
|
1021
|
+
sage: f(J) <= I
|
|
1022
|
+
True
|
|
1023
|
+
|
|
1024
|
+
TESTS:
|
|
1025
|
+
|
|
1026
|
+
Check that :issue:`31367` is fixed::
|
|
1027
|
+
|
|
1028
|
+
sage: A.<t> = QQ[]
|
|
1029
|
+
sage: B.<x,y> = QQ['x,y'].quotient('y') # needs sage.libs.singular
|
|
1030
|
+
sage: f = A.hom([x], B) # needs sage.libs.singular
|
|
1031
|
+
sage: f.kernel() # needs sage.libs.singular
|
|
1032
|
+
Principal ideal (0) of Univariate Polynomial Ring in t over Rational Field
|
|
1033
|
+
|
|
1034
|
+
::
|
|
1035
|
+
|
|
1036
|
+
sage: A.<t,u> = QQ[]
|
|
1037
|
+
sage: B.<x,y,z> = QQ['x,y,z'].quotient('z') # needs sage.libs.singular
|
|
1038
|
+
sage: f = A.hom([x, y], B) # needs sage.libs.singular
|
|
1039
|
+
sage: f.kernel() # needs sage.libs.singular
|
|
1040
|
+
Ideal (0) of Multivariate Polynomial Ring in t, u over Rational Field
|
|
1041
|
+
"""
|
|
1042
|
+
from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_generic
|
|
1043
|
+
from sage.rings.quotient_ring import QuotientRing_nc
|
|
1044
|
+
from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base
|
|
1045
|
+
from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic
|
|
1046
|
+
B = self.codomain()
|
|
1047
|
+
graph, from_B, to_A = self._graph_ideal()
|
|
1048
|
+
Q = graph.ring()
|
|
1049
|
+
gens_B = Q.gens()[:B.ngens()]
|
|
1050
|
+
if I.is_zero():
|
|
1051
|
+
# avoid adding the 0-ideal to the graph ideal in order to benefit
|
|
1052
|
+
# from a cached Gröbner basis
|
|
1053
|
+
graph_I = graph
|
|
1054
|
+
elif isinstance(B, (MPolynomialRing_base,
|
|
1055
|
+
PolynomialRing_generic,
|
|
1056
|
+
QuotientRing_nc,
|
|
1057
|
+
PolynomialQuotientRing_generic)):
|
|
1058
|
+
graph_I = graph + from_B(I)
|
|
1059
|
+
else:
|
|
1060
|
+
# nonzero fractional ideals of number fields not yet supported
|
|
1061
|
+
raise NotImplementedError("inverse image not implemented "
|
|
1062
|
+
"for ideals in %s" % B)
|
|
1063
|
+
if isinstance(Q, QuotientRing_nc):
|
|
1064
|
+
# elimination_ideal does not work with quotient rings, so
|
|
1065
|
+
# switch to the cover ring
|
|
1066
|
+
gens_B_lifted = Q.cover_ring().gens()[:B.ngens()]
|
|
1067
|
+
graph_I_lifted = Q.cover()._inverse_image_ideal(graph_I)
|
|
1068
|
+
preimage = graph_I_lifted.elimination_ideal(gens_B_lifted)
|
|
1069
|
+
_, ambient_to_A = to_A
|
|
1070
|
+
return ambient_to_A(preimage)
|
|
1071
|
+
else:
|
|
1072
|
+
preimage = graph_I.elimination_ideal(gens_B)
|
|
1073
|
+
return to_A(preimage)
|
|
1074
|
+
|
|
1075
|
+
def _inverse_image_element(self, b):
|
|
1076
|
+
"""
|
|
1077
|
+
Return an element `a` such that ``self(a) = b`` if one such exists.
|
|
1078
|
+
|
|
1079
|
+
TESTS:
|
|
1080
|
+
|
|
1081
|
+
A degenerate case::
|
|
1082
|
+
|
|
1083
|
+
sage: R.<x,y> = QQ['x,y'].quotient(1) # needs sage.libs.singular
|
|
1084
|
+
sage: f = R.hom([y, x], R) # needs sage.libs.singular
|
|
1085
|
+
sage: f.inverse_image(x), f.inverse_image(y) # indirect doctest # needs sage.libs.singular
|
|
1086
|
+
(0, 0)
|
|
1087
|
+
|
|
1088
|
+
Check cases involving quotient rings in which a generator is constant
|
|
1089
|
+
(:issue:`31178`)::
|
|
1090
|
+
|
|
1091
|
+
sage: # needs sage.libs.singular
|
|
1092
|
+
sage: R.<x,y> = QQ[]
|
|
1093
|
+
sage: B.<c,d> = R.quotient(R.ideal(x))
|
|
1094
|
+
sage: g = R.hom([d^2, d^3], B)
|
|
1095
|
+
sage: g.inverse_image(d)
|
|
1096
|
+
Traceback (most recent call last):
|
|
1097
|
+
...
|
|
1098
|
+
ValueError: element d does not have preimage
|
|
1099
|
+
sage: g.inverse_image(d^2)
|
|
1100
|
+
x
|
|
1101
|
+
sage: g.inverse_image(d^3)
|
|
1102
|
+
y
|
|
1103
|
+
sage: A.<a,b> = R.quotient(R.ideal(y^2 - x^3))
|
|
1104
|
+
sage: h = A.hom([d^2, d^3], B)
|
|
1105
|
+
sage: h.inverse_image(d^2)
|
|
1106
|
+
a
|
|
1107
|
+
|
|
1108
|
+
Check that quotient rings are handled correctly (:issue:`33217`)::
|
|
1109
|
+
|
|
1110
|
+
sage: # needs sage.libs.singular
|
|
1111
|
+
sage: A.<x,y,z> = QQ['X,Y,Z'].quotient('X^2+Y^2+Z^2-1')
|
|
1112
|
+
sage: B.<t,u,v,w> = QQ['T,U,V,W'].quotient(['T^2+U^2-1', 'V^2+W^2-1'])
|
|
1113
|
+
sage: psi = A.hom([v*u, w*u, t], B)
|
|
1114
|
+
sage: psi.inverse_image(t^2) == z^2
|
|
1115
|
+
True
|
|
1116
|
+
|
|
1117
|
+
Check that the case in which the domain is a quotient ring
|
|
1118
|
+
and codomain a finite field of same characteristic is handled correctly::
|
|
1119
|
+
|
|
1120
|
+
sage: # needs sage.rings.finite_rings
|
|
1121
|
+
sage: F8.<a> = GF(2^3)
|
|
1122
|
+
sage: PR.<y> = PolynomialRing(F8)
|
|
1123
|
+
sage: IP = y^4 + a*y^3 + (a^2 + 1)*y + a^2 + 1
|
|
1124
|
+
sage: assert IP.is_irreducible()
|
|
1125
|
+
sage: Q.<w> = PR.quotient(IP)
|
|
1126
|
+
sage: SF.<z> = IP.splitting_field()
|
|
1127
|
+
sage: r = z^9 + z^7 + z^3 + z + 1
|
|
1128
|
+
sage: assert IP.change_ring(SF)(r) == 0
|
|
1129
|
+
sage: f = Q.hom([r,], SF)
|
|
1130
|
+
sage: f.inverse_image(z) # indirect doctest # needs sage.modules
|
|
1131
|
+
w^3 + (a^2 + a + 1)*w^2 + (a^2 + 1)*w + a^2 + 1
|
|
1132
|
+
"""
|
|
1133
|
+
from sage.rings.finite_rings.finite_field_base import FiniteField
|
|
1134
|
+
from sage.rings.quotient_ring import QuotientRing_nc
|
|
1135
|
+
if isinstance(self.domain(), QuotientRing_nc) and isinstance(self.codomain(), FiniteField):
|
|
1136
|
+
if self.domain().characteristic() == self.codomain().characteristic():
|
|
1137
|
+
return self._preimage_from_linear_dependence(b)
|
|
1138
|
+
graph, from_B, to_A = self._graph_ideal()
|
|
1139
|
+
gens_A = graph.ring().gens()[-self.domain().ngens():]
|
|
1140
|
+
a = graph.reduce(from_B(b))
|
|
1141
|
+
if not all(x in gens_A for x in a.lm().variables()):
|
|
1142
|
+
raise ValueError(f"element {b} does not have preimage")
|
|
1143
|
+
return to_A(a)
|
|
1144
|
+
|
|
1145
|
+
@cached_method
|
|
1146
|
+
def _preimage_from_linear_dependence(self, b):
|
|
1147
|
+
r"""
|
|
1148
|
+
Return an element `a` in self's domain such that ``self(a) = b``.
|
|
1149
|
+
|
|
1150
|
+
Return the preimage of ``b`` by solving a linear system
|
|
1151
|
+
in the common prime subfield. This yields the unique
|
|
1152
|
+
element in the domain that maps to ``b`` in the codomain.
|
|
1153
|
+
|
|
1154
|
+
An error is raised when the domain and codomain are not isomorphic.
|
|
1155
|
+
|
|
1156
|
+
INPUT:
|
|
1157
|
+
|
|
1158
|
+
- ``b`` -- an element in the codomain of this morphism
|
|
1159
|
+
|
|
1160
|
+
OUTPUT: an element `a` in the domain of this morphism such that ``self(a) = b``.
|
|
1161
|
+
|
|
1162
|
+
EXAMPLES::
|
|
1163
|
+
|
|
1164
|
+
This example illustrates the error message we get if the domain and codomain have different cardinality.
|
|
1165
|
+
In that case, we certainly know the morphism is not an isomorphism::
|
|
1166
|
+
|
|
1167
|
+
sage: # needs sage.rings.finite_rings
|
|
1168
|
+
sage: F4.<a> = GF(2^2, modulus=[1,1,1])
|
|
1169
|
+
sage: PR.<y> = PolynomialRing(F4)
|
|
1170
|
+
sage: IP = y^5 + y + 1
|
|
1171
|
+
sage: assert not IP.is_irreducible()
|
|
1172
|
+
sage: Q.<w> = PR.quotient(IP)
|
|
1173
|
+
sage: SF.<z> = IP.splitting_field()
|
|
1174
|
+
sage: r = IP.change_ring(SF).roots()[0][0]
|
|
1175
|
+
sage: f = Q.hom([r,], SF)
|
|
1176
|
+
sage: f._preimage_from_linear_dependence(z)
|
|
1177
|
+
Traceback (most recent call last):
|
|
1178
|
+
...
|
|
1179
|
+
ValueError: the cardinalities of the domain (=1024) and codomain (=64) should be equal
|
|
1180
|
+
"""
|
|
1181
|
+
D = self.domain()
|
|
1182
|
+
C = self.codomain()
|
|
1183
|
+
if D.characteristic() != C.characteristic():
|
|
1184
|
+
raise ValueError("the domain's and codomain's characteristic should be equal")
|
|
1185
|
+
if (d_card := D.cardinality()) != (c_card := C.cardinality()):
|
|
1186
|
+
raise ValueError(f"the cardinalities of the domain (={d_card}) and codomain (={c_card}) should be equal")
|
|
1187
|
+
if C != b.parent():
|
|
1188
|
+
raise TypeError(f"{b} fails to convert into the morphism's codomain {C}")
|
|
1189
|
+
F1 = D.base_ring()
|
|
1190
|
+
im_gen = self.im_gens()[0]
|
|
1191
|
+
target = im_gen.parent().gen()
|
|
1192
|
+
g = F1.gen()
|
|
1193
|
+
ncoeffs = F1.degree()
|
|
1194
|
+
from sage.modules.free_module_element import vector
|
|
1195
|
+
A = [vector(g**j * im_gen**i) for i in range(D.degree()) for j in range(ncoeffs)]
|
|
1196
|
+
from sage.matrix.constructor import Matrix
|
|
1197
|
+
M = Matrix(A).T
|
|
1198
|
+
T = vector(target)
|
|
1199
|
+
s = M.solve_right(T)
|
|
1200
|
+
P = D([F1(s[i:i+ncoeffs]) for i in range(0, len(s), ncoeffs)])
|
|
1201
|
+
return self.parent().reversed()(P)(b)
|
|
1202
|
+
|
|
1203
|
+
@cached_method
|
|
1204
|
+
def kernel(self):
|
|
1205
|
+
"""
|
|
1206
|
+
Return the kernel ideal of this ring homomorphism.
|
|
1207
|
+
|
|
1208
|
+
EXAMPLES::
|
|
1209
|
+
|
|
1210
|
+
sage: A.<x,y> = QQ[]
|
|
1211
|
+
sage: B.<t> = QQ[]
|
|
1212
|
+
sage: f = A.hom([t^4, t^3 - t^2], B)
|
|
1213
|
+
sage: f.kernel() # needs sage.libs.singular
|
|
1214
|
+
Ideal (y^4 - x^3 + 4*x^2*y - 2*x*y^2 + x^2)
|
|
1215
|
+
of Multivariate Polynomial Ring in x, y over Rational Field
|
|
1216
|
+
|
|
1217
|
+
We express a Veronese subring of a polynomial ring as a quotient ring::
|
|
1218
|
+
|
|
1219
|
+
sage: A.<a,b,c,d> = QQ[]
|
|
1220
|
+
sage: B.<u,v> = QQ[]
|
|
1221
|
+
sage: f = A.hom([u^3, u^2*v, u*v^2, v^3], B)
|
|
1222
|
+
sage: f.kernel() == A.ideal(matrix.hankel([a, b, c], [d]).minors(2)) # needs sage.libs.singular
|
|
1223
|
+
True
|
|
1224
|
+
sage: Q = A.quotient(f.kernel()) # needs sage.libs.singular
|
|
1225
|
+
sage: Q.hom(f.im_gens(), B).is_injective() # needs sage.libs.singular
|
|
1226
|
+
True
|
|
1227
|
+
|
|
1228
|
+
The Steiner-Roman surface::
|
|
1229
|
+
|
|
1230
|
+
sage: R.<x,y,z> = QQ[]
|
|
1231
|
+
sage: S = R.quotient(x^2 + y^2 + z^2 - 1)
|
|
1232
|
+
sage: f = R.hom([x*y, x*z, y*z], S) # needs sage.libs.singular
|
|
1233
|
+
sage: f.kernel() # needs sage.libs.singular
|
|
1234
|
+
Ideal (x^2*y^2 + x^2*z^2 + y^2*z^2 - x*y*z)
|
|
1235
|
+
of Multivariate Polynomial Ring in x, y, z over Rational Field
|
|
1236
|
+
|
|
1237
|
+
TESTS:
|
|
1238
|
+
|
|
1239
|
+
The results are cached::
|
|
1240
|
+
|
|
1241
|
+
sage: f.kernel() is f.kernel() # needs sage.libs.singular
|
|
1242
|
+
True
|
|
1243
|
+
|
|
1244
|
+
A degenerate case::
|
|
1245
|
+
|
|
1246
|
+
sage: R.<x,y> = QQ[]
|
|
1247
|
+
sage: f = R.hom([0, 0], R.quotient(1)) # needs sage.libs.singular
|
|
1248
|
+
sage: f.kernel().is_one() # needs sage.libs.singular
|
|
1249
|
+
True
|
|
1250
|
+
|
|
1251
|
+
::
|
|
1252
|
+
|
|
1253
|
+
sage: K.<sqrt2> = QuadraticField(2) # needs sage.rings.number_field
|
|
1254
|
+
sage: K.hom([-sqrt2], K).kernel().is_zero() # needs sage.libs.singular sage.rings.number_field
|
|
1255
|
+
True
|
|
1256
|
+
|
|
1257
|
+
::
|
|
1258
|
+
|
|
1259
|
+
sage: # needs sage.rings.number_field
|
|
1260
|
+
sage: A.<a> = QuadraticField(2)
|
|
1261
|
+
sage: B.<b> = A.extension(A['b']('b^2-3'))
|
|
1262
|
+
sage: C.<c> = B.absolute_field()
|
|
1263
|
+
sage: A.hom([B(a)], C).kernel().is_zero() # needs sage.libs.singular
|
|
1264
|
+
True
|
|
1265
|
+
sage: A.hom([a], B).kernel()
|
|
1266
|
+
Traceback (most recent call last):
|
|
1267
|
+
...
|
|
1268
|
+
NotImplementedError: base rings must be equal
|
|
1269
|
+
"""
|
|
1270
|
+
return self._inverse_image_ideal(self.codomain().zero_ideal())
|
|
1271
|
+
|
|
1272
|
+
def lift(self, x=None):
|
|
1273
|
+
"""
|
|
1274
|
+
Return a lifting map associated to this homomorphism, if
|
|
1275
|
+
it has been defined.
|
|
1276
|
+
|
|
1277
|
+
If ``x`` is not ``None``, return the value of the lift morphism on
|
|
1278
|
+
``x``.
|
|
1279
|
+
|
|
1280
|
+
EXAMPLES::
|
|
1281
|
+
|
|
1282
|
+
sage: R.<x,y> = QQ[]
|
|
1283
|
+
sage: f = R.hom([x,x])
|
|
1284
|
+
sage: f(x+y)
|
|
1285
|
+
2*x
|
|
1286
|
+
sage: f.lift()
|
|
1287
|
+
Traceback (most recent call last):
|
|
1288
|
+
...
|
|
1289
|
+
ValueError: no lift map defined
|
|
1290
|
+
sage: g = R.hom(R)
|
|
1291
|
+
sage: f._set_lift(g)
|
|
1292
|
+
sage: f.lift() == g
|
|
1293
|
+
True
|
|
1294
|
+
sage: f.lift(x)
|
|
1295
|
+
x
|
|
1296
|
+
"""
|
|
1297
|
+
if self._lift is None:
|
|
1298
|
+
raise ValueError("no lift map defined")
|
|
1299
|
+
if x is None:
|
|
1300
|
+
return self._lift
|
|
1301
|
+
return self._lift(x)
|
|
1302
|
+
|
|
1303
|
+
@cached_method
|
|
1304
|
+
def _graph_ideal(self):
|
|
1305
|
+
"""
|
|
1306
|
+
Return the ideal corresponding to the graph of this ring homomorphism.
|
|
1307
|
+
|
|
1308
|
+
OUTPUT:
|
|
1309
|
+
|
|
1310
|
+
- the graph as an ideal in the tensor product of codomain and domain
|
|
1311
|
+
- a map from the codomain to the ring of the graph ideal
|
|
1312
|
+
- a map from the ring of the graph ideal to the domain
|
|
1313
|
+
|
|
1314
|
+
The second map is only meaningful for those elements that involve only
|
|
1315
|
+
variables of the domain of ``self``.
|
|
1316
|
+
|
|
1317
|
+
EXAMPLES::
|
|
1318
|
+
|
|
1319
|
+
sage: R.<x,y> = QQ[]
|
|
1320
|
+
sage: QQ['t'].hom([x*y^2], R)._graph_ideal()
|
|
1321
|
+
(Ideal (x*y^2 - t) of Multivariate Polynomial Ring in x, y, t over
|
|
1322
|
+
Rational Field,
|
|
1323
|
+
Ring morphism:
|
|
1324
|
+
From: Multivariate Polynomial Ring in x, y over Rational Field
|
|
1325
|
+
To: Multivariate Polynomial Ring in x, y, t over Rational Field
|
|
1326
|
+
Defn: x |--> x
|
|
1327
|
+
y |--> y,
|
|
1328
|
+
Ring morphism:
|
|
1329
|
+
From: Multivariate Polynomial Ring in x, y, t over Rational Field
|
|
1330
|
+
To: Univariate Polynomial Ring in t over Rational Field
|
|
1331
|
+
Defn: x |--> 0
|
|
1332
|
+
y |--> 0
|
|
1333
|
+
t |--> t)
|
|
1334
|
+
|
|
1335
|
+
TESTS:
|
|
1336
|
+
|
|
1337
|
+
Ideals in quotient rings over ``QQbar`` do not support reduction yet,
|
|
1338
|
+
so the graph is constructed in the ambient ring instead::
|
|
1339
|
+
|
|
1340
|
+
sage: # needs sage.libs.singular sage.rings.number_field
|
|
1341
|
+
sage: A.<z,w> = QQbar['z,w'].quotient('z*w - 1')
|
|
1342
|
+
sage: B.<x,y> = QQbar['x,y'].quotient('2*x^2 + y^2 - 1')
|
|
1343
|
+
sage: f = A.hom([QQbar(2).sqrt()*x + QQbar(I)*y,
|
|
1344
|
+
....: QQbar(2).sqrt()*x - QQbar(I)*y], B)
|
|
1345
|
+
sage: f._graph_ideal()[0]
|
|
1346
|
+
Ideal (z*w - 1, 2*x^2 + y^2 - 1,
|
|
1347
|
+
1.414213562373095?*x + I*y - z,
|
|
1348
|
+
1.414213562373095?*x + (-I)*y - w)
|
|
1349
|
+
of Multivariate Polynomial Ring in x, y, z, w over Algebraic Field
|
|
1350
|
+
sage: f.inverse()(f(z)), f.inverse()(f(w))
|
|
1351
|
+
(z, w)
|
|
1352
|
+
|
|
1353
|
+
Non-trivial base maps are not supported::
|
|
1354
|
+
|
|
1355
|
+
sage: # needs sage.rings.number_field
|
|
1356
|
+
sage: K.<a> = QuadraticField(2)
|
|
1357
|
+
sage: R.<x,y> = K[]
|
|
1358
|
+
sage: f = R.hom([x, a*x + y], R, base_map=K.hom([-a], K))
|
|
1359
|
+
sage: f._graph_ideal()
|
|
1360
|
+
Traceback (most recent call last):
|
|
1361
|
+
...
|
|
1362
|
+
NotImplementedError: base map must be trivial
|
|
1363
|
+
|
|
1364
|
+
Non-commutative rings are not supported (:issue:`32824`)::
|
|
1365
|
+
|
|
1366
|
+
sage: A = GradedCommutativeAlgebra(QQ, 'x,y,z') # needs sage.combinat sage.modules
|
|
1367
|
+
sage: A.hom(A.gens(), A).kernel() # needs sage.combinat sage.modules
|
|
1368
|
+
Traceback (most recent call last):
|
|
1369
|
+
...
|
|
1370
|
+
NotImplementedError: rings are not commutative
|
|
1371
|
+
"""
|
|
1372
|
+
from sage.rings.quotient_ring import QuotientRing_nc
|
|
1373
|
+
from sage.rings.ideal import Ideal_generic
|
|
1374
|
+
A = self.domain()
|
|
1375
|
+
B = self.codomain()
|
|
1376
|
+
Comm = Rings().Commutative()
|
|
1377
|
+
if not (A in Comm and B in Comm):
|
|
1378
|
+
raise NotImplementedError("rings are not commutative")
|
|
1379
|
+
if A.base_ring() != B.base_ring():
|
|
1380
|
+
raise NotImplementedError("base rings must be equal")
|
|
1381
|
+
try:
|
|
1382
|
+
base_map = self.base_map()
|
|
1383
|
+
except AttributeError:
|
|
1384
|
+
pass
|
|
1385
|
+
else:
|
|
1386
|
+
if base_map is not None:
|
|
1387
|
+
raise NotImplementedError("base map must be trivial")
|
|
1388
|
+
Q = _tensor_product_ring(B, A)
|
|
1389
|
+
A_to_Q = A.hom(Q.gens()[B.ngens():], Q, check=False)
|
|
1390
|
+
B_to_Q = B.hom(Q.gens()[:B.ngens()], Q, check=False)
|
|
1391
|
+
graph = Q.ideal([B_to_Q(self(x)) - A_to_Q(x) for x in A.gens()])
|
|
1392
|
+
R = Q.cover_ring() if isinstance(Q, QuotientRing_nc) else Q
|
|
1393
|
+
R_to_A = R.hom(tuple([0] * B.ngens()) + A.gens(), A, check=False)
|
|
1394
|
+
Q_to_A = R_to_A if R is Q else R_to_A * Q.lifting_map()
|
|
1395
|
+
|
|
1396
|
+
# Since we compute normal forms modulo the graph ideal, check that
|
|
1397
|
+
# the default `reduce` method has been overwritten
|
|
1398
|
+
if graph.reduce.__func__ is Ideal_generic.reduce:
|
|
1399
|
+
if Q is not R:
|
|
1400
|
+
# Although the graph naturally lives in the quotient Q, we try
|
|
1401
|
+
# to lift it to the ambient R as a workaround, since in some
|
|
1402
|
+
# cases (e.g. over QQbar) reduction is supported in R
|
|
1403
|
+
graph_R = Q.cover()._inverse_image_ideal(graph)
|
|
1404
|
+
if graph_R.reduce.__func__ is not Ideal_generic.reduce:
|
|
1405
|
+
return graph_R, (Q.lifting_map() * B_to_Q), R_to_A
|
|
1406
|
+
raise NotImplementedError('"reduce" not implemented for %s' % Q)
|
|
1407
|
+
return graph, B_to_Q, Q_to_A
|
|
1408
|
+
|
|
1409
|
+
@cached_method
|
|
1410
|
+
def inverse(self):
|
|
1411
|
+
"""
|
|
1412
|
+
Return the inverse of this ring homomorphism if it exists.
|
|
1413
|
+
|
|
1414
|
+
Raises a :exc:`ZeroDivisionError` if the inverse does not exist.
|
|
1415
|
+
|
|
1416
|
+
ALGORITHM:
|
|
1417
|
+
|
|
1418
|
+
By default, this computes a Gröbner basis of the ideal corresponding to
|
|
1419
|
+
the graph of the ring homomorphism.
|
|
1420
|
+
|
|
1421
|
+
EXAMPLES::
|
|
1422
|
+
|
|
1423
|
+
sage: R.<t> = QQ[]
|
|
1424
|
+
sage: f = R.hom([2*t - 1], R)
|
|
1425
|
+
sage: f.inverse() # needs sage.libs.singular
|
|
1426
|
+
Ring endomorphism of Univariate Polynomial Ring in t over Rational Field
|
|
1427
|
+
Defn: t |--> 1/2*t + 1/2
|
|
1428
|
+
|
|
1429
|
+
The following non-linear homomorphism is not invertible, but it induces
|
|
1430
|
+
an isomorphism on a quotient ring::
|
|
1431
|
+
|
|
1432
|
+
sage: # needs sage.libs.singular
|
|
1433
|
+
sage: R.<x,y,z> = QQ[]
|
|
1434
|
+
sage: f = R.hom([y*z, x*z, x*y], R)
|
|
1435
|
+
sage: f.inverse()
|
|
1436
|
+
Traceback (most recent call last):
|
|
1437
|
+
...
|
|
1438
|
+
ZeroDivisionError: ring homomorphism not surjective
|
|
1439
|
+
sage: f.is_injective()
|
|
1440
|
+
True
|
|
1441
|
+
sage: Q.<x,y,z> = R.quotient(x*y*z - 1)
|
|
1442
|
+
sage: g = Q.hom([y*z, x*z, x*y], Q)
|
|
1443
|
+
sage: g.inverse()
|
|
1444
|
+
Ring endomorphism of Quotient of Multivariate Polynomial Ring
|
|
1445
|
+
in x, y, z over Rational Field by the ideal (x*y*z - 1)
|
|
1446
|
+
Defn: x |--> y*z
|
|
1447
|
+
y |--> x*z
|
|
1448
|
+
z |--> x*y
|
|
1449
|
+
|
|
1450
|
+
Homomorphisms over the integers are supported::
|
|
1451
|
+
|
|
1452
|
+
sage: S.<x,y> = ZZ[]
|
|
1453
|
+
sage: f = S.hom([x + 2*y, x + 3*y], S)
|
|
1454
|
+
sage: f.inverse() # needs sage.libs.singular
|
|
1455
|
+
Ring endomorphism of Multivariate Polynomial Ring in x, y over Integer Ring
|
|
1456
|
+
Defn: x |--> 3*x - 2*y
|
|
1457
|
+
y |--> -x + y
|
|
1458
|
+
sage: (f.inverse() * f).is_identity() # needs sage.libs.singular
|
|
1459
|
+
True
|
|
1460
|
+
|
|
1461
|
+
The following homomorphism is invertible over the rationals, but not
|
|
1462
|
+
over the integers::
|
|
1463
|
+
|
|
1464
|
+
sage: g = S.hom([x + y, x - y - 2], S)
|
|
1465
|
+
sage: g.inverse() # needs sage.libs.singular
|
|
1466
|
+
Traceback (most recent call last):
|
|
1467
|
+
...
|
|
1468
|
+
ZeroDivisionError: ring homomorphism not surjective
|
|
1469
|
+
sage: R.<x,y> = QQ[x,y]
|
|
1470
|
+
sage: h = R.hom([x + y, x - y - 2], R)
|
|
1471
|
+
sage: (h.inverse() * h).is_identity() # needs sage.libs.singular
|
|
1472
|
+
True
|
|
1473
|
+
|
|
1474
|
+
This example by M. Nagata is a wild automorphism::
|
|
1475
|
+
|
|
1476
|
+
sage: R.<x,y,z> = QQ[]
|
|
1477
|
+
sage: sigma = R.hom([x - 2*y*(z*x+y^2) - z*(z*x+y^2)^2,
|
|
1478
|
+
....: y + z*(z*x+y^2), z], R)
|
|
1479
|
+
sage: tau = sigma.inverse(); tau # needs sage.libs.singular
|
|
1480
|
+
Ring endomorphism of Multivariate Polynomial Ring in x, y, z over
|
|
1481
|
+
Rational Field
|
|
1482
|
+
Defn: x |--> -y^4*z - 2*x*y^2*z^2 - x^2*z^3 + 2*y^3 + 2*x*y*z + x
|
|
1483
|
+
y |--> -y^2*z - x*z^2 + y
|
|
1484
|
+
z |--> z
|
|
1485
|
+
sage: (tau * sigma).is_identity() # needs sage.libs.singular
|
|
1486
|
+
True
|
|
1487
|
+
|
|
1488
|
+
We compute the triangular automorphism that converts moments to
|
|
1489
|
+
cumulants, as well as its inverse, using the moment generating
|
|
1490
|
+
function. The choice of a term ordering can have a great impact on the
|
|
1491
|
+
computation time of a Gröbner basis, so here we choose a weighted
|
|
1492
|
+
ordering such that the images of the generators are homogeneous
|
|
1493
|
+
polynomials. ::
|
|
1494
|
+
|
|
1495
|
+
sage: d = 12
|
|
1496
|
+
sage: T = TermOrder('wdegrevlex', [1..d])
|
|
1497
|
+
sage: R = PolynomialRing(QQ, ['x%s' % j for j in (1..d)], order=T)
|
|
1498
|
+
sage: S.<t> = PowerSeriesRing(R)
|
|
1499
|
+
sage: egf = S([0] + list(R.gens())).ogf_to_egf().exp(prec=d+1)
|
|
1500
|
+
sage: phi = R.hom(egf.egf_to_ogf().list()[1:], R)
|
|
1501
|
+
sage: phi.im_gens()[:5]
|
|
1502
|
+
[x1,
|
|
1503
|
+
x1^2 + x2,
|
|
1504
|
+
x1^3 + 3*x1*x2 + x3,
|
|
1505
|
+
x1^4 + 6*x1^2*x2 + 3*x2^2 + 4*x1*x3 + x4,
|
|
1506
|
+
x1^5 + 10*x1^3*x2 + 15*x1*x2^2 + 10*x1^2*x3 + 10*x2*x3 + 5*x1*x4 + x5]
|
|
1507
|
+
sage: all(p.is_homogeneous() for p in phi.im_gens()) # needs sage.libs.singular
|
|
1508
|
+
True
|
|
1509
|
+
sage: phi.inverse().im_gens()[:5] # needs sage.libs.singular
|
|
1510
|
+
[x1,
|
|
1511
|
+
-x1^2 + x2,
|
|
1512
|
+
2*x1^3 - 3*x1*x2 + x3,
|
|
1513
|
+
-6*x1^4 + 12*x1^2*x2 - 3*x2^2 - 4*x1*x3 + x4,
|
|
1514
|
+
24*x1^5 - 60*x1^3*x2 + 30*x1*x2^2 + 20*x1^2*x3 - 10*x2*x3 - 5*x1*x4 + x5]
|
|
1515
|
+
sage: (phi.inverse() * phi).is_identity() # needs sage.libs.singular
|
|
1516
|
+
True
|
|
1517
|
+
|
|
1518
|
+
Automorphisms of number fields as well as Galois fields are supported::
|
|
1519
|
+
|
|
1520
|
+
sage: K.<zeta7> = CyclotomicField(7) # needs sage.rings.number_field
|
|
1521
|
+
sage: c = K.hom([1/zeta7]) # needs sage.rings.number_field
|
|
1522
|
+
sage: (c.inverse() * c).is_identity() # needs sage.libs.singular sage.rings.number_field
|
|
1523
|
+
True
|
|
1524
|
+
|
|
1525
|
+
sage: F.<t> = GF(7^3) # needs sage.rings.finite_rings
|
|
1526
|
+
sage: f = F.hom(t^7, F) # needs sage.rings.finite_rings
|
|
1527
|
+
sage: (f.inverse() * f).is_identity() # needs sage.libs.singular sage.rings.finite_rings
|
|
1528
|
+
True
|
|
1529
|
+
|
|
1530
|
+
An isomorphism between the algebraic torus and the circle over a number
|
|
1531
|
+
field::
|
|
1532
|
+
|
|
1533
|
+
sage: # needs sage.libs.singular sage.rings.number_field
|
|
1534
|
+
sage: K.<i> = QuadraticField(-1)
|
|
1535
|
+
sage: A.<z,w> = K['z,w'].quotient('z*w - 1')
|
|
1536
|
+
sage: B.<x,y> = K['x,y'].quotient('x^2 + y^2 - 1')
|
|
1537
|
+
sage: f = A.hom([x + i*y, x - i*y], B)
|
|
1538
|
+
sage: g = f.inverse()
|
|
1539
|
+
sage: g.morphism_from_cover().im_gens()
|
|
1540
|
+
[1/2*z + 1/2*w, (-1/2*i)*z + (1/2*i)*w]
|
|
1541
|
+
sage: all(g(f(z)) == z for z in A.gens())
|
|
1542
|
+
True
|
|
1543
|
+
|
|
1544
|
+
TESTS:
|
|
1545
|
+
|
|
1546
|
+
Morphisms involving quotient rings::
|
|
1547
|
+
|
|
1548
|
+
sage: # needs sage.libs.singular
|
|
1549
|
+
sage: R.<x,y> = QQ[]
|
|
1550
|
+
sage: S.<s,u,t> = QQ['s,u,t'].quotient('u-t^2')
|
|
1551
|
+
sage: f = R.hom([s, -t], S)
|
|
1552
|
+
sage: (f.inverse() * f).is_identity()
|
|
1553
|
+
True
|
|
1554
|
+
sage: Q.<v,w> = R.quotient(x - y^2)
|
|
1555
|
+
sage: g = Q.hom([v, -w], Q)
|
|
1556
|
+
sage: g.inverse()(g(v)) == v and g.inverse()(g(w)) == w
|
|
1557
|
+
True
|
|
1558
|
+
sage: S.<z> = QQ[]
|
|
1559
|
+
sage: h = Q.hom([z^2, -z], S)
|
|
1560
|
+
sage: h.inverse()(h(v)) == v and h.inverse()(h(w)) == w
|
|
1561
|
+
True
|
|
1562
|
+
|
|
1563
|
+
Morphisms between number fields and quotient rings::
|
|
1564
|
+
|
|
1565
|
+
sage: # needs sage.rings.number_field
|
|
1566
|
+
sage: K.<sqrt2> = QuadraticField(2)
|
|
1567
|
+
sage: f = K.hom([-sqrt2], K.polynomial_quotient_ring())
|
|
1568
|
+
sage: (f.inverse() * f).is_identity() # needs sage.libs.singular
|
|
1569
|
+
True
|
|
1570
|
+
sage: g = K.polynomial_quotient_ring().hom([-sqrt2], K)
|
|
1571
|
+
sage: (g.inverse() * g).is_identity() # needs sage.libs.singular
|
|
1572
|
+
True
|
|
1573
|
+
|
|
1574
|
+
Morphisms involving Galois fields::
|
|
1575
|
+
|
|
1576
|
+
sage: # needs sage.rings.finite_rings
|
|
1577
|
+
sage: A.<t> = GF(7^3)
|
|
1578
|
+
sage: R = A.polynomial_ring().quotient(A.polynomial())
|
|
1579
|
+
sage: g = A.hom(R.gens(), R)
|
|
1580
|
+
sage: (g.inverse() * g).is_identity() # needs sage.libs.singular
|
|
1581
|
+
True
|
|
1582
|
+
sage: B.<T>, f = A.extension(3, map=True)
|
|
1583
|
+
sage: f.inverse()
|
|
1584
|
+
Traceback (most recent call last):
|
|
1585
|
+
...
|
|
1586
|
+
ZeroDivisionError: ring homomorphism not surjective
|
|
1587
|
+
sage: B.<T>, f = A.extension(1, map=True)
|
|
1588
|
+
sage: f.inverse()
|
|
1589
|
+
Ring morphism:
|
|
1590
|
+
From: Finite Field in T of size 7^3
|
|
1591
|
+
To: Finite Field in t of size 7^3
|
|
1592
|
+
Defn: T |--> t
|
|
1593
|
+
|
|
1594
|
+
Non-injective homomorphisms::
|
|
1595
|
+
|
|
1596
|
+
sage: # needs sage.libs.singular
|
|
1597
|
+
sage: R.<x,y> = QQ[]
|
|
1598
|
+
sage: S.<a,b,c> = QQ[]
|
|
1599
|
+
sage: S.hom([x, y, 0], R).inverse()
|
|
1600
|
+
Traceback (most recent call last):
|
|
1601
|
+
...
|
|
1602
|
+
ZeroDivisionError: ring homomorphism not injective
|
|
1603
|
+
sage: T.<z> = QQ[]
|
|
1604
|
+
sage: R.hom([2*z, 3*z], T).inverse()
|
|
1605
|
+
Traceback (most recent call last):
|
|
1606
|
+
...
|
|
1607
|
+
ZeroDivisionError: ring homomorphism not injective
|
|
1608
|
+
sage: Q.<u,v> = R.quotient([x^5, y^4])
|
|
1609
|
+
sage: R.hom([u, v], Q).inverse()
|
|
1610
|
+
Traceback (most recent call last):
|
|
1611
|
+
...
|
|
1612
|
+
ZeroDivisionError: ring homomorphism not injective
|
|
1613
|
+
sage: Q.cover().inverse()
|
|
1614
|
+
Traceback (most recent call last):
|
|
1615
|
+
...
|
|
1616
|
+
ZeroDivisionError: ring homomorphism not injective
|
|
1617
|
+
|
|
1618
|
+
Univariate quotient rings::
|
|
1619
|
+
|
|
1620
|
+
sage: R.<t> = QQ['t'].quotient('t^5') # needs sage.libs.pari
|
|
1621
|
+
sage: f = R.hom([2*t], R)
|
|
1622
|
+
sage: (f.inverse() * f).is_identity() # needs sage.libs.singular
|
|
1623
|
+
True
|
|
1624
|
+
|
|
1625
|
+
A homomorphism over ``QQbar``::
|
|
1626
|
+
|
|
1627
|
+
sage: R.<x,y> = QQbar[] # needs sage.rings.number_field
|
|
1628
|
+
sage: f = R.hom([x + QQbar(I)*y^2, -y], R) # needs sage.rings.number_field
|
|
1629
|
+
sage: (f.inverse() * f).is_identity() # needs sage.libs.singular sage.rings.number_field
|
|
1630
|
+
True
|
|
1631
|
+
|
|
1632
|
+
Check that results are cached::
|
|
1633
|
+
|
|
1634
|
+
sage: R.<x,y> = GF(823)[]
|
|
1635
|
+
sage: f = R.hom([x, y + x^2], R)
|
|
1636
|
+
sage: f.inverse() is f.inverse() # needs sage.libs.singular
|
|
1637
|
+
True
|
|
1638
|
+
|
|
1639
|
+
Some subclasses of ring homomorphisms are not supported::
|
|
1640
|
+
|
|
1641
|
+
sage: from sage.rings.morphism import FrobeniusEndomorphism_generic
|
|
1642
|
+
sage: K.<u> = PowerSeriesRing(GF(5))
|
|
1643
|
+
sage: FrobeniusEndomorphism_generic(K).inverse()
|
|
1644
|
+
Traceback (most recent call last):
|
|
1645
|
+
...
|
|
1646
|
+
NotImplementedError
|
|
1647
|
+
|
|
1648
|
+
::
|
|
1649
|
+
|
|
1650
|
+
sage: R.<x,y> = LaurentPolynomialRing(QQ) # needs sage.modules
|
|
1651
|
+
sage: R.hom([y, x], R).inverse() # needs sage.libs.singular sage.modules
|
|
1652
|
+
Traceback (most recent call last):
|
|
1653
|
+
...
|
|
1654
|
+
NotImplementedError
|
|
1655
|
+
|
|
1656
|
+
::
|
|
1657
|
+
|
|
1658
|
+
sage: K.<x> = FunctionField(QQ)
|
|
1659
|
+
sage: K.hom(1/x).inverse()
|
|
1660
|
+
Traceback (most recent call last):
|
|
1661
|
+
...
|
|
1662
|
+
NotImplementedError: inverse not implemented...
|
|
1663
|
+
|
|
1664
|
+
The implementation performs several computations that require a Gröbner
|
|
1665
|
+
basis of the graph ideal, so we check that the Gröbner basis is cached
|
|
1666
|
+
after the first such computation::
|
|
1667
|
+
|
|
1668
|
+
sage: R.<x,y> = QQ[]
|
|
1669
|
+
sage: f = R.hom([x + 123*y^2, y], R)
|
|
1670
|
+
sage: f._graph_ideal()[0].groebner_basis.is_in_cache()
|
|
1671
|
+
False
|
|
1672
|
+
sage: f.is_injective() # needs sage.libs.singular
|
|
1673
|
+
True
|
|
1674
|
+
sage: f._graph_ideal()[0].groebner_basis.is_in_cache() # needs sage.libs.singular
|
|
1675
|
+
True
|
|
1676
|
+
|
|
1677
|
+
Check case where domain is quotient ring and codomain a finite field of same characteristic. Fixes (:issue:`39690`)::
|
|
1678
|
+
|
|
1679
|
+
sage: # needs sage.rings.finite_rings
|
|
1680
|
+
sage: F4.<a> = GF(2^2, modulus=[1,1,1])
|
|
1681
|
+
sage: PR.<y> = PolynomialRing(F4)
|
|
1682
|
+
sage: IP = y^3 + y + 1
|
|
1683
|
+
sage: assert IP.is_irreducible()
|
|
1684
|
+
sage: Q.<w> = PR.quotient(IP)
|
|
1685
|
+
sage: SF.<z> = IP.splitting_field()
|
|
1686
|
+
sage: SF
|
|
1687
|
+
Finite Field in z of size 2^6
|
|
1688
|
+
sage: r = z^4 + z^2 + z + 1
|
|
1689
|
+
sage: assert IP.change_ring(SF)(r) == 0
|
|
1690
|
+
sage: f = Q.hom([r,], SF)
|
|
1691
|
+
sage: f
|
|
1692
|
+
Ring morphism:
|
|
1693
|
+
From: Univariate Quotient Polynomial Ring in w over Finite Field in a of size 2^2 with modulus y^3 + y + 1
|
|
1694
|
+
To: Finite Field in z of size 2^6
|
|
1695
|
+
Defn: w |--> z^4 + z^2 + z + 1
|
|
1696
|
+
sage: f.inverse() # indirect doctest # needs sage.modules
|
|
1697
|
+
Ring morphism:
|
|
1698
|
+
From: Finite Field in z of size 2^6
|
|
1699
|
+
To: Univariate Quotient Polynomial Ring in w over Finite Field in a of size 2^2 with modulus y^3 + y + 1
|
|
1700
|
+
Defn: z |--> (a + 1)*w^2 + a*w + 1
|
|
1701
|
+
"""
|
|
1702
|
+
if not self.is_injective():
|
|
1703
|
+
raise ZeroDivisionError("ring homomorphism not injective")
|
|
1704
|
+
ys = self.codomain().gens()
|
|
1705
|
+
try:
|
|
1706
|
+
preimages = [self._inverse_image_element(y) for y in ys]
|
|
1707
|
+
except ValueError:
|
|
1708
|
+
raise ZeroDivisionError("ring homomorphism not surjective")
|
|
1709
|
+
return self.parent().reversed()(preimages, check=False)
|
|
1710
|
+
|
|
1711
|
+
def __invert__(self):
|
|
1712
|
+
"""
|
|
1713
|
+
Return the inverse of this ring homomorphism if it exists.
|
|
1714
|
+
|
|
1715
|
+
This simply calls :meth:`inverse`.
|
|
1716
|
+
|
|
1717
|
+
EXAMPLES::
|
|
1718
|
+
|
|
1719
|
+
sage: R.<x,y> = GF(17)[]
|
|
1720
|
+
sage: f = R.hom([3*x, y + x^2 + x^3], R)
|
|
1721
|
+
sage: (f * ~f).is_identity() # needs sage.libs.singular
|
|
1722
|
+
True
|
|
1723
|
+
"""
|
|
1724
|
+
return self.inverse()
|
|
1725
|
+
|
|
1726
|
+
def is_surjective(self):
|
|
1727
|
+
"""
|
|
1728
|
+
Return whether this ring homomorphism is surjective.
|
|
1729
|
+
|
|
1730
|
+
EXAMPLES::
|
|
1731
|
+
|
|
1732
|
+
sage: R.<x,y,z> = QQ[]
|
|
1733
|
+
sage: R.hom([y*z, x*z, x*y], R).is_surjective() # needs sage.libs.singular
|
|
1734
|
+
False
|
|
1735
|
+
sage: Q.<x,y,z> = R.quotient(x*y*z - 1) # needs sage.libs.singular
|
|
1736
|
+
sage: R.hom([y*z, x*z, x*y], Q).is_surjective() # needs sage.libs.singular
|
|
1737
|
+
True
|
|
1738
|
+
|
|
1739
|
+
ALGORITHM:
|
|
1740
|
+
|
|
1741
|
+
By default, this requires the computation of a Gröbner basis.
|
|
1742
|
+
"""
|
|
1743
|
+
for y in self.codomain().gens():
|
|
1744
|
+
try:
|
|
1745
|
+
self._inverse_image_element(y)
|
|
1746
|
+
except ValueError:
|
|
1747
|
+
return False
|
|
1748
|
+
return True
|
|
1749
|
+
|
|
1750
|
+
def is_invertible(self):
|
|
1751
|
+
"""
|
|
1752
|
+
Return whether this ring homomorphism is bijective.
|
|
1753
|
+
|
|
1754
|
+
EXAMPLES::
|
|
1755
|
+
|
|
1756
|
+
sage: R.<x,y,z> = QQ[]
|
|
1757
|
+
sage: R.hom([y*z, x*z, x*y], R).is_invertible() # needs sage.libs.singular
|
|
1758
|
+
False
|
|
1759
|
+
sage: Q.<x,y,z> = R.quotient(x*y*z - 1) # needs sage.libs.singular
|
|
1760
|
+
sage: Q.hom([y*z, x*z, x*y], Q).is_invertible() # needs sage.libs.singular
|
|
1761
|
+
True
|
|
1762
|
+
|
|
1763
|
+
ALGORITHM:
|
|
1764
|
+
|
|
1765
|
+
By default, this requires the computation of a Gröbner basis.
|
|
1766
|
+
"""
|
|
1767
|
+
return self.is_injective() and self.is_surjective()
|
|
1768
|
+
|
|
1769
|
+
|
|
1770
|
+
cdef class RingHomomorphism_im_gens(RingHomomorphism):
|
|
1771
|
+
"""
|
|
1772
|
+
A ring homomorphism determined by the images of generators.
|
|
1773
|
+
"""
|
|
1774
|
+
def __init__(self, parent, im_gens, check=True, base_map=None):
|
|
1775
|
+
"""
|
|
1776
|
+
EXAMPLES::
|
|
1777
|
+
|
|
1778
|
+
sage: R.<x,y> = QQ[]
|
|
1779
|
+
sage: phi = R.hom([x, x + y]); phi
|
|
1780
|
+
Ring endomorphism of Multivariate Polynomial Ring in x, y over Rational Field
|
|
1781
|
+
Defn: x |--> x
|
|
1782
|
+
y |--> x + y
|
|
1783
|
+
sage: type(phi)
|
|
1784
|
+
<class 'sage.rings.morphism.RingHomomorphism_im_gens'>
|
|
1785
|
+
|
|
1786
|
+
Here's another example where the domain isn't free::
|
|
1787
|
+
|
|
1788
|
+
sage: S.<xx,yy> = R.quotient(x - y) # needs sage.libs.singular
|
|
1789
|
+
sage: phi = S.hom([xx + 1, xx + 1]) # needs sage.libs.singular
|
|
1790
|
+
|
|
1791
|
+
Note that one has to specify valid images::
|
|
1792
|
+
|
|
1793
|
+
sage: phi = S.hom([xx + 1, xx - 1]) # needs sage.libs.singular
|
|
1794
|
+
Traceback (most recent call last):
|
|
1795
|
+
...
|
|
1796
|
+
ValueError: relations do not all (canonically) map to 0
|
|
1797
|
+
under map determined by images of generators
|
|
1798
|
+
|
|
1799
|
+
You can give a map of the base ring::
|
|
1800
|
+
|
|
1801
|
+
sage: # needs sage.rings.number_field
|
|
1802
|
+
sage: Zx.<x> = ZZ[]
|
|
1803
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
1804
|
+
sage: cc = K.hom([-i])
|
|
1805
|
+
sage: R.<t> = K[]
|
|
1806
|
+
sage: z = 1 + i*t + (3+4*i)*t^2
|
|
1807
|
+
sage: z._im_gens_(R, [t^2], base_map=cc)
|
|
1808
|
+
(-4*i + 3)*t^4 - i*t^2 + 1
|
|
1809
|
+
|
|
1810
|
+
The base map's codomain is extended to the whole codomain::
|
|
1811
|
+
|
|
1812
|
+
sage: S.<x> = QQ[]
|
|
1813
|
+
sage: T.<y> = S[]
|
|
1814
|
+
sage: cc = S.hom([x + 1])
|
|
1815
|
+
sage: f = T.hom([x - y], base_map=cc)
|
|
1816
|
+
sage: g = T.hom([x - y], base_map=cc.extend_codomain(T))
|
|
1817
|
+
sage: f == g
|
|
1818
|
+
True
|
|
1819
|
+
sage: f.base_map() == cc.extend_codomain(T)
|
|
1820
|
+
True
|
|
1821
|
+
|
|
1822
|
+
There is a check option, but it may be ignored in some cases
|
|
1823
|
+
-- it's purpose isn't so you can lie to Sage, but to sometimes
|
|
1824
|
+
speed up creation of a homomorphism::
|
|
1825
|
+
|
|
1826
|
+
sage: R.<x,y> = QQ[]
|
|
1827
|
+
sage: S.<xx,yy> = R.quotient(x - y) # needs sage.libs.singular
|
|
1828
|
+
sage: phi = S.hom([xx + 1, xx - 1], check=False) # needs sage.libs.singular
|
|
1829
|
+
Traceback (most recent call last):
|
|
1830
|
+
...
|
|
1831
|
+
ValueError: relations do not all (canonically) map to 0
|
|
1832
|
+
under map determined by images of generators
|
|
1833
|
+
"""
|
|
1834
|
+
RingHomomorphism.__init__(self, parent)
|
|
1835
|
+
if not isinstance(im_gens, sage.structure.sequence.Sequence_generic):
|
|
1836
|
+
if not isinstance(im_gens, (tuple, list)):
|
|
1837
|
+
im_gens = [im_gens]
|
|
1838
|
+
im_gens = sage.structure.all.Sequence(im_gens, parent.codomain(),
|
|
1839
|
+
check=check, immutable=True)
|
|
1840
|
+
if check:
|
|
1841
|
+
if len(im_gens) != parent.domain().ngens():
|
|
1842
|
+
raise ValueError("number of images must equal number of generators")
|
|
1843
|
+
if base_map is None:
|
|
1844
|
+
tkwds = {}
|
|
1845
|
+
else:
|
|
1846
|
+
if base_map.codomain() is not self.codomain():
|
|
1847
|
+
base_map = base_map.extend_codomain(self.codomain())
|
|
1848
|
+
tkwds = {'base_map': base_map}
|
|
1849
|
+
t = parent.domain()._is_valid_homomorphism_(parent.codomain(), im_gens, **tkwds)
|
|
1850
|
+
if not t:
|
|
1851
|
+
raise ValueError("relations do not all (canonically) map to 0 under map determined by images of generators")
|
|
1852
|
+
if not im_gens.is_immutable():
|
|
1853
|
+
import copy
|
|
1854
|
+
im_gens = copy.copy(im_gens)
|
|
1855
|
+
im_gens.set_immutable()
|
|
1856
|
+
self._im_gens = im_gens
|
|
1857
|
+
self._base_map = base_map
|
|
1858
|
+
|
|
1859
|
+
def im_gens(self):
|
|
1860
|
+
"""
|
|
1861
|
+
Return the images of the generators of the domain.
|
|
1862
|
+
|
|
1863
|
+
OUTPUT:
|
|
1864
|
+
|
|
1865
|
+
- ``list`` -- a copy of the list of gens (it is safe to change this)
|
|
1866
|
+
|
|
1867
|
+
EXAMPLES::
|
|
1868
|
+
|
|
1869
|
+
sage: R.<x,y> = QQ[]
|
|
1870
|
+
sage: f = R.hom([x, x + y])
|
|
1871
|
+
sage: f.im_gens()
|
|
1872
|
+
[x, x + y]
|
|
1873
|
+
|
|
1874
|
+
We verify that the returned list of images of gens is a copy,
|
|
1875
|
+
so changing it doesn't change ``f``::
|
|
1876
|
+
|
|
1877
|
+
sage: f.im_gens()[0] = 5
|
|
1878
|
+
sage: f.im_gens()
|
|
1879
|
+
[x, x + y]
|
|
1880
|
+
"""
|
|
1881
|
+
return list(self._im_gens)
|
|
1882
|
+
|
|
1883
|
+
def base_map(self):
|
|
1884
|
+
"""
|
|
1885
|
+
Return the map on the base ring that is part of the defining
|
|
1886
|
+
data for this morphism. May return ``None`` if a coercion is used.
|
|
1887
|
+
|
|
1888
|
+
EXAMPLES::
|
|
1889
|
+
|
|
1890
|
+
sage: # needs sage.rings.number_field
|
|
1891
|
+
sage: R.<x> = ZZ[]
|
|
1892
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
1893
|
+
sage: cc = K.hom([-i])
|
|
1894
|
+
sage: S.<y> = K[]
|
|
1895
|
+
sage: phi = S.hom([y^2], base_map=cc)
|
|
1896
|
+
sage: phi
|
|
1897
|
+
Ring endomorphism of Univariate Polynomial Ring in y
|
|
1898
|
+
over Number Field in i with defining polynomial x^2 + 1
|
|
1899
|
+
Defn: y |--> y^2
|
|
1900
|
+
with map of base ring
|
|
1901
|
+
sage: phi(y)
|
|
1902
|
+
y^2
|
|
1903
|
+
sage: phi(i*y)
|
|
1904
|
+
-i*y^2
|
|
1905
|
+
sage: phi.base_map()
|
|
1906
|
+
Composite map:
|
|
1907
|
+
From: Number Field in i with defining polynomial x^2 + 1
|
|
1908
|
+
To: Univariate Polynomial Ring in y over Number Field in i
|
|
1909
|
+
with defining polynomial x^2 + 1
|
|
1910
|
+
Defn: Ring endomorphism of Number Field in i with defining polynomial x^2 + 1
|
|
1911
|
+
Defn: i |--> -i
|
|
1912
|
+
then
|
|
1913
|
+
Polynomial base injection morphism:
|
|
1914
|
+
From: Number Field in i with defining polynomial x^2 + 1
|
|
1915
|
+
To: Univariate Polynomial Ring in y over Number Field in i
|
|
1916
|
+
with defining polynomial x^2 + 1
|
|
1917
|
+
"""
|
|
1918
|
+
return self._base_map
|
|
1919
|
+
|
|
1920
|
+
cdef _update_slots(self, dict _slots):
|
|
1921
|
+
"""
|
|
1922
|
+
Helper for copying and pickling.
|
|
1923
|
+
|
|
1924
|
+
EXAMPLES::
|
|
1925
|
+
|
|
1926
|
+
sage: R.<x,y> = QQ[]
|
|
1927
|
+
sage: f = R.hom([x, x + y])
|
|
1928
|
+
sage: g = copy(f) # indirect doctest
|
|
1929
|
+
sage: g == f
|
|
1930
|
+
True
|
|
1931
|
+
sage: g is f
|
|
1932
|
+
False
|
|
1933
|
+
sage: g(y)
|
|
1934
|
+
x + y
|
|
1935
|
+
"""
|
|
1936
|
+
self._im_gens = _slots['__im_gens'] # double underscores for legacy pickles
|
|
1937
|
+
self._base_map = _slots.get('_base_map')
|
|
1938
|
+
RingHomomorphism._update_slots(self, _slots)
|
|
1939
|
+
|
|
1940
|
+
cdef dict _extra_slots(self):
|
|
1941
|
+
"""
|
|
1942
|
+
Helper for copying and pickling.
|
|
1943
|
+
|
|
1944
|
+
EXAMPLES::
|
|
1945
|
+
|
|
1946
|
+
sage: R.<x,y> = QQ[]
|
|
1947
|
+
sage: f = R.hom([x, x + y])
|
|
1948
|
+
sage: g = copy(f) # indirect doctest
|
|
1949
|
+
sage: g == f
|
|
1950
|
+
True
|
|
1951
|
+
sage: g is f
|
|
1952
|
+
False
|
|
1953
|
+
sage: g(y)
|
|
1954
|
+
x + y
|
|
1955
|
+
"""
|
|
1956
|
+
slots = RingHomomorphism._extra_slots(self)
|
|
1957
|
+
slots['__im_gens'] = self._im_gens
|
|
1958
|
+
slots['_base_map'] = self._base_map
|
|
1959
|
+
return slots
|
|
1960
|
+
|
|
1961
|
+
cpdef _richcmp_(self, other, int op):
|
|
1962
|
+
r"""
|
|
1963
|
+
EXAMPLES:
|
|
1964
|
+
|
|
1965
|
+
A single variate quotient over `\QQ`::
|
|
1966
|
+
|
|
1967
|
+
sage: # needs sage.libs.pari
|
|
1968
|
+
sage: R.<x> = QQ[]
|
|
1969
|
+
sage: Q.<a> = R.quotient(x^2 + x + 1)
|
|
1970
|
+
sage: f1 = R.hom([a])
|
|
1971
|
+
sage: f2 = R.hom([a + a^2 + a + 1])
|
|
1972
|
+
sage: f1 == f2
|
|
1973
|
+
True
|
|
1974
|
+
sage: f1 == R.hom([a^2])
|
|
1975
|
+
False
|
|
1976
|
+
sage: f1(x^3 + x)
|
|
1977
|
+
a + 1
|
|
1978
|
+
sage: f2(x^3 + x)
|
|
1979
|
+
a + 1
|
|
1980
|
+
|
|
1981
|
+
TESTS::
|
|
1982
|
+
|
|
1983
|
+
sage: loads(dumps(f2)) == f2 # needs sage.libs.pari
|
|
1984
|
+
True
|
|
1985
|
+
|
|
1986
|
+
::
|
|
1987
|
+
|
|
1988
|
+
sage: R.<x,y> = QQ[]; f = R.hom([x, x + y]); g = R.hom([y, x])
|
|
1989
|
+
sage: f == g # indirect doctest
|
|
1990
|
+
False
|
|
1991
|
+
|
|
1992
|
+
EXAMPLES:
|
|
1993
|
+
|
|
1994
|
+
A multivariate quotient over a finite field::
|
|
1995
|
+
|
|
1996
|
+
sage: # needs sage.libs.singular
|
|
1997
|
+
sage: R.<x,y> = GF(7)[]
|
|
1998
|
+
sage: Q.<a,b> = R.quotient([x^2 + x + 1, y^2 + y + 1])
|
|
1999
|
+
sage: f1 = R.hom([a, b])
|
|
2000
|
+
sage: f2 = R.hom([a + a^2 + a + 1, b + b^2 + b + 1])
|
|
2001
|
+
sage: f1 == f2
|
|
2002
|
+
True
|
|
2003
|
+
sage: f1 == R.hom([b, a])
|
|
2004
|
+
False
|
|
2005
|
+
sage: x^3 + x + y^2
|
|
2006
|
+
x^3 + y^2 + x
|
|
2007
|
+
sage: f1(x^3 + x + y^2)
|
|
2008
|
+
a - b
|
|
2009
|
+
sage: f2(x^3 + x + y^2)
|
|
2010
|
+
a - b
|
|
2011
|
+
|
|
2012
|
+
TESTS::
|
|
2013
|
+
|
|
2014
|
+
sage: loads(dumps(f2)) == f2 # needs sage.libs.pari
|
|
2015
|
+
True
|
|
2016
|
+
|
|
2017
|
+
This was fixed in :issue:`24277`::
|
|
2018
|
+
|
|
2019
|
+
sage: H = End(QQ)
|
|
2020
|
+
sage: H(1) == H.identity()
|
|
2021
|
+
True
|
|
2022
|
+
"""
|
|
2023
|
+
if not isinstance(other, RingHomomorphism_im_gens):
|
|
2024
|
+
# Generic comparison
|
|
2025
|
+
return RingMap._richcmp_(self, other, op)
|
|
2026
|
+
# Check equality using the images of the generators.
|
|
2027
|
+
self_im = self._im_gens
|
|
2028
|
+
other_im = (<RingHomomorphism_im_gens>other)._im_gens
|
|
2029
|
+
self_hom = self._base_map
|
|
2030
|
+
other_hom = (<RingHomomorphism_im_gens>other)._base_map
|
|
2031
|
+
return richcmp((self_im, self_hom), (other_im, other_hom), op)
|
|
2032
|
+
|
|
2033
|
+
def __hash__(self):
|
|
2034
|
+
"""
|
|
2035
|
+
Return the hash of this morphism.
|
|
2036
|
+
|
|
2037
|
+
EXAMPLES::
|
|
2038
|
+
|
|
2039
|
+
sage: R.<x> = ZZ[]
|
|
2040
|
+
sage: s = R.hom([x+1])
|
|
2041
|
+
sage: type(s)
|
|
2042
|
+
<class 'sage.rings.morphism.RingHomomorphism_im_gens'>
|
|
2043
|
+
sage: hash(s) == hash(s)
|
|
2044
|
+
True
|
|
2045
|
+
sage: {s: 1}[s]
|
|
2046
|
+
1
|
|
2047
|
+
"""
|
|
2048
|
+
return hash((self._im_gens, self._base_map))
|
|
2049
|
+
|
|
2050
|
+
def _repr_defn(self):
|
|
2051
|
+
"""
|
|
2052
|
+
Used in constructing string representation of ``self``.
|
|
2053
|
+
|
|
2054
|
+
EXAMPLES::
|
|
2055
|
+
|
|
2056
|
+
sage: R.<x,y> = QQ[]; f = R.hom([x^2,x+y])
|
|
2057
|
+
sage: print(f._repr_defn())
|
|
2058
|
+
x |--> x^2
|
|
2059
|
+
y |--> x + y
|
|
2060
|
+
"""
|
|
2061
|
+
D = self.domain()
|
|
2062
|
+
if D in FacadeSets():
|
|
2063
|
+
D, = D.facade_for()
|
|
2064
|
+
ig = self._im_gens
|
|
2065
|
+
s = '\n'.join('{} |--> {}'.format(D.gen(i), ig[i])
|
|
2066
|
+
for i in range(D.ngens()))
|
|
2067
|
+
if s and self._base_map is not None:
|
|
2068
|
+
s += '\nwith map of base ring'
|
|
2069
|
+
return s
|
|
2070
|
+
|
|
2071
|
+
cpdef Element _call_(self, x):
|
|
2072
|
+
"""
|
|
2073
|
+
Evaluate this homomorphism at ``x``.
|
|
2074
|
+
|
|
2075
|
+
EXAMPLES::
|
|
2076
|
+
|
|
2077
|
+
sage: R.<x,y,z> = ZZ[]; f = R.hom([2*x,z,y])
|
|
2078
|
+
sage: f(x+2*y+3*z) # indirect doctest
|
|
2079
|
+
2*x + 3*y + 2*z
|
|
2080
|
+
"""
|
|
2081
|
+
return x._im_gens_(self.codomain(), self.im_gens(), base_map=self.base_map())
|
|
2082
|
+
|
|
2083
|
+
|
|
2084
|
+
cdef class RingHomomorphism_from_base(RingHomomorphism):
|
|
2085
|
+
"""
|
|
2086
|
+
A ring homomorphism determined by a ring homomorphism of the base ring.
|
|
2087
|
+
|
|
2088
|
+
AUTHOR:
|
|
2089
|
+
|
|
2090
|
+
- Simon King (initial version, 2010-04-30)
|
|
2091
|
+
|
|
2092
|
+
EXAMPLES:
|
|
2093
|
+
|
|
2094
|
+
We define two polynomial rings and a ring homomorphism::
|
|
2095
|
+
|
|
2096
|
+
sage: R.<x,y> = QQ[]
|
|
2097
|
+
sage: S.<z> = QQ[]
|
|
2098
|
+
sage: f = R.hom([2*z,3*z],S)
|
|
2099
|
+
|
|
2100
|
+
Now we construct polynomial rings based on ``R`` and ``S``, and let
|
|
2101
|
+
``f`` act on the coefficients::
|
|
2102
|
+
|
|
2103
|
+
sage: PR.<t> = R[]
|
|
2104
|
+
sage: PS = S['t']
|
|
2105
|
+
sage: Pf = PR.hom(f,PS)
|
|
2106
|
+
sage: Pf
|
|
2107
|
+
Ring morphism:
|
|
2108
|
+
From: Univariate Polynomial Ring in t
|
|
2109
|
+
over Multivariate Polynomial Ring in x, y over Rational Field
|
|
2110
|
+
To: Univariate Polynomial Ring in t
|
|
2111
|
+
over Univariate Polynomial Ring in z over Rational Field
|
|
2112
|
+
Defn: Induced from base ring by
|
|
2113
|
+
Ring morphism:
|
|
2114
|
+
From: Multivariate Polynomial Ring in x, y over Rational Field
|
|
2115
|
+
To: Univariate Polynomial Ring in z over Rational Field
|
|
2116
|
+
Defn: x |--> 2*z
|
|
2117
|
+
y |--> 3*z
|
|
2118
|
+
sage: p = (x - 4*y + 1/13)*t^2 + (1/2*x^2 - 1/3*y^2)*t + 2*y^2 + x
|
|
2119
|
+
sage: Pf(p)
|
|
2120
|
+
(-10*z + 1/13)*t^2 - z^2*t + 18*z^2 + 2*z
|
|
2121
|
+
|
|
2122
|
+
Similarly, we can construct the induced homomorphism on a matrix ring over
|
|
2123
|
+
our polynomial rings::
|
|
2124
|
+
|
|
2125
|
+
sage: # needs sage.modules
|
|
2126
|
+
sage: MR = MatrixSpace(R, 2, 2)
|
|
2127
|
+
sage: MS = MatrixSpace(S, 2, 2)
|
|
2128
|
+
sage: M = MR([x^2 + 1/7*x*y - y^2, -1/2*y^2 + 2*y + 1/6,
|
|
2129
|
+
....: 4*x^2 - 14*x, 1/2*y^2 + 13/4*x - 2/11*y])
|
|
2130
|
+
sage: Mf = MR.hom(f, MS)
|
|
2131
|
+
sage: Mf
|
|
2132
|
+
Ring morphism:
|
|
2133
|
+
From: Full MatrixSpace of 2 by 2 dense matrices
|
|
2134
|
+
over Multivariate Polynomial Ring in x, y over Rational Field
|
|
2135
|
+
To: Full MatrixSpace of 2 by 2 dense matrices
|
|
2136
|
+
over Univariate Polynomial Ring in z over Rational Field
|
|
2137
|
+
Defn: Induced from base ring by
|
|
2138
|
+
Ring morphism:
|
|
2139
|
+
From: Multivariate Polynomial Ring in x, y over Rational Field
|
|
2140
|
+
To: Univariate Polynomial Ring in z over Rational Field
|
|
2141
|
+
Defn: x |--> 2*z
|
|
2142
|
+
y |--> 3*z
|
|
2143
|
+
sage: Mf(M)
|
|
2144
|
+
[ -29/7*z^2 -9/2*z^2 + 6*z + 1/6]
|
|
2145
|
+
[ 16*z^2 - 28*z 9/2*z^2 + 131/22*z]
|
|
2146
|
+
|
|
2147
|
+
The construction of induced homomorphisms is recursive, and so we have::
|
|
2148
|
+
|
|
2149
|
+
sage: # needs sage.modules
|
|
2150
|
+
sage: MPR = MatrixSpace(PR, 2)
|
|
2151
|
+
sage: MPS = MatrixSpace(PS, 2)
|
|
2152
|
+
sage: M = MPR([(-x + y)*t^2 + 58*t - 3*x^2 + x*y,
|
|
2153
|
+
....: (- 1/7*x*y - 1/40*x)*t^2 + (5*x^2 + y^2)*t + 2*y,
|
|
2154
|
+
....: (- 1/3*y + 1)*t^2 + 1/3*x*y + y^2 + 5/2*y + 1/4,
|
|
2155
|
+
....: (x + 6*y + 1)*t^2])
|
|
2156
|
+
sage: MPf = MPR.hom(f, MPS); MPf
|
|
2157
|
+
Ring morphism:
|
|
2158
|
+
From: Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial
|
|
2159
|
+
Ring in t over Multivariate Polynomial Ring in x, y over Rational Field
|
|
2160
|
+
To: Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial
|
|
2161
|
+
Ring in t over Univariate Polynomial Ring in z over Rational Field
|
|
2162
|
+
Defn: Induced from base ring by
|
|
2163
|
+
Ring morphism:
|
|
2164
|
+
From: Univariate Polynomial Ring in t
|
|
2165
|
+
over Multivariate Polynomial Ring in x, y over Rational Field
|
|
2166
|
+
To: Univariate Polynomial Ring in t
|
|
2167
|
+
over Univariate Polynomial Ring in z over Rational Field
|
|
2168
|
+
Defn: Induced from base ring by
|
|
2169
|
+
Ring morphism:
|
|
2170
|
+
From: Multivariate Polynomial Ring in x, y over Rational Field
|
|
2171
|
+
To: Univariate Polynomial Ring in z over Rational Field
|
|
2172
|
+
Defn: x |--> 2*z
|
|
2173
|
+
y |--> 3*z
|
|
2174
|
+
sage: MPf(M)
|
|
2175
|
+
[ z*t^2 + 58*t - 6*z^2 (-6/7*z^2 - 1/20*z)*t^2 + 29*z^2*t + 6*z]
|
|
2176
|
+
[ (-z + 1)*t^2 + 11*z^2 + 15/2*z + 1/4 (20*z + 1)*t^2]
|
|
2177
|
+
"""
|
|
2178
|
+
def __init__(self, parent, underlying):
|
|
2179
|
+
"""
|
|
2180
|
+
Initialize ``self``.
|
|
2181
|
+
|
|
2182
|
+
TESTS::
|
|
2183
|
+
|
|
2184
|
+
sage: from sage.rings.morphism import RingHomomorphism_from_base
|
|
2185
|
+
sage: R.<x> = ZZ[]
|
|
2186
|
+
sage: f = R.hom([2*x], R)
|
|
2187
|
+
sage: P = MatrixSpace(R, 2).Hom(MatrixSpace(R, 2)) # needs sage.modules
|
|
2188
|
+
sage: g = RingHomomorphism_from_base(P, f) # needs sage.modules
|
|
2189
|
+
sage: g # needs sage.modules
|
|
2190
|
+
Ring endomorphism of Full MatrixSpace of 2 by 2 dense matrices
|
|
2191
|
+
over Univariate Polynomial Ring in x over Integer Ring
|
|
2192
|
+
Defn: Induced from base ring by
|
|
2193
|
+
Ring endomorphism of Univariate Polynomial Ring in x over Integer Ring
|
|
2194
|
+
Defn: x |--> 2*x
|
|
2195
|
+
|
|
2196
|
+
Note that an induced homomorphism only makes sense if domain and
|
|
2197
|
+
codomain are constructed in a compatible way. So, the following
|
|
2198
|
+
results in an error::
|
|
2199
|
+
|
|
2200
|
+
sage: P = MatrixSpace(R, 2).Hom(R['t']) # needs sage.modules
|
|
2201
|
+
sage: g = RingHomomorphism_from_base(P, f) # needs sage.modules
|
|
2202
|
+
Traceback (most recent call last):
|
|
2203
|
+
...
|
|
2204
|
+
ValueError: domain (Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring)
|
|
2205
|
+
and codomain (Univariate Polynomial Ring in t over Univariate Polynomial Ring in x over Integer Ring)
|
|
2206
|
+
must have the same functorial construction over their base rings
|
|
2207
|
+
"""
|
|
2208
|
+
RingHomomorphism.__init__(self, parent)
|
|
2209
|
+
if underlying.domain() != parent.domain().base():
|
|
2210
|
+
raise ValueError("The given homomorphism has to have the domain %s" % parent.domain().base())
|
|
2211
|
+
if underlying.codomain() != parent.codomain().base():
|
|
2212
|
+
raise ValueError("The given homomorphism has to have the codomain %s" % parent.codomain().base())
|
|
2213
|
+
if parent.domain().construction()[0] != parent.codomain().construction()[0]:
|
|
2214
|
+
raise ValueError(f"domain ({parent.domain()}) and codomain ({parent.codomain()}) must have the same functorial construction over their base rings")
|
|
2215
|
+
self._underlying = underlying
|
|
2216
|
+
|
|
2217
|
+
def underlying_map(self):
|
|
2218
|
+
"""
|
|
2219
|
+
Return the underlying homomorphism of the base ring.
|
|
2220
|
+
|
|
2221
|
+
EXAMPLES::
|
|
2222
|
+
|
|
2223
|
+
sage: # needs sage.modules
|
|
2224
|
+
sage: R.<x,y> = QQ[]
|
|
2225
|
+
sage: S.<z> = QQ[]
|
|
2226
|
+
sage: f = R.hom([2*z, 3*z], S)
|
|
2227
|
+
sage: MR = MatrixSpace(R, 2)
|
|
2228
|
+
sage: MS = MatrixSpace(S, 2)
|
|
2229
|
+
sage: g = MR.hom(f, MS)
|
|
2230
|
+
sage: g.underlying_map() == f
|
|
2231
|
+
True
|
|
2232
|
+
"""
|
|
2233
|
+
return self._underlying
|
|
2234
|
+
|
|
2235
|
+
cdef _update_slots(self, dict _slots):
|
|
2236
|
+
"""
|
|
2237
|
+
Helper for copying and pickling.
|
|
2238
|
+
|
|
2239
|
+
EXAMPLES::
|
|
2240
|
+
|
|
2241
|
+
sage: R.<x,y> = QQ[]
|
|
2242
|
+
sage: S.<z> = QQ[]
|
|
2243
|
+
sage: f = R.hom([2*z, 3*z],S)
|
|
2244
|
+
sage: PR.<t> = R[]
|
|
2245
|
+
sage: PS = S['t']
|
|
2246
|
+
sage: phi = PR.hom(f, PS)
|
|
2247
|
+
sage: type(phi)
|
|
2248
|
+
<class 'sage.rings.morphism.RingHomomorphism_from_base'>
|
|
2249
|
+
sage: psi = copy(phi); psi # indirect doctest
|
|
2250
|
+
Ring morphism:
|
|
2251
|
+
From: Univariate Polynomial Ring in t over Multivariate Polynomial Ring in x, y over Rational Field
|
|
2252
|
+
To: Univariate Polynomial Ring in t over Univariate Polynomial Ring in z over Rational Field
|
|
2253
|
+
Defn: Induced from base ring by
|
|
2254
|
+
Ring morphism:
|
|
2255
|
+
From: Multivariate Polynomial Ring in x, y over Rational Field
|
|
2256
|
+
To: Univariate Polynomial Ring in z over Rational Field
|
|
2257
|
+
Defn: x |--> 2*z
|
|
2258
|
+
y |--> 3*z
|
|
2259
|
+
sage: psi(x*t)
|
|
2260
|
+
2*z*t
|
|
2261
|
+
"""
|
|
2262
|
+
self._underlying = _slots['__underlying'] # double underscore for legacy pickles
|
|
2263
|
+
RingHomomorphism._update_slots(self, _slots)
|
|
2264
|
+
|
|
2265
|
+
cdef dict _extra_slots(self):
|
|
2266
|
+
"""
|
|
2267
|
+
Helper for copying and pickling.
|
|
2268
|
+
|
|
2269
|
+
EXAMPLES::
|
|
2270
|
+
|
|
2271
|
+
sage: R.<x,y> = QQ[]
|
|
2272
|
+
sage: S.<z> = QQ[]
|
|
2273
|
+
sage: f = R.hom([2*z,3*z],S)
|
|
2274
|
+
sage: PR.<t> = R[]
|
|
2275
|
+
sage: PS = S['t']
|
|
2276
|
+
sage: phi = PR.hom(f,PS)
|
|
2277
|
+
sage: type(phi)
|
|
2278
|
+
<class 'sage.rings.morphism.RingHomomorphism_from_base'>
|
|
2279
|
+
sage: psi = copy(phi); psi # indirect doctest
|
|
2280
|
+
Ring morphism:
|
|
2281
|
+
From: Univariate Polynomial Ring in t over Multivariate Polynomial Ring in x, y over Rational Field
|
|
2282
|
+
To: Univariate Polynomial Ring in t over Univariate Polynomial Ring in z over Rational Field
|
|
2283
|
+
Defn: Induced from base ring by
|
|
2284
|
+
Ring morphism:
|
|
2285
|
+
From: Multivariate Polynomial Ring in x, y over Rational Field
|
|
2286
|
+
To: Univariate Polynomial Ring in z over Rational Field
|
|
2287
|
+
Defn: x |--> 2*z
|
|
2288
|
+
y |--> 3*z
|
|
2289
|
+
sage: psi(x*t)
|
|
2290
|
+
2*z*t
|
|
2291
|
+
"""
|
|
2292
|
+
slots = RingHomomorphism._extra_slots(self)
|
|
2293
|
+
slots['__underlying'] = self._underlying
|
|
2294
|
+
return slots
|
|
2295
|
+
|
|
2296
|
+
cpdef _richcmp_(self, other, int op):
|
|
2297
|
+
r"""
|
|
2298
|
+
EXAMPLES:
|
|
2299
|
+
|
|
2300
|
+
A multivariate polynomial ring over a single variate quotient over
|
|
2301
|
+
`\QQ`::
|
|
2302
|
+
|
|
2303
|
+
sage: # needs sage.libs.pari sage.libs.singular sage.modules
|
|
2304
|
+
sage: R.<x> = QQ[]
|
|
2305
|
+
sage: Q.<a> = R.quotient(x^2 + x + 1)
|
|
2306
|
+
sage: f1 = R.hom([a])
|
|
2307
|
+
sage: f2 = R.hom([a + a^2 + a + 1])
|
|
2308
|
+
sage: PR.<s,t> = R[]
|
|
2309
|
+
sage: PQ = Q['s','t']
|
|
2310
|
+
sage: f1P = PR.hom(f1,PQ)
|
|
2311
|
+
sage: f2P = PR.hom(f2,PQ)
|
|
2312
|
+
sage: f1P == f2P
|
|
2313
|
+
True
|
|
2314
|
+
|
|
2315
|
+
TESTS::
|
|
2316
|
+
|
|
2317
|
+
sage: f1P == loads(dumps(f1P)) # needs sage.libs.pari sage.libs.singular sage.modules
|
|
2318
|
+
True
|
|
2319
|
+
|
|
2320
|
+
sage: R.<x,y> = QQ[]; f = R.hom([x, x + y]); g = R.hom([y, x])
|
|
2321
|
+
sage: S.<z> = R[]
|
|
2322
|
+
sage: fS = S.hom(f, S); gS = S.hom(g, S)
|
|
2323
|
+
sage: fS != gS # indirect doctest
|
|
2324
|
+
True
|
|
2325
|
+
|
|
2326
|
+
EXAMPLES:
|
|
2327
|
+
|
|
2328
|
+
A matrix ring over a multivariate quotient over a finite field::
|
|
2329
|
+
|
|
2330
|
+
sage: # needs sage.libs.singular sage.modules
|
|
2331
|
+
sage: R.<x,y> = GF(7)[]
|
|
2332
|
+
sage: Q.<a,b> = R.quotient([x^2 + x + 1, y^2 + y + 1])
|
|
2333
|
+
sage: f1 = R.hom([a, b])
|
|
2334
|
+
sage: f2 = R.hom([a + a^2 + a + 1, b + b^2 + b + 1])
|
|
2335
|
+
sage: MR = MatrixSpace(R, 2)
|
|
2336
|
+
sage: MQ = MatrixSpace(Q, 2)
|
|
2337
|
+
sage: f1M = MR.hom(f1, MQ)
|
|
2338
|
+
sage: f2M = MR.hom(f2, MQ)
|
|
2339
|
+
sage: f1M == f2M
|
|
2340
|
+
True
|
|
2341
|
+
|
|
2342
|
+
TESTS::
|
|
2343
|
+
|
|
2344
|
+
sage: f1M == loads(dumps(f1M)) # needs sage.libs.singular sage.modules
|
|
2345
|
+
True
|
|
2346
|
+
"""
|
|
2347
|
+
if not isinstance(other, RingHomomorphism_from_base):
|
|
2348
|
+
# Generic comparison
|
|
2349
|
+
return RingMap._richcmp_(self, other, op)
|
|
2350
|
+
self_underlying = self._underlying
|
|
2351
|
+
other_underlying = (<RingHomomorphism_from_base>other)._underlying
|
|
2352
|
+
return richcmp(self_underlying, other_underlying, op)
|
|
2353
|
+
|
|
2354
|
+
def _repr_defn(self):
|
|
2355
|
+
"""
|
|
2356
|
+
Used in constructing string representation of ``self``.
|
|
2357
|
+
|
|
2358
|
+
EXAMPLES:
|
|
2359
|
+
|
|
2360
|
+
We use a matrix ring over univariate polynomial ring over the fraction field
|
|
2361
|
+
over a multivariate polynomial ring::
|
|
2362
|
+
|
|
2363
|
+
sage: R1.<x,y> = ZZ[]
|
|
2364
|
+
sage: f = R1.hom([x + y, x - y])
|
|
2365
|
+
sage: R2 = MatrixSpace(FractionField(R1)['t'], 2) # needs sage.modules
|
|
2366
|
+
sage: g = R2.hom(f, R2) # needs sage.modules
|
|
2367
|
+
sage: g # indirect doctest # needs sage.modules
|
|
2368
|
+
Ring endomorphism of Full MatrixSpace of 2 by 2 dense matrices
|
|
2369
|
+
over Univariate Polynomial Ring in t over Fraction Field of Multivariate Polynomial Ring in x, y over Integer Ring
|
|
2370
|
+
Defn: Induced from base ring by
|
|
2371
|
+
Ring endomorphism of Univariate Polynomial Ring in t over Fraction Field of Multivariate Polynomial Ring in x, y over Integer Ring
|
|
2372
|
+
Defn: Induced from base ring by
|
|
2373
|
+
Ring endomorphism of Fraction Field of Multivariate Polynomial Ring in x, y over Integer Ring
|
|
2374
|
+
Defn: x |--> x + y
|
|
2375
|
+
y |--> x - y
|
|
2376
|
+
"""
|
|
2377
|
+
U = repr(self._underlying).split('\n')
|
|
2378
|
+
return 'Induced from base ring by\n'+'\n'.join(U)
|
|
2379
|
+
|
|
2380
|
+
cpdef Element _call_(self, x):
|
|
2381
|
+
"""
|
|
2382
|
+
Evaluate this homomorphism at ``x``.
|
|
2383
|
+
|
|
2384
|
+
EXAMPLES::
|
|
2385
|
+
|
|
2386
|
+
sage: R1.<x,y> = ZZ[]
|
|
2387
|
+
sage: f = R1.hom([x+y,x-y])
|
|
2388
|
+
sage: f(2*x + y + 2) # indirect doctest
|
|
2389
|
+
3*x + y + 2
|
|
2390
|
+
"""
|
|
2391
|
+
P = self.codomain()
|
|
2392
|
+
try:
|
|
2393
|
+
return P({a: self._underlying(b) for a, b in x.monomial_coefficients().items()})
|
|
2394
|
+
except Exception:
|
|
2395
|
+
pass
|
|
2396
|
+
try:
|
|
2397
|
+
return P([self._underlying(b) for b in x])
|
|
2398
|
+
except Exception:
|
|
2399
|
+
pass
|
|
2400
|
+
try:
|
|
2401
|
+
return P(self._underlying(x.numerator()))/P(self._underlying(x.denominator()))
|
|
2402
|
+
except Exception:
|
|
2403
|
+
raise TypeError("invalid argument %s" % repr(x))
|
|
2404
|
+
|
|
2405
|
+
@cached_method
|
|
2406
|
+
def inverse(self):
|
|
2407
|
+
"""
|
|
2408
|
+
Return the inverse of this ring homomorphism if the underlying
|
|
2409
|
+
homomorphism of the base ring is invertible.
|
|
2410
|
+
|
|
2411
|
+
EXAMPLES::
|
|
2412
|
+
|
|
2413
|
+
sage: R.<x,y> = QQ[]
|
|
2414
|
+
sage: S.<a,b> = QQ[]
|
|
2415
|
+
sage: f = R.hom([a + b, a - b], S)
|
|
2416
|
+
sage: PR.<t> = R[]
|
|
2417
|
+
sage: PS = S['t']
|
|
2418
|
+
sage: Pf = PR.hom(f, PS)
|
|
2419
|
+
sage: Pf.inverse() # needs sage.libs.singular
|
|
2420
|
+
Ring morphism:
|
|
2421
|
+
From: Univariate Polynomial Ring in t over Multivariate
|
|
2422
|
+
Polynomial Ring in a, b over Rational Field
|
|
2423
|
+
To: Univariate Polynomial Ring in t over Multivariate
|
|
2424
|
+
Polynomial Ring in x, y over Rational Field
|
|
2425
|
+
Defn: Induced from base ring by
|
|
2426
|
+
Ring morphism:
|
|
2427
|
+
From: Multivariate Polynomial Ring in a, b over Rational Field
|
|
2428
|
+
To: Multivariate Polynomial Ring in x, y over Rational Field
|
|
2429
|
+
Defn: a |--> 1/2*x + 1/2*y
|
|
2430
|
+
b |--> 1/2*x - 1/2*y
|
|
2431
|
+
sage: Pf.inverse()(Pf(x*t^2 + y*t)) # needs sage.libs.singular
|
|
2432
|
+
x*t^2 + y*t
|
|
2433
|
+
"""
|
|
2434
|
+
return self.parent().reversed()(self._underlying.inverse())
|
|
2435
|
+
|
|
2436
|
+
|
|
2437
|
+
cdef class RingHomomorphism_from_fraction_field(RingHomomorphism):
|
|
2438
|
+
r"""
|
|
2439
|
+
Morphisms between fraction fields.
|
|
2440
|
+
|
|
2441
|
+
TESTS::
|
|
2442
|
+
|
|
2443
|
+
sage: S.<x> = QQ[]
|
|
2444
|
+
sage: f = S.hom([x^2])
|
|
2445
|
+
sage: g = f.extend_to_fraction_field() # needs sage.libs.singular
|
|
2446
|
+
sage: type(g) # needs sage.libs.singular
|
|
2447
|
+
<class 'sage.rings.morphism.RingHomomorphism_from_fraction_field'>
|
|
2448
|
+
"""
|
|
2449
|
+
def __init__(self, parent, morphism):
|
|
2450
|
+
r"""
|
|
2451
|
+
Initialize this morphism.
|
|
2452
|
+
|
|
2453
|
+
TESTS::
|
|
2454
|
+
|
|
2455
|
+
sage: # needs sage.rings.number_field
|
|
2456
|
+
sage: x = polygen(ZZ, 'x')
|
|
2457
|
+
sage: A.<a> = ZZ.extension(x^2 - 2)
|
|
2458
|
+
sage: f = A.coerce_map_from(ZZ)
|
|
2459
|
+
sage: g = f.extend_to_fraction_field() # indirect doctest
|
|
2460
|
+
sage: g
|
|
2461
|
+
Ring morphism:
|
|
2462
|
+
From: Rational Field
|
|
2463
|
+
To: Number Field in a with defining polynomial x^2 - 2
|
|
2464
|
+
"""
|
|
2465
|
+
RingHomomorphism.__init__(self, parent)
|
|
2466
|
+
self._morphism = morphism
|
|
2467
|
+
|
|
2468
|
+
def _repr_defn(self):
|
|
2469
|
+
r"""
|
|
2470
|
+
Return a string definition of this morphism.
|
|
2471
|
+
|
|
2472
|
+
EXAMPLES::
|
|
2473
|
+
|
|
2474
|
+
sage: S.<x> = QQ[]
|
|
2475
|
+
sage: f = S.hom([x^2]).extend_to_fraction_field() # needs sage.libs.singular
|
|
2476
|
+
sage: f # needs sage.libs.singular
|
|
2477
|
+
Ring endomorphism of Fraction Field of Univariate Polynomial Ring in x over Rational Field
|
|
2478
|
+
Defn: x |--> x^2
|
|
2479
|
+
sage: f._repr_defn() # needs sage.libs.singular
|
|
2480
|
+
'x |--> x^2'
|
|
2481
|
+
"""
|
|
2482
|
+
return self._morphism._repr_defn()
|
|
2483
|
+
|
|
2484
|
+
cpdef Element _call_(self, x):
|
|
2485
|
+
r"""
|
|
2486
|
+
Return the value of this morphism at ``x``.
|
|
2487
|
+
|
|
2488
|
+
INPUT:
|
|
2489
|
+
|
|
2490
|
+
- ``x`` -- an element in the domain of this morphism
|
|
2491
|
+
|
|
2492
|
+
EXAMPLES::
|
|
2493
|
+
|
|
2494
|
+
sage: S.<x> = QQ[]
|
|
2495
|
+
sage: f = S.hom([x + 1]).extend_to_fraction_field() # needs sage.libs.singular
|
|
2496
|
+
sage: f(1/x) # needs sage.libs.singular
|
|
2497
|
+
1/(x + 1)
|
|
2498
|
+
sage: f(1/(x-1)) # needs sage.libs.singular
|
|
2499
|
+
1/x
|
|
2500
|
+
"""
|
|
2501
|
+
return self._morphism(x.numerator()) / self._morphism(x.denominator())
|
|
2502
|
+
|
|
2503
|
+
cdef _update_slots(self, dict _slots):
|
|
2504
|
+
"""
|
|
2505
|
+
Helper function for copying and pickling.
|
|
2506
|
+
|
|
2507
|
+
TESTS::
|
|
2508
|
+
|
|
2509
|
+
sage: # needs sage.libs.singular
|
|
2510
|
+
sage: S.<x> = QQ[]
|
|
2511
|
+
sage: f = S.hom([x + 1]).extend_to_fraction_field()
|
|
2512
|
+
|
|
2513
|
+
sage: g = copy(f) # indirect doctest # needs sage.libs.singular
|
|
2514
|
+
sage: f == g # needs sage.libs.singular
|
|
2515
|
+
True
|
|
2516
|
+
sage: f is g # needs sage.libs.singular
|
|
2517
|
+
False
|
|
2518
|
+
"""
|
|
2519
|
+
self._morphism = _slots['_morphism']
|
|
2520
|
+
RingHomomorphism._update_slots(self, _slots)
|
|
2521
|
+
|
|
2522
|
+
cdef dict _extra_slots(self):
|
|
2523
|
+
"""
|
|
2524
|
+
Helper function for copying and pickling.
|
|
2525
|
+
|
|
2526
|
+
TESTS::
|
|
2527
|
+
|
|
2528
|
+
sage: S.<x> = QQ[]
|
|
2529
|
+
sage: f = S.hom([x + 1]).extend_to_fraction_field() # needs sage.libs.singular
|
|
2530
|
+
sage: loads(dumps(f)) == f # needs sage.libs.singular
|
|
2531
|
+
True
|
|
2532
|
+
"""
|
|
2533
|
+
slots = RingHomomorphism._extra_slots(self)
|
|
2534
|
+
slots['_morphism'] = self._morphism
|
|
2535
|
+
return slots
|
|
2536
|
+
|
|
2537
|
+
@cached_method
|
|
2538
|
+
def inverse(self):
|
|
2539
|
+
"""
|
|
2540
|
+
Return the inverse of this ring homomorphism if it exists.
|
|
2541
|
+
|
|
2542
|
+
EXAMPLES::
|
|
2543
|
+
|
|
2544
|
+
sage: S.<x> = QQ[]
|
|
2545
|
+
sage: f = S.hom([2*x - 1])
|
|
2546
|
+
sage: g = f.extend_to_fraction_field() # needs sage.libs.singular
|
|
2547
|
+
sage: g.inverse() # needs sage.libs.singular
|
|
2548
|
+
Ring endomorphism of Fraction Field of Univariate Polynomial Ring
|
|
2549
|
+
in x over Rational Field
|
|
2550
|
+
Defn: x |--> 1/2*x + 1/2
|
|
2551
|
+
"""
|
|
2552
|
+
return self.parent().reversed()(self._morphism.inverse())
|
|
2553
|
+
|
|
2554
|
+
|
|
2555
|
+
cdef class RingHomomorphism_cover(RingHomomorphism):
|
|
2556
|
+
r"""
|
|
2557
|
+
A homomorphism induced by quotienting a ring out by an ideal.
|
|
2558
|
+
|
|
2559
|
+
EXAMPLES::
|
|
2560
|
+
|
|
2561
|
+
sage: R.<x,y> = PolynomialRing(QQ, 2)
|
|
2562
|
+
sage: S.<a,b> = R.quo(x^2 + y^2) # needs sage.libs.singular
|
|
2563
|
+
sage: phi = S.cover(); phi # needs sage.libs.singular
|
|
2564
|
+
Ring morphism:
|
|
2565
|
+
From: Multivariate Polynomial Ring in x, y over Rational Field
|
|
2566
|
+
To: Quotient of Multivariate Polynomial Ring in x, y over Rational Field
|
|
2567
|
+
by the ideal (x^2 + y^2)
|
|
2568
|
+
Defn: Natural quotient map
|
|
2569
|
+
sage: phi(x + y) # needs sage.libs.singular
|
|
2570
|
+
a + b
|
|
2571
|
+
"""
|
|
2572
|
+
def __init__(self, parent):
|
|
2573
|
+
"""
|
|
2574
|
+
Create a covering ring homomorphism, induced by quotienting out by an
|
|
2575
|
+
ideal.
|
|
2576
|
+
|
|
2577
|
+
EXAMPLES::
|
|
2578
|
+
|
|
2579
|
+
sage: f = Zmod(6).cover(); f # implicit test
|
|
2580
|
+
Ring morphism:
|
|
2581
|
+
From: Integer Ring
|
|
2582
|
+
To: Ring of integers modulo 6
|
|
2583
|
+
Defn: Natural quotient map
|
|
2584
|
+
sage: type(f)
|
|
2585
|
+
<class 'sage.rings.morphism.RingHomomorphism_cover'>
|
|
2586
|
+
"""
|
|
2587
|
+
RingHomomorphism.__init__(self, parent)
|
|
2588
|
+
|
|
2589
|
+
cpdef Element _call_(self, x):
|
|
2590
|
+
"""
|
|
2591
|
+
Evaluate this covering homomorphism at ``x``, which just involves
|
|
2592
|
+
coercing ``x`` into the domain, then codomain.
|
|
2593
|
+
|
|
2594
|
+
EXAMPLES::
|
|
2595
|
+
|
|
2596
|
+
sage: f = Zmod(6).cover()
|
|
2597
|
+
sage: type(f)
|
|
2598
|
+
<class 'sage.rings.morphism.RingHomomorphism_cover'>
|
|
2599
|
+
sage: f(-5) # indirect doctest
|
|
2600
|
+
1
|
|
2601
|
+
|
|
2602
|
+
TESTS:
|
|
2603
|
+
|
|
2604
|
+
We verify that calling directly raises the expected error
|
|
2605
|
+
(just coercing into the codomain), but calling with __call__
|
|
2606
|
+
(the second call below) gives a :exc:`TypeError` since 1/2 cannot be
|
|
2607
|
+
coerced into the domain. ::
|
|
2608
|
+
|
|
2609
|
+
sage: f._call_(1/2)
|
|
2610
|
+
Traceback (most recent call last):
|
|
2611
|
+
...
|
|
2612
|
+
ZeroDivisionError: inverse of Mod(2, 6) does not exist
|
|
2613
|
+
sage: f(1/2)
|
|
2614
|
+
Traceback (most recent call last):
|
|
2615
|
+
...
|
|
2616
|
+
TypeError: 1/2 fails to convert into the map's domain Integer Ring,
|
|
2617
|
+
but a `pushforward` method is not properly implemented
|
|
2618
|
+
"""
|
|
2619
|
+
return self.codomain()(x)
|
|
2620
|
+
|
|
2621
|
+
def _repr_defn(self):
|
|
2622
|
+
"""
|
|
2623
|
+
Used internally for printing covering morphisms.
|
|
2624
|
+
|
|
2625
|
+
EXAMPLES::
|
|
2626
|
+
|
|
2627
|
+
sage: f = Zmod(6).cover()
|
|
2628
|
+
sage: f._repr_defn()
|
|
2629
|
+
'Natural quotient map'
|
|
2630
|
+
sage: type(f)
|
|
2631
|
+
<class 'sage.rings.morphism.RingHomomorphism_cover'>
|
|
2632
|
+
"""
|
|
2633
|
+
return "Natural quotient map"
|
|
2634
|
+
|
|
2635
|
+
def kernel(self):
|
|
2636
|
+
"""
|
|
2637
|
+
Return the kernel of this covering morphism, which is the ideal that
|
|
2638
|
+
was quotiented out by.
|
|
2639
|
+
|
|
2640
|
+
EXAMPLES::
|
|
2641
|
+
|
|
2642
|
+
sage: f = Zmod(6).cover()
|
|
2643
|
+
sage: f.kernel()
|
|
2644
|
+
Principal ideal (6) of Integer Ring
|
|
2645
|
+
"""
|
|
2646
|
+
return self.codomain().defining_ideal()
|
|
2647
|
+
|
|
2648
|
+
cpdef _richcmp_(self, other, int op):
|
|
2649
|
+
"""
|
|
2650
|
+
Compare ``self`` to ``other``.
|
|
2651
|
+
|
|
2652
|
+
EXAMPLES::
|
|
2653
|
+
|
|
2654
|
+
sage: # needs sage.libs.singular
|
|
2655
|
+
sage: R.<x,y> = PolynomialRing(QQ, 2)
|
|
2656
|
+
sage: S.<a,b> = R.quo(x^2 + y^2)
|
|
2657
|
+
sage: phi = S.cover()
|
|
2658
|
+
sage: phi == loads(dumps(phi))
|
|
2659
|
+
True
|
|
2660
|
+
sage: phi == R.quo(x^2 + y^3).cover()
|
|
2661
|
+
False
|
|
2662
|
+
"""
|
|
2663
|
+
if not isinstance(other, RingHomomorphism_cover):
|
|
2664
|
+
# Generic comparison
|
|
2665
|
+
return RingMap._richcmp_(self, other, op)
|
|
2666
|
+
# Two cover maps with the same parent must be equal
|
|
2667
|
+
return rich_to_bool(op, 0)
|
|
2668
|
+
|
|
2669
|
+
def __hash__(self):
|
|
2670
|
+
"""
|
|
2671
|
+
Return the hash of this morphism.
|
|
2672
|
+
|
|
2673
|
+
TESTS::
|
|
2674
|
+
|
|
2675
|
+
sage: # needs sage.libs.singular
|
|
2676
|
+
sage: R.<x,y> = PolynomialRing(QQ, 2)
|
|
2677
|
+
sage: S.<a,b> = R.quo(x^2 + y^2)
|
|
2678
|
+
sage: phi = S.cover()
|
|
2679
|
+
sage: type(phi)
|
|
2680
|
+
<class 'sage.rings.morphism.RingHomomorphism_cover'>
|
|
2681
|
+
sage: hash(phi) == hash(phi)
|
|
2682
|
+
True
|
|
2683
|
+
sage: {phi: 1}[phi]
|
|
2684
|
+
1
|
|
2685
|
+
"""
|
|
2686
|
+
return hash((self.domain(), self.codomain()))
|
|
2687
|
+
|
|
2688
|
+
def _inverse_image_ideal(self, I):
|
|
2689
|
+
"""
|
|
2690
|
+
Return the inverse image of the ideal `I` under this covering morphism.
|
|
2691
|
+
|
|
2692
|
+
INPUT:
|
|
2693
|
+
|
|
2694
|
+
- ``I`` -- an ideal in the quotient ring
|
|
2695
|
+
|
|
2696
|
+
EXAMPLES::
|
|
2697
|
+
|
|
2698
|
+
sage: # needs sage.libs.singular
|
|
2699
|
+
sage: R.<x,y> = QQ['x,y'].quotient('x^2 * y^2')
|
|
2700
|
+
sage: R.cover().inverse_image(R.ideal(x^3, y^3 + 1))
|
|
2701
|
+
Ideal (x^2*y^2, x^3, y^3 + 1) of Multivariate Polynomial Ring
|
|
2702
|
+
in x, y over Rational Field
|
|
2703
|
+
sage: S.<u,v> = QQbar['u,v'].quotient('u^4 - 1')
|
|
2704
|
+
sage: S.cover().inverse_image(S.ideal(u^2 - 1))
|
|
2705
|
+
Ideal (u^4 - 1, u^2 - 1) of Multivariate Polynomial Ring in u, v
|
|
2706
|
+
over Algebraic Field
|
|
2707
|
+
"""
|
|
2708
|
+
if I.is_zero():
|
|
2709
|
+
return self.kernel()
|
|
2710
|
+
return self.kernel() + [f.lift() for f in I.gens()]
|
|
2711
|
+
|
|
2712
|
+
def _inverse_image_element(self, b):
|
|
2713
|
+
"""
|
|
2714
|
+
Lift an element from the quotient to the cover ring of this ring
|
|
2715
|
+
homomorphism.
|
|
2716
|
+
|
|
2717
|
+
EXAMPLES::
|
|
2718
|
+
|
|
2719
|
+
sage: Q.<u,v> = QQ['x,y'].quotient('x + y') # needs sage.libs.singular
|
|
2720
|
+
sage: Q.cover().inverse_image(u) # needs sage.libs.singular
|
|
2721
|
+
-y
|
|
2722
|
+
"""
|
|
2723
|
+
return b.lift()
|
|
2724
|
+
|
|
2725
|
+
|
|
2726
|
+
cdef class RingHomomorphism_from_quotient(RingHomomorphism):
|
|
2727
|
+
r"""
|
|
2728
|
+
A ring homomorphism with domain a generic quotient ring.
|
|
2729
|
+
|
|
2730
|
+
INPUT:
|
|
2731
|
+
|
|
2732
|
+
- ``parent`` -- a ring homset ``Hom(R,S)``
|
|
2733
|
+
|
|
2734
|
+
- ``phi`` -- a ring homomorphism ``C --> S``, where ``C`` is the
|
|
2735
|
+
domain of ``R.cover()``
|
|
2736
|
+
|
|
2737
|
+
OUTPUT: a ring homomorphism
|
|
2738
|
+
|
|
2739
|
+
The domain `R` is a quotient object `C \to R`, and
|
|
2740
|
+
``R.cover()`` is the ring homomorphism
|
|
2741
|
+
`\varphi: C \to R`. The condition on the elements
|
|
2742
|
+
``im_gens`` of `S` is that they define a
|
|
2743
|
+
homomorphism `C \to S` such that each generator of the
|
|
2744
|
+
kernel of `\varphi` maps to `0`.
|
|
2745
|
+
|
|
2746
|
+
EXAMPLES::
|
|
2747
|
+
|
|
2748
|
+
sage: # needs sage.libs.singular
|
|
2749
|
+
sage: R.<x, y, z> = PolynomialRing(QQ, 3)
|
|
2750
|
+
sage: S.<a, b, c> = R.quo(x^3 + y^3 + z^3)
|
|
2751
|
+
sage: phi = S.hom([b, c, a]); phi
|
|
2752
|
+
Ring endomorphism of Quotient of Multivariate Polynomial Ring in x, y, z
|
|
2753
|
+
over Rational Field by the ideal (x^3 + y^3 + z^3)
|
|
2754
|
+
Defn: a |--> b
|
|
2755
|
+
b |--> c
|
|
2756
|
+
c |--> a
|
|
2757
|
+
sage: phi(a + b + c)
|
|
2758
|
+
a + b + c
|
|
2759
|
+
sage: loads(dumps(phi)) == phi
|
|
2760
|
+
True
|
|
2761
|
+
|
|
2762
|
+
Validity of the homomorphism is determined, when possible, and a
|
|
2763
|
+
:exc:`TypeError` is raised if there is no homomorphism sending the
|
|
2764
|
+
generators to the given images::
|
|
2765
|
+
|
|
2766
|
+
sage: S.hom([b^2, c^2, a^2]) # needs sage.libs.singular
|
|
2767
|
+
Traceback (most recent call last):
|
|
2768
|
+
...
|
|
2769
|
+
ValueError: relations do not all (canonically) map to 0
|
|
2770
|
+
under map determined by images of generators
|
|
2771
|
+
"""
|
|
2772
|
+
def __init__(self, parent, phi):
|
|
2773
|
+
"""
|
|
2774
|
+
Initialize ``self``.
|
|
2775
|
+
|
|
2776
|
+
EXAMPLES::
|
|
2777
|
+
|
|
2778
|
+
sage: R.<x,y> = QQ[]; S.<xx,yy> = R.quo([x^2,y^2]); S.hom([yy,xx]) # needs sage.libs.singular
|
|
2779
|
+
Ring endomorphism of Quotient of Multivariate Polynomial Ring in x, y
|
|
2780
|
+
over Rational Field by the ideal (x^2, y^2)
|
|
2781
|
+
Defn: xx |--> yy
|
|
2782
|
+
yy |--> xx
|
|
2783
|
+
"""
|
|
2784
|
+
RingHomomorphism.__init__(self, parent)
|
|
2785
|
+
R = parent.domain()
|
|
2786
|
+
pi = R.cover() # the covering map, which should be a RingHomomorphism
|
|
2787
|
+
if not isinstance(pi, RingHomomorphism):
|
|
2788
|
+
raise TypeError("pi should be a ring homomorphism")
|
|
2789
|
+
if not isinstance(phi, RingHomomorphism):
|
|
2790
|
+
raise TypeError("phi should be a ring homomorphism")
|
|
2791
|
+
if pi.domain() != phi.domain():
|
|
2792
|
+
raise ValueError("Domain of phi must equal domain of covering (%s != %s)." % (pi.domain(), phi.domain()))
|
|
2793
|
+
for x in pi.kernel().gens():
|
|
2794
|
+
if phi(x) != 0:
|
|
2795
|
+
raise ValueError("relations do not all (canonically) map to 0 under map determined by images of generators")
|
|
2796
|
+
self._lift = pi.lift()
|
|
2797
|
+
self.phi = phi
|
|
2798
|
+
|
|
2799
|
+
cdef _update_slots(self, dict _slots):
|
|
2800
|
+
"""
|
|
2801
|
+
Helper for copying and pickling.
|
|
2802
|
+
|
|
2803
|
+
EXAMPLES::
|
|
2804
|
+
|
|
2805
|
+
sage: # needs sage.libs.singular
|
|
2806
|
+
sage: R.<x, y, z> = PolynomialRing(QQ, 3)
|
|
2807
|
+
sage: S.<a, b, c> = R.quo(x^3 + y^3 + z^3)
|
|
2808
|
+
sage: phi = S.hom([b, c, a]); phi
|
|
2809
|
+
Ring endomorphism of Quotient of Multivariate Polynomial Ring in x, y, z
|
|
2810
|
+
over Rational Field by the ideal (x^3 + y^3 + z^3)
|
|
2811
|
+
Defn: a |--> b
|
|
2812
|
+
b |--> c
|
|
2813
|
+
c |--> a
|
|
2814
|
+
sage: phi(a + b + c)
|
|
2815
|
+
a + b + c
|
|
2816
|
+
sage: psi = copy(phi) # indirect doctest
|
|
2817
|
+
sage: psi == phi
|
|
2818
|
+
True
|
|
2819
|
+
sage: psi is phi
|
|
2820
|
+
False
|
|
2821
|
+
sage: psi(a) == phi(a)
|
|
2822
|
+
True
|
|
2823
|
+
"""
|
|
2824
|
+
self.phi = _slots['phi']
|
|
2825
|
+
RingHomomorphism._update_slots(self, _slots)
|
|
2826
|
+
|
|
2827
|
+
cdef dict _extra_slots(self):
|
|
2828
|
+
"""
|
|
2829
|
+
Helper for copying and pickling.
|
|
2830
|
+
|
|
2831
|
+
EXAMPLES::
|
|
2832
|
+
|
|
2833
|
+
sage: # needs sage.libs.singular
|
|
2834
|
+
sage: R.<x, y, z> = PolynomialRing(QQ, 3)
|
|
2835
|
+
sage: S.<a, b, c> = R.quo(x^3 + y^3 + z^3)
|
|
2836
|
+
sage: phi = S.hom([b, c, a]); phi
|
|
2837
|
+
Ring endomorphism of Quotient of Multivariate Polynomial Ring in x, y, z
|
|
2838
|
+
over Rational Field by the ideal (x^3 + y^3 + z^3)
|
|
2839
|
+
Defn: a |--> b
|
|
2840
|
+
b |--> c
|
|
2841
|
+
c |--> a
|
|
2842
|
+
sage: phi(a + b + c)
|
|
2843
|
+
a + b + c
|
|
2844
|
+
sage: psi = copy(phi) # indirect doctest
|
|
2845
|
+
sage: psi == phi
|
|
2846
|
+
True
|
|
2847
|
+
sage: psi is phi
|
|
2848
|
+
False
|
|
2849
|
+
sage: psi(a) == phi(a)
|
|
2850
|
+
True
|
|
2851
|
+
"""
|
|
2852
|
+
slots = RingHomomorphism._extra_slots(self)
|
|
2853
|
+
slots['phi'] = self.phi
|
|
2854
|
+
return slots
|
|
2855
|
+
|
|
2856
|
+
def _phi(self):
|
|
2857
|
+
"""
|
|
2858
|
+
Underlying morphism used to define this quotient map, i.e.,
|
|
2859
|
+
morphism from the cover of the domain.
|
|
2860
|
+
|
|
2861
|
+
EXAMPLES::
|
|
2862
|
+
|
|
2863
|
+
sage: R.<x,y> = QQ[]; S.<xx,yy> = R.quo([x^2, y^2]); f = S.hom([yy,xx]) # needs sage.libs.singular
|
|
2864
|
+
sage: f._phi() # needs sage.libs.singular
|
|
2865
|
+
Ring morphism:
|
|
2866
|
+
From: Multivariate Polynomial Ring in x, y over Rational Field
|
|
2867
|
+
To: Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2, y^2)
|
|
2868
|
+
Defn: x |--> yy
|
|
2869
|
+
y |--> xx
|
|
2870
|
+
"""
|
|
2871
|
+
return self.phi
|
|
2872
|
+
|
|
2873
|
+
def morphism_from_cover(self):
|
|
2874
|
+
"""
|
|
2875
|
+
Underlying morphism used to define this quotient map, i.e.,
|
|
2876
|
+
the morphism from the cover of the domain.
|
|
2877
|
+
|
|
2878
|
+
EXAMPLES::
|
|
2879
|
+
|
|
2880
|
+
sage: R.<x,y> = QQ[]; S.<xx,yy> = R.quo([x^2, y^2]) # needs sage.libs.singular
|
|
2881
|
+
sage: S.hom([yy,xx]).morphism_from_cover() # needs sage.libs.singular
|
|
2882
|
+
Ring morphism:
|
|
2883
|
+
From: Multivariate Polynomial Ring in x, y over Rational Field
|
|
2884
|
+
To: Quotient of Multivariate Polynomial Ring in x, y
|
|
2885
|
+
over Rational Field by the ideal (x^2, y^2)
|
|
2886
|
+
Defn: x |--> yy
|
|
2887
|
+
y |--> xx
|
|
2888
|
+
"""
|
|
2889
|
+
return self.phi
|
|
2890
|
+
|
|
2891
|
+
cpdef _richcmp_(self, other, int op):
|
|
2892
|
+
"""
|
|
2893
|
+
Compare ``self`` to ``other``.
|
|
2894
|
+
|
|
2895
|
+
EXAMPLES::
|
|
2896
|
+
|
|
2897
|
+
sage: # needs sage.libs.singular
|
|
2898
|
+
sage: R.<x, y, z> = PolynomialRing(GF(19), 3)
|
|
2899
|
+
sage: S.<a, b, c> = R.quo(x^3 + y^3 + z^3)
|
|
2900
|
+
sage: phi = S.hom([b, c, a])
|
|
2901
|
+
sage: psi = S.hom([c, b, a])
|
|
2902
|
+
sage: f = S.hom([b, c, a + a^3 + b^3 + c^3])
|
|
2903
|
+
sage: phi == psi
|
|
2904
|
+
False
|
|
2905
|
+
sage: phi == f
|
|
2906
|
+
True
|
|
2907
|
+
"""
|
|
2908
|
+
if not isinstance(other, RingHomomorphism_from_quotient):
|
|
2909
|
+
# Generic comparison
|
|
2910
|
+
return RingMap._richcmp_(self, other, op)
|
|
2911
|
+
# Generic comparison
|
|
2912
|
+
self_phi = self.phi
|
|
2913
|
+
other_phi = (<RingHomomorphism_from_quotient>other).phi
|
|
2914
|
+
return richcmp(self_phi, other_phi, op)
|
|
2915
|
+
|
|
2916
|
+
def __hash__(self):
|
|
2917
|
+
"""
|
|
2918
|
+
Return the hash of this morphism.
|
|
2919
|
+
|
|
2920
|
+
EXAMPLES::
|
|
2921
|
+
|
|
2922
|
+
sage: # needs sage.libs.singular
|
|
2923
|
+
sage: R.<x, y, z> = PolynomialRing(GF(19), 3)
|
|
2924
|
+
sage: S.<a, b, c> = R.quo(x^3 + y^3 + z^3)
|
|
2925
|
+
sage: phi = S.hom([b, c, a])
|
|
2926
|
+
sage: type(phi)
|
|
2927
|
+
<class 'sage.rings.morphism.RingHomomorphism_from_quotient'>
|
|
2928
|
+
sage: hash(phi) == hash(phi)
|
|
2929
|
+
True
|
|
2930
|
+
sage: {phi: 1}[phi]
|
|
2931
|
+
1
|
|
2932
|
+
"""
|
|
2933
|
+
return hash(self.phi)
|
|
2934
|
+
|
|
2935
|
+
def _repr_defn(self) -> str:
|
|
2936
|
+
"""
|
|
2937
|
+
Used internally for printing this function.
|
|
2938
|
+
|
|
2939
|
+
EXAMPLES::
|
|
2940
|
+
|
|
2941
|
+
sage: R.<x,y> = QQ[]; S.<xx,yy> = R.quo([x^2,y^2]) # needs sage.libs.singular
|
|
2942
|
+
sage: f = S.hom([yy, xx]) # needs sage.libs.singular
|
|
2943
|
+
sage: print(f._repr_defn()) # needs sage.libs.singular
|
|
2944
|
+
xx |--> yy
|
|
2945
|
+
yy |--> xx
|
|
2946
|
+
"""
|
|
2947
|
+
D = self.domain()
|
|
2948
|
+
ig = self.phi.im_gens()
|
|
2949
|
+
return '\n'.join('{} |--> {}'.format(D.gen(i), ig[i])
|
|
2950
|
+
for i in range(D.ngens()))
|
|
2951
|
+
|
|
2952
|
+
cpdef Element _call_(self, x):
|
|
2953
|
+
"""
|
|
2954
|
+
Evaluate this function at ``x``.
|
|
2955
|
+
|
|
2956
|
+
EXAMPLES::
|
|
2957
|
+
|
|
2958
|
+
sage: R.<x,y> = QQ[]; S.<xx,yy> = R.quo([x^2, y^2]); f = S.hom([yy, xx]) # needs sage.libs.singular
|
|
2959
|
+
sage: f(3*x + (1/2)*y) # indirect doctest # needs sage.libs.singular
|
|
2960
|
+
1/2*xx + 3*yy
|
|
2961
|
+
"""
|
|
2962
|
+
return self.phi(self.lift(x))
|
|
2963
|
+
|
|
2964
|
+
|
|
2965
|
+
cdef class FrobeniusEndomorphism_generic(RingHomomorphism):
|
|
2966
|
+
"""
|
|
2967
|
+
A class implementing Frobenius endomorphisms on rings of prime
|
|
2968
|
+
characteristic.
|
|
2969
|
+
"""
|
|
2970
|
+
def __init__(self, domain, n=1):
|
|
2971
|
+
"""
|
|
2972
|
+
INPUT:
|
|
2973
|
+
|
|
2974
|
+
- ``domain`` -- a ring
|
|
2975
|
+
|
|
2976
|
+
- ``n`` -- nonnegative integer (default: 1)
|
|
2977
|
+
|
|
2978
|
+
OUTPUT:
|
|
2979
|
+
|
|
2980
|
+
The `n`-th power of the absolute (arithmetic) Frobenius
|
|
2981
|
+
endomorphism on ``domain``
|
|
2982
|
+
|
|
2983
|
+
TESTS::
|
|
2984
|
+
|
|
2985
|
+
sage: from sage.rings.morphism import FrobeniusEndomorphism_generic
|
|
2986
|
+
sage: K.<u> = PowerSeriesRing(GF(5))
|
|
2987
|
+
sage: FrobeniusEndomorphism_generic(K)
|
|
2988
|
+
Frobenius endomorphism x |--> x^5 of Power Series Ring in u
|
|
2989
|
+
over Finite Field of size 5
|
|
2990
|
+
sage: FrobeniusEndomorphism_generic(K, 2)
|
|
2991
|
+
Frobenius endomorphism x |--> x^(5^2) of Power Series Ring in u
|
|
2992
|
+
over Finite Field of size 5
|
|
2993
|
+
"""
|
|
2994
|
+
from sage.rings.ring import CommutativeRing
|
|
2995
|
+
from sage.categories.commutative_rings import CommutativeRings
|
|
2996
|
+
from sage.categories.homset import Hom
|
|
2997
|
+
if not (domain in CommutativeRings() or
|
|
2998
|
+
isinstance(domain, CommutativeRing)): # TODO: remove this line
|
|
2999
|
+
raise TypeError("The base ring must be a commutative ring")
|
|
3000
|
+
self._p = domain.characteristic()
|
|
3001
|
+
if not self._p.is_prime():
|
|
3002
|
+
raise TypeError("the characteristic of the base ring must be prime")
|
|
3003
|
+
try:
|
|
3004
|
+
n = Integer(n)
|
|
3005
|
+
except TypeError:
|
|
3006
|
+
raise TypeError("n (=%s) is not a nonnegative integer" % n)
|
|
3007
|
+
if n < 0:
|
|
3008
|
+
raise TypeError("n (=%s) is not a nonnegative integer" % n)
|
|
3009
|
+
self._power = n
|
|
3010
|
+
self._q = self._p ** self._power
|
|
3011
|
+
RingHomomorphism.__init__(self, Hom(domain, domain))
|
|
3012
|
+
|
|
3013
|
+
cdef _update_slots(self, dict _slots):
|
|
3014
|
+
"""
|
|
3015
|
+
Update information with the given slots.
|
|
3016
|
+
|
|
3017
|
+
Helper function for copying or pickling.
|
|
3018
|
+
|
|
3019
|
+
EXAMPLES::
|
|
3020
|
+
|
|
3021
|
+
sage: # needs sage.rings.finite_rings
|
|
3022
|
+
sage: K = Frac(GF(5)['T'])
|
|
3023
|
+
sage: phi = K.frobenius_endomorphism()
|
|
3024
|
+
sage: psi = copy(phi)
|
|
3025
|
+
sage: phi == psi
|
|
3026
|
+
True
|
|
3027
|
+
"""
|
|
3028
|
+
self._p = _slots['_domain'].characteristic()
|
|
3029
|
+
self._power = _slots['_power']
|
|
3030
|
+
self._q = self._p ** self._power
|
|
3031
|
+
RingHomomorphism._update_slots(self, _slots)
|
|
3032
|
+
|
|
3033
|
+
cdef dict _extra_slots(self):
|
|
3034
|
+
"""
|
|
3035
|
+
Return additional information about this morphism
|
|
3036
|
+
as a dictionary.
|
|
3037
|
+
|
|
3038
|
+
Helper function for copying or pickling.
|
|
3039
|
+
|
|
3040
|
+
EXAMPLES::
|
|
3041
|
+
|
|
3042
|
+
sage: # needs sage.rings.finite_rings
|
|
3043
|
+
sage: K = Frac(GF(25)['T'])
|
|
3044
|
+
sage: phi = K.frobenius_endomorphism(2)
|
|
3045
|
+
sage: phi
|
|
3046
|
+
Frobenius endomorphism x |--> x^(5^2) of Fraction Field of
|
|
3047
|
+
Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2
|
|
3048
|
+
sage: psi = loads(dumps(phi)); psi
|
|
3049
|
+
Frobenius endomorphism x |--> x^(5^2) of Fraction Field of
|
|
3050
|
+
Univariate Polynomial Ring in T over Finite Field in z2 of size 5^2
|
|
3051
|
+
sage: phi == psi
|
|
3052
|
+
True
|
|
3053
|
+
"""
|
|
3054
|
+
slots = RingHomomorphism._extra_slots(self)
|
|
3055
|
+
slots['_power'] = self._power
|
|
3056
|
+
return slots
|
|
3057
|
+
|
|
3058
|
+
def _repr_(self):
|
|
3059
|
+
"""
|
|
3060
|
+
Return a string representation of this endomorphism.
|
|
3061
|
+
|
|
3062
|
+
EXAMPLES::
|
|
3063
|
+
|
|
3064
|
+
sage: K.<u> = PowerSeriesRing(GF(5))
|
|
3065
|
+
sage: Frob = K.frobenius_endomorphism(); Frob
|
|
3066
|
+
Frobenius endomorphism x |--> x^5 of Power Series Ring in u
|
|
3067
|
+
over Finite Field of size 5
|
|
3068
|
+
|
|
3069
|
+
sage: Frob._repr_()
|
|
3070
|
+
'Frobenius endomorphism x |--> x^5 of Power Series Ring in u
|
|
3071
|
+
over Finite Field of size 5'
|
|
3072
|
+
"""
|
|
3073
|
+
if self._power == 0:
|
|
3074
|
+
s = "Identity endomorphism"
|
|
3075
|
+
elif self._power == 1:
|
|
3076
|
+
s = "Frobenius endomorphism x |--> x^%s" % self._p
|
|
3077
|
+
else:
|
|
3078
|
+
s = "Frobenius endomorphism x |--> x^(%s^%s)" % (self._p, self._power)
|
|
3079
|
+
s += " of %s" % self.domain()
|
|
3080
|
+
return s
|
|
3081
|
+
|
|
3082
|
+
def _repr_short(self):
|
|
3083
|
+
"""
|
|
3084
|
+
Return a short string representation of this endomorphism.
|
|
3085
|
+
|
|
3086
|
+
EXAMPLES::
|
|
3087
|
+
|
|
3088
|
+
sage: # needs sage.rings.finite_rings
|
|
3089
|
+
sage: K.<u> = PowerSeriesRing(GF(5))
|
|
3090
|
+
sage: Frob = K.frobenius_endomorphism()
|
|
3091
|
+
sage: Frob._repr_short()
|
|
3092
|
+
'Frob'
|
|
3093
|
+
sage: (Frob^2)._repr_short()
|
|
3094
|
+
'Frob^2'
|
|
3095
|
+
"""
|
|
3096
|
+
if self._power == 0:
|
|
3097
|
+
s = "Identity"
|
|
3098
|
+
elif self._power == 1:
|
|
3099
|
+
s = "Frob"
|
|
3100
|
+
else:
|
|
3101
|
+
s = "Frob^%s" % self._power
|
|
3102
|
+
return s
|
|
3103
|
+
|
|
3104
|
+
def _latex_(self):
|
|
3105
|
+
r"""
|
|
3106
|
+
Return a latex representation of this endomorphism.
|
|
3107
|
+
|
|
3108
|
+
EXAMPLES::
|
|
3109
|
+
|
|
3110
|
+
sage: K.<u> = PowerSeriesRing(GF(5))
|
|
3111
|
+
sage: Frob = K.frobenius_endomorphism(2)
|
|
3112
|
+
sage: Frob._latex_()
|
|
3113
|
+
'\\verb"Frob"^{2}'
|
|
3114
|
+
"""
|
|
3115
|
+
if self._power == 0:
|
|
3116
|
+
s = '\\verb"id"'
|
|
3117
|
+
elif self._power == 1:
|
|
3118
|
+
s = '\\verb"Frob"'
|
|
3119
|
+
else:
|
|
3120
|
+
s = '\\verb"Frob"^{%s}' % self._power
|
|
3121
|
+
return s
|
|
3122
|
+
|
|
3123
|
+
cpdef Element _call_ (self, x):
|
|
3124
|
+
"""
|
|
3125
|
+
TESTS::
|
|
3126
|
+
|
|
3127
|
+
sage: # needs sage.rings.finite_rings
|
|
3128
|
+
sage: K.<u> = PowerSeriesRing(GF(5))
|
|
3129
|
+
sage: Frob = K.frobenius_endomorphism()
|
|
3130
|
+
sage: Frob(u)
|
|
3131
|
+
u^5
|
|
3132
|
+
sage: (Frob^2)(1 + u)
|
|
3133
|
+
1 + u^25
|
|
3134
|
+
"""
|
|
3135
|
+
return x ** self._q
|
|
3136
|
+
|
|
3137
|
+
def power(self):
|
|
3138
|
+
"""
|
|
3139
|
+
Return an integer `n` such that this endomorphism
|
|
3140
|
+
is the `n`-th power of the absolute (arithmetic)
|
|
3141
|
+
Frobenius.
|
|
3142
|
+
|
|
3143
|
+
EXAMPLES::
|
|
3144
|
+
|
|
3145
|
+
sage: # needs sage.rings.finite_rings
|
|
3146
|
+
sage: K.<u> = PowerSeriesRing(GF(5))
|
|
3147
|
+
sage: Frob = K.frobenius_endomorphism()
|
|
3148
|
+
sage: Frob.power()
|
|
3149
|
+
1
|
|
3150
|
+
sage: (Frob^9).power()
|
|
3151
|
+
9
|
|
3152
|
+
"""
|
|
3153
|
+
return self._power
|
|
3154
|
+
|
|
3155
|
+
def __pow__(self, n, ignored):
|
|
3156
|
+
"""
|
|
3157
|
+
Return the `n`-th iterate of this endomorphism.
|
|
3158
|
+
|
|
3159
|
+
EXAMPLES::
|
|
3160
|
+
|
|
3161
|
+
sage: K.<u> = PowerSeriesRing(GF(5))
|
|
3162
|
+
sage: Frob = K.frobenius_endomorphism(); Frob
|
|
3163
|
+
Frobenius endomorphism x |--> x^5 of Power Series Ring in u
|
|
3164
|
+
over Finite Field of size 5
|
|
3165
|
+
sage: Frob^2
|
|
3166
|
+
Frobenius endomorphism x |--> x^(5^2) of Power Series Ring in u
|
|
3167
|
+
over Finite Field of size 5
|
|
3168
|
+
"""
|
|
3169
|
+
return self.__class__(self.domain(), self.power()*n)
|
|
3170
|
+
|
|
3171
|
+
def _composition(self, right):
|
|
3172
|
+
"""
|
|
3173
|
+
Return ``self`` o ``right``.
|
|
3174
|
+
|
|
3175
|
+
EXAMPLES::
|
|
3176
|
+
|
|
3177
|
+
sage: # needs sage.rings.finite_rings
|
|
3178
|
+
sage: K.<u> = PowerSeriesRing(GF(5))
|
|
3179
|
+
sage: f = K.frobenius_endomorphism(); f
|
|
3180
|
+
Frobenius endomorphism x |--> x^5 of Power Series Ring in u
|
|
3181
|
+
over Finite Field of size 5
|
|
3182
|
+
sage: g = K.frobenius_endomorphism(2); g
|
|
3183
|
+
Frobenius endomorphism x |--> x^(5^2) of Power Series Ring in u
|
|
3184
|
+
over Finite Field of size 5
|
|
3185
|
+
sage: f * g
|
|
3186
|
+
Frobenius endomorphism x |--> x^(5^3) of Power Series Ring in u
|
|
3187
|
+
over Finite Field of size 5
|
|
3188
|
+
"""
|
|
3189
|
+
if isinstance(right, FrobeniusEndomorphism_generic):
|
|
3190
|
+
return self.__class__(self.domain(), self._power + right.power())
|
|
3191
|
+
else:
|
|
3192
|
+
return RingHomomorphism._composition(self, right)
|
|
3193
|
+
|
|
3194
|
+
def __hash__(self):
|
|
3195
|
+
"""
|
|
3196
|
+
Return a hash of this morphism.
|
|
3197
|
+
|
|
3198
|
+
It is the hash of the triple (domain, codomain, definition)
|
|
3199
|
+
where ``definition`` is:
|
|
3200
|
+
|
|
3201
|
+
- a tuple consisting of the images of the generators
|
|
3202
|
+
of the domain if domain has generators
|
|
3203
|
+
|
|
3204
|
+
- the string representation of this morphism otherwise
|
|
3205
|
+
|
|
3206
|
+
AUTHOR:
|
|
3207
|
+
|
|
3208
|
+
- Xavier Caruso (2012-07-09)
|
|
3209
|
+
"""
|
|
3210
|
+
domain = self.domain()
|
|
3211
|
+
codomain = self.codomain()
|
|
3212
|
+
return hash((domain, codomain, ('Frob', self._power)))
|
|
3213
|
+
|
|
3214
|
+
|
|
3215
|
+
def _tensor_product_ring(B, A):
|
|
3216
|
+
"""
|
|
3217
|
+
Construct a quotient ring representing the tensor product of two rings
|
|
3218
|
+
over a common base ring.
|
|
3219
|
+
|
|
3220
|
+
Allowed arguments are polynomial rings, quotient rings, number fields and
|
|
3221
|
+
finite fields.
|
|
3222
|
+
|
|
3223
|
+
EXAMPLES::
|
|
3224
|
+
|
|
3225
|
+
sage: # needs sage.libs.singular
|
|
3226
|
+
sage: from sage.rings.morphism import _tensor_product_ring
|
|
3227
|
+
sage: R.<x,y> = QQ[]
|
|
3228
|
+
sage: S.<u,v> = R.quotient(x^2 + y^2)
|
|
3229
|
+
sage: Q = _tensor_product_ring(S, R); Q
|
|
3230
|
+
Quotient of Multivariate Polynomial Ring in u, v, x, y over
|
|
3231
|
+
Rational Field by the ideal (u^2 + v^2)
|
|
3232
|
+
sage: Q.term_order()
|
|
3233
|
+
Block term order with blocks:
|
|
3234
|
+
(Degree reverse lexicographic term order of length 2,
|
|
3235
|
+
Degree reverse lexicographic term order of length 2)
|
|
3236
|
+
sage: _tensor_product_ring(R, R)
|
|
3237
|
+
Multivariate Polynomial Ring in y0, y1, x0, x1 over Rational Field
|
|
3238
|
+
|
|
3239
|
+
TESTS:
|
|
3240
|
+
|
|
3241
|
+
Local orderings are not supported::
|
|
3242
|
+
|
|
3243
|
+
sage: R = PolynomialRing(QQ, 'x,y', order='negdeglex')
|
|
3244
|
+
sage: _tensor_product_ring(R, R) # needs sage.libs.singular
|
|
3245
|
+
Traceback (most recent call last):
|
|
3246
|
+
...
|
|
3247
|
+
ValueError: term ordering must be global
|
|
3248
|
+
"""
|
|
3249
|
+
from sage.rings.finite_rings.finite_field_base import FiniteField
|
|
3250
|
+
from sage.rings.number_field.number_field_base import NumberField
|
|
3251
|
+
from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base
|
|
3252
|
+
from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_generic
|
|
3253
|
+
from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic
|
|
3254
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
3255
|
+
from sage.rings.polynomial.term_order import TermOrder
|
|
3256
|
+
from sage.rings.quotient_ring import QuotientRing_nc
|
|
3257
|
+
|
|
3258
|
+
if set(B.variable_names()).isdisjoint(A.variable_names()):
|
|
3259
|
+
names = B.variable_names() + A.variable_names()
|
|
3260
|
+
else:
|
|
3261
|
+
names = (['y%d' % d for d in range(B.ngens())] +
|
|
3262
|
+
['x%d' % d for d in range(A.ngens())])
|
|
3263
|
+
|
|
3264
|
+
def term_order(A):
|
|
3265
|
+
# univariate rings do not have a term order
|
|
3266
|
+
if (isinstance(A, (PolynomialRing_generic, PolynomialQuotientRing_generic))
|
|
3267
|
+
or (isinstance(A, (NumberField, FiniteField))
|
|
3268
|
+
and not A.is_prime_field())):
|
|
3269
|
+
return TermOrder('lex', 1)
|
|
3270
|
+
try:
|
|
3271
|
+
t = A.term_order()
|
|
3272
|
+
except AttributeError:
|
|
3273
|
+
raise NotImplementedError("inverse not implemented for "
|
|
3274
|
+
"morphisms of %s" % A)
|
|
3275
|
+
if not t.is_global():
|
|
3276
|
+
raise ValueError("term ordering must be global")
|
|
3277
|
+
return t
|
|
3278
|
+
R = PolynomialRing(A.base_ring(), names=names,
|
|
3279
|
+
order=term_order(B) + term_order(A))
|
|
3280
|
+
|
|
3281
|
+
def relations(A, R_gens_A):
|
|
3282
|
+
if isinstance(A, (MPolynomialRing_base, PolynomialRing_generic)):
|
|
3283
|
+
return []
|
|
3284
|
+
elif isinstance(A, PolynomialQuotientRing_generic):
|
|
3285
|
+
to_R = A.ambient().hom(R_gens_A, R, check=False)
|
|
3286
|
+
return [to_R(A.modulus())]
|
|
3287
|
+
elif isinstance(A, QuotientRing_nc):
|
|
3288
|
+
to_R = A.ambient().hom(R_gens_A, R, check=False)
|
|
3289
|
+
return list(to_R(A.defining_ideal()).gens())
|
|
3290
|
+
elif (isinstance(A, (NumberField, FiniteField))
|
|
3291
|
+
and not A.is_prime_field()):
|
|
3292
|
+
to_R = A.polynomial_ring().hom(R_gens_A, R, check=False)
|
|
3293
|
+
return [to_R(A.polynomial())]
|
|
3294
|
+
else:
|
|
3295
|
+
raise NotImplementedError("inverse not implemented for "
|
|
3296
|
+
"morphisms of %s" % A)
|
|
3297
|
+
rels_A = relations(A, R.gens()[B.ngens():])
|
|
3298
|
+
rels_B = relations(B, R.gens()[:B.ngens()])
|
|
3299
|
+
return R.quotient(rels_A + rels_B, names=R.variable_names())
|