|
2 | 2 | Additive semigroups |
3 | 3 | """ |
4 | 4 | #***************************************************************************** |
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> |
6 | 6 | # |
7 | 7 | # Distributed under the terms of the GNU General Public License (GPL) |
8 | 8 | # http://www.gnu.org/licenses/ |
9 | 9 | #****************************************************************************** |
10 | 10 |
|
| 11 | +import operator |
11 | 12 | from sage.misc.cachefunc import cached_method |
12 | 13 | from sage.misc.lazy_import import LazyImport |
13 | 14 | from sage.categories.category_with_axiom import CategoryWithAxiom_singleton |
14 | 15 | from sage.categories.algebra_functor import AlgebrasCategory |
15 | 16 | from sage.categories.additive_magmas import AdditiveMagmas |
| 17 | +from sage.categories.action import Action |
| 18 | +from sage.structure.element import generic_power |
16 | 19 |
|
17 | 20 | class AdditiveSemigroups(CategoryWithAxiom_singleton): |
18 | 21 | """ |
@@ -82,10 +85,139 @@ def _test_additive_associativity(self, **options): |
82 | 85 | for x,y,z in tester.some_elements(CartesianProduct(S,S,S)): |
83 | 86 | tester.assert_((x + y) + z == x + (y + z)) |
84 | 87 |
|
| 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 | + |
85 | 214 | class Algebras(AlgebrasCategory): |
86 | 215 |
|
87 | 216 | def extra_super_categories(self): |
88 | 217 | """ |
| 218 | + Implement the fact that the algebra of a semigroup is an |
| 219 | + associative (but not necessarily unital) algebra. |
| 220 | +
|
89 | 221 | EXAMPLES:: |
90 | 222 |
|
91 | 223 | sage: from sage.categories.additive_semigroups import AdditiveSemigroups |
@@ -139,3 +271,36 @@ def product_on_basis(self, g1, g2): |
139 | 271 | """ |
140 | 272 | return self.monomial(g1 + g2) |
141 | 273 |
|
| 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 | + |
0 commit comments