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

File trac_10604-diagonal-matrix-constructor-v2.patch, 10.2 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 bd7d08009d9e6dd4d0135e2ac615e5ddee3c7471
    # Parent  a565e478956adb900ae7884e8f9e21b1bf83ce94
    10604: rewrite diagonal matrix constructor, support NumPy input
    
    diff -r a565e478956a -r bd7d08009d9e 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. ::
    12141262   
    1215         sage: diagonal_matrix(3, [1,2])
    1216         [1 0 0]
    1217         [0 2 0]
    1218         [0 0 0]
     1263        sage: import numpy
     1264        sage: entries = numpy.array([1.2, 5.6]); entries
     1265        array([ 1.2,  5.6])
     1266        sage: A = diagonal_matrix(3, entries); A
     1267        [1.2 0.0 0.0]
     1268        [0.0 5.6 0.0]
     1269        [0.0 0.0 0.0]
     1270        sage: A.parent()
     1271        Full MatrixSpace of 3 by 3 sparse matrices over Real Double Field
     1272       
     1273        sage: j = numpy.complex(0,1)
     1274        sage: entries = numpy.array([2.0+j, 8.1, 3.4+2.6*j]); entries
     1275        array([ 2.0+1.j ,  8.1+0.j ,  3.4+2.6j])
     1276        sage: A = diagonal_matrix(entries); A
     1277        [2.0 + 1.0*I           0           0]
     1278        [          0         8.1           0]
     1279        [          0           0 3.4 + 2.6*I]
     1280        sage: A.parent()
     1281        Full MatrixSpace of 3 by 3 sparse matrices over Complex Double Field
     1282       
     1283        sage: entries = numpy.array([4, 5, 6])
     1284        sage: A = diagonal_matrix(entries); A
     1285        [4 0 0]
     1286        [0 5 0]
     1287        [0 0 6]
     1288        sage: A.parent()
     1289        Full MatrixSpace of 3 by 3 sparse matrices over Integer Ring
     1290
     1291        sage: entries = numpy.array([4.1, 5.2, 6.3])
     1292        sage: A = diagonal_matrix(ZZ, entries); A
     1293        Traceback (most recent call last):
     1294        ...
     1295        TypeError: Cannot convert non-integral float to integer
     1296
     1297    By default returned matrices have a sparse implementation.  This can be changed
     1298    when using any of the formats.  ::
    12191299   
    1220     Input format 3::
     1300        sage: A = diagonal_matrix([1,2,3], sparse=False)
     1301        sage: A.parent()
     1302        Full MatrixSpace of 3 by 3 dense matrices over Integer Ring
     1303
     1304    An empty list and no ring specified defaults to the integers. ::
    12211305   
    1222         sage: diagonal_matrix(GF(3), [1,2,3])
    1223         [1 0 0]
    1224         [0 2 0]
    1225         [0 0 0]
     1306        sage: A = diagonal_matrix([])
     1307        sage: A.parent()
     1308        Full MatrixSpace of 0 by 0 sparse matrices over Integer Ring
     1309
     1310    Giving the entries improperly may first complain about not having a length.  ::
    12261311   
    1227     Input format 4::
     1312        sage: diagonal_matrix(QQ, 5, 10)
     1313        Traceback (most recent call last):
     1314        ...
     1315        TypeError: unable to determine number of entries for diagonal matrix construction
     1316       
     1317    Giving too many entries will raise an error. ::
    12281318   
    1229         sage: diagonal_matrix(GF(3), 3, [8,2])
    1230         [2 0 0]
    1231         [0 2 0]
    1232         [0 0 0]
     1319        sage: diagonal_matrix(QQ, 3, [1,2,3,4])
     1320        Traceback (most recent call last):
     1321        ...
     1322        ValueError: number of diagonal matrix entries (4) exceeds the requested matrix size (3)
     1323               
     1324    A negative size sometimes causes the error that there are too many elements. ::
    12331325   
    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 
     1326        sage: diagonal_matrix(-2, [2])
     1327        Traceback (most recent call last):
     1328        ...
     1329        ValueError: number of diagonal matrix entries (1) exceeds the requested matrix size (-2)
     1330       
     1331    Types for the entries are limited, even though they may have a length.  ::
     1332   
     1333        sage: diagonal_matrix(x^2)
     1334        Traceback (most recent call last):
     1335        ...
     1336        TypeError: diagonal matrix entries are not a supported type (list, tuple, vector, or NumPy array)
     1337       
     1338    AUTHOR:
     1339   
     1340        - Rob Beezer (2011-01-11): total rewrite
    12411341    """
     1342    # Roll arguments leftward
     1343    #
     1344    # Leads with a ring?
     1345    # Formats 3, 4, else remains None
    12421346    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
     1347    if rings.is_Ring(arg0):
     1348        ring = arg0
     1349        arg0 = arg1
     1350        arg1 = arg2
     1351    # Size of matrix specified?
     1352    # Formats 2, 4
     1353    nrows = None
     1354    if isinstance(arg0, (int, long, rings.Integer)):
    12491355        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]
    1269     else:
    1270         w = v
    1271 
     1356        arg0 = arg1
     1357    # Object holding entries
     1358    # Formats 1, 2, 3, 4
     1359    entries = arg0
     1360   
     1361    # Reconcile matrix size and number of entries
     1362    try:
     1363        nentries = len(entries)
     1364    except TypeError:
     1365        raise TypeError('unable to determine number of entries for diagonal matrix construction')
     1366    # sometimes catches a negative size
     1367    if not nrows is None and nentries > nrows:
     1368        raise ValueError('number of diagonal matrix entries (%s) exceeds the requested matrix size (%s)' % (nentries, nrows))
     1369    if nrows is None:
     1370        nrows = nentries
     1371   
     1372    # provide a default ring for an empty list
     1373    if len(entries) == 0 and ring is None:
     1374      ring = rings.ZZ
     1375   
     1376    # Sanity check on entries (partially, e.g. a list of lists will survive this check)
     1377    from numpy import ndarray
     1378    if not any([isinstance(entries, (list, tuple)), isinstance(entries, ndarray), is_Vector(entries)]):
     1379        raise TypeError('diagonal matrix entries are not a supported type (list, tuple, vector, or NumPy array)')
     1380   
     1381    # Convert entries to a list v over a common ring
     1382    from sage.modules.free_module_element import prepare
     1383    v, ring = prepare(entries, ring)
     1384   
     1385    # Create a "diagonal" dictionary for matrix constructor
     1386    # If nentries < nrows, diagonal is effectively padded with zeros at end
     1387    w = {}
     1388    for i in range(len(v)):
     1389        w[(i,i)] = v[i]
     1390   
     1391    # Ship ring, matrix size, dictionary to matrix constructor
    12721392    if ring is None:
    12731393        return matrix(nrows, nrows, w, sparse=sparse)
    12741394    else: