Skip to content
This repository was archived by the owner on Jan 30, 2023. It is now read-only.

Commit 68d43b8

Browse files
committed
16384: implement the multiplication by integers for elements of an additive semigroup, through an action
1 parent 15658bd commit 68d43b8

File tree

2 files changed

+166
-37
lines changed

2 files changed

+166
-37
lines changed

src/sage/categories/additive_semigroups.py

Lines changed: 166 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,20 @@
22
Additive semigroups
33
"""
44
#*****************************************************************************
5-
# Copyright (C) 2013 Nicolas M. Thiery <nthiery at users.sf.net>
5+
# Copyright (C) 2013-2014 Nicolas M. Thiery <nthiery at users.sf.net>
66
#
77
# Distributed under the terms of the GNU General Public License (GPL)
88
# http://www.gnu.org/licenses/
99
#******************************************************************************
1010

11+
import operator
1112
from sage.misc.cachefunc import cached_method
1213
from sage.misc.lazy_import import LazyImport
1314
from sage.categories.category_with_axiom import CategoryWithAxiom_singleton
1415
from sage.categories.algebra_functor import AlgebrasCategory
1516
from sage.categories.additive_magmas import AdditiveMagmas
17+
from sage.categories.action import Action
18+
from sage.structure.element import generic_power
1619

1720
class AdditiveSemigroups(CategoryWithAxiom_singleton):
1821
"""
@@ -82,10 +85,139 @@ def _test_additive_associativity(self, **options):
8285
for x,y,z in tester.some_elements(CartesianProduct(S,S,S)):
8386
tester.assert_((x + y) + z == x + (y + z))
8487

88+
def __init_extra__(self):
89+
"""
90+
Register the (partial) action of `\ZZ` by multiplication on the left and on the right.
91+
92+
.. WARNING:: This is actually only an action of `\NN`.
93+
94+
EXAMPLES::
95+
96+
sage: E = CommutativeAdditiveMonoids().example()
97+
sage: e = E.an_element(); e
98+
a + 3*c + 2*b + 4*d
99+
sage: 2*e
100+
2*a + 6*c + 4*b + 8*d
101+
sage: e*3
102+
3*a + 9*c + 6*b + 12*d
103+
"""
104+
from sage.categories.modules import Modules
105+
if self in Modules:
106+
# In this case multiplication by integers is already
107+
# defined via coercion into the base ring. Since this
108+
# is likely to be faster, we don't redefine it here.
109+
return
110+
# TODO: it ought to be possible to define such an action
111+
# from just a method (or method name), without having to
112+
# create a class just for that.
113+
from sage.rings.integer_ring import ZZ
114+
left_action = IntMultAction(self, ZZ, is_left=1, op=operator.mul)
115+
right_action = IntMultAction(self, ZZ, is_left=0, op=operator.mul)
116+
self.register_action(left_action)
117+
self.register_action(right_action)
118+
119+
class ElementMethods:
120+
def __mul__(left, right):
121+
"""
122+
Return ``left*right``.
123+
124+
The calculation is delegated to the coercion model.
125+
126+
EXAMPLES::
127+
128+
sage: E = CommutativeAdditiveMonoids().example()
129+
sage: e = E.an_element(); e
130+
a + 3*c + 2*b + 4*d
131+
sage: e * 3
132+
3*a + 9*c + 6*b + 12*d
133+
134+
TESTS::
135+
136+
sage: F = CombinatorialFreeModule(QQ, ["a", "b"])
137+
sage: x = F.monomial("a")
138+
sage: x * int(2)
139+
2*B['a']
140+
"""
141+
from sage.structure.element import get_coercion_model
142+
import operator
143+
return get_coercion_model().bin_op(left, right, operator.mul)
144+
145+
def __rmul__(right, left):
146+
"""
147+
Return ``left*right`` with ``right`` in this class.
148+
149+
The calculation is delegated to the coercion model.
150+
151+
EXAMPLES::
152+
153+
sage: E = CommutativeAdditiveMonoids().example()
154+
sage: e = E.an_element(); e
155+
a + 3*c + 2*b + 4*d
156+
sage: 3 * e
157+
3*a + 9*c + 6*b + 12*d
158+
159+
TESTS::
160+
161+
sage: F = CombinatorialFreeModule(QQ, ["a", "b"])
162+
sage: x = F.monomial("a")
163+
sage: int(2) * x
164+
2*B['a']
165+
166+
.. TODO::
167+
168+
Add an example where multiplication on the left and on
169+
the right differ.
170+
"""
171+
from sage.structure.element import get_coercion_model
172+
import operator
173+
return get_coercion_model().bin_op(left, right, operator.mul)
174+
175+
def _intmul_(self, n):
176+
"""
177+
Return ``self`` multiplied by ``n``.
178+
179+
INPUT:
180+
181+
- ``n`` -- a positive integer
182+
183+
EXAMPLES::
184+
185+
sage: E = CommutativeAdditiveMonoids().example()
186+
sage: e = E.an_element(); e
187+
a + 3*c + 2*b + 4*d
188+
sage: e._intmul_(3)
189+
3*a + 9*c + 6*b + 12*d
190+
sage: e._intmul_(1)
191+
a + 3*c + 2*b + 4*d
192+
193+
sage: e._intmul_(-1)
194+
Traceback (most recent call last):
195+
...
196+
ValueError: n should be positive
197+
198+
Multiplication by `0` could be implemented in
199+
:class:`.additive_monoids.AdditiveMonoids`::
200+
201+
sage: e._intmul_(0)
202+
Traceback (most recent call last):
203+
...
204+
ValueError: n should be positive
205+
sage: e._intmul_(0) # todo: not implemented
206+
0
207+
"""
208+
n = int(n)
209+
if n <= 0:
210+
raise ValueError("n should be positive")
211+
# This should use binary powering and share the code with generic_power
212+
return sum([self for i in range(n-1)], self)
213+
85214
class Algebras(AlgebrasCategory):
86215

