passagemath-objects 10.6.47__cp311-cp311-macosx_13_0_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_objects/.dylibs/libgmp.10.dylib +0 -0
- passagemath_objects/__init__.py +3 -0
- passagemath_objects-10.6.47.dist-info/METADATA +115 -0
- passagemath_objects-10.6.47.dist-info/RECORD +280 -0
- passagemath_objects-10.6.47.dist-info/WHEEL +6 -0
- passagemath_objects-10.6.47.dist-info/top_level.txt +3 -0
- sage/all__sagemath_objects.py +37 -0
- sage/arith/all__sagemath_objects.py +5 -0
- sage/arith/long.pxd +411 -0
- sage/arith/numerical_approx.cpython-311-darwin.so +0 -0
- sage/arith/numerical_approx.pxd +35 -0
- sage/arith/numerical_approx.pyx +75 -0
- sage/arith/power.cpython-311-darwin.so +0 -0
- sage/arith/power.pxd +31 -0
- sage/arith/power.pyx +127 -0
- sage/categories/action.cpython-311-darwin.so +0 -0
- sage/categories/action.pxd +29 -0
- sage/categories/action.pyx +641 -0
- sage/categories/algebra_functor.py +745 -0
- sage/categories/all__sagemath_objects.py +33 -0
- sage/categories/basic.py +62 -0
- sage/categories/cartesian_product.py +295 -0
- sage/categories/category.py +3401 -0
- sage/categories/category_cy_helper.cpython-311-darwin.so +0 -0
- sage/categories/category_cy_helper.pxd +8 -0
- sage/categories/category_cy_helper.pyx +322 -0
- sage/categories/category_singleton.cpython-311-darwin.so +0 -0
- sage/categories/category_singleton.pxd +3 -0
- sage/categories/category_singleton.pyx +342 -0
- sage/categories/category_types.py +637 -0
- sage/categories/category_with_axiom.py +2876 -0
- sage/categories/covariant_functorial_construction.py +703 -0
- sage/categories/facade_sets.py +228 -0
- sage/categories/functor.cpython-311-darwin.so +0 -0
- sage/categories/functor.pxd +7 -0
- sage/categories/functor.pyx +691 -0
- sage/categories/homset.py +1338 -0
- sage/categories/homsets.py +364 -0
- sage/categories/isomorphic_objects.py +73 -0
- sage/categories/map.cpython-311-darwin.so +0 -0
- sage/categories/map.pxd +34 -0
- sage/categories/map.pyx +2106 -0
- sage/categories/morphism.cpython-311-darwin.so +0 -0
- sage/categories/morphism.pxd +14 -0
- sage/categories/morphism.pyx +895 -0
- sage/categories/objects.py +167 -0
- sage/categories/primer.py +1696 -0
- sage/categories/pushout.py +4834 -0
- sage/categories/quotients.py +64 -0
- sage/categories/realizations.py +200 -0
- sage/categories/sets_cat.py +3290 -0
- sage/categories/sets_with_partial_maps.py +52 -0
- sage/categories/subobjects.py +64 -0
- sage/categories/subquotients.py +21 -0
- sage/categories/with_realizations.py +311 -0
- sage/cpython/__init__.py +19 -0
- sage/cpython/_py2_random.py +619 -0
- sage/cpython/all.py +3 -0
- sage/cpython/atexit.cpython-311-darwin.so +0 -0
- sage/cpython/atexit.pyx +269 -0
- sage/cpython/builtin_types.cpython-311-darwin.so +0 -0
- sage/cpython/builtin_types.pyx +7 -0
- sage/cpython/cython_metaclass.cpython-311-darwin.so +0 -0
- sage/cpython/cython_metaclass.h +117 -0
- sage/cpython/cython_metaclass.pxd +3 -0
- sage/cpython/cython_metaclass.pyx +130 -0
- sage/cpython/debug.cpython-311-darwin.so +0 -0
- sage/cpython/debug.pyx +302 -0
- sage/cpython/dict_del_by_value.cpython-311-darwin.so +0 -0
- sage/cpython/dict_del_by_value.pxd +9 -0
- sage/cpython/dict_del_by_value.pyx +191 -0
- sage/cpython/dict_internal.h +245 -0
- sage/cpython/getattr.cpython-311-darwin.so +0 -0
- sage/cpython/getattr.pxd +9 -0
- sage/cpython/getattr.pyx +439 -0
- sage/cpython/pycore_long.h +97 -0
- sage/cpython/pycore_long.pxd +10 -0
- sage/cpython/python_debug.h +44 -0
- sage/cpython/python_debug.pxd +47 -0
- sage/cpython/pyx_visit.h +13 -0
- sage/cpython/string.cpython-311-darwin.so +0 -0
- sage/cpython/string.pxd +76 -0
- sage/cpython/string.pyx +34 -0
- sage/cpython/string_impl.h +60 -0
- sage/cpython/type.cpython-311-darwin.so +0 -0
- sage/cpython/type.pxd +2 -0
- sage/cpython/type.pyx +40 -0
- sage/cpython/wrapperdescr.pxd +67 -0
- sage/ext/all__sagemath_objects.py +3 -0
- sage/ext/ccobject.h +64 -0
- sage/ext/cplusplus.pxd +17 -0
- sage/ext/mod_int.h +30 -0
- sage/ext/mod_int.pxd +24 -0
- sage/ext/stdsage.pxd +39 -0
- sage/groups/all__sagemath_objects.py +1 -0
- sage/groups/group.cpython-311-darwin.so +0 -0
- sage/groups/group.pxd +14 -0
- sage/groups/group.pyx +322 -0
- sage/groups/old.cpython-311-darwin.so +0 -0
- sage/groups/old.pxd +14 -0
- sage/groups/old.pyx +219 -0
- sage/libs/all__sagemath_objects.py +3 -0
- sage/libs/gmp/__init__.py +1 -0
- sage/libs/gmp/all.pxd +6 -0
- sage/libs/gmp/binop.pxd +23 -0
- sage/libs/gmp/misc.pxd +8 -0
- sage/libs/gmp/mpf.pxd +88 -0
- sage/libs/gmp/mpn.pxd +57 -0
- sage/libs/gmp/mpq.pxd +57 -0
- sage/libs/gmp/mpz.pxd +202 -0
- sage/libs/gmp/pylong.cpython-311-darwin.so +0 -0
- sage/libs/gmp/pylong.pxd +12 -0
- sage/libs/gmp/pylong.pyx +150 -0
- sage/libs/gmp/random.pxd +25 -0
- sage/libs/gmp/randomize.pxd +59 -0
- sage/libs/gmp/types.pxd +53 -0
- sage/libs/gmpxx.pxd +19 -0
- sage/misc/abstract_method.py +276 -0
- sage/misc/all__sagemath_objects.py +43 -0
- sage/misc/bindable_class.py +253 -0
- sage/misc/c3_controlled.cpython-311-darwin.so +0 -0
- sage/misc/c3_controlled.pxd +2 -0
- sage/misc/c3_controlled.pyx +1402 -0
- sage/misc/cachefunc.cpython-311-darwin.so +0 -0
- sage/misc/cachefunc.pxd +43 -0
- sage/misc/cachefunc.pyx +3781 -0
- sage/misc/call.py +188 -0
- sage/misc/classcall_metaclass.cpython-311-darwin.so +0 -0
- sage/misc/classcall_metaclass.pxd +14 -0
- sage/misc/classcall_metaclass.pyx +599 -0
- sage/misc/constant_function.cpython-311-darwin.so +0 -0
- sage/misc/constant_function.pyx +130 -0
- sage/misc/decorators.py +747 -0
- sage/misc/fast_methods.cpython-311-darwin.so +0 -0
- sage/misc/fast_methods.pxd +20 -0
- sage/misc/fast_methods.pyx +351 -0
- sage/misc/flatten.py +90 -0
- sage/misc/fpickle.cpython-311-darwin.so +0 -0
- sage/misc/fpickle.pyx +177 -0
- sage/misc/function_mangling.cpython-311-darwin.so +0 -0
- sage/misc/function_mangling.pxd +11 -0
- sage/misc/function_mangling.pyx +308 -0
- sage/misc/inherit_comparison.cpython-311-darwin.so +0 -0
- sage/misc/inherit_comparison.pxd +5 -0
- sage/misc/inherit_comparison.pyx +105 -0
- sage/misc/instancedoc.cpython-311-darwin.so +0 -0
- sage/misc/instancedoc.pyx +331 -0
- sage/misc/lazy_attribute.cpython-311-darwin.so +0 -0
- sage/misc/lazy_attribute.pyx +607 -0
- sage/misc/lazy_format.py +135 -0
- sage/misc/lazy_import.cpython-311-darwin.so +0 -0
- sage/misc/lazy_import.pyx +1299 -0
- sage/misc/lazy_import_cache.py +36 -0
- sage/misc/lazy_list.cpython-311-darwin.so +0 -0
- sage/misc/lazy_list.pxd +19 -0
- sage/misc/lazy_list.pyx +1187 -0
- sage/misc/lazy_string.cpython-311-darwin.so +0 -0
- sage/misc/lazy_string.pxd +7 -0
- sage/misc/lazy_string.pyx +546 -0
- sage/misc/misc.py +1066 -0
- sage/misc/misc_c.cpython-311-darwin.so +0 -0
- sage/misc/misc_c.pxd +3 -0
- sage/misc/misc_c.pyx +766 -0
- sage/misc/namespace_package.py +37 -0
- sage/misc/nested_class.cpython-311-darwin.so +0 -0
- sage/misc/nested_class.pxd +3 -0
- sage/misc/nested_class.pyx +394 -0
- sage/misc/persist.cpython-311-darwin.so +0 -0
- sage/misc/persist.pyx +1251 -0
- sage/misc/prandom.py +418 -0
- sage/misc/randstate.cpython-311-darwin.so +0 -0
- sage/misc/randstate.pxd +30 -0
- sage/misc/randstate.pyx +1059 -0
- sage/misc/repr.py +203 -0
- sage/misc/reset.cpython-311-darwin.so +0 -0
- sage/misc/reset.pyx +196 -0
- sage/misc/sage_ostools.cpython-311-darwin.so +0 -0
- sage/misc/sage_ostools.pyx +323 -0
- sage/misc/sage_timeit.py +275 -0
- sage/misc/sage_timeit_class.cpython-311-darwin.so +0 -0
- sage/misc/sage_timeit_class.pyx +120 -0
- sage/misc/sage_unittest.py +637 -0
- sage/misc/sageinspect.py +2768 -0
- sage/misc/session.cpython-311-darwin.so +0 -0
- sage/misc/session.pyx +392 -0
- sage/misc/superseded.py +557 -0
- sage/misc/test_nested_class.py +228 -0
- sage/misc/timing.py +264 -0
- sage/misc/unknown.py +222 -0
- sage/misc/verbose.py +253 -0
- sage/misc/weak_dict.cpython-311-darwin.so +0 -0
- sage/misc/weak_dict.pxd +15 -0
- sage/misc/weak_dict.pyx +1231 -0
- sage/modules/all__sagemath_objects.py +1 -0
- sage/modules/module.cpython-311-darwin.so +0 -0
- sage/modules/module.pxd +5 -0
- sage/modules/module.pyx +329 -0
- sage/rings/all__sagemath_objects.py +3 -0
- sage/rings/integer_fake.h +22 -0
- sage/rings/integer_fake.pxd +55 -0
- sage/sets/all__sagemath_objects.py +3 -0
- sage/sets/pythonclass.cpython-311-darwin.so +0 -0
- sage/sets/pythonclass.pxd +9 -0
- sage/sets/pythonclass.pyx +247 -0
- sage/structure/__init__.py +4 -0
- sage/structure/all.py +30 -0
- sage/structure/category_object.cpython-311-darwin.so +0 -0
- sage/structure/category_object.pxd +28 -0
- sage/structure/category_object.pyx +1087 -0
- sage/structure/coerce.cpython-311-darwin.so +0 -0
- sage/structure/coerce.pxd +44 -0
- sage/structure/coerce.pyx +2107 -0
- sage/structure/coerce_actions.cpython-311-darwin.so +0 -0
- sage/structure/coerce_actions.pxd +27 -0
- sage/structure/coerce_actions.pyx +988 -0
- sage/structure/coerce_dict.cpython-311-darwin.so +0 -0
- sage/structure/coerce_dict.pxd +51 -0
- sage/structure/coerce_dict.pyx +1557 -0
- sage/structure/coerce_exceptions.py +23 -0
- sage/structure/coerce_maps.cpython-311-darwin.so +0 -0
- sage/structure/coerce_maps.pxd +28 -0
- sage/structure/coerce_maps.pyx +718 -0
- sage/structure/debug_options.cpython-311-darwin.so +0 -0
- sage/structure/debug_options.pxd +6 -0
- sage/structure/debug_options.pyx +54 -0
- sage/structure/dynamic_class.py +541 -0
- sage/structure/element.cpython-311-darwin.so +0 -0
- sage/structure/element.pxd +272 -0
- sage/structure/element.pyx +4772 -0
- sage/structure/element_wrapper.cpython-311-darwin.so +0 -0
- sage/structure/element_wrapper.pxd +12 -0
- sage/structure/element_wrapper.pyx +582 -0
- sage/structure/factorization.py +1422 -0
- sage/structure/factorization_integer.py +105 -0
- sage/structure/factory.cpython-311-darwin.so +0 -0
- sage/structure/factory.pyx +786 -0
- sage/structure/formal_sum.py +489 -0
- sage/structure/gens_py.py +73 -0
- sage/structure/global_options.py +1743 -0
- sage/structure/indexed_generators.py +863 -0
- sage/structure/list_clone.cpython-311-darwin.so +0 -0
- sage/structure/list_clone.pxd +65 -0
- sage/structure/list_clone.pyx +1867 -0
- sage/structure/list_clone_demo.cpython-311-darwin.so +0 -0
- sage/structure/list_clone_demo.pyx +248 -0
- sage/structure/list_clone_timings.py +179 -0
- sage/structure/list_clone_timings_cy.cpython-311-darwin.so +0 -0
- sage/structure/list_clone_timings_cy.pyx +86 -0
- sage/structure/mutability.cpython-311-darwin.so +0 -0
- sage/structure/mutability.pxd +21 -0
- sage/structure/mutability.pyx +348 -0
- sage/structure/nonexact.py +69 -0
- sage/structure/parent.cpython-311-darwin.so +0 -0
- sage/structure/parent.pxd +112 -0
- sage/structure/parent.pyx +3093 -0
- sage/structure/parent_base.cpython-311-darwin.so +0 -0
- sage/structure/parent_base.pxd +13 -0
- sage/structure/parent_base.pyx +44 -0
- sage/structure/parent_gens.cpython-311-darwin.so +0 -0
- sage/structure/parent_gens.pxd +22 -0
- sage/structure/parent_gens.pyx +377 -0
- sage/structure/parent_old.cpython-311-darwin.so +0 -0
- sage/structure/parent_old.pxd +25 -0
- sage/structure/parent_old.pyx +294 -0
- sage/structure/proof/__init__.py +1 -0
- sage/structure/proof/all.py +243 -0
- sage/structure/proof/proof.py +300 -0
- sage/structure/richcmp.cpython-311-darwin.so +0 -0
- sage/structure/richcmp.pxd +213 -0
- sage/structure/richcmp.pyx +495 -0
- sage/structure/sage_object.cpython-311-darwin.so +0 -0
- sage/structure/sage_object.pxd +3 -0
- sage/structure/sage_object.pyx +988 -0
- sage/structure/sage_object_test.py +19 -0
- sage/structure/sequence.py +937 -0
- sage/structure/set_factories.py +1178 -0
- sage/structure/set_factories_example.py +527 -0
- sage/structure/support_view.py +179 -0
- sage/structure/test_factory.py +56 -0
- sage/structure/unique_representation.py +1359 -0
|
@@ -0,0 +1,1338 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-objects
|
|
2
|
+
r"""
|
|
3
|
+
Homsets
|
|
4
|
+
|
|
5
|
+
The class :class:`Hom` is the base class used to represent sets of morphisms
|
|
6
|
+
between objects of a given category.
|
|
7
|
+
:class:`Hom` objects are usually "weakly" cached upon creation so that they
|
|
8
|
+
don't have to be generated over and over but can be garbage collected together
|
|
9
|
+
with the corresponding objects when these are not strongly ref'ed anymore.
|
|
10
|
+
|
|
11
|
+
EXAMPLES:
|
|
12
|
+
|
|
13
|
+
In the following, the :class:`Hom` object is indeed cached::
|
|
14
|
+
|
|
15
|
+
sage: K = GF(17)
|
|
16
|
+
sage: H = Hom(ZZ, K)
|
|
17
|
+
sage: H
|
|
18
|
+
Set of Homomorphisms from Integer Ring to Finite Field of size 17
|
|
19
|
+
sage: H is Hom(ZZ, K)
|
|
20
|
+
True
|
|
21
|
+
|
|
22
|
+
Nonetheless, garbage collection occurs when the original references are
|
|
23
|
+
overwritten::
|
|
24
|
+
|
|
25
|
+
sage: # needs sage.libs.pari
|
|
26
|
+
sage: for p in prime_range(200):
|
|
27
|
+
....: K = GF(p)
|
|
28
|
+
....: H = Hom(ZZ, K)
|
|
29
|
+
sage: import gc
|
|
30
|
+
sage: _ = gc.collect()
|
|
31
|
+
sage: from sage.rings.finite_rings.finite_field_prime_modn import FiniteField_prime_modn as FF
|
|
32
|
+
sage: L = [x for x in gc.get_objects() if isinstance(x, FF)]
|
|
33
|
+
sage: len(L)
|
|
34
|
+
1
|
|
35
|
+
sage: L
|
|
36
|
+
[Finite Field of size 199]
|
|
37
|
+
|
|
38
|
+
AUTHORS:
|
|
39
|
+
|
|
40
|
+
- David Kohel and William Stein
|
|
41
|
+
|
|
42
|
+
- David Joyner (2005-12-17): added examples
|
|
43
|
+
|
|
44
|
+
- William Stein (2006-01-14): Changed from Homspace to Homset.
|
|
45
|
+
|
|
46
|
+
- Nicolas M. Thiery (2008-12-): Updated for the new category framework
|
|
47
|
+
|
|
48
|
+
- Simon King (2011-12): Use a weak cache for homsets
|
|
49
|
+
|
|
50
|
+
- Simon King (2013-02): added examples
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
# ****************************************************************************
|
|
54
|
+
# Copyright (C) 2005 David Kohel <kohel@maths.usyd.edu>,
|
|
55
|
+
# William Stein <wstein@gmail.com>
|
|
56
|
+
#
|
|
57
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
58
|
+
#
|
|
59
|
+
# This code is distributed in the hope that it will be useful,
|
|
60
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
61
|
+
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
62
|
+
#
|
|
63
|
+
# See the GNU General Public License for more details; the full text
|
|
64
|
+
# is available at:
|
|
65
|
+
#
|
|
66
|
+
# https://www.gnu.org/licenses/
|
|
67
|
+
# ****************************************************************************
|
|
68
|
+
|
|
69
|
+
from sage.categories import morphism
|
|
70
|
+
from sage.categories.category import Category, JoinCategory
|
|
71
|
+
from sage.misc.fast_methods import WithEqualityById
|
|
72
|
+
from sage.misc.lazy_attribute import lazy_attribute
|
|
73
|
+
|
|
74
|
+
###################################
|
|
75
|
+
# Use the weak "triple" dictionary
|
|
76
|
+
# introduced in github issue #715
|
|
77
|
+
# with weak values, as introduced in
|
|
78
|
+
# github issue #14159
|
|
79
|
+
from sage.structure.coerce_dict import TripleDict
|
|
80
|
+
from sage.structure.dynamic_class import dynamic_class
|
|
81
|
+
from sage.structure.parent import Parent, Set_generic
|
|
82
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
|
83
|
+
|
|
84
|
+
_cache = TripleDict(weak_values=True)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def Hom(X, Y, category=None, check=True):
|
|
88
|
+
"""
|
|
89
|
+
Create the space of homomorphisms from X to Y in the category ``category``.
|
|
90
|
+
|
|
91
|
+
INPUT:
|
|
92
|
+
|
|
93
|
+
- ``X`` -- an object of a category
|
|
94
|
+
|
|
95
|
+
- ``Y`` -- an object of a category
|
|
96
|
+
|
|
97
|
+
- ``category`` -- a category in which the morphisms must be
|
|
98
|
+
(default: the meet of the categories of ``X`` and ``Y``);
|
|
99
|
+
both ``X`` and ``Y`` must belong to that category
|
|
100
|
+
|
|
101
|
+
- ``check`` -- boolean (default: ``True``); whether to check the
|
|
102
|
+
input, and in particular that ``X`` and ``Y`` belong to
|
|
103
|
+
``category``.
|
|
104
|
+
|
|
105
|
+
OUTPUT: a homset in category
|
|
106
|
+
|
|
107
|
+
EXAMPLES::
|
|
108
|
+
|
|
109
|
+
sage: V = VectorSpace(QQ, 3) # needs sage.modules
|
|
110
|
+
sage: Hom(V, V) # needs sage.modules
|
|
111
|
+
Set of Morphisms (Linear Transformations) from
|
|
112
|
+
Vector space of dimension 3 over Rational Field to
|
|
113
|
+
Vector space of dimension 3 over Rational Field
|
|
114
|
+
sage: G = AlternatingGroup(3) # needs sage.groups
|
|
115
|
+
sage: Hom(G, G) # needs sage.groups
|
|
116
|
+
Set of Morphisms
|
|
117
|
+
from Alternating group of order 3!/2 as a permutation group
|
|
118
|
+
to Alternating group of order 3!/2 as a permutation group
|
|
119
|
+
in Category of finite enumerated permutation groups
|
|
120
|
+
sage: Hom(ZZ, QQ, Sets())
|
|
121
|
+
Set of Morphisms from Integer Ring to Rational Field in Category of sets
|
|
122
|
+
|
|
123
|
+
sage: Hom(FreeModule(ZZ, 1), FreeModule(QQ, 1)) # needs sage.modules
|
|
124
|
+
Set of Morphisms
|
|
125
|
+
from Ambient free module of rank 1 over the principal ideal domain Integer Ring
|
|
126
|
+
to Vector space of dimension 1 over Rational Field
|
|
127
|
+
in Category of commutative additive groups
|
|
128
|
+
sage: Hom(FreeModule(QQ, 1), FreeModule(ZZ, 1)) # needs sage.modules
|
|
129
|
+
Set of Morphisms
|
|
130
|
+
from Vector space of dimension 1 over Rational Field
|
|
131
|
+
to Ambient free module of rank 1 over the principal ideal domain Integer Ring
|
|
132
|
+
in Category of commutative additive groups
|
|
133
|
+
|
|
134
|
+
Here, we test against a memory leak that has been fixed at :issue:`11521` by
|
|
135
|
+
using a weak cache::
|
|
136
|
+
|
|
137
|
+
sage: # needs sage.libs.pari
|
|
138
|
+
sage: for p in prime_range(10^3):
|
|
139
|
+
....: K = GF(p)
|
|
140
|
+
....: a = K(0)
|
|
141
|
+
sage: import gc
|
|
142
|
+
sage: gc.collect() # random
|
|
143
|
+
624
|
|
144
|
+
sage: from sage.rings.finite_rings.finite_field_prime_modn import FiniteField_prime_modn as FF
|
|
145
|
+
sage: L = [x for x in gc.get_objects() if isinstance(x, FF)]
|
|
146
|
+
sage: len(L), L[0]
|
|
147
|
+
(1, Finite Field of size 997)
|
|
148
|
+
|
|
149
|
+
To illustrate the choice of the category, we consider the
|
|
150
|
+
following parents as running examples::
|
|
151
|
+
|
|
152
|
+
sage: X = ZZ; X
|
|
153
|
+
Integer Ring
|
|
154
|
+
sage: Y = SymmetricGroup(3); Y # needs sage.groups
|
|
155
|
+
Symmetric group of order 3! as a permutation group
|
|
156
|
+
|
|
157
|
+
By default, the smallest category containing both ``X`` and ``Y``,
|
|
158
|
+
is used::
|
|
159
|
+
|
|
160
|
+
sage: Hom(X, Y) # needs sage.groups
|
|
161
|
+
Set of Morphisms from Integer Ring
|
|
162
|
+
to Symmetric group of order 3! as a permutation group
|
|
163
|
+
in Category of enumerated monoids
|
|
164
|
+
|
|
165
|
+
Otherwise, if ``category`` is specified, then ``category`` is used,
|
|
166
|
+
after checking that ``X`` and ``Y`` are indeed in ``category``::
|
|
167
|
+
|
|
168
|
+
sage: Hom(X, Y, Magmas()) # needs sage.groups
|
|
169
|
+
Set of Morphisms
|
|
170
|
+
from Integer Ring
|
|
171
|
+
to Symmetric group of order 3! as a permutation group
|
|
172
|
+
in Category of magmas
|
|
173
|
+
|
|
174
|
+
sage: Hom(X, Y, Groups()) # needs sage.groups
|
|
175
|
+
Traceback (most recent call last):
|
|
176
|
+
...
|
|
177
|
+
ValueError: Integer Ring is not in Category of groups
|
|
178
|
+
|
|
179
|
+
A parent (or a parent class of a category) may specify how to
|
|
180
|
+
construct certain homsets by implementing a method ``_Hom_(self,
|
|
181
|
+
codomain, category)``. This method should either construct the
|
|
182
|
+
requested homset or raise a :exc:`TypeError`. This hook is currently
|
|
183
|
+
mostly used to create homsets in some specific subclass of
|
|
184
|
+
:class:`Homset` (e.g. :class:`sage.rings.homset.RingHomset`)::
|
|
185
|
+
|
|
186
|
+
sage: Hom(QQ,QQ).__class__
|
|
187
|
+
<class 'sage.rings.homset.RingHomset_generic_with_category'>
|
|
188
|
+
|
|
189
|
+
Do not call this hook directly to create homsets, as it does not
|
|
190
|
+
handle unique representation::
|
|
191
|
+
|
|
192
|
+
sage: Hom(QQ,QQ) == QQ._Hom_(QQ, category=QQ.category())
|
|
193
|
+
True
|
|
194
|
+
sage: Hom(QQ,QQ) is QQ._Hom_(QQ, category=QQ.category())
|
|
195
|
+
False
|
|
196
|
+
|
|
197
|
+
TESTS:
|
|
198
|
+
|
|
199
|
+
Homset are unique parents::
|
|
200
|
+
|
|
201
|
+
sage: k = GF(5)
|
|
202
|
+
sage: H1 = Hom(k, k)
|
|
203
|
+
sage: H2 = Hom(k, k)
|
|
204
|
+
sage: H1 is H2
|
|
205
|
+
True
|
|
206
|
+
|
|
207
|
+
Moreover, if no category is provided, then the result is identical
|
|
208
|
+
with the result for the meet of the categories of the domain and
|
|
209
|
+
the codomain::
|
|
210
|
+
|
|
211
|
+
sage: Hom(QQ, ZZ) is Hom(QQ,ZZ, Category.meet([QQ.category(), ZZ.category()]))
|
|
212
|
+
True
|
|
213
|
+
|
|
214
|
+
Some doc tests in :mod:`sage.rings` (need to) break the unique
|
|
215
|
+
parent assumption. But if domain or codomain are not unique
|
|
216
|
+
parents, then the homset will not fit. That is to say, the hom set
|
|
217
|
+
found in the cache will have a (co)domain that is equal to, but
|
|
218
|
+
not identical with, the given (co)domain.
|
|
219
|
+
|
|
220
|
+
By :issue:`9138`, we abandon the uniqueness of homsets, if the
|
|
221
|
+
domain or codomain break uniqueness::
|
|
222
|
+
|
|
223
|
+
sage: from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict_domain
|
|
224
|
+
sage: P.<x,y,z>=MPolynomialRing_polydict_domain(QQ, 3, order='degrevlex')
|
|
225
|
+
sage: Q.<x,y,z>=MPolynomialRing_polydict_domain(QQ, 3, order='degrevlex')
|
|
226
|
+
sage: P == Q
|
|
227
|
+
True
|
|
228
|
+
sage: P is Q
|
|
229
|
+
False
|
|
230
|
+
|
|
231
|
+
Hence, ``P`` and ``Q`` are not unique parents. By consequence, the
|
|
232
|
+
following homsets aren't either::
|
|
233
|
+
|
|
234
|
+
sage: H1 = Hom(QQ,P)
|
|
235
|
+
sage: H2 = Hom(QQ,Q)
|
|
236
|
+
sage: H1 == H2
|
|
237
|
+
True
|
|
238
|
+
sage: H1 is H2
|
|
239
|
+
False
|
|
240
|
+
|
|
241
|
+
It is always the most recently constructed homset that remains in
|
|
242
|
+
the cache::
|
|
243
|
+
|
|
244
|
+
sage: H2 is Hom(QQ,Q)
|
|
245
|
+
True
|
|
246
|
+
|
|
247
|
+
Variation on the theme::
|
|
248
|
+
|
|
249
|
+
sage: # needs sage.modules
|
|
250
|
+
sage: U1 = FreeModule(ZZ, 2)
|
|
251
|
+
sage: U2 = FreeModule(ZZ, 2, inner_product_matrix=matrix([[1,0], [0,-1]]))
|
|
252
|
+
sage: U1 == U2, U1 is U2
|
|
253
|
+
(False, False)
|
|
254
|
+
sage: V = ZZ^3
|
|
255
|
+
sage: H1 = Hom(U1, V); H2 = Hom(U2, V)
|
|
256
|
+
sage: H1 == H2, H1 is H2
|
|
257
|
+
(False, False)
|
|
258
|
+
sage: H1 = Hom(V, U1); H2 = Hom(V, U2)
|
|
259
|
+
sage: H1 == H2, H1 is H2
|
|
260
|
+
(False, False)
|
|
261
|
+
|
|
262
|
+
Since :issue:`11900`, the meet of the categories of the given arguments is
|
|
263
|
+
used to determine the default category of the homset. This can also be a
|
|
264
|
+
join category, as in the following example::
|
|
265
|
+
|
|
266
|
+
sage: PA = Parent(category=Algebras(QQ))
|
|
267
|
+
sage: PJ = Parent(category=Rings() & Modules(QQ))
|
|
268
|
+
sage: Hom(PA, PJ)
|
|
269
|
+
Set of Homomorphisms
|
|
270
|
+
from <sage.structure.parent.Parent object at ...>
|
|
271
|
+
to <sage.structure.parent.Parent object at ...>
|
|
272
|
+
sage: Hom(PA, PJ).category()
|
|
273
|
+
Category of homsets of
|
|
274
|
+
unital magmas and right modules over Rational Field
|
|
275
|
+
and left modules over Rational Field
|
|
276
|
+
sage: Hom(PA, PJ, Rngs())
|
|
277
|
+
Set of Morphisms
|
|
278
|
+
from <sage.structure.parent.Parent object at ...>
|
|
279
|
+
to <sage.structure.parent.Parent object at ...> in Category of rngs
|
|
280
|
+
|
|
281
|
+
.. TODO::
|
|
282
|
+
|
|
283
|
+
- Design decision: how much of the homset comes from the
|
|
284
|
+
category of ``X`` and ``Y``, and how much from the specific
|
|
285
|
+
``X`` and ``Y``. In particular, do we need several parent
|
|
286
|
+
classes depending on ``X`` and ``Y``, or does the difference
|
|
287
|
+
only lie in the elements (i.e. the morphism), and of course
|
|
288
|
+
how the parent calls their constructors.
|
|
289
|
+
- Specify the protocol for the ``_Hom_`` hook in case of ambiguity
|
|
290
|
+
(e.g. if both a parent and some category thereof provide one).
|
|
291
|
+
|
|
292
|
+
TESTS:
|
|
293
|
+
|
|
294
|
+
Facade parents over plain Python types are supported::
|
|
295
|
+
|
|
296
|
+
sage: from sage.sets.pythonclass import Set_PythonType
|
|
297
|
+
sage: R = Set_PythonType(int)
|
|
298
|
+
sage: S = Set_PythonType(float)
|
|
299
|
+
sage: Hom(R, S)
|
|
300
|
+
Set of Morphisms from Set of Python objects of class 'int'
|
|
301
|
+
to Set of Python objects of class 'float' in Category of infinite sets
|
|
302
|
+
|
|
303
|
+
Checks that the domain and codomain are in the specified
|
|
304
|
+
category. Case of a non parent::
|
|
305
|
+
|
|
306
|
+
sage: # needs sage.graphs
|
|
307
|
+
sage: S = SimplicialComplex([[1,2], [1,4]]); S.rename('S')
|
|
308
|
+
sage: Hom(S, S, SimplicialComplexes())
|
|
309
|
+
Set of Morphisms from S to S in Category of finite simplicial complexes
|
|
310
|
+
sage: Hom(Set(), S, Sets())
|
|
311
|
+
Set of Morphisms from {} to S in Category of sets
|
|
312
|
+
sage: Hom(S, Set(), Sets())
|
|
313
|
+
Set of Morphisms from S to {} in Category of sets
|
|
314
|
+
sage: H = Hom(S, S, ChainComplexes(QQ))
|
|
315
|
+
Traceback (most recent call last):
|
|
316
|
+
...
|
|
317
|
+
ValueError: S is not in Category of chain complexes over Rational Field
|
|
318
|
+
|
|
319
|
+
Those checks are done with the natural idiom ``X in category``,
|
|
320
|
+
and not ``X.category().is_subcategory(category)`` as it used to be
|
|
321
|
+
before :issue:`16275` (see :issue:`15801` for a real use case)::
|
|
322
|
+
|
|
323
|
+
sage: # needs sage.graphs
|
|
324
|
+
sage: class PermissiveCategory(Category):
|
|
325
|
+
....: def super_categories(self): return [Objects()]
|
|
326
|
+
....: def __contains__(self, X): return True
|
|
327
|
+
sage: C = PermissiveCategory(); C.rename('Permissive category')
|
|
328
|
+
sage: S.category().is_subcategory(C)
|
|
329
|
+
False
|
|
330
|
+
sage: S in C
|
|
331
|
+
True
|
|
332
|
+
sage: Hom(S, S, C)
|
|
333
|
+
Set of Morphisms from S to S in Permissive category
|
|
334
|
+
|
|
335
|
+
With ``check=False``, uninitialized parents, as can appear upon
|
|
336
|
+
unpickling, are supported. Case of a parent::
|
|
337
|
+
|
|
338
|
+
sage: cls = type(Set())
|
|
339
|
+
sage: S = unpickle_newobj(cls, ()) # A non parent
|
|
340
|
+
sage: H = Hom(S, S, SimplicialComplexes(), check=False)
|
|
341
|
+
sage: H = Hom(S, S, Sets(), check=False)
|
|
342
|
+
sage: H = Hom(S, S, ChainComplexes(QQ), check=False)
|
|
343
|
+
|
|
344
|
+
Case of a non parent::
|
|
345
|
+
|
|
346
|
+
sage: # needs sage.graphs
|
|
347
|
+
sage: cls = type(SimplicialComplex([[1,2], [1,4]]))
|
|
348
|
+
sage: S = unpickle_newobj(cls, ())
|
|
349
|
+
sage: H = Hom(S, S, Sets(), check=False)
|
|
350
|
+
sage: H = Hom(S, S, Groups(), check=False)
|
|
351
|
+
sage: H = Hom(S, S, SimplicialComplexes(), check=False)
|
|
352
|
+
|
|
353
|
+
Typical example where unpickling involves calling Hom on an
|
|
354
|
+
uninitialized parent::
|
|
355
|
+
|
|
356
|
+
sage: P.<x,y> = QQ['x,y']
|
|
357
|
+
sage: Q = P.quotient([x^2 - 1, y^2 - 1])
|
|
358
|
+
sage: q = Q.an_element() # needs sage.libs.singular
|
|
359
|
+
sage: explain_pickle(dumps(Q)) # needs sage.libs.singular
|
|
360
|
+
pg_...
|
|
361
|
+
... = pg_dynamic_class('QuotientRing_generic_with_category', (pg_QuotientRing_generic, pg_getattr(..., 'parent_class')), None, None, pg_QuotientRing_generic)
|
|
362
|
+
si... = unpickle_newobj(..., ())
|
|
363
|
+
...
|
|
364
|
+
si... = pg_unpickle_MPolynomialRing_libsingular(..., ('x', 'y'), ...)
|
|
365
|
+
si... = ... pg_Hom(si..., si..., ...) ...
|
|
366
|
+
sage: Q == loads(dumps(Q))
|
|
367
|
+
True
|
|
368
|
+
|
|
369
|
+
Check that the ``_Hom_`` method of the ``category`` input is used::
|
|
370
|
+
|
|
371
|
+
sage: from sage.categories.category_types import Category_over_base_ring
|
|
372
|
+
sage: class ModulesWithHom(Category_over_base_ring):
|
|
373
|
+
....: def super_categories(self):
|
|
374
|
+
....: return [Modules(self.base_ring())]
|
|
375
|
+
....: class ParentMethods:
|
|
376
|
+
....: def _Hom_(self, Y, category=None):
|
|
377
|
+
....: print("Modules")
|
|
378
|
+
....: raise TypeError
|
|
379
|
+
sage: class AlgebrasWithHom(Category_over_base_ring):
|
|
380
|
+
....: def super_categories(self):
|
|
381
|
+
....: return [Algebras(self.base_ring()), ModulesWithHom(self.base_ring())]
|
|
382
|
+
....: class ParentMethods:
|
|
383
|
+
....: def _Hom_(self, Y, category=None):
|
|
384
|
+
....: R = self.base_ring()
|
|
385
|
+
....: if category is not None and category.is_subcategory(Algebras(R)):
|
|
386
|
+
....: print("Algebras")
|
|
387
|
+
....: raise TypeError
|
|
388
|
+
sage: from sage.structure.element import Element
|
|
389
|
+
sage: class Foo(Parent):
|
|
390
|
+
....: def _coerce_map_from_base_ring(self):
|
|
391
|
+
....: return self._generic_coerce_map(self.base_ring())
|
|
392
|
+
....: class Element(Element):
|
|
393
|
+
....: pass
|
|
394
|
+
sage: X = Foo(base=QQ, category=AlgebrasWithHom(QQ))
|
|
395
|
+
sage: H = Hom(X, X, ModulesWithHom(QQ))
|
|
396
|
+
Modules
|
|
397
|
+
"""
|
|
398
|
+
# This should use cache_function instead
|
|
399
|
+
# However some special handling is currently needed for
|
|
400
|
+
# domains/codomains that break the unique parent condition. Also,
|
|
401
|
+
# at some point, it somehow broke the coercion (see e.g. sage -t
|
|
402
|
+
# sage.rings.real_mpfr). To be investigated.
|
|
403
|
+
global _cache
|
|
404
|
+
key = (X,Y,category)
|
|
405
|
+
try:
|
|
406
|
+
H = _cache[key]
|
|
407
|
+
except KeyError:
|
|
408
|
+
H = None
|
|
409
|
+
if H is not None:
|
|
410
|
+
# Return H unless the domain or codomain breaks the unique parent condition
|
|
411
|
+
if H.domain() is X and H.codomain() is Y:
|
|
412
|
+
return H
|
|
413
|
+
|
|
414
|
+
# Determines the category
|
|
415
|
+
if category is None:
|
|
416
|
+
category = X.category()._meet_(Y.category())
|
|
417
|
+
# Recurse to make sure that Hom(X, Y) and Hom(X, Y, category) are identical
|
|
418
|
+
# No need to check the input again
|
|
419
|
+
H = Hom(X, Y, category, check=False)
|
|
420
|
+
else:
|
|
421
|
+
if check:
|
|
422
|
+
if not isinstance(category, Category):
|
|
423
|
+
raise TypeError("Argument category (= {}) must be a category.".format(category))
|
|
424
|
+
for O in [X, Y]:
|
|
425
|
+
try:
|
|
426
|
+
category_mismatch = O not in category
|
|
427
|
+
except Exception:
|
|
428
|
+
# An error should not happen, this here is just to be on
|
|
429
|
+
# the safe side.
|
|
430
|
+
category_mismatch = True
|
|
431
|
+
# A category mismatch does not necessarily mean that an error
|
|
432
|
+
# should be raised. Instead, it could be the case that we are
|
|
433
|
+
# unpickling an old pickle (that doesn't set the "check"
|
|
434
|
+
# argument to False). In this case, it could be that the
|
|
435
|
+
# (co)domain is not properly initialised, which we are
|
|
436
|
+
# checking now. See trac #16275 and #14793.
|
|
437
|
+
if category_mismatch and O._is_category_initialized():
|
|
438
|
+
# At this point, we can be rather sure that O is properly
|
|
439
|
+
# initialised, and thus its string representation is
|
|
440
|
+
# available for the following error message. It simply
|
|
441
|
+
# belongs to the wrong category.
|
|
442
|
+
raise ValueError("{} is not in {}".format(O, category))
|
|
443
|
+
|
|
444
|
+
# Construct H
|
|
445
|
+
try: # _Hom_ hook from the parent
|
|
446
|
+
H = X._Hom_(Y, category)
|
|
447
|
+
except (AttributeError, TypeError):
|
|
448
|
+
# Workaround in case the above fails, but the category
|
|
449
|
+
# also provides a _Hom_ hook.
|
|
450
|
+
# FIXME:
|
|
451
|
+
# - If X._Hom_ actually comes from category and fails, it
|
|
452
|
+
# will be called twice.
|
|
453
|
+
# - This is bound to fail if X is an extension type and
|
|
454
|
+
# does not actually inherit from category.parent_class
|
|
455
|
+
# For join categories, we check all of the direct super
|
|
456
|
+
# categories as the parent_class of the join category is
|
|
457
|
+
# not (necessarily) inherited and join categories do not
|
|
458
|
+
# implement a _Hom_ (see trac #23418).
|
|
459
|
+
if not isinstance(category, JoinCategory):
|
|
460
|
+
cats = [category]
|
|
461
|
+
else:
|
|
462
|
+
cats = category.super_categories()
|
|
463
|
+
H = None
|
|
464
|
+
for C in cats:
|
|
465
|
+
try:
|
|
466
|
+
H = C.parent_class._Hom_(X, Y, category=category)
|
|
467
|
+
break
|
|
468
|
+
except (AttributeError, TypeError):
|
|
469
|
+
pass
|
|
470
|
+
if H is None:
|
|
471
|
+
# By default, construct a plain homset.
|
|
472
|
+
H = Homset(X, Y, category=category, check=check)
|
|
473
|
+
_cache[key] = H
|
|
474
|
+
if isinstance(X, UniqueRepresentation) and isinstance(Y, UniqueRepresentation):
|
|
475
|
+
if not isinstance(H, WithEqualityById):
|
|
476
|
+
try:
|
|
477
|
+
H.__class__ = dynamic_class(H.__class__.__name__+"_with_equality_by_id", (WithEqualityById, H.__class__), doccls=H.__class__)
|
|
478
|
+
except Exception:
|
|
479
|
+
pass
|
|
480
|
+
return H
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
def hom(X, Y, f):
|
|
484
|
+
"""
|
|
485
|
+
Return ``Hom(X,Y)(f)``, where ``f`` is data that defines an element of
|
|
486
|
+
``Hom(X,Y)``.
|
|
487
|
+
|
|
488
|
+
EXAMPLES::
|
|
489
|
+
|
|
490
|
+
sage: R.<x> = QQ[]
|
|
491
|
+
sage: phi = hom(R, QQ, [2])
|
|
492
|
+
sage: phi(x^2 + 3)
|
|
493
|
+
7
|
|
494
|
+
"""
|
|
495
|
+
return Hom(X,Y)(f)
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
def End(X, category=None):
|
|
499
|
+
r"""
|
|
500
|
+
Create the set of endomorphisms of ``X`` in the category category.
|
|
501
|
+
|
|
502
|
+
INPUT:
|
|
503
|
+
|
|
504
|
+
- ``X`` -- anything
|
|
505
|
+
|
|
506
|
+
- ``category`` -- (optional) category in which to coerce ``X``
|
|
507
|
+
|
|
508
|
+
OUTPUT: a set of endomorphisms in category
|
|
509
|
+
|
|
510
|
+
EXAMPLES::
|
|
511
|
+
|
|
512
|
+
sage: V = VectorSpace(QQ, 3) # needs sage.modules
|
|
513
|
+
sage: End(V) # needs sage.modules
|
|
514
|
+
Set of Morphisms (Linear Transformations)
|
|
515
|
+
from Vector space of dimension 3 over Rational Field
|
|
516
|
+
to Vector space of dimension 3 over Rational Field
|
|
517
|
+
|
|
518
|
+
::
|
|
519
|
+
|
|
520
|
+
sage: # needs sage.groups
|
|
521
|
+
sage: G = AlternatingGroup(3)
|
|
522
|
+
sage: S = End(G); S
|
|
523
|
+
Set of Morphisms
|
|
524
|
+
from Alternating group of order 3!/2 as a permutation group
|
|
525
|
+
to Alternating group of order 3!/2 as a permutation group
|
|
526
|
+
in Category of finite enumerated permutation groups
|
|
527
|
+
sage: S.domain()
|
|
528
|
+
Alternating group of order 3!/2 as a permutation group
|
|
529
|
+
|
|
530
|
+
To avoid creating superfluous categories, a homset in a category
|
|
531
|
+
``Cs()`` is in the homset category of the lowest full super category
|
|
532
|
+
``Bs()`` of ``Cs()`` that implements ``Bs.Homsets`` (or the join
|
|
533
|
+
thereof if there are several). For example, finite groups form a
|
|
534
|
+
full subcategory of unital magmas: any unital magma morphism
|
|
535
|
+
between two finite groups is a finite group morphism. Since finite
|
|
536
|
+
groups currently implement nothing more than unital magmas about
|
|
537
|
+
their homsets, we have::
|
|
538
|
+
|
|
539
|
+
sage: # needs sage.groups sage.modules
|
|
540
|
+
sage: G = GL(3, 3)
|
|
541
|
+
sage: G.category()
|
|
542
|
+
Category of finite groups
|
|
543
|
+
sage: H = Hom(G, G)
|
|
544
|
+
sage: H.homset_category()
|
|
545
|
+
Category of finite groups
|
|
546
|
+
sage: H.category()
|
|
547
|
+
Category of endsets of unital magmas
|
|
548
|
+
|
|
549
|
+
Similarly, a ring morphism just needs to preserve addition,
|
|
550
|
+
multiplication, zero, and one. Accordingly, and since the category
|
|
551
|
+
of rings implements nothing specific about its homsets, a ring
|
|
552
|
+
homset is currently constructed in the category of homsets of
|
|
553
|
+
unital magmas and unital additive magmas::
|
|
554
|
+
|
|
555
|
+
sage: H = Hom(ZZ,ZZ,Rings())
|
|
556
|
+
sage: H.category()
|
|
557
|
+
Category of endsets of unital magmas and additive unital additive magmas
|
|
558
|
+
"""
|
|
559
|
+
return Hom(X,X, category)
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
def end(X, f):
|
|
563
|
+
"""
|
|
564
|
+
Return ``End(X)(f)``, where ``f`` is data that defines an element of
|
|
565
|
+
``End(X)``.
|
|
566
|
+
|
|
567
|
+
EXAMPLES::
|
|
568
|
+
|
|
569
|
+
sage: R.<x> = QQ[]
|
|
570
|
+
sage: phi = end(R, [x + 1])
|
|
571
|
+
sage: phi
|
|
572
|
+
Ring endomorphism of Univariate Polynomial Ring in x over Rational Field
|
|
573
|
+
Defn: x |--> x + 1
|
|
574
|
+
sage: phi(x^2 + 5)
|
|
575
|
+
x^2 + 2*x + 6
|
|
576
|
+
"""
|
|
577
|
+
return End(X)(f)
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
class Homset(Set_generic):
|
|
581
|
+
"""
|
|
582
|
+
The class for collections of morphisms in a category.
|
|
583
|
+
|
|
584
|
+
EXAMPLES::
|
|
585
|
+
|
|
586
|
+
sage: H = Hom(QQ^2, QQ^3) # needs sage.modules
|
|
587
|
+
sage: loads(H.dumps()) is H # needs sage.modules
|
|
588
|
+
True
|
|
589
|
+
|
|
590
|
+
Homsets of unique parents are unique as well::
|
|
591
|
+
|
|
592
|
+
sage: H = End(AffineSpace(2, names='x,y'))
|
|
593
|
+
sage: loads(dumps(AffineSpace(2, names='x,y'))) is AffineSpace(2, names='x,y')
|
|
594
|
+
True
|
|
595
|
+
sage: loads(dumps(H)) is H
|
|
596
|
+
True
|
|
597
|
+
|
|
598
|
+
Conversely, homsets of non-unique parents are non-unique::
|
|
599
|
+
|
|
600
|
+
sage: P11 = ProductProjectiveSpaces(QQ, [1, 1])
|
|
601
|
+
sage: H = End(P11)
|
|
602
|
+
sage: loads(dumps(P11)) is ProductProjectiveSpaces(QQ, [1, 1])
|
|
603
|
+
False
|
|
604
|
+
sage: loads(dumps(P11)) == ProductProjectiveSpaces(QQ, [1, 1])
|
|
605
|
+
True
|
|
606
|
+
sage: loads(dumps(H)) is H
|
|
607
|
+
False
|
|
608
|
+
sage: loads(dumps(H)) == H
|
|
609
|
+
True
|
|
610
|
+
"""
|
|
611
|
+
def __init__(self, X, Y, category=None, base=None, check=True):
|
|
612
|
+
r"""
|
|
613
|
+
TESTS::
|
|
614
|
+
|
|
615
|
+
sage: X = ZZ['x']; X.rename('X')
|
|
616
|
+
sage: Y = ZZ['y']; Y.rename('Y')
|
|
617
|
+
sage: f = X.hom([0], Y)
|
|
618
|
+
sage: class MyHomset(Homset):
|
|
619
|
+
....: def _an_element_(self):
|
|
620
|
+
....: return sage.categories.morphism.SetMorphism(self, f)
|
|
621
|
+
sage: import __main__; __main__.MyHomset = MyHomset # fakes MyHomset being defined in a Python module
|
|
622
|
+
sage: H = MyHomset(X, Y, category=Monoids(), base = ZZ)
|
|
623
|
+
sage: H
|
|
624
|
+
Set of Morphisms from X to Y in Category of monoids
|
|
625
|
+
sage: TestSuite(H).run()
|
|
626
|
+
|
|
627
|
+
sage: H = MyHomset(X, Y, category=1, base = ZZ)
|
|
628
|
+
Traceback (most recent call last):
|
|
629
|
+
...
|
|
630
|
+
TypeError: category (=1) must be a category
|
|
631
|
+
|
|
632
|
+
sage: H = MyHomset(X, Y, category=1, base = ZZ, check = False)
|
|
633
|
+
Traceback (most recent call last):
|
|
634
|
+
...
|
|
635
|
+
AttributeError: 'sage.rings.integer.Integer' object has no attribute 'Homsets'...
|
|
636
|
+
sage: P.<t> = ZZ[]
|
|
637
|
+
sage: f = P.hom([1/2*t])
|
|
638
|
+
sage: f.parent().domain()
|
|
639
|
+
Univariate Polynomial Ring in t over Integer Ring
|
|
640
|
+
sage: f.domain() is f.parent().domain()
|
|
641
|
+
True
|
|
642
|
+
|
|
643
|
+
Test that ``base_ring`` is initialized properly::
|
|
644
|
+
|
|
645
|
+
sage: R = QQ['x']
|
|
646
|
+
sage: Hom(R, R).base_ring()
|
|
647
|
+
Rational Field
|
|
648
|
+
sage: Hom(R, R, category=Sets()).base_ring()
|
|
649
|
+
sage: Hom(R, R, category=Modules(QQ)).base_ring()
|
|
650
|
+
Rational Field
|
|
651
|
+
sage: Hom(QQ^3, QQ^3, category=Modules(QQ)).base_ring() # needs sage.modules
|
|
652
|
+
Rational Field
|
|
653
|
+
|
|
654
|
+
For whatever it's worth, the ``base`` arguments takes precedence::
|
|
655
|
+
|
|
656
|
+
sage: MyHomset(ZZ^3, ZZ^3, base=QQ).base_ring() # needs sage.modules
|
|
657
|
+
Rational Field
|
|
658
|
+
"""
|
|
659
|
+
self._domain = X
|
|
660
|
+
self._codomain = Y
|
|
661
|
+
if category is None:
|
|
662
|
+
category = X.category()
|
|
663
|
+
self.__category = category
|
|
664
|
+
if check:
|
|
665
|
+
if not isinstance(category, Category):
|
|
666
|
+
raise TypeError("category (=%s) must be a category" % category)
|
|
667
|
+
# if not X in category:
|
|
668
|
+
# raise TypeError("X (=%s) must be in category (=%s)" % (X, category))
|
|
669
|
+
# if not Y in category:
|
|
670
|
+
# raise TypeError("Y (=%s) must be in category (=%s)" % (Y, category))
|
|
671
|
+
|
|
672
|
+
if base is None and hasattr(category, "WithBasis"):
|
|
673
|
+
# The above is a lame but fast check that category is a
|
|
674
|
+
# subcategory of Modules(...). That will do until
|
|
675
|
+
# CategoryObject.base_ring will be gone and not prevent
|
|
676
|
+
# anymore from implementing base_ring in Modules.Homsets.ParentMethods.
|
|
677
|
+
# See also #15801.
|
|
678
|
+
base = X.base_ring()
|
|
679
|
+
|
|
680
|
+
Parent.__init__(self, base=base,
|
|
681
|
+
category=category.Endsets() if X is Y else category.Homsets())
|
|
682
|
+
|
|
683
|
+
def __reduce__(self):
|
|
684
|
+
"""
|
|
685
|
+
Implement pickling by construction for Homsets.
|
|
686
|
+
|
|
687
|
+
Homsets are unpickled using the function
|
|
688
|
+
:func:`~sage.categories.homset.Hom` which is cached:
|
|
689
|
+
``Hom(domain, codomain, category, check=False)``.
|
|
690
|
+
|
|
691
|
+
.. NOTE::
|
|
692
|
+
|
|
693
|
+
It can happen, that ``Hom(X,X)`` is called during
|
|
694
|
+
unpickling with an uninitialized instance ``X`` of a Python
|
|
695
|
+
class. In some of these cases, testing that ``X in
|
|
696
|
+
category`` can trigger ``X.category()``. This in turn can
|
|
697
|
+
raise a error, or return a too large category (``Sets()``,
|
|
698
|
+
for example) and (worse!) assign this larger category to
|
|
699
|
+
the ``X._category`` cdef attribute, so that it would
|
|
700
|
+
subsequently seem that ``X``'s category was initialised.
|
|
701
|
+
|
|
702
|
+
Beside speed considerations, this is the main rationale
|
|
703
|
+
for disabling checks upon unpickling.
|
|
704
|
+
|
|
705
|
+
.. SEEALSO:: :issue:`14793`, :issue:`16275`
|
|
706
|
+
|
|
707
|
+
EXAMPLES::
|
|
708
|
+
|
|
709
|
+
sage: H = Hom(QQ^2, QQ^3) # needs sage.modules
|
|
710
|
+
sage: H.__reduce__() # needs sage.modules
|
|
711
|
+
(<function Hom at ...>,
|
|
712
|
+
(Vector space of dimension 2 over Rational Field,
|
|
713
|
+
Vector space of dimension 3 over Rational Field,
|
|
714
|
+
Category of finite dimensional vector spaces with basis over
|
|
715
|
+
(number fields and quotient fields and metric spaces),
|
|
716
|
+
False))
|
|
717
|
+
|
|
718
|
+
TESTS::
|
|
719
|
+
|
|
720
|
+
sage: loads(H.dumps()) is H # needs sage.modules
|
|
721
|
+
True
|
|
722
|
+
|
|
723
|
+
Homsets of non-unique parents are non-unique as well::
|
|
724
|
+
|
|
725
|
+
sage: # needs sage.groups
|
|
726
|
+
sage: G = PermutationGroup([[(1, 2, 3), (4, 5)], [(3, 4)]])
|
|
727
|
+
sage: G is loads(dumps(G))
|
|
728
|
+
False
|
|
729
|
+
sage: H = Hom(G, G)
|
|
730
|
+
sage: H is loads(dumps(H))
|
|
731
|
+
False
|
|
732
|
+
sage: H == loads(dumps(H))
|
|
733
|
+
True
|
|
734
|
+
"""
|
|
735
|
+
return Hom, (self._domain, self._codomain, self.__category, False)
|
|
736
|
+
|
|
737
|
+
def _repr_(self):
|
|
738
|
+
"""
|
|
739
|
+
TESTS::
|
|
740
|
+
|
|
741
|
+
sage: Hom(ZZ^2, QQ, category=Sets())._repr_() # needs sage.modules
|
|
742
|
+
'Set of Morphisms from Ambient free module of rank 2 over the principal ideal domain Integer Ring to Rational Field in Category of sets'
|
|
743
|
+
"""
|
|
744
|
+
return "Set of Morphisms from {} to {} in {}".format(self._domain,
|
|
745
|
+
self._codomain, self.__category)
|
|
746
|
+
|
|
747
|
+
def __hash__(self):
|
|
748
|
+
"""
|
|
749
|
+
The hash is obtained from domain, codomain and base.
|
|
750
|
+
|
|
751
|
+
TESTS::
|
|
752
|
+
|
|
753
|
+
sage: hash(Hom(ZZ, QQ)) == hash((ZZ, QQ, ZZ))
|
|
754
|
+
True
|
|
755
|
+
sage: hash(Hom(QQ, ZZ)) == hash((QQ, ZZ, QQ))
|
|
756
|
+
True
|
|
757
|
+
|
|
758
|
+
sage: # needs database_cremona_mini_ellcurve sage.schemes
|
|
759
|
+
sage: E = EllipticCurve('37a')
|
|
760
|
+
sage: H = E(0).parent(); H
|
|
761
|
+
Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
|
|
762
|
+
sage: hash(H) == hash((H.domain(), H.codomain(), H.base()))
|
|
763
|
+
True
|
|
764
|
+
"""
|
|
765
|
+
return hash((self._domain, self._codomain, self.base()))
|
|
766
|
+
|
|
767
|
+
def __bool__(self) -> bool:
|
|
768
|
+
"""
|
|
769
|
+
TESTS::
|
|
770
|
+
|
|
771
|
+
sage: bool(Hom(ZZ, QQ))
|
|
772
|
+
True
|
|
773
|
+
"""
|
|
774
|
+
return True
|
|
775
|
+
|
|
776
|
+
def homset_category(self):
|
|
777
|
+
"""
|
|
778
|
+
Return the category that this is a Hom in, i.e., this is typically
|
|
779
|
+
the category of the domain or codomain object.
|
|
780
|
+
|
|
781
|
+
EXAMPLES::
|
|
782
|
+
|
|
783
|
+
sage: H = Hom(AlternatingGroup(4), AlternatingGroup(7)) # needs sage.groups
|
|
784
|
+
sage: H.homset_category() # needs sage.groups
|
|
785
|
+
Category of finite enumerated permutation groups
|
|
786
|
+
"""
|
|
787
|
+
return self.__category
|
|
788
|
+
|
|
789
|
+
def _element_constructor_(self, x, check=None, **options):
|
|
790
|
+
r"""
|
|
791
|
+
Construct a morphism in this homset from ``x`` if possible.
|
|
792
|
+
|
|
793
|
+
EXAMPLES::
|
|
794
|
+
|
|
795
|
+
sage: H = Hom(SymmetricGroup(4), SymmetricGroup(7)) # needs sage.groups
|
|
796
|
+
sage: phi = Hom(SymmetricGroup(5), SymmetricGroup(6)).natural_map() # needs sage.groups
|
|
797
|
+
sage: phi # needs sage.groups
|
|
798
|
+
Coercion morphism:
|
|
799
|
+
From: Symmetric group of order 5! as a permutation group
|
|
800
|
+
To: Symmetric group of order 6! as a permutation group
|
|
801
|
+
|
|
802
|
+
When converting `\phi` into `H`, some coerce maps are applied. Note
|
|
803
|
+
that (in contrast to what is stated in the following string
|
|
804
|
+
representation) it is safe to use the resulting map, since a composite
|
|
805
|
+
map prevents the codomains of all constituent maps from garbage
|
|
806
|
+
collection, if there is a strong reference to its domain (which is the
|
|
807
|
+
case here)::
|
|
808
|
+
|
|
809
|
+
sage: H(phi) # needs sage.groups
|
|
810
|
+
Composite map:
|
|
811
|
+
From: Symmetric group of order 4! as a permutation group
|
|
812
|
+
To: Symmetric group of order 7! as a permutation group
|
|
813
|
+
Defn: (map internal to coercion system -- copy before use)
|
|
814
|
+
Coercion map:
|
|
815
|
+
From: Symmetric group of order 4! as a permutation group
|
|
816
|
+
To: Symmetric group of order 5! as a permutation group
|
|
817
|
+
then
|
|
818
|
+
Coercion morphism:
|
|
819
|
+
From: Symmetric group of order 5! as a permutation group
|
|
820
|
+
To: Symmetric group of order 6! as a permutation group
|
|
821
|
+
then
|
|
822
|
+
(map internal to coercion system -- copy before use)
|
|
823
|
+
Coercion map:
|
|
824
|
+
From: Symmetric group of order 6! as a permutation group
|
|
825
|
+
To: Symmetric group of order 7! as a permutation group
|
|
826
|
+
|
|
827
|
+
Also note that making a copy of the resulting map will automatically
|
|
828
|
+
make strengthened copies of the composed maps::
|
|
829
|
+
|
|
830
|
+
sage: copy(H(phi)) # needs sage.groups
|
|
831
|
+
Composite map:
|
|
832
|
+
From: Symmetric group of order 4! as a permutation group
|
|
833
|
+
To: Symmetric group of order 7! as a permutation group
|
|
834
|
+
Defn: Coercion map:
|
|
835
|
+
From: Symmetric group of order 4! as a permutation group
|
|
836
|
+
To: Symmetric group of order 5! as a permutation group
|
|
837
|
+
then
|
|
838
|
+
Coercion morphism:
|
|
839
|
+
From: Symmetric group of order 5! as a permutation group
|
|
840
|
+
To: Symmetric group of order 6! as a permutation group
|
|
841
|
+
then
|
|
842
|
+
Coercion map:
|
|
843
|
+
From: Symmetric group of order 6! as a permutation group
|
|
844
|
+
To: Symmetric group of order 7! as a permutation group
|
|
845
|
+
sage: H = Hom(ZZ, ZZ, Sets())
|
|
846
|
+
sage: f = H( lambda x: x + 1 )
|
|
847
|
+
sage: f.parent()
|
|
848
|
+
Set of Morphisms from Integer Ring to Integer Ring in Category of sets
|
|
849
|
+
sage: f.domain()
|
|
850
|
+
Integer Ring
|
|
851
|
+
sage: f.codomain()
|
|
852
|
+
Integer Ring
|
|
853
|
+
sage: f(1), f(2), f(3)
|
|
854
|
+
(2, 3, 4)
|
|
855
|
+
|
|
856
|
+
sage: H = Hom(Set([1,2,3]), Set([1,2,3]))
|
|
857
|
+
sage: f = H(lambda x: 4 - x)
|
|
858
|
+
sage: f.parent()
|
|
859
|
+
Set of Morphisms from {1, 2, 3} to {1, 2, 3} in Category of finite enumerated sets
|
|
860
|
+
sage: f(1), f(2), f(3) # todo: not implemented
|
|
861
|
+
|
|
862
|
+
sage: H = Hom(ZZ, QQ, Sets())
|
|
863
|
+
sage: f = H( ConstantFunction(2/3) )
|
|
864
|
+
sage: f.parent()
|
|
865
|
+
Set of Morphisms from Integer Ring to Rational Field in Category of sets
|
|
866
|
+
sage: f(1), f(2), f(3)
|
|
867
|
+
(2/3, 2/3, 2/3)
|
|
868
|
+
|
|
869
|
+
By :issue:`14711`, conversion and coerce maps should be copied
|
|
870
|
+
before using them outside of the coercion system::
|
|
871
|
+
|
|
872
|
+
sage: H = Hom(ZZ,QQ['t'], CommutativeAdditiveGroups())
|
|
873
|
+
sage: P.<t> = ZZ[]
|
|
874
|
+
sage: f = P.hom([2*t])
|
|
875
|
+
sage: phi = H._generic_convert_map(f.parent()); phi
|
|
876
|
+
Conversion map:
|
|
877
|
+
From: Set of Homomorphisms from Univariate Polynomial Ring in t over Integer Ring to Univariate Polynomial Ring in t over Integer Ring
|
|
878
|
+
To: Set of Morphisms from Integer Ring to Univariate Polynomial Ring in t over Rational Field in Category of commutative additive groups
|
|
879
|
+
sage: H._generic_convert_map(f.parent())(f)
|
|
880
|
+
Composite map:
|
|
881
|
+
From: Integer Ring
|
|
882
|
+
To: Univariate Polynomial Ring in t over Rational Field
|
|
883
|
+
Defn: (map internal to coercion system -- copy before use)
|
|
884
|
+
Polynomial base injection morphism:
|
|
885
|
+
From: Integer Ring
|
|
886
|
+
To: Univariate Polynomial Ring in t over Integer Ring
|
|
887
|
+
then
|
|
888
|
+
Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring
|
|
889
|
+
Defn: t |--> 2*t
|
|
890
|
+
then
|
|
891
|
+
(map internal to coercion system -- copy before use)
|
|
892
|
+
Ring morphism:
|
|
893
|
+
From: Univariate Polynomial Ring in t over Integer Ring
|
|
894
|
+
To: Univariate Polynomial Ring in t over Rational Field
|
|
895
|
+
sage: copy(H._generic_convert_map(f.parent())(f))
|
|
896
|
+
Composite map:
|
|
897
|
+
From: Integer Ring
|
|
898
|
+
To: Univariate Polynomial Ring in t over Rational Field
|
|
899
|
+
Defn: Polynomial base injection morphism:
|
|
900
|
+
From: Integer Ring
|
|
901
|
+
To: Univariate Polynomial Ring in t over Integer Ring
|
|
902
|
+
then
|
|
903
|
+
Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring
|
|
904
|
+
Defn: t |--> 2*t
|
|
905
|
+
then
|
|
906
|
+
Ring morphism:
|
|
907
|
+
From: Univariate Polynomial Ring in t over Integer Ring
|
|
908
|
+
To: Univariate Polynomial Ring in t over Rational Field
|
|
909
|
+
Defn: Induced from base ring by
|
|
910
|
+
Natural morphism:
|
|
911
|
+
From: Integer Ring
|
|
912
|
+
To: Rational Field
|
|
913
|
+
|
|
914
|
+
TESTS::
|
|
915
|
+
|
|
916
|
+
sage: # needs sage.combinat sage.groups
|
|
917
|
+
sage: G.<x,y,z> = FreeGroup()
|
|
918
|
+
sage: H = Hom(G, G)
|
|
919
|
+
sage: H(H.identity())
|
|
920
|
+
Identity endomorphism of Free Group on generators {x, y, z}
|
|
921
|
+
sage: H()
|
|
922
|
+
Traceback (most recent call last):
|
|
923
|
+
...
|
|
924
|
+
TypeError: unable to convert 0 to an element of
|
|
925
|
+
Set of Morphisms from Free Group on generators {x, y, z}
|
|
926
|
+
to Free Group on generators {x, y, z} in Category of infinite groups
|
|
927
|
+
sage: H("whatever")
|
|
928
|
+
Traceback (most recent call last):
|
|
929
|
+
...
|
|
930
|
+
TypeError: unable to convert 'whatever' to an element of
|
|
931
|
+
Set of Morphisms from Free Group on generators {x, y, z}
|
|
932
|
+
to Free Group on generators {x, y, z} in Category of infinite groups
|
|
933
|
+
sage: HH = Hom(H, H)
|
|
934
|
+
sage: HH(HH.identity(), foo='bar')
|
|
935
|
+
Traceback (most recent call last):
|
|
936
|
+
...
|
|
937
|
+
NotImplementedError: no keywords are implemented for
|
|
938
|
+
constructing elements of ...
|
|
939
|
+
|
|
940
|
+
AUTHORS:
|
|
941
|
+
|
|
942
|
+
- Robert Bradshaw, with changes by Nicolas M. Thiery
|
|
943
|
+
"""
|
|
944
|
+
if options:
|
|
945
|
+
# TODO: this is specific for ModulesWithBasis; generalize
|
|
946
|
+
# this to allow homsets and categories to provide more
|
|
947
|
+
# morphism constructors (on_algebra_generators, ...)
|
|
948
|
+
try:
|
|
949
|
+
call_with_keywords = self.__call_on_basis__
|
|
950
|
+
except AttributeError:
|
|
951
|
+
if 'base_map' in options:
|
|
952
|
+
raise NotImplementedError("base_map not supported for this Homset; you may need to specify a category")
|
|
953
|
+
raise NotImplementedError("no keywords are implemented for constructing elements of {}".format(self))
|
|
954
|
+
options.setdefault("category", self.homset_category())
|
|
955
|
+
return call_with_keywords(**options)
|
|
956
|
+
|
|
957
|
+
if isinstance(x, morphism.Morphism):
|
|
958
|
+
if x.domain() != self.domain():
|
|
959
|
+
mor = x.domain()._internal_coerce_map_from(self.domain())
|
|
960
|
+
if mor is None:
|
|
961
|
+
raise TypeError("Incompatible domains: x (=%s) cannot be an element of %s" % (x,self))
|
|
962
|
+
x = x * mor
|
|
963
|
+
if x.codomain() != self.codomain():
|
|
964
|
+
mor = self.codomain()._internal_coerce_map_from(x.codomain())
|
|
965
|
+
if mor is None:
|
|
966
|
+
raise TypeError("Incompatible codomains: x (=%s) cannot be an element of %s" % (x,self))
|
|
967
|
+
x = mor * x
|
|
968
|
+
return x
|
|
969
|
+
|
|
970
|
+
if callable(x):
|
|
971
|
+
return self.element_class_set_morphism(self, x)
|
|
972
|
+
|
|
973
|
+
raise TypeError("unable to convert {!r} to an element of {}".format(x, self))
|
|
974
|
+
|
|
975
|
+
@lazy_attribute
|
|
976
|
+
def _abstract_element_class(self):
|
|
977
|
+
"""
|
|
978
|
+
An abstract class for the elements of this homset.
|
|
979
|
+
|
|
980
|
+
This class is built from the element class of the homset
|
|
981
|
+
category and the morphism class of the category. This makes
|
|
982
|
+
it possible for a category to provide code for its morphisms
|
|
983
|
+
and for morphisms of all its subcategories, full or not.
|
|
984
|
+
|
|
985
|
+
.. NOTE::
|
|
986
|
+
|
|
987
|
+
The element class of ``C.Homsets()`` will be inherited by
|
|
988
|
+
morphisms in *full* subcategories of ``C``, while the morphism
|
|
989
|
+
class of ``C`` will be inherited by *all* subcategories of
|
|
990
|
+
``C``. Hence, if some feature of a morphism depends on the
|
|
991
|
+
algebraic properties of the homsets, it should be implemented by
|
|
992
|
+
``C.Homsets.ElementMethods``, but if it depends only on the
|
|
993
|
+
algebraic properties of domain and codomain, it should be
|
|
994
|
+
implemented in ``C.MorphismMethods``.
|
|
995
|
+
|
|
996
|
+
At this point, the homset element classes take precedence over the
|
|
997
|
+
morphism classes. But this may be subject to change.
|
|
998
|
+
|
|
999
|
+
|
|
1000
|
+
.. TODO::
|
|
1001
|
+
|
|
1002
|
+
- Make sure this class is shared whenever possible.
|
|
1003
|
+
- Flatten join category classes
|
|
1004
|
+
|
|
1005
|
+
.. SEEALSO::
|
|
1006
|
+
|
|
1007
|
+
- :meth:`Parent._abstract_element_class`
|
|
1008
|
+
|
|
1009
|
+
EXAMPLES:
|
|
1010
|
+
|
|
1011
|
+
Let's take a homset of finite commutative groups as example; at
|
|
1012
|
+
this point this is the simplest one to create (gosh)::
|
|
1013
|
+
|
|
1014
|
+
sage: # needs sage.groups
|
|
1015
|
+
sage: cat = Groups().Finite().Commutative()
|
|
1016
|
+
sage: C3 = PermutationGroup([(1,2,3)])
|
|
1017
|
+
sage: C3._refine_category_(cat)
|
|
1018
|
+
sage: C2 = PermutationGroup([(1,2)])
|
|
1019
|
+
sage: C2._refine_category_(cat)
|
|
1020
|
+
sage: H = Hom(C3, C2, cat)
|
|
1021
|
+
sage: H.homset_category()
|
|
1022
|
+
Category of finite commutative groups
|
|
1023
|
+
sage: H.category()
|
|
1024
|
+
Category of homsets of unital magmas
|
|
1025
|
+
sage: cls = H._abstract_element_class; cls
|
|
1026
|
+
<class 'sage.categories.homsets.GroupHomset_libgap_with_category._abstract_element_class'>
|
|
1027
|
+
sage: cls.__bases__ == (H.category().element_class, H.homset_category().morphism_class)
|
|
1028
|
+
True
|
|
1029
|
+
|
|
1030
|
+
A morphism of finite commutative semigroups is also a morphism
|
|
1031
|
+
of semigroups, of magmas, ...; it thus inherits code from all
|
|
1032
|
+
those categories::
|
|
1033
|
+
|
|
1034
|
+
sage: # needs sage.groups
|
|
1035
|
+
sage: issubclass(cls, Semigroups().Finite().morphism_class)
|
|
1036
|
+
True
|
|
1037
|
+
sage: issubclass(cls, Semigroups().morphism_class)
|
|
1038
|
+
True
|
|
1039
|
+
sage: issubclass(cls, Magmas().Commutative().morphism_class)
|
|
1040
|
+
True
|
|
1041
|
+
sage: issubclass(cls, Magmas().morphism_class)
|
|
1042
|
+
True
|
|
1043
|
+
sage: issubclass(cls, Sets().morphism_class)
|
|
1044
|
+
True
|
|
1045
|
+
|
|
1046
|
+
Recall that FiniteMonoids() is a full subcategory of
|
|
1047
|
+
``Monoids()``, but not of ``FiniteSemigroups()``. Thus::
|
|
1048
|
+
|
|
1049
|
+
sage: issubclass(cls, Monoids().Finite().Homsets().element_class) # needs sage.groups
|
|
1050
|
+
True
|
|
1051
|
+
sage: issubclass(cls, Semigroups().Finite().Homsets().element_class) # needs sage.groups
|
|
1052
|
+
False
|
|
1053
|
+
"""
|
|
1054
|
+
class_name = "%s._abstract_element_class" % self.__class__.__name__
|
|
1055
|
+
return dynamic_class(class_name, (self.category().element_class, self.homset_category().morphism_class))
|
|
1056
|
+
|
|
1057
|
+
@lazy_attribute
|
|
1058
|
+
def element_class_set_morphism(self):
|
|
1059
|
+
"""
|
|
1060
|
+
A base class for elements of this homset which are
|
|
1061
|
+
also ``SetMorphism``, i.e. implemented by mean of a
|
|
1062
|
+
Python function.
|
|
1063
|
+
|
|
1064
|
+
This is currently plain ``SetMorphism``, without inheritance
|
|
1065
|
+
from categories.
|
|
1066
|
+
|
|
1067
|
+
.. TODO::
|
|
1068
|
+
|
|
1069
|
+
Refactor during the upcoming homset cleanup.
|
|
1070
|
+
|
|
1071
|
+
EXAMPLES::
|
|
1072
|
+
|
|
1073
|
+
sage: H = Hom(ZZ, ZZ)
|
|
1074
|
+
sage: H.element_class_set_morphism
|
|
1075
|
+
<class 'sage.categories.morphism.SetMorphism'>
|
|
1076
|
+
"""
|
|
1077
|
+
return self.__make_element_class__(morphism.SetMorphism)
|
|
1078
|
+
|
|
1079
|
+
def __eq__(self, other):
|
|
1080
|
+
"""
|
|
1081
|
+
For two homsets, it is tested whether the domain, the codomain and
|
|
1082
|
+
the category coincide.
|
|
1083
|
+
|
|
1084
|
+
EXAMPLES::
|
|
1085
|
+
|
|
1086
|
+
sage: H1 = Hom(ZZ,QQ, CommutativeAdditiveGroups())
|
|
1087
|
+
sage: H2 = Hom(ZZ,QQ)
|
|
1088
|
+
sage: H1 == H2
|
|
1089
|
+
False
|
|
1090
|
+
sage: H1 == loads(dumps(H1))
|
|
1091
|
+
True
|
|
1092
|
+
"""
|
|
1093
|
+
if not isinstance(other, Homset):
|
|
1094
|
+
return False
|
|
1095
|
+
return (self._domain == other._domain
|
|
1096
|
+
and self._codomain == other._codomain
|
|
1097
|
+
and self.__category == other.__category)
|
|
1098
|
+
|
|
1099
|
+
def __ne__(self, other):
|
|
1100
|
+
"""
|
|
1101
|
+
Check for not-equality of ``self`` and ``other``.
|
|
1102
|
+
|
|
1103
|
+
EXAMPLES::
|
|
1104
|
+
|
|
1105
|
+
sage: H1 = Hom(ZZ,QQ, CommutativeAdditiveGroups())
|
|
1106
|
+
sage: H2 = Hom(ZZ,QQ)
|
|
1107
|
+
sage: H3 = Hom(ZZ['t'],QQ, CommutativeAdditiveGroups())
|
|
1108
|
+
sage: H4 = Hom(ZZ,QQ['t'], CommutativeAdditiveGroups())
|
|
1109
|
+
sage: H1 != H2
|
|
1110
|
+
True
|
|
1111
|
+
sage: H1 != loads(dumps(H1))
|
|
1112
|
+
False
|
|
1113
|
+
sage: H1 != H3 != H4 != H1
|
|
1114
|
+
True
|
|
1115
|
+
"""
|
|
1116
|
+
return not (self == other)
|
|
1117
|
+
|
|
1118
|
+
def __contains__(self, x):
|
|
1119
|
+
"""
|
|
1120
|
+
Test whether the parent of the argument is ``self``.
|
|
1121
|
+
|
|
1122
|
+
TESTS::
|
|
1123
|
+
|
|
1124
|
+
sage: P.<t> = ZZ[]
|
|
1125
|
+
sage: f = P.hom([1/2*t])
|
|
1126
|
+
sage: f in Hom(ZZ['t'],QQ['t']) # indirect doctest
|
|
1127
|
+
True
|
|
1128
|
+
sage: f in Hom(ZZ['t'],QQ['t'], CommutativeAdditiveGroups()) # indirect doctest
|
|
1129
|
+
False
|
|
1130
|
+
"""
|
|
1131
|
+
try:
|
|
1132
|
+
return x.parent() == self
|
|
1133
|
+
except AttributeError:
|
|
1134
|
+
pass
|
|
1135
|
+
return False
|
|
1136
|
+
|
|
1137
|
+
def natural_map(self):
|
|
1138
|
+
"""
|
|
1139
|
+
Return the "natural map" of this homset.
|
|
1140
|
+
|
|
1141
|
+
.. NOTE::
|
|
1142
|
+
|
|
1143
|
+
By default, a formal coercion morphism is returned.
|
|
1144
|
+
|
|
1145
|
+
EXAMPLES::
|
|
1146
|
+
|
|
1147
|
+
sage: H = Hom(ZZ['t'],QQ['t'], CommutativeAdditiveGroups())
|
|
1148
|
+
sage: H.natural_map()
|
|
1149
|
+
Coercion morphism:
|
|
1150
|
+
From: Univariate Polynomial Ring in t over Integer Ring
|
|
1151
|
+
To: Univariate Polynomial Ring in t over Rational Field
|
|
1152
|
+
sage: H = Hom(QQ['t'], GF(3)['t'])
|
|
1153
|
+
sage: H.natural_map()
|
|
1154
|
+
Traceback (most recent call last):
|
|
1155
|
+
...
|
|
1156
|
+
TypeError: natural coercion morphism
|
|
1157
|
+
from Univariate Polynomial Ring in t over Rational Field
|
|
1158
|
+
to Univariate Polynomial Ring in t over Finite Field of size 3 not defined
|
|
1159
|
+
"""
|
|
1160
|
+
return morphism.FormalCoercionMorphism(self) # good default in many cases
|
|
1161
|
+
|
|
1162
|
+
def identity(self):
|
|
1163
|
+
"""
|
|
1164
|
+
The identity map of this homset.
|
|
1165
|
+
|
|
1166
|
+
.. NOTE::
|
|
1167
|
+
|
|
1168
|
+
Of course, this only exists for sets of endomorphisms.
|
|
1169
|
+
|
|
1170
|
+
EXAMPLES::
|
|
1171
|
+
|
|
1172
|
+
sage: H = Hom(QQ,QQ)
|
|
1173
|
+
sage: H.identity()
|
|
1174
|
+
Identity endomorphism of Rational Field
|
|
1175
|
+
sage: H = Hom(ZZ,QQ)
|
|
1176
|
+
sage: H.identity()
|
|
1177
|
+
Traceback (most recent call last):
|
|
1178
|
+
...
|
|
1179
|
+
TypeError: identity map only defined for endomorphisms; try natural_map() instead
|
|
1180
|
+
sage: H.natural_map()
|
|
1181
|
+
Natural morphism:
|
|
1182
|
+
From: Integer Ring
|
|
1183
|
+
To: Rational Field
|
|
1184
|
+
"""
|
|
1185
|
+
if self.is_endomorphism_set():
|
|
1186
|
+
return morphism.IdentityMorphism(self)
|
|
1187
|
+
raise TypeError("identity map only defined for endomorphisms; try natural_map() instead")
|
|
1188
|
+
|
|
1189
|
+
def one(self):
|
|
1190
|
+
"""
|
|
1191
|
+
The identity map of this homset.
|
|
1192
|
+
|
|
1193
|
+
.. NOTE::
|
|
1194
|
+
|
|
1195
|
+
Of course, this only exists for sets of endomorphisms.
|
|
1196
|
+
|
|
1197
|
+
EXAMPLES::
|
|
1198
|
+
|
|
1199
|
+
sage: K = GaussianIntegers() # needs sage.rings.number_field
|
|
1200
|
+
sage: End(K).one() # needs sage.rings.number_field
|
|
1201
|
+
Identity endomorphism of Gaussian Integers generated by I
|
|
1202
|
+
in Number Field in I with defining polynomial x^2 + 1 with I = 1*I
|
|
1203
|
+
"""
|
|
1204
|
+
return self.identity()
|
|
1205
|
+
|
|
1206
|
+
def domain(self):
|
|
1207
|
+
"""
|
|
1208
|
+
Return the domain of this homset.
|
|
1209
|
+
|
|
1210
|
+
EXAMPLES::
|
|
1211
|
+
|
|
1212
|
+
sage: P.<t> = ZZ[]
|
|
1213
|
+
sage: f = P.hom([1/2*t])
|
|
1214
|
+
sage: f.parent().domain()
|
|
1215
|
+
Univariate Polynomial Ring in t over Integer Ring
|
|
1216
|
+
sage: f.domain() is f.parent().domain()
|
|
1217
|
+
True
|
|
1218
|
+
"""
|
|
1219
|
+
return self._domain
|
|
1220
|
+
|
|
1221
|
+
def codomain(self):
|
|
1222
|
+
"""
|
|
1223
|
+
Return the codomain of this homset.
|
|
1224
|
+
|
|
1225
|
+
EXAMPLES::
|
|
1226
|
+
|
|
1227
|
+
sage: P.<t> = ZZ[]
|
|
1228
|
+
sage: f = P.hom([1/2*t])
|
|
1229
|
+
sage: f.parent().codomain()
|
|
1230
|
+
Univariate Polynomial Ring in t over Rational Field
|
|
1231
|
+
sage: f.codomain() is f.parent().codomain()
|
|
1232
|
+
True
|
|
1233
|
+
"""
|
|
1234
|
+
return self._codomain
|
|
1235
|
+
|
|
1236
|
+
def reversed(self):
|
|
1237
|
+
"""
|
|
1238
|
+
Return the corresponding homset, but with the domain and codomain
|
|
1239
|
+
reversed.
|
|
1240
|
+
|
|
1241
|
+
EXAMPLES::
|
|
1242
|
+
|
|
1243
|
+
sage: # needs sage.modules
|
|
1244
|
+
sage: H = Hom(ZZ^2, ZZ^3); H
|
|
1245
|
+
Set of Morphisms from Ambient free module of rank 2 over
|
|
1246
|
+
the principal ideal domain Integer Ring to Ambient free module
|
|
1247
|
+
of rank 3 over the principal ideal domain Integer Ring in
|
|
1248
|
+
Category of finite dimensional modules with basis over (Dedekind
|
|
1249
|
+
domains and euclidean domains and noetherian rings
|
|
1250
|
+
and infinite enumerated sets and metric spaces)
|
|
1251
|
+
sage: type(H)
|
|
1252
|
+
<class 'sage.modules.free_module_homspace.FreeModuleHomspace_with_category'>
|
|
1253
|
+
sage: H.reversed()
|
|
1254
|
+
Set of Morphisms from Ambient free module of rank 3 over
|
|
1255
|
+
the principal ideal domain Integer Ring to Ambient free module
|
|
1256
|
+
of rank 2 over the principal ideal domain Integer Ring in
|
|
1257
|
+
Category of finite dimensional modules with basis over (Dedekind
|
|
1258
|
+
domains and euclidean domains and noetherian rings
|
|
1259
|
+
and infinite enumerated sets and metric spaces)
|
|
1260
|
+
sage: type(H.reversed())
|
|
1261
|
+
<class 'sage.modules.free_module_homspace.FreeModuleHomspace_with_category'>
|
|
1262
|
+
"""
|
|
1263
|
+
return Hom(self.codomain(), self.domain(),
|
|
1264
|
+
category=self.homset_category())
|
|
1265
|
+
|
|
1266
|
+
|
|
1267
|
+
# Really needed???
|
|
1268
|
+
class HomsetWithBase(Homset):
|
|
1269
|
+
def __init__(self, X, Y, category=None, check=True, base=None):
|
|
1270
|
+
r"""
|
|
1271
|
+
TESTS::
|
|
1272
|
+
|
|
1273
|
+
sage: X = ZZ['x']; X.rename('X')
|
|
1274
|
+
sage: Y = ZZ['y']; Y.rename('Y')
|
|
1275
|
+
sage: f = X.hom([0], Y)
|
|
1276
|
+
sage: class MyHomset(HomsetWithBase):
|
|
1277
|
+
....: def _an_element_(self):
|
|
1278
|
+
....: return sage.categories.morphism.SetMorphism(self, f)
|
|
1279
|
+
sage: import __main__; __main__.MyHomset = MyHomset # fakes MyHomset being defined in a Python module
|
|
1280
|
+
sage: H = MyHomset(X, Y, category=Monoids())
|
|
1281
|
+
sage: H
|
|
1282
|
+
Set of Morphisms from X to Y in Category of monoids
|
|
1283
|
+
sage: H.base()
|
|
1284
|
+
Integer Ring
|
|
1285
|
+
sage: TestSuite(H).run()
|
|
1286
|
+
"""
|
|
1287
|
+
if base is None:
|
|
1288
|
+
base = X.base_ring()
|
|
1289
|
+
Homset.__init__(self, X, Y, check=check, category=category, base=base)
|
|
1290
|
+
|
|
1291
|
+
|
|
1292
|
+
def is_Homset(x):
|
|
1293
|
+
"""
|
|
1294
|
+
Return ``True`` if ``x`` is a set of homomorphisms in a category.
|
|
1295
|
+
|
|
1296
|
+
EXAMPLES::
|
|
1297
|
+
|
|
1298
|
+
sage: from sage.categories.homset import is_Homset
|
|
1299
|
+
sage: P.<t> = ZZ[]
|
|
1300
|
+
sage: f = P.hom([1/2*t])
|
|
1301
|
+
sage: is_Homset(f)
|
|
1302
|
+
doctest:warning...
|
|
1303
|
+
DeprecationWarning: the function is_Homset is deprecated;
|
|
1304
|
+
use 'isinstance(..., Homset)' instead
|
|
1305
|
+
See https://github.com/sagemath/sage/issues/37922 for details.
|
|
1306
|
+
False
|
|
1307
|
+
sage: is_Homset(f.category())
|
|
1308
|
+
False
|
|
1309
|
+
sage: is_Homset(f.parent())
|
|
1310
|
+
True
|
|
1311
|
+
"""
|
|
1312
|
+
from sage.misc.superseded import deprecation
|
|
1313
|
+
deprecation(37922, "the function is_Homset is deprecated; use 'isinstance(..., Homset)' instead")
|
|
1314
|
+
return isinstance(x, Homset)
|
|
1315
|
+
|
|
1316
|
+
|
|
1317
|
+
def is_Endset(x):
|
|
1318
|
+
"""
|
|
1319
|
+
Return ``True`` if ``x`` is a set of endomorphisms in a category.
|
|
1320
|
+
|
|
1321
|
+
EXAMPLES::
|
|
1322
|
+
|
|
1323
|
+
sage: from sage.categories.homset import is_Endset
|
|
1324
|
+
sage: P.<t> = ZZ[]
|
|
1325
|
+
sage: f = P.hom([1/2*t])
|
|
1326
|
+
sage: is_Endset(f.parent())
|
|
1327
|
+
doctest:warning...
|
|
1328
|
+
DeprecationWarning: the function is_Endset is deprecated;
|
|
1329
|
+
use 'isinstance(..., Homset) and ....is_endomorphism_set()' instead
|
|
1330
|
+
See https://github.com/sagemath/sage/issues/37922 for details.
|
|
1331
|
+
False
|
|
1332
|
+
sage: g = P.hom([2*t])
|
|
1333
|
+
sage: is_Endset(g.parent())
|
|
1334
|
+
True
|
|
1335
|
+
"""
|
|
1336
|
+
from sage.misc.superseded import deprecation
|
|
1337
|
+
deprecation(37922, "the function is_Endset is deprecated; use 'isinstance(..., Homset) and ....is_endomorphism_set()' instead")
|
|
1338
|
+
return isinstance(x, Homset) and x.is_endomorphism_set()
|