Ticket #9648: trac_9648_modulemorphism_codomain_extension-cs.patch

File trac_9648_modulemorphism_codomain_extension-cs.patch, 11.8 KB (added by stumpc5, 11 years ago)
  • sage/categories/modules_with_basis.py

    # HG changeset patch
    # User Christian Stump <christian.stump@univie.ac.at>
    # Date 1280514062 14400
    # Node ID 76441d22e8cb279d306245aea44fd972783aa9a4
    # Parent 2aaa49c742960801c5ac3408f8cb29923d105acc
    #9648: New feature: ModulesWithBasis allows module_morphism's to a wider class of codomains
    
    diff --git a/sage/categories/modules_with_basis.py b/sage/categories/modules_with_basis.py
    a b r""" 
    22Modules With Basis
    33
    44AUTHORS:
    5 - Nicolas Thiery (2008): initial revision
     5- Nicolas M. Thiery (2008-2010): initial revision
    66- Jason Bandlow & Florent Hivert (2010): Triangular Morphisms
    7 
     7- Christian Stump (2010): #9648: module_morphism's to a wider class of codomains
    88"""
    99#*****************************************************************************
    1010#  Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) <Teresa.Gomez-Diaz@univ-mlv.fr>
    from sage.misc.lazy_attribute import laz 
    1818from sage.misc.cachefunc import cached_method
    1919from sage.misc.misc import attrcall, deprecated_function_alias
    2020from sage.misc.sage_itertools import max_cmp, min_cmp
    21 from sage.categories.all import Modules, Fields, HomCategory, Homset
     21from sage.categories.all import Sets, CommutativeAdditiveSemigroups, Modules, HomCategory, Homset
    2222from sage.categories.cartesian_product import CartesianProductsCategory
    2323from sage.categories.tensor import tensor, TensorProductsCategory
    2424from sage.categories.dual import DualObjectsCategory
    class ModulesWithBasis(Category_over_bas 
    188188
    189189            INPUT:
    190190
    191              - ``self`` - a parent `X` in ``ModulesWithBasis(R)``, with basis `x`
     191             - ``self`` -- a parent `X` in ``ModulesWithBasis(R)``, with basis `x`
    192192               indexed by `I`
    193              - ``codomain`` - the codomain `Y` of `f`: defaults to ``f.codomain()``
     193             - ``codomain`` -- the codomain `Y` of `f`: defaults to ``f.codomain()``
    194194               if the later is defined
    195              - ``zero`` - the zero of the codomain; defaults to
    196                ``codomain.zero()`` or 0 if codomain is not specified
    197              - ``position`` - a non negative integer; defaults to 0
    198              - ``on_basis`` - a function `f` which accepts elements of `I`
    199                as position-th argument and returns  elements of `Y`
    200              - ``diagonal`` - a function `d` from `I` to `R`
    201              - ``triangular`` - "upper" or "lower" or None
     195             - ``zero`` -- the zero of the codomain; defaults to ``codomain.zero()``
     196               Can be used (with care) to define affine maps
     197             - ``position`` -- a non negative integer; defaults to 0
     198             - ``on_basis`` -- a function `f` which accepts elements of `I`
     199               as position-th argument and returns elements of `Y`
     200             - ``diagonal`` -- a function `d` from `I` to `R`
     201             - ``triangular`` -- "upper" or "lower" or None
    202202                 - "upper": if the `leading_support()`  of the image of `F(i)` is `i`, or
    203203                 - "lower": if the `trailing_support()` of the image of `F(i)` is `i`.
    204              - ``category`` - a category. By default, this is
     204             - ``category`` -- a category. By default, this is
    205205               ``ModulesWithBasis(R)`` if `Y` is in this category, and
    206206               otherwise this lets `\hom(X,Y)` decide
    207207
    class ModulesWithBasis(Category_over_bas 
    223223                Generic morphism:
    224224                From: X
    225225                To:   Y
    226                 sage: x = X.basis()
     226                sage: phi.category_for()
     227                Category of modules with basis over Rational Field
     228                sage: x = X.basis(); y = Y.basis()
    227229                sage: phi(x[1] + x[3])
    228230                B[1] + 2*B[2] + B[3] + 2*B[4]
    229231
     232            With the ``zero`` argument, one can define affine morphisms:
     233
     234                sage: phi = X.module_morphism(lambda i: Y.monomial(i) + 2*Y.monomial(i+1), codomain = Y, zero = 10*y[1])
     235                sage: phi(x[1] + x[3])
     236                11*B[1] + 2*B[2] + B[3] + 2*B[4]
     237                sage: phi.category_for()
     238                Category of sets
     239
     240            One can construct morphisms with the base ring as codomain::
     241
     242                sage: X = CombinatorialFreeModule(ZZ,[1,-1])
     243                sage: phi = X.module_morphism( on_basis=lambda i: i, codomain=ZZ )
     244                sage: phi( 2 * X.monomial(1) + 3 * X.monomial(-1) )
     245                -1
     246                sage: phi.category_for()
     247                Category of commutative additive semigroups
     248                sage: phi.category_for() # todo: not implemented (ZZ is currently not in Modules(ZZ))
     249                Category of modules over Integer Ring
     250
     251            Or more generaly any ring admitting a coercion map from the base ring:
     252
     253                sage: phi = X.module_morphism(on_basis= lambda i: i, codomain=RR )
     254                sage: phi( 2 * X.monomial(1) + 3 * X.monomial(-1) )
     255                -1.00000000000000
     256                sage: phi.category_for()
     257                Category of commutative additive semigroups
     258                sage: phi.category_for() # todo: not implemented (RR is currently not in Modules(ZZ))
     259                Category of modules over Integer Ring
     260
     261                sage: phi = X.module_morphism(on_basis= lambda i: i, codomain=Zmod(4) )
     262                sage: phi( 2 * X.monomial(1) + 3 * X.monomial(-1) )
     263                3
     264
     265                sage: phi = Y.module_morphism(on_basis= lambda i: i, codomain=Zmod(4) )
     266                Traceback (most recent call last):
     267                ...
     268                AssertionError: codomain should be a module over base_ring
     269
     270            On can also define module morphism betweem free modules
     271            over different base rings; here we implement the natural
     272            map from `X = \RR^2` to `Y = \CC`::
     273
     274                sage: X = CombinatorialFreeModule(RR,['x','y'])
     275                sage: Y = CombinatorialFreeModule(CC,['z'])
     276                sage: x = X.monomial('x')
     277                sage: y = X.monomial('y')
     278                sage: z = Y.monomial('z')
     279                sage: def on_basis( a ):
     280                ...       if a == 'x':
     281                ...           return CC(1) * z
     282                ...       elif a == 'y':
     283                ...           return CC(I) * z
     284                sage: phi = X.module_morphism( on_basis=on_basis, codomain=Y )
     285                sage: v = 3 * x + 2 * y; v
     286                3.00000000000000*B['x'] + 2.00000000000000*B['y']
     287                sage: phi(v)
     288                (3.00000000000000+2.00000000000000*I)*B['z']
     289                sage: phi.category_for()
     290                Category of commutative additive semigroups
     291                sage: phi.category_for() # todo: not implemented (CC is currently not in Modules(RR)!)
     292                Category of vector spaces over Real Field with 53 bits of precision
     293
     294                sage: Y = CombinatorialFreeModule(CC['q'],['z'])
     295                sage: z = Y.monomial('z')
     296                sage: phi = X.module_morphism( on_basis=on_basis, codomain=Y )
     297                sage: phi(v)
     298                (3.00000000000000+2.00000000000000*I)*B['z']
     299
     300            Of course, there should be a coercion between the
     301            respective base rings of the domain and the codomain for
     302            this to be meaningful::
     303
     304                sage: Y = CombinatorialFreeModule(QQ,['z'])
     305                sage: phi = X.module_morphism( on_basis=on_basis, codomain=Y )
     306                Traceback (most recent call last):
     307                ...
     308                AssertionError: codomain should be a module over base_ring
     309
     310                sage: Y = CombinatorialFreeModule(RR['q'],['z'])
     311                sage: phi = Y.module_morphism( on_basis=on_basis, codomain=X )
     312                Traceback (most recent call last):
     313                ...
     314                AssertionError: codomain should be a module over base_ring
     315
     316
    230317            With the ``diagonal`` argument, this returns the module morphism `g` such that:
    231318
    232319                `g(x_i) = d(i) y_i`
    class ModuleMorphismByLinearity(Morphism 
    10221109         - ``codomain`` -- a parent in Modules(...); defaults to f.codomain() if the later is defined
    10231110         - ``position`` -- a non negative integer; defaults to 0
    10241111         - ``on_basis`` -- a function which accepts indices of the basis of domain as position-th argument (optional)
    1025          - ``zero`` -- the zero of the codomain; defaults to codomain.zero() or 0 if codomain is not specified
     1112         - ``zero`` -- the zero of the codomain; defaults to ``codomain.zero()``
    10261113
    10271114        ``on_basis`` may alternatively be provided in derived classes by implementing or setting ``_on_basis``.
    10281115
    class ModuleMorphismByLinearity(Morphism 
    10501137        by making sure to create ``phi`` through its parent.
    10511138
    10521139        """
     1140        # Might want to assert that domain is a module with basis
     1141        base_ring = domain.base_ring()
     1142
    10531143        if codomain is None and hasattr(on_basis, 'codomain'):
    10541144            codomain = on_basis.codomain()
     1145        assert codomain is not None
     1146        assert hasattr( codomain, 'base_ring' )
     1147        # codomain should be a module over base_ring
     1148        # The natural test would be ``codomains in Modules(base_ring)``
     1149        # But this is not properly implemented yet:
     1150        #     sage: CC in Modules(QQ)
     1151        #     False
     1152        #     sage: QQ in Modules(QQ)
     1153        #     False
     1154        #     sage: CC[x] in Modules(QQ)
     1155        #     False
     1156        # The test below is a bit more restrictive
     1157        assert codomain.base_ring().has_coerce_map_from(base_ring) or \
     1158            codomain.has_coerce_map_from(base_ring),                  \
     1159            "codomain should be a module over base_ring"
     1160
    10551161        if zero is None:
    1056             if codomain is not None:
    1057                 zero = codomain.zero()
     1162            zero = codomain.zero()
     1163        self._zero = zero
     1164
     1165        self._is_module_with_basis_over_same_base_ring = \
     1166            codomain in ModulesWithBasis( base_ring ) and zero == codomain.zero()
     1167
     1168        if category is None:
     1169            if self._is_module_with_basis_over_same_base_ring:
     1170                category = ModulesWithBasis(base_ring)
     1171            elif zero == codomain.zero():
     1172                if codomain in Modules(base_ring):
     1173                    category = Modules(base_ring)
     1174                else:
     1175                    # QQ is not in Modules(QQ)!
     1176                    category = CommutativeAdditiveSemigroups()
    10581177            else:
    1059                 zero = 0
    1060         assert domain.base_ring()    == codomain.base_ring()
    1061         if category is None and codomain is not None and codomain.category().is_subcategory(ModulesWithBasis(domain.base_ring())):
    1062             category = ModulesWithBasis(domain.base_ring())
    1063         assert codomain is not None
     1178                category = Sets()
     1179
    10641180        Morphism.__init__(self, Hom(domain, codomain, category = category))
    1065         self._zero = zero
     1181
     1182
    10661183        self._position = position
    10671184        if on_basis is not None:
    10681185            self._on_basis = on_basis
    class ModuleMorphismByLinearity(Morphism 
    11291246        after = args[self._position+1:len(args)]
    11301247        x = args[self._position]
    11311248        assert(x.parent() is self.domain())
    1132         return sum([self._on_basis(*(before+(index,)+after))._lmul_(coeff) for (index, coeff) in args[self._position]], self._zero)
     1249
     1250        if self._is_module_with_basis_over_same_base_ring:
     1251            return self.codomain().sum(self._on_basis(*(before+(index,)+after))._lmul_(coeff) for (index, coeff) in args[self._position])
     1252        else:
     1253            return sum(( coeff * self._on_basis(*(before+(index,)+after)) for (index, coeff) in args[self._position]), self._zero)
    11331254
    11341255    # As per the specs of Map, we should in fact implement _call_.
    11351256    # However we currently need to abuse Map.__call__ (which strict