Ticket #11114: trac_11114-diagonalizable-matrices.patch

File trac_11114-diagonalizable-matrices.patch, 7.7 KB (added by rbeezer, 11 years ago)
  • sage/matrix/matrix2.pyx

    # HG changeset patch
    # User Rob Beezer <beezer@ups.edu>
    # Date 1301691532 25200
    # Node ID 37d03ab8cb13ed4b98b33cab35d7d3647faaf0d1
    # Parent  6a679959b54b7975af1841df4dd77d28b0faef28
    11114: diagonalizable check for matrices
    
    diff -r 6a679959b54b -r 37d03ab8cb13 sage/matrix/matrix2.pyx
    a b  
    62996299            return J, transformation_matrix
    63006300        else:
    63016301            return J
    6302    
     6302
     6303    def is_diagonalizable(self, base_field=None):
     6304        r"""
     6305        Determines if the matrix is similar to a diagonal matrix.
     6306
     6307        INPUT:
     6308
     6309        - ``base_field`` - a new field to use for entries
     6310          of the matrix.
     6311
     6312        OUTPUT:
     6313
     6314        If ``self`` is the matrix `A`, then it is diagonalizable
     6315        if there is an invertible matrix `S` and a diagonal matrix
     6316        `D` such that
     6317
     6318        .. math::
     6319
     6320            S^{-1}AS = D
     6321
     6322        This routine returns ``True`` if ``self`` is diagonalizable.
     6323        The diagonal entries of the matrix `D` are the eigenvalues
     6324        of `A`.  It may be necessary to "increase" the base field to
     6325        contain all of the eigenvalues.  Over the rationals, the field
     6326        of algebraic integers, :mod:`sage.rings.qqbar` is a good choice.
     6327
     6328        To obtain the matrices `S` and `D` use the :meth:`jordan_form`
     6329        method with the ``transformation=True`` keyword.
     6330
     6331        ALGORITHM:
     6332
     6333        For each eigenvalue, this routine checks that the algebraic
     6334        multiplicity (number of occurences as a root of the characteristic
     6335        polynomial) is equal to the geometric multiplicity (dimension
     6336        of the eigenspace), which is sufficient to ensure a basis of
     6337        eigenvectors for the columns of `S`.
     6338
     6339        EXAMPLES:
     6340
     6341        A matrix that is diagonalizable over the rationals, as evidenced
     6342        by its Jordan form.  ::
     6343
     6344            sage: A = matrix(QQ, [[-7, 16, 12,  0,    6],
     6345            ...                   [-9, 15,  0,  12, -27],
     6346            ...                   [ 9, -8, 11, -12,  51],
     6347            ...                   [ 3, -4,  0,  -1,   9],
     6348            ...                   [-1,  0, -4,   4, -12]])
     6349            sage: A.jordan_form(subdivide=False)
     6350            [ 2  0  0  0  0]
     6351            [ 0  3  0  0  0]
     6352            [ 0  0  3  0  0]
     6353            [ 0  0  0 -1  0]
     6354            [ 0  0  0  0 -1]
     6355            sage: A.is_diagonalizable()
     6356            True
     6357
     6358        A matrix that is not diagonalizable over the rationals, as evidenced
     6359        by its Jordan form.  ::
     6360
     6361            sage: A = matrix(QQ, [[-3, -14, 2, -1, 15],
     6362            ...                   [4, 6, -2, 3, -8],
     6363            ...                   [-2, -14, 0, 0, 10],
     6364            ...                   [3, 13, -2, 0, -11],
     6365            ...                   [-1, 6, 1, -3, 1]])
     6366            sage: A.jordan_form(subdivide=False)
     6367            [-1  1  0  0  0]
     6368            [ 0 -1  0  0  0]
     6369            [ 0  0  2  1  0]
     6370            [ 0  0  0  2  1]
     6371            [ 0  0  0  0  2]
     6372            sage: A.is_diagonalizable()
     6373            False
     6374
     6375        If any eigenvalue of a matrix is outside the base ring, then
     6376        this routine raises an error.  However, the ring can be
     6377        "expanded" to contain the eigenvalues.  ::
     6378
     6379            sage: A = matrix(QQ, [[1,  0,  1,  1, -1],
     6380            ...                   [0,  1,  0,  4,  8],
     6381            ...                   [2,  1,  3,  5,  1],
     6382            ...                   [2, -1,  1,  0, -2],
     6383            ...                   [0, -1, -1, -5, -8]])
     6384
     6385            sage: [e in QQ for e in A.eigenvalues()]
     6386            [False, False, False, False, False]
     6387            sage: A.is_diagonalizable()
     6388            Traceback (most recent call last):
     6389            ...
     6390            RuntimeError: an eigenvalue of the matrix is not contained in Rational Field
     6391
     6392            sage: [e in QQbar for e in A.eigenvalues()]
     6393            [True, True, True, True, True]
     6394            sage: A.is_diagonalizable(base_field=QQbar)
     6395            True
     6396
     6397        Other exact fields may be employed, though it will not always
     6398        be possible to expand their base fields to contain all
     6399        the eigenvalues.  ::
     6400
     6401            sage: F.<b> = FiniteField(5^2)
     6402            sage: A = matrix(F, [[      4, 3*b + 2, 3*b + 1, 3*b + 4],
     6403            ...                  [2*b + 1,     4*b,       0,       2],
     6404            ...                  [    4*b,   b + 2, 2*b + 3,       3],
     6405            ...                  [    2*b,     3*b, 4*b + 4, 3*b + 3]])
     6406            sage: A.jordan_form()
     6407            [      4       1|      0       0]
     6408            [      0       4|      0       0]
     6409            [---------------+---------------]
     6410            [      0       0|2*b + 1       1]
     6411            [      0       0|      0 2*b + 1]
     6412            sage: A.is_diagonalizable()
     6413            False
     6414
     6415            sage: F.<c> = QuadraticField(-7)
     6416            sage: A = matrix(F, [[   c + 3,   2*c - 2,   -2*c + 2,     c - 1],
     6417            ...                  [2*c + 10, 13*c + 15, -13*c - 17, 11*c + 31],
     6418            ...                  [2*c + 10, 14*c + 10, -14*c - 12, 12*c + 30],
     6419            ...                  [       0,   2*c - 2,   -2*c + 2,   2*c + 2]])
     6420            sage: A.jordan_form(subdivide=False)
     6421            [    4     0     0     0]
     6422            [    0    -2     0     0]
     6423            [    0     0 c + 3     0]
     6424            [    0     0     0 c + 3]
     6425            sage: A.is_diagonalizable()
     6426            True
     6427
     6428        A trivial matrix is diagonalizable, trivially.  ::
     6429
     6430            sage: A = matrix(QQ, 0, 0)
     6431            sage: A.is_diagonalizable()
     6432            True
     6433
     6434        A matrix must be square to be diagonalizable. ::
     6435
     6436            sage: A = matrix(QQ, 3, 4)
     6437            sage: A.is_diagonalizable()
     6438            False
     6439
     6440        The matrix must have entries from a field,
     6441        and it must be an exact field.  ::
     6442
     6443            sage: A = matrix(ZZ, 4, range(16))
     6444            sage: A.is_diagonalizable()
     6445            Traceback (most recent call last):
     6446            ...
     6447            ValueError: matrix entries must be from a field, not Integer Ring
     6448
     6449            sage: A = matrix(RDF, 4, range(16))
     6450            sage: A.is_diagonalizable()
     6451            Traceback (most recent call last):
     6452            ...
     6453            ValueError: base field must be exact, not Real Double Field
     6454
     6455        AUTHOR:
     6456
     6457        - Rob Beezer (2011-04-01)
     6458        """
     6459        if not self.is_square():
     6460            return False
     6461        if not base_field is None:
     6462            self = self.change_ring(base_field)
     6463        if not self.base_ring().is_exact():
     6464            raise ValueError('base field must be exact, not {0}'.format(self.base_ring()))
     6465        if not self.base_ring().is_field():
     6466            raise ValueError('matrix entries must be from a field, not {0}'.format(self.base_ring()))
     6467
     6468        evals = self.charpoly().roots()
     6469        if sum([mult for (_,mult) in evals]) < self._nrows:
     6470            raise RuntimeError('an eigenvalue of the matrix is not contained in {0}'.format(self.base_ring()))
     6471
     6472        # Obtaining a generic minimal polynomial requires much more
     6473        # computation with kernels and their dimensions than the following.
     6474        # However, if a derived class has a fast minimal polynomial routine
     6475        # then overriding this by checking for repeated factors might be faster.
     6476
     6477        # check equality of algebraic multiplicity and geometric multiplicity
     6478        for e, am in evals:
     6479            gm = (self - e).right_kernel().dimension()
     6480            if am != gm:
     6481                return False
     6482        return True
     6483
    63036484    def symplectic_form(self):
    63046485        r"""
    63056486        Find a symplectic form for self if self is an anti-symmetric,