Ticket #11558: trac_11558_echelon_form_with_transformation.patch

File trac_11558_echelon_form_with_transformation.patch, 13.2 KB (added by vbraun, 10 years ago)

Updated patch

  • sage/matrix/matrix2.pyx

    # HG changeset patch
    # User Volker Braun <vbraun@stp.dias.ie>
    # Date 1309514846 -3600
    # Node ID fa3c1e7d52295677aaf5807c3f55228301f8ffdf
    # Parent  f6ee7b0c4308e20c34b530f35498f18dae555460
    Trac #11558: Echelonize with transformation=True oddness for sparse matrix
    
    diff -r f6ee7b0c4308 -r fa3c1e7d5229 sage/matrix/matrix2.pyx
    a b  
    52155215            )
    52165216            sage: E == T*m
    52175217            True
     5218
     5219        TESTS:
     5220
     5221        Check that http://trac.sagemath.org/sage_trac/ticket/11558 is fixed::
     5222
     5223            sage: matrix(ZZ, [[1,2],[4,6]], sparse=False).echelon_form(transformation=True)
     5224            (
     5225            [1 0]  [-3  1]
     5226            [0 2], [ 4 -1]
     5227            )
     5228            sage: matrix(ZZ, [[1,2],[4,6]], sparse=True).echelon_form(transformation=True)
     5229            (
     5230            [1 0]  [-3  1]
     5231            [0 2], [ 4 -1]
     5232            )
    52185233        """
    52195234        self.check_mutability()
    52205235        cdef Matrix d, a
    52215236        cdef Py_ssize_t r, c
     5237        cdef bint transformation = kwds.has_key('transformation') and kwds['transformation']
    52225238        if self._base_ring == ZZ:
    52235239            if kwds.has_key('include_zero_rows') and not kwds['include_zero_rows']:
    52245240                raise ValueError, "cannot echelonize in place and delete zero rows"
    5225             d = self.dense_matrix().echelon_form(**kwds)
     5241            if transformation:
     5242                d, a = self.dense_matrix().echelon_form(**kwds)
     5243            else:
     5244                d = self.dense_matrix().echelon_form(**kwds)
    52265245            for c from 0 <= c < self.ncols():
    52275246                for r from 0 <= r < self.nrows():
    52285247                    self.set_unsafe(r, c, d.get_unsafe(r,c))
    52295248            self.clear_cache()
    52305249            self.cache('pivots', d.pivots())
    52315250            self.cache('in_echelon_form', True)
    5232             return
    52335251        else:
    52345252            try:
    52355253                a, d, p = self._echelon_form_PID()
     
    52425260            self.clear_cache()
    52435261            self.cache('pivots', tuple(p))
    52445262            self.cache('in_echelon_form', True)
    5245             if kwds.has_key('transformation') and kwds['transformation']:
    5246                 return a
    5247             else:
    5248                 return
     5263        if transformation:
     5264            return a
     5265        else:
     5266            return
    52495267
    52505268    def echelonize(self, algorithm="default", cutoff=0, **kwds):
    52515269        r"""
    5252         Transform self into a matrix in echelon form over the same base
    5253         ring as self.
    5254        
    5255         INPUT:
    5256        
    5257        
    5258         -  ``algorithm`` - string, which algorithm to use
    5259            (default: 'default')
    5260        
    5261         -  ``'default'`` - use a default algorithm, chosen by
    5262            Sage
    5263        
    5264         -  ``'strassen'`` - use a Strassen divide and conquer
    5265            algorithm (if available)
    5266        
    5267         -  ``cutoff`` - integer; only used if the Strassen
    5268            algorithm is selected.
    5269        
     5270        Transform ``self`` into a matrix in echelon form over the same
     5271        base ring as self.
     5272       
     5273        .. note::
     5274
     5275            This row reduction does not use division if the
     5276            matrix is not over a field (e.g., if the matrix is over
     5277            the integers).  If you want to calculate the echelon form
     5278            using division, then use :meth:`rref`, which assumes that
     5279            the matrix entries are in a field (specifically, the field
     5280            of fractions of the base ring of the matrix).
     5281       
     5282        INPUT:       
     5283       
     5284        - ``algorithm`` -- string. Which algorithm to use. Choices are
     5285       
     5286          - ``'default'``: Let Sage choose an algorithm (default).
     5287       
     5288          - ``'classical'``: Gauss elimination.
     5289       
     5290          - ``'strassen'``: use a Strassen divide and conquer
     5291            algorithm (if available)
     5292       
     5293        - ``cutoff`` -- integer. Only used if the Strassen algorithm
     5294          is selected.
     5295
     5296        - ``transformation`` -- boolean. Whether to also return the
     5297          transformation matrix. Some matrix backends do not provide
     5298          this information, in which case this option is ignored.
     5299
     5300        OUTPUT:
     5301
     5302        The matrix ``self`` is put into echelon form. Nothing is
     5303        returned unless the keyword option ``transformation=True`` is
     5304        specified, in which case the transformation matrix is
     5305        returned.
    52705306       
    52715307        EXAMPLES::
    52725308       
     
    52875323            sage: a.echelonize()
    52885324            Traceback (most recent call last):
    52895325            ...
    5290             ValueError: matrix is immutable; please change a copy instead (i.e., use copy(M) to change a copy of M).
     5326            ValueError: matrix is immutable; please change a copy instead
     5327            (i.e., use copy(M) to change a copy of M).
    52915328            sage: a.echelon_form()
    52925329            [ 1  0 -1]
    52935330            [ 0  1  2]
     
    53395376            [ 1  0  2]
    53405377            [ 0  1 -1]
    53415378            [ 0  0  0]
     5379
     5380        The transformation matrix is optionally returned::
     5381
     5382            sage: m_original = m
     5383            sage: transformation_matrix = m.echelonize(transformation=True)
     5384            sage: m == transformation_matrix * m_original
     5385            True
    53425386        """
    53435387        self.check_mutability()
    53445388
     
    53745418            using division, then use :meth:`rref`, which assumes that
    53755419            the matrix entries are in a field (specifically, the field
    53765420            of fractions of the base ring of the matrix).
    5377 
    5378         INPUT:
    5379        
    5380        
    5381         -  ``matrix`` - an element A of a MatrixSpace
    5382        
     5421       
     5422        INPUT:       
     5423       
     5424        - ``algorithm`` -- string. Which algorithm to use. Choices are
     5425       
     5426          - ``'default'``: Let Sage choose an algorithm (default).
     5427       
     5428          - ``'classical'``: Gauss elimination.
     5429       
     5430          - ``'strassen'``: use a Strassen divide and conquer
     5431            algorithm (if available)
     5432       
     5433        - ``cutoff`` -- integer. Only used if the Strassen algorithm is selected.
     5434
     5435        - ``transformation`` -- boolean. Whether to also return the
     5436          transformation matrix. Some matrix backends do not provide
     5437          this information, in which case this option is ignored.
    53835438       
    53845439        OUTPUT:
    53855440       
    5386        
    5387         -  ``matrix`` - The reduced row echelon form of A, as
    5388            an immutable matrix. Note that self is *not* changed by this
    5389            command. Use A.echelonize() to change A in place.
    5390        
     5441        The reduced row echelon form of ``self``, as an immutable
     5442        matrix. Note that self is *not* changed by this command. Use
     5443        :meth:`echelonize` to change ``self`` in place.
     5444
     5445        If the optional parameter ``transformation=True`` is
     5446        specified, the output consists of a pair `(E,T)` of matrices
     5447        where `E` is the echelon form of ``self`` and `T` is the
     5448        transformation matrix.
    53915449       
    53925450        EXAMPLES::
    53935451       
     
    54005458            sage: C.echelon_form()
    54015459            [ 1  0 18]
    54025460            [ 0  1  2]
    5403         """
     5461
     5462        The matrix library used for `\ZZ/p`-matrices does not return
     5463        the transformation matrix, so the ``transformation`` option is
     5464        ignored::
     5465
     5466            sage: C.echelon_form(transformation=True)
     5467            [ 1  0 18]
     5468            [ 0  1  2]
     5469
     5470            sage: D = matrix(ZZ, 2, 3, [1,2,3,4,5,6])
     5471            sage: D.echelon_form(transformation=True)
     5472            (
     5473            [1 2 3]  [ 1  0]
     5474            [0 3 6], [ 4 -1]
     5475            )
     5476            sage: E, T = D.echelon_form(transformation=True)
     5477            sage: T*D == E
     5478            True
     5479        """
     5480        cdef bint transformation = (kwds.has_key('transformation') and kwds['transformation'])
    54045481        x = self.fetch('echelon_form')
    54055482        if x is not None:
    5406             if not (kwds.has_key('transformation') and kwds['transformation']):
     5483            if not transformation:
    54075484                return x
    54085485            y = self.fetch('echelon_transformation')
    54095486            if y:
    5410                 return x, y
     5487                return (x, y)
    54115488
    54125489        E = self.__copy__()
    54135490        if algorithm == 'default':
     
    54195496        if v is not None:
    54205497            self.cache('echelon_transformation', v)
    54215498        self.cache('pivots', E.pivots())
    5422         if v is not None and (kwds.has_key('transformation') and kwds['transformation']):
    5423             return E, v
     5499        if transformation and v is not None:
     5500            return (E, v)
    54245501        else:
    54255502            return E
    54265503       
  • sage/matrix/matrix_integer_dense.pyx

    diff -r f6ee7b0c4308 -r fa3c1e7d5229 sage/matrix/matrix_integer_dense.pyx
    a b  
    14211421        import sage.matrix.symplectic_basis
    14221422        return sage.matrix.symplectic_basis.symplectic_basis_over_ZZ(self)
    14231423
    1424     def hermite_form(self, *args, **kwds):
    1425         r"""
    1426         Return the Hermite normal form of self.
    1427        
    1428         This is a synonym for ``self.echelon_form(...)``. See
    1429         the documentation for ``self.echelon_form`` for more
    1430         details.
    1431        
    1432         EXAMPLES::
    1433        
    1434             sage: A = matrix(ZZ, 3, 5, [-1, -1, -2, 2, -2, -4, -19, -17, 1, 2, -3, 1, 1, -4, 1])
    1435             sage: E, U = A.hermite_form(transformation=True)
    1436             sage: E
    1437             [   1    0   52 -133  109]
    1438             [   0    1   19  -47   38]
    1439             [   0    0   69 -178  145]
    1440             sage: U
    1441             [-46   3  11]
    1442             [-16   1   4]
    1443             [-61   4  15]
    1444             sage: U*A
    1445             [   1    0   52 -133  109]
    1446             [   0    1   19  -47   38]
    1447             [   0    0   69 -178  145]
    1448             sage: A.hermite_form()
    1449             [   1    0   52 -133  109]
    1450             [   0    1   19  -47   38]
    1451             [   0    0   69 -178  145]
    1452        
    1453         TESTS: This example illustrated trac 2398.
    1454        
    1455         ::
    1456        
    1457             sage: a = matrix([(0, 0, 3), (0, -2, 2), (0, 1, 2), (0, -2, 5)])
    1458             sage: a.hermite_form()
    1459             [0 1 2]
    1460             [0 0 3]
    1461             [0 0 0]
    1462             [0 0 0]
    1463         """
    1464         return self.echelon_form(*args, **kwds)
     1424    hermite_form = echelon_form
    14651425
    14661426    def echelon_form(self, algorithm="default", proof=None, include_zero_rows=True,
    14671427                     transformation=False, D=None):
     
    14711431       
    14721432        INPUT:
    14731433
    1474 
    1475         - ``algorithm``
    1476 
    1477           --``'default'`` - max 10 rows or columns: pari with flag 0
    1478                             max 75 rows or columns: pari with flag 1
    1479                             larger -- use padic algorithm
    1480        
    1481           - ``'padic'`` - an asymptotically fast p-adic modular algorithm,
    1482                           If your matrix has large coefficients and is small,
    1483                           you may also want to try this.
     1434        - ``algorithm`` -- String. The algorithm to use. Valid options are:
     1435
     1436          - ``'default'`` -- Let Sage pick an algorithm (default). Up
     1437            to 10 rows or columns: pari with flag 0; Up to 75 rows or
     1438            columns: pari with flag 1; Larger: use padic algorithm.
     1439       
     1440          - ``'padic'`` - an asymptotically fast p-adic modular
     1441            algorithm, If your matrix has large coefficients and is
     1442            small, you may also want to try this.
    14841443
    14851444          - ``'pari'`` - use PARI with flag 1
    14861445
     
    14891448          - ``'pari4'`` - use PARI with flag 4 (use heuristic LLL)
    14901449
    14911450          - ``'ntl'`` - use NTL (only works for square matrices of
    1492                          full rank!)
     1451            full rank!)
    14931452       
    14941453        -  ``proof`` - (default: True); if proof=False certain
    14951454           determinants are computed using a randomized hybrid p-adic
     
    15071466           is 'ntl', then D must be a multiple of the determinant and this
    15081467           function will use that fact.
    15091468       
    1510        
    15111469        OUTPUT:
    15121470       
    1513        
    1514         -  ``matrix`` - the Hermite normal form (=echelon form
    1515            over ZZ) of self.
    1516        
    1517        
    1518         .. note::
    1519 
    1520            The result is cached.
     1471        The Hermite normal form (=echelon form over `\ZZ`) of self.
    15211472       
    15221473        EXAMPLES::
    15231474       
     
    16271578            [1 0 0]
    16281579            [0 1 0]
    16291580            [0 0 3]
     1581
     1582        TESTS:
     1583
     1584        This example illustrated trac 2398::
     1585       
     1586            sage: a = matrix([(0, 0, 3), (0, -2, 2), (0, 1, 2), (0, -2, 5)])
     1587            sage: a.hermite_form()
     1588            [0 1 2]
     1589            [0 0 3]
     1590            [0 0 0]
     1591            [0 0 0]
    16301592        """
    16311593        if self._nrows == 0 or self._ncols == 0:
    16321594            self.cache('pivots', ())
  • sage/matrix/matrix_integer_sparse.pyx

    diff -r f6ee7b0c4308 -r fa3c1e7d5229 sage/matrix/matrix_integer_sparse.pyx
    a b  
    492492        """
    493493        return self.dense_matrix()._right_kernel_matrix(**kwds)
    494494
     495    hermite_form = Matrix.echelon_form
    495496
    496497    def elementary_divisors(self, algorithm='pari'):
    497498        """
     
    594595
    595596           :meth:`elementary_divisors`
    596597        """
    597         return self.dense_matrix().smith_form()
    598  No newline at end of file
     598        return self.dense_matrix().smith_form()