# Ticket #10604: trac_10604-diagonal-matrix-constructor.patch

File trac_10604-diagonal-matrix-constructor.patch, 10.9 KB (added by rbeezer, 11 years ago)
• ## sage/matrix/constructor.py

```# HG changeset patch
# User Rob Beezer <beezer@ups.edu>
# Date 1294868691 28800
# Node ID 2583fb7bbaa05ecc4989fac8f788b2044f41ef89
# Parent  3b5f79f2d47e5ec182180673a97a3e7bd4fdefb1
10604: rewrite diagonal matrix constructor, support NumPy input

diff -r 3b5f79f2d47e -r 2583fb7bbaa0 sage/matrix/constructor.py```
 a raise ValueError('random matrix algorithm "%s" is not recognized' % algorithm) def diagonal_matrix(arg0=None, arg1=None, arg2=None, sparse=None): """ def diagonal_matrix(arg0=None, arg1=None, arg2=None, sparse=True): r""" Return a square matrix with specified diagonal entries, and zeros elsewhere. FORMATS: 1. diagonal_matrix(entries) 2. diagonal_matrix(nrows, entries) 3. diagonal_matrix(ring, entries) 4. diagonal_matrix(ring, nrows, entries) INPUT: - ``entries`` - the values to place along the diagonal of the returned matrix.  This may be a flat list, a flat tuple, a vector or free module element, or a one-dimensional NumPy array. - ``nrows`` - the size of the returned matrix, which will have an equal number of columns - ``ring`` - the ring containing the entries of the diagonal entries.  This may not be specified in combination with a NumPy array. - ``sparse`` - default: ``True`` - whether or not the result has a sparse implementation. Supported formats 1. diagonal_matrix(diagonal_entries, [sparse=True]): diagonal matrix with flat list of entries 2. diagonal_matrix(nrows, diagonal_entries, [sparse=True]): diagonal matrix with flat list of entries and the rest zeros 3. diagonal_matrix(ring, diagonal_entries, [sparse=True]): diagonal matrix over specified ring with flat list of entries 4. diagonal_matrix(ring, nrows, diagonal_entries, [sparse=True]): diagonal matrix over specified ring with flat list of entries and the rest zeros 5. diagonal_matrix(vect, [sparse=True]): diagonal matrix with entries taken from a vector The sparse option is optional, must be explicitly named (i.e., sparse=True), and may be either True or False. OUTPUT: A square matrix over the given ``ring`` with a size given by ``nrows``.  If the ring is not given it is inferred from the given entries.  The values on the diagonal of the returned matrix come from ``entries``. If the number of entries is not enough to fill the whole diagonal, it is padded with zeros. EXAMPLES: Input format 1:: sage: diagonal_matrix([1,2,3]) We first demonstrate each of the input formats with various different ways to specify the entries. Format 1: a flat list of entries.  :: sage: A = diagonal_matrix([2, 1.3, 5]); A [ 2.00000000000000 0.000000000000000 0.000000000000000] [0.000000000000000  1.30000000000000 0.000000000000000] [0.000000000000000 0.000000000000000  5.00000000000000] sage: A.parent() Full MatrixSpace of 3 by 3 sparse matrices over Real Field with 53 bits of precision Format 2: size specified, a tuple with initial entries. Note that a short list of entries is effectively padded with zeros.  :: sage: A = diagonal_matrix(3, (4, 5)); A [4 0 0] [0 5 0] [0 0 0] sage: A.parent() Full MatrixSpace of 3 by 3 sparse matrices over Integer Ring Format 3: ring specified, a vector of entries. :: sage: A = diagonal_matrix(QQ, vector(ZZ, [1,2,3])); A [1 0 0] [0 2 0] [0 0 3] sage: A.parent() Full MatrixSpace of 3 by 3 sparse matrices over Rational Field Format 4: ring, size and list of entries. :: Input format 2:: sage: A = diagonal_matrix(FiniteField(3), 3, [2, 16]); A [2 0 0] [0 1 0] [0 0 0] sage: A.parent() Full MatrixSpace of 3 by 3 sparse matrices over Finite Field of size 3 NumPy arrays may be used as input, without giving a ring.  Resulting matrices have ``RDF`` or ``CDF`` for base rings. :: sage: diagonal_matrix(3, [1,2]) sage: import numpy sage: entries = numpy.array([1.2, 5.6]); entries array([ 1.2,  5.6]) sage: A = diagonal_matrix(3, entries); A [1.2 0.0 0.0] [0.0 5.6 0.0] [0.0 0.0 0.0] sage: A.parent() Full MatrixSpace of 3 by 3 sparse matrices over Real Double Field sage: j = numpy.complex(0,1) sage: entries = numpy.array([2.0+j, 8.1, 3.4+2.6*j]); entries array([ 2.0+1.j ,  8.1+0.j ,  3.4+2.6j]) sage: A = diagonal_matrix(entries); A [2.0 + 1.0*I           0           0] [          0         8.1           0] [          0           0 3.4 + 2.6*I] sage: A.parent() Full MatrixSpace of 3 by 3 sparse matrices over Complex Double Field By default returned matrices have a sparse implementation.  This can be changed when using any of the formats.  :: sage: A = diagonal_matrix([1,2,3], sparse=False) sage: A.parent() Full MatrixSpace of 3 by 3 dense matrices over Integer Ring Giving the entries improperly may first complain about not having a length.  :: sage: diagonal_matrix(QQ, 5, 10) Traceback (most recent call last): ... TypeError: unable to determine number of entries for diagonal matrix construction Giving too many entries will raise an error. :: sage: diagonal_matrix(QQ, 3, [1,2,3,4]) Traceback (most recent call last): ... ValueError: number of diagonal matrix entries (4) exceeds the requested matrix size (3) You cannot specify a ring with a NumPy array since the ring is determined automatically, though you can change it after the fact.  Also, the dimensionality of the NumPy array is checked. :: sage: import numpy sage: entries = numpy.array([1.2, 1.3]) sage: diagonal_matrix(RDF, entries) Traceback (most recent call last): ... ValueError: cannot specify ring for diagonal matrix constructor with a NumPy array sage: entries = numpy.array([1.0, 2.0, 3.0]) sage: A = diagonal_matrix(3, entries) sage: B = A.change_ring(ZZ); B [1 0 0] [0 2 0] [0 0 0] [0 0 3] sage: B.parent() Full MatrixSpace of 3 by 3 sparse matrices over Integer Ring sage: entries = numpy.array([[1.2], [1.3]]) sage: entries.shape (2, 1) sage: diagonal_matrix(entries) Traceback (most recent call last): ... TypeError: NumPy array for diagonal matrix constructor must be a 1-dimensional list A negative size sometimes causes the error that there are too many elements. :: Input format 3:: sage: diagonal_matrix(-2, [2]) Traceback (most recent call last): ... ValueError: number of diagonal matrix entries (1) exceeds the requested matrix size (-2) Types for the entries are limited, even though they may have a length.  :: sage: diagonal_matrix(GF(3), [1,2,3]) [1 0 0] [0 2 0] [0 0 0] sage: diagonal_matrix(x^2) Traceback (most recent call last): ... TypeError: diagonal matrix entries are not a supported type (list, tuple, vector, or NumPy array) AUTHOR: Input format 4:: - Rob Beezer (2011-01-11): total rewrite """ # Roll arguments forward # Lead with a ring? # Formats 3, 4, else remains None ring = None if rings.is_Ring(arg0): ring = arg0 arg0 = arg1 arg1 = arg2 # Size of matrix specified? # Formats 2, 4 nrows = None if isinstance(arg0, (int, long, rings.Integer)): nrows = arg0 arg0 = arg1 # Object holding entries # Formats 1, 2, 3, 4 entries = arg0 sage: diagonal_matrix(GF(3), 3, [8,2]) [2 0 0] [0 2 0] [0 0 0] # Reconcile matrix size and number of entries try: nentries = len(entries) except TypeError: raise TypeError('unable to determine number of entries for diagonal matrix construction') # sometimes catches a negative size if not nrows is None and nentries > nrows: raise ValueError('number of diagonal matrix entries (%s) exceeds the requested matrix size (%s)' % (nentries, nrows)) if nrows is None: nrows = nentries Input format 5:: sage: diagonal_matrix(vector(GF(3),[1,2,3])) [1 0 0] [0 2 0] [0 0 0] """ ring = None if isinstance(arg0, (list, tuple)): # Format 1 v = arg0 nrows = len(v) elif isinstance(arg0, (int, long, rings.Integer)): # Format 2 nrows = arg0 v = arg1 elif rings.is_Ring(arg0): ring = arg0 if isinstance(arg1, (list, tuple)): # Format 3 v = arg1 nrows = len(v) else: # Format 4 nrows = arg1 v = arg2 elif is_Vector(arg0): # Format 5 v = list(arg0) nrows = len(v) if isinstance(v, list): w = {} for i in range(len(v)): w[(i,i)] = v[i] # Convert entries to a list v from numpy import ndarray if isinstance(entries, (list, tuple)) or is_Vector(entries): v = list(entries) elif isinstance(entries, ndarray): if not ring is None: raise ValueError('cannot specify ring for diagonal matrix constructor with a NumPy array') if not len(entries.shape)==1: raise TypeError('NumPy array for diagonal matrix constructor must be a 1-dimensional list') # Set ring and convert NumPy types to Sage types if str(entries.dtype).count('float')==1: ring = RDF if str(entries.dtype).count('complex')==1: ring = CDF v = [ring(x) for x in entries] else: w = v raise TypeError('diagonal matrix entries are not a supported type (list, tuple, vector, or NumPy array)') # Create a "diagonal" dictionary for matrix constructor # If nentries < nrows, diagonal is effectively padded with zeros at end w = {} for i in range(len(v)): w[(i,i)] = v[i] # Ship ring, matrix size, dictionary to matrix constructor if ring is None: return matrix(nrows, nrows, w, sparse=sparse) else: