Ticket #11556: trac_11556-linear-transformations-v4.patch

File trac_11556-linear-transformations-v4.patch, 87.0 KB (added by rbeezer, 10 years ago)
  • doc/en/reference/modules.rst

    # HG changeset patch
    # User Rob Beezer <beezer@ups.edu>
    # Date 1311723732 25200
    # Node ID d00bdedc8a14d439a30d1d6bec44bf88be1ed1df
    # Parent  8dad877c0f47c2463c8cc7cfa2fe1418a0ef2c9d
    11556: linear transformations from free module morphisms
    
    diff --git a/doc/en/reference/modules.rst b/doc/en/reference/modules.rst
    a b  
    1414   sage/modules/real_double_vector
    1515   sage/modules/vector_callable_symbolic_dense   
    1616
     17   sage/modules/vector_space_homspace
     18   sage/modules/vector_space_morphism
     19
    1720   sage/modules/free_module_homspace
    1821   sage/modules/free_module_morphism
    19    
     22
    2023   sage/modules/matrix_morphism
    2124
    2225   sage/modules/fg_pid/fgp_module
  • sage/categories/homset.py

    diff --git a/sage/categories/homset.py b/sage/categories/homset.py
    a b  
    5858   
    5959        sage: V = VectorSpace(QQ,3)
    6060        sage: Hom(V, V)
    61         Set of Morphisms from Vector space of dimension 3 over Rational
    62         Field to Vector space of dimension 3 over Rational Field in
    63         Category of vector spaces over Rational Field
     61        Set of Morphisms (Linear Transformations) from
     62        Vector space of dimension 3 over Rational Field to
     63        Vector space of dimension 3 over Rational Field
    6464        sage: G = AlternatingGroup(3)
    6565        sage: Hom(G, G)
    6666        Set of Morphisms from AlternatingGroup(3) to AlternatingGroup(3) in Category of finite permutation groups
     
    188188   
    189189        sage: V = VectorSpace(QQ, 3)
    190190        sage: End(V)
    191         Set of Morphisms from Vector space of dimension 3 over Rational
    192         Field to Vector space of dimension 3 over Rational Field in
    193         Category of vector spaces over Rational Field
    194    
     191        Set of Morphisms (Linear Transformations) from
     192        Vector space of dimension 3 over Rational Field to
     193        Vector space of dimension 3 over Rational Field
     194
    195195    ::
    196196   
    197197        sage: G = AlternatingGroup(3)
     
    246246        True
    247247    """
    248248    def __init__(self, X, Y, category=None, base = None, check=True):
    249         """
     249        r"""
    250250        TESTS::
     251
    251252            sage: X = ZZ['x']; X.rename("X")
    252253            sage: Y = ZZ['y']; Y.rename("Y")
    253254            sage: class MyHomset(Homset):
     
    522523# Really needed???
    523524class HomsetWithBase(Homset):
    524525    def __init__(self, X, Y, category=None, check=True, base=None):
    525         """
     526        r"""
    526527        TESTS::
     528       
    527529            sage: X = ZZ['x']; X.rename("X")
    528530            sage: Y = ZZ['y']; Y.rename("Y")
    529531            sage: class MyHomset(HomsetWithBase):
  • sage/categories/map.pyx

    diff --git a/sage/categories/map.pyx b/sage/categories/map.pyx
    a b  
    13931393
    13941394            sage: V1 = QQ^2
    13951395            sage: V2 = QQ^3
    1396             sage: phi1 = (QQ^1).hom(Matrix([[1],[1]]),V1)
    1397             sage: phi2 = V1.hom(Matrix([[1,2],[3,4],[5,6]]),V2)
     1396            sage: phi1 = (QQ^1).hom(Matrix([[1, 1]]),V1)
     1397            sage: phi2 = V1.hom(Matrix([[1,3,5], [2,4,6]]),V2)
    13981398
    13991399        If both constituents are injective, the composition is injective::
    14001400
     
    14061406        If it can not be determined whether the composition is injective,
    14071407        an error is raised::
    14081408
    1409             sage: psi1 = V2.hom(Matrix([[1,2,3],[4,5,6]]),V1)
     1409            sage: psi1 = V2.hom(Matrix([[1,4],[2,5],[3,6]]),V1)
    14101410            sage: c2 = FormalCompositeMap(Hom(V1,V1,phi2.category_for()),phi2,psi1)
    14111411            sage: c2.is_injective()
    14121412            Traceback (most recent call last):
     
    14161416        If the first map is surjective and the second map is not injective,
    14171417        then the composition is not injective::
    14181418
    1419             sage: psi2 = V1.hom([1,1],QQ^1)
     1419            sage: psi2 = V1.hom([[1],[1]],QQ^1)
    14201420            sage: c3 = FormalCompositeMap(Hom(V2,QQ^1,phi2.category_for()),psi2,psi1)
    14211421            sage: c3.is_injective()
    14221422            False
     
    14471447
    14481448        If both maps are surjective, the composition is surjective::
    14491449
    1450             sage: phi32 = V3.hom(Matrix([[1,2,3],[4,5,6]]),V2)
    1451             sage: phi21 = V2.hom(Matrix([[1,1]]),V1)
     1450            sage: phi32 = V3.hom(Matrix([[1,2],[3,4],[5,6]]),V2)
     1451            sage: phi21 = V2.hom(Matrix([[1],[1]]),V1)
    14521452            sage: c_phi = FormalCompositeMap(Hom(V3,V1,phi32.category_for()),phi32,phi21)
    14531453            sage: c_phi.is_surjective()
    14541454            True
     
    14561456        If the second map is not surjective, the composition is not
    14571457        surjective::
    14581458
    1459             sage: FormalCompositeMap(Hom(V3,V1,phi32.category_for()),phi32,V2.hom(Matrix([[0,0]]),V1)).is_surjective()
     1459            sage: FormalCompositeMap(Hom(V3,V1,phi32.category_for()),phi32,V2.hom(Matrix([[0],[0]]),V1)).is_surjective()
    14601460            False
    14611461
    14621462        If the second map is an isomorphism and the first map is not
    14631463        surjective, then the composition is not surjective::
    14641464
    1465             sage: FormalCompositeMap(Hom(V2,V1,phi32.category_for()),V2.hom(Matrix([[0,0]]),V1),V1.hom(Matrix([[1]]),V1)).is_surjective()
     1465            sage: FormalCompositeMap(Hom(V2,V1,phi32.category_for()),V2.hom(Matrix([[0],[0]]),V1),V1.hom(Matrix([[1]]),V1)).is_surjective()
    14661466            False
    14671467
    14681468        Otherwise, surjectivity of the composition can not be determined::
    14691469
    1470             sage: FormalCompositeMap(Hom(V2,V1,phi32.category_for()),V2.hom(Matrix([[1,1],[1,1]]),V2),V2.hom(Matrix([[1,1]]),V1)).is_surjective()
     1470            sage: FormalCompositeMap(Hom(V2,V1,phi32.category_for()),V2.hom(Matrix([[1,1],[1,1]]),V2),V2.hom(Matrix([[1],[1]]),V1)).is_surjective()
    14711471            Traceback (most recent call last):
    14721472            ...
    14731473            NotImplementedError: Not enough information to deduce surjectivity.
  • sage/modules/all.py

    diff --git a/sage/modules/all.py b/sage/modules/all.py
    a b  
    2929
    3030import vector_callable_symbolic_dense
    3131
     32from vector_space_homspace import is_VectorSpaceHomspace
     33
     34from vector_space_morphism import is_VectorSpaceMorphism, linear_transformation
     35
    3236import vector_symbolic_dense
  • sage/modules/free_module.py

    diff --git a/sage/modules/free_module.py b/sage/modules/free_module.py
    a b  
    604604
    605605    # FIXME: what's the level of generality of FreeModuleHomspace?
    606606    # Should there be a category for free modules accepting it as hom space?
     607    # See similar method for FreeModule_generic_field class
    607608    def _Hom_(self, Y, category):
    608609        from free_module_homspace import FreeModuleHomspace
    609610        return FreeModuleHomspace(self, Y, category)
     
    28962897            raise TypeError, "The base_field (=%s) must be a field"%base_field
    28972898        FreeModule_generic_pid.__init__(self, base_ring, dimension, degree, sparse=sparse)
    28982899
     2900    def _Hom_(self, Y, category):
     2901        r"""
     2902        Returns a homspace whose morphisms have this vector space as domain.
     2903
     2904        This is called by the general methods such as
     2905        :meth:`sage.structure.parent.Parent.Hom` and
     2906        :meth:`sage.structure.parent_base.ParentWithBase.Hom`.
     2907
     2908        INPUT:
     2909
     2910        - ``Y`` - a free module (or vector space) that will
     2911          be the codomain of the morphisms in returned homspace
     2912        - ``category`` - the category for the homspace
     2913
     2914        OUTPUT:
     2915
     2916        If ``Y`` is a free module over a field, in other words, a vector space,
     2917        then this returns a space of homomorphisms between vector spaces,
     2918        in other words a space of linear transformations.
     2919
     2920        If ``Y`` is a free module that is not a vector space, then
     2921        the returned space contains homomorphisms between free modules.
     2922
     2923        EXAMPLES::
     2924
     2925            sage: V = QQ^2
     2926            sage: W = QQ^3
     2927            sage: H = V._Hom_(W, category=None)
     2928            sage: type(H)
     2929            <class 'sage.modules.vector_space_homspace.VectorSpaceHomspace_with_category'>
     2930            sage: H
     2931            Set of Morphisms (Linear Transformations) from Vector space of dimension 2 over Rational Field to Vector space of dimension 3 over Rational Field
     2932
     2933            sage: V = QQ^2
     2934            sage: W = ZZ^3
     2935            sage: H = V._Hom_(W, category=None)
     2936            sage: type(H)
     2937            <class 'sage.modules.free_module_homspace.FreeModuleHomspace_with_category'>
     2938            sage: H
     2939            Set of Morphisms from Vector space of dimension 2 over Rational Field to Ambient free module of rank 3 over the principal ideal domain Integer Ring in Category of vector spaces over Rational Field
     2940        """
     2941        if Y.base_ring().is_field():
     2942            import vector_space_homspace
     2943            return vector_space_homspace.VectorSpaceHomspace(self, Y, category)
     2944        import free_module_homspace
     2945        return free_module_homspace.FreeModuleHomspace(self, Y, category)
     2946
    28992947    def scale(self, other):
    29002948        """
    29012949        Return the product of self by the number other, which is the module
  • sage/modules/free_module_homspace.py

    diff --git a/sage/modules/free_module_homspace.py b/sage/modules/free_module_homspace.py
    a b  
    1818    Domain: Ambient free module of rank 2 over the principal ideal domain ...
    1919    Codomain: Ambient free module of rank 2 over the principal ideal domain ...
    2020
    21 We create `\mathrm{Hom}(\QQ^3, \QQ^2)` and
     21We create `\mathrm{Hom}(\ZZ^3, \ZZ^2)` and
    2222compute a basis.
    2323
    2424::
    2525
    26     sage: V3 = VectorSpace(RationalField(),3)
    27     sage: V2 = VectorSpace(RationalField(),2)
     26    sage: V3 = FreeModule(IntegerRing(),3)
     27    sage: V2 = FreeModule(IntegerRing(),2)
    2828    sage: H = Hom(V3,V2)
    2929    sage: H
    30     Set of Morphisms from Vector space of dimension 3 over Rational Field
    31     to Vector space of dimension 2 over Rational Field in Category of
    32     vector spaces over Rational Field
     30    Set of Morphisms from Ambient free module of rank 3
     31    over the principal ideal domain Integer Ring to
     32    Ambient free module of rank 2
     33    over the principal ideal domain Integer Ring
     34    in Category of modules with basis over Integer Ring
    3335    sage: B = H.basis()
    3436    sage: len(B)
    3537    6
     
    4749
    4850See trac 5886::
    4951
    50     sage: V = (QQ^2).span_of_basis([[1,2],[3,4]])
     52    sage: V = (ZZ^2).span_of_basis([[1,2],[3,4]])
    5153    sage: V.hom([V.0, V.1])
    5254    Free module morphism defined by the matrix
    5355    [1 0]
     
    7981from matrix_morphism import MatrixMorphism
    8082
    8183def is_FreeModuleHomspace(x):
    82     """
    83     Return True if x is a Free module homspace.
     84    r"""
     85    Return ``True`` if ``x`` is a free module homspace.
    8486
    85     EXAMPLES::
     87    EXAMPLES:
    8688
    87         sage: H = Hom(QQ^3, QQ^2)
     89    Notice that every vector space is a field, but when we construct a set of
     90    morphisms between two vector spaces, it is a ``VectorSpaceHomspace``,
     91    which qualifies as a ``FreeModuleHomspace``, since the former is
     92    special case of the latter.
     93
     94        sage: H = Hom(ZZ^3, ZZ^2)
     95        sage: type(H)
     96        <class 'sage.modules.free_module_homspace.FreeModuleHomspace_with_category'>
    8897        sage: sage.modules.free_module_homspace.is_FreeModuleHomspace(H)
    8998        True
    90         sage: sage.modules.free_module_homspace.is_FreeModuleHomspace(2)
     99
     100        sage: K = Hom(QQ^3, ZZ^2)
     101        sage: type(K)
     102        <class 'sage.modules.free_module_homspace.FreeModuleHomspace_with_category'>
     103        sage: sage.modules.free_module_homspace.is_FreeModuleHomspace(K)
     104        True
     105
     106        sage: L = Hom(ZZ^3, QQ^2)
     107        sage: type(L)
     108        <class 'sage.modules.free_module_homspace.FreeModuleHomspace_with_category'>
     109        sage: sage.modules.free_module_homspace.is_FreeModuleHomspace(L)
     110        True
     111
     112        sage: P = Hom(QQ^3, QQ^2)
     113        sage: type(P)
     114        <class 'sage.modules.vector_space_homspace.VectorSpaceHomspace_with_category'>
     115        sage: sage.modules.free_module_homspace.is_FreeModuleHomspace(P)
     116        True
     117
     118        sage: sage.modules.free_module_homspace.is_FreeModuleHomspace('junk')
    91119        False
    92120    """
    93121    return isinstance(x, FreeModuleHomspace)
    94122
    95123class FreeModuleHomspace(sage.categories.homset.HomsetWithBase):
    96124    def __call__(self, A, check=True):
    97         """
     125        r"""
    98126        INPUT:
    99127
    100128        - A -- either a matrix or a list/tuple of images of generators,
     
    109137
    110138        EXAMPLES::
    111139
    112             sage: V = (QQ^3).span_of_basis([[1,1,0],[1,0,2]])
     140            sage: V = (ZZ^3).span_of_basis([[1,1,0],[1,0,2]])
    113141            sage: H = V.Hom(V); H
    114142            Set of Morphisms from ...
    115143            sage: H([V.0,V.1])                    # indirect doctest
     
    195223
    196224        EXAMPLES::
    197225
    198             sage: H = Hom(QQ^2, QQ^1)
     226            sage: H = Hom(ZZ^2, ZZ^1)
    199227            sage: H.basis()
    200228            (Free module morphism defined by the matrix
    201229            [1]
    202230            [0]
    203             Domain: Vector space of dimension 2 over Rational Field
    204             Codomain: Vector space of dimension 1 over Rational Field,
    205              Free module morphism defined by the matrix
     231            Domain: Ambient free module of rank 2 over the principal ideal domain ...
     232            Codomain: Ambient free module of rank 1 over the principal ideal domain ..., Free module morphism defined by the matrix
    206233            [0]
    207234            [1]
    208             Domain: Vector space of dimension 2 over Rational Field
    209             Codomain: Vector space of dimension 1 over Rational Field)
     235            Domain: Ambient free module of rank 2 over the principal ideal domain ...
     236            Codomain: Ambient free module of rank 1 over the principal ideal domain ...)
    210237        """
    211238        try:
    212239            return self.__basis
     
    217244            return self.__basis
    218245       
    219246    def identity(self):
    220        r"""
    221        Return identity morphism in an endomorphism ring.
     247        r"""
     248        Return identity morphism in an endomorphism ring.
    222249       
    223        EXAMPLE::
     250        EXAMPLE::
    224251       
    225            sage: V=VectorSpace(QQ,5)
    226            sage: H=V.Hom(V)
    227            sage: H.identity()
    228            Free module morphism defined by the matrix
    229            [1 0 0 0 0]
    230            [0 1 0 0 0]
    231            [0 0 1 0 0]
    232            [0 0 0 1 0]
    233            [0 0 0 0 1]
    234            Domain: Vector space of dimension 5 over Rational Field
    235            Codomain: Vector space of dimension 5 over Rational Field
    236        """
    237        if self.is_endomorphism_set():
    238            return self(matrix.identity_matrix(self.base_ring(),self.domain().rank()))
    239        else:
    240            raise TypeError, "Identity map only defined for endomorphisms. Try natural_map() instead."
    241    
    242        
     252            sage: V=FreeModule(ZZ,5)
     253            sage: H=V.Hom(V)
     254            sage: H.identity()
     255            Free module morphism defined by the matrix
     256            [1 0 0 0 0]
     257            [0 1 0 0 0]
     258            [0 0 1 0 0]
     259            [0 0 0 1 0]
     260            [0 0 0 0 1]
     261            Domain: Ambient free module of rank 5 over the principal ideal domain ...
     262            Codomain: Ambient free module of rank 5 over the principal ideal domain ...
     263        """
     264        if self.is_endomorphism_set():
     265            return self(matrix.identity_matrix(self.base_ring(),self.domain().rank()))
     266        else:
     267            raise TypeError, "Identity map only defined for endomorphisms. Try natural_map() instead."
    243268
  • sage/modules/free_module_morphism.py

    diff --git a/sage/modules/free_module_morphism.py b/sage/modules/free_module_morphism.py
    a b  
    7171       
    7272        EXAMPLES::
    7373       
    74             sage: V = QQ^3; W = span([[1,2,3],[-1,2,5/3]], QQ)
    75             sage: phi = V.hom(matrix(QQ,3,[1..9]))
     74            sage: V = ZZ^3; W = span([[1,2,3],[-1,2,8]], ZZ)
     75            sage: phi = V.hom(matrix(ZZ,3,[1..9]))
    7676            sage: type(phi)
    7777            <class 'sage.modules.free_module_morphism.FreeModuleMorphism'>
    7878        """
     
    148148       
    149149        EXAMPLES::
    150150       
    151             sage: V = QQ^3; W = span([[1,2,3],[-1,2,5/3]], QQ)
    152             sage: phi = V.hom(matrix(QQ,3,[1..9]))
    153             sage: phi._repr_()       
    154             'Free module morphism defined by the matrix\n[1 2 3]\n[4 5 6]\n[7 8 9]\nDomain: Vector space of dimension 3 over Rational Field\nCodomain: Vector space of dimension 3 over Rational Field'
     151            sage: V = ZZ^3; W = span([[1,2,3],[-1,2,8]], ZZ)
     152            sage: phi = V.hom(matrix(ZZ,3,[1..9]))
     153            sage: phi._repr_()
     154            'Free module morphism defined by the matrix\n[1 2 3]\n[4 5 6]\n[7 8 9]\nDomain: Ambient free module of rank 3 over the principal ideal domain ...\nCodomain: Ambient free module of rank 3 over the principal ideal domain ...'
    155155        """
    156156        if max(self.matrix().nrows(),self.matrix().ncols()) > 5:
    157157            mat = "(not printing %s x %s matrix)"%(self.matrix().nrows(), self.matrix().ncols())
     
    178178            sage: h.change_ring(QQ).base_ring()
    179179            Rational Field
    180180            sage: f = h.change_ring(QQ); f
    181             Free module morphism defined by the matrix
     181            Vector space morphism represented by the matrix:
    182182            [-3 -3]
    183183            [-3 -3]
    184184            Domain: Vector space of degree 3 and dimension 2 over Rational Field
    185             Basis ...
     185            Basis matrix:
     186            [0 1 0]
     187            [0 0 1]
    186188            Codomain: Vector space of degree 2 and dimension 2 over Rational Field
    187             Basis ...
     189            Basis matrix:
     190            [1 0]
     191            [0 1]
    188192            sage: f = h.change_ring(GF(7)); f
    189             Free module morphism defined by the matrix
     193            Vector space morphism represented by the matrix:
    190194            [4 4]
    191195            [4 4]
    192             Domain: Vector space of degree 3 and dimension 2 over Finite Field of ...
    193             Codomain: Vector space of degree 2 and dimension 2 over Finite Field of ...
     196            Domain: Vector space of degree 3 and dimension 2 over Finite Field of size 7
     197            Basis matrix:
     198            [0 1 0]
     199            [0 0 1]
     200            Codomain: Vector space of degree 2 and dimension 2 over Finite Field of size 7
     201            Basis matrix:
     202            [1 0]
     203            [0 1]
    194204        """
    195205        D = self.domain().change_ring(R)
    196206        C = self.codomain().change_ring(R)
     
    433443    def eigenvectors(self,extend=True):
    434444        """
    435445        Computes the subspace of eigenvectors of a given eigenvalue.
    436        
     446
    437447        INPUT:
    438        
     448
    439449        - ``extend`` -- boolean (default: True) decides if base field
    440450          extensions should be considered or not.
    441        
     451
    442452        OUTPUT:
    443        
     453
    444454        A sequence of tuples. Each tuple contains an eigenvalue, a sequence
    445455        with a basis of the corresponding subspace of eigenvectors, and the
    446456        algebraic multiplicity of the eigenvalue.
    447        
    448         EXAMPLES:
    449        
    450        
    451         ::
    452            
     457
     458        EXAMPLES::
     459
    453460            sage: V=(QQ^4).subspace([[0,2,1,4],[1,2,5,0],[1,1,1,1]])
    454             sage: H=(V.Hom(V))([[0,1,0],[-1,0,0],[0,0,3]])
     461            sage: H=(V.Hom(V))(matrix(QQ, [[0,1,0],[-1,0,0],[0,0,3]]))
    455462            sage: H.eigenvectors()
    456463            [(3, [
    457464            (0, 0, 1, -6/7)
     
    464471            [(3, [
    465472            (0, 0, 1, -6/7)
    466473            ], 1)]
    467             sage: H1=(V.Hom(V))([[2,1,0],[0,2,0],[0,0,3]])
     474            sage: H1=(V.Hom(V))(matrix(QQ, [[2,1,0],[0,2,0],[0,0,3]]))
    468475            sage: H1.eigenvectors()
    469476            [(3, [
    470477            (0, 0, 1, -6/7)
     
    477484            ], 1), (2, [
    478485            (0, 1, 0, 17/7)
    479486            ], 2)]
    480 
    481        
    482487        """
    483488        if self.base_ring().is_field():
    484489            if self.is_endomorphism():
     
    488493                    V=self.domain().base_extend(i[0].parent())
    489494                    svectors=Sequence(map(lambda j: V(j * V.basis_matrix()),i[1]), cr=True)
    490495                    resu.append((i[0],svectors,i[2]))
    491                 return resu                 
     496                return resu
    492497            else:
    493498                raise TypeError, "not an endomorphism"
    494499        else:
    495500            raise NotImplementedError, "module must be a vector space"
    496    
    497        
    498     def minpoly(self,var='x'):
    499         """
     501
     502    def minimal_polynomial(self,var='x'):
     503        r"""
    500504        Computes the minimal polynomial.
    501        
     505
     506        ``minpoly()`` and ``minimal_polynomial()`` are the same method.
     507
    502508        INPUT:
    503        
     509
    504510        - ``var`` - string (default: 'x') a variable name
    505        
     511
    506512        OUTPUT:
    507        
     513
    508514        polynomial in var - the minimal polynomial of the endomorphism.
    509        
     515
    510516        EXAMPLES:
    511        
    512         Compute the minimal polynomial, and check it
    513        
    514         ::
    515        
    516             sage: V=GF(7)^3     
     517
     518        Compute the minimal polynomial, and check it. ::
     519
     520            sage: V=GF(7)^3
    517521            sage: H=V.Hom(V)([[0,1,2],[-1,0,3],[2,4,1]])
    518522            sage: H
    519             Free module morphism defined by the matrix
     523            Vector space morphism represented by the matrix:
    520524            [0 1 2]
    521525            [6 0 3]
    522526            [2 4 1]
    523527            Domain: Vector space of dimension 3 over Finite Field of size 7
    524528            Codomain: Vector space of dimension 3 over Finite Field of size 7
     529
    525530            sage: H.minpoly()
    526531            x^3 + 6*x^2 + 6*x + 1
    527             sage: H^3+6*H^2+6*H+1                 
    528             Free module morphism defined by the matrix
     532
     533            sage: H.minimal_polynomial()
     534            x^3 + 6*x^2 + 6*x + 1
     535
     536            sage: H^3 + (H^2)*6 + H*6 + 1
     537            Vector space morphism represented by the matrix:
    529538            [0 0 0]
    530539            [0 0 0]
    531540            [0 0 0]
    532541            Domain: Vector space of dimension 3 over Finite Field of size 7
    533542            Codomain: Vector space of dimension 3 over Finite Field of size 7
    534 
    535543        """
    536544        if self.is_endomorphism():
    537545            return self.matrix().minpoly(var)
    538546        else:
    539547            raise TypeError, "not an endomorphism"
    540548
     549    minpoly = minimal_polynomial
     550 No newline at end of file
  • sage/modules/matrix_morphism.py

    diff --git a/sage/modules/matrix_morphism.py b/sage/modules/matrix_morphism.py
    a b  
    8686        EXAMPLES::
    8787       
    8888            sage: from sage.modules.matrix_morphism import MatrixMorphism
    89             sage: T = End(QQ^3)
    90             sage: M = MatrixSpace(QQ,3)
     89            sage: T = End(ZZ^3)
     90            sage: M = MatrixSpace(ZZ,3)
    9191            sage: I = M.identity_matrix()
    9292            sage: A = MatrixMorphism(T, I)
    9393            sage: loads(A.dumps()) == A
     
    120120       
    121121            sage: V = QQ^3; W = QQ^2
    122122            sage: H = Hom(V, W); H
    123             Set of Morphisms from Vector space of dimension 3 over Rational Field to Vector space of dimension 2 over Rational Field in Category of vector spaces over Rational Field
    124             sage: phi = H(range(6)); phi
    125             Free module morphism defined by the matrix
     123            Set of Morphisms (Linear Transformations) from
     124            Vector space of dimension 3 over Rational Field to
     125            Vector space of dimension 2 over Rational Field
     126            sage: phi = H(matrix(QQ, 3, 2, range(6))); phi
     127            Vector space morphism represented by the matrix:
    126128            [0 1]
    127129            [2 3]
    128130            [4 5]
     
    170172           
    171173            sage: V = QQ^2; phi = V.hom([3*V.0, 2*V.1])
    172174            sage: phi^(-1)
    173             Free module morphism defined by the matrix
     175            Vector space morphism represented by the matrix:
    174176            [1/3   0]
    175177            [  0 1/2]
    176178            Domain: Vector space of dimension 2 over Rational Field
     
    215217            sage: y = zeta(x); y
    216218            (-3, 0, -1)
    217219            sage: inv = zeta.inverse(); inv
    218             Free module morphism defined by the matrix
     220            Vector space morphism represented by the matrix:
    219221            [-1  3]
    220222            [ 1 -2]
    221223            Domain: Vector space of degree 3 and dimension 2 over Rational Field
    222             Basis ...
     224            Basis matrix:
     225            [1 0 0]
     226            [0 0 1]
    223227            Codomain: Vector space of degree 4 and dimension 2 over Rational Field
    224             Basis ...
     228            Basis matrix:
     229            [1 0 0 0]
     230            [0 0 0 1]
    225231            sage: inv(y) == x
    226232            True
    227233
     
    298304            sage: phi = V.hom(r, V)
    299305            sage: rho = phi.inverse()
    300306            sage: zeta = ~phi
    301             sage: rho == zeta
     307            sage: rho.is_equal_function(zeta)
    302308            True
    303309
    304310        TESTS::
     
    350356            sage: V = QQ^3
    351357            sage: E = V.endomorphism_ring()
    352358            sage: phi = E(Matrix(QQ,3,range(9))) ; phi
    353             Free module morphism defined by the matrix
     359            Vector space morphism represented by the matrix:
    354360            [0 1 2]
    355361            [3 4 5]
    356362            [6 7 8]
    357363            Domain: Vector space of dimension 3 over Rational Field
    358364            Codomain: Vector space of dimension 3 over Rational Field
    359365            sage: phi*phi
    360             Free module morphism defined by the matrix
     366            Vector space morphism represented by the matrix:
    361367            [ 15  18  21]
    362368            [ 42  54  66]
    363369            [ 69  90 111]
     
    367373            [ 15  18  21]
    368374            [ 42  54  66]
    369375            [ 69  90 111]
    370        
     376
    371377        ::
    372        
     378
    373379            sage: W = QQ**4
    374380            sage: E_VW = V.Hom(W)
    375381            sage: psi = E_VW(Matrix(QQ,3,4,range(12))) ; psi
    376             Free module morphism defined by the matrix
     382            Vector space morphism represented by the matrix:
    377383            [ 0  1  2  3]
    378384            [ 4  5  6  7]
    379385            [ 8  9 10 11]
    380386            Domain: Vector space of dimension 3 over Rational Field
    381387            Codomain: Vector space of dimension 4 over Rational Field
    382388            sage: psi*phi
    383             Free module morphism defined by the matrix
     389            Vector space morphism represented by the matrix:
    384390            [ 20  23  26  29]
    385391            [ 56  68  80  92]
    386392            [ 92 113 134 155]
     
    401407            sage: V, VtoK, KtoV = K.vector_space()
    402408            sage: f = V.hom([V.0 - V.1, V.0 + V.1])*KtoV; f
    403409            Composite map:
    404               From: Number Field in a with defining polynomial x^2 + 23
    405               To:   Vector space of dimension 2 over Rational Field
    406               Defn:   Isomorphism map:
    407                       From: Number Field in a with defining polynomial x^2 + 23
    408                       To:   Vector space of dimension 2 over Rational Field
     410            From: Number Field in a with defining polynomial x^2 + 23
     411            To:   Vector space of dimension 2 over Rational Field
     412            Defn:   Isomorphism map:
     413                    From: Number Field in a with defining polynomial x^2 + 23
     414                    To:   Vector space of dimension 2 over Rational Field
    409415                    then
    410                       Free module morphism defined by the matrix
     416                    Vector space morphism represented by the matrix:
    411417                    [ 1 -1]
    412418                    [ 1  1]
    413419                    Domain: Vector space of dimension 2 over Rational Field
     
    512518        """
    513519        return self.domain().base_ring()
    514520
    515     def charpoly(self, var='x'):
    516         """
     521    def characteristic_polynomial(self, var='x'):
     522        r"""
    517523        Return the characteristic polynomial of this endomorphism.
    518524
     525        ``characteristic_polynomial`` and ``char_poly`` are the same method.
     526
    519527        INPUT:
    520528            - var -- variable
    521529
    522530        EXAMPLES::
    523531       
    524532            sage: V = ZZ^2; phi = V.hom([V.0+V.1, 2*V.1])
     533            sage: phi.characteristic_polynomial()
     534            x^2 - 3*x + 2
    525535            sage: phi.charpoly()
    526536            x^2 - 3*x + 2
    527537            sage: phi.matrix().charpoly()
     
    533543            raise ArithmeticError, "charpoly only defined for endomorphisms " +\
    534544                    "(i.e., domain = range)"
    535545        return self.matrix().charpoly(var)
     546
     547    charpoly = characteristic_polynomial
    536548       
    537549    def decomposition(self, *args, **kwds):
    538550        """
     
    626638            Vector space of degree 3 and dimension 1 over Rational Field
    627639            Basis matrix:
    628640            [ 1 -2  1]
    629             sage: hom(CC^2, CC^2, 1).kernel()
     641            sage: hom(CC^2, CC^2, matrix(CC, [[1,0], [0,1]])).kernel()
    630642            Vector space of degree 2 and dimension 0 over Complex Field with 53 bits of precision
    631643            Basis matrix:
    632644            []
     
    648660        EXAMPLES::
    649661       
    650662            sage: V = VectorSpace(QQ,3)
    651             sage: phi = V.Hom(V)(range(9))
     663            sage: phi = V.Hom(V)(matrix(QQ, 3, range(9)))
    652664            sage: phi.image()
    653665            Vector space of degree 3 and dimension 2 over Rational Field
    654666            Basis matrix:
    655667            [ 1  0 -1]
    656668            [ 0  1  2]
    657             sage: hom(GF(7)^3, GF(7)^2, 0).image()
     669            sage: hom(GF(7)^3, GF(7)^2, zero_matrix(GF(7), 3, 2)).image()
    658670            Vector space of degree 2 and dimension 0 over Finite Field of size 7
    659671            Basis matrix:
    660672            []
     
    739751
    740752            sage: V1 = QQ^2
    741753            sage: V2 = QQ^3
    742             sage: phi = V1.hom(Matrix([[1,2],[3,4],[5,6]]),V2)
     754            sage: phi = V1.hom(Matrix([[1,2,3],[4,5,6]]),V2)
    743755            sage: phi.is_injective()
    744756            True
    745             sage: psi = V2.hom(Matrix([[1,2,3],[4,5,6]]),V1)
     757            sage: psi = V2.hom(Matrix([[1,2],[3,4],[5,6]]),V1)
    746758            sage: psi.is_injective()
    747759            False
    748760
     
    760772
    761773            sage: V1 = QQ^2
    762774            sage: V2 = QQ^3
    763             sage: phi = V1.hom(Matrix([[1,2],[3,4],[5,6]]), V2)
     775            sage: phi = V1.hom(Matrix([[1,2,3],[4,5,6]]), V2)
    764776            sage: phi.is_surjective()
    765777            False
    766             sage: psi = V2.hom(Matrix([[1,2,3],[4,5,6]]), V1)
     778            sage: psi = V2.hom(Matrix([[1,2],[3,4],[5,6]]), V1)
    767779            sage: psi.is_surjective()
    768780            True
    769781
     
    816828
    817829            sage: V1 = QQ^2
    818830            sage: V2 = QQ^3
    819             sage: m = matrix(QQ, [[1,2],[3,4],[5,6]])
     831            sage: m = matrix(QQ, [[1,2,3], [4,5,6]])
    820832            sage: phi = V1.hom(m, V2)
    821833            sage: phi.is_injective()
    822834            True
     
    833845
    834846            sage: V1 = QQ^3
    835847            sage: V2 = QQ^2
    836             sage: phi = V1.hom(matrix(QQ, [[1, 2, 3], [4, 5, 6]]), V2)
     848            sage: phi = V1.hom(matrix(QQ, [[1, 2], [3, 4], [5, 6]]), V2)
    837849            sage: x = vector(QQ, [1, -1, 4])
    838850            sage: y = phi(x); y
    839851            (18, 22)
     
    11351147            sage: phi(V.1) in X
    11361148            True
    11371149            sage: psi = phi.restrict_codomain(X); psi
    1138             Free module morphism defined by the matrix
     1150            Vector space morphism represented by the matrix:
    11391151            [1]
    11401152            [2]
    11411153            Domain: Vector space of dimension 2 over Rational Field
    11421154            Codomain: Vector space of degree 2 and dimension 1 over Rational Field
    1143             Basis ...
     1155            Basis matrix:
     1156            [1 2]
    11441157            sage: psi(V.0)
    11451158            (1, 2)
    11461159            sage: psi(V.1)
     
    11861199            Basis matrix:
    11871200            [  1 4/3]
    11881201            sage: psi = phi.restrict(W); psi
    1189             Free module morphism defined by the matrix
     1202            Vector space morphism represented by the matrix:
    11901203            [2]
    11911204            Domain: Vector space of degree 2 and dimension 1 over Rational Field
    1192             Basis ...
     1205            Basis matrix:
     1206            [  1 4/3]
    11931207            Codomain: Vector space of degree 2 and dimension 1 over Rational Field
    1194             Basis ...
     1208            Basis matrix:
     1209            [  1 4/3]
    11951210            sage: psi.domain() == W
    11961211            True
    11971212            sage: psi(W.0) == 2*W.0
     
    12321247        EXAMPLES::
    12331248       
    12341249            sage: from sage.modules.matrix_morphism import MatrixMorphism
    1235             sage: T = End(QQ^3)
    1236             sage: M = MatrixSpace(QQ,3)
     1250            sage: T = End(ZZ^3)
     1251            sage: M = MatrixSpace(ZZ,3)
    12371252            sage: I = M.identity_matrix()
    12381253            sage: A = MatrixMorphism(T, I)
    12391254            sage: loads(A.dumps()) == A
     
    12511266        self._matrix = A
    12521267        MatrixMorphism_abstract.__init__(self, parent)
    12531268
    1254     def matrix(self):
    1255         """
    1256         Return matrix that defines this morphism.
    1257        
     1269    def matrix(self, side='left'):
     1270        r"""
     1271        Return a matrix that defines this morphism.
     1272
     1273        INPUT:
     1274
     1275        - ``side`` - default:``'left'`` - the side of the matrix
     1276          where a vector is placed to effect the morphism (function).
     1277
     1278        OUTPUT:
     1279
     1280        A matrix which represents the morphism, relative to bases
     1281        for the domain and codomain.  If the modules are provided
     1282        with user bases, then the representation is relative to
     1283        these bases.
     1284
     1285        Internally, Sage represents a matrix morphism with the
     1286        matrix multiplying a row vector placed to the left of the
     1287        matrix.  If the option ``side='right'`` is used, then a
     1288        matrix is returned that acts on a vector to the right of
     1289        the matrix.  These two matrices are just transposes of
     1290        each other and the difference is just a preference for
     1291        the style of representation.
     1292
    12581293        EXAMPLES::
    12591294
    1260             sage: V = ZZ^2; phi = V.hom([3*V.0, 2*V.1])
     1295            sage: V = ZZ^2; W = ZZ^3
     1296            sage: phi = V.hom([3*V.0 - 5*V.1, 4*V.0 + 2*V.1, V.0 + V.1], W)
    12611297            sage: phi.matrix()
    1262             [3 0]
    1263             [0 2]
     1298            [ 3  4  1]
     1299            [-5  2  1]
     1300
     1301            sage: phi.matrix(side='right')
     1302            [ 3 -5]
     1303            [ 4  2]
     1304            [ 1  1]
     1305
     1306        TESTS::
     1307
     1308            sage: V = ZZ^2
     1309            sage: phi = V.hom([3*V.0, 2*V.1])
     1310            sage: phi.matrix(side='junk')
     1311            Traceback (most recent call last):
     1312            ...
     1313            ValueError: side must be 'left' or 'right', not junk
    12641314        """
    1265         return self._matrix
     1315        if not side in ['left', 'right']:
     1316            raise ValueError("side must be 'left' or 'right', not {0}".format(side))
     1317        if side == 'left':
     1318            return self._matrix
     1319        else:
     1320            return self._matrix.transpose()
    12661321
    12671322
    12681323    def _repr_(self):
  • sage/modules/quotient_module.py

    diff --git a/sage/modules/quotient_module.py b/sage/modules/quotient_module.py
    a b  
    4848        Basis matrix:
    4949        [    1 1/3*i 1/3*i]
    5050        sage: U.quotient_map()
    51         Free module morphism defined by the matrix
     51        Vector space morphism represented by the matrix:
    5252        [  1]
    5353        [3*i]
    54         Domain: Vector space of degree 3 and dimension 2 over Number Field in ...
    55         Codomain: Vector space quotient V/W of dimension 1 over Number Field in ...
     54        Domain: Vector space of degree 3 and dimension 2 over Number Field in i with defining polynomial x^2 + 1
     55        Basis matrix:
     56        [ 1  0  i]
     57        [ 0  1 -2]
     58        Codomain: Vector space quotient V/W of dimension 1 over Number Field in i with defining polynomial x^2 + 1 where
     59        V: Vector space of degree 3 and dimension 2 over Number Field in i with defining polynomial x^2 + 1
     60        Basis matrix:
     61        [ 1  0  i]
     62        [ 0  1 -2]
     63        W: Vector space of degree 3 and dimension 1 over Number Field in i with defining polynomial x^2 + 1
     64        Basis matrix:
     65        [    1 1/3*i 1/3*i]
    5666        sage: Z = V.quotient(W)
    5767        sage: Z == U
    5868        True
     
    262272        EXAMPLES:
    263273            sage: M = QQ^3 / [[1,2,3]]
    264274            sage: M.quotient_map()
    265             Free module morphism defined by the matrix
     275            Vector space morphism represented by the matrix:
    266276            [   1    0]
    267277            [   0    1]
    268278            [-1/3 -2/3]
    269279            Domain: Vector space of dimension 3 over Rational Field
    270             Codomain: Vector space quotient V/W of dimension 2 over Rational Field ...
     280            Codomain: Vector space quotient V/W of dimension 2 over Rational Field where
     281            V: Vector space of dimension 3 over Rational Field
     282            W: Vector space of degree 3 and dimension 1 over Rational Field
     283            Basis matrix:
     284            [1 2 3]
    271285           
    272286            sage: M.quotient_map()( (QQ^3)([1,2,3]) )
    273287            (0, 0)
     
    282296        EXAMPLES:
    283297            sage: M = QQ^3 / [[1,2,3]]
    284298            sage: M.lift_map()
    285             Free module morphism defined by the matrix
     299            Vector space morphism represented by the matrix:
    286300            [1 0 0]
    287301            [0 1 0]
    288             Domain: Vector space quotient V/W of dimension 2 over Rational Field ...
     302            Domain: Vector space quotient V/W of dimension 2 over Rational Field where
     303            V: Vector space of dimension 3 over Rational Field
     304            W: Vector space of degree 3 and dimension 1 over Rational Field
     305            Basis matrix:
     306            [1 2 3]
    289307            Codomain: Vector space of dimension 3 over Rational Field
    290308        """
    291309        return self.__lift_map
  • new file sage/modules/vector_space_homspace.py

    diff --git a/sage/modules/vector_space_homspace.py b/sage/modules/vector_space_homspace.py
    new file mode 100644
    - +  
     1r"""
     2Space of Morphisms of Vector Spaces (Linear Transformations)
     3
     4AUTHOR:
     5
     6    - Rob Beezer: (2011-06-29)
     7
     8A :class:`VectorSpaceHomspace` object represents the set of all
     9possible homomorphisms from one vector space to another.
     10These mappings are usually known as linear transformations.
     11
     12For more information on the use of linear transformations,
     13consult the documentation for vector space morphisms at
     14:mod:`sage.modules.vector_space_morphism`. Also, this is
     15an extremely thin veneer on free module homspaces
     16(:mod:`sage.modules.free_module_homspace`) and free module
     17morphisms (:mod:`sage.modules.free_module_morphism`) -
     18objects which might also be useful, and places
     19where much of the documentation resides.
     20
     21EXAMPLES:
     22
     23Creation and basic examination is simple. ::
     24
     25    sage: V = QQ^3
     26    sage: W = QQ^2
     27    sage: H = Hom(V, W)
     28    sage: H
     29    Set of Morphisms (Linear Transformations) from
     30    Vector space of dimension 3 over Rational Field to
     31    Vector space of dimension 2 over Rational Field
     32    sage: H.domain()
     33    Vector space of dimension 3 over Rational Field
     34    sage: H.codomain()
     35    Vector space of dimension 2 over Rational Field
     36
     37Homspaces have a few useful properties.  A basis is provided by
     38a list of matrix representations, where these matrix representatives
     39are relative to the bases of the domain and codomain.  ::
     40
     41    sage: K = Hom(GF(3)^2, GF(3)^2)
     42    sage: B = K.basis()
     43    sage: for f in B:
     44    ...     print f, "\n"
     45    Vector space morphism represented by the matrix:
     46    [1 0]
     47    [0 0]
     48    Domain: Vector space of dimension 2 over Finite Field of size 3
     49    Codomain: Vector space of dimension 2 over Finite Field of size 3
     50    <BLANKLINE>
     51    Vector space morphism represented by the matrix:
     52    [0 1]
     53    [0 0]
     54    Domain: Vector space of dimension 2 over Finite Field of size 3
     55    Codomain: Vector space of dimension 2 over Finite Field of size 3
     56    <BLANKLINE>
     57    Vector space morphism represented by the matrix:
     58    [0 0]
     59    [1 0]
     60    Domain: Vector space of dimension 2 over Finite Field of size 3
     61    Codomain: Vector space of dimension 2 over Finite Field of size 3
     62    <BLANKLINE>
     63    Vector space morphism represented by the matrix:
     64    [0 0]
     65    [0 1]
     66    Domain: Vector space of dimension 2 over Finite Field of size 3
     67    Codomain: Vector space of dimension 2 over Finite Field of size 3
     68    <BLANKLINE>
     69
     70The zero and identity mappings are properties of the space.
     71The identity mapping will only be available if the domain and codomain
     72allow for endomorphisms (equal vector spaces with equal bases).  ::
     73
     74    sage: H = Hom(QQ^3, QQ^3)
     75    sage: g = H.zero()
     76    sage: g([1, 1/2, -3])
     77    (0, 0, 0)
     78    sage: f = H.identity()
     79    sage: f([1, 1/2, -3])
     80    (1, 1/2, -3)
     81
     82The homspace may be used with various representations of a
     83morphism in the space to create the morphism.  We demonstrate
     84three ways to create the same linear transformation between
     85two two-dimensional subspaces of ``QQ^3``.  The ``V.n`` notation
     86is a shortcut to the generators of each vector space, better
     87known as the basis elements.  Note that the matrix representations
     88are relative to the bases, which are purposely fixed when the
     89subspaces are created ("user bases").  ::
     90
     91    sage: U = QQ^3
     92    sage: V = U.subspace_with_basis([U.0+U.1, U.1-U.2])
     93    sage: W = U.subspace_with_basis([U.0, U.1+U.2])
     94    sage: H = Hom(V, W)
     95
     96First, with a matrix.  Note that the matrix representation
     97acts by matrix multiplication with the vector on the left.
     98The input to the linear transformation, ``(3, 1, 2)``,
     99is converted to the coordinate vector ``(3, -2)``, then
     100matrix multiplication yields the vector ``(-3, -2)``,
     101which represents the vector ``(-3, -2, -2)`` in the codomain.  ::
     102
     103    sage: m = matrix(QQ, [[1, 2], [3, 4]])
     104    sage: f1 = H(m)
     105    sage: f1
     106    Vector space morphism represented by the matrix:
     107    [1 2]
     108    [3 4]
     109    Domain: Vector space of degree 3 and dimension 2 over Rational Field
     110    User basis matrix:
     111    [ 1  1  0]
     112    [ 0  1 -1]
     113    Codomain: Vector space of degree 3 and dimension 2 over Rational Field
     114    User basis matrix:
     115    [1 0 0]
     116    [0 1 1]
     117    sage: f1([3,1,2])
     118    (-3, -2, -2)
     119
     120Second, with a list of images of the domain's basis elements.  ::
     121
     122    sage: img = [1*(U.0) + 2*(U.1+U.2), 3*U.0 + 4*(U.1+U.2)]
     123    sage: f2 = H(img)
     124    sage: f2
     125    Vector space morphism represented by the matrix:
     126    [1 2]
     127    [3 4]
     128    Domain: Vector space of degree 3 and dimension 2 over Rational Field
     129    User basis matrix:
     130    [ 1  1  0]
     131    [ 0  1 -1]
     132    Codomain: Vector space of degree 3 and dimension 2 over Rational Field
     133    User basis matrix:
     134    [1 0 0]
     135    [0 1 1]
     136    sage: f2([3,1,2])
     137    (-3, -2, -2)
     138
     139Third, with a linear function taking the domain to the codomain.  ::
     140
     141    sage: g = lambda x: vector(QQ, [-2*x[0]+3*x[1], -2*x[0]+4*x[1], -2*x[0]+4*x[1]])
     142    sage: f3 = H(g)
     143    sage: f3
     144    Vector space morphism represented by the matrix:
     145    [1 2]
     146    [3 4]
     147    Domain: Vector space of degree 3 and dimension 2 over Rational Field
     148    User basis matrix:
     149    [ 1  1  0]
     150    [ 0  1 -1]
     151    Codomain: Vector space of degree 3 and dimension 2 over Rational Field
     152    User basis matrix:
     153    [1 0 0]
     154    [0 1 1]
     155    sage: f3([3,1,2])
     156    (-3, -2, -2)
     157
     158The three linear transformations look the same, and are the same.  ::
     159
     160    sage: f1 == f2
     161    True
     162    sage: f2 == f3
     163    True
     164
     165TESTS::
     166
     167    sage: V = QQ^2
     168    sage: W = QQ^3
     169    sage: H = Hom(QQ^2, QQ^3)
     170    sage: loads(dumps(H))
     171    Set of Morphisms (Linear Transformations) from
     172    Vector space of dimension 2 over Rational Field to
     173    Vector space of dimension 3 over Rational Field
     174    sage: loads(dumps(H)) == H
     175    True
     176"""
     177
     178####################################################################################
     179#       Copyright (C) 2011 Rob Beezer <beezer@ups.edu>
     180#
     181#  Distributed under the terms of the GNU General Public License (GPL)
     182#
     183#    This code is distributed in the hope that it will be useful,
     184#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     185#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     186#    General Public License for more details.
     187#
     188#  The full text of the GPL is available at:
     189#
     190#                  http://www.gnu.org/licenses/
     191####################################################################################
     192
     193import inspect
     194import sage.matrix.all as matrix
     195import sage.modules.free_module_homspace
     196import vector_space_morphism
     197
     198# This module initially overrides just the minimum functionality necessary
     199# from  sage.modules.free_module_homspace.FreeModuleHomSpace.
     200# If additional methods here override the free module homspace methods,
     201# consider adjusting the free module doctests, since many are written with
     202# examples that are actually vector spaces and not so many use "pure" modules
     203# for the examples.
     204
     205
     206def is_VectorSpaceHomspace(x):
     207    r"""
     208    Return ``True`` if ``x`` is a vector space homspace.
     209
     210    INPUT:
     211
     212    ``x`` - anything
     213
     214    EXAMPLES:
     215
     216    To be a vector space morphism, the domain and codomain must both be
     217    vector spaces, in other words, modules over fields.  If either
     218    set is just a module, then the ``Hom()`` constructor will build a
     219    space of free module morphisms.  ::
     220
     221        sage: H = Hom(QQ^3, QQ^2)
     222        sage: type(H)
     223        <class 'sage.modules.vector_space_homspace.VectorSpaceHomspace_with_category'>
     224        sage: sage.modules.vector_space_homspace.is_VectorSpaceHomspace(H)
     225        True
     226
     227        sage: K = Hom(QQ^3, ZZ^2)
     228        sage: type(K)
     229        <class 'sage.modules.free_module_homspace.FreeModuleHomspace_with_category'>
     230        sage: sage.modules.vector_space_homspace.is_VectorSpaceHomspace(K)
     231        False
     232
     233        sage: L = Hom(ZZ^3, QQ^2)
     234        sage: type(L)
     235        <class 'sage.modules.free_module_homspace.FreeModuleHomspace_with_category'>
     236        sage: sage.modules.vector_space_homspace.is_VectorSpaceHomspace(L)
     237        False
     238
     239        sage: sage.modules.vector_space_homspace.is_VectorSpaceHomspace('junk')
     240        False
     241    """
     242    return isinstance(x, VectorSpaceHomspace)
     243
     244class VectorSpaceHomspace(sage.modules.free_module_homspace.FreeModuleHomspace):
     245
     246    def __call__(self, A, check=True):
     247        r"""
     248        INPUT:
     249
     250        - ``A`` - one of several possible inputs representing
     251          a morphism from this vector space homspace.
     252          - a vector space morphism in this homspace
     253          - a matrix representation relative to the bases of the vector spaces,
     254            which acts on a vector placed to the left of the matrix
     255          - a list or tuple containing images of the domain's basis vectors
     256          - a function from the domain to the codomain
     257        - ``check`` (default: True) - ``True`` or ``False``, required for
     258          compatibility with calls from
     259          :meth:`sage.structure.parent_gens.ParentWithGens.hom`.
     260
     261        EXAMPLES::
     262
     263            sage: V = (QQ^3).span_of_basis([[1,1,0],[1,0,2]])
     264            sage: H = V.Hom(V)
     265            sage: H
     266            Set of Morphisms (Linear Transformations) from
     267            Vector space of degree 3 and dimension 2 over Rational Field
     268            User basis matrix:
     269            [1 1 0]
     270            [1 0 2]
     271            to
     272            Vector space of degree 3 and dimension 2 over Rational Field
     273            User basis matrix:
     274            [1 1 0]
     275            [1 0 2]
     276
     277        Coercing a matrix::
     278
     279            sage: A = matrix(QQ, [[0, 1], [1, 0]])
     280            sage: rho = H(A)          # indirect doctest
     281            sage: rho
     282            Vector space morphism represented by the matrix:
     283            [0 1]
     284            [1 0]
     285            Domain: Vector space of degree 3 and dimension 2 over Rational Field
     286            User basis matrix:
     287            [1 1 0]
     288            [1 0 2]
     289            Codomain: Vector space of degree 3 and dimension 2 over Rational Field
     290            User basis matrix:
     291            [1 1 0]
     292            [1 0 2]
     293
     294        Coercing a list of images::
     295
     296            sage: phi = H([V.1, V.0])
     297            sage: phi(V.1) == V.0
     298            True
     299            sage: phi(V.0) == V.1
     300            True
     301            sage: phi
     302            Vector space morphism represented by the matrix:
     303            [0 1]
     304            [1 0]
     305            Domain: Vector space of degree 3 and dimension 2 over Rational Field
     306            User basis matrix:
     307            [1 1 0]
     308            [1 0 2]
     309            Codomain: Vector space of degree 3 and dimension 2 over Rational Field
     310            User basis matrix:
     311            [1 1 0]
     312            [1 0 2]
     313
     314        Coercing a lambda function::
     315
     316            sage: f = lambda x: vector(QQ, [x[0], (1/2)*x[2], 2*x[1]])
     317            sage: zeta = H(f)
     318            sage: zeta
     319            Vector space morphism represented by the matrix:
     320            [0 1]
     321            [1 0]
     322            Domain: Vector space of degree 3 and dimension 2 over Rational Field
     323            User basis matrix:
     324            [1 1 0]
     325            [1 0 2]
     326            Codomain: Vector space of degree 3 and dimension 2 over Rational Field
     327            User basis matrix:
     328            [1 1 0]
     329            [1 0 2]
     330
     331        Coercing a vector space morphism into the parent of a second vector
     332        space morphism will unify their parents. ::
     333
     334            sage: U = QQ^3
     335            sage: V = QQ^4
     336            sage: W = QQ^3
     337            sage: X = QQ^4
     338            sage: H = Hom(U, V)
     339            sage: K = Hom(W, X)
     340
     341            sage: A = matrix(QQ, 3, 4, [0]*12)
     342            sage: f = H(A)
     343            sage: B = matrix(QQ, 3, 4, range(12))
     344            sage: g = K(B)
     345            sage: f.parent() is g.parent()
     346            False
     347
     348            sage: h = H(g)
     349            sage: f.parent() is h.parent()
     350            True
     351
     352        See other examples in the module-level documentation.
     353        """
     354        import vector_space_morphism
     355        D = self.domain()
     356        C = self.codomain()
     357        if matrix.is_Matrix(A):
     358            pass
     359        elif vector_space_morphism.is_VectorSpaceMorphism(A):
     360            A = A.matrix()
     361        elif inspect.isfunction(A):
     362            try:
     363                images = [A(g) for g in D.basis()]
     364            except (ValueError, TypeError, IndexError), e:
     365                msg = 'function cannot be applied properly to some basis element because\n' + e.args[0]
     366                raise ValueError(msg)
     367            try:
     368                A = matrix.matrix([C.coordinates(C(a)) for a in images])
     369            except (ArithmeticError, TypeError), e:
     370                msg = 'some image of the function is not in the codomain, because\n' + e.args[0]
     371                raise ArithmeticError(msg)
     372        elif isinstance(A, (list, tuple)):
     373            if len(A) != len(D.basis()):
     374                msg = "number of images should equal the size of the domain's basis (={0}), not {1}"
     375                raise ValueError(msg.format(len(D.basis()), len(A)))
     376            try:
     377                v = [C(a) for a in A]
     378                A = matrix.matrix([C.coordinates(a) for a in v])
     379            except (ArithmeticError, TypeError), e:
     380                msg = 'some proposed image is not in the codomain, because\n' + e.args[0]
     381                raise ArithmeticError(msg)
     382        else:
     383            msg = 'vector space homspace can only coerce matrices, vector space morphisms, functions or lists, not {0}'
     384            raise TypeError(msg.format(A))
     385        return vector_space_morphism.VectorSpaceMorphism(self, A)
     386
     387    def _repr_(self):
     388        r"""
     389        Text representation of a space of vector space morphisms.
     390
     391        EXAMPLE::
     392
     393            sage: H = Hom(QQ^2, QQ^3)
     394            sage: H._repr_().split(' ')
     395            ['Set', 'of', 'Morphisms', '(Linear', 'Transformations)',
     396            'from', 'Vector', 'space', 'of', 'dimension', '2', 'over',
     397            'Rational', 'Field', 'to', 'Vector', 'space', 'of',
     398            'dimension', '3', 'over', 'Rational', 'Field']
     399        """
     400        msg = 'Set of Morphisms (Linear Transformations) from {0} to {1}'
     401        return msg.format(self.domain(), self.codomain())
     402 No newline at end of file
  • new file sage/modules/vector_space_morphism.py

    diff --git a/sage/modules/vector_space_morphism.py b/sage/modules/vector_space_morphism.py
    new file mode 100644
    - +  
     1r"""
     2Vector Space Morphisms (aka Linear Transformations)
     3
     4AUTHOR:
     5
     6    - Rob Beezer: (2011-06-29)
     7
     8A vector space morphism is a homomorphism between vector spaces, better known
     9as a linear transformation.  These are a specialization of Sage's free module
     10homomorphisms.  (A free module is like a vector space, but with scalars from a
     11ring that may not be a field.)  So references to free modules in the
     12documentation or error messages should be understood as simply reflectng a
     13more general situation.
     14
     15Creation
     16--------
     17
     18The constructor :func:`linear_transformation` is designed to accept a
     19variety of inputs that can define a linear transformation.  See the
     20documentation of the function for all the possibilities.  Here we give two.
     21
     22First a matrix representation.  By default input matrices are understood
     23to act on vectors placed to left of the matrix.  Optionally, an input
     24matrix can be described as acting on vectors placed to the right.  ::
     25
     26    sage: A = matrix(QQ, [[-1, 2, 3], [4, 2, 0]])
     27    sage: phi = linear_transformation(A)
     28    sage: phi
     29    Vector space morphism represented by the matrix:
     30    [-1  2  3]
     31    [ 4  2  0]
     32    Domain: Vector space of dimension 2 over Rational Field
     33    Codomain: Vector space of dimension 3 over Rational Field
     34    sage: phi([2, -3])
     35    (-14, -2, 6)
     36
     37A symbolic function can be used to specify the "rule" for a
     38linear transformation, along with explicit descriptions of the
     39domain and codomain.  ::
     40
     41    sage: F = Integers(13)
     42    sage: D = F^3
     43    sage: C = F^2
     44    sage: x, y, z = var('x y z')
     45    sage: f(x, y, z) = [2*x + 3*y + 5*z, x + z]
     46    sage: rho = linear_transformation(D, C, f)
     47    sage: f(1, 2, 3)
     48    (23, 4)
     49    sage: rho([1, 2, 3])
     50    (10, 4)
     51
     52A "vector space homspace" is the set of all linear transformations
     53between two vector spaces.  Various input can be coerced into a
     54homspace to create a linear transformation.  See
     55:mod:`sage.modules.vector_space_homspace` for more. ::
     56
     57    sage: D = QQ^4
     58    sage: C = QQ^2
     59    sage: hom_space = Hom(D, C)
     60    sage: images = [[1, 3], [2, -1], [4, 0], [3, 7]]
     61    sage: zeta = hom_space(images)
     62    sage: zeta
     63    Vector space morphism represented by the matrix:
     64    [ 1  3]
     65    [ 2 -1]
     66    [ 4  0]
     67    [ 3  7]
     68    Domain: Vector space of dimension 4 over Rational Field
     69    Codomain: Vector space of dimension 2 over Rational Field
     70
     71A homomorphism may also be created via a method on the domain.  ::
     72
     73    sage: F = QQ[sqrt(3)]
     74    sage: a = F.gen(0)
     75    sage: D = F^2
     76    sage: C = F^2
     77    sage: A = matrix(F, [[a, 1], [2*a, 2]])
     78    sage: psi = D.hom(A, C)
     79    sage: psi
     80    Vector space morphism represented by the matrix:
     81    [  sqrt3       1]
     82    [2*sqrt3       2]
     83    Domain: Vector space of dimension 2 over Number Field in sqrt3 with defining polynomial x^2 - 3
     84    Codomain: Vector space of dimension 2 over Number Field in sqrt3 with defining polynomial x^2 - 3
     85    sage: psi([1, 4])
     86    (9*sqrt3, 9)
     87
     88Properties
     89----------
     90
     91Many natural properties of a linear transformation can be computed.
     92Some of these are more general methods of objects in the classes
     93:class:`sage.modules.free_module_morphism.FreeModuleMorphism` and
     94:class:`sage.modules.matrix_morphism.MatrixMorphism`.
     95
     96Values are computed in a natural way, an inverse image of an
     97element can be computed with the ``lift()`` method, when the inverse
     98image actually exists.  ::
     99
     100    sage: A = matrix(QQ, [[1,2], [2,4], [3,6]])
     101    sage: phi = linear_transformation(A)
     102    sage: phi([1,2,0])
     103    (5, 10)
     104    sage: phi.lift([10, 20])
     105    (10, 0, 0)
     106    sage: phi.lift([100, 100])
     107    Traceback (most recent call last):
     108    ...
     109    ValueError: element is not in the image
     110
     111Images and pre-images can be computed as vector spaces.  ::
     112
     113    sage: A = matrix(QQ, [[1,2], [2,4], [3,6]])
     114    sage: phi = linear_transformation(A)
     115    sage: phi.image()
     116    Vector space of degree 2 and dimension 1 over Rational Field
     117    Basis matrix:
     118    [1 2]
     119
     120    sage: phi.inverse_image( (QQ^2).span([[1,2]]) )
     121    Vector space of degree 3 and dimension 3 over Rational Field
     122    Basis matrix:
     123    [1 0 0]
     124    [0 1 0]
     125    [0 0 1]
     126
     127    sage: phi.inverse_image( (QQ^2).span([[1,1]]) )
     128    Vector space of degree 3 and dimension 2 over Rational Field
     129    Basis matrix:
     130    [   1    0 -1/3]
     131    [   0    1 -2/3]
     132
     133Injectivity and surjectivity can be checked.  ::
     134
     135    sage: A = matrix(QQ, [[1,2], [2,4], [3,6]])
     136    sage: phi = linear_transformation(A)
     137    sage: phi.is_injective()
     138    False
     139    sage: phi.is_surjective()
     140    False
     141
     142Restrictions and Representations
     143--------------------------------
     144
     145It is possible to restrict the domain and codomain of a linear
     146transformation to make a new linear transformation.  We will use
     147those commands to replace the domain and codomain by equal vector
     148spaces, but with alternate bases.  The point here is that the
     149matrix representation used to represent linear transformations are
     150relative to the bases of both the domain and codomain. ::
     151
     152    sage: A = graphs.PetersenGraph().adjacency_matrix()
     153    sage: V = QQ^10
     154    sage: phi = linear_transformation(V, V, A)
     155    sage: phi
     156    Vector space morphism represented by the matrix:
     157    [0 1 0 0 1 1 0 0 0 0]
     158    [1 0 1 0 0 0 1 0 0 0]
     159    [0 1 0 1 0 0 0 1 0 0]
     160    [0 0 1 0 1 0 0 0 1 0]
     161    [1 0 0 1 0 0 0 0 0 1]
     162    [1 0 0 0 0 0 0 1 1 0]
     163    [0 1 0 0 0 0 0 0 1 1]
     164    [0 0 1 0 0 1 0 0 0 1]
     165    [0 0 0 1 0 1 1 0 0 0]
     166    [0 0 0 0 1 0 1 1 0 0]
     167    Domain: Vector space of dimension 10 over Rational Field
     168    Codomain: Vector space of dimension 10 over Rational Field
     169
     170    sage: B1 = [V.gen(i) + V.gen(i+1) for i in range(9)] + [V.gen(9)]
     171    sage: B2 = [V.gen(0)] + [-V.gen(i-1) + V.gen(i) for i in range(1,10)]
     172    sage: D = V.subspace_with_basis(B1)
     173    sage: C = V.subspace_with_basis(B2)
     174    sage: rho = phi.restrict_codomain(C)
     175    sage: zeta = rho.restrict_domain(D)
     176    sage: zeta
     177    Vector space morphism represented by the matrix:
     178    [6 5 4 3 3 2 1 0 0 0]
     179    [6 5 4 3 2 2 2 1 0 0]
     180    [6 6 5 4 3 2 2 2 1 0]
     181    [6 5 5 4 3 2 2 2 2 1]
     182    [6 4 4 4 3 3 3 3 2 1]
     183    [6 5 4 4 4 4 4 4 3 1]
     184    [6 6 5 4 4 4 3 3 3 2]
     185    [6 6 6 5 4 4 2 1 1 1]
     186    [6 6 6 6 5 4 3 1 0 0]
     187    [3 3 3 3 3 2 2 1 0 0]
     188    Domain: Vector space of degree 10 and dimension 10 over Rational Field
     189    User basis matrix:
     190    [1 1 0 0 0 0 0 0 0 0]
     191    [0 1 1 0 0 0 0 0 0 0]
     192    [0 0 1 1 0 0 0 0 0 0]
     193    [0 0 0 1 1 0 0 0 0 0]
     194    [0 0 0 0 1 1 0 0 0 0]
     195    [0 0 0 0 0 1 1 0 0 0]
     196    [0 0 0 0 0 0 1 1 0 0]
     197    [0 0 0 0 0 0 0 1 1 0]
     198    [0 0 0 0 0 0 0 0 1 1]
     199    [0 0 0 0 0 0 0 0 0 1]
     200    Codomain: Vector space of degree 10 and dimension 10 over Rational Field
     201    User basis matrix:
     202    [ 1  0  0  0  0  0  0  0  0  0]
     203    [-1  1  0  0  0  0  0  0  0  0]
     204    [ 0 -1  1  0  0  0  0  0  0  0]
     205    [ 0  0 -1  1  0  0  0  0  0  0]
     206    [ 0  0  0 -1  1  0  0  0  0  0]
     207    [ 0  0  0  0 -1  1  0  0  0  0]
     208    [ 0  0  0  0  0 -1  1  0  0  0]
     209    [ 0  0  0  0  0  0 -1  1  0  0]
     210    [ 0  0  0  0  0  0  0 -1  1  0]
     211    [ 0  0  0  0  0  0  0  0 -1  1]
     212
     213An endomorphism is a linear transformation with an equal domain and codomain,
     214and here each needs to have the same basis.  We are using a
     215matrix that has well-behaved eigenvalues, as part of showing that these
     216do not change as the representation changes.  ::
     217
     218    sage: A = graphs.PetersenGraph().adjacency_matrix()
     219    sage: V = QQ^10
     220    sage: phi = linear_transformation(V, V, A)
     221    sage: phi.eigenvalues()
     222    [3, -2, -2, -2, -2, 1, 1, 1, 1, 1]
     223
     224    sage: B1 = [V.gen(i) + V.gen(i+1) for i in range(9)] + [V.gen(9)]
     225    sage: C = V.subspace_with_basis(B1)
     226    sage: zeta = phi.restrict(C)
     227    sage: zeta
     228    Vector space morphism represented by the matrix:
     229    [ 1  0  1 -1  2 -1  2 -2  2 -2]
     230    [ 1  0  1  0  0  0  1  0  0  0]
     231    [ 0  1  0  1  0  0  0  1  0  0]
     232    [ 1 -1  2 -1  2 -2  2 -2  3 -2]
     233    [ 2 -2  2 -1  1 -1  1  0  1  0]
     234    [ 1  0  0  0  0  0  0  1  1  0]
     235    [ 0  1  0  0  0  1 -1  1  0  2]
     236    [ 0  0  1  0  0  2 -1  1 -1  2]
     237    [ 0  0  0  1  0  1  1  0  0  0]
     238    [ 0  0  0  0  1 -1  2 -1  1 -1]
     239    Domain: Vector space of degree 10 and dimension 10 over Rational Field
     240    User basis matrix:
     241    [1 1 0 0 0 0 0 0 0 0]
     242    [0 1 1 0 0 0 0 0 0 0]
     243    [0 0 1 1 0 0 0 0 0 0]
     244    [0 0 0 1 1 0 0 0 0 0]
     245    [0 0 0 0 1 1 0 0 0 0]
     246    [0 0 0 0 0 1 1 0 0 0]
     247    [0 0 0 0 0 0 1 1 0 0]
     248    [0 0 0 0 0 0 0 1 1 0]
     249    [0 0 0 0 0 0 0 0 1 1]
     250    [0 0 0 0 0 0 0 0 0 1]
     251    Codomain: Vector space of degree 10 and dimension 10 over Rational Field
     252    User basis matrix:
     253    [1 1 0 0 0 0 0 0 0 0]
     254    [0 1 1 0 0 0 0 0 0 0]
     255    [0 0 1 1 0 0 0 0 0 0]
     256    [0 0 0 1 1 0 0 0 0 0]
     257    [0 0 0 0 1 1 0 0 0 0]
     258    [0 0 0 0 0 1 1 0 0 0]
     259    [0 0 0 0 0 0 1 1 0 0]
     260    [0 0 0 0 0 0 0 1 1 0]
     261    [0 0 0 0 0 0 0 0 1 1]
     262    [0 0 0 0 0 0 0 0 0 1]
     263
     264    sage: zeta.eigenvalues()
     265    [3, -2, -2, -2, -2, 1, 1, 1, 1, 1]
     266
     267Equality
     268--------
     269
     270Equality of linear transformations is a bit nuanced.  The equality operator
     271``==`` tests if two linear transformations have equal matrix representations,
     272while we determine if two linear transformations are the same function with the
     273``.is_equal_function()`` method.  Notice in this example that the function
     274never changes, just the representations.  ::
     275
     276    sage: f = lambda x: vector(QQ, [x[1], x[0]+x[1], x[0]])
     277    sage: H = Hom(QQ^2, QQ^3)
     278    sage: phi = H(f)
     279
     280    sage: rho = linear_transformation(QQ^2, QQ^3, matrix(QQ,2, 3, [[0,1,1], [1,1,0]]))
     281
     282    sage: phi == rho
     283    True
     284
     285    sage: U = (QQ^2).subspace_with_basis([[1, 2], [-3, 1]])
     286    sage: V = (QQ^3).subspace_with_basis([[0, 1, 0], [2, 3, 1], [-1, 1, 6]])
     287    sage: K = Hom(U, V)
     288    sage: zeta = K(f)
     289
     290    sage: zeta == phi
     291    False
     292    sage: zeta.is_equal_function(phi)
     293    True
     294    sage: zeta.is_equal_function(rho)
     295    True
     296
     297TESTS::
     298
     299    sage: V = QQ^2
     300    sage: H = Hom(V, V)
     301    sage: f = H([V.1,-2*V.0])
     302    sage: loads(dumps(f))
     303    Vector space morphism represented by the matrix:
     304    [ 0  1]
     305    [-2  0]
     306    Domain: Vector space of dimension 2 over Rational Field
     307    Codomain: Vector space of dimension 2 over Rational Field
     308    sage: loads(dumps(f)) == f
     309    True
     310"""
     311
     312####################################################################################
     313#       Copyright (C) 2011 Rob Beezer <beezer@ups.edu>
     314#
     315#  Distributed under the terms of the GNU General Public License (GPL)
     316#
     317#    This code is distributed in the hope that it will be useful,
     318#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     319#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     320#    General Public License for more details.
     321#
     322#  The full text of the GPL is available at:
     323#
     324#                  http://www.gnu.org/licenses/
     325####################################################################################
     326
     327
     328import sage.modules.matrix_morphism as matrix_morphism
     329import sage.modules.free_module_morphism as free_module_morphism
     330import vector_space_homspace
     331
     332def linear_transformation(arg0, arg1=None, arg2=None, side='left'):
     333    r"""
     334    Create a linear transformation from a variety of possible inputs.
     335
     336    FORMATS:
     337
     338    In the following, ``D`` and ``C`` are vector spaces over
     339    the same field that are the domain and codomain
     340    (respectively) of the linear transformation.
     341
     342    ``side`` is a keyword that is either 'left' or 'right'.
     343    When a matrix is used to specify a linear transformation,
     344    as in the first two call formats below, you may specify
     345    if the function is given by matrix multiplication with
     346    the vector on the left, or the vector on the right.
     347    The default is 'left'. Internally representations are
     348    always carried as the 'left' version, and the default
     349    text representation is this version.
     350
     351    - ``linear_transformation(A, side='left')``
     352
     353      Where ``A`` is a matrix.  The domain and codomain are inferred
     354      from the dimension of the matrix and the base ring of the matrix.
     355      The base ring must be a field, or have its fraction field implemented
     356      in Sage.
     357
     358    - ``linear_transformation(D, C, A, side='left')``
     359
     360      ``A`` is a matrix that behaves as above.  However, now the domain
     361      and codomain are given explicitly. The matrix is checked for
     362      compatibility with the domain and codomain.  Additionally, the
     363      domain and codomain may be supplied with alternate ("user") bases
     364      and the matrix is interpreted as being a representation relative
     365      to those bases.
     366
     367    - ``linear_transformation(D, C, f)``
     368
     369      ``f`` is any function that can be applied to the basis elements of the
     370      domain and that produces elements of the codomain.  The linear
     371      transformation returned is the unique linear transformation that
     372      extends this mapping on the basis elements.  ``f`` may come from a
     373      function defined by a Python ``def`` statement, or may be defined as a
     374      ``lambda`` function.
     375
     376      Alternatively, ``f`` may be specified by a callable symbolic function,
     377      see the examples below for a demonstration.
     378
     379    - ``linear_transformation(D, C, images)``
     380
     381      ``images`` is a list, or tuple, of codomain elements, equal in number
     382      to the size of the basis of the domain.  Each basis element of the domain
     383      is mapped to the corresponding element of the ``images`` list, and the
     384      linear transformation returned is the unique linear transfromation that
     385      extends this mapping.
     386
     387    OUTPUT:
     388
     389    A linear transformation described by the input.  This is a
     390    "vector space morphism", an object of the class
     391    :class:`sage.modules.vector_space_morphism`.
     392
     393    EXAMPLES:
     394
     395    We can define a linear transformation with just a matrix, acting from
     396    either side of the vector.  The field for the vector spaces used as
     397    domain and codomain is obtained from the base ring of the matrix,
     398    possibly promoting to a fraction field.  ::
     399
     400        sage: A = matrix(ZZ, [[1, -1, 4], [2, 0, 5]])
     401        sage: phi = linear_transformation(A)
     402        sage: phi
     403        Vector space morphism represented by the matrix:
     404        [ 1 -1  4]
     405        [ 2  0  5]
     406        Domain: Vector space of dimension 2 over Rational Field
     407        Codomain: Vector space of dimension 3 over Rational Field
     408        sage: phi([1/2, 5])
     409        (21/2, -1/2, 27)
     410
     411        sage: B = matrix(Integers(7), [[1, 2, 1], [3, 5, 6]])
     412        sage: rho = linear_transformation(B, side='right')
     413        sage: rho
     414        Vector space morphism represented by the matrix:
     415        [1 3]
     416        [2 5]
     417        [1 6]
     418        Domain: Vector space of dimension 3 over Ring of integers modulo 7
     419        Codomain: Vector space of dimension 2 over Ring of integers modulo 7
     420        sage: rho([2, 4, 6])
     421        (2, 6)
     422
     423    We can define a linear transformation with a matrix, while explicitly
     424    giving the domain and codomain.  Matrix entries will be coerced into the
     425    common field of scalars for the vector spaces.  ::
     426
     427        sage: D = QQ^3
     428        sage: C = QQ^2
     429        sage: A = matrix([[1, 7], [2, -1], [0, 5]])
     430        sage: A.parent()
     431        Full MatrixSpace of 3 by 2 dense matrices over Integer Ring
     432        sage: zeta = linear_transformation(D, C, A)
     433        sage: zeta.matrix().parent()
     434        Full MatrixSpace of 3 by 2 dense matrices over Rational Field
     435        sage: zeta
     436        Vector space morphism represented by the matrix:
     437        [ 1  7]
     438        [ 2 -1]
     439        [ 0  5]
     440        Domain: Vector space of dimension 3 over Rational Field
     441        Codomain: Vector space of dimension 2 over Rational Field
     442
     443    Matrix representations are relative to the bases for the domain
     444    and codomain.  ::
     445
     446        sage: u = vector(QQ, [1, -1])
     447        sage: v = vector(QQ, [2, 3])
     448        sage: D = (QQ^2).subspace_with_basis([u, v])
     449        sage: x = vector(QQ, [2, 1])
     450        sage: y = vector(QQ, [-1, 4])
     451        sage: C = (QQ^2).subspace_with_basis([x, y])
     452        sage: A = matrix(QQ, [[2, 5], [3, 7]])
     453        sage: psi = linear_transformation(D, C, A)
     454        sage: psi
     455        Vector space morphism represented by the matrix:
     456        [2 5]
     457        [3 7]
     458        Domain: Vector space of degree 2 and dimension 2 over Rational Field
     459        User basis matrix:
     460        [ 1 -1]
     461        [ 2  3]
     462        Codomain: Vector space of degree 2 and dimension 2 over Rational Field
     463        User basis matrix:
     464        [ 2  1]
     465        [-1  4]
     466        sage: psi(u) == 2*x + 5*y
     467        True
     468        sage: psi(v) == 3*x + 7*y
     469        True
     470
     471    Functions that act on the domain may be used to compute images of
     472    the domain's basis elements, and this mapping can be extended to
     473    a unique linear transformation.  The function may be a Python
     474    function (via ``def`` or ``lambda``) or a Sage symbolic function.
     475    The ```side`` keyword will determine how the linear transformation
     476    will be printed.  ::
     477
     478        sage: def g(x):
     479        ...     return vector(QQ, [2*x[0]+x[2], 5*x[1]])
     480        ...
     481        sage: phi = linear_transformation(QQ^3, QQ^2, g)
     482        sage: phi
     483        Vector space morphism represented by the matrix:
     484        [2 0]
     485        [0 5]
     486        [1 0]
     487        Domain: Vector space of dimension 3 over Rational Field
     488        Codomain: Vector space of dimension 2 over Rational Field
     489
     490        sage: f = lambda x: vector(QQ, [2*x[0]+x[2], 5*x[1]])
     491        sage: rho = linear_transformation(QQ^3, QQ^2, f)
     492        sage: rho
     493        Vector space morphism represented by the matrix:
     494        [2 0]
     495        [0 5]
     496        [1 0]
     497        Domain: Vector space of dimension 3 over Rational Field
     498        Codomain: Vector space of dimension 2 over Rational Field
     499
     500        sage: x, y, z = var('x y z')
     501        sage: h(x, y, z) = [2*x + z, 5*y]
     502        sage: zeta = linear_transformation(QQ^3, QQ^2, h)
     503        sage: zeta
     504        Vector space morphism represented by the matrix:
     505        [2 0]
     506        [0 5]
     507        [1 0]
     508        Domain: Vector space of dimension 3 over Rational Field
     509        Codomain: Vector space of dimension 2 over Rational Field
     510
     511        sage: phi == rho
     512        True
     513        sage: rho == zeta
     514        True
     515
     516
     517    We create a linear transformation relative to non-standard bases,
     518    and capture its representation relative to standard bases.  With this, we
     519    can build functions that create the same linear transformation relative
     520    to the nonstandard bases.  ::
     521
     522        sage: u = vector(QQ, [1, -1])
     523        sage: v = vector(QQ, [2, 3])
     524        sage: D = (QQ^2).subspace_with_basis([u, v])
     525        sage: x = vector(QQ, [2, 1])
     526        sage: y = vector(QQ, [-1, 4])
     527        sage: C = (QQ^2).subspace_with_basis([x, y])
     528        sage: A = matrix(QQ, [[2, 5], [3, 7]])
     529        sage: psi = linear_transformation(D, C, A)
     530        sage: rho = psi.restrict_codomain(QQ^2).restrict_domain(QQ^2)
     531        sage: rho.matrix()
     532        [ -4/5  97/5]
     533        [  1/5 -13/5]
     534
     535        sage: f = lambda x: vector(QQ, [(-4/5)*x[0] + (1/5)*x[1], (97/5)*x[0] + (-13/5)*x[1]])
     536        sage: psi = linear_transformation(D, C, f)
     537        sage: psi.matrix()
     538        [2 5]
     539        [3 7]
     540
     541        sage: s, t = var('s t')
     542        sage: h(s, t) = [(-4/5)*s + (1/5)*t, (97/5)*s + (-13/5)*t]
     543        sage: zeta = linear_transformation(D, C, h)
     544        sage: zeta.matrix()
     545        [2 5]
     546        [3 7]
     547
     548    Finally, we can give an explicit list of images for the basis
     549    elements of the domain.  ::
     550
     551        sage: x = polygen(QQ)
     552        sage: F.<a> = NumberField(x^3+x+1)
     553        sage: u = vector(F, [1, a, a^2])
     554        sage: v = vector(F, [a, a^2, 2])
     555        sage: w = u + v
     556        sage: D = F^3
     557        sage: C = F^3
     558        sage: rho = linear_transformation(D, C, [u, v, w])
     559        sage: rho.matrix()
     560        [      1       a     a^2]
     561        [      a     a^2       2]
     562        [  a + 1 a^2 + a a^2 + 2]
     563        sage: C = (F^3).subspace_with_basis([u, v])
     564        sage: D = (F^3).subspace_with_basis([u, v])
     565        sage: psi = linear_transformation(C, D, [u+v, u-v])
     566        sage: psi.matrix()
     567        [ 1  1]
     568        [ 1 -1]
     569
     570    TESTS:
     571
     572    We test some bad inputs.  First, the wrong things in the wrong places.  ::
     573
     574        sage: linear_transformation('junk')
     575        Traceback (most recent call last):
     576        ...
     577        TypeError: first argument must be a matrix or a vector space, not junk
     578
     579        sage: linear_transformation(QQ^2, QQ^3, 'stuff')
     580        Traceback (most recent call last):
     581        ...
     582        TypeError: third argument must be a matrix, function, or list of images, not stuff
     583
     584        sage: linear_transformation(QQ^2, 'garbage')
     585        Traceback (most recent call last):
     586        ...
     587        TypeError: if first argument is a vector space, then second argument must be a vector space, not garbage
     588
     589        sage: linear_transformation(QQ^2, Integers(7)^2)
     590        Traceback (most recent call last):
     591        ...
     592        TypeError: vector spaces must have the same field of scalars, not Rational Field and Ring of integers modulo 7
     593
     594    Matrices must be over a field (or a ring that can be promoted to a field),
     595    and of the right size.  ::
     596
     597        sage: linear_transformation(matrix(Integers(6), [[2, 3],[4, 5]]))
     598        Traceback (most recent call last):
     599        ...
     600        TypeError: matrix must have entries from a field, or a ring with a fraction field, not Ring of integers modulo 6
     601
     602        sage: A = matrix(QQ, 3, 4, range(12))
     603        sage: linear_transformation(QQ^4, QQ^4, A)
     604        Traceback (most recent call last):
     605        ...
     606        TypeError: domain dimension is incompatible with matrix size
     607
     608        sage: linear_transformation(QQ^3, QQ^3, A, side='right')
     609        Traceback (most recent call last):
     610        ...
     611        TypeError: domain dimension is incompatible with matrix size
     612
     613        sage: linear_transformation(QQ^3, QQ^3, A)
     614        Traceback (most recent call last):
     615        ...
     616        TypeError: codomain dimension is incompatible with matrix size
     617
     618        sage: linear_transformation(QQ^4, QQ^4, A, side='right')
     619        Traceback (most recent call last):
     620        ...
     621        TypeError: codomain dimension is incompatible with matrix size
     622
     623    Lists of images can be of the wrong number, or not really
     624    elements of the codomain.  ::
     625
     626        sage: linear_transformation(QQ^3, QQ^2, [vector(QQ, [1,2])])
     627        Traceback (most recent call last):
     628        ...
     629        ValueError: number of images should equal the size of the domain's basis (=3), not 1
     630
     631        sage: C = (QQ^2).subspace_with_basis([vector(QQ, [1,1])])
     632        sage: linear_transformation(QQ^1, C, [vector(QQ, [1,2])])
     633        Traceback (most recent call last):
     634        ...
     635        ArithmeticError: some proposed image is not in the codomain, because
     636        element (= [1, 2]) is not in free module
     637
     638
     639    Functions may not apply properly to domain elemnets,
     640    or return values outside the codomain.  ::
     641
     642        sage: f = lambda x: vector(QQ, [x[0], x[4]])
     643        sage: linear_transformation(QQ^3, QQ^2, f)
     644        Traceback (most recent call last):
     645        ...
     646        ValueError: function cannot be applied properly to some basis element because
     647        index out of range
     648
     649        sage: f = lambda x: vector(QQ, [x[0], x[1]])
     650        sage: C = (QQ^2).span([vector(QQ, [1, 1])])
     651        sage: linear_transformation(QQ^2, C, f)
     652        Traceback (most recent call last):
     653        ...
     654        ArithmeticError: some image of the function is not in the codomain, because
     655        element (= [1, 0]) is not in free module
     656
     657    A Sage symbolic function can come in a variety of forms that are
     658    not representative of a linear transformation. ::
     659
     660        sage: x, y = var('x, y')
     661        sage: f(x, y) = [y, x, y]
     662        sage: linear_transformation(QQ^3, QQ^3, f)
     663        Traceback (most recent call last):
     664        ...
     665        ValueError: symbolic function has the wrong number of inputs for domain
     666
     667        sage: linear_transformation(QQ^2, QQ^2, f)
     668        Traceback (most recent call last):
     669        ...
     670        ValueError: symbolic function has the wrong number of outputs for codomain
     671
     672        sage: x, y = var('x y')
     673        sage: f(x, y) = [y, x*y]
     674        sage: linear_transformation(QQ^2, QQ^2, f)
     675        Traceback (most recent call last):
     676        ...
     677        ValueError: symbolic function must be linear in all the inputs:
     678        unable to convert y to a rational
     679
     680        sage: x, y = var('x y')
     681        sage: f(x, y) = [x, 2*y]
     682        sage: C = (QQ^2).span([vector(QQ, [1, 1])])
     683        sage: linear_transformation(QQ^2, C, f)
     684        Traceback (most recent call last):
     685        ...
     686        ArithmeticError: some image of the function is not in the codomain, because
     687        element (= [1, 0]) is not in free module
     688    """
     689    from sage.matrix.matrix import is_Matrix
     690    from sage.matrix.constructor import matrix
     691    from sage.modules.module import is_VectorSpace
     692    from sage.modules.free_module import VectorSpace
     693    #from sage.modules.vector_space_homspace import VectorSpaceHomspace
     694    from sage.categories.homset import Hom
     695    from sage.modules.vector_space_morphism import VectorSpaceMorphism
     696    from sage.symbolic.ring import SymbolicRing
     697    from sage.modules.vector_callable_symbolic_dense import Vector_callable_symbolic_dense
     698    from inspect import isfunction
     699
     700    if not side in ['left', 'right']:
     701        raise ValueError("side must be 'left' or 'right', not {0}".format(side))
     702    if not (is_Matrix(arg0) or is_VectorSpace(arg0)):
     703        raise TypeError('first argument must be a matrix or a vector space, not {0}'.format(arg0))
     704    if is_Matrix(arg0):
     705        R = arg0.base_ring()
     706        if not R.is_field():
     707            try:
     708                R = R.fraction_field()
     709            except (NotImplementedError, TypeError):
     710                msg = 'matrix must have entries from a field, or a ring with a fraction field, not {0}'
     711                raise TypeError(msg.format(R))
     712        if side == 'right':
     713            arg0 = arg0.transpose()
     714            side = 'left'
     715        arg2 = arg0
     716        arg0 = VectorSpace(R, arg2.nrows())
     717        arg1 = VectorSpace(R, arg2.ncols())
     718    elif is_VectorSpace(arg0):
     719        if not is_VectorSpace(arg1):
     720            msg = 'if first argument is a vector space, then second argument must be a vector space, not {0}'
     721            raise TypeError(msg.format(arg1))
     722        if arg0.base_ring() != arg1.base_ring():
     723            msg = 'vector spaces must have the same field of scalars, not {0} and {1}'
     724            raise TypeError(msg.format(arg0.base_ring(), arg1.base_ring()))
     725
     726    # Now arg0 = domain D, arg1 = codomain C, and
     727    #   both are vector spaces with common field of scalars
     728    #   use these to make a VectorSpaceHomSpace
     729    # arg2 might be a matrix that began in arg0
     730    D = arg0
     731    C = arg1
     732    # next line must be Hom() to register unique parents?
     733    H = Hom(D, C, category=None)
     734
     735    # Examine arg2 as the "rule" for the linear transformation
     736    # Pass on matrices, Python functions and lists to homspace call
     737    # Convert symbolic function here, to a matrix
     738    if is_Matrix(arg2):
     739        if side == 'right':
     740            arg2 = arg2.transpose()
     741    elif isinstance(arg2, (list, tuple)):
     742        pass
     743    elif isfunction(arg2):
     744        pass
     745    elif isinstance(arg2, Vector_callable_symbolic_dense):
     746        args = arg2.parent().base_ring()._arguments
     747        exprs = arg2.change_ring(SymbolicRing())
     748        m = len(args)
     749        n = len(exprs)
     750        if m != D.degree():
     751            raise ValueError('symbolic function has the wrong number of inputs for domain')
     752        if n != C.degree():
     753            raise ValueError('symbolic function has the wrong number of outputs for codomain')
     754        arg2 = [[e.coeff(a) for e in exprs] for a in args]
     755        try:
     756            arg2 = matrix(D.base_ring(), m, n, arg2)
     757        except TypeError, e:
     758            msg = 'symbolic function must be linear in all the inputs:\n' + e.args[0]
     759            raise ValueError(msg)
     760        # have matrix with respect to standard bases, now consider user bases
     761        images = [v*arg2 for v in D.basis()]
     762        try:
     763            arg2 = matrix([C.coordinates(C(a)) for a in images])
     764        except (ArithmeticError, TypeError), e:
     765            msg = 'some image of the function is not in the codomain, because\n' + e.args[0]
     766            raise ArithmeticError(msg)
     767    else:
     768        msg = 'third argument must be a matrix, function, or list of images, not {0}'
     769        raise TypeError(msg.format(arg2))
     770
     771    # arg2 now compatible with homspace H call method
     772    # class __init__ will check
     773    #   matrix sizes versus domain/codomain dimensions
     774    return H(arg2)
     775    ## return VectorSpaceMorphism(H, arg2)
     776
     777def is_VectorSpaceMorphism(x):
     778    r"""
     779    Returns ``True`` if ``x`` is a vector space morphism (a linear transformation).
     780
     781    INPUT:
     782
     783    ``x`` - anything
     784
     785    OUTPUT:
     786
     787    ``True`` only if ``x`` is an instance of a vector space morphism,
     788    which are also known as linear transformations.
     789
     790    EXAMPLES::
     791
     792        sage: V = QQ^2; f = V.hom([V.1,-2*V.0])
     793        sage: sage.modules.vector_space_morphism.is_VectorSpaceMorphism(f)
     794        True
     795        sage: sage.modules.vector_space_morphism.is_VectorSpaceMorphism('junk')
     796        False
     797    """
     798    return isinstance(x, VectorSpaceMorphism)
     799
     800
     801class VectorSpaceMorphism(free_module_morphism.FreeModuleMorphism):
     802
     803    def __init__(self, homspace, A):
     804        r"""
     805        Create a linear transformation, a morphism between vector spaces.
     806
     807        INPUT:
     808
     809        -  ``homspace`` - a homspace (of vector spaces) to serve
     810           as a parent for the linear transformation and a home for
     811           the domain and codomain of the morphism
     812        -  ``A`` - a matrix representing the linear transformation,
     813           which will act on vectors placed to the left of the matrix
     814
     815        EXAMPLES:
     816
     817        Nominally, we require a homspace to hold the domain
     818        and codomain and a matrix representation of the morphism
     819        (linear transformation).  ::
     820
     821            sage: from sage.modules.vector_space_homspace import VectorSpaceHomspace
     822            sage: from sage.modules.vector_space_morphism import VectorSpaceMorphism
     823            sage: H = VectorSpaceHomspace(QQ^3, QQ^2)
     824            sage: A = matrix(QQ, 3, 2, range(6))
     825            sage: zeta = VectorSpaceMorphism(H, A)
     826            sage: zeta
     827            Vector space morphism represented by the matrix:
     828            [0 1]
     829            [2 3]
     830            [4 5]
     831            Domain: Vector space of dimension 3 over Rational Field
     832            Codomain: Vector space of dimension 2 over Rational Field
     833
     834        See the constructor,
     835        :func:`sage.modules.vector_space_morphism.linear_transformation`
     836        for another way to create linear transformations.
     837
     838        The ``.hom()`` method of a vector space will create a vector
     839        space morphism. ::
     840
     841            sage: V = QQ^3; W = V.subspace_with_basis([[1,2,3], [-1,2,5/3], [0,1,-1]])
     842            sage: phi = V.hom(matrix(QQ, 3, range(9)), codomain=W) # indirect doctest
     843            sage: type(phi)
     844            <class 'sage.modules.vector_space_morphism.VectorSpaceMorphism'>
     845
     846        A matrix may be coerced into a vector space homspace to
     847        create a vector space morphism.  ::
     848
     849            sage: from sage.modules.vector_space_homspace import VectorSpaceHomspace
     850            sage: H = VectorSpaceHomspace(QQ^3, QQ^2)
     851            sage: A = matrix(QQ, 3, 2, range(6))
     852            sage: rho = H(A)  # indirect doctest
     853            sage: type(rho)
     854            <class 'sage.modules.vector_space_morphism.VectorSpaceMorphism'>
     855        """
     856        from sage.matrix.matrix import is_Matrix
     857        if not vector_space_homspace.is_VectorSpaceHomspace(homspace):
     858            raise TypeError, 'homspace must be a vector space hom space, not {0}'.format(homspace)
     859        if isinstance(A, matrix_morphism.MatrixMorphism):
     860            A = A.matrix()
     861        if not is_Matrix(A):
     862            msg = 'input must be a matrix representation or another matrix morphism, not {0}'
     863            raise TypeError(msg.format(A))
     864        # now have a vector space homspace, and a matrix, check compatibility
     865
     866        if homspace.domain().dimension() != A.nrows():
     867            raise TypeError('domain dimension is incompatible with matrix size')
     868        if homspace.codomain().dimension() != A.ncols():
     869            raise TypeError('codomain dimension is incompatible with matrix size')
     870
     871        A = homspace._matrix_space()(A)
     872        free_module_morphism.FreeModuleMorphism.__init__(self, homspace, A)
     873
     874    def is_invertible(self):
     875        r"""
     876        Determines if the vector space morphism has an inverse.
     877
     878        OUTPUT:
     879
     880        ``True`` if the vector space morphism is invertible, otherwise
     881        ``False``.
     882
     883        EXAMPLES:
     884
     885        If the dimension of the domain does not match the dimension
     886        of the codomain, then the morphism cannot be invertible.  ::
     887
     888            sage: V = QQ^3
     889            sage: U = V.subspace_with_basis([V.0 + V.1, 2*V.1 + 3*V.2])
     890            sage: phi = V.hom([U.0, U.0 + U.1, U.0 - U.1], U)
     891            sage: phi.is_invertible()
     892            False
     893
     894        An invertible linear transformation. ::
     895
     896            sage: A = matrix(QQ, 3, [[-3, 5, -5], [4, -7, 7], [6, -8, 10]])
     897            sage: A.determinant()
     898            2
     899            sage: H = Hom(QQ^3, QQ^3)
     900            sage: rho = H(A)
     901            sage: rho.is_invertible()
     902            True
     903
     904        A non-invertible linear transformation, an endomorphism of
     905        a vector space over a finite field.  ::
     906
     907            sage: F.<a> = GF(11^2)
     908            sage: A = matrix(F, [[6*a + 3,   8*a +  2, 10*a + 3],
     909            ...                  [2*a + 7,   4*a +  3,  2*a + 3],
     910            ...                  [9*a + 2,  10*a + 10,  3*a + 3]])
     911            sage: A.nullity()
     912            1
     913            sage: E = End(F^3)
     914            sage: zeta = E(A)
     915            sage: zeta.is_invertible()
     916            False
     917        """
     918        # endomorphism or not, this is equivalent to invertibility of
     919        #   the matrix representation, so any test of this will suffice
     920        m = self.matrix()
     921        if not m.is_square():
     922            return False
     923        return m.rank() == m.ncols()
     924
     925    def _latex_(self):
     926        r"""
     927        A LaTeX representation of this vector space morphism.
     928
     929        EXAMPLE::
     930
     931            sage: H = Hom(QQ^3, QQ^2)
     932            sage: f = H(matrix(3, 2, range(6)))
     933            sage: f._latex_().split(' ')
     934            ['\\texttt{vector', 'space', 'morphism', 'from',
     935            '}\n\\Bold{Q}^{3}\\texttt{', 'to', '}\n\\Bold{Q}^{2}\\texttt{',
     936            'represented', 'by', 'the', 'matrix',
     937            '}\n\\left(\\begin{array}{rr}\n0', '&', '1',
     938            '\\\\\n2', '&', '3', '\\\\\n4', '&', '5\n\\end{array}\\right)']
     939        """
     940        from sage.misc.latex import latex
     941        s = ('\\texttt{vector space morphism from }\n', self.domain()._latex_(),
     942             '\\texttt{ to }\n', self.codomain()._latex_(),
     943             '\\texttt{ represented by the matrix }\n', self.matrix()._latex_())
     944        return ''.join(s)
     945
     946    def _repr_(self):
     947        r"""
     948        A text representation of this vector space morphism.
     949
     950        EXAMPLE::
     951
     952            sage: H = Hom(QQ^3, QQ^2)
     953            sage: f = H(matrix(3, 2, range(6)))
     954            sage: f._repr_().split(' ')
     955            ['Vector', 'space', 'morphism', 'represented', 'by',
     956            'the', 'matrix:\n[0', '1]\n[2', '3]\n[4', '5]\nDomain:',
     957            'Vector', 'space', 'of', 'dimension', '3', 'over',
     958            'Rational', 'Field\nCodomain:', 'Vector', 'space', 'of',
     959            'dimension', '2', 'over', 'Rational', 'Field']
     960        """
     961        m = self.matrix()
     962        msg = ("Vector space morphism represented by the matrix:\n",
     963               "{0}\n",
     964               "Domain: {1}\n",
     965               "Codomain: {2}")
     966        return ''.join(msg).format(m, self.domain(), self.codomain())