passagemath-objects 10.6.41__cp312-cp312-win_amd64.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/__init__.py +3 -0
- passagemath_objects-10.6.41.dist-info/DELVEWHEEL +2 -0
- passagemath_objects-10.6.41.dist-info/METADATA +115 -0
- passagemath_objects-10.6.41.dist-info/RECORD +281 -0
- passagemath_objects-10.6.41.dist-info/WHEEL +5 -0
- passagemath_objects-10.6.41.dist-info/top_level.txt +3 -0
- passagemath_objects.libs/libgmp-10-79b4110c7ea2b760f16cfef97e8a8a34.dll +0 -0
- sage/all__sagemath_objects.py +46 -0
- sage/arith/all__sagemath_objects.py +5 -0
- sage/arith/long.pxd +411 -0
- sage/arith/numerical_approx.cp312-win_amd64.pyd +0 -0
- sage/arith/numerical_approx.pxd +35 -0
- sage/arith/numerical_approx.pyx +75 -0
- sage/arith/power.cp312-win_amd64.pyd +0 -0
- sage/arith/power.pxd +31 -0
- sage/arith/power.pyx +127 -0
- sage/categories/action.cp312-win_amd64.pyd +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 +71 -0
- sage/categories/cartesian_product.py +295 -0
- sage/categories/category.py +3401 -0
- sage/categories/category_cy_helper.cp312-win_amd64.pyd +0 -0
- sage/categories/category_cy_helper.pxd +8 -0
- sage/categories/category_cy_helper.pyx +322 -0
- sage/categories/category_singleton.cp312-win_amd64.pyd +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 +2885 -0
- sage/categories/covariant_functorial_construction.py +703 -0
- sage/categories/facade_sets.py +228 -0
- sage/categories/functor.cp312-win_amd64.pyd +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.cp312-win_amd64.pyd +0 -0
- sage/categories/map.pxd +34 -0
- sage/categories/map.pyx +2112 -0
- sage/categories/morphism.cp312-win_amd64.pyd +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 +3228 -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 +28 -0
- sage/cpython/_py2_random.py +619 -0
- sage/cpython/all.py +3 -0
- sage/cpython/atexit.cp312-win_amd64.pyd +0 -0
- sage/cpython/atexit.pyx +269 -0
- sage/cpython/builtin_types.cp312-win_amd64.pyd +0 -0
- sage/cpython/builtin_types.pyx +7 -0
- sage/cpython/cython_metaclass.cp312-win_amd64.pyd +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.cp312-win_amd64.pyd +0 -0
- sage/cpython/debug.pyx +302 -0
- sage/cpython/dict_del_by_value.cp312-win_amd64.pyd +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.cp312-win_amd64.pyd +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.cp312-win_amd64.pyd +0 -0
- sage/cpython/string.pxd +76 -0
- sage/cpython/string.pyx +34 -0
- sage/cpython/string_impl.h +60 -0
- sage/cpython/type.cp312-win_amd64.pyd +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.cp312-win_amd64.pyd +0 -0
- sage/groups/group.pxd +14 -0
- sage/groups/group.pyx +322 -0
- sage/groups/old.cp312-win_amd64.pyd +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.cp312-win_amd64.pyd +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.cp312-win_amd64.pyd +0 -0
- sage/misc/c3_controlled.pxd +2 -0
- sage/misc/c3_controlled.pyx +1402 -0
- sage/misc/cachefunc.cp312-win_amd64.pyd +0 -0
- sage/misc/cachefunc.pxd +43 -0
- sage/misc/cachefunc.pyx +3781 -0
- sage/misc/call.py +188 -0
- sage/misc/classcall_metaclass.cp312-win_amd64.pyd +0 -0
- sage/misc/classcall_metaclass.pxd +14 -0
- sage/misc/classcall_metaclass.pyx +599 -0
- sage/misc/constant_function.cp312-win_amd64.pyd +0 -0
- sage/misc/constant_function.pyx +130 -0
- sage/misc/decorators.py +747 -0
- sage/misc/fast_methods.cp312-win_amd64.pyd +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.cp312-win_amd64.pyd +0 -0
- sage/misc/fpickle.pyx +177 -0
- sage/misc/function_mangling.cp312-win_amd64.pyd +0 -0
- sage/misc/function_mangling.pxd +11 -0
- sage/misc/function_mangling.pyx +308 -0
- sage/misc/inherit_comparison.cp312-win_amd64.pyd +0 -0
- sage/misc/inherit_comparison.pxd +5 -0
- sage/misc/inherit_comparison.pyx +105 -0
- sage/misc/instancedoc.cp312-win_amd64.pyd +0 -0
- sage/misc/instancedoc.pyx +331 -0
- sage/misc/lazy_attribute.cp312-win_amd64.pyd +0 -0
- sage/misc/lazy_attribute.pyx +607 -0
- sage/misc/lazy_format.py +135 -0
- sage/misc/lazy_import.cp312-win_amd64.pyd +0 -0
- sage/misc/lazy_import.pyx +1299 -0
- sage/misc/lazy_import_cache.py +36 -0
- sage/misc/lazy_list.cp312-win_amd64.pyd +0 -0
- sage/misc/lazy_list.pxd +19 -0
- sage/misc/lazy_list.pyx +1187 -0
- sage/misc/lazy_string.cp312-win_amd64.pyd +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.cp312-win_amd64.pyd +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.cp312-win_amd64.pyd +0 -0
- sage/misc/nested_class.pxd +3 -0
- sage/misc/nested_class.pyx +394 -0
- sage/misc/persist.cp312-win_amd64.pyd +0 -0
- sage/misc/persist.pyx +1251 -0
- sage/misc/prandom.py +418 -0
- sage/misc/randstate.cp312-win_amd64.pyd +0 -0
- sage/misc/randstate.pxd +30 -0
- sage/misc/randstate.pyx +1059 -0
- sage/misc/repr.py +203 -0
- sage/misc/reset.cp312-win_amd64.pyd +0 -0
- sage/misc/reset.pyx +196 -0
- sage/misc/sage_ostools.cp312-win_amd64.pyd +0 -0
- sage/misc/sage_ostools.pyx +323 -0
- sage/misc/sage_timeit.py +276 -0
- sage/misc/sage_timeit_class.cp312-win_amd64.pyd +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.cp312-win_amd64.pyd +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.cp312-win_amd64.pyd +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.cp312-win_amd64.pyd +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.cp312-win_amd64.pyd +0 -0
- sage/sets/pythonclass.pxd +9 -0
- sage/sets/pythonclass.pyx +247 -0
- sage/structure/__init__.py +13 -0
- sage/structure/all.py +30 -0
- sage/structure/category_object.cp312-win_amd64.pyd +0 -0
- sage/structure/category_object.pxd +28 -0
- sage/structure/category_object.pyx +1087 -0
- sage/structure/coerce.cp312-win_amd64.pyd +0 -0
- sage/structure/coerce.pxd +44 -0
- sage/structure/coerce.pyx +2107 -0
- sage/structure/coerce_actions.cp312-win_amd64.pyd +0 -0
- sage/structure/coerce_actions.pxd +27 -0
- sage/structure/coerce_actions.pyx +988 -0
- sage/structure/coerce_dict.cp312-win_amd64.pyd +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.cp312-win_amd64.pyd +0 -0
- sage/structure/coerce_maps.pxd +28 -0
- sage/structure/coerce_maps.pyx +718 -0
- sage/structure/debug_options.cp312-win_amd64.pyd +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.cp312-win_amd64.pyd +0 -0
- sage/structure/element.pxd +272 -0
- sage/structure/element.pyx +4772 -0
- sage/structure/element_wrapper.cp312-win_amd64.pyd +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.cp312-win_amd64.pyd +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.cp312-win_amd64.pyd +0 -0
- sage/structure/list_clone.pxd +65 -0
- sage/structure/list_clone.pyx +1867 -0
- sage/structure/list_clone_demo.cp312-win_amd64.pyd +0 -0
- sage/structure/list_clone_demo.pyx +248 -0
- sage/structure/list_clone_timings.py +179 -0
- sage/structure/list_clone_timings_cy.cp312-win_amd64.pyd +0 -0
- sage/structure/list_clone_timings_cy.pyx +86 -0
- sage/structure/mutability.cp312-win_amd64.pyd +0 -0
- sage/structure/mutability.pxd +21 -0
- sage/structure/mutability.pyx +348 -0
- sage/structure/nonexact.py +69 -0
- sage/structure/parent.cp312-win_amd64.pyd +0 -0
- sage/structure/parent.pxd +112 -0
- sage/structure/parent.pyx +3093 -0
- sage/structure/parent_base.cp312-win_amd64.pyd +0 -0
- sage/structure/parent_base.pxd +13 -0
- sage/structure/parent_base.pyx +44 -0
- sage/structure/parent_gens.cp312-win_amd64.pyd +0 -0
- sage/structure/parent_gens.pxd +22 -0
- sage/structure/parent_gens.pyx +377 -0
- sage/structure/parent_old.cp312-win_amd64.pyd +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.cp312-win_amd64.pyd +0 -0
- sage/structure/richcmp.pxd +213 -0
- sage/structure/richcmp.pyx +495 -0
- sage/structure/sage_object.cp312-win_amd64.pyd +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,29 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-objects
|
|
2
|
+
from sage.structure.element cimport Element
|
|
3
|
+
from sage.categories.morphism cimport Morphism
|
|
4
|
+
from sage.categories.map cimport Map
|
|
5
|
+
from sage.categories.functor cimport Functor
|
|
6
|
+
|
|
7
|
+
cdef class Action(Functor):
|
|
8
|
+
cdef readonly G
|
|
9
|
+
cdef readonly op
|
|
10
|
+
cdef readonly bint _is_left
|
|
11
|
+
cdef US
|
|
12
|
+
cdef underlying_set(self)
|
|
13
|
+
|
|
14
|
+
cdef _act_convert(self, g, x)
|
|
15
|
+
cpdef _act_(self, g, x)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
cdef class InverseAction(Action):
|
|
19
|
+
cdef Action _action
|
|
20
|
+
cdef Map S_precomposition
|
|
21
|
+
|
|
22
|
+
cdef class PrecomposedAction(Action):
|
|
23
|
+
cdef Action _action
|
|
24
|
+
cdef Map G_precomposition
|
|
25
|
+
cdef Map S_precomposition
|
|
26
|
+
|
|
27
|
+
cdef class ActionEndomorphism(Morphism):
|
|
28
|
+
cdef Action _action
|
|
29
|
+
cdef Element _g
|
|
@@ -0,0 +1,641 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-objects
|
|
2
|
+
r"""
|
|
3
|
+
Group, ring, etc. actions on objects
|
|
4
|
+
|
|
5
|
+
The terminology and notation used is suggestive of groups acting on sets,
|
|
6
|
+
but this framework can be used for modules, algebras, etc.
|
|
7
|
+
|
|
8
|
+
A group action `G \times S \rightarrow S` is a functor from `G` to Sets.
|
|
9
|
+
|
|
10
|
+
.. WARNING::
|
|
11
|
+
|
|
12
|
+
An :class:`Action` object only keeps a weak reference to the underlying set
|
|
13
|
+
which is acted upon. This decision was made in :issue:`715` in order to
|
|
14
|
+
allow garbage collection within the coercion framework (this is where
|
|
15
|
+
actions are mainly used) and avoid memory leaks.
|
|
16
|
+
|
|
17
|
+
::
|
|
18
|
+
|
|
19
|
+
sage: from sage.categories.action import Action
|
|
20
|
+
sage: class P: pass
|
|
21
|
+
sage: A = Action(P(),P())
|
|
22
|
+
sage: import gc
|
|
23
|
+
sage: _ = gc.collect()
|
|
24
|
+
sage: A
|
|
25
|
+
<repr(<sage.categories.action.Action at 0x...>) failed:
|
|
26
|
+
RuntimeError: This action acted on a set that became garbage collected>
|
|
27
|
+
|
|
28
|
+
To avoid garbage collection of the underlying set, it is sufficient to
|
|
29
|
+
create a strong reference to it before the action is created.
|
|
30
|
+
|
|
31
|
+
::
|
|
32
|
+
|
|
33
|
+
sage: _ = gc.collect()
|
|
34
|
+
sage: from sage.categories.action import Action
|
|
35
|
+
sage: class P: pass
|
|
36
|
+
sage: q = P()
|
|
37
|
+
sage: A = Action(P(),q)
|
|
38
|
+
sage: gc.collect()
|
|
39
|
+
0
|
|
40
|
+
sage: A
|
|
41
|
+
Left action by <__main__.P ... at ...> on <__main__.P ... at ...>
|
|
42
|
+
|
|
43
|
+
AUTHOR:
|
|
44
|
+
|
|
45
|
+
- Robert Bradshaw: initial version
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
# ****************************************************************************
|
|
49
|
+
# Copyright (C) 2007 Robert Bradshaw <robertwb@math.washington.edu>
|
|
50
|
+
#
|
|
51
|
+
# This program is free software: you can redistribute it and/or modify
|
|
52
|
+
# it under the terms of the GNU General Public License as published by
|
|
53
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
54
|
+
# (at your option) any later version.
|
|
55
|
+
# https://www.gnu.org/licenses/
|
|
56
|
+
# ****************************************************************************
|
|
57
|
+
|
|
58
|
+
from cpython.tuple cimport PyTuple_GET_ITEM
|
|
59
|
+
|
|
60
|
+
from sage.categories.functor cimport Functor
|
|
61
|
+
from sage.categories.morphism cimport Morphism
|
|
62
|
+
from sage.categories.map cimport Map
|
|
63
|
+
from sage.structure.element cimport parent
|
|
64
|
+
from sage.structure.parent cimport Parent
|
|
65
|
+
|
|
66
|
+
from sage.categories import homset
|
|
67
|
+
from weakref import ref
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
cdef inline category(x):
|
|
71
|
+
try:
|
|
72
|
+
return x.category()
|
|
73
|
+
except AttributeError:
|
|
74
|
+
from sage.categories.objects import Objects
|
|
75
|
+
return Objects()
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
cdef class Action(Functor):
|
|
79
|
+
"""
|
|
80
|
+
The action of ``G`` on ``S``.
|
|
81
|
+
|
|
82
|
+
INPUT:
|
|
83
|
+
|
|
84
|
+
- ``G`` -- a parent or Python type
|
|
85
|
+
|
|
86
|
+
- ``S`` -- a parent or Python type
|
|
87
|
+
|
|
88
|
+
- ``is_left`` -- boolean (default: ``True``); whether elements of
|
|
89
|
+
``G`` are on the left
|
|
90
|
+
|
|
91
|
+
- ``op`` -- (default: ``None``) operation. This is not used by
|
|
92
|
+
:class:`Action` itself, but other classes may use it
|
|
93
|
+
"""
|
|
94
|
+
def __init__(self, G, S, is_left=True, op=None):
|
|
95
|
+
from sage.categories.groupoid import Groupoid
|
|
96
|
+
Functor.__init__(self, Groupoid(G), category(S))
|
|
97
|
+
self.G = G
|
|
98
|
+
self.US = ref(S)
|
|
99
|
+
self._is_left = is_left
|
|
100
|
+
self.op = op
|
|
101
|
+
|
|
102
|
+
def _apply_functor(self, x):
|
|
103
|
+
return self(x)
|
|
104
|
+
|
|
105
|
+
def __reduce__(self):
|
|
106
|
+
"""
|
|
107
|
+
Used in pickling.
|
|
108
|
+
|
|
109
|
+
.. WARNING::
|
|
110
|
+
|
|
111
|
+
If you change the signature of the ``__init__`` for a subclass,
|
|
112
|
+
you must override this method as well.
|
|
113
|
+
|
|
114
|
+
TESTS:
|
|
115
|
+
|
|
116
|
+
Check that this action can be pickled (:issue:`29031`)::
|
|
117
|
+
|
|
118
|
+
sage: P = QQ['x']
|
|
119
|
+
sage: R = (ZZ['x'])['y']
|
|
120
|
+
sage: A = R.get_action(P, operator.mul, True)
|
|
121
|
+
sage: loads(dumps(A)) is not None
|
|
122
|
+
True
|
|
123
|
+
"""
|
|
124
|
+
return (type(self), (self.G, self.underlying_set(), self._is_left, self.op))
|
|
125
|
+
|
|
126
|
+
def __call__(self, *args):
|
|
127
|
+
"""
|
|
128
|
+
Let this action act.
|
|
129
|
+
|
|
130
|
+
For a left action, ``action(a, b)`` lets ``a`` act on ``b``.
|
|
131
|
+
For a right action, ``action(a, b)`` lets ``b`` act on ``a``.
|
|
132
|
+
|
|
133
|
+
If needed, ``a`` and ``b`` are converted to the correct parent.
|
|
134
|
+
|
|
135
|
+
.. SEEALSO::
|
|
136
|
+
|
|
137
|
+
:meth:`act` which lets you pass the acting and acted-on
|
|
138
|
+
elements directly.
|
|
139
|
+
|
|
140
|
+
EXAMPLES::
|
|
141
|
+
|
|
142
|
+
sage: R.<x> = ZZ []
|
|
143
|
+
sage: from sage.structure.coerce_actions import IntegerMulAction
|
|
144
|
+
sage: A = IntegerMulAction(ZZ, R, True) # Left action
|
|
145
|
+
sage: A(5, x)
|
|
146
|
+
5*x
|
|
147
|
+
sage: A(int(5), x)
|
|
148
|
+
5*x
|
|
149
|
+
sage: A(x, 5)
|
|
150
|
+
Traceback (most recent call last):
|
|
151
|
+
...
|
|
152
|
+
TypeError: x is not a constant polynomial
|
|
153
|
+
sage: A = IntegerMulAction(ZZ, R, False) # Right action
|
|
154
|
+
sage: A(x, 5)
|
|
155
|
+
5*x
|
|
156
|
+
sage: A(x, int(5))
|
|
157
|
+
5*x
|
|
158
|
+
sage: A(5, x)
|
|
159
|
+
Traceback (most recent call last):
|
|
160
|
+
...
|
|
161
|
+
TypeError: x is not a constant polynomial
|
|
162
|
+
"""
|
|
163
|
+
if len(args) == 2:
|
|
164
|
+
# Normal case, called with (g, x) or (x, g) as arguments
|
|
165
|
+
#
|
|
166
|
+
# For a left action: g = args[0] and x = args[1]
|
|
167
|
+
# For a right action: g = args[1] and x = args[0]
|
|
168
|
+
g = <object>PyTuple_GET_ITEM(args, 1 - self._is_left)
|
|
169
|
+
x = <object>PyTuple_GET_ITEM(args, self._is_left)
|
|
170
|
+
return self._act_convert(g, x)
|
|
171
|
+
elif len(args) == 1:
|
|
172
|
+
g = <object>PyTuple_GET_ITEM(args, 0)
|
|
173
|
+
if g in self.G:
|
|
174
|
+
return ActionEndomorphism(self, self.G(g))
|
|
175
|
+
elif g == self.G:
|
|
176
|
+
return self.underlying_set()
|
|
177
|
+
else:
|
|
178
|
+
raise TypeError("%s not an element of %s" % (g, self.G))
|
|
179
|
+
else:
|
|
180
|
+
raise TypeError("actions should be called with 1 or 2 arguments")
|
|
181
|
+
|
|
182
|
+
cdef _act_convert(self, g, x):
|
|
183
|
+
"""
|
|
184
|
+
Let ``g`` act on ``x`` under this action, converting ``g``
|
|
185
|
+
and ``x`` to the correct parents first.
|
|
186
|
+
"""
|
|
187
|
+
U = self.underlying_set()
|
|
188
|
+
if parent(g) is not self.G:
|
|
189
|
+
g = self.G(g)
|
|
190
|
+
if parent(x) is not U:
|
|
191
|
+
x = U(x)
|
|
192
|
+
return self._act_(g, x)
|
|
193
|
+
|
|
194
|
+
cpdef _act_(self, g, x):
|
|
195
|
+
"""
|
|
196
|
+
Let ``g`` act on ``x`` under this action.
|
|
197
|
+
|
|
198
|
+
Regardless of whether this is a left or right action, the acting
|
|
199
|
+
element comes first.
|
|
200
|
+
|
|
201
|
+
INPUT:
|
|
202
|
+
|
|
203
|
+
- ``g`` -- an object with parent ``self.G``
|
|
204
|
+
|
|
205
|
+
- ``x`` -- an object with parent ``self.US()``
|
|
206
|
+
|
|
207
|
+
.. WARNING::
|
|
208
|
+
|
|
209
|
+
This is meant to be a fast internal function, so the
|
|
210
|
+
conditions on the input are not checked!
|
|
211
|
+
"""
|
|
212
|
+
raise NotImplementedError(f"action for {type(self)} not implemented")
|
|
213
|
+
|
|
214
|
+
def act(self, g, x):
|
|
215
|
+
"""
|
|
216
|
+
This is a consistent interface for acting on ``x`` by ``g``,
|
|
217
|
+
regardless of whether it's a left or right action.
|
|
218
|
+
|
|
219
|
+
If needed, ``g`` and ``x`` are converted to the correct parent.
|
|
220
|
+
|
|
221
|
+
EXAMPLES::
|
|
222
|
+
|
|
223
|
+
sage: R.<x> = ZZ []
|
|
224
|
+
sage: from sage.structure.coerce_actions import IntegerMulAction
|
|
225
|
+
sage: A = IntegerMulAction(ZZ, R, True) # Left action
|
|
226
|
+
sage: A.act(5, x)
|
|
227
|
+
5*x
|
|
228
|
+
sage: A.act(int(5), x)
|
|
229
|
+
5*x
|
|
230
|
+
sage: A = IntegerMulAction(ZZ, R, False) # Right action
|
|
231
|
+
sage: A.act(5, x)
|
|
232
|
+
5*x
|
|
233
|
+
sage: A.act(int(5), x)
|
|
234
|
+
5*x
|
|
235
|
+
"""
|
|
236
|
+
return self._act_convert(g, x)
|
|
237
|
+
|
|
238
|
+
def __invert__(self):
|
|
239
|
+
return InverseAction(self)
|
|
240
|
+
|
|
241
|
+
def is_left(self):
|
|
242
|
+
return self._is_left
|
|
243
|
+
|
|
244
|
+
def _repr_(self):
|
|
245
|
+
side = "Left" if self._is_left else "Right"
|
|
246
|
+
return "%s %s by %r on %r" % (side, self._repr_name_(), self.G,
|
|
247
|
+
self.underlying_set())
|
|
248
|
+
|
|
249
|
+
def _repr_name_(self):
|
|
250
|
+
return "action"
|
|
251
|
+
|
|
252
|
+
def actor(self):
|
|
253
|
+
return self.G
|
|
254
|
+
|
|
255
|
+
cdef underlying_set(self):
|
|
256
|
+
"""
|
|
257
|
+
The set on which the actor acts (it is not necessarily the codomain of
|
|
258
|
+
the action).
|
|
259
|
+
|
|
260
|
+
.. NOTE::
|
|
261
|
+
|
|
262
|
+
Since this is a cdef'ed method, we can only provide an indirect doctest.
|
|
263
|
+
|
|
264
|
+
EXAMPLES::
|
|
265
|
+
|
|
266
|
+
sage: P = QQ['x']
|
|
267
|
+
sage: R = (ZZ['x'])['y']
|
|
268
|
+
sage: A = R.get_action(P,operator.mul,True)
|
|
269
|
+
sage: A # indirect doctest
|
|
270
|
+
Right scalar multiplication
|
|
271
|
+
by Univariate Polynomial Ring in x over Rational Field
|
|
272
|
+
on Univariate Polynomial Ring in y over
|
|
273
|
+
Univariate Polynomial Ring in x over Integer Ring
|
|
274
|
+
|
|
275
|
+
In this example, the underlying set is the ring ``R``. This is the same
|
|
276
|
+
as the left domain, which is different from the codomain of the action::
|
|
277
|
+
|
|
278
|
+
sage: A.codomain()
|
|
279
|
+
Univariate Polynomial Ring in y
|
|
280
|
+
over Univariate Polynomial Ring in x over Rational Field
|
|
281
|
+
sage: A.codomain() == R
|
|
282
|
+
False
|
|
283
|
+
sage: A.left_domain() is R
|
|
284
|
+
True
|
|
285
|
+
|
|
286
|
+
By :issue:`715`, there is only a weak reference to the underlying set.
|
|
287
|
+
Hence, the underlying set may be garbage collected, even when the
|
|
288
|
+
action is still alive. This may result in a runtime error, as follows::
|
|
289
|
+
|
|
290
|
+
sage: from sage.categories.action import Action
|
|
291
|
+
sage: class P: pass
|
|
292
|
+
sage: p = P()
|
|
293
|
+
sage: q = P()
|
|
294
|
+
sage: A = Action(p,q)
|
|
295
|
+
sage: A
|
|
296
|
+
Left action by <__main__.P ... at ...> on <__main__.P ... at ...>
|
|
297
|
+
sage: del q
|
|
298
|
+
sage: import gc
|
|
299
|
+
sage: _ = gc.collect()
|
|
300
|
+
sage: A
|
|
301
|
+
<repr(<sage.categories.action.Action at 0x...>) failed:
|
|
302
|
+
RuntimeError: This action acted on a set that became garbage collected>
|
|
303
|
+
"""
|
|
304
|
+
S = self.US()
|
|
305
|
+
if S is None:
|
|
306
|
+
raise RuntimeError("This action acted on a set that became garbage collected")
|
|
307
|
+
return S
|
|
308
|
+
|
|
309
|
+
def codomain(self):
|
|
310
|
+
return self.underlying_set()
|
|
311
|
+
|
|
312
|
+
def domain(self):
|
|
313
|
+
return self.underlying_set()
|
|
314
|
+
|
|
315
|
+
def left_domain(self):
|
|
316
|
+
if self._is_left:
|
|
317
|
+
return self.G
|
|
318
|
+
else:
|
|
319
|
+
return self.domain()
|
|
320
|
+
|
|
321
|
+
def right_domain(self):
|
|
322
|
+
if self._is_left:
|
|
323
|
+
return self.domain()
|
|
324
|
+
else:
|
|
325
|
+
return self.G
|
|
326
|
+
|
|
327
|
+
def operation(self):
|
|
328
|
+
return self.op
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
cdef class InverseAction(Action):
|
|
332
|
+
"""
|
|
333
|
+
An action that acts as the inverse of the given action.
|
|
334
|
+
|
|
335
|
+
EXAMPLES::
|
|
336
|
+
|
|
337
|
+
sage: V = QQ^3 # needs sage.modules
|
|
338
|
+
sage: v = V((1, 2, 3)) # needs sage.modules
|
|
339
|
+
sage: cm = get_coercion_model()
|
|
340
|
+
|
|
341
|
+
sage: # needs sage.modules
|
|
342
|
+
sage: a = cm.get_action(V, QQ, operator.mul)
|
|
343
|
+
sage: a
|
|
344
|
+
Right scalar multiplication by Rational Field
|
|
345
|
+
on Vector space of dimension 3 over Rational Field
|
|
346
|
+
sage: ~a
|
|
347
|
+
Right inverse action by Rational Field
|
|
348
|
+
on Vector space of dimension 3 over Rational Field
|
|
349
|
+
sage: (~a)(v, 1/3)
|
|
350
|
+
(3, 6, 9)
|
|
351
|
+
|
|
352
|
+
sage: # needs sage.modules
|
|
353
|
+
sage: b = cm.get_action(QQ, V, operator.mul)
|
|
354
|
+
sage: b
|
|
355
|
+
Left scalar multiplication by Rational Field
|
|
356
|
+
on Vector space of dimension 3 over Rational Field
|
|
357
|
+
sage: ~b
|
|
358
|
+
Left inverse action by Rational Field
|
|
359
|
+
on Vector space of dimension 3 over Rational Field
|
|
360
|
+
sage: (~b)(1/3, v)
|
|
361
|
+
(3, 6, 9)
|
|
362
|
+
|
|
363
|
+
sage: c = cm.get_action(ZZ, list, operator.mul)
|
|
364
|
+
sage: c
|
|
365
|
+
Left action by Integer Ring on <... 'list'>
|
|
366
|
+
sage: ~c
|
|
367
|
+
Traceback (most recent call last):
|
|
368
|
+
...
|
|
369
|
+
TypeError: no inverse defined for Left action by Integer Ring on <... 'list'>
|
|
370
|
+
|
|
371
|
+
TESTS:
|
|
372
|
+
|
|
373
|
+
sage: x = polygen(QQ,'x')
|
|
374
|
+
sage: a = 2*x^2+2; a
|
|
375
|
+
2*x^2 + 2
|
|
376
|
+
sage: a / 2
|
|
377
|
+
x^2 + 1
|
|
378
|
+
sage: a /= 2
|
|
379
|
+
sage: a
|
|
380
|
+
x^2 + 1
|
|
381
|
+
"""
|
|
382
|
+
def __init__(self, Action action):
|
|
383
|
+
G = action.G
|
|
384
|
+
try:
|
|
385
|
+
from sage.groups.group import Group
|
|
386
|
+
# We must be in the case that parent(~a) == parent(a)
|
|
387
|
+
# so we can invert in _call_ code below.
|
|
388
|
+
if (isinstance(G, Group) and G.is_multiplicative()) or G.is_field():
|
|
389
|
+
Action.__init__(self, G, action.underlying_set(), action._is_left)
|
|
390
|
+
self._action = action
|
|
391
|
+
return
|
|
392
|
+
except (AttributeError, NotImplementedError):
|
|
393
|
+
pass
|
|
394
|
+
raise TypeError(f"no inverse defined for {action!r}")
|
|
395
|
+
|
|
396
|
+
def __reduce__(self):
|
|
397
|
+
"""
|
|
398
|
+
Used in pickling.
|
|
399
|
+
|
|
400
|
+
TESTS:
|
|
401
|
+
|
|
402
|
+
Check that this action can be pickled (:issue:`29031`)::
|
|
403
|
+
|
|
404
|
+
sage: # needs sage.modules
|
|
405
|
+
sage: V = QQ^3
|
|
406
|
+
sage: v = V((1, 2, 3))
|
|
407
|
+
sage: cm = get_coercion_model()
|
|
408
|
+
sage: a = cm.get_action(V, QQ, operator.mul)
|
|
409
|
+
sage: loads(dumps(~a)) is not None
|
|
410
|
+
True
|
|
411
|
+
"""
|
|
412
|
+
return (type(self), (self._action,))
|
|
413
|
+
|
|
414
|
+
cpdef _act_(self, g, x):
|
|
415
|
+
if self.S_precomposition is not None:
|
|
416
|
+
x = self.S_precomposition(x)
|
|
417
|
+
return self._action._act_(~g, x)
|
|
418
|
+
|
|
419
|
+
def codomain(self):
|
|
420
|
+
return self._action.codomain()
|
|
421
|
+
|
|
422
|
+
def __invert__(self):
|
|
423
|
+
return self._action
|
|
424
|
+
|
|
425
|
+
def _repr_name_(self):
|
|
426
|
+
return "inverse action"
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
cdef class PrecomposedAction(Action):
|
|
430
|
+
"""
|
|
431
|
+
A precomposed action first applies given maps, and then applying an action
|
|
432
|
+
to the return values of the maps.
|
|
433
|
+
|
|
434
|
+
EXAMPLES:
|
|
435
|
+
|
|
436
|
+
We demonstrate that an example discussed on :issue:`14711` did not become a
|
|
437
|
+
problem::
|
|
438
|
+
|
|
439
|
+
sage: # needs sage.libs.flint sage.modular
|
|
440
|
+
sage: E = ModularSymbols(11).2
|
|
441
|
+
sage: s = E.modular_symbol_rep()
|
|
442
|
+
sage: del E,s
|
|
443
|
+
sage: import gc
|
|
444
|
+
sage: _ = gc.collect()
|
|
445
|
+
sage: E = ModularSymbols(11).2
|
|
446
|
+
sage: v = E.manin_symbol_rep()
|
|
447
|
+
sage: c,x = v[0]
|
|
448
|
+
sage: y = x.modular_symbol_rep()
|
|
449
|
+
sage: coercion_model.get_action(QQ, parent(y), op=operator.mul)
|
|
450
|
+
Left scalar multiplication by Rational Field
|
|
451
|
+
on Abelian Group of all Formal Finite Sums over Rational Field
|
|
452
|
+
with precomposition on right by Coercion map:
|
|
453
|
+
From: Abelian Group of all Formal Finite Sums over Integer Ring
|
|
454
|
+
To: Abelian Group of all Formal Finite Sums over Rational Field
|
|
455
|
+
"""
|
|
456
|
+
def __init__(self, Action action, Map left_precomposition, Map right_precomposition):
|
|
457
|
+
left = action.left_domain()
|
|
458
|
+
right = action.right_domain()
|
|
459
|
+
US = action.underlying_set()
|
|
460
|
+
cdef Parent lco, rco
|
|
461
|
+
if left_precomposition is not None:
|
|
462
|
+
lco = left_precomposition._codomain
|
|
463
|
+
if lco is not left:
|
|
464
|
+
left_precomposition = homset.Hom(lco, left).natural_map() * left_precomposition
|
|
465
|
+
left = left_precomposition.domain()
|
|
466
|
+
if right_precomposition is not None:
|
|
467
|
+
rco = right_precomposition._codomain
|
|
468
|
+
if rco is not right:
|
|
469
|
+
right_precomposition = homset.Hom(rco, right).natural_map() * right_precomposition
|
|
470
|
+
right = right_precomposition.domain()
|
|
471
|
+
if action._is_left:
|
|
472
|
+
Action.__init__(self, left, US, 1)
|
|
473
|
+
else:
|
|
474
|
+
Action.__init__(self, right, US, 0)
|
|
475
|
+
self._action = action
|
|
476
|
+
if self._is_left:
|
|
477
|
+
self.G_precomposition = left_precomposition
|
|
478
|
+
self.S_precomposition = right_precomposition
|
|
479
|
+
else:
|
|
480
|
+
self.G_precomposition = right_precomposition
|
|
481
|
+
self.S_precomposition = left_precomposition
|
|
482
|
+
|
|
483
|
+
def __reduce__(self):
|
|
484
|
+
"""
|
|
485
|
+
Used in pickling.
|
|
486
|
+
|
|
487
|
+
TESTS:
|
|
488
|
+
|
|
489
|
+
Check that this action can be pickled (:issue:`29031`)::
|
|
490
|
+
|
|
491
|
+
sage: # needs sage.libs.flint sage.modular
|
|
492
|
+
sage: E = ModularSymbols(11).2
|
|
493
|
+
sage: v = E.manin_symbol_rep()
|
|
494
|
+
sage: c,x = v[0]
|
|
495
|
+
sage: y = x.modular_symbol_rep()
|
|
496
|
+
sage: act = coercion_model.get_action(QQ, parent(y), op=operator.mul)
|
|
497
|
+
sage: loads(dumps(act)) is not None
|
|
498
|
+
True
|
|
499
|
+
"""
|
|
500
|
+
return (type(self), (self._action, self.G_precomposition, self.S_precomposition))
|
|
501
|
+
|
|
502
|
+
cpdef _act_(self, g, x):
|
|
503
|
+
if self.G_precomposition is not None:
|
|
504
|
+
g = self.G_precomposition._call_(g)
|
|
505
|
+
if self.S_precomposition is not None:
|
|
506
|
+
x = self.S_precomposition._call_(x)
|
|
507
|
+
return self._action._act_(g, x)
|
|
508
|
+
|
|
509
|
+
def domain(self):
|
|
510
|
+
if self.S_precomposition is not None:
|
|
511
|
+
return self.S_precomposition.domain()
|
|
512
|
+
else:
|
|
513
|
+
return self._action.domain()
|
|
514
|
+
|
|
515
|
+
def codomain(self):
|
|
516
|
+
return self._action.codomain()
|
|
517
|
+
|
|
518
|
+
@property
|
|
519
|
+
def left_precomposition(self):
|
|
520
|
+
"""
|
|
521
|
+
The left map to precompose with, or ``None`` if there is no
|
|
522
|
+
left precomposition map.
|
|
523
|
+
"""
|
|
524
|
+
if self._is_left:
|
|
525
|
+
return self.G_precomposition
|
|
526
|
+
else:
|
|
527
|
+
return self.S_precomposition
|
|
528
|
+
|
|
529
|
+
@property
|
|
530
|
+
def right_precomposition(self):
|
|
531
|
+
"""
|
|
532
|
+
The right map to precompose with, or ``None`` if there is no
|
|
533
|
+
right precomposition map.
|
|
534
|
+
"""
|
|
535
|
+
if self._is_left:
|
|
536
|
+
return self.S_precomposition
|
|
537
|
+
else:
|
|
538
|
+
return self.G_precomposition
|
|
539
|
+
|
|
540
|
+
def __invert__(self):
|
|
541
|
+
return PrecomposedAction(~self._action, self.left_precomposition, self.right_precomposition)
|
|
542
|
+
|
|
543
|
+
def _repr_(self):
|
|
544
|
+
s = repr(self._action)
|
|
545
|
+
if self.left_precomposition is not None:
|
|
546
|
+
s += "\nwith precomposition on left by %s" % self.left_precomposition._default_repr_()
|
|
547
|
+
if self.right_precomposition is not None:
|
|
548
|
+
s += "\nwith precomposition on right by %s" % self.right_precomposition._default_repr_()
|
|
549
|
+
return s
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
cdef class ActionEndomorphism(Morphism):
|
|
553
|
+
"""
|
|
554
|
+
The endomorphism defined by the action of one element.
|
|
555
|
+
|
|
556
|
+
EXAMPLES::
|
|
557
|
+
|
|
558
|
+
sage: A = ZZ['x'].get_action(QQ, self_on_left=False, op=operator.mul)
|
|
559
|
+
sage: A
|
|
560
|
+
Left scalar multiplication by Rational Field
|
|
561
|
+
on Univariate Polynomial Ring in x over Integer Ring
|
|
562
|
+
sage: A(1/2)
|
|
563
|
+
Action of 1/2 on Univariate Polynomial Ring in x over Integer Ring
|
|
564
|
+
under Left scalar multiplication by Rational Field on Univariate
|
|
565
|
+
Polynomial Ring in x over Integer Ring.
|
|
566
|
+
"""
|
|
567
|
+
def __init__(self, Action action, g):
|
|
568
|
+
Morphism.__init__(self, homset.Hom(action.underlying_set(),
|
|
569
|
+
action.underlying_set()))
|
|
570
|
+
self._action = action
|
|
571
|
+
self._g = g
|
|
572
|
+
|
|
573
|
+
cdef dict _extra_slots(self):
|
|
574
|
+
"""
|
|
575
|
+
Helper for pickling and copying.
|
|
576
|
+
|
|
577
|
+
TESTS::
|
|
578
|
+
|
|
579
|
+
sage: P.<x> = ZZ[]
|
|
580
|
+
sage: A = P.get_action(QQ, self_on_left=False, op=operator.mul)
|
|
581
|
+
sage: phi = A(1/2)
|
|
582
|
+
sage: psi = copy(phi) # indirect doctest
|
|
583
|
+
sage: psi
|
|
584
|
+
Action of 1/2 on Univariate Polynomial Ring in x over
|
|
585
|
+
Integer Ring under Left scalar multiplication by Rational
|
|
586
|
+
Field on Univariate Polynomial Ring in x over Integer Ring.
|
|
587
|
+
sage: psi(x) == phi(x)
|
|
588
|
+
True
|
|
589
|
+
"""
|
|
590
|
+
slots = Morphism._extra_slots(self)
|
|
591
|
+
slots['_action'] = self._action
|
|
592
|
+
slots['_g'] = self._g
|
|
593
|
+
return slots
|
|
594
|
+
|
|
595
|
+
cdef _update_slots(self, dict _slots):
|
|
596
|
+
"""
|
|
597
|
+
Helper for pickling and copying.
|
|
598
|
+
|
|
599
|
+
TESTS::
|
|
600
|
+
|
|
601
|
+
sage: P.<x> = ZZ[]
|
|
602
|
+
sage: A = P.get_action(QQ, self_on_left=False, op=operator.mul)
|
|
603
|
+
sage: phi = A(1/2)
|
|
604
|
+
sage: psi = copy(phi) # indirect doctest
|
|
605
|
+
sage: psi
|
|
606
|
+
Action of 1/2 on Univariate Polynomial Ring in x over
|
|
607
|
+
Integer Ring under Left scalar multiplication by Rational
|
|
608
|
+
Field on Univariate Polynomial Ring in x over Integer Ring.
|
|
609
|
+
sage: psi(x) == phi(x)
|
|
610
|
+
True
|
|
611
|
+
"""
|
|
612
|
+
self._action = _slots['_action']
|
|
613
|
+
self._g = _slots['_g']
|
|
614
|
+
Morphism._update_slots(self, _slots)
|
|
615
|
+
|
|
616
|
+
cpdef Element _call_(self, x):
|
|
617
|
+
return self._action._act_(self._g, x)
|
|
618
|
+
|
|
619
|
+
def _repr_(self):
|
|
620
|
+
return "Action of %s on %s under %s." % (self._g,
|
|
621
|
+
self._action.underlying_set(),
|
|
622
|
+
self._action)
|
|
623
|
+
|
|
624
|
+
def __mul__(left, right):
|
|
625
|
+
cdef ActionEndomorphism left_c, right_c
|
|
626
|
+
if isinstance(left, ActionEndomorphism) and isinstance(right, ActionEndomorphism):
|
|
627
|
+
left_c = left
|
|
628
|
+
right_c = right
|
|
629
|
+
if left_c._action is right_c._action:
|
|
630
|
+
if left_c._action._is_left:
|
|
631
|
+
return ActionEndomorphism(left_c._action, left_c._g * right_c._g)
|
|
632
|
+
else:
|
|
633
|
+
return ActionEndomorphism(left_c._action, right_c._g * left_c._g)
|
|
634
|
+
return Morphism.__mul__(left, right)
|
|
635
|
+
|
|
636
|
+
def __invert__(self):
|
|
637
|
+
inv_g = ~self._g
|
|
638
|
+
if parent(inv_g) is parent(self._g):
|
|
639
|
+
return ActionEndomorphism(self._action, inv_g)
|
|
640
|
+
else:
|
|
641
|
+
return (~self._action)(self._g)
|