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 b  
    11761176        raise ValueError('random matrix algorithm "%s" is not recognized' % algorithm)
    11771177
    11781178
    1179 def diagonal_matrix(arg0=None, arg1=None, arg2=None, sparse=None):
    1180     """
     1179def diagonal_matrix(arg0=None, arg1=None, arg2=None, sparse=True):
     1180    r"""
     1181    Return a square matrix with specified diagonal entries, and zeros elsewhere.
     1182   
     1183    FORMATS:
     1184   
     1185      1. diagonal_matrix(entries)
     1186     
     1187      2. diagonal_matrix(nrows, entries)
     1188     
     1189      3. diagonal_matrix(ring, entries)
     1190     
     1191      4. diagonal_matrix(ring, nrows, entries)
     1192 
    11811193    INPUT:
     1194   
     1195    - ``entries`` - the values to place along the diagonal
     1196      of the returned matrix.  This may be a flat list, a
     1197      flat tuple, a vector or free module element, or
     1198      a one-dimensional NumPy array.
     1199     
     1200    - ``nrows`` - the size of the returned matrix, which
     1201      will have an equal number of columns
     1202     
     1203    - ``ring`` - the ring containing the entries of the
     1204      diagonal entries.  This may not be specified in
     1205      combination with a NumPy array.
     1206     
     1207    - ``sparse`` - default: ``True`` - whether or not
     1208      the result has a sparse implementation.
    11821209
    1183     Supported formats
    1184 
    1185     1. diagonal_matrix(diagonal_entries, [sparse=True]):
    1186        diagonal matrix with flat list of entries
    1187 
    1188     2. diagonal_matrix(nrows, diagonal_entries, [sparse=True]):
    1189        diagonal matrix with flat list of entries and the rest zeros
    1190 
    1191     3. diagonal_matrix(ring, diagonal_entries, [sparse=True]):
    1192        diagonal matrix over specified ring with flat list of entries
    1193 
    1194     4. diagonal_matrix(ring, nrows, diagonal_entries, [sparse=True]):
    1195        diagonal matrix over specified ring with flat
    1196        list of entries and the rest zeros
    1197 
    1198     5. diagonal_matrix(vect, [sparse=True]):
    1199        diagonal matrix with entries taken from a vector
    1200 
    1201     The sparse option is optional, must be explicitly named (i.e.,
    1202     sparse=True), and may be either True or False.
     1210    OUTPUT:
     1211   
     1212    A square matrix over the given ``ring`` with a size
     1213    given by ``nrows``.  If the ring is not given it
     1214    is inferred from the given entries.  The values on
     1215    the diagonal of the returned matrix come from ``entries``.
     1216    If the number of entries is not enough to fill the whole
     1217    diagonal, it is padded with zeros.
    12031218
    12041219    EXAMPLES:
    1205 
    1206     Input format 1::
    1207 
    1208         sage: diagonal_matrix([1,2,3])
     1220   
     1221    We first demonstrate each of the input formats with various
     1222    different ways to specify the entries.
     1223   
     1224    Format 1: a flat list of entries.  ::
     1225   
     1226        sage: A = diagonal_matrix([2, 1.3, 5]); A
     1227        [ 2.00000000000000 0.000000000000000 0.000000000000000]
     1228        [0.000000000000000  1.30000000000000 0.000000000000000]
     1229        [0.000000000000000 0.000000000000000  5.00000000000000]
     1230        sage: A.parent()
     1231        Full MatrixSpace of 3 by 3 sparse matrices over Real Field with 53 bits of precision
     1232       
     1233    Format 2: size specified, a tuple with initial entries. Note that a short list of entries
     1234    is effectively padded with zeros.  ::
     1235   
     1236        sage: A = diagonal_matrix(3, (4, 5)); A
     1237        [4 0 0]
     1238        [0 5 0]
     1239        [0 0 0]
     1240        sage: A.parent()
     1241        Full MatrixSpace of 3 by 3 sparse matrices over Integer Ring
     1242       
     1243    Format 3: ring specified, a vector of entries. ::
     1244   
     1245        sage: A = diagonal_matrix(QQ, vector(ZZ, [1,2,3])); A
    12091246        [1 0 0]
    12101247        [0 2 0]
    12111248        [0 0 3]
     1249        sage: A.parent()
     1250        Full MatrixSpace of 3 by 3 sparse matrices over Rational Field
     1251       
     1252    Format 4: ring, size and list of entries. ::
    12121253   
    1213     Input format 2::
     1254        sage: A = diagonal_matrix(FiniteField(3), 3, [2, 16]); A
     1255        [2 0 0]
     1256        [0 1 0]
     1257        [0 0 0]
     1258        sage: A.parent()
     1259        Full MatrixSpace of 3 by 3 sparse matrices over Finite Field of size 3
     1260
     1261    NumPy arrays may be used as input, without giving a ring.  Resulting matrices
     1262    have ``RDF`` or ``CDF`` for base rings. ::
    12141263   
    1215         sage: diagonal_matrix(3, [1,2])
     1264        sage: import numpy
     1265        sage: entries = numpy.array([1.2, 5.6]); entries
     1266        array([ 1.2,  5.6])
     1267        sage: A = diagonal_matrix(3, entries); A
     1268        [1.2 0.0 0.0]
     1269        [0.0 5.6 0.0]
     1270        [0.0 0.0 0.0]
     1271        sage: A.parent()
     1272        Full MatrixSpace of 3 by 3 sparse matrices over Real Double Field
     1273       
     1274        sage: j = numpy.complex(0,1)
     1275        sage: entries = numpy.array([2.0+j, 8.1, 3.4+2.6*j]); entries
     1276        array([ 2.0+1.j ,  8.1+0.j ,  3.4+2.6j])
     1277        sage: A = diagonal_matrix(entries); A
     1278        [2.0 + 1.0*I           0           0]
     1279        [          0         8.1           0]
     1280        [          0           0 3.4 + 2.6*I]
     1281        sage: A.parent()
     1282        Full MatrixSpace of 3 by 3 sparse matrices over Complex Double Field
     1283
     1284    By default returned matrices have a sparse implementation.  This can be changed
     1285    when using any of the formats.  ::
     1286   
     1287        sage: A = diagonal_matrix([1,2,3], sparse=False)
     1288        sage: A.parent()
     1289        Full MatrixSpace of 3 by 3 dense matrices over Integer Ring
     1290       
     1291    Giving the entries improperly may first complain about not having a length.  ::
     1292   
     1293        sage: diagonal_matrix(QQ, 5, 10)
     1294        Traceback (most recent call last):
     1295        ...
     1296        TypeError: unable to determine number of entries for diagonal matrix construction
     1297       
     1298    Giving too many entries will raise an error. ::
     1299   
     1300        sage: diagonal_matrix(QQ, 3, [1,2,3,4])
     1301        Traceback (most recent call last):
     1302        ...
     1303        ValueError: number of diagonal matrix entries (4) exceeds the requested matrix size (3)
     1304       
     1305    You cannot specify a ring with a NumPy array since the ring is determined
     1306    automatically, though you can change it after the fact.  Also, the
     1307    dimensionality of the NumPy array is checked. ::
     1308   
     1309        sage: import numpy
     1310        sage: entries = numpy.array([1.2, 1.3])
     1311        sage: diagonal_matrix(RDF, entries)
     1312        Traceback (most recent call last):
     1313        ...
     1314        ValueError: cannot specify ring for diagonal matrix constructor with a NumPy array
     1315       
     1316        sage: entries = numpy.array([1.0, 2.0, 3.0])
     1317        sage: A = diagonal_matrix(3, entries)
     1318        sage: B = A.change_ring(ZZ); B
    12161319        [1 0 0]
    12171320        [0 2 0]
    1218         [0 0 0]
     1321        [0 0 3]
     1322        sage: B.parent()
     1323        Full MatrixSpace of 3 by 3 sparse matrices over Integer Ring
     1324       
     1325        sage: entries = numpy.array([[1.2], [1.3]])
     1326        sage: entries.shape
     1327        (2, 1)
     1328        sage: diagonal_matrix(entries)
     1329        Traceback (most recent call last):
     1330        ...
     1331        TypeError: NumPy array for diagonal matrix constructor must be a 1-dimensional list
     1332       
     1333    A negative size sometimes causes the error that there are too many elements. ::
    12191334   
    1220     Input format 3::
     1335        sage: diagonal_matrix(-2, [2])
     1336        Traceback (most recent call last):
     1337        ...
     1338        ValueError: number of diagonal matrix entries (1) exceeds the requested matrix size (-2)
     1339       
     1340    Types for the entries are limited, even though they may have a length.  ::
    12211341   
    1222         sage: diagonal_matrix(GF(3), [1,2,3])
    1223         [1 0 0]
    1224         [0 2 0]
    1225         [0 0 0]
     1342        sage: diagonal_matrix(x^2)
     1343        Traceback (most recent call last):
     1344        ...
     1345        TypeError: diagonal matrix entries are not a supported type (list, tuple, vector, or NumPy array)
     1346       
     1347    AUTHOR:
    12261348   
    1227     Input format 4::
     1349        - Rob Beezer (2011-01-11): total rewrite
     1350    """
     1351    # Roll arguments forward
     1352    # Lead with a ring?
     1353    # Formats 3, 4, else remains None
     1354    ring = None
     1355    if rings.is_Ring(arg0):
     1356        ring = arg0
     1357        arg0 = arg1
     1358        arg1 = arg2
     1359    # Size of matrix specified?
     1360    # Formats 2, 4
     1361    nrows = None
     1362    if isinstance(arg0, (int, long, rings.Integer)):
     1363        nrows = arg0
     1364        arg0 = arg1
     1365    # Object holding entries
     1366    # Formats 1, 2, 3, 4
     1367    entries = arg0
    12281368   
    1229         sage: diagonal_matrix(GF(3), 3, [8,2])
    1230         [2 0 0]
    1231         [0 2 0]
    1232         [0 0 0]
     1369    # Reconcile matrix size and number of entries
     1370    try:
     1371        nentries = len(entries)
     1372    except TypeError:
     1373        raise TypeError('unable to determine number of entries for diagonal matrix construction')
     1374    # sometimes catches a negative size
     1375    if not nrows is None and nentries > nrows:
     1376        raise ValueError('number of diagonal matrix entries (%s) exceeds the requested matrix size (%s)' % (nentries, nrows))
     1377    if nrows is None:
     1378        nrows = nentries
    12331379   
    1234     Input format 5::
    1235 
    1236         sage: diagonal_matrix(vector(GF(3),[1,2,3]))
    1237         [1 0 0]
    1238         [0 2 0]
    1239         [0 0 0]
    1240 
    1241     """
    1242     ring = None
    1243     if isinstance(arg0, (list, tuple)):
    1244         # Format 1
    1245         v = arg0
    1246         nrows = len(v)
    1247     elif isinstance(arg0, (int, long, rings.Integer)):
    1248         # Format 2
    1249         nrows = arg0
    1250         v = arg1
    1251     elif rings.is_Ring(arg0):
    1252         ring = arg0
    1253         if isinstance(arg1, (list, tuple)):
    1254             # Format 3
    1255             v = arg1
    1256             nrows = len(v)
    1257         else:
    1258             # Format 4
    1259             nrows = arg1
    1260             v = arg2
    1261     elif is_Vector(arg0):
    1262         # Format 5
    1263         v = list(arg0)
    1264         nrows = len(v)
    1265     if isinstance(v, list):
    1266         w = {}
    1267         for i in range(len(v)):
    1268             w[(i,i)] = v[i]
     1380    # Convert entries to a list v
     1381    from numpy import ndarray
     1382    if isinstance(entries, (list, tuple)) or is_Vector(entries):
     1383        v = list(entries)
     1384    elif isinstance(entries, ndarray):
     1385        if not ring is None:
     1386          raise ValueError('cannot specify ring for diagonal matrix constructor with a NumPy array')
     1387        if not len(entries.shape)==1:
     1388          raise TypeError('NumPy array for diagonal matrix constructor must be a 1-dimensional list')
     1389        # Set ring and convert NumPy types to Sage types
     1390        if str(entries.dtype).count('float')==1:
     1391            ring = RDF
     1392        if str(entries.dtype).count('complex')==1:
     1393            ring = CDF
     1394        v = [ring(x) for x in entries]
    12691395    else:
    1270         w = v
    1271 
     1396        raise TypeError('diagonal matrix entries are not a supported type (list, tuple, vector, or NumPy array)')
     1397       
     1398    # Create a "diagonal" dictionary for matrix constructor
     1399    # If nentries < nrows, diagonal is effectively padded with zeros at end
     1400    w = {}
     1401    for i in range(len(v)):
     1402        w[(i,i)] = v[i]
     1403   
     1404    # Ship ring, matrix size, dictionary to matrix constructor
    12721405    if ring is None:
    12731406        return matrix(nrows, nrows, w, sparse=sparse)
    12741407    else: