Ticket #11553: trac_11553-matrix-morphisms-additions-v3.patch

File trac_11553-matrix-morphisms-additions-v3.patch, 19.7 KB (added by rbeezer, 23 months ago)
  • sage/modules/matrix_morphism.py

    # HG changeset patch
    # User Rob Beezer <beezer@ups.edu>
    # Date 1309303921 25200
    # Node ID 2c5ad01c9e18f83ec0086dc382f60d5c8041f3b4
    # Parent  e2d2c3ff0e9d631be7133e221c0a0f8b573c4d2c
    11553: matrix morphisms,  additional methods
    
    diff --git a/sage/modules/matrix_morphism.py b/sage/modules/matrix_morphism.py
    a b  
    4747- William Stein (2005-01-07): added __reduce__ 
    4848 
    4949- Craig Citro (2008-03-18): refactored MatrixMorphism class 
     50 
     51- Rob Beezer (2011-07-15): additional methods, bug fixes, documentation 
    5052""" 
    5153 
    52  
    5354import sage.categories.morphism 
    5455import sage.categories.homset 
    5556import sage.matrix.all as matrix 
     
    192193        except TypeError: 
    193194            raise ZeroDivisionError, "matrix morphism not invertible" 
    194195 
     196    def inverse(self): 
     197        r""" 
     198        Returns the inverse of this matrix morphism, if the inverse exists. 
     199 
     200        Raises a ``ZeroDivisionError`` if the inverse does not exist. 
     201 
     202        EXAMPLES: 
     203 
     204        An invertible morphism created as a restriction of 
     205        a non-invertible morphism, and which has an unequal 
     206        domain and codomain.  :: 
     207 
     208            sage: V = QQ^4 
     209            sage: W = QQ^3 
     210            sage: m = matrix(QQ, [[2, 0, 3], [-6, 1, 4], [1, 2, -4], [1, 0, 1]]) 
     211            sage: phi = V.hom(m, W) 
     212            sage: rho = phi.restrict_domain(V.span([V.0, V.3])) 
     213            sage: zeta = rho.restrict_codomain(W.span([W.0, W.2])) 
     214            sage: x = vector(QQ, [2, 0, 0, -7]) 
     215            sage: y = zeta(x); y 
     216            (-3, 0, -1) 
     217            sage: inv = zeta.inverse(); inv 
     218            Free module morphism defined by the matrix 
     219            [-1  3] 
     220            [ 1 -2] 
     221            Domain: Vector space of degree 3 and dimension 2 over Rational Field 
     222            Basis ... 
     223            Codomain: Vector space of degree 4 and dimension 2 over Rational Field 
     224            Basis ... 
     225            sage: inv(y) == x 
     226            True 
     227 
     228        An example of an invertible morphism between modules, 
     229        (rather than between vector spaces).  :: 
     230 
     231            sage: M = ZZ^4 
     232            sage: p = matrix(ZZ, [[ 0, -1,  1, -2], 
     233            ...                   [ 1, -3,  2, -3], 
     234            ...                   [ 0,  4, -3,  4], 
     235            ...                   [-2,  8, -4,  3]]) 
     236            sage: phi = M.hom(p, M) 
     237            sage: x = vector(ZZ, [1, -3, 5, -2]) 
     238            sage: y = phi(x); y 
     239            (1, 12, -12, 21) 
     240            sage: rho = phi.inverse(); rho 
     241            Free module morphism defined by the matrix 
     242            [ -5   3  -1   1] 
     243            [ -9   4  -3   2] 
     244            [-20   8  -7   4] 
     245            [ -6   2  -2   1] 
     246            Domain: Ambient free module of rank 4 over the principal ideal domain ... 
     247            Codomain: Ambient free module of rank 4 over the principal ideal domain ... 
     248            sage: rho(y) == x 
     249            True 
     250 
     251        A non-invertible morphism, despite having an appropriate 
     252        domain and codomain.  :: 
     253 
     254            sage: V = QQ^2 
     255            sage: m = matrix(QQ, [[1, 2], [20, 40]]) 
     256            sage: phi = V.hom(m, V) 
     257            sage: phi.is_bijective() 
     258            False 
     259            sage: phi.inverse() 
     260            Traceback (most recent call last): 
     261            ... 
     262            ZeroDivisionError: matrix morphism not invertible 
     263 
     264        The matrix representation of this morphism is invertible 
     265        over the rationals, but not over the integers, thus the 
     266        morphism is not invertible as a map between modules. 
     267        It is easy to notice from the definition that every 
     268        vector of the image will have a second entry that 
     269        is an even integer.  :: 
     270 
     271            sage: V = ZZ^2 
     272            sage: q = matrix(ZZ, [[1, 2], [3, 4]]) 
     273            sage: phi = V.hom(q, V) 
     274            sage: phi.matrix().change_ring(QQ).inverse() 
     275            [  -2    1] 
     276            [ 3/2 -1/2] 
     277            sage: phi.is_bijective() 
     278            False 
     279            sage: phi.image() 
     280            Free module of degree 2 and rank 2 over Integer Ring 
     281            Echelon basis matrix: 
     282            [1 0] 
     283            [0 2] 
     284            sage: phi.lift(vector(ZZ, [1, 1])) 
     285            Traceback (most recent call last): 
     286            ... 
     287            ValueError: element is not in the image 
     288            sage: phi.inverse() 
     289            Traceback (most recent call last): 
     290            ... 
     291            ZeroDivisionError: matrix morphism not invertible 
     292 
     293        The unary invert operator (~, tilde, "wiggle") is synonymous 
     294        with the ``inverse()`` method (and a lot easier to type).  :: 
     295 
     296            sage: V = QQ^2 
     297            sage: r = matrix(QQ, [[4, 3], [-2, 5]]) 
     298            sage: phi = V.hom(r, V) 
     299            sage: rho = phi.inverse() 
     300            sage: zeta = ~phi 
     301            sage: rho == zeta 
     302            True 
     303 
     304        TESTS:: 
     305 
     306            sage: V = QQ^2 
     307            sage: W = QQ^3 
     308            sage: U = W.span([W.0, W.1]) 
     309            sage: m = matrix(QQ, [[2, 1], [3, 4]]) 
     310            sage: phi = V.hom(m, U) 
     311            sage: inv = phi.inverse() 
     312            sage: (inv*phi).is_identity() 
     313            True 
     314            sage: (phi*inv).is_identity() 
     315            True 
     316        """ 
     317        return self.__invert__() 
     318 
    195319    def __rmul__(self, left): 
    196320        """ 
    197321        EXAMPLES:: 
     
    446570                                         check=False) for V, _ in E], 
    447571                            cr=True, check=False) 
    448572 
     573    def trace(self): 
     574        """ 
     575        EXAMPLES:: 
     576 
     577            sage: V = ZZ^2; phi = V.hom([V.0+V.1, 2*V.1]) 
     578            sage: phi.trace() 
     579            3 
     580        """ 
     581        return self.matrix().trace() 
     582 
    449583    def det(self): 
    450584        """ 
    451585        Return the determinant of this endomorphism. 
     
    568702        raise NotImplementedError, "this method must be overridden in the extension class" 
    569703 
    570704    def rank(self): 
    571         """ 
     705        r""" 
     706        Returns the rank of the matrix representing this morphism. 
     707 
    572708        EXAMPLES:: 
    573          
     709 
    574710            sage: V = ZZ^2; phi = V.hom(V.basis()) 
    575711            sage: phi.rank() 
    576712            2 
     
    580716        """ 
    581717        return self.matrix().rank() 
    582718 
     719    def nullity(self): 
     720        r""" 
     721        Returns the nullity of the matrix representing this morphism. 
     722 
     723        EXAMPLES:: 
     724 
     725            sage: V = ZZ^2; phi = V.hom(V.basis()) 
     726            sage: phi.nullity() 
     727            0 
     728            sage: V = ZZ^2; phi = V.hom([V.0, V.0]) 
     729            sage: phi.nullity() 
     730            1 
     731        """ 
     732        return self.matrix().left_nullity() 
     733 
     734    def is_injective(self): 
     735        r""" 
     736        Tell whether ``self`` is injective. 
     737 
     738        EXAMPLE:: 
     739 
     740            sage: V1 = QQ^2 
     741            sage: V2 = QQ^3 
     742            sage: phi = V1.hom(Matrix([[1,2],[3,4],[5,6]]),V2) 
     743            sage: phi.is_injective() 
     744            True 
     745            sage: psi = V2.hom(Matrix([[1,2,3],[4,5,6]]),V1) 
     746            sage: psi.is_injective() 
     747            False 
     748 
     749        AUTHOR: 
     750 
     751        -- Simon King (2010-05) 
     752        """ 
     753        return self._matrix.kernel().dimension() == 0 
     754 
     755    def is_surjective(self): 
     756        r""" 
     757        Tell whether ``self`` is surjective. 
     758 
     759        EXAMPLES:: 
     760 
     761            sage: V1 = QQ^2 
     762            sage: V2 = QQ^3 
     763            sage: phi = V1.hom(Matrix([[1,2],[3,4],[5,6]]), V2) 
     764            sage: phi.is_surjective() 
     765            False 
     766            sage: psi = V2.hom(Matrix([[1,2,3],[4,5,6]]), V1) 
     767            sage: psi.is_surjective() 
     768            True 
     769 
     770        An example over a PID that is not `\ZZ`.  :: 
     771 
     772            sage: R = PolynomialRing(QQ, 'x') 
     773            sage: A = R^2 
     774            sage: B = R^2 
     775            sage: H = A.hom([B([x^2-1, 1]), B([x^2, 1])]) 
     776            sage: H.image() 
     777            Free module of degree 2 and rank 2 over Univariate Polynomial Ring in x over Rational Field 
     778            Echelon basis matrix: 
     779            [ 1  0] 
     780            [ 0 -1] 
     781            sage: H.is_surjective() 
     782            True 
     783 
     784        This tests if Trac #11552 is fixed. :: 
     785 
     786            sage: V = ZZ^2 
     787            sage: m = matrix(ZZ, [[1,2],[0,2]]) 
     788            sage: phi = V.hom(m, V) 
     789            sage: phi.lift(vector(ZZ, [0, 1])) 
     790            Traceback (most recent call last): 
     791            ... 
     792            ValueError: element is not in the image 
     793            sage: phi.is_surjective() 
     794            False 
     795 
     796        AUTHORS: 
     797 
     798        - Simon King (2010-05) 
     799        - Rob Beezer (2011-06-28) 
     800        """ 
     801        # Testing equality of free modules over PIDs is unreliable 
     802        #   see Trac #11579 for explanation and status 
     803        # We test if image equals codomain with two inclusions 
     804        #   reverse inclusion of below is trivially true 
     805        return self.codomain().is_submodule(self.image()) 
     806 
     807    def is_bijective(self): 
     808        r""" 
     809        Tell whether ``self`` is bijective. 
     810 
     811        EXAMPLES: 
     812 
     813        Two morphisms that are obviously not bijective, simply on 
     814        considerations of the dimensions.  However, each fullfills 
     815        half of the requirements to be a bijection.  :: 
     816 
     817            sage: V1 = QQ^2 
     818            sage: V2 = QQ^3 
     819            sage: m = matrix(QQ, [[1,2],[3,4],[5,6]]) 
     820            sage: phi = V1.hom(m, V2) 
     821            sage: phi.is_injective() 
     822            True 
     823            sage: phi.is_bijective() 
     824            False 
     825            sage: rho = V2.hom(m.transpose(), V1) 
     826            sage: rho.is_surjective() 
     827            True 
     828            sage: rho.is_bijective() 
     829            False 
     830 
     831        We construct a simple bijection between two one-dimensional 
     832        vector spaces.  :: 
     833 
     834            sage: V1 = QQ^3 
     835            sage: V2 = QQ^2 
     836            sage: phi = V1.hom(matrix(QQ, [[1, 2, 3], [4, 5, 6]]), V2) 
     837            sage: x = vector(QQ, [1, -1, 4]) 
     838            sage: y = phi(x); y 
     839            (18, 22) 
     840            sage: rho = phi.restrict_domain(V1.span([x])) 
     841            sage: zeta = rho.restrict_codomain(V2.span([y])) 
     842            sage: zeta.is_bijective() 
     843            True 
     844 
     845        AUTHOR: 
     846 
     847        - Rob Beezer (2011-06-28) 
     848        """ 
     849        return self.is_injective() and self.is_surjective() 
     850 
     851    def is_identity(self): 
     852        r""" 
     853        Determines if this morphism is an identity function or not. 
     854 
     855        EXAMPLES: 
     856 
     857        A homomorphism that cannot possibly be the identity 
     858        due to an unequal domain and codomain.  :: 
     859 
     860            sage: V = QQ^3 
     861            sage: W = QQ^2 
     862            sage: m = matrix(QQ, [[1, 2], [3, 4], [5, 6]]) 
     863            sage: phi = V.hom(m, W) 
     864            sage: phi.is_identity() 
     865            False 
     866 
     867        A bijection, but not the identity. :: 
     868 
     869            sage: V = QQ^3 
     870            sage: n = matrix(QQ, [[3, 1, -8], [5, -4, 6], [1, 1, -5]]) 
     871            sage: phi = V.hom(n, V) 
     872            sage: phi.is_bijective() 
     873            True 
     874            sage: phi.is_identity() 
     875            False 
     876 
     877        A restriction that is the identity.  :: 
     878 
     879            sage: V = QQ^3 
     880            sage: p = matrix(QQ, [[1, 0, 0], [5, 8, 3], [0, 0, 1]]) 
     881            sage: phi = V.hom(p, V) 
     882            sage: rho = phi.restrict(V.span([V.0, V.2])) 
     883            sage: rho.is_identity() 
     884            True 
     885 
     886        An identity linear transformation that is defined with a 
     887        domain and codomain with wildly different bases, so that the 
     888        matrix representation is not simply the identity matrix. :: 
     889 
     890            sage: A = matrix(QQ, [[1, 1, 0], [2, 3, -4], [2, 4, -7]]) 
     891            sage: B = matrix(QQ, [[2, 7, -2], [-1, -3, 1], [-1, -6, 2]]) 
     892            sage: U = (QQ^3).subspace_with_basis(A.rows()) 
     893            sage: V = (QQ^3).subspace_with_basis(B.rows()) 
     894            sage: H = Hom(U, V) 
     895            sage: id = lambda x: x 
     896            sage: phi = H(id) 
     897            sage: phi([203, -179, 34]) 
     898            (203, -179, 34) 
     899            sage: phi.matrix() 
     900            [  1   0   1] 
     901            [ -9 -18  -2] 
     902            [-17 -31  -5] 
     903            sage: phi.is_identity() 
     904            True 
     905 
     906        TEST:: 
     907 
     908            sage: V = QQ^10 
     909            sage: H = Hom(V, V) 
     910            sage: id = H.identity() 
     911            sage: id.is_identity() 
     912            True 
     913 
     914        AUTHOR: 
     915 
     916        - Rob Beezer (2011-06-28) 
     917        """ 
     918        if self.domain() != self.codomain(): 
     919            return False 
     920        # testing for the identity matrix will only work for 
     921        #   endomorphisms which have the same basis for domain and codomain 
     922        #   so we test equality on a basis, which is sufficient 
     923        return all( self(u) == u for u in self.domain().basis() ) 
     924 
     925    def is_zero(self): 
     926        r""" 
     927        Determines if this morphism is a zero function or not. 
     928 
     929        EXAMPLES: 
     930 
     931        A zero morphism created from a function.  :: 
     932 
     933            sage: V = ZZ^5 
     934            sage: W = ZZ^3 
     935            sage: z = lambda x: zero_vector(ZZ, 3) 
     936            sage: phi = V.hom(z, W) 
     937            sage: phi.is_zero() 
     938            True 
     939 
     940        An image list that just barely makes a non-zero morphism.  :: 
     941 
     942            sage: V = ZZ^4 
     943            sage: W = ZZ^6 
     944            sage: z = zero_vector(ZZ, 6) 
     945            sage: images = [z, z, W.5, z] 
     946            sage: phi = V.hom(images, W) 
     947            sage: phi.is_zero() 
     948            False 
     949 
     950        TEST:: 
     951 
     952            sage: V = QQ^10 
     953            sage: W = QQ^3 
     954            sage: H = Hom(V, W) 
     955            sage: rho = H.zero() 
     956            sage: rho.is_zero() 
     957            True 
     958 
     959        AUTHOR: 
     960 
     961        - Rob Beezer (2011-07-15) 
     962        """ 
     963        # any nonzero entry in any matrix representation 
     964        #   disqualifies the morphism as having totally zero outputs 
     965        return self.matrix().is_zero() 
     966 
     967    def is_equal_function(self, other): 
     968        r""" 
     969        Determines if two morphisms are equal functions. 
     970 
     971        INPUT: 
     972 
     973        - ``other`` - a morphism to compare with ``self`` 
     974 
     975        OUTPUT: 
     976 
     977        Returns ``True`` precisely when the two morphisms have 
     978        equal domains and codomains (as sets) and produce identical 
     979        output when given the same input.  Otherwise returns ``False``. 
     980 
     981        This is useful when ``self`` and ``other`` may have different 
     982        representations. 
     983 
     984        Sage's default comparison of matrix morphisms requires the 
     985        domains to have the same bases and the codomains to have the 
     986        same bases, and then compares the matrix representations. 
     987        This notion of equality is more permissive (it will 
     988        return ``True`` "more often"), but is more correct 
     989        mathematically. 
     990 
     991        EXAMPLES: 
     992 
     993        Three morphisms defined by combinations of different 
     994        bases for the domain and codomain and different functions. 
     995        Two are equal, the third is different from both of the others.  :: 
     996 
     997            sage: B = matrix(QQ, [[-3,  5, -4,  2], 
     998            ...                   [-1,  2, -1,  4], 
     999            ...                   [ 4, -6,  5, -1], 
     1000            ...                   [-5,  7, -6,  1]]) 
     1001            sage: U = (QQ^4).subspace_with_basis(B.rows()) 
     1002            sage: C = matrix(QQ, [[-1, -6, -4], 
     1003            ...                   [ 3, -5,  6], 
     1004            ...                   [ 1,  2,  3]]) 
     1005            sage: V = (QQ^3).subspace_with_basis(C.rows()) 
     1006            sage: H = Hom(U, V) 
     1007 
     1008            sage: D = matrix(QQ, [[-7, -2, -5,  2], 
     1009            ...                   [-5,  1, -4, -8], 
     1010            ...                   [ 1, -1,  1,  4], 
     1011            ...                   [-4, -1, -3,   1]]) 
     1012            sage: X = (QQ^4).subspace_with_basis(D.rows()) 
     1013            sage: E = matrix(QQ, [[ 4, -1,  4], 
     1014            ...                   [ 5, -4, -5], 
     1015            ...                   [-1,  0, -2]]) 
     1016            sage: Y = (QQ^3).subspace_with_basis(E.rows()) 
     1017            sage: K = Hom(X, Y) 
     1018 
     1019            sage: f = lambda x: vector(QQ, [x[0]+x[1], 2*x[1]-4*x[2], 5*x[3]]) 
     1020            sage: g = lambda x: vector(QQ, [x[0]-x[2], 2*x[1]-4*x[2], 5*x[3]]) 
     1021 
     1022            sage: rho = H(f) 
     1023            sage: phi = K(f) 
     1024            sage: zeta = H(g) 
     1025 
     1026            sage: rho.is_equal_function(phi) 
     1027            True 
     1028            sage: phi.is_equal_function(rho) 
     1029            True 
     1030            sage: zeta.is_equal_function(rho) 
     1031            False 
     1032            sage: phi.is_equal_function(zeta) 
     1033            False 
     1034 
     1035        TEST:: 
     1036 
     1037            sage: H = Hom(ZZ^2, ZZ^2) 
     1038            sage: phi = H(matrix(ZZ, 2, range(4))) 
     1039            sage: phi.is_equal_function('junk') 
     1040            Traceback (most recent call last): 
     1041            ... 
     1042            TypeError: can only compare to a matrix morphism, not junk 
     1043 
     1044        AUTHOR: 
     1045 
     1046        - Rob Beezer (2011-07-15) 
     1047        """ 
     1048        if not is_MatrixMorphism(other): 
     1049            msg = 'can only compare to a matrix morphism, not {0}' 
     1050            raise TypeError(msg.format(other)) 
     1051        if self.domain() != other.domain(): 
     1052            return False 
     1053        if self.codomain() != other.codomain(): 
     1054            return False 
     1055        # check agreement on any basis of the domain 
     1056        return all( self(u) == other(u) for u in self.domain().basis() ) 
     1057 
    5831058    def restrict_domain(self, sub): 
    5841059        """ 
    5851060        Restrict this matrix morphism to a subspace sub of the domain. The 
     
    7381213        A = self.matrix().restrict(V) 
    7391214        H = sage.categories.homset.End(sub, self.domain().category()) 
    7401215        return H(A) 
    741          
    742     def trace(self): 
    743         """ 
    744         EXAMPLES:: 
    7451216 
    746             sage: V = ZZ^2; phi = V.hom([V.0+V.1, 2*V.1]) 
    747             sage: phi.trace() 
    748             3 
    749         """ 
    750         return self.matrix().trace() 
    7511217 
    7521218class MatrixMorphism(MatrixMorphism_abstract): 
    7531219    """ 
     
    7981264        """ 
    7991265        return self._matrix 
    8001266 
    801     def is_injective(self): 
    802         """ 
    803         Tell whether ``self`` is injective. 
    804  
    805         EXAMPLE:: 
    806  
    807             sage: V1 = QQ^2 
    808             sage: V2 = QQ^3 
    809             sage: phi = V1.hom(Matrix([[1,2],[3,4],[5,6]]),V2) 
    810             sage: phi.is_injective() 
    811             True 
    812             sage: psi = V2.hom(Matrix([[1,2,3],[4,5,6]]),V1) 
    813             sage: psi.is_injective() 
    814             False 
    815  
    816         AUTHOR: 
    817  
    818         -- Simon King (2010-05) 
    819         """ 
    820         return self._matrix.kernel().dimension() == 0 
    821  
    822     def is_surjective(self): 
    823         r""" 
    824         Tell whether ``self`` is surjective. 
    825  
    826         EXAMPLES:: 
    827  
    828             sage: V1 = QQ^2 
    829             sage: V2 = QQ^3 
    830             sage: phi = V1.hom(Matrix([[1,2],[3,4],[5,6]]), V2) 
    831             sage: phi.is_surjective() 
    832             False 
    833             sage: psi = V2.hom(Matrix([[1,2,3],[4,5,6]]), V1) 
    834             sage: psi.is_surjective() 
    835             True 
    836  
    837         An example over a PID that is not `\ZZ`.  :: 
    838  
    839             sage: R = PolynomialRing(QQ, 'x') 
    840             sage: A = R^2 
    841             sage: B = R^2 
    842             sage: H = A.hom([B([x^2-1, 1]), B([x^2, 1])]) 
    843             sage: H.image() 
    844             Free module of degree 2 and rank 2 over Univariate Polynomial Ring in x over Rational Field 
    845             Echelon basis matrix: 
    846             [ 1  0] 
    847             [ 0 -1] 
    848             sage: H.is_surjective() 
    849             True 
    850  
    851         This tests if Trac #11552 is fixed. :: 
    852  
    853             sage: V = ZZ^2 
    854             sage: m = matrix(ZZ, [[1,2],[0,2]]) 
    855             sage: phi = V.hom(m, V) 
    856             sage: phi.lift(vector(ZZ, [0, 1])) 
    857             Traceback (most recent call last): 
    858             ... 
    859             ValueError: element is not in the image 
    860             sage: phi.is_surjective() 
    861             False 
    862  
    863         AUTHORS: 
    864  
    865         - Simon King (2010-05) 
    866         - Rob Beezer (2011-06-28) 
    867         """ 
    868         # Testing equality of free modules over PIDs is unreliable 
    869         #   see Trac #11579 for explanation and status 
    870         # We test if image equals codomain with two inclusions 
    871         #   reverse inclusion of below is trivially true 
    872         return self.codomain().is_submodule(self.image()) 
    8731267 
    8741268    def _repr_(self): 
    8751269        """