Ticket #11556: trac_11556-linear-transformations-v6-consolidated.patch

File trac_11556-linear-transformations-v6-consolidated.patch, 83.8 KB (added by rbeezer, 10 years ago)

Consolidated, standalone

  • doc/en/reference/modules.rst

    # HG changeset patch
    # User Rob Beezer <beezer@ups.edu>
    # Date 1311723732 25200
    # Node ID 5f534d820a1c9b8587ff6812af8d8f9444056828
    # Parent  df5620969fbddef0cf191407d046c2ed522d6a49
    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  
    5757   
    5858        sage: V = VectorSpace(QQ,3)
    5959        sage: Hom(V, V)
    60         Set of Morphisms from Vector space of dimension 3 over Rational
    61         Field to Vector space of dimension 3 over Rational Field in
    62         Category of vector spaces over Rational Field
     60        Set of Morphisms (Linear Transformations) from
     61        Vector space of dimension 3 over Rational Field to
     62        Vector space of dimension 3 over Rational Field
    6363        sage: G = AlternatingGroup(3)
    6464        sage: Hom(G, G)
    6565        Set of Morphisms from Alternating group of order 3!/2 as a permutation group to Alternating group of order 3!/2 as a permutation group in Category of finite permutation groups
     
    187187   
    188188        sage: V = VectorSpace(QQ, 3)
    189189        sage: End(V)
    190         Set of Morphisms from Vector space of dimension 3 over Rational
    191         Field to Vector space of dimension 3 over Rational Field in
    192         Category of vector spaces over Rational Field
    193    
     190        Set of Morphisms (Linear Transformations) from
     191        Vector space of dimension 3 over Rational Field to
     192        Vector space of dimension 3 over Rational Field
     193
    194194    ::
    195195   
    196196        sage: G = AlternatingGroup(3)
     
    245245        True
    246246    """
    247247    def __init__(self, X, Y, category=None, base = None, check=True):
    248         """
     248        r"""
    249249        TESTS::
     250
    250251            sage: X = ZZ['x']; X.rename("X")
    251252            sage: Y = ZZ['y']; Y.rename("Y")
    252253            sage: class MyHomset(Homset):
     
    521522# Really needed???
    522523class HomsetWithBase(Homset):
    523524    def __init__(self, X, Y, category=None, check=True, base=None):
    524         """
     525        r"""
    525526        TESTS::
     527       
    526528            sage: X = ZZ['x']; X.rename("X")
    527529            sage: Y = ZZ['y']; Y.rename("Y")
    528530            sage: class MyHomset(HomsetWithBase):
  • sage/categories/map.pyx

    diff --git a/sage/categories/map.pyx b/sage/categories/map.pyx
    a b  
    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
     
    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::
  • 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  
    603603
    604604    # FIXME: what's the level of generality of FreeModuleHomspace?
    605605    # Should there be a category for free modules accepting it as hom space?
     606    # See similar method for FreeModule_generic_field class
    606607    def _Hom_(self, Y, category):
    607608        from free_module_homspace import FreeModuleHomspace
    608609        return FreeModuleHomspace(self, Y, category)
     
    29342935            raise TypeError, "The base_field (=%s) must be a field"%base_field
    29352936        FreeModule_generic_pid.__init__(self, base_field, dimension, degree, sparse=sparse)
    29362937
     2938    def _Hom_(self, Y, category):
     2939        r"""
     2940        Returns a homspace whose morphisms have this vector space as domain.
     2941
     2942        This is called by the general methods such as
     2943        :meth:`sage.structure.parent.Parent.Hom` and
     2944        :meth:`sage.structure.parent_base.ParentWithBase.Hom`.
     2945
     2946        INPUT:
     2947
     2948        - ``Y`` - a free module (or vector space) that will
     2949          be the codomain of the morphisms in returned homspace
     2950        - ``category`` - the category for the homspace
     2951
     2952        OUTPUT:
     2953
     2954        If ``Y`` is a free module over a field, in other words, a vector space,
     2955        then this returns a space of homomorphisms between vector spaces,
     2956        in other words a space of linear transformations.
     2957
     2958        If ``Y`` is a free module that is not a vector space, then
     2959        the returned space contains homomorphisms between free modules.
     2960
     2961        EXAMPLES::
     2962
     2963            sage: V = QQ^2
     2964            sage: W = QQ^3
     2965            sage: H = V._Hom_(W, category=None)
     2966            sage: type(H)
     2967            <class 'sage.modules.vector_space_homspace.VectorSpaceHomspace_with_category'>
     2968            sage: H
     2969            Set of Morphisms (Linear Transformations) from Vector space of dimension 2 over Rational Field to Vector space of dimension 3 over Rational Field
     2970
     2971            sage: V = QQ^2
     2972            sage: W = ZZ^3
     2973            sage: H = V._Hom_(W, category=None)
     2974            sage: type(H)
     2975            <class 'sage.modules.free_module_homspace.FreeModuleHomspace_with_category'>
     2976            sage: H
     2977            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
     2978        """
     2979        if Y.base_ring().is_field():
     2980            import vector_space_homspace
     2981            return vector_space_homspace.VectorSpaceHomspace(self, Y, category)
     2982        import free_module_homspace
     2983        return free_module_homspace.FreeModuleHomspace(self, Y, category)
     2984
    29372985    def scale(self, other):
    29382986        """
    29392987        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]
     
    7779
    7880
    7981def is_FreeModuleHomspace(x):
    80     """
    81     Return True if x is a Free module homspace.
     82    r"""
     83    Return ``True`` if ``x`` is a free module homspace.
    8284
    83     EXAMPLES::
     85    EXAMPLES:
    8486
    85         sage: H = Hom(QQ^3, QQ^2)
     87    Notice that every vector space is a field, but when we construct a set of
     88    morphisms between two vector spaces, it is a ``VectorSpaceHomspace``,
     89    which qualifies as a ``FreeModuleHomspace``, since the former is
     90    special case of the latter.
     91
     92        sage: H = Hom(ZZ^3, ZZ^2)
     93        sage: type(H)
     94        <class 'sage.modules.free_module_homspace.FreeModuleHomspace_with_category'>
    8695        sage: sage.modules.free_module_homspace.is_FreeModuleHomspace(H)
    8796        True
    88         sage: sage.modules.free_module_homspace.is_FreeModuleHomspace(2)
     97
     98        sage: K = Hom(QQ^3, ZZ^2)
     99        sage: type(K)
     100        <class 'sage.modules.free_module_homspace.FreeModuleHomspace_with_category'>
     101        sage: sage.modules.free_module_homspace.is_FreeModuleHomspace(K)
     102        True
     103
     104        sage: L = Hom(ZZ^3, QQ^2)
     105        sage: type(L)
     106        <class 'sage.modules.free_module_homspace.FreeModuleHomspace_with_category'>
     107        sage: sage.modules.free_module_homspace.is_FreeModuleHomspace(L)
     108        True
     109
     110        sage: P = Hom(QQ^3, QQ^2)
     111        sage: type(P)
     112        <class 'sage.modules.vector_space_homspace.VectorSpaceHomspace_with_category'>
     113        sage: sage.modules.free_module_homspace.is_FreeModuleHomspace(P)
     114        True
     115
     116        sage: sage.modules.free_module_homspace.is_FreeModuleHomspace('junk')
    89117        False
    90118    """
    91119    return isinstance(x, FreeModuleHomspace)
    92120
    93121class FreeModuleHomspace(sage.categories.homset.HomsetWithBase):
    94122    def __call__(self, A, check=True):
    95         """
     123        r"""
    96124        INPUT:
    97125
    98126        - A -- either a matrix or a list/tuple of images of generators,
     
    107135
    108136        EXAMPLES::
    109137
    110             sage: V = (QQ^3).span_of_basis([[1,1,0],[1,0,2]])
     138            sage: V = (ZZ^3).span_of_basis([[1,1,0],[1,0,2]])
    111139            sage: H = V.Hom(V); H
    112140            Set of Morphisms from ...
    113141            sage: H([V.0,V.1])                    # indirect doctest
     
    193221
    194222        EXAMPLES::
    195223
    196             sage: H = Hom(QQ^2, QQ^1)
     224            sage: H = Hom(ZZ^2, ZZ^1)
    197225            sage: H.basis()
    198226            (Free module morphism defined by the matrix
    199227            [1]
    200228            [0]
    201             Domain: Vector space of dimension 2 over Rational Field
    202             Codomain: Vector space of dimension 1 over Rational Field,
    203              Free module morphism defined by the matrix
     229            Domain: Ambient free module of rank 2 over the principal ideal domain ...
     230            Codomain: Ambient free module of rank 1 over the principal ideal domain ..., Free module morphism defined by the matrix
    204231            [0]
    205232            [1]
    206             Domain: Vector space of dimension 2 over Rational Field
    207             Codomain: Vector space of dimension 1 over Rational Field)
     233            Domain: Ambient free module of rank 2 over the principal ideal domain ...
     234            Codomain: Ambient free module of rank 1 over the principal ideal domain ...)
    208235        """
    209236        try:
    210237            return self.__basis
     
    215242            return self.__basis
    216243       
    217244    def identity(self):
    218        r"""
    219        Return identity morphism in an endomorphism ring.
     245        r"""
     246        Return identity morphism in an endomorphism ring.
    220247       
    221        EXAMPLE::
     248        EXAMPLE::
    222249       
    223            sage: V=VectorSpace(QQ,5)
    224            sage: H=V.Hom(V)
    225            sage: H.identity()
    226            Free module morphism defined by the matrix
    227            [1 0 0 0 0]
    228            [0 1 0 0 0]
    229            [0 0 1 0 0]
    230            [0 0 0 1 0]
    231            [0 0 0 0 1]
    232            Domain: Vector space of dimension 5 over Rational Field
    233            Codomain: Vector space of dimension 5 over Rational Field
    234        """
    235        if self.is_endomorphism_set():
    236            return self(matrix.identity_matrix(self.base_ring(),self.domain().rank()))
    237        else:
    238            raise TypeError, "Identity map only defined for endomorphisms. Try natural_map() instead."
    239    
    240        
     250            sage: V=FreeModule(ZZ,5)
     251            sage: H=V.Hom(V)
     252            sage: H.identity()
     253            Free module morphism defined by the matrix
     254            [1 0 0 0 0]
     255            [0 1 0 0 0]
     256            [0 0 1 0 0]
     257            [0 0 0 1 0]
     258            [0 0 0 0 1]
     259            Domain: Ambient free module of rank 5 over the principal ideal domain ...
     260            Codomain: Ambient free module of rank 5 over the principal ideal domain ...
     261        """
     262        if self.is_endomorphism_set():
     263            return self(matrix.identity_matrix(self.base_ring(),self.domain().rank()))
     264        else:
     265            raise TypeError, "Identity map only defined for endomorphisms. Try natural_map() instead."
    241266
  • sage/modules/free_module_morphism.py

    diff --git a/sage/modules/free_module_morphism.py b/sage/modules/free_module_morphism.py
    a b  
    7070       
    7171        EXAMPLES::
    7272       
    73             sage: V = QQ^3; W = span([[1,2,3],[-1,2,5/3]], QQ)
    74             sage: phi = V.hom(matrix(QQ,3,[1..9]))
     73            sage: V = ZZ^3; W = span([[1,2,3],[-1,2,8]], ZZ)
     74            sage: phi = V.hom(matrix(ZZ,3,[1..9]))
    7575            sage: type(phi)
    7676            <class 'sage.modules.free_module_morphism.FreeModuleMorphism'>
    7777        """
     
    147147
    148148        EXAMPLES::
    149149
    150             sage: V = QQ^3; W = span([[1,2,3],[-1,2,5/3]], QQ)
    151             sage: phi = V.hom(matrix(QQ,3,[1..9]))
     150            sage: V = ZZ^3; W = span([[1,2,3],[-1,2,8]], ZZ)
     151            sage: phi = V.hom(matrix(ZZ,3,[1..9]))
    152152            sage: phi._repr_()
    153             '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'
     153            '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 Integer Ring\nCodomain: Ambient free module of rank 3 over the principal ideal domain Integer Ring'
    154154
    155155            sage: V = ZZ^6
    156156            sage: W = ZZ^4
     
    174174            sage: m = matrix(QQ, 40, 40, 1600)
    175175            sage: phi = V.hom(m, V)
    176176            sage: phi
    177             Free module morphism defined by the matrix
     177            Vector space morphism represented by the matrix:
    178178            40 x 40 dense matrix over Rational Field
    179179            Domain: Vector space of dimension 40 over Rational Field
    180180            Codomain: Vector space of dimension 40 over Rational Field
     
    200200            sage: h.change_ring(QQ).base_ring()
    201201            Rational Field
    202202            sage: f = h.change_ring(QQ); f
    203             Free module morphism defined by the matrix
     203            Vector space morphism represented by the matrix:
    204204            [-3 -3]
    205205            [-3 -3]
    206206            Domain: Vector space of degree 3 and dimension 2 over Rational Field
    207             Basis ...
     207            Basis matrix:
     208            [0 1 0]
     209            [0 0 1]
    208210            Codomain: Vector space of degree 2 and dimension 2 over Rational Field
    209             Basis ...
     211            Basis matrix:
     212            [1 0]
     213            [0 1]
    210214            sage: f = h.change_ring(GF(7)); f
    211             Free module morphism defined by the matrix
     215            Vector space morphism represented by the matrix:
    212216            [4 4]
    213217            [4 4]
    214             Domain: Vector space of degree 3 and dimension 2 over Finite Field of ...
    215             Codomain: Vector space of degree 2 and dimension 2 over Finite Field of ...
     218            Domain: Vector space of degree 3 and dimension 2 over Finite Field of size 7
     219            Basis matrix:
     220            [0 1 0]
     221            [0 0 1]
     222            Codomain: Vector space of degree 2 and dimension 2 over Finite Field of size 7
     223            Basis matrix:
     224            [1 0]
     225            [0 1]
    216226        """
    217227        D = self.domain().change_ring(R)
    218228        C = self.codomain().change_ring(R)
     
    455465    def eigenvectors(self,extend=True):
    456466        """
    457467        Computes the subspace of eigenvectors of a given eigenvalue.
    458        
     468
    459469        INPUT:
    460        
     470
    461471        - ``extend`` -- boolean (default: True) decides if base field
    462472          extensions should be considered or not.
    463        
     473
    464474        OUTPUT:
    465        
     475
    466476        A sequence of tuples. Each tuple contains an eigenvalue, a sequence
    467477        with a basis of the corresponding subspace of eigenvectors, and the
    468478        algebraic multiplicity of the eigenvalue.
    469        
    470         EXAMPLES:
    471        
    472        
    473         ::
    474            
     479
     480        EXAMPLES::
     481
    475482            sage: V=(QQ^4).subspace([[0,2,1,4],[1,2,5,0],[1,1,1,1]])
    476             sage: H=(V.Hom(V))([[0,1,0],[-1,0,0],[0,0,3]])
     483            sage: H=(V.Hom(V))(matrix(QQ, [[0,1,0],[-1,0,0],[0,0,3]]))
    477484            sage: H.eigenvectors()
    478485            [(3, [
    479486            (0, 0, 1, -6/7)
     
    486493            [(3, [
    487494            (0, 0, 1, -6/7)
    488495            ], 1)]
    489             sage: H1=(V.Hom(V))([[2,1,0],[0,2,0],[0,0,3]])
     496            sage: H1=(V.Hom(V))(matrix(QQ, [[2,1,0],[0,2,0],[0,0,3]]))
    490497            sage: H1.eigenvectors()
    491498            [(3, [
    492499            (0, 0, 1, -6/7)
     
    499506            ], 1), (2, [
    500507            (0, 1, 0, 17/7)
    501508            ], 2)]
    502 
    503        
    504509        """
    505510        if self.base_ring().is_field():
    506511            if self.is_endomorphism():
     
    510515                    V=self.domain().base_extend(i[0].parent())
    511516                    svectors=Sequence(map(lambda j: V(j * V.basis_matrix()),i[1]), cr=True)
    512517                    resu.append((i[0],svectors,i[2]))
    513                 return resu                 
     518                return resu
    514519            else:
    515520                raise TypeError, "not an endomorphism"
    516521        else:
    517522            raise NotImplementedError, "module must be a vector space"
    518    
    519        
    520     def minpoly(self,var='x'):
    521         """
     523
     524    def minimal_polynomial(self,var='x'):
     525        r"""
    522526        Computes the minimal polynomial.
    523        
     527
     528        ``minpoly()`` and ``minimal_polynomial()`` are the same method.
     529
    524530        INPUT:
    525        
     531
    526532        - ``var`` - string (default: 'x') a variable name
    527        
     533
    528534        OUTPUT:
    529        
     535
    530536        polynomial in var - the minimal polynomial of the endomorphism.
    531        
     537
    532538        EXAMPLES:
    533        
    534         Compute the minimal polynomial, and check it
    535        
    536         ::
    537        
    538             sage: V=GF(7)^3     
     539
     540        Compute the minimal polynomial, and check it. ::
     541
     542            sage: V=GF(7)^3
    539543            sage: H=V.Hom(V)([[0,1,2],[-1,0,3],[2,4,1]])
    540544            sage: H
    541             Free module morphism defined by the matrix
     545            Vector space morphism represented by the matrix:
    542546            [0 1 2]
    543547            [6 0 3]
    544548            [2 4 1]
    545549            Domain: Vector space of dimension 3 over Finite Field of size 7
    546550            Codomain: Vector space of dimension 3 over Finite Field of size 7
     551
    547552            sage: H.minpoly()
    548553            x^3 + 6*x^2 + 6*x + 1
    549             sage: H^3+6*H^2+6*H+1                 
    550             Free module morphism defined by the matrix
     554
     555            sage: H.minimal_polynomial()
     556            x^3 + 6*x^2 + 6*x + 1
     557
     558            sage: H^3 + (H^2)*6 + H*6 + 1
     559            Vector space morphism represented by the matrix:
    551560            [0 0 0]
    552561            [0 0 0]
    553562            [0 0 0]
    554563            Domain: Vector space of dimension 3 over Finite Field of size 7
    555564            Codomain: Vector space of dimension 3 over Finite Field of size 7
    556 
    557565        """
    558566        if self.is_endomorphism():
    559567            return self.matrix().minpoly(var)
    560568        else:
    561569            raise TypeError, "not an endomorphism"
    562570
     571    minpoly = minimal_polynomial
     572   
     573 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  
    8484        EXAMPLES::
    8585       
    8686            sage: from sage.modules.matrix_morphism import MatrixMorphism
    87             sage: T = End(QQ^3)
    88             sage: M = MatrixSpace(QQ,3)
     87            sage: T = End(ZZ^3)
     88            sage: M = MatrixSpace(ZZ,3)
    8989            sage: I = M.identity_matrix()
    9090            sage: A = MatrixMorphism(T, I)
    9191            sage: loads(A.dumps()) == A
     
    118118       
    119119            sage: V = QQ^3; W = QQ^2
    120120            sage: H = Hom(V, W); H
    121             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
    122             sage: phi = H(range(6)); phi
    123             Free module morphism defined by the matrix
     121            Set of Morphisms (Linear Transformations) from
     122            Vector space of dimension 3 over Rational Field to
     123            Vector space of dimension 2 over Rational Field
     124            sage: phi = H(matrix(QQ, 3, 2, range(6))); phi
     125            Vector space morphism represented by the matrix:
    124126            [0 1]
    125127            [2 3]
    126128            [4 5]
     
    168170           
    169171            sage: V = QQ^2; phi = V.hom([3*V.0, 2*V.1])
    170172            sage: phi^(-1)
    171             Free module morphism defined by the matrix
     173            Vector space morphism represented by the matrix:
    172174            [1/3   0]
    173175            [  0 1/2]
    174176            Domain: Vector space of dimension 2 over Rational Field
     
    213215            sage: y = zeta(x); y
    214216            (-3, 0, -1)
    215217            sage: inv = zeta.inverse(); inv
    216             Free module morphism defined by the matrix
     218            Vector space morphism represented by the matrix:
    217219            [-1  3]
    218220            [ 1 -2]
    219221            Domain: Vector space of degree 3 and dimension 2 over Rational Field
    220             Basis ...
     222            Basis matrix:
     223            [1 0 0]
     224            [0 0 1]
    221225            Codomain: Vector space of degree 4 and dimension 2 over Rational Field
    222             Basis ...
     226            Basis matrix:
     227            [1 0 0 0]
     228            [0 0 0 1]
    223229            sage: inv(y) == x
    224230            True
    225231
     
    296302            sage: phi = V.hom(r, V)
    297303            sage: rho = phi.inverse()
    298304            sage: zeta = ~phi
    299             sage: rho == zeta
     305            sage: rho.is_equal_function(zeta)
    300306            True
    301307
    302308        TESTS::
     
    348354            sage: V = QQ^3
    349355            sage: E = V.endomorphism_ring()
    350356            sage: phi = E(Matrix(QQ,3,range(9))) ; phi
    351             Free module morphism defined by the matrix
     357            Vector space morphism represented by the matrix:
    352358            [0 1 2]
    353359            [3 4 5]
    354360            [6 7 8]
    355361            Domain: Vector space of dimension 3 over Rational Field
    356362            Codomain: Vector space of dimension 3 over Rational Field
    357363            sage: phi*phi
    358             Free module morphism defined by the matrix
     364            Vector space morphism represented by the matrix:
    359365            [ 15  18  21]
    360366            [ 42  54  66]
    361367            [ 69  90 111]
     
    365371            [ 15  18  21]
    366372            [ 42  54  66]
    367373            [ 69  90 111]
    368        
     374
    369375        ::
    370        
     376
    371377            sage: W = QQ**4
    372378            sage: E_VW = V.Hom(W)
    373379            sage: psi = E_VW(Matrix(QQ,3,4,range(12))) ; psi
    374             Free module morphism defined by the matrix
     380            Vector space morphism represented by the matrix:
    375381            [ 0  1  2  3]
    376382            [ 4  5  6  7]
    377383            [ 8  9 10 11]
    378384            Domain: Vector space of dimension 3 over Rational Field
    379385            Codomain: Vector space of dimension 4 over Rational Field
    380386            sage: psi*phi
    381             Free module morphism defined by the matrix
     387            Vector space morphism represented by the matrix:
    382388            [ 20  23  26  29]
    383389            [ 56  68  80  92]
    384390            [ 92 113 134 155]
     
    399405            sage: V, VtoK, KtoV = K.vector_space()
    400406            sage: f = V.hom([V.0 - V.1, V.0 + V.1])*KtoV; f
    401407            Composite map:
    402               From: Number Field in a with defining polynomial x^2 + 23
    403               To:   Vector space of dimension 2 over Rational Field
    404               Defn:   Isomorphism map:
    405                       From: Number Field in a with defining polynomial x^2 + 23
    406                       To:   Vector space of dimension 2 over Rational Field
     408            From: Number Field in a with defining polynomial x^2 + 23
     409            To:   Vector space of dimension 2 over Rational Field
     410            Defn:   Isomorphism map:
     411                    From: Number Field in a with defining polynomial x^2 + 23
     412                    To:   Vector space of dimension 2 over Rational Field
    407413                    then
    408                       Free module morphism defined by the matrix
     414                    Vector space morphism represented by the matrix:
    409415                    [ 1 -1]
    410416                    [ 1  1]
    411417                    Domain: Vector space of dimension 2 over Rational Field
     
    513519        """
    514520        return self.domain().base_ring()
    515521
    516     def charpoly(self, var='x'):
    517         """
     522    def characteristic_polynomial(self, var='x'):
     523        r"""
    518524        Return the characteristic polynomial of this endomorphism.
    519525
     526        ``characteristic_polynomial`` and ``char_poly`` are the same method.
     527
    520528        INPUT:
    521529            - var -- variable
    522530
    523531        EXAMPLES::
    524532       
    525533            sage: V = ZZ^2; phi = V.hom([V.0+V.1, 2*V.1])
     534            sage: phi.characteristic_polynomial()
     535            x^2 - 3*x + 2
    526536            sage: phi.charpoly()
    527537            x^2 - 3*x + 2
    528538            sage: phi.matrix().charpoly()
     
    534544            raise ArithmeticError, "charpoly only defined for endomorphisms " +\
    535545                    "(i.e., domain = range)"
    536546        return self.matrix().charpoly(var)
     547
     548    charpoly = characteristic_polynomial
    537549       
    538550    def decomposition(self, *args, **kwds):
    539551        """
     
    629641            Vector space of degree 3 and dimension 1 over Rational Field
    630642            Basis matrix:
    631643            [ 1 -2  1]
    632             sage: hom(CC^2, CC^2, 1).kernel()
     644            sage: hom(CC^2, CC^2, matrix(CC, [[1,0], [0,1]])).kernel()
    633645            Vector space of degree 2 and dimension 0 over Complex Field with 53 bits of precision
    634646            Basis matrix:
    635647            []
     
    651663        EXAMPLES::
    652664       
    653665            sage: V = VectorSpace(QQ,3)
    654             sage: phi = V.Hom(V)(range(9))
     666            sage: phi = V.Hom(V)(matrix(QQ, 3, range(9)))
    655667            sage: phi.image()
    656668            Vector space of degree 3 and dimension 2 over Rational Field
    657669            Basis matrix:
    658670            [ 1  0 -1]
    659671            [ 0  1  2]
    660             sage: hom(GF(7)^3, GF(7)^2, 0).image()
     672            sage: hom(GF(7)^3, GF(7)^2, zero_matrix(GF(7), 3, 2)).image()
    661673            Vector space of degree 2 and dimension 0 over Finite Field of size 7
    662674            Basis matrix:
    663675            []
     
    10661078            sage: phi(V.1) in X
    10671079            True
    10681080            sage: psi = phi.restrict_codomain(X); psi
    1069             Free module morphism defined by the matrix
     1081            Vector space morphism represented by the matrix:
    10701082            [1]
    10711083            [2]
    10721084            Domain: Vector space of dimension 2 over Rational Field
    10731085            Codomain: Vector space of degree 2 and dimension 1 over Rational Field
    1074             Basis ...
     1086            Basis matrix:
     1087            [1 2]
    10751088            sage: psi(V.0)
    10761089            (1, 2)
    10771090            sage: psi(V.1)
     
    11171130            Basis matrix:
    11181131            [  1 4/3]
    11191132            sage: psi = phi.restrict(W); psi
    1120             Free module morphism defined by the matrix
     1133            Vector space morphism represented by the matrix:
    11211134            [2]
    11221135            Domain: Vector space of degree 2 and dimension 1 over Rational Field
    1123             Basis ...
     1136            Basis matrix:
     1137            [  1 4/3]
    11241138            Codomain: Vector space of degree 2 and dimension 1 over Rational Field
    1125             Basis ...
     1139            Basis matrix:
     1140            [  1 4/3]
    11261141            sage: psi.domain() == W
    11271142            True
    11281143            sage: psi(W.0) == 2*W.0
     
    11631178        EXAMPLES::
    11641179       
    11651180            sage: from sage.modules.matrix_morphism import MatrixMorphism
    1166             sage: T = End(QQ^3)
    1167             sage: M = MatrixSpace(QQ,3)
     1181            sage: T = End(ZZ^3)
     1182            sage: M = MatrixSpace(ZZ,3)
    11681183            sage: I = M.identity_matrix()
    11691184            sage: A = MatrixMorphism(T, I)
    11701185            sage: loads(A.dumps()) == A
     
    11821197        self._matrix = A
    11831198        MatrixMorphism_abstract.__init__(self, parent)
    11841199
    1185     def matrix(self):
    1186         """
    1187         Return matrix that defines this morphism.
    1188        
     1200    def matrix(self, side='left'):
     1201        r"""
     1202        Return a matrix that defines this morphism.
     1203
     1204        INPUT:
     1205
     1206        - ``side`` - default:``'left'`` - the side of the matrix
     1207          where a vector is placed to effect the morphism (function).
     1208
     1209        OUTPUT:
     1210
     1211        A matrix which represents the morphism, relative to bases
     1212        for the domain and codomain.  If the modules are provided
     1213        with user bases, then the representation is relative to
     1214        these bases.
     1215
     1216        Internally, Sage represents a matrix morphism with the
     1217        matrix multiplying a row vector placed to the left of the
     1218        matrix.  If the option ``side='right'`` is used, then a
     1219        matrix is returned that acts on a vector to the right of
     1220        the matrix.  These two matrices are just transposes of
     1221        each other and the difference is just a preference for
     1222        the style of representation.
     1223
    11891224        EXAMPLES::
    11901225
    1191             sage: V = ZZ^2; phi = V.hom([3*V.0, 2*V.1])
     1226            sage: V = ZZ^2; W = ZZ^3
     1227            sage: phi = V.hom([3*V.0 - 5*V.1, 4*V.0 + 2*V.1, V.0 + V.1], W)
    11921228            sage: phi.matrix()
    1193             [3 0]
    1194             [0 2]
     1229            [ 3  4  1]
     1230            [-5  2  1]
     1231
     1232            sage: phi.matrix(side='right')
     1233            [ 3 -5]
     1234            [ 4  2]
     1235            [ 1  1]
     1236
     1237        TESTS::
     1238
     1239            sage: V = ZZ^2
     1240            sage: phi = V.hom([3*V.0, 2*V.1])
     1241            sage: phi.matrix(side='junk')
     1242            Traceback (most recent call last):
     1243            ...
     1244            ValueError: side must be 'left' or 'right', not junk
    11951245        """
    1196         return self._matrix
     1246        if not side in ['left', 'right']:
     1247            raise ValueError("side must be 'left' or 'right', not {0}".format(side))
     1248        if side == 'left':
     1249            return self._matrix
     1250        else:
     1251            return self._matrix.transpose()
    11971252
    11981253    def is_injective(self):
    11991254        """
  • 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
     331from sage.matrix.matrix import is_Matrix
     332
     333def linear_transformation(arg0, arg1=None, arg2=None, side='left'):
     334    r"""
     335    Create a linear transformation from a variety of possible inputs.
     336
     337    FORMATS:
     338
     339    In the following, ``D`` and ``C`` are vector spaces over
     340    the same field that are the domain and codomain
     341    (respectively) of the linear transformation.
     342
     343    ``side`` is a keyword that is either 'left' or 'right'.
     344    When a matrix is used to specify a linear transformation,
     345    as in the first two call formats below, you may specify
     346    if the function is given by matrix multiplication with
     347    the vector on the left, or the vector on the right.
     348    The default is 'left'. Internally representations are
     349    always carried as the 'left' version, and the default
     350    text representation is this version.  However, the matrix
     351    representation may be obtained as either version, no matter
     352    how it is created.
     353
     354    - ``linear_transformation(A, side='left')``
     355
     356      Where ``A`` is a matrix.  The domain and codomain are inferred
     357      from the dimension of the matrix and the base ring of the matrix.
     358      The base ring must be a field, or have its fraction field implemented
     359      in Sage.
     360
     361    - ``linear_transformation(D, C, A, side='left')``
     362
     363      ``A`` is a matrix that behaves as above.  However, now the domain
     364      and codomain are given explicitly. The matrix is checked for
     365      compatibility with the domain and codomain.  Additionally, the
     366      domain and codomain may be supplied with alternate ("user") bases
     367      and the matrix is interpreted as being a representation relative
     368      to those bases.
     369
     370    - ``linear_transformation(D, C, f)``
     371
     372      ``f`` is any function that can be applied to the basis elements of the
     373      domain and that produces elements of the codomain.  The linear
     374      transformation returned is the unique linear transformation that
     375      extends this mapping on the basis elements.  ``f`` may come from a
     376      function defined by a Python ``def`` statement, or may be defined as a
     377      ``lambda`` function.
     378
     379      Alternatively, ``f`` may be specified by a callable symbolic function,
     380      see the examples below for a demonstration.
     381
     382    - ``linear_transformation(D, C, images)``
     383
     384      ``images`` is a list, or tuple, of codomain elements, equal in number
     385      to the size of the basis of the domain.  Each basis element of the domain
     386      is mapped to the corresponding element of the ``images`` list, and the
     387      linear transformation returned is the unique linear transfromation that
     388      extends this mapping.
     389
     390    OUTPUT:
     391
     392    A linear transformation described by the input.  This is a
     393    "vector space morphism", an object of the class
     394    :class:`sage.modules.vector_space_morphism`.
     395
     396    EXAMPLES:
     397
     398    We can define a linear transformation with just a matrix, understood to
     399    act on a vector placed on one side or the other.  The field for the
     400    vector spaces used as domain and codomain is obtained from the base
     401    ring of the matrix, possibly promoting to a fraction field.  ::
     402
     403        sage: A = matrix(ZZ, [[1, -1, 4], [2, 0, 5]])
     404        sage: phi = linear_transformation(A)
     405        sage: phi
     406        Vector space morphism represented by the matrix:
     407        [ 1 -1  4]
     408        [ 2  0  5]
     409        Domain: Vector space of dimension 2 over Rational Field
     410        Codomain: Vector space of dimension 3 over Rational Field
     411        sage: phi([1/2, 5])
     412        (21/2, -1/2, 27)
     413
     414        sage: B = matrix(Integers(7), [[1, 2, 1], [3, 5, 6]])
     415        sage: rho = linear_transformation(B, side='right')
     416        sage: rho
     417        Vector space morphism represented by the matrix:
     418        [1 3]
     419        [2 5]
     420        [1 6]
     421        Domain: Vector space of dimension 3 over Ring of integers modulo 7
     422        Codomain: Vector space of dimension 2 over Ring of integers modulo 7
     423        sage: rho([2, 4, 6])
     424        (2, 6)
     425
     426    We can define a linear transformation with a matrix, while explicitly
     427    giving the domain and codomain.  Matrix entries will be coerced into the
     428    common field of scalars for the vector spaces.  ::
     429
     430        sage: D = QQ^3
     431        sage: C = QQ^2
     432        sage: A = matrix([[1, 7], [2, -1], [0, 5]])
     433        sage: A.parent()
     434        Full MatrixSpace of 3 by 2 dense matrices over Integer Ring
     435        sage: zeta = linear_transformation(D, C, A)
     436        sage: zeta.matrix().parent()
     437        Full MatrixSpace of 3 by 2 dense matrices over Rational Field
     438        sage: zeta
     439        Vector space morphism represented by the matrix:
     440        [ 1  7]
     441        [ 2 -1]
     442        [ 0  5]
     443        Domain: Vector space of dimension 3 over Rational Field
     444        Codomain: Vector space of dimension 2 over Rational Field
     445
     446    Matrix representations are relative to the bases for the domain
     447    and codomain.  ::
     448
     449        sage: u = vector(QQ, [1, -1])
     450        sage: v = vector(QQ, [2, 3])
     451        sage: D = (QQ^2).subspace_with_basis([u, v])
     452        sage: x = vector(QQ, [2, 1])
     453        sage: y = vector(QQ, [-1, 4])
     454        sage: C = (QQ^2).subspace_with_basis([x, y])
     455        sage: A = matrix(QQ, [[2, 5], [3, 7]])
     456        sage: psi = linear_transformation(D, C, A)
     457        sage: psi
     458        Vector space morphism represented by the matrix:
     459        [2 5]
     460        [3 7]
     461        Domain: Vector space of degree 2 and dimension 2 over Rational Field
     462        User basis matrix:
     463        [ 1 -1]
     464        [ 2  3]
     465        Codomain: Vector space of degree 2 and dimension 2 over Rational Field
     466        User basis matrix:
     467        [ 2  1]
     468        [-1  4]
     469        sage: psi(u) == 2*x + 5*y
     470        True
     471        sage: psi(v) == 3*x + 7*y
     472        True
     473
     474    Functions that act on the domain may be used to compute images of
     475    the domain's basis elements, and this mapping can be extended to
     476    a unique linear transformation.  The function may be a Python
     477    function (via ``def`` or ``lambda``) or a Sage symbolic function.  ::
     478
     479        sage: def g(x):
     480        ...     return vector(QQ, [2*x[0]+x[2], 5*x[1]])
     481        ...
     482        sage: phi = linear_transformation(QQ^3, QQ^2, g)
     483        sage: phi
     484        Vector space morphism represented by the matrix:
     485        [2 0]
     486        [0 5]
     487        [1 0]
     488        Domain: Vector space of dimension 3 over Rational Field
     489        Codomain: Vector space of dimension 2 over Rational Field
     490
     491        sage: f = lambda x: vector(QQ, [2*x[0]+x[2], 5*x[1]])
     492        sage: rho = linear_transformation(QQ^3, QQ^2, f)
     493        sage: rho
     494        Vector space morphism represented by the matrix:
     495        [2 0]
     496        [0 5]
     497        [1 0]
     498        Domain: Vector space of dimension 3 over Rational Field
     499        Codomain: Vector space of dimension 2 over Rational Field
     500
     501        sage: x, y, z = var('x y z')
     502        sage: h(x, y, z) = [2*x + z, 5*y]
     503        sage: zeta = linear_transformation(QQ^3, QQ^2, h)
     504        sage: zeta
     505        Vector space morphism represented by the matrix:
     506        [2 0]
     507        [0 5]
     508        [1 0]
     509        Domain: Vector space of dimension 3 over Rational Field
     510        Codomain: Vector space of dimension 2 over Rational Field
     511
     512        sage: phi == rho
     513        True
     514        sage: rho == zeta
     515        True
     516
     517
     518    We create a linear transformation relative to non-standard bases,
     519    and capture its representation relative to standard bases.  With this, we
     520    can build functions that create the same linear transformation relative
     521    to the nonstandard bases.  ::
     522
     523        sage: u = vector(QQ, [1, -1])
     524        sage: v = vector(QQ, [2, 3])
     525        sage: D = (QQ^2).subspace_with_basis([u, v])
     526        sage: x = vector(QQ, [2, 1])
     527        sage: y = vector(QQ, [-1, 4])
     528        sage: C = (QQ^2).subspace_with_basis([x, y])
     529        sage: A = matrix(QQ, [[2, 5], [3, 7]])
     530        sage: psi = linear_transformation(D, C, A)
     531        sage: rho = psi.restrict_codomain(QQ^2).restrict_domain(QQ^2)
     532        sage: rho.matrix()
     533        [ -4/5  97/5]
     534        [  1/5 -13/5]
     535
     536        sage: f = lambda x: vector(QQ, [(-4/5)*x[0] + (1/5)*x[1], (97/5)*x[0] + (-13/5)*x[1]])
     537        sage: psi = linear_transformation(D, C, f)
     538        sage: psi.matrix()
     539        [2 5]
     540        [3 7]
     541
     542        sage: s, t = var('s t')
     543        sage: h(s, t) = [(-4/5)*s + (1/5)*t, (97/5)*s + (-13/5)*t]
     544        sage: zeta = linear_transformation(D, C, h)
     545        sage: zeta.matrix()
     546        [2 5]
     547        [3 7]
     548
     549    Finally, we can give an explicit list of images for the basis
     550    elements of the domain.  ::
     551
     552        sage: x = polygen(QQ)
     553        sage: F.<a> = NumberField(x^3+x+1)
     554        sage: u = vector(F, [1, a, a^2])
     555        sage: v = vector(F, [a, a^2, 2])
     556        sage: w = u + v
     557        sage: D = F^3
     558        sage: C = F^3
     559        sage: rho = linear_transformation(D, C, [u, v, w])
     560        sage: rho.matrix()
     561        [      1       a     a^2]
     562        [      a     a^2       2]
     563        [  a + 1 a^2 + a a^2 + 2]
     564        sage: C = (F^3).subspace_with_basis([u, v])
     565        sage: D = (F^3).subspace_with_basis([u, v])
     566        sage: psi = linear_transformation(C, D, [u+v, u-v])
     567        sage: psi.matrix()
     568        [ 1  1]
     569        [ 1 -1]
     570
     571    TESTS:
     572
     573    We test some bad inputs.  First, the wrong things in the wrong places.  ::
     574
     575        sage: linear_transformation('junk')
     576        Traceback (most recent call last):
     577        ...
     578        TypeError: first argument must be a matrix or a vector space, not junk
     579
     580        sage: linear_transformation(QQ^2, QQ^3, 'stuff')
     581        Traceback (most recent call last):
     582        ...
     583        TypeError: third argument must be a matrix, function, or list of images, not stuff
     584
     585        sage: linear_transformation(QQ^2, 'garbage')
     586        Traceback (most recent call last):
     587        ...
     588        TypeError: if first argument is a vector space, then second argument must be a vector space, not garbage
     589
     590        sage: linear_transformation(QQ^2, Integers(7)^2)
     591        Traceback (most recent call last):
     592        ...
     593        TypeError: vector spaces must have the same field of scalars, not Rational Field and Ring of integers modulo 7
     594
     595    Matrices must be over a field (or a ring that can be promoted to a field),
     596    and of the right size.  ::
     597
     598        sage: linear_transformation(matrix(Integers(6), [[2, 3],[4, 5]]))
     599        Traceback (most recent call last):
     600        ...
     601        TypeError: matrix must have entries from a field, or a ring with a fraction field, not Ring of integers modulo 6
     602
     603        sage: A = matrix(QQ, 3, 4, range(12))
     604        sage: linear_transformation(QQ^4, QQ^4, A)
     605        Traceback (most recent call last):
     606        ...
     607        TypeError: domain dimension is incompatible with matrix size
     608
     609        sage: linear_transformation(QQ^3, QQ^3, A, side='right')
     610        Traceback (most recent call last):
     611        ...
     612        TypeError: domain dimension is incompatible with matrix size
     613
     614        sage: linear_transformation(QQ^3, QQ^3, A)
     615        Traceback (most recent call last):
     616        ...
     617        TypeError: codomain dimension is incompatible with matrix size
     618
     619        sage: linear_transformation(QQ^4, QQ^4, A, side='right')
     620        Traceback (most recent call last):
     621        ...
     622        TypeError: codomain dimension is incompatible with matrix size
     623
     624    Lists of images can be of the wrong number, or not really
     625    elements of the codomain.  ::
     626
     627        sage: linear_transformation(QQ^3, QQ^2, [vector(QQ, [1,2])])
     628        Traceback (most recent call last):
     629        ...
     630        ValueError: number of images should equal the size of the domain's basis (=3), not 1
     631
     632        sage: C = (QQ^2).subspace_with_basis([vector(QQ, [1,1])])
     633        sage: linear_transformation(QQ^1, C, [vector(QQ, [1,2])])
     634        Traceback (most recent call last):
     635        ...
     636        ArithmeticError: some proposed image is not in the codomain, because
     637        element (= [1, 2]) is not in free module
     638
     639
     640    Functions may not apply properly to domain elements,
     641    or return values outside the codomain.  ::
     642
     643        sage: f = lambda x: vector(QQ, [x[0], x[4]])
     644        sage: linear_transformation(QQ^3, QQ^2, f)
     645        Traceback (most recent call last):
     646        ...
     647        ValueError: function cannot be applied properly to some basis element because
     648        index out of range
     649
     650        sage: f = lambda x: vector(QQ, [x[0], x[1]])
     651        sage: C = (QQ^2).span([vector(QQ, [1, 1])])
     652        sage: linear_transformation(QQ^2, C, f)
     653        Traceback (most recent call last):
     654        ...
     655        ArithmeticError: some image of the function is not in the codomain, because
     656        element (= [1, 0]) is not in free module
     657
     658    A Sage symbolic function can come in a variety of forms that are
     659    not representative of a linear transformation. ::
     660
     661        sage: x, y = var('x, y')
     662        sage: f(x, y) = [y, x, y]
     663        sage: linear_transformation(QQ^3, QQ^3, f)
     664        Traceback (most recent call last):
     665        ...
     666        ValueError: symbolic function has the wrong number of inputs for domain
     667
     668        sage: linear_transformation(QQ^2, QQ^2, f)
     669        Traceback (most recent call last):
     670        ...
     671        ValueError: symbolic function has the wrong number of outputs for codomain
     672
     673        sage: x, y = var('x y')
     674        sage: f(x, y) = [y, x*y]
     675        sage: linear_transformation(QQ^2, QQ^2, f)
     676        Traceback (most recent call last):
     677        ...
     678        ValueError: symbolic function must be linear in all the inputs:
     679        unable to convert y to a rational
     680
     681        sage: x, y = var('x y')
     682        sage: f(x, y) = [x, 2*y]
     683        sage: C = (QQ^2).span([vector(QQ, [1, 1])])
     684        sage: linear_transformation(QQ^2, C, f)
     685        Traceback (most recent call last):
     686        ...
     687        ArithmeticError: some image of the function is not in the codomain, because
     688        element (= [1, 0]) is not in free module
     689    """
     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.categories.homset import Hom
     694    from sage.symbolic.ring import SymbolicRing
     695    from sage.modules.vector_callable_symbolic_dense import Vector_callable_symbolic_dense
     696    from inspect import isfunction
     697
     698    if not side in ['left', 'right']:
     699        raise ValueError("side must be 'left' or 'right', not {0}".format(side))
     700    if not (is_Matrix(arg0) or is_VectorSpace(arg0)):
     701        raise TypeError('first argument must be a matrix or a vector space, not {0}'.format(arg0))
     702    if is_Matrix(arg0):
     703        R = arg0.base_ring()
     704        if not R.is_field():
     705            try:
     706                R = R.fraction_field()
     707            except (NotImplementedError, TypeError):
     708                msg = 'matrix must have entries from a field, or a ring with a fraction field, not {0}'
     709                raise TypeError(msg.format(R))
     710        if side == 'right':
     711            arg0 = arg0.transpose()
     712            side = 'left'
     713        arg2 = arg0
     714        arg0 = VectorSpace(R, arg2.nrows())
     715        arg1 = VectorSpace(R, arg2.ncols())
     716    elif is_VectorSpace(arg0):
     717        if not is_VectorSpace(arg1):
     718            msg = 'if first argument is a vector space, then second argument must be a vector space, not {0}'
     719            raise TypeError(msg.format(arg1))
     720        if arg0.base_ring() != arg1.base_ring():
     721            msg = 'vector spaces must have the same field of scalars, not {0} and {1}'
     722            raise TypeError(msg.format(arg0.base_ring(), arg1.base_ring()))
     723
     724    # Now arg0 = domain D, arg1 = codomain C, and
     725    #   both are vector spaces with common field of scalars
     726    #   use these to make a VectorSpaceHomSpace
     727    # arg2 might be a matrix that began in arg0
     728    D = arg0
     729    C = arg1
     730    H = Hom(D, C, category=None)
     731
     732    # Examine arg2 as the "rule" for the linear transformation
     733    # Pass on matrices, Python functions and lists to homspace call
     734    # Convert symbolic function here, to a matrix
     735    if is_Matrix(arg2):
     736        if side == 'right':
     737            arg2 = arg2.transpose()
     738    elif isinstance(arg2, (list, tuple)):
     739        pass
     740    elif isfunction(arg2):
     741        pass
     742    elif isinstance(arg2, Vector_callable_symbolic_dense):
     743        args = arg2.parent().base_ring()._arguments
     744        exprs = arg2.change_ring(SymbolicRing())
     745        m = len(args)
     746        n = len(exprs)
     747        if m != D.degree():
     748            raise ValueError('symbolic function has the wrong number of inputs for domain')
     749        if n != C.degree():
     750            raise ValueError('symbolic function has the wrong number of outputs for codomain')
     751        arg2 = [[e.coeff(a) for e in exprs] for a in args]
     752        try:
     753            arg2 = matrix(D.base_ring(), m, n, arg2)
     754        except TypeError, e:
     755            msg = 'symbolic function must be linear in all the inputs:\n' + e.args[0]
     756            raise ValueError(msg)
     757        # have matrix with respect to standard bases, now consider user bases
     758        images = [v*arg2 for v in D.basis()]
     759        try:
     760            arg2 = matrix([C.coordinates(C(a)) for a in images])
     761        except (ArithmeticError, TypeError), e:
     762            msg = 'some image of the function is not in the codomain, because\n' + e.args[0]
     763            raise ArithmeticError(msg)
     764    else:
     765        msg = 'third argument must be a matrix, function, or list of images, not {0}'
     766        raise TypeError(msg.format(arg2))
     767
     768    # arg2 now compatible with homspace H call method
     769    # __init__ will check matrix sizes versus domain/codomain dimensions
     770    return H(arg2)
     771
     772def is_VectorSpaceMorphism(x):
     773    r"""
     774    Returns ``True`` if ``x`` is a vector space morphism (a linear transformation).
     775
     776    INPUT:
     777
     778    ``x`` - anything
     779
     780    OUTPUT:
     781
     782    ``True`` only if ``x`` is an instance of a vector space morphism,
     783    which are also known as linear transformations.
     784
     785    EXAMPLES::
     786
     787        sage: V = QQ^2; f = V.hom([V.1,-2*V.0])
     788        sage: sage.modules.vector_space_morphism.is_VectorSpaceMorphism(f)
     789        True
     790        sage: sage.modules.vector_space_morphism.is_VectorSpaceMorphism('junk')
     791        False
     792    """
     793    return isinstance(x, VectorSpaceMorphism)
     794
     795
     796class VectorSpaceMorphism(free_module_morphism.FreeModuleMorphism):
     797
     798    def __init__(self, homspace, A):
     799        r"""
     800        Create a linear transformation, a morphism between vector spaces.
     801
     802        INPUT:
     803
     804        -  ``homspace`` - a homspace (of vector spaces) to serve
     805           as a parent for the linear transformation and a home for
     806           the domain and codomain of the morphism
     807        -  ``A`` - a matrix representing the linear transformation,
     808           which will act on vectors placed to the left of the matrix
     809
     810        EXAMPLES:
     811
     812        Nominally, we require a homspace to hold the domain
     813        and codomain and a matrix representation of the morphism
     814        (linear transformation).  ::
     815
     816            sage: from sage.modules.vector_space_homspace import VectorSpaceHomspace
     817            sage: from sage.modules.vector_space_morphism import VectorSpaceMorphism
     818            sage: H = VectorSpaceHomspace(QQ^3, QQ^2)
     819            sage: A = matrix(QQ, 3, 2, range(6))
     820            sage: zeta = VectorSpaceMorphism(H, A)
     821            sage: zeta
     822            Vector space morphism represented by the matrix:
     823            [0 1]
     824            [2 3]
     825            [4 5]
     826            Domain: Vector space of dimension 3 over Rational Field
     827            Codomain: Vector space of dimension 2 over Rational Field
     828
     829        See the constructor,
     830        :func:`sage.modules.vector_space_morphism.linear_transformation`
     831        for another way to create linear transformations.
     832
     833        The ``.hom()`` method of a vector space will create a vector
     834        space morphism. ::
     835
     836            sage: V = QQ^3; W = V.subspace_with_basis([[1,2,3], [-1,2,5/3], [0,1,-1]])
     837            sage: phi = V.hom(matrix(QQ, 3, range(9)), codomain=W) # indirect doctest
     838            sage: type(phi)
     839            <class 'sage.modules.vector_space_morphism.VectorSpaceMorphism'>
     840
     841        A matrix may be coerced into a vector space homspace to
     842        create a vector space morphism.  ::
     843
     844            sage: from sage.modules.vector_space_homspace import VectorSpaceHomspace
     845            sage: H = VectorSpaceHomspace(QQ^3, QQ^2)
     846            sage: A = matrix(QQ, 3, 2, range(6))
     847            sage: rho = H(A)  # indirect doctest
     848            sage: type(rho)
     849            <class 'sage.modules.vector_space_morphism.VectorSpaceMorphism'>
     850        """
     851        if not vector_space_homspace.is_VectorSpaceHomspace(homspace):
     852            raise TypeError, 'homspace must be a vector space hom space, not {0}'.format(homspace)
     853        if isinstance(A, matrix_morphism.MatrixMorphism):
     854            A = A.matrix()
     855        if not is_Matrix(A):
     856            msg = 'input must be a matrix representation or another matrix morphism, not {0}'
     857            raise TypeError(msg.format(A))
     858        # now have a vector space homspace, and a matrix, check compatibility
     859
     860        if homspace.domain().dimension() != A.nrows():
     861            raise TypeError('domain dimension is incompatible with matrix size')
     862        if homspace.codomain().dimension() != A.ncols():
     863            raise TypeError('codomain dimension is incompatible with matrix size')
     864
     865        A = homspace._matrix_space()(A)
     866        free_module_morphism.FreeModuleMorphism.__init__(self, homspace, A)
     867
     868    def is_invertible(self):
     869        r"""
     870        Determines if the vector space morphism has an inverse.
     871
     872        OUTPUT:
     873
     874        ``True`` if the vector space morphism is invertible, otherwise
     875        ``False``.
     876
     877        EXAMPLES:
     878
     879        If the dimension of the domain does not match the dimension
     880        of the codomain, then the morphism cannot be invertible.  ::
     881
     882            sage: V = QQ^3
     883            sage: U = V.subspace_with_basis([V.0 + V.1, 2*V.1 + 3*V.2])
     884            sage: phi = V.hom([U.0, U.0 + U.1, U.0 - U.1], U)
     885            sage: phi.is_invertible()
     886            False
     887
     888        An invertible linear transformation. ::
     889
     890            sage: A = matrix(QQ, 3, [[-3, 5, -5], [4, -7, 7], [6, -8, 10]])
     891            sage: A.determinant()
     892            2
     893            sage: H = Hom(QQ^3, QQ^3)
     894            sage: rho = H(A)
     895            sage: rho.is_invertible()
     896            True
     897
     898        A non-invertible linear transformation, an endomorphism of
     899        a vector space over a finite field.  ::
     900
     901            sage: F.<a> = GF(11^2)
     902            sage: A = matrix(F, [[6*a + 3,   8*a +  2, 10*a + 3],
     903            ...                  [2*a + 7,   4*a +  3,  2*a + 3],
     904            ...                  [9*a + 2,  10*a + 10,  3*a + 3]])
     905            sage: A.nullity()
     906            1
     907            sage: E = End(F^3)
     908            sage: zeta = E(A)
     909            sage: zeta.is_invertible()
     910            False
     911        """
     912        # endomorphism or not, this is equivalent to invertibility of
     913        #   the matrix representation, so any test of this will suffice
     914        m = self.matrix()
     915        if not m.is_square():
     916            return False
     917        return m.rank() == m.ncols()
     918
     919    def _latex_(self):
     920        r"""
     921        A LaTeX representation of this vector space morphism.
     922
     923        EXAMPLE::
     924
     925            sage: H = Hom(QQ^3, QQ^2)
     926            sage: f = H(matrix(3, 2, range(6)))
     927            sage: f._latex_().split(' ')
     928            ['\\texttt{vector', 'space', 'morphism', 'from',
     929            '}\n\\Bold{Q}^{3}\\texttt{', 'to', '}\n\\Bold{Q}^{2}\\texttt{',
     930            'represented', 'by', 'the', 'matrix',
     931            '}\n\\left(\\begin{array}{rr}\n0', '&', '1',
     932            '\\\\\n2', '&', '3', '\\\\\n4', '&', '5\n\\end{array}\\right)']
     933        """
     934        from sage.misc.latex import latex
     935        s = ('\\texttt{vector space morphism from }\n', self.domain()._latex_(),
     936             '\\texttt{ to }\n', self.codomain()._latex_(),
     937             '\\texttt{ represented by the matrix }\n', self.matrix()._latex_())
     938        return ''.join(s)
     939
     940    def _repr_(self):
     941        r"""
     942        A text representation of this vector space morphism.
     943
     944        EXAMPLE::
     945
     946            sage: H = Hom(QQ^3, QQ^2)
     947            sage: f = H(matrix(3, 2, range(6)))
     948            sage: f._repr_().split(' ')
     949            ['Vector', 'space', 'morphism', 'represented', 'by',
     950            'the', 'matrix:\n[0', '1]\n[2', '3]\n[4', '5]\nDomain:',
     951            'Vector', 'space', 'of', 'dimension', '3', 'over',
     952            'Rational', 'Field\nCodomain:', 'Vector', 'space', 'of',
     953            'dimension', '2', 'over', 'Rational', 'Field']
     954        """
     955        m = self.matrix()
     956        msg = ("Vector space morphism represented by the matrix:\n",
     957               "{0}\n",
     958               "Domain: {1}\n",
     959               "Codomain: {2}")
     960        return ''.join(msg).format(m, self.domain(), self.codomain())