87216
def extra_super_categories(self):
88217
"""
218+
Implement the fact that the algebra of a semigroup is an
219+
associative (but not necessarily unital) algebra.
220+
89221
EXAMPLES::
90222
91223
sage: from sage.categories.additive_semigroups import AdditiveSemigroups
@@ -139,3 +271,36 @@ def product_on_basis(self, g1, g2):
139271
"""
140272
return self.monomial(g1 + g2)
141273

274+
class IntMultAction(Action):
275+
r"""
276+
Action of integers on an additive semigroup by multiplication.
277+
"""
278+
279+
def _call_(self, x, n):
280+
r"""
281+
Return ``self*n`` or ``n*self``.
282+
283+
INPUT::
284+
285+
- ``n`` -- an integer
286+
287+
This assumes that ``self*n == n*self``, and calls
288+
``self._int_mul_(n)``.
289+
290+
EXAMPLES::
291+
292+
sage: from sage.categories.additive_semigroups import IntMultAction
293+
sage: E = CommutativeAdditiveMonoids().example()
294+
sage: left_action = IntMultAction(E, ZZ, is_left=True)
295+
sage: right_action = IntMultAction(E, ZZ, is_left=False)
296+
sage: e = E.an_element(); e
297+
a + 3*c + 2*b + 4*d
298+
sage: left_action._call_(e, 2)
299+
2*a + 6*c + 4*b + 8*d
300+
sage: right_action._call_(3, e)
301+
3*a + 9*c + 6*b + 12*d
302+
"""
303+
if not self.is_left():
304+
x,n = n,x
305+
return x._intmul_(n)
306+

src/sage/categories/modules.py

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -410,42 +410,6 @@ def extra_super_categories(self):
410410
Graded = LazyImport('sage.categories.graded_modules', 'GradedModules')
411411
WithBasis = LazyImport('sage.categories.modules_with_basis', 'ModulesWithBasis')
412412

413-
class ParentMethods:
414-
pass
415-
416-
class ElementMethods:
417-
418-
def __mul__(left, right):
419-
"""
420-
TESTS::
421-
422-
sage: F = CombinatorialFreeModule(QQ, ["a", "b"])
423-
sage: x = F.monomial("a")
424-
sage: x * int(2)
425-
2*B['a']
426-
427-
TODO: make a better unit test once Modules().example() is implemented
428-
"""
429-
from sage.structure.element import get_coercion_model
430-
import operator
431-
return get_coercion_model().bin_op(left, right, operator.mul)
432-
433-
def __rmul__(right, left):
434-
"""
435-
TESTS::
436-
437-
sage: F = CombinatorialFreeModule(QQ, ["a", "b"])
438-
sage: x = F.monomial("a")
439-
sage: int(2) * x
440-
2*B['a']
441-
442-
TODO: make a better unit test once Modules().example() is implemented
443-
"""
444-
from sage.structure.element import get_coercion_model
445-
import operator
446-
return get_coercion_model().bin_op(left, right, operator.mul)
447-
448-
449413
class HomCategory(HomCategory):
450414
"""
451415
The category of homomorphism sets `\hom(X,Y)` for `X`, `Y` modules.

0 commit comments

Comments
 (0)