Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/matrix/constructor.py
4036 views
1
"""
2
Matrix Constructor
3
"""
4
5
#*****************************************************************************
6
# Copyright (C) 2005 William Stein <[email protected]>
7
#
8
# Distributed under the terms of the GNU General Public License (GPL)
9
#
10
# This code is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
# General Public License for more details.
14
#
15
# The full text of the GPL is available at:
16
#
17
# http://www.gnu.org/licenses/
18
#*****************************************************************************
19
import types
20
import sage.rings.all as rings
21
import sage.matrix.matrix_space as matrix_space
22
from sage.modules.free_module_element import vector
23
from sage.structure.element import is_Vector
24
from sage.structure.sequence import Sequence
25
from sage.rings.real_double import RDF
26
from sage.rings.complex_double import CDF
27
from sage.rings.all import ZZ, QQ
28
from sage.misc.misc_c import running_total
29
from matrix import is_Matrix
30
from copy import copy
31
32
import sage.categories.pushout
33
34
def matrix(*args, **kwds):
35
"""
36
Create a matrix.
37
38
INPUT: The matrix command takes the entries of a matrix, optionally
39
preceded by a ring and the dimensions of the matrix, and returns a
40
matrix.
41
42
The entries of a matrix can be specified as a flat list of
43
elements, a list of lists (i.e., a list of rows), a list of Sage
44
vectors, a callable object, or a dictionary having positions as
45
keys and matrix entries as values (see the examples). If you pass
46
in a callable object, then you must specify the number of rows and
47
columns. You can create a matrix of zeros by passing an empty list
48
or the integer zero for the entries. To construct a multiple of
49
the identity (`cI`), you can specify square dimensions and pass in
50
`c`. Calling matrix() with a Sage object may return something that
51
makes sense. Calling matrix() with a NumPy array will convert the
52
array to a matrix.
53
54
The ring, number of rows, and number of columns of the matrix can
55
be specified by setting the ring, nrows, or ncols parameters or by
56
passing them as the first arguments to the function in the order
57
ring, nrows, ncols. The ring defaults to ZZ if it is not specified
58
or cannot be determined from the entries. If the numbers of rows
59
and columns are not specified and cannot be determined, then an
60
empty 0x0 matrix is returned.
61
62
63
- ``ring`` - the base ring for the entries of the
64
matrix.
65
66
- ``nrows`` - the number of rows in the matrix.
67
68
- ``ncols`` - the number of columns in the matrix.
69
70
- ``sparse`` - create a sparse matrix. This defaults
71
to True when the entries are given as a dictionary, otherwise
72
defaults to False.
73
74
75
OUTPUT:
76
77
a matrix
78
79
EXAMPLES::
80
81
sage: m=matrix(2); m; m.parent()
82
[0 0]
83
[0 0]
84
Full MatrixSpace of 2 by 2 dense matrices over Integer Ring
85
86
::
87
88
sage: m=matrix(2,3); m; m.parent()
89
[0 0 0]
90
[0 0 0]
91
Full MatrixSpace of 2 by 3 dense matrices over Integer Ring
92
93
::
94
95
sage: m=matrix(QQ,[[1,2,3],[4,5,6]]); m; m.parent()
96
[1 2 3]
97
[4 5 6]
98
Full MatrixSpace of 2 by 3 dense matrices over Rational Field
99
100
::
101
102
sage: m = matrix(QQ, 3, 3, lambda i, j: i+j); m
103
[0 1 2]
104
[1 2 3]
105
[2 3 4]
106
sage: m = matrix(3, lambda i,j: i-j); m
107
[ 0 -1 -2]
108
[ 1 0 -1]
109
[ 2 1 0]
110
111
::
112
113
sage: matrix(QQ,2,3,lambda x, y: x+y)
114
[0 1 2]
115
[1 2 3]
116
sage: matrix(QQ,3,2,lambda x, y: x+y)
117
[0 1]
118
[1 2]
119
[2 3]
120
121
::
122
123
sage: v1=vector((1,2,3))
124
sage: v2=vector((4,5,6))
125
sage: m=matrix([v1,v2]); m; m.parent()
126
[1 2 3]
127
[4 5 6]
128
Full MatrixSpace of 2 by 3 dense matrices over Integer Ring
129
130
::
131
132
sage: m=matrix(QQ,2,[1,2,3,4,5,6]); m; m.parent()
133
[1 2 3]
134
[4 5 6]
135
Full MatrixSpace of 2 by 3 dense matrices over Rational Field
136
137
::
138
139
sage: m=matrix(QQ,2,3,[1,2,3,4,5,6]); m; m.parent()
140
[1 2 3]
141
[4 5 6]
142
Full MatrixSpace of 2 by 3 dense matrices over Rational Field
143
144
::
145
146
sage: m=matrix({(0,1): 2, (1,1):2/5}); m; m.parent()
147
[ 0 2]
148
[ 0 2/5]
149
Full MatrixSpace of 2 by 2 sparse matrices over Rational Field
150
151
::
152
153
sage: m=matrix(QQ,2,3,{(1,1): 2}); m; m.parent()
154
[0 0 0]
155
[0 2 0]
156
Full MatrixSpace of 2 by 3 sparse matrices over Rational Field
157
158
::
159
160
sage: import numpy
161
sage: n=numpy.array([[1,2],[3,4]],float)
162
sage: m=matrix(n); m; m.parent()
163
[1.0 2.0]
164
[3.0 4.0]
165
Full MatrixSpace of 2 by 2 dense matrices over Real Double Field
166
167
::
168
169
sage: v = vector(ZZ, [1, 10, 100])
170
sage: m=matrix(v); m; m.parent()
171
[ 1 10 100]
172
Full MatrixSpace of 1 by 3 dense matrices over Integer Ring
173
sage: m=matrix(GF(7), v); m; m.parent()
174
[1 3 2]
175
Full MatrixSpace of 1 by 3 dense matrices over Finite Field of size 7
176
177
::
178
179
sage: g = graphs.PetersenGraph()
180
sage: m = matrix(g); m; m.parent()
181
[0 1 0 0 1 1 0 0 0 0]
182
[1 0 1 0 0 0 1 0 0 0]
183
[0 1 0 1 0 0 0 1 0 0]
184
[0 0 1 0 1 0 0 0 1 0]
185
[1 0 0 1 0 0 0 0 0 1]
186
[1 0 0 0 0 0 0 1 1 0]
187
[0 1 0 0 0 0 0 0 1 1]
188
[0 0 1 0 0 1 0 0 0 1]
189
[0 0 0 1 0 1 1 0 0 0]
190
[0 0 0 0 1 0 1 1 0 0]
191
Full MatrixSpace of 10 by 10 dense matrices over Integer Ring
192
193
::
194
195
sage: matrix(ZZ, 10, 10, range(100), sparse=True).parent()
196
Full MatrixSpace of 10 by 10 sparse matrices over Integer Ring
197
198
::
199
200
sage: R = PolynomialRing(QQ, 9, 'x')
201
sage: A = matrix(R, 3, 3, R.gens()); A
202
[x0 x1 x2]
203
[x3 x4 x5]
204
[x6 x7 x8]
205
sage: det(A)
206
-x2*x4*x6 + x1*x5*x6 + x2*x3*x7 - x0*x5*x7 - x1*x3*x8 + x0*x4*x8
207
208
TESTS::
209
210
sage: m=matrix(); m; m.parent()
211
[]
212
Full MatrixSpace of 0 by 0 dense matrices over Integer Ring
213
sage: m=matrix(QQ); m; m.parent()
214
[]
215
Full MatrixSpace of 0 by 0 dense matrices over Rational Field
216
sage: m=matrix(QQ,2); m; m.parent()
217
[0 0]
218
[0 0]
219
Full MatrixSpace of 2 by 2 dense matrices over Rational Field
220
sage: m=matrix(QQ,2,3); m; m.parent()
221
[0 0 0]
222
[0 0 0]
223
Full MatrixSpace of 2 by 3 dense matrices over Rational Field
224
sage: m=matrix([]); m; m.parent()
225
[]
226
Full MatrixSpace of 0 by 0 dense matrices over Integer Ring
227
sage: m=matrix(QQ,[]); m; m.parent()
228
[]
229
Full MatrixSpace of 0 by 0 dense matrices over Rational Field
230
sage: m=matrix(2,2,1); m; m.parent()
231
[1 0]
232
[0 1]
233
Full MatrixSpace of 2 by 2 dense matrices over Integer Ring
234
sage: m=matrix(QQ,2,2,1); m; m.parent()
235
[1 0]
236
[0 1]
237
Full MatrixSpace of 2 by 2 dense matrices over Rational Field
238
sage: m=matrix(2,3,0); m; m.parent()
239
[0 0 0]
240
[0 0 0]
241
Full MatrixSpace of 2 by 3 dense matrices over Integer Ring
242
sage: m=matrix(QQ,2,3,0); m; m.parent()
243
[0 0 0]
244
[0 0 0]
245
Full MatrixSpace of 2 by 3 dense matrices over Rational Field
246
sage: m=matrix([[1,2,3],[4,5,6]]); m; m.parent()
247
[1 2 3]
248
[4 5 6]
249
Full MatrixSpace of 2 by 3 dense matrices over Integer Ring
250
sage: m=matrix(QQ,2,[[1,2,3],[4,5,6]]); m; m.parent()
251
[1 2 3]
252
[4 5 6]
253
Full MatrixSpace of 2 by 3 dense matrices over Rational Field
254
sage: m=matrix(QQ,3,[[1,2,3],[4,5,6]]); m; m.parent()
255
Traceback (most recent call last):
256
...
257
ValueError: Number of rows does not match up with specified number.
258
sage: m=matrix(QQ,2,3,[[1,2,3],[4,5,6]]); m; m.parent()
259
[1 2 3]
260
[4 5 6]
261
Full MatrixSpace of 2 by 3 dense matrices over Rational Field
262
sage: m=matrix(QQ,2,4,[[1,2,3],[4,5,6]]); m; m.parent()
263
Traceback (most recent call last):
264
...
265
ValueError: Number of columns does not match up with specified number.
266
sage: m=matrix([(1,2,3),(4,5,6)]); m; m.parent()
267
[1 2 3]
268
[4 5 6]
269
Full MatrixSpace of 2 by 3 dense matrices over Integer Ring
270
sage: m=matrix([1,2,3,4,5,6]); m; m.parent()
271
[1 2 3 4 5 6]
272
Full MatrixSpace of 1 by 6 dense matrices over Integer Ring
273
sage: m=matrix((1,2,3,4,5,6)); m; m.parent()
274
[1 2 3 4 5 6]
275
Full MatrixSpace of 1 by 6 dense matrices over Integer Ring
276
sage: m=matrix(QQ,[1,2,3,4,5,6]); m; m.parent()
277
[1 2 3 4 5 6]
278
Full MatrixSpace of 1 by 6 dense matrices over Rational Field
279
sage: m=matrix(QQ,3,2,[1,2,3,4,5,6]); m; m.parent()
280
[1 2]
281
[3 4]
282
[5 6]
283
Full MatrixSpace of 3 by 2 dense matrices over Rational Field
284
sage: m=matrix(QQ,2,4,[1,2,3,4,5,6]); m; m.parent()
285
Traceback (most recent call last):
286
...
287
ValueError: entries has the wrong length
288
sage: m=matrix(QQ,5,[1,2,3,4,5,6]); m; m.parent()
289
Traceback (most recent call last):
290
...
291
TypeError: cannot construct an element of
292
Full MatrixSpace of 5 by 1 dense matrices over Rational Field
293
from [1, 2, 3, 4, 5, 6]!
294
sage: m=matrix({(1,1): 2}); m; m.parent()
295
[0 0]
296
[0 2]
297
Full MatrixSpace of 2 by 2 sparse matrices over Integer Ring
298
sage: m=matrix(QQ,{(1,1): 2}); m; m.parent()
299
[0 0]
300
[0 2]
301
Full MatrixSpace of 2 by 2 sparse matrices over Rational Field
302
sage: m=matrix(QQ,3,{(1,1): 2}); m; m.parent()
303
[0 0 0]
304
[0 2 0]
305
[0 0 0]
306
Full MatrixSpace of 3 by 3 sparse matrices over Rational Field
307
sage: m=matrix(QQ,3,4,{(1,1): 2}); m; m.parent()
308
[0 0 0 0]
309
[0 2 0 0]
310
[0 0 0 0]
311
Full MatrixSpace of 3 by 4 sparse matrices over Rational Field
312
sage: m=matrix(QQ,2,{(1,1): 2}); m; m.parent()
313
[0 0]
314
[0 2]
315
Full MatrixSpace of 2 by 2 sparse matrices over Rational Field
316
sage: m=matrix(QQ,1,{(1,1): 2}); m; m.parent()
317
Traceback (most recent call last):
318
...
319
IndexError: invalid entries list
320
sage: m=matrix({}); m; m.parent()
321
[]
322
Full MatrixSpace of 0 by 0 sparse matrices over Integer Ring
323
sage: m=matrix(QQ,{}); m; m.parent()
324
[]
325
Full MatrixSpace of 0 by 0 sparse matrices over Rational Field
326
sage: m=matrix(QQ,2,{}); m; m.parent()
327
[0 0]
328
[0 0]
329
Full MatrixSpace of 2 by 2 sparse matrices over Rational Field
330
sage: m=matrix(QQ,2,3,{}); m; m.parent()
331
[0 0 0]
332
[0 0 0]
333
Full MatrixSpace of 2 by 3 sparse matrices over Rational Field
334
sage: m=matrix(2,{}); m; m.parent()
335
[0 0]
336
[0 0]
337
Full MatrixSpace of 2 by 2 sparse matrices over Integer Ring
338
sage: m=matrix(2,3,{}); m; m.parent()
339
[0 0 0]
340
[0 0 0]
341
Full MatrixSpace of 2 by 3 sparse matrices over Integer Ring
342
sage: m=matrix(0); m; m.parent()
343
[]
344
Full MatrixSpace of 0 by 0 dense matrices over Integer Ring
345
sage: m=matrix(0,2); m; m.parent()
346
[]
347
Full MatrixSpace of 0 by 2 dense matrices over Integer Ring
348
sage: m=matrix(2,0); m; m.parent()
349
[]
350
Full MatrixSpace of 2 by 0 dense matrices over Integer Ring
351
sage: m=matrix(0,[1]); m; m.parent()
352
Traceback (most recent call last):
353
...
354
ValueError: entries has the wrong length
355
sage: m=matrix(1,0,[]); m; m.parent()
356
[]
357
Full MatrixSpace of 1 by 0 dense matrices over Integer Ring
358
sage: m=matrix(0,1,[]); m; m.parent()
359
[]
360
Full MatrixSpace of 0 by 1 dense matrices over Integer Ring
361
sage: m=matrix(0,[]); m; m.parent()
362
[]
363
Full MatrixSpace of 0 by 0 dense matrices over Integer Ring
364
sage: m=matrix(0,{}); m; m.parent()
365
[]
366
Full MatrixSpace of 0 by 0 sparse matrices over Integer Ring
367
sage: m=matrix(0,{(1,1):2}); m; m.parent()
368
Traceback (most recent call last):
369
...
370
IndexError: invalid entries list
371
sage: m=matrix(2,0,{(1,1):2}); m; m.parent()
372
Traceback (most recent call last):
373
...
374
IndexError: invalid entries list
375
sage: import numpy
376
sage: n=numpy.array([[numpy.complex(0,1),numpy.complex(0,2)],[3,4]],complex)
377
sage: m=matrix(n); m; m.parent()
378
[1.0*I 2.0*I]
379
[ 3.0 4.0]
380
Full MatrixSpace of 2 by 2 dense matrices over Complex Double Field
381
sage: n=numpy.array([[1,2],[3,4]],'int32')
382
sage: m=matrix(n); m; m.parent()
383
[1 2]
384
[3 4]
385
Full MatrixSpace of 2 by 2 dense matrices over Integer Ring
386
sage: n = numpy.array([[1,2,3],[4,5,6],[7,8,9]],'float32')
387
sage: m=matrix(n); m; m.parent()
388
[1.0 2.0 3.0]
389
[4.0 5.0 6.0]
390
[7.0 8.0 9.0]
391
Full MatrixSpace of 3 by 3 dense matrices over Real Double Field
392
sage: n=numpy.array([[1,2,3],[4,5,6],[7,8,9]],'float64')
393
sage: m=matrix(n); m; m.parent()
394
[1.0 2.0 3.0]
395
[4.0 5.0 6.0]
396
[7.0 8.0 9.0]
397
Full MatrixSpace of 3 by 3 dense matrices over Real Double Field
398
sage: n=numpy.array([[1,2,3],[4,5,6],[7,8,9]],'complex64')
399
sage: m=matrix(n); m; m.parent()
400
[1.0 2.0 3.0]
401
[4.0 5.0 6.0]
402
[7.0 8.0 9.0]
403
Full MatrixSpace of 3 by 3 dense matrices over Complex Double Field
404
sage: n=numpy.array([[1,2,3],[4,5,6],[7,8,9]],'complex128')
405
sage: m=matrix(n); m; m.parent()
406
[1.0 2.0 3.0]
407
[4.0 5.0 6.0]
408
[7.0 8.0 9.0]
409
Full MatrixSpace of 3 by 3 dense matrices over Complex Double Field
410
sage: a = matrix([[1,2],[3,4]])
411
sage: b = matrix(a.numpy()); b
412
[1 2]
413
[3 4]
414
sage: a == b
415
True
416
sage: c = matrix(a.numpy('float32')); c
417
[1.0 2.0]
418
[3.0 4.0]
419
sage: matrix(numpy.array([[5]]))
420
[5]
421
sage: v = vector(ZZ, [1, 10, 100])
422
sage: m=matrix(ZZ['x'], v); m; m.parent()
423
[ 1 10 100]
424
Full MatrixSpace of 1 by 3 dense matrices over Univariate Polynomial Ring in x over Integer Ring
425
sage: matrix(ZZ, 10, 10, range(100)).parent()
426
Full MatrixSpace of 10 by 10 dense matrices over Integer Ring
427
sage: m = matrix(GF(7), [[1/3,2/3,1/2], [3/4,4/5,7]]); m; m.parent()
428
[5 3 4]
429
[6 5 0]
430
Full MatrixSpace of 2 by 3 dense matrices over Finite Field of size 7
431
sage: m = matrix([[1,2,3], [RDF(2), CDF(1,2), 3]]); m; m.parent()
432
[ 1.0 2.0 3.0]
433
[ 2.0 1.0 + 2.0*I 3.0]
434
Full MatrixSpace of 2 by 3 dense matrices over Complex Double Field
435
sage: m=matrix(3,3,1/2); m; m.parent()
436
[1/2 0 0]
437
[ 0 1/2 0]
438
[ 0 0 1/2]
439
Full MatrixSpace of 3 by 3 dense matrices over Rational Field
440
sage: matrix([[1],[2,3]])
441
Traceback (most recent call last):
442
...
443
ValueError: List of rows is not valid (rows are wrong types or lengths)
444
sage: matrix([[1],2])
445
Traceback (most recent call last):
446
...
447
ValueError: List of rows is not valid (rows are wrong types or lengths)
448
sage: matrix(vector(RR,[1,2,3])).parent()
449
Full MatrixSpace of 1 by 3 dense matrices over Real Field with 53 bits of precision
450
sage: matrix(ZZ, [[0] for i in range(10^5)]).is_zero() # see #10158
451
True
452
453
AUTHORS:
454
455
- ??: Initial implementation
456
457
- Jason Grout (2008-03): almost a complete rewrite, with bits and
458
pieces from the original implementation
459
"""
460
args = list(args)
461
sparse = kwds.get('sparse',False)
462
# if the first object already knows how to make itself into a
463
# matrix, try that, defaulting to a matrix over the integers.
464
if len(args) == 1 and hasattr(args[0], '_matrix_'):
465
try:
466
return args[0]._matrix_(sparse=sparse)
467
except TypeError:
468
return args[0]._matrix_()
469
elif len(args) == 2:
470
if hasattr(args[0], '_matrix_'):
471
try:
472
return args[0]._matrix_(args[1], sparse=sparse)
473
except TypeError:
474
return args[0]._matrix_(args[1])
475
elif hasattr(args[1], '_matrix_'):
476
try:
477
return args[1]._matrix_(args[0], sparse=sparse)
478
except TypeError:
479
return args[1]._matrix_(args[0])
480
481
if len(args) == 0:
482
# if nothing was passed return the empty matrix over the
483
# integer ring.
484
return matrix_space.MatrixSpace(rings.ZZ, 0, 0, sparse=sparse)([])
485
486
if len(args) >= 1 and rings.is_Ring(args[0]):
487
# A ring is specified
488
if kwds.get('ring', args[0]) != args[0]:
489
raise ValueError, "Specified rings are not the same"
490
else:
491
ring = args[0]
492
args.pop(0)
493
else:
494
ring = kwds.get('ring', None)
495
496
if len(args) >= 1:
497
# check to see if the number of rows is specified
498
try:
499
import numpy
500
if isinstance(args[0], numpy.ndarray):
501
raise TypeError
502
nrows = int(args[0])
503
args.pop(0)
504
if kwds.get('nrows', nrows) != nrows:
505
raise ValueError, "Number of rows specified in two places and they are not the same"
506
except TypeError:
507
nrows = kwds.get('nrows', None)
508
else:
509
nrows = kwds.get('nrows', None)
510
511
if len(args) >= 1:
512
# check to see if additionally, the number of columns is specified
513
try:
514
import numpy
515
if isinstance(args[0], numpy.ndarray):
516
raise TypeError
517
ncols = int(args[0])
518
args.pop(0)
519
if kwds.get('ncols', ncols) != ncols:
520
raise ValueError, "Number of columns specified in two places and they are not the same"
521
except TypeError:
522
ncols = kwds.get('ncols', None)
523
else:
524
ncols = kwds.get('ncols', None)
525
526
527
# Now we've taken care of initial ring, nrows, and ncols arguments.
528
# We've also taken care of the Sage object case.
529
530
# Now the rest of the arguments are a list of rows, a flat list of
531
# entries, a callable, a dict, a numpy array, or a single value.
532
if len(args) == 0:
533
# If no entries are specified, pass back a zero matrix
534
entries = 0
535
entry_ring = rings.ZZ
536
elif len(args) == 1:
537
if isinstance(args[0], (types.FunctionType, types.LambdaType, types.MethodType)):
538
if ncols is None and nrows is None:
539
raise ValueError, "When passing in a callable, the dimensions of the matrix must be specified"
540
if ncols is None:
541
ncols = nrows
542
elif nrows is None:
543
nrows = ncols
544
545
f = args[0]
546
args[0] = [[f(i,j) for j in range(ncols)] for i in range(nrows)]
547
548
if isinstance(args[0], (list, tuple)):
549
if len(args[0]) == 0:
550
# no entries are specified, pass back the zero matrix
551
entries = 0
552
entry_ring = rings.ZZ
553
elif isinstance(args[0][0], (list, tuple)) or is_Vector(args[0][0]):
554
# Ensure we have a list of lists, each inner list having the same number of elements
555
first_len = len(args[0][0])
556
if not all( (isinstance(v, (list, tuple)) or is_Vector(v)) and len(v) == first_len for v in args[0]):
557
raise ValueError, "List of rows is not valid (rows are wrong types or lengths)"
558
# We have a list of rows or vectors
559
if nrows is None:
560
nrows = len(args[0])
561
elif nrows != len(args[0]):
562
raise ValueError, "Number of rows does not match up with specified number."
563
if ncols is None:
564
ncols = len(args[0][0])
565
elif ncols != len(args[0][0]):
566
raise ValueError, "Number of columns does not match up with specified number."
567
568
entries = []
569
for v in args[0]:
570
entries.extend(v)
571
572
else:
573
# We have a flat list; figure out nrows and ncols
574
if nrows is None:
575
nrows = 1
576
577
if nrows > 0:
578
if ncols is None:
579
ncols = len(args[0]) // nrows
580
elif ncols != len(args[0]) // nrows:
581
raise ValueError, "entries has the wrong length"
582
elif len(args[0]) > 0:
583
raise ValueError, "entries has the wrong length"
584
585
entries = args[0]
586
587
if nrows > 0 and ncols > 0 and ring is None:
588
entries, ring = prepare(entries)
589
590
elif isinstance(args[0], dict):
591
# We have a dictionary
592
# default to sparse
593
sparse = kwds.get('sparse', True)
594
if len(args[0]) == 0:
595
# no entries are specified, pass back the zero matrix
596
entries = 0
597
else:
598
entries, entry_ring = prepare_dict(args[0])
599
if nrows is None:
600
nrows = nrows_from_dict(entries)
601
ncols = ncols_from_dict(entries)
602
# note that ncols can still be None if nrows is set --
603
# it will be assigned nrows down below.
604
605
# See the construction after the numpy case below.
606
else:
607
import numpy
608
if isinstance(args[0], numpy.ndarray):
609
num_array = args[0]
610
str_dtype = str(num_array.dtype)
611
612
if not( num_array.flags.c_contiguous is True or num_array.flags.f_contiguous is True):
613
raise TypeError('numpy matrix must be either c_contiguous or f_contiguous')
614
if str_dtype.count('float32')==1:
615
m=matrix(RDF,num_array.shape[0],num_array.shape[1],0)
616
m._replace_self_with_numpy32(num_array)
617
618
elif str_dtype.count('float64')==1:
619
m=matrix(RDF,num_array.shape[0],num_array.shape[1],0)
620
m._replace_self_with_numpy(num_array)
621
622
elif str_dtype.count('complex64')==1:
623
m=matrix(CDF,num_array.shape[0],num_array.shape[1],0)
624
m._replace_self_with_numpy32(num_array)
625
626
elif str_dtype.count('complex128')==1:
627
m=matrix(CDF,num_array.shape[0],num_array.shape[1],0)
628
m._replace_self_with_numpy(num_array)
629
630
elif str_dtype.count('int') == 1:
631
m = matrix(ZZ, [list(row) for row in list(num_array)])
632
633
elif str_dtype.count('object') == 1:
634
#Get the raw nested list from the numpy array
635
#and feed it back into matrix
636
try:
637
return matrix( [list(row) for row in list(num_array)])
638
except TypeError:
639
raise TypeError("cannot convert NumPy matrix to Sage matrix")
640
else:
641
raise TypeError("cannot convert NumPy matrix to Sage matrix")
642
643
return m
644
elif nrows is not None and ncols is not None:
645
# assume that we should just pass the thing into the
646
# MatrixSpace constructor and hope for the best
647
# This is not documented, but it is doctested
648
if ring is None:
649
entry_ring = args[0].parent()
650
entries = args[0]
651
else:
652
raise ValueError, "Invalid matrix constructor. Type matrix? for help"
653
else:
654
raise ValueError, "Invalid matrix constructor. Type matrix? for help"
655
656
if nrows is None:
657
nrows = 0
658
if ncols is None:
659
ncols = nrows
660
661
662
if ring is None:
663
try:
664
ring = entry_ring
665
except NameError:
666
ring = rings.ZZ
667
668
return matrix_space.MatrixSpace(ring, nrows, ncols, sparse=sparse)(entries)
669
670
671
672
def prepare(w):
673
"""
674
Given a list w of numbers, find a common ring that they all
675
canonically map to, and return the list of images of the elements
676
of w in that ring along with the ring.
677
678
This is for internal use by the matrix function.
679
680
INPUT:
681
682
- ``w`` - list
683
684
OUTPUT:
685
686
list, ring
687
688
EXAMPLES::
689
690
sage: sage.matrix.constructor.prepare([-2, Mod(1,7)])
691
([5, 1], Ring of integers modulo 7)
692
693
Notice that the elements must all canonically coerce to a common
694
ring (since Sequence is called)::
695
696
sage: sage.matrix.constructor.prepare([2/1, Mod(1,7)])
697
Traceback (most recent call last):
698
...
699
TypeError: unable to find a common ring for all elements
700
"""
701
if 0 == len(w):
702
return Sequence([], rings.ZZ), rings.ZZ
703
entries = Sequence(w)
704
ring = entries.universe()
705
if ring is int or ring is long:
706
ring = rings.ZZ
707
elif ring is float:
708
ring = rings.RDF
709
elif ring is complex:
710
ring = rings.CDF
711
elif not rings.is_Ring(ring):
712
raise TypeError, "unable to find a common ring for all elements"
713
return entries, ring
714
715
def prepare_dict(w):
716
"""
717
Given a dictionary w of numbers, find a common ring that they all
718
canonically map to, and return the dictionary of images of the
719
elements of w in that ring along with the ring.
720
721
This is for internal use by the matrix function.
722
723
INPUT:
724
725
- ``w`` - dict
726
727
OUTPUT:
728
729
dict, ring
730
731
EXAMPLES::
732
733
sage: sage.matrix.constructor.prepare_dict({(0,1):2, (4,10):Mod(1,7)})
734
({(0, 1): 2, (4, 10): 1}, Ring of integers modulo 7)
735
"""
736
Z = w.items()
737
X = [x for _, x in Z]
738
entries, ring = prepare(X)
739
return dict([(Z[i][0],entries[i]) for i in xrange(len(entries))]), ring
740
741
def nrows_from_dict(d):
742
"""
743
Given a dictionary that defines a sparse matrix, return the number
744
of rows that matrix should have.
745
746
This is for internal use by the matrix function.
747
748
INPUT:
749
750
- ``d`` - dict
751
752
OUTPUT:
753
754
integer
755
756
EXAMPLES::
757
758
sage: sage.matrix.constructor.nrows_from_dict({})
759
0
760
761
Here the answer is 301 not 300, since there is a 0-th row.
762
763
::
764
sage: sage.matrix.constructor.nrows_from_dict({(300,4):10})
765
301
766
"""
767
if 0 == len(d):
768
return 0
769
return max([0] + [ij[0] for ij in d.keys()]) + 1
770
771
def ncols_from_dict(d):
772
"""
773
Given a dictionary that defines a sparse matrix, return the number
774
of columns that matrix should have.
775
776
This is for internal use by the matrix function.
777
778
INPUT:
779
780
- ``d`` - dict
781
782
OUTPUT:
783
784
integer
785
786
EXAMPLES::
787
788
sage: sage.matrix.constructor.ncols_from_dict({})
789
0
790
791
Here the answer is 301 not 300, since there is a 0-th row.
792
793
::
794
795
sage: sage.matrix.constructor.ncols_from_dict({(4,300):10})
796
301
797
"""
798
if 0 == len(d):
799
return 0
800
return max([0] + [ij[1] for ij in d.keys()]) + 1
801
802
Matrix = matrix
803
804
def column_matrix(*args, **kwds):
805
r"""
806
Constructs a matrix, and then swaps rows for columns and columns for rows.
807
808
.. note::
809
810
Linear algebra in Sage favors rows over columns. So, generally,
811
when creating a matrix, input vectors and lists are treated as rows.
812
This function is a convenience that turns around this convention
813
when creating a matrix. If you are not familiar with the usual
814
:func:`matrix` constructor, you might want to consider it first.
815
816
INPUT:
817
818
Inputs are almost exactly the same as for the :func:`matrix`
819
constructor, which are documented there. But see examples below
820
for how dimensions are handled.
821
822
OUTPUT:
823
824
Output is exactly the transpose of what the :func:`matrix`
825
constructor would return. In other words, the ``matrix``
826
constructor builds a matrix and then this function exchanges
827
rows for columns, and columns for rows.
828
829
EXAMPLES:
830
831
The most compelling use of this function is when you have
832
a collection of lists or vectors that you would like to
833
become the columns of a matrix. In almost any other
834
situation, the :func:`matrix` constructor can probably do
835
the job just as easily, or easier. ::
836
837
sage: col_1 = [1,2,3]
838
sage: col_2 = [4,5,6]
839
sage: column_matrix([col_1, col_2])
840
[1 4]
841
[2 5]
842
[3 6]
843
844
sage: v1 = vector(QQ, [10, 20])
845
sage: v2 = vector(QQ, [30, 40])
846
sage: column_matrix(QQ, [v1, v2])
847
[10 30]
848
[20 40]
849
850
If you only specify one dimension along with a flat list of entries,
851
then it will be the number of columns in the result (which is different
852
from the behavior of the ``matrix`` constructor). ::
853
854
sage: column_matrix(ZZ, 8, range(24))
855
[ 0 3 6 9 12 15 18 21]
856
[ 1 4 7 10 13 16 19 22]
857
[ 2 5 8 11 14 17 20 23]
858
859
And when you specify two dimensions, then they should be number of
860
columns first, then the number of rows, which is the reverse of how
861
they would be specified for the ``matrix`` constructor. ::
862
863
sage: column_matrix(QQ, 5, 3, range(15))
864
[ 0 3 6 9 12]
865
[ 1 4 7 10 13]
866
[ 2 5 8 11 14]
867
868
And a few unproductive, but illustrative, examples. ::
869
870
sage: A = matrix(ZZ, 3, 4, range(12))
871
sage: B = column_matrix(ZZ, 3, 4, range(12))
872
sage: A == B.transpose()
873
True
874
875
sage: A = matrix(QQ, 7, 12, range(84))
876
sage: A == column_matrix(A.columns())
877
True
878
879
sage: A=column_matrix(QQ, matrix(ZZ, 3, 2, range(6)) )
880
sage: A
881
[0 2 4]
882
[1 3 5]
883
sage: A.parent()
884
Full MatrixSpace of 2 by 3 dense matrices over Rational Field
885
"""
886
return matrix(*args, **kwds).transpose()
887
888
889
def random_matrix(ring, nrows, ncols=None, algorithm='randomize', *args, **kwds):
890
r"""
891
Return a random matrix with entries in a specified ring, and possibly with additional properties.
892
893
INPUT:
894
895
- ``ring`` - base ring for entries of the matrix
896
897
- ``nrows`` - Integer; number of rows
898
899
- ``ncols`` - (default: ``None``); number of columns; if ``None``
900
defaults to ``nrows``
901
902
- ``algorithm`` - (default: ``randomize``); determines what properties
903
the matrix will have. See examples below for possible additional
904
arguments.
905
906
- ``randomize`` - randomize the elements of the matrix, possibly
907
controlling the density of non-zero entries.
908
909
- ``echelon_form`` - creates a matrix in echelon form
910
911
- ``echelonizable`` - creates a matrix that has a predictable
912
echelon form
913
914
- ``subspaces`` - creates a matrix whose four subspaces, when
915
explored, have reasonably sized, integral valued, entries.
916
917
- ``unimodular`` - creates a matrix of determinant 1.
918
919
- ``diagonalizable`` - creates a diagonalizable matrix whose
920
eigenvectors, if computed by hand, will have only integer
921
entries.
922
923
- ``*args, **kwds`` - arguments and keywords to describe additional properties.
924
See more detailed documentation below.
925
926
.. note::
927
928
When constructing matrices with random entries and no additional properties
929
(i.e. when ``algorithm='randomize'``), most of the randomness
930
is controlled by the ``random_element`` method for elements of the
931
base ring of the matrix, so the documentation of that method may be
932
relevant or useful. Also, the default is to not create zero entries,
933
unless the ``density`` keyword is set to something strictly less
934
than one.
935
936
EXAMPLES:
937
938
Random integer matrices. With no arguments, the majority of the entries
939
are -1 and 1, never zero, and rarely "large." ::
940
941
sage: random_matrix(ZZ, 5, 5)
942
[ -8 2 0 0 1]
943
[ -1 2 1 -95 -1]
944
[ -2 -12 0 0 1]
945
[ -1 1 -1 -2 -1]
946
[ 4 -4 -6 5 0]
947
948
The ``distribution`` keyword set to ``uniform`` will limit values
949
between -2 and 2, and never zero. ::
950
951
sage: random_matrix(ZZ, 5, 5, distribution='uniform')
952
[ 1 0 -2 1 1]
953
[ 1 0 0 0 2]
954
[-1 -2 0 2 -2]
955
[-1 -1 1 1 2]
956
[ 0 -2 -1 0 0]
957
958
The ``x`` and ``y`` keywords can be used to distribute entries uniformly.
959
When both are used ``x`` is the minimum and ``y`` is one greater than the the maximum.
960
But still entries are never zero, even if the range contains zero. ::
961
962
sage: random_matrix(ZZ, 4, 8, x=70, y=100)
963
[81 82 70 81 78 71 79 94]
964
[80 98 89 87 91 94 94 77]
965
[86 89 85 92 95 94 72 89]
966
[78 80 89 82 94 72 90 92]
967
968
sage: random_matrix(ZZ, 3, 7, x=-5, y=5)
969
[-3 3 1 -5 3 1 2]
970
[ 3 3 0 3 -5 -2 1]
971
[ 0 -2 -2 2 -3 -4 -2]
972
973
If only ``x`` is given, then it is used as the upper bound of a range starting at 0. ::
974
975
sage: random_matrix(ZZ, 5, 5, x=25)
976
[20 16 8 3 8]
977
[ 8 2 2 14 5]
978
[18 18 10 20 11]
979
[19 16 17 15 7]
980
[ 0 24 3 17 24]
981
982
To allow, and control, zero entries use the ``density`` keyword at a value
983
strictly below the default of 1.0, even if distributing entries across an
984
interval that does not contain zero already. Note that for a square matrix it
985
is only necessary to set a single dimension. ::
986
987
sage: random_matrix(ZZ, 5, x=-10, y=10, density=0.75)
988
[-6 1 0 0 0]
989
[ 9 0 0 4 1]
990
[-6 0 0 -8 0]
991
[ 0 4 0 6 0]
992
[ 1 -9 0 0 -8]
993
994
sage: random_matrix(ZZ, 5, x=20, y=30, density=0.75)
995
[ 0 28 0 27 0]
996
[25 28 20 0 0]
997
[ 0 21 0 21 0]
998
[ 0 28 22 0 0]
999
[ 0 0 0 26 24]
1000
1001
It is possible to construct sparse matrices, where it may now be advisable
1002
(but not required) to control the density of nonzero entries. ::
1003
1004
sage: A=random_matrix(ZZ, 5, 5)
1005
sage: A.is_sparse()
1006
False
1007
sage: A=random_matrix(ZZ, 5, 5, sparse=True)
1008
sage: A.is_sparse()
1009
True
1010
1011
sage: random_matrix(ZZ, 5, 5, density=0.3, sparse=True)
1012
[ 4 0 0 0 -1]
1013
[ 0 0 0 0 -7]
1014
[ 0 0 2 0 0]
1015
[ 0 0 1 0 -4]
1016
[ 0 0 0 0 0]
1017
1018
For algorithm testing you might want to control the number of bits,
1019
say 10,000 entries, each limited to 16 bits. ::
1020
1021
sage: A = random_matrix(ZZ, 100, 100, x=2^16); A
1022
100 x 100 dense matrix over Integer Ring (type 'print A.str()' to see all of the entries)
1023
1024
Random rational matrices. Now ``num_bound`` and ``den_bound`` control the
1025
generation of random elements, by specifying limits on the absolute value of
1026
numerators and denominators (respectively). Entries will be positive and
1027
negative (map the absolute value function through the entries to get all
1028
positive values), and zeros are avoided unless the density is set. If either
1029
the numerator or denominator bound (or both) is not used, then the values
1030
default to the distribution for `ZZ` described above that is most frequently
1031
positive or negative one. ::
1032
1033
sage: random_matrix(QQ, 2, 8, num_bound=20, den_bound=4)
1034
[ -1/2 6 13 -12 -2/3 -1/4 5 5]
1035
[ -9/2 5/3 19 15/2 19/2 20/3 -13/4 0]
1036
1037
sage: random_matrix(QQ, 4, density = 0.5, sparse=True)
1038
[ 0 71 0 -1/2]
1039
[ 0 0 0 0]
1040
[31/85 0 -31/2 0]
1041
[ 1 -1/4 0 0]
1042
1043
sage: A = random_matrix(QQ, 3, 10, num_bound = 99, den_bound = 99)
1044
sage: positives = map(abs, A.list())
1045
sage: matrix(QQ, 3, 10, positives)
1046
[61/18 47/41 1/22 1/2 75/68 6/7 1 1/2 72/41 7/3]
1047
[33/13 9/2 40/21 45/46 17/22 1 70/79 97/71 7/24 12/5]
1048
[ 13/8 8/25 1/3 61/14 92/45 4/85 3/38 95/16 82/71 1/5]
1049
1050
sage: random_matrix(QQ, 4, 10, den_bound = 10)
1051
[ -1 0 1/8 1/6 2/9 -1/6 1/5 -1/8 1/5 -1/5]
1052
[ 1/9 1/5 -1 2/9 1/4 -1/7 1/8 -1/9 0 2]
1053
[ 2/3 2 1/8 -2 0 0 -2 2 0 -1/2]
1054
[ 0 2 1 -2/3 0 0 1/6 0 -1/3 -2/9]
1055
1056
Random matrices over other rings. Several classes of matrices have specialized
1057
``randomize()`` methods. You can locate these with the Sage command::
1058
1059
search_def('randomize')
1060
1061
The default implementation of :meth:`~sage.matrix.matrix2.randomize` relies
1062
on the ``random_element()`` method for the base ring. The ``density`` and
1063
``sparse`` keywords behave as described above. ::
1064
1065
sage: K.<a>=FiniteField(3^2)
1066
sage: random_matrix(K, 2, 5)
1067
[ 1 2*a 1 a + 2 2]
1068
[ a 2*a + 1 0 2 1]
1069
1070
sage: random_matrix(RR, 3, 4, density=0.66)
1071
[ 0.000000000000000 -0.806696574554030 -0.693915509972359 0.000000000000000]
1072
[ 0.629781664418083 0.000000000000000 -0.833709843116637 0.000000000000000]
1073
[ 0.922346867410064 0.000000000000000 0.000000000000000 -0.940316454178921]
1074
1075
sage: A = random_matrix(ComplexField(32), 3, density=0.8, sparse=True); A
1076
[ 0.000000000 0.399739209 + 0.909948633*I 0.000000000]
1077
[-0.361911424 - 0.455087671*I -0.687810605 + 0.460619713*I 0.625520058 - 0.360952012*I]
1078
[ 0.000000000 0.000000000 -0.162196416 - 0.193242896*I]
1079
sage: A.is_sparse()
1080
True
1081
1082
Random matrices in echelon form. The ``algorithm='echelon_form'`` keyword,
1083
along with a requested number of non-zero rows (``num_pivots``) will return
1084
a random matrix in echelon form. When the base ring is ``QQ`` the result has integer
1085
entries. Other exact rings may be also specified. ::
1086
1087
sage: A=random_matrix(QQ, 4, 8, algorithm='echelon_form', num_pivots=3); A # random
1088
[ 1 -5 0 -2 0 1 1 -2]
1089
[ 0 0 1 -5 0 -3 -1 0]
1090
[ 0 0 0 0 1 2 -2 1]
1091
[ 0 0 0 0 0 0 0 0]
1092
sage: A.base_ring()
1093
Rational Field
1094
sage: (A.nrows(), A.ncols())
1095
(4, 8)
1096
sage: A in sage.matrix.matrix_space.MatrixSpace(ZZ, 4, 8)
1097
True
1098
sage: A.rank()
1099
3
1100
sage: A==A.rref()
1101
True
1102
1103
For more, see the documentation of the :func:`~sage.matrix.constructor.random_rref_matrix`
1104
function. In the notebook or at the Sage command-line, first execute the following to make
1105
this further documentation available::
1106
1107
from sage.matrix.constructor import random_rref_matrix
1108
1109
Random matrices with predictable echelon forms. The ``algorithm='echelonizable'``
1110
keyword, along with a requested rank (``rank``) and optional size control
1111
(``upper_bound``) will return a random matrix in echelon form. When the
1112
base ring is ``ZZ`` or ``QQ`` the result has integer entries, whose magnitudes
1113
can be limited by the value of ``upper_bound``, and the echelon form of the
1114
matrix also has integer entries. Other exact rings may be also
1115
specified, but there is no notion of controlling the size. Square matrices
1116
of full rank generated by this function always have determinant one, and
1117
can be constructed with the ``unimodular`` keyword. ::
1118
1119
sage: A=random_matrix(QQ, 4, 8, algorithm='echelonizable', rank=3, upper_bound=60); A # random
1120
sage: A.base_ring()
1121
Rational Field
1122
sage: (A.nrows(), A.ncols())
1123
(4, 8)
1124
sage: A in sage.matrix.matrix_space.MatrixSpace(ZZ, 4, 8)
1125
True
1126
sage: A.rank()
1127
3
1128
sage: all([abs(x)<60 for x in A.list()])
1129
True
1130
sage: A.rref() in sage.matrix.matrix_space.MatrixSpace(ZZ, 4, 8)
1131
True
1132
1133
For more, see the documentation of the :func:`~sage.matrix.constructor.random_echelonizable_matrix`
1134
function. In the notebook or at the Sage command-line, first execute the following to make
1135
this further documentation available::
1136
1137
from sage.matrix.constructor import random_echelonizable_matrix
1138
1139
Random diagonalizable matrices. The ``algorithm='diagonalizable'`` keyword,
1140
along with a requested matrix size (``size``) and optional lists of
1141
eigenvalues (``eigenvalues``) and the corresponding eigenspace
1142
dimensions (``dimensions``) will return a random diagonalizable matrix.
1143
When the eigenvalues and dimensions are not specified the result will have
1144
randomly generated values for both that fit with the designated size. ::
1145
1146
sage: A=random_matrix(QQ, 5, algorithm='diagonalizable', eigenvalues=[2,3,-1], dimensions=[1,2,2]); A # random
1147
sage: all([x in ZZ for x in (A-(2*identity_matrix(5))).rref().list()])
1148
True
1149
sage: all([x in ZZ for x in (A-(3*identity_matrix(5))).rref().list()])
1150
True
1151
sage: all([x in ZZ for x in (A-(-1*identity_matrix(5))).rref().list()])
1152
True
1153
sage: A.jordan_form()
1154
[ 2| 0| 0| 0| 0]
1155
[--+--+--+--+--]
1156
[ 0| 3| 0| 0| 0]
1157
[--+--+--+--+--]
1158
[ 0| 0| 3| 0| 0]
1159
[--+--+--+--+--]
1160
[ 0| 0| 0|-1| 0]
1161
[--+--+--+--+--]
1162
[ 0| 0| 0| 0|-1]
1163
1164
For more, see the documentation of the :func:`~sage.matrix.constructor.random_diagonalizable_matrix`
1165
function. In the notebook or at the Sage command-line, first execute the following to make
1166
this further documentation available::
1167
1168
from sage.matrix.constructor import random_diagonalizable_matrix
1169
1170
Random matrices with predictable subspaces. The ``algorithm='subspaces'``
1171
keyword, along with an optional rank (``rank``) will return
1172
a matrix whose natural basis vectors for its four fundamental subspaces, if computed as
1173
described in the documentation of the :func:`~sage.matrix.constructor.random_subspaces_matrix`
1174
contain only integer entries. If ``rank``, is not set, the
1175
rank of the matrix will be generated randomly. ::
1176
1177
sage: B=random_matrix(QQ, 5, 6, algorithm='subspaces', rank=3); B #random
1178
sage: B_expanded=B.augment(identity_matrix(5)).rref()
1179
sage: (B.nrows(), B.ncols())
1180
(5, 6)
1181
sage: all([x in ZZ for x in B_expanded.list()])
1182
True
1183
sage: C=B_expanded.submatrix(0,0,B.nrows()-B.nullity(),B.ncols())
1184
sage: L=B_expanded.submatrix(B.nrows()-B.nullity(),B.ncols())
1185
sage: B.right_kernel()==C.right_kernel()
1186
True
1187
sage: B.row_space()==C.row_space()
1188
True
1189
sage: B.column_space()==L.right_kernel()
1190
True
1191
sage: B.left_kernel()==L.row_space()
1192
True
1193
1194
For more, see the documentation of the :func:`~sage.matrix.constructor.random_subspaces_matrix`
1195
function. In the notebook or at the Sage command-line, first execute the following to make
1196
this further documentation available::
1197
1198
from sage.matrix.constructor import random_subspaces_matrix
1199
1200
Random unimodular matrices. The ``algorithm='unimodular'``
1201
keyword, along with an optional entry size control (``upper_bound``)
1202
will return a matrix of determinant 1. When the base ring is ``ZZ``
1203
or ``QQ`` the result has integer entries, whose magnitudes
1204
can be limited by the value of ``upper_bound``. ::
1205
1206
sage: C=random_matrix(QQ, 5, algorithm='unimodular', upper_bound=70); C # random
1207
sage: det(C)
1208
1
1209
sage: C.base_ring()
1210
Rational Field
1211
sage: (C.nrows(), C.ncols())
1212
(5, 5)
1213
sage: all([abs(x)<70 for x in C.list()])
1214
True
1215
1216
For more, see the documentation of the :func:`~sage.matrix.constructor.random_unimodular_matrix`
1217
function. In the notebook or at the Sage command-line, first execute the following to make
1218
this further documentation available::
1219
1220
from sage.matrix.constructor import random_unimodular_matrix
1221
1222
TESTS:
1223
1224
We return an error for a bogus value of ``algorithm``::
1225
1226
sage: random_matrix(ZZ, 5, algorithm = 'bogus')
1227
Traceback (most recent call last):
1228
...
1229
ValueError: random matrix algorithm "bogus" is not recognized
1230
1231
AUTHOR:
1232
1233
- William Stein (2007-02-06)
1234
1235
- Rob Beezer (2010-08-25) Documentation, code to allow additional types of output
1236
"""
1237
if ncols is None:
1238
ncols = nrows
1239
sparse = kwds.pop('sparse', False)
1240
# Construct the parent of the desired matrix
1241
parent = matrix_space.MatrixSpace(ring, nrows, ncols, sparse=sparse)
1242
if algorithm == 'randomize':
1243
density = kwds.pop('density', None)
1244
# zero matrix is immutable, copy is mutable
1245
A = copy(parent.zero_matrix())
1246
if density is None:
1247
A.randomize(density=float(1), nonzero=False, *args, **kwds)
1248
else:
1249
A.randomize(density=density, nonzero=True, *args, **kwds)
1250
return A
1251
elif algorithm == 'echelon_form':
1252
return random_rref_matrix(parent, *args, **kwds)
1253
elif algorithm == 'echelonizable':
1254
return random_echelonizable_matrix(parent, *args, **kwds)
1255
elif algorithm == 'diagonalizable':
1256
return random_diagonalizable_matrix(parent, *args, **kwds)
1257
elif algorithm == 'subspaces':
1258
return random_subspaces_matrix(parent, *args, **kwds)
1259
elif algorithm == 'unimodular':
1260
return random_unimodular_matrix(parent, *args, **kwds)
1261
else:
1262
raise ValueError('random matrix algorithm "%s" is not recognized' % algorithm)
1263
1264
1265
def diagonal_matrix(arg0=None, arg1=None, arg2=None, sparse=True):
1266
r"""
1267
Return a square matrix with specified diagonal entries, and zeros elsewhere.
1268
1269
FORMATS:
1270
1271
1. diagonal_matrix(entries)
1272
1273
2. diagonal_matrix(nrows, entries)
1274
1275
3. diagonal_matrix(ring, entries)
1276
1277
4. diagonal_matrix(ring, nrows, entries)
1278
1279
INPUT:
1280
1281
- ``entries`` - the values to place along the diagonal
1282
of the returned matrix. This may be a flat list, a
1283
flat tuple, a vector or free module element, or
1284
a one-dimensional NumPy array.
1285
1286
- ``nrows`` - the size of the returned matrix, which
1287
will have an equal number of columns
1288
1289
- ``ring`` - the ring containing the entries of the
1290
diagonal entries. This may not be specified in
1291
combination with a NumPy array.
1292
1293
- ``sparse`` - default: ``True`` - whether or not
1294
the result has a sparse implementation.
1295
1296
OUTPUT:
1297
1298
A square matrix over the given ``ring`` with a size
1299
given by ``nrows``. If the ring is not given it
1300
is inferred from the given entries. The values on
1301
the diagonal of the returned matrix come from ``entries``.
1302
If the number of entries is not enough to fill the whole
1303
diagonal, it is padded with zeros.
1304
1305
EXAMPLES:
1306
1307
We first demonstrate each of the input formats with various
1308
different ways to specify the entries.
1309
1310
Format 1: a flat list of entries. ::
1311
1312
sage: A = diagonal_matrix([2, 1.3, 5]); A
1313
[ 2.00000000000000 0.000000000000000 0.000000000000000]
1314
[0.000000000000000 1.30000000000000 0.000000000000000]
1315
[0.000000000000000 0.000000000000000 5.00000000000000]
1316
sage: A.parent()
1317
Full MatrixSpace of 3 by 3 sparse matrices over Real Field with 53 bits of precision
1318
1319
Format 2: size specified, a tuple with initial entries. Note that a short list of entries
1320
is effectively padded with zeros. ::
1321
1322
sage: A = diagonal_matrix(3, (4, 5)); A
1323
[4 0 0]
1324
[0 5 0]
1325
[0 0 0]
1326
sage: A.parent()
1327
Full MatrixSpace of 3 by 3 sparse matrices over Integer Ring
1328
1329
Format 3: ring specified, a vector of entries. ::
1330
1331
sage: A = diagonal_matrix(QQ, vector(ZZ, [1,2,3])); A
1332
[1 0 0]
1333
[0 2 0]
1334
[0 0 3]
1335
sage: A.parent()
1336
Full MatrixSpace of 3 by 3 sparse matrices over Rational Field
1337
1338
Format 4: ring, size and list of entries. ::
1339
1340
sage: A = diagonal_matrix(FiniteField(3), 3, [2, 16]); A
1341
[2 0 0]
1342
[0 1 0]
1343
[0 0 0]
1344
sage: A.parent()
1345
Full MatrixSpace of 3 by 3 sparse matrices over Finite Field of size 3
1346
1347
NumPy arrays may be used as input. ::
1348
1349
sage: import numpy
1350
sage: entries = numpy.array([1.2, 5.6]); entries
1351
array([ 1.2, 5.6])
1352
sage: A = diagonal_matrix(3, entries); A
1353
[1.2 0.0 0.0]
1354
[0.0 5.6 0.0]
1355
[0.0 0.0 0.0]
1356
sage: A.parent()
1357
Full MatrixSpace of 3 by 3 sparse matrices over Real Double Field
1358
1359
sage: j = numpy.complex(0,1)
1360
sage: entries = numpy.array([2.0+j, 8.1, 3.4+2.6*j]); entries
1361
array([ 2.0+1.j , 8.1+0.j , 3.4+2.6j])
1362
sage: A = diagonal_matrix(entries); A
1363
[2.0 + 1.0*I 0.0 0.0]
1364
[ 0.0 8.1 0.0]
1365
[ 0.0 0.0 3.4 + 2.6*I]
1366
sage: A.parent()
1367
Full MatrixSpace of 3 by 3 sparse matrices over Complex Double Field
1368
1369
sage: entries = numpy.array([4, 5, 6])
1370
sage: A = diagonal_matrix(entries); A
1371
[4 0 0]
1372
[0 5 0]
1373
[0 0 6]
1374
sage: A.parent()
1375
Full MatrixSpace of 3 by 3 sparse matrices over Integer Ring
1376
1377
sage: entries = numpy.array([4.1, 5.2, 6.3])
1378
sage: A = diagonal_matrix(ZZ, entries); A
1379
Traceback (most recent call last):
1380
...
1381
TypeError: Cannot convert non-integral float to integer
1382
1383
By default returned matrices have a sparse implementation. This can be changed
1384
when using any of the formats. ::
1385
1386
sage: A = diagonal_matrix([1,2,3], sparse=False)
1387
sage: A.parent()
1388
Full MatrixSpace of 3 by 3 dense matrices over Integer Ring
1389
1390
An empty list and no ring specified defaults to the integers. ::
1391
1392
sage: A = diagonal_matrix([])
1393
sage: A.parent()
1394
Full MatrixSpace of 0 by 0 sparse matrices over Integer Ring
1395
1396
Giving the entries improperly may first complain about not having a length. ::
1397
1398
sage: diagonal_matrix(QQ, 5, 10)
1399
Traceback (most recent call last):
1400
...
1401
TypeError: unable to determine number of entries for diagonal matrix construction
1402
1403
Giving too many entries will raise an error. ::
1404
1405
sage: diagonal_matrix(QQ, 3, [1,2,3,4])
1406
Traceback (most recent call last):
1407
...
1408
ValueError: number of diagonal matrix entries (4) exceeds the requested matrix size (3)
1409
1410
A negative size sometimes causes the error that there are too many elements. ::
1411
1412
sage: diagonal_matrix(-2, [2])
1413
Traceback (most recent call last):
1414
...
1415
ValueError: number of diagonal matrix entries (1) exceeds the requested matrix size (-2)
1416
1417
Types for the entries are limited, even though they may have a length. ::
1418
1419
sage: diagonal_matrix(x^2)
1420
Traceback (most recent call last):
1421
...
1422
TypeError: diagonal matrix entries are not a supported type (list, tuple, vector, or NumPy array)
1423
1424
AUTHOR:
1425
1426
- Rob Beezer (2011-01-11): total rewrite
1427
"""
1428
# Roll arguments leftward
1429
#
1430
# Leads with a ring?
1431
# Formats 3, 4, else remains None
1432
ring = None
1433
if rings.is_Ring(arg0):
1434
ring = arg0
1435
arg0 = arg1
1436
arg1 = arg2
1437
# Size of matrix specified?
1438
# Formats 2, 4
1439
nrows = None
1440
if isinstance(arg0, (int, long, rings.Integer)):
1441
nrows = arg0
1442
arg0 = arg1
1443
# Object holding entries
1444
# Formats 1, 2, 3, 4
1445
entries = arg0
1446
1447
# Reconcile matrix size and number of entries
1448
try:
1449
nentries = len(entries)
1450
except TypeError:
1451
raise TypeError('unable to determine number of entries for diagonal matrix construction')
1452
# sometimes catches a negative size
1453
if not nrows is None and nentries > nrows:
1454
raise ValueError('number of diagonal matrix entries (%s) exceeds the requested matrix size (%s)' % (nentries, nrows))
1455
if nrows is None:
1456
nrows = nentries
1457
1458
# provide a default ring for an empty list
1459
if len(entries) == 0 and ring is None:
1460
ring = rings.ZZ
1461
1462
# Sanity check on entries (partially, e.g. a list of lists will survive this check)
1463
from numpy import ndarray
1464
if not any([isinstance(entries, (list, tuple)), isinstance(entries, ndarray), is_Vector(entries)]):
1465
raise TypeError('diagonal matrix entries are not a supported type (list, tuple, vector, or NumPy array)')
1466
1467
# Convert entries to a list v over a common ring
1468
from sage.modules.free_module_element import prepare
1469
v, ring = prepare(entries, ring)
1470
1471
# Create a "diagonal" dictionary for matrix constructor
1472
# If nentries < nrows, diagonal is effectively padded with zeros at end
1473
w = {}
1474
for i in range(len(v)):
1475
w[(i,i)] = v[i]
1476
1477
# Ship ring, matrix size, dictionary to matrix constructor
1478
if ring is None:
1479
return matrix(nrows, nrows, w, sparse=sparse)
1480
else:
1481
return matrix(ring, nrows, nrows, w, sparse=sparse)
1482
1483
1484
def identity_matrix(ring, n=0, sparse=False):
1485
r"""
1486
Return the `n \times n` identity matrix over the given
1487
ring.
1488
1489
The default ring is the integers.
1490
1491
EXAMPLES::
1492
1493
sage: M = identity_matrix(QQ, 2); M
1494
[1 0]
1495
[0 1]
1496
sage: M.parent()
1497
Full MatrixSpace of 2 by 2 dense matrices over Rational Field
1498
sage: M = identity_matrix(2); M
1499
[1 0]
1500
[0 1]
1501
sage: M.parent()
1502
Full MatrixSpace of 2 by 2 dense matrices over Integer Ring
1503
sage: M.is_mutable()
1504
True
1505
sage: M = identity_matrix(3, sparse=True); M
1506
[1 0 0]
1507
[0 1 0]
1508
[0 0 1]
1509
sage: M.parent()
1510
Full MatrixSpace of 3 by 3 sparse matrices over Integer Ring
1511
sage: M.is_mutable()
1512
True
1513
"""
1514
if isinstance(ring, (int, long, rings.Integer)):
1515
n = ring
1516
ring = rings.ZZ
1517
return matrix_space.MatrixSpace(ring, n, n, sparse)(1)
1518
1519
1520
def zero_matrix(ring, nrows, ncols=None, sparse=False):
1521
r"""
1522
Return the `nrows \times ncols` zero matrix over the given
1523
ring.
1524
1525
The default ring is the integers.
1526
1527
EXAMPLES::
1528
1529
sage: M = zero_matrix(QQ, 2); M
1530
[0 0]
1531
[0 0]
1532
sage: M.parent()
1533
Full MatrixSpace of 2 by 2 dense matrices over Rational Field
1534
sage: M = zero_matrix(2, 3); M
1535
[0 0 0]
1536
[0 0 0]
1537
sage: M.parent()
1538
Full MatrixSpace of 2 by 3 dense matrices over Integer Ring
1539
sage: M.is_mutable()
1540
True
1541
sage: M = zero_matrix(3, 1, sparse=True); M
1542
[0]
1543
[0]
1544
[0]
1545
sage: M.parent()
1546
Full MatrixSpace of 3 by 1 sparse matrices over Integer Ring
1547
sage: M.is_mutable()
1548
True
1549
"""
1550
if isinstance(ring, (int, long, rings.Integer)):
1551
nrows, ncols = (ring, nrows)
1552
ring = rings.ZZ
1553
return matrix_space.MatrixSpace(ring, nrows, ncols, sparse)(0)
1554
1555
def ones_matrix(ring, nrows=None, ncols=None, sparse=False):
1556
r"""
1557
Return a matrix with all entries equal to 1.
1558
1559
CALL FORMATS:
1560
1561
In each case, the optional keyword ``sparse`` can be used.
1562
1563
1. ones_matrix(ring, nrows, ncols)
1564
2. ones_matrix(ring, nrows)
1565
3. ones_matrix(nrows, ncols)
1566
4. ones_matrix(nrows)
1567
1568
INPUT:
1569
1570
- ``ring`` - default: ``ZZ`` - base ring for the matrix.
1571
- ``nrows`` - number of rows in the matrix.
1572
- ``ncols`` - number of columns in the matrix.
1573
If omitted, defaults to the number of rows, producing a square matrix.
1574
- ``sparse`` - default: ``False`` - if ``True`` creates a sparse representation.
1575
1576
OUTPUT:
1577
1578
A matrix of size ``nrows`` by ``ncols`` over the ``ring`` with every
1579
entry equal to 1. While the result is far from sparse, you may wish
1580
to choose a sparse representation when mixing this matrix with
1581
other sparse matrices.
1582
1583
EXAMPLES:
1584
1585
A call specifying the ring and the size. ::
1586
1587
sage: M= ones_matrix(QQ, 2, 5); M
1588
[1 1 1 1 1]
1589
[1 1 1 1 1]
1590
sage: M.parent()
1591
Full MatrixSpace of 2 by 5 dense matrices over Rational Field
1592
1593
Without specifying the number of columns, the result is square. ::
1594
1595
sage: M = ones_matrix(RR, 2); M
1596
[1.00000000000000 1.00000000000000]
1597
[1.00000000000000 1.00000000000000]
1598
sage: M.parent()
1599
Full MatrixSpace of 2 by 2 dense matrices over Real Field with 53 bits of precision
1600
1601
The ring defaults to the integers if not given. ::
1602
1603
sage: M = ones_matrix(2, 3); M
1604
[1 1 1]
1605
[1 1 1]
1606
sage: M.parent()
1607
Full MatrixSpace of 2 by 3 dense matrices over Integer Ring
1608
1609
A lone integer input produces a square matrix over the integers. ::
1610
1611
sage: M = ones_matrix(3); M
1612
[1 1 1]
1613
[1 1 1]
1614
[1 1 1]
1615
sage: M.parent()
1616
Full MatrixSpace of 3 by 3 dense matrices over Integer Ring
1617
1618
The result can have a sparse implementation. ::
1619
1620
sage: M = ones_matrix(3, 1, sparse=True); M
1621
[1]
1622
[1]
1623
[1]
1624
sage: M.parent()
1625
Full MatrixSpace of 3 by 1 sparse matrices over Integer Ring
1626
1627
Giving just a ring will yield an error. ::
1628
1629
sage: ones_matrix(CC)
1630
Traceback (most recent call last):
1631
...
1632
ValueError: constructing an all ones matrix requires at least one dimension
1633
"""
1634
if isinstance(ring, (int, long, rings.Integer)):
1635
nrows, ncols = (ring, nrows)
1636
ring = rings.ZZ
1637
if nrows is None:
1638
raise ValueError("constructing an all ones matrix requires at least one dimension")
1639
if ncols is None:
1640
nents = nrows**2
1641
else:
1642
nents = nrows*ncols
1643
one = ring(1)
1644
return matrix_space.MatrixSpace(ring, nrows, ncols, sparse).matrix([one]*nents)
1645
1646
def elementary_matrix(arg0, arg1=None, **kwds):
1647
r"""
1648
Creates a square matrix that corresponds to a row operation or a column operation.
1649
1650
FORMATS:
1651
1652
In each case, ``R`` is the base ring, and is optional. ``n`` is the size
1653
of the square matrix created. Any call may include the ``sparse`` keyword
1654
to determine the representation used. The default is ``False`` which
1655
leads to a dense representation. We describe the matrices by their
1656
associated row operation, see the output description for more.
1657
1658
- ``elementary_matrix(R, n, row1=i, row2=j)``
1659
1660
The matrix which swaps rows ``i`` and ``j``.
1661
1662
- ``elementary_matrix(R, n, row1=i, scale=s)``
1663
1664
The matrix which multiplies row ``i`` by ``s``.
1665
1666
- ``elementary_matrix(R, n, row1=i, row2=j, scale=s)``
1667
1668
The matrix which multiplies row ``j`` by ``s``
1669
and adds it to row ``i``.
1670
1671
Elementary matrices representing column operations are created
1672
in an entirely analogous way, replacing ``row1`` by ``col1`` and
1673
replacing ``row2`` by ``col2``.
1674
1675
Specifying the ring for entries of the matrix is optional. If it
1676
is not given, and a scale parameter is provided, then a ring containing
1677
the value of ``scale`` will be used. Otherwise, the ring defaults
1678
to the integers.
1679
1680
OUTPUT:
1681
1682
An elementary matrix is a square matrix that is very close to being
1683
an identity matrix. If ``E`` is an elementary matrix and ``A`` is any
1684
matrix with the same number of rows, then ``E*A`` is the result of
1685
applying a row operation to ``A``. This is how the three types
1686
created by this function are described. Similarly, an elementary matrix
1687
can be associated with a column operation, so if ``E`` has the same number
1688
of columns as ``A`` then ``A*E`` is the result of performing a column
1689
operation on ``A``.
1690
1691
An elementary matrix representing a row operation is created if ``row1``
1692
is specified, while an elementary matrix representing a column operation
1693
is created if ``col1`` is specified.
1694
1695
EXAMPLES:
1696
1697
Over the integers, creating row operations. Recall that row
1698
and column numbering begins at zero. ::
1699
1700
sage: A = matrix(ZZ, 4, 10, range(40)); A
1701
[ 0 1 2 3 4 5 6 7 8 9]
1702
[10 11 12 13 14 15 16 17 18 19]
1703
[20 21 22 23 24 25 26 27 28 29]
1704
[30 31 32 33 34 35 36 37 38 39]
1705
1706
sage: E = elementary_matrix(4, row1=1, row2=3); E
1707
[1 0 0 0]
1708
[0 0 0 1]
1709
[0 0 1 0]
1710
[0 1 0 0]
1711
sage: E*A
1712
[ 0 1 2 3 4 5 6 7 8 9]
1713
[30 31 32 33 34 35 36 37 38 39]
1714
[20 21 22 23 24 25 26 27 28 29]
1715
[10 11 12 13 14 15 16 17 18 19]
1716
1717
sage: E = elementary_matrix(4, row1=2, scale=10); E
1718
[ 1 0 0 0]
1719
[ 0 1 0 0]
1720
[ 0 0 10 0]
1721
[ 0 0 0 1]
1722
sage: E*A
1723
[ 0 1 2 3 4 5 6 7 8 9]
1724
[ 10 11 12 13 14 15 16 17 18 19]
1725
[200 210 220 230 240 250 260 270 280 290]
1726
[ 30 31 32 33 34 35 36 37 38 39]
1727
1728
sage: E = elementary_matrix(4, row1=2, row2=1, scale=10); E
1729
[ 1 0 0 0]
1730
[ 0 1 0 0]
1731
[ 0 10 1 0]
1732
[ 0 0 0 1]
1733
sage: E*A
1734
[ 0 1 2 3 4 5 6 7 8 9]
1735
[ 10 11 12 13 14 15 16 17 18 19]
1736
[120 131 142 153 164 175 186 197 208 219]
1737
[ 30 31 32 33 34 35 36 37 38 39]
1738
1739
Over the rationals, now as column operations. Recall that row
1740
and column numbering begins at zero. Checks now have the
1741
elementary matrix on the right. ::
1742
1743
sage: A = matrix(QQ, 5, 4, range(20)); A
1744
[ 0 1 2 3]
1745
[ 4 5 6 7]
1746
[ 8 9 10 11]
1747
[12 13 14 15]
1748
[16 17 18 19]
1749
1750
sage: E = elementary_matrix(QQ, 4, col1=1, col2=3); E
1751
[1 0 0 0]
1752
[0 0 0 1]
1753
[0 0 1 0]
1754
[0 1 0 0]
1755
sage: A*E
1756
[ 0 3 2 1]
1757
[ 4 7 6 5]
1758
[ 8 11 10 9]
1759
[12 15 14 13]
1760
[16 19 18 17]
1761
1762
sage: E = elementary_matrix(QQ, 4, col1=2, scale=1/2); E
1763
[ 1 0 0 0]
1764
[ 0 1 0 0]
1765
[ 0 0 1/2 0]
1766
[ 0 0 0 1]
1767
sage: A*E
1768
[ 0 1 1 3]
1769
[ 4 5 3 7]
1770
[ 8 9 5 11]
1771
[12 13 7 15]
1772
[16 17 9 19]
1773
1774
sage: E = elementary_matrix(QQ, 4, col1=2, col2=1, scale=10); E
1775
[ 1 0 0 0]
1776
[ 0 1 10 0]
1777
[ 0 0 1 0]
1778
[ 0 0 0 1]
1779
sage: A*E
1780
[ 0 1 12 3]
1781
[ 4 5 56 7]
1782
[ 8 9 100 11]
1783
[ 12 13 144 15]
1784
[ 16 17 188 19]
1785
1786
An elementary matrix is always nonsingular. Then repeated row
1787
operations can be represented by products of elementary matrices,
1788
and this product is again nonsingular. If row operations are to
1789
preserve fundamental properties of a matrix (like rank), we do not
1790
allow scaling a row by zero. Similarly, the corresponding elementary
1791
matrix is not constructed. Also, we do not allow adding a multiple
1792
of a row to itself, since this could also lead to a new zero row. ::
1793
1794
sage: A = matrix(QQ, 4, 10, range(40)); A
1795
[ 0 1 2 3 4 5 6 7 8 9]
1796
[10 11 12 13 14 15 16 17 18 19]
1797
[20 21 22 23 24 25 26 27 28 29]
1798
[30 31 32 33 34 35 36 37 38 39]
1799
1800
sage: E1 = elementary_matrix(QQ, 4, row1=0, row2=1)
1801
sage: E2 = elementary_matrix(QQ, 4, row1=3, row2=0, scale=100)
1802
sage: E = E2*E1
1803
sage: E.is_singular()
1804
False
1805
sage: E*A
1806
[ 10 11 12 13 14 15 16 17 18 19]
1807
[ 0 1 2 3 4 5 6 7 8 9]
1808
[ 20 21 22 23 24 25 26 27 28 29]
1809
[1030 1131 1232 1333 1434 1535 1636 1737 1838 1939]
1810
1811
sage: E3 = elementary_matrix(QQ, 4, row1=3, scale=0)
1812
Traceback (most recent call last):
1813
...
1814
ValueError: scale parameter of row of elementary matrix must be non-zero
1815
1816
sage: E4 = elementary_matrix(QQ, 4, row1=3, row2=3, scale=12)
1817
Traceback (most recent call last):
1818
...
1819
ValueError: cannot add a multiple of a row to itself
1820
1821
If the ring is not specified, and a scale parameter is given, the
1822
base ring for the matrix is chosen to contain the scale parameter.
1823
Otherwise, if no ring is given, the default is the integers. ::
1824
1825
sage: E = elementary_matrix(4, row1=1, row2=3)
1826
sage: E.parent()
1827
Full MatrixSpace of 4 by 4 dense matrices over Integer Ring
1828
1829
sage: E = elementary_matrix(4, row1=1, scale=4/3)
1830
sage: E.parent()
1831
Full MatrixSpace of 4 by 4 dense matrices over Rational Field
1832
1833
sage: E = elementary_matrix(4, row1=1, scale=I)
1834
sage: E.parent()
1835
Full MatrixSpace of 4 by 4 dense matrices over Symbolic Ring
1836
1837
sage: E = elementary_matrix(4, row1=1, scale=CDF(I))
1838
sage: E.parent()
1839
Full MatrixSpace of 4 by 4 dense matrices over Complex Double Field
1840
1841
sage: E = elementary_matrix(4, row1=1, scale=QQbar(I))
1842
sage: E.parent()
1843
Full MatrixSpace of 4 by 4 dense matrices over Algebraic Field
1844
1845
Returned matrices have a dense implementation by default,
1846
but a sparse implementation may be requested. ::
1847
1848
sage: E = elementary_matrix(4, row1=0, row2=1)
1849
sage: E.is_dense()
1850
True
1851
1852
sage: E = elementary_matrix(4, row1=0, row2=1, sparse=True)
1853
sage: E.is_sparse()
1854
True
1855
1856
And the ridiculously small cases. The zero-row matrix cannot be built
1857
since then there are no rows to manipulate. ::
1858
1859
sage: elementary_matrix(QQ, 1, row1=0, row2=0)
1860
[1]
1861
sage: elementary_matrix(QQ, 0, row1=0, row2=0)
1862
Traceback (most recent call last):
1863
...
1864
ValueError: size of elementary matrix must be 1 or greater, not 0
1865
1866
TESTS::
1867
1868
sage: E = elementary_matrix('junk', 5, row1=3, row2=1, scale=12)
1869
Traceback (most recent call last):
1870
...
1871
TypeError: optional first parameter must be a ring, not junk
1872
1873
sage: E = elementary_matrix(5, row1=3, scale='junk')
1874
Traceback (most recent call last):
1875
...
1876
TypeError: scale must be an element of some ring, not junk
1877
1878
sage: E = elementary_matrix(ZZ, 5, row1=3, col2=3, scale=12)
1879
Traceback (most recent call last):
1880
...
1881
ValueError: received an unexpected keyword: col2=3
1882
1883
sage: E = elementary_matrix(QQ, row1=3, scale=12)
1884
Traceback (most recent call last):
1885
...
1886
ValueError: size of elementary matrix must be given
1887
1888
sage: E = elementary_matrix(ZZ, 4/3, row1=3, row2=1, scale=12)
1889
Traceback (most recent call last):
1890
...
1891
TypeError: size of elementary matrix must be an integer, not 4/3
1892
1893
sage: E = elementary_matrix(ZZ, -3, row1=3, row2=1, scale=12)
1894
Traceback (most recent call last):
1895
...
1896
ValueError: size of elementary matrix must be 1 or greater, not -3
1897
1898
sage: E = elementary_matrix(ZZ, 5, row2=1, scale=12)
1899
Traceback (most recent call last):
1900
...
1901
ValueError: row1 or col1 must be specified
1902
1903
sage: E = elementary_matrix(ZZ, 5, row1=3, col1=3, scale=12)
1904
Traceback (most recent call last):
1905
...
1906
ValueError: cannot specify both row1 and col1
1907
1908
sage: E = elementary_matrix(ZZ, 5, row1=4/3, row2=1, scale=12)
1909
Traceback (most recent call last):
1910
...
1911
TypeError: row of elementary matrix must be an integer, not 4/3
1912
1913
sage: E = elementary_matrix(ZZ, 5, col1=5, col2=1, scale=12)
1914
Traceback (most recent call last):
1915
...
1916
ValueError: column of elementary matrix must be positive and smaller than 5, not 5
1917
1918
sage: E = elementary_matrix(ZZ, 5, col1=3, col2=4/3, scale=12)
1919
Traceback (most recent call last):
1920
...
1921
TypeError: column of elementary matrix must be an integer, not 4/3
1922
1923
sage: E = elementary_matrix(ZZ, 5, row1=3, row2=-1, scale=12)
1924
Traceback (most recent call last):
1925
...
1926
ValueError: row of elementary matrix must be positive and smaller than 5, not -1
1927
1928
sage: E = elementary_matrix(ZZ, 5, row1=3, row2=1, scale=4/3)
1929
Traceback (most recent call last):
1930
...
1931
TypeError: scale parameter of elementary matrix must an element of Integer Ring, not 4/3
1932
1933
sage: E = elementary_matrix(ZZ, 5, row1=3)
1934
Traceback (most recent call last):
1935
...
1936
ValueError: insufficient parameters provided to construct elementary matrix
1937
1938
sage: E = elementary_matrix(ZZ, 5, row1=3, row2=3, scale=12)
1939
Traceback (most recent call last):
1940
...
1941
ValueError: cannot add a multiple of a row to itself
1942
1943
sage: E = elementary_matrix(ZZ, 5, col1=3, scale=0)
1944
Traceback (most recent call last):
1945
...
1946
ValueError: scale parameter of column of elementary matrix must be non-zero
1947
1948
AUTHOR:
1949
1950
- Rob Beezer (2011-03-04)
1951
"""
1952
import sage.structure.element
1953
# determine ring and matrix size
1954
if not arg1 is None and not rings.is_Ring(arg0):
1955
raise TypeError('optional first parameter must be a ring, not {0}'.format(arg0))
1956
scale = kwds.pop('scale', None)
1957
if rings.is_Ring(arg0):
1958
R = arg0
1959
arg0 = arg1
1960
elif scale is not None:
1961
if not sage.structure.element.is_RingElement(scale):
1962
raise TypeError('scale must be an element of some ring, not {0}'.format(scale))
1963
R = scale.parent()
1964
else:
1965
R = rings.ZZ
1966
if arg0 is None:
1967
raise ValueError('size of elementary matrix must be given')
1968
try:
1969
n = rings.Integer(arg0)
1970
except:
1971
raise TypeError('size of elementary matrix must be an integer, not {0}'.format(arg0))
1972
if n <= 0:
1973
raise ValueError('size of elementary matrix must be 1 or greater, not {0}'.format(n))
1974
# row operations or column operations?
1975
# column operation matrix will be transpose of a row operation matrix
1976
row1 = kwds.pop('row1', None)
1977
col1 = kwds.pop('col1', None)
1978
if row1 is None and col1 is None:
1979
raise ValueError('row1 or col1 must be specified')
1980
if not row1 is None and not col1 is None:
1981
raise ValueError('cannot specify both row1 and col1')
1982
rowop = not row1 is None
1983
if rowop:
1984
opstring = "row"
1985
row2 = kwds.pop('row2', None)
1986
else:
1987
opstring = "column"
1988
row1 = col1
1989
row2 = kwds.pop('col2', None)
1990
sparse = kwds.pop('sparse', False)
1991
if kwds:
1992
extra = kwds.popitem()
1993
raise ValueError('received an unexpected keyword: {0}={1}'.format(extra[0], extra[1]))
1994
1995
# analyze parameters to determine matrix type
1996
try:
1997
row1 = rings.Integer(row1)
1998
except:
1999
raise TypeError('{0} of elementary matrix must be an integer, not {1}'.format(opstring, row1))
2000
if row1 < 0 or row1 >= n :
2001
raise ValueError('{0} of elementary matrix must be positive and smaller than {1}, not {2}'.format(opstring, n, row1))
2002
if not row2 is None:
2003
try:
2004
row2 = rings.Integer(row2)
2005
except:
2006
raise TypeError('{0} of elementary matrix must be an integer, not {1}'.format(opstring, row2))
2007
if row2 < 0 or row2 >= n :
2008
raise ValueError('{0} of elementary matrix must be positive and smaller than {1}, not {2}'.format(opstring, n, row2))
2009
if not scale is None:
2010
try:
2011
scale = R(scale)
2012
except:
2013
raise TypeError('scale parameter of elementary matrix must an element of {0}, not {1}'.format(R, scale))
2014
2015
# determine type of matrix and adjust an identity matrix
2016
# return row operation matrix or the transpose as a column operation matrix
2017
elem = identity_matrix(R, n, sparse=sparse)
2018
if row2 is None and scale is None:
2019
raise ValueError('insufficient parameters provided to construct elementary matrix')
2020
elif not row2 is None and not scale is None:
2021
if row1 == row2:
2022
raise ValueError('cannot add a multiple of a {0} to itself'.format(opstring))
2023
elem[row1, row2] = scale
2024
elif not row2 is None and scale is None:
2025
elem[row1, row1] = 0
2026
elem[row2, row2] = 0
2027
elem[row1, row2] = 1
2028
elem[row2, row1] = 1
2029
elif row2 is None and not scale is None:
2030
if scale == 0:
2031
raise ValueError('scale parameter of {0} of elementary matrix must be non-zero'.format(opstring))
2032
elem[row1, row1] = scale
2033
if rowop:
2034
return elem
2035
else:
2036
return elem.transpose()
2037
2038
def _determine_block_matrix_grid(sub_matrices):
2039
r"""
2040
For internal use. This tries to determine the dimensions
2041
of rows/columns when assembling the matrices in sub_matrices in a
2042
rectangular grid. It returns a pair of lists containing
2043
respectively the sizes of rows and columns.
2044
2045
sub_matrices must be a list of lists of matrices. All sublists
2046
are expected to be the same size.
2047
2048
Non-zero scalars are considered to be square matrices of any size,
2049
and zeroes are considered to be zero matrices of any size.
2050
2051
A ValueError is raised if there is insufficient or
2052
conflicting information.
2053
2054
TESTS::
2055
2056
sage: from sage.matrix.constructor import _determine_block_matrix_grid
2057
sage: A = matrix(QQ, 2, 2, [3,9,6,10])
2058
sage: _determine_block_matrix_grid([[A, A], [A, A]])
2059
([2, 2], [2, 2])
2060
2061
sage: B = matrix(QQ, 1, 1, [ 1 ] )
2062
sage: C = matrix(QQ, 2, 2, [ 2, 3, 4, 5 ] )
2063
sage: _determine_block_matrix_grid([[B, 0], [0, C]])
2064
([1, 2], [1, 2])
2065
"""
2066
2067
nrows = len(sub_matrices)
2068
if nrows == 0:
2069
return ([], [])
2070
ncols = len(sub_matrices[0])
2071
2072
if ncols == 0:
2073
return ([0] * nrows, [])
2074
2075
row_heights = [None] * nrows
2076
col_widths = [None] * ncols
2077
2078
changing = True
2079
while changing:
2080
changing = False
2081
for i in range(nrows):
2082
for j in range(ncols):
2083
M = sub_matrices[i][j]
2084
sub_width = None
2085
sub_height = None
2086
if is_Matrix(M):
2087
sub_width = M.ncols()
2088
sub_height = M.nrows()
2089
elif M: # non-zero scalar is interpreted as a square matrix
2090
if row_heights[i] is None:
2091
sub_width = col_widths[j]
2092
else:
2093
sub_width = row_heights[i]
2094
sub_height = sub_width
2095
if sub_width is not None:
2096
if col_widths[j] is None:
2097
changing = True
2098
col_widths[j] = sub_width
2099
elif col_widths[j] != sub_width:
2100
raise ValueError("incompatible submatrix widths")
2101
if sub_height is not None:
2102
if row_heights[i] is None:
2103
changing = True
2104
row_heights[i] = sub_height
2105
elif row_heights[i] != sub_height:
2106
raise ValueError("incompatible submatrix heights")
2107
2108
if None in row_heights or None in col_widths:
2109
if None in row_heights or None in col_widths:
2110
raise ValueError("insufficient information to determine dimensions.")
2111
2112
return (row_heights, col_widths)
2113
2114
def _determine_block_matrix_rows(sub_matrices):
2115
"""
2116
For internal use. This tests if the matrices in sub_matrices
2117
fit in a rectangular matrix when assembled a row at a time.
2118
2119
sub_matrices must be a list of lists of matrices.
2120
2121
It returns a pair (row_heights, zero_widths, width) where
2122
row_heights is the list of row heights, zero_widths is the
2123
total width filled up by zero matrices per row, and width
2124
is the total width of the resulting matrix.
2125
2126
Non-zero scalars are considered to be square matrices of any size,
2127
and zeroes are considered to be zero matrices of any size.
2128
2129
A ValueError is raised if there is insufficient or
2130
conflicting information.
2131
2132
TESTS::
2133
2134
sage: from sage.matrix.constructor import _determine_block_matrix_rows
2135
sage: A = Matrix(ZZ, 1, 4, [1, 2, 3, 4])
2136
sage: _determine_block_matrix_rows([ [1, 1], [ A ] ])
2137
([2, 1], [0, 0], 4)
2138
2139
sage: B = Matrix(ZZ, 2, 2, [1, 2, 3, 4])
2140
sage: _determine_block_matrix_rows([ [B, B], [B, 1] ])
2141
([2, 2], [0, 0], 4)
2142
"""
2143
2144
total_height = 0
2145
total_width = None
2146
2147
row_heights = [ None ] * len(sub_matrices)
2148
zero_widths = [ 0 ] * len(sub_matrices)
2149
2150
# We first do a pass to see if we can determine the width
2151
unknowns = False
2152
for i in range(len(sub_matrices)):
2153
R = sub_matrices[i]
2154
height = None
2155
# We first do a pass to see if we can determine the height
2156
# of this row
2157
found_zeroes = False
2158
for M in R:
2159
if is_Matrix(M):
2160
if height is None:
2161
height = M.nrows()
2162
elif height != M.nrows():
2163
raise ValueError("incompatible submatrix heights")
2164
elif not M:
2165
found_zeroes = True
2166
if len(R) == 0:
2167
height = 0
2168
2169
# If we have a height, then we know the dimensions of any
2170
# non-zero scalars, and can maybe compute the width
2171
if height is not None and not found_zeroes:
2172
width = 0
2173
for M in R:
2174
if is_Matrix(M):
2175
width += M.ncols()
2176
else:
2177
# non-zero scalar
2178
width += height
2179
if total_width is None:
2180
total_width = width
2181
elif total_width != width:
2182
raise ValueError("incompatible submatrix widths")
2183
row_heights[i] = height
2184
else:
2185
# We don't set height here even if we know it,
2186
# to signal this row hasn't been fit yet.
2187
unknowns = True
2188
2189
if total_width is None:
2190
raise ValueError("insufficient information to determine submatrix widths")
2191
2192
if unknowns:
2193
# Do a second pass and see if the remaining rows can be
2194
# determined now that we know the width of the matrix.
2195
for i in range(len(sub_matrices)):
2196
if row_heights[i] is not None:
2197
continue
2198
R = sub_matrices[i]
2199
zero_state = 0
2200
# 0: no zeroes found
2201
# 1: consecutive zeroes found
2202
# 2: consecutive zeroes followed by non-zero found
2203
# 3: non-consecutive zeroes found
2204
scalars = 0
2205
width = 0
2206
height = None
2207
for j in range(len(R)):
2208
M = R[j]
2209
if is_Matrix(M):
2210
height = M.nrows()
2211
width += M.ncols()
2212
if zero_state == 1:
2213
zero_state = 2
2214
elif not M:
2215
if zero_state == 0:
2216
zero_state = 1
2217
elif zero_state == 2:
2218
zero_state = 3
2219
else:
2220
scalars += 1
2221
2222
remaining_width = total_width - width
2223
# This remaining width has to be split over the
2224
# zeroes and (non-zero) scalars
2225
2226
if height is not None:
2227
remaining_width -= scalars * height
2228
if remaining_width < 0:
2229
raise ValueError("incompatible submatrix widths")
2230
if remaining_width > 0 and zero_state == 3:
2231
raise ValueError("insufficient information to determine submatrix widths")
2232
if remaining_width > 0 and zero_state == 0:
2233
raise ValueError("incompatible submatrix widths")
2234
# otherwise, things fit
2235
row_heights[i] = height
2236
zero_widths[i] = remaining_width
2237
elif zero_state != 0:
2238
# if we don't know the height, and there are zeroes,
2239
# we can't determine the height
2240
raise ValueError("insufficient information to determine submatrix heights")
2241
elif total_width % len(R) != 0:
2242
raise ValueError("incompatible submatrix widths")
2243
else:
2244
height = int(total_width / len(R))
2245
row_heights[i] = height
2246
2247
# If we got this far, then everything fits
2248
return (row_heights, zero_widths, total_width)
2249
2250
def block_matrix(*args, **kwds):
2251
r"""
2252
Returns a larger matrix made by concatenating submatrices
2253
(rows first, then columns). For example, the matrix
2254
2255
::
2256
2257
[ A B ]
2258
[ C D ]
2259
2260
is made up of submatrices A, B, C, and D.
2261
2262
INPUT:
2263
2264
The block_matrix command takes a list of submatrices to add
2265
as blocks, optionally preceded by a ring and the number of block rows
2266
and block columns, and returns a matrix.
2267
2268
The submatrices can be specified as a list of matrices (using
2269
``nrows`` and ``ncols`` to determine their layout), or a list
2270
of lists of matrices, where each list forms a row.
2271
2272
- ``ring`` - the base ring
2273
2274
- ``nrows`` - the number of block rows
2275
2276
- ``ncols`` - the number of block cols
2277
2278
- ``sub_matrices`` - matrices (see below for syntax)
2279
2280
- ``subdivide`` - boolean, whether or not to add
2281
subdivision information to the matrix
2282
2283
- ``sparse`` - boolean, whether to make the resulting matrix sparse
2284
2285
2286
EXAMPLES::
2287
2288
sage: A = matrix(QQ, 2, 2, [3,9,6,10])
2289
sage: block_matrix([ [A, -A], [~A, 100*A] ])
2290
[ 3 9| -3 -9]
2291
[ 6 10| -6 -10]
2292
[-----------+-----------]
2293
[-5/12 3/8| 300 900]
2294
[ 1/4 -1/8| 600 1000]
2295
2296
If the number of submatrices in each row is the same,
2297
you can specify the submatrices as a single list too::
2298
2299
sage: block_matrix(2, 2, [ A, A, A, A ])
2300
[ 3 9| 3 9]
2301
[ 6 10| 6 10]
2302
[-----+-----]
2303
[ 3 9| 3 9]
2304
[ 6 10| 6 10]
2305
2306
2307
One can use constant entries::
2308
2309
sage: block_matrix([ [1, A], [0, 1] ])
2310
[ 1 0| 3 9]
2311
[ 0 1| 6 10]
2312
[-----+-----]
2313
[ 0 0| 1 0]
2314
[ 0 0| 0 1]
2315
2316
A zero entry may represent any square or non-square zero matrix::
2317
2318
sage: B = matrix(QQ, 1, 1, [ 1 ] )
2319
sage: C = matrix(QQ, 2, 2, [ 2, 3, 4, 5 ] )
2320
sage: block_matrix([ [B, 0], [0, C] ])
2321
[1|0 0]
2322
[-+---]
2323
[0|2 3]
2324
[0|4 5]
2325
2326
One can specify the number of rows or columns as keywords too::
2327
2328
sage: block_matrix([A, -A, ~A, 100*A], ncols=4)
2329
[ 3 9| -3 -9|-5/12 3/8| 300 900]
2330
[ 6 10| -6 -10| 1/4 -1/8| 600 1000]
2331
2332
sage: block_matrix([A, -A, ~A, 100*A], nrows=1)
2333
[ 3 9| -3 -9|-5/12 3/8| 300 900]
2334
[ 6 10| -6 -10| 1/4 -1/8| 600 1000]
2335
2336
It handles base rings nicely too::
2337
2338
sage: R.<x> = ZZ['x']
2339
sage: block_matrix(2, 2, [1/2, A, 0, x-1])
2340
[ 1/2 0| 3 9]
2341
[ 0 1/2| 6 10]
2342
[-----------+-----------]
2343
[ 0 0|x - 1 0]
2344
[ 0 0| 0 x - 1]
2345
2346
sage: block_matrix(2, 2, [1/2, A, 0, x-1]).parent()
2347
Full MatrixSpace of 4 by 4 dense matrices over Univariate Polynomial Ring in x over Rational Field
2348
2349
Subdivisions are optional. If they are disabled, the columns need not line up::
2350
2351
sage: B = matrix(QQ, 2, 3, range(6))
2352
sage: block_matrix([ [~A, B], [B, ~A] ], subdivide=False)
2353
[-5/12 3/8 0 1 2]
2354
[ 1/4 -1/8 3 4 5]
2355
[ 0 1 2 -5/12 3/8]
2356
[ 3 4 5 1/4 -1/8]
2357
2358
Without subdivisions it also deduces dimensions for scalars if possible::
2359
2360
sage: C = matrix(ZZ, 1, 2, range(2))
2361
sage: block_matrix([ [ C, 0 ], [ 3, 4 ], [ 5, 6, C ] ], subdivide=False )
2362
[0 1 0 0]
2363
[3 0 4 0]
2364
[0 3 0 4]
2365
[5 6 0 1]
2366
2367
If all submatrices are sparse (unless there are none at all), the result
2368
will be a sparse matrix. Otherwise it will be dense by default. The
2369
``sparse`` keyword can be used to override this::
2370
2371
sage: A = Matrix(ZZ, 2, 2, [0, 1, 0, 0], sparse=True)
2372
sage: block_matrix([ [ A ], [ A ] ]).parent()
2373
Full MatrixSpace of 4 by 2 sparse matrices over Integer Ring
2374
sage: block_matrix([ [ A ], [ A ] ], sparse=False).parent()
2375
Full MatrixSpace of 4 by 2 dense matrices over Integer Ring
2376
2377
Consecutive zero submatrices are consolidated. ::
2378
2379
sage: B = matrix(2, range(4))
2380
sage: C = matrix(2, 8, range(16))
2381
sage: block_matrix(2, [[B,0,0,B],[C]], subdivide=False)
2382
[ 0 1 0 0 0 0 0 1]
2383
[ 2 3 0 0 0 0 2 3]
2384
[ 0 1 2 3 4 5 6 7]
2385
[ 8 9 10 11 12 13 14 15]
2386
2387
Ambiguity is not tolerated. ::
2388
2389
sage: B = matrix(2, range(4))
2390
sage: C = matrix(2, 8, range(16))
2391
sage: block_matrix(2, [[B,0,B,0],[C]], subdivide=False)
2392
Traceback (most recent call last):
2393
...
2394
ValueError: insufficient information to determine submatrix widths
2395
2396
Historically, giving only a flat list of submatrices, whose number
2397
was a perfect square, would create a new matrix by laying out the submatrices
2398
in a square grid. This behavior is now deprecated. ::
2399
2400
sage: A = matrix(2, 3, range(6))
2401
sage: B = matrix(3, 3, range(9))
2402
sage: block_matrix([A, A, B, B])
2403
doctest:...: DeprecationWarning: invocation of block_matrix with just a list whose length is a perfect square is deprecated. See the documentation for details.
2404
[0 1 2|0 1 2]
2405
[3 4 5|3 4 5]
2406
[-----+-----]
2407
[0 1 2|0 1 2]
2408
[3 4 5|3 4 5]
2409
[6 7 8|6 7 8]
2410
2411
Historically, a flat list of matrices whose number is not a perfect square,
2412
with no specification of the number of rows or columns, would raise an error.
2413
This behavior continues, but could be removed when the deprecation above is
2414
completed. ::
2415
2416
sage: A = matrix(2, 3, range(6))
2417
sage: B = matrix(3, 3, range(9))
2418
sage: block_matrix([A, A, A, B, B, B])
2419
Traceback (most recent call last):
2420
...
2421
ValueError: must specify nrows or ncols for non-square block matrix.
2422
"""
2423
args = list(args)
2424
sparse = kwds.get('sparse',None)
2425
2426
if len(args) == 0:
2427
if sparse is not None:
2428
return matrix_space.MatrixSpace(rings.ZZ, 0, 0, sparse=sparse)([])
2429
else:
2430
return matrix_space.MatrixSpace(rings.ZZ, 0, 0)([])
2431
2432
if len(args) >= 1 and rings.is_Ring(args[0]):
2433
# A ring is specified
2434
if kwds.get('ring', args[0]) != args[0]:
2435
raise ValueError("base ring specified twice and they are different")
2436
ring = args[0]
2437
args.pop(0)
2438
else:
2439
ring = kwds.get('ring', None)
2440
2441
if len(args) >= 1:
2442
try:
2443
nrows = int(args[0])
2444
args.pop(0)
2445
if kwds.get('nrows', nrows) != nrows:
2446
raise ValueError("number of rows specified twice and they are different")
2447
except TypeError:
2448
nrows = kwds.get('nrows', None)
2449
else:
2450
nrows = kwds.get('nrows', None)
2451
2452
if len(args) >= 1:
2453
# check to see if additionally, the number of columns is specified
2454
try:
2455
ncols = int(args[0])
2456
args.pop(0)
2457
if kwds.get('ncols', ncols) != ncols:
2458
raise ValueError("number of columns specified twice and they are different")
2459
except TypeError:
2460
ncols = kwds.get('ncols', None)
2461
else:
2462
ncols = kwds.get('ncols', None)
2463
2464
# Now we've taken care of initial ring, nrows, and ncols arguments.
2465
2466
# Now the rest of the arguments are a list of rows, a flat list of
2467
# matrices, or a single value.
2468
2469
if len(args) == 0:
2470
args = [[]]
2471
if len(args) > 1:
2472
print args
2473
raise TypeError("invalid block_matrix invocation")
2474
2475
sub_matrices = args[0]
2476
2477
if is_Matrix(sub_matrices):
2478
# a single matrix (check nrows/ncols/ring)
2479
if (nrows is not None and nrows != 1) or \
2480
(ncols is not None and ncols != 1):
2481
raise ValueError("invalid nrows/ncols passed to block_matrix")
2482
if ring is not None:
2483
M = M.change_ring(ring)
2484
if sparse is not None and M.is_sparse() != sparse:
2485
M = M.sparse_matrix() if sparse else M.dense_matrix()
2486
return M
2487
2488
if not isinstance(sub_matrices, (list, tuple)):
2489
raise TypeError("invalid block_matrix invocation")
2490
2491
subdivide = kwds.get('subdivide', True)
2492
2493
# Will we try to place the matrices in a rectangular grid?
2494
try_grid = True
2495
2496
2497
if len(sub_matrices) == 0:
2498
if (nrows is not None and nrows != 0) or \
2499
(ncols is not None and ncols != 0):
2500
raise ValueError("invalid nrows/ncols passed to block_matrix")
2501
elif isinstance(sub_matrices[0], (list, tuple)):
2502
# A list of lists: verify all elements are lists, and if
2503
# ncols is set, the lengths match.
2504
if nrows is not None and len(sub_matrices) != nrows:
2505
raise ValueError("invalid nrows passed to block_matrix")
2506
first_len = len(sub_matrices[0])
2507
if ncols is not None and first_len != ncols:
2508
raise ValueError("invalid ncols passed to block_matrix")
2509
same_length = all(isinstance(v, (list, tuple)) and len(v) == first_len for v in sub_matrices)
2510
if subdivide and not same_length:
2511
raise ValueError("list of rows is not valid (rows are wrong types or lengths)")
2512
try_grid = same_length
2513
else:
2514
# A flat list
2515
# determine the block dimensions
2516
n = ZZ(len(sub_matrices))
2517
if nrows is None:
2518
if ncols is None:
2519
if n.is_square():
2520
import warnings
2521
warnings.resetwarnings()
2522
warnings.warn("invocation of block_matrix with just a list whose length is a perfect square is deprecated. See the documentation for details.", DeprecationWarning, stacklevel=2)
2523
nrows = ncols = n.sqrt()
2524
else:
2525
# this form (ie just a flat list) could be allowed once deprecated invocation (above) goes away
2526
raise ValueError("must specify nrows or ncols for non-square block matrix.")
2527
else:
2528
nrows = int(n/ncols)
2529
elif ncols is None:
2530
ncols = int(n/nrows)
2531
if nrows * ncols != n:
2532
raise ValueError("given number of rows (%s), columns (%s) incompatible with number of submatrices (%s)" % (nrows, ncols, n))
2533
# Now create a list of lists from this
2534
sub_matrices = [ sub_matrices[i*ncols : (i+1)*ncols] for i in range(nrows) ]
2535
2536
# At this point sub_matrices is a list of lists
2537
2538
# determine the base ring and sparsity
2539
if ring is None:
2540
ring = ZZ
2541
for row in sub_matrices:
2542
for M in row:
2543
R = M.base_ring() if is_Matrix(M) else M.parent()
2544
if R is not ZZ:
2545
ring = sage.categories.pushout.pushout(ring, R)
2546
2547
if sparse is None:
2548
sparse = True
2549
for row in sub_matrices:
2550
for M in row:
2551
if sparse and is_Matrix(M) and not M.is_sparse():
2552
sparse = False
2553
2554
row_heights = None
2555
col_widths = None
2556
zero_widths = None
2557
total_width = None
2558
2559
# We first try to place the matrices in a rectangular grid
2560
if try_grid:
2561
try:
2562
(row_heights, col_widths) = _determine_block_matrix_grid(sub_matrices)
2563
except ValueError as e:
2564
if subdivide:
2565
raise ValueError(e)
2566
2567
2568
if col_widths is None:
2569
# Try placing the matrices in rows instead
2570
# (Only if subdivide is False)
2571
(row_heights, zero_widths, total_width) = _determine_block_matrix_rows(sub_matrices)
2572
2573
2574
# Success, so assemble the final matrix
2575
2576
big = None
2577
for i in range(len(sub_matrices)):
2578
R = sub_matrices[i]
2579
row = None
2580
for j in range(len(R)):
2581
M = R[j]
2582
2583
if is_Matrix(M):
2584
if M.base_ring() is not ring:
2585
M = M.change_ring(ring)
2586
if M.is_sparse() != sparse:
2587
M = M.sparse_matrix() if sparse else M.dense_matrix()
2588
elif not M and zero_widths is not None:
2589
if zero_widths[i] > 0:
2590
M = matrix(ring, row_heights[i], zero_widths[i], 0, sparse=sparse)
2591
zero_widths[i] = 0
2592
else:
2593
continue # zero-width matrix
2594
else:
2595
if zero_widths is not None:
2596
M = matrix(ring, row_heights[i], row_heights[i], M, sparse=sparse)
2597
else:
2598
M = matrix(ring, row_heights[i], col_widths[j], M, sparse=sparse)
2599
2600
# append M to this row
2601
if row is None:
2602
row = M
2603
else:
2604
row = row.augment(M)
2605
2606
# append row to final matrix
2607
if big is None:
2608
big = row
2609
else:
2610
big = big.stack(row)
2611
2612
if big is None:
2613
if ring is None:
2614
ring = ZZ
2615
big = Matrix(ring, 0, 0)
2616
2617
if subdivide:
2618
big.subdivide(running_total(row_heights[:-1]),
2619
running_total(col_widths[:-1]))
2620
2621
return big
2622
2623
def block_diagonal_matrix(*sub_matrices, **kwds):
2624
"""
2625
Create a block matrix whose diagonal block entries are given by
2626
sub_matrices, with zero elsewhere.
2627
2628
See also :meth:`block_matrix`.
2629
2630
EXAMPLES::
2631
2632
sage: A = matrix(ZZ, 2, [1,2,3,4])
2633
sage: block_diagonal_matrix(A, A)
2634
[1 2|0 0]
2635
[3 4|0 0]
2636
[---+---]
2637
[0 0|1 2]
2638
[0 0|3 4]
2639
2640
The sub-matrices need not be square::
2641
2642
sage: B = matrix(QQ, 2, 3, range(6))
2643
sage: block_diagonal_matrix(~A, B)
2644
[ -2 1| 0 0 0]
2645
[ 3/2 -1/2| 0 0 0]
2646
[---------+--------------]
2647
[ 0 0| 0 1 2]
2648
[ 0 0| 3 4 5]
2649
"""
2650
if isinstance(sub_matrices, (list, tuple)) and len(sub_matrices) == 1:
2651
sub_matrices = sub_matrices[0]
2652
n = len(sub_matrices)
2653
entries = [ZZ.zero_element()] * n**2
2654
for i in range(n):
2655
entries[n*i+i] = sub_matrices[i]
2656
return block_matrix(n, n, entries, **kwds)
2657
2658
def jordan_block(eigenvalue, size, sparse=False):
2659
r"""
2660
Returns the Jordan block for the given eigenvalue with given size.
2661
2662
INPUT:
2663
2664
- ``eigenvalue`` - eigenvalue for the diagonal entries of the block
2665
- ``size`` - size of the square matrix
2666
- ``sparse`` - (default: False) - if True, return a sparse matrix
2667
2668
2669
EXAMPLE::
2670
2671
sage: jordan_block(5, 3)
2672
[5 1 0]
2673
[0 5 1]
2674
[0 0 5]
2675
2676
TESTS::
2677
2678
sage: jordan_block(6.2, 'junk')
2679
Traceback (most recent call last):
2680
...
2681
TypeError: size of Jordan block needs to be an integer, not junk
2682
sage: jordan_block(6.2, -1)
2683
Traceback (most recent call last):
2684
...
2685
ValueError: size of Jordan block must be non-negative, not -1
2686
"""
2687
try:
2688
size = ZZ(size)
2689
except TypeError:
2690
msg = "size of Jordan block needs to be an integer, not {0}"
2691
raise TypeError(msg.format(size))
2692
if size < 0:
2693
msg = "size of Jordan block must be non-negative, not {0}"
2694
raise ValueError(msg.format(size))
2695
block = diagonal_matrix([eigenvalue]*size, sparse=sparse)
2696
for i in xrange(size-1):
2697
block[i,i+1]=1
2698
return block
2699
2700
def companion_matrix(poly, format='right'):
2701
r"""
2702
Create a companion matrix from a monic polynomial.
2703
2704
INPUT:
2705
2706
- ``poly`` - a univariate polynomial, or an iterable containing
2707
the coefficients of a polynomial, with low-degree coefficients first.
2708
The polynomial (or the polynomial implied by the coefficients) must
2709
be monic. In other words, the leading coefficient must be one.
2710
A symbolic expression that might also be a polynomial is not
2711
proper input, see examples below.
2712
2713
- ``format`` - default: 'right' - specifies one of four
2714
variations of a companion matrix. Allowable values are
2715
'right', 'left', 'top' and 'bottom', which indicates which
2716
border of the matrix contains the negatives of the coefficients.
2717
2718
OUTPUT:
2719
2720
A square matrix with a size equal to the degree of the polynomial.
2721
The returned matrix has ones above, or below the diagonal, and the
2722
negatives of the coefficients along the indicated border of the
2723
matrix (excepting the leading one coefficient).
2724
See the first examples below for precise illustrations.
2725
2726
EXAMPLES:
2727
2728
Each of the four possibilities. Notice that the coefficients are
2729
specified and their negatives become the entries of the matrix. The
2730
leading one must be given, but is not used. The permutation matrix
2731
``P`` is the identity matrix, with the columns reversed. The last three
2732
statements test the general relationships between the four variants. ::
2733
2734
sage: poly = [-2, -3, -4, -5, -6, 1]
2735
sage: R = companion_matrix(poly, format='right'); R
2736
[0 0 0 0 2]
2737
[1 0 0 0 3]
2738
[0 1 0 0 4]
2739
[0 0 1 0 5]
2740
[0 0 0 1 6]
2741
sage: L = companion_matrix(poly, format='left'); L
2742
[6 1 0 0 0]
2743
[5 0 1 0 0]
2744
[4 0 0 1 0]
2745
[3 0 0 0 1]
2746
[2 0 0 0 0]
2747
sage: B = companion_matrix(poly, format='bottom'); B
2748
[0 1 0 0 0]
2749
[0 0 1 0 0]
2750
[0 0 0 1 0]
2751
[0 0 0 0 1]
2752
[2 3 4 5 6]
2753
sage: T = companion_matrix(poly, format='top'); T
2754
[6 5 4 3 2]
2755
[1 0 0 0 0]
2756
[0 1 0 0 0]
2757
[0 0 1 0 0]
2758
[0 0 0 1 0]
2759
2760
sage: perm = Permutation([5, 4, 3, 2, 1])
2761
sage: P = perm.to_matrix()
2762
sage: L == P*R*P
2763
True
2764
sage: B == R.transpose()
2765
True
2766
sage: T == P*R.transpose()*P
2767
True
2768
2769
A polynomial may be used as input, however a symbolic expression,
2770
even if it looks like a polynomial, is not regarded as such when used
2771
as input to this routine. Obtaining the list of coefficients from a
2772
symbolic polynomial is one route to the companion matrix. ::
2773
2774
sage: x = polygen(QQ, 'x')
2775
sage: p = x^3 - 4*x^2 + 8*x - 12
2776
sage: companion_matrix(p)
2777
[ 0 0 12]
2778
[ 1 0 -8]
2779
[ 0 1 4]
2780
2781
sage: y = var('y')
2782
sage: q = y^3 -2*y + 1
2783
sage: companion_matrix(q)
2784
Traceback (most recent call last):
2785
...
2786
TypeError: input must be a polynomial (not a symbolic expression, see docstring), or other iterable, not y^3 - 2*y + 1
2787
2788
sage: coeff_list = [q(y=0)] + [q.coeff(y^k) for k in range(1, q.degree(y)+1)]
2789
sage: coeff_list
2790
[1, -2, 0, 1]
2791
sage: companion_matrix(coeff_list)
2792
[ 0 0 -1]
2793
[ 1 0 2]
2794
[ 0 1 0]
2795
2796
The minimal polynomial of a companion matrix is equal to the
2797
polynomial used to create it. Used in a block diagonal
2798
construction, they can be used to create matrices with
2799
any desired minimal polynomial, or characteristic polynomial. ::
2800
2801
sage: t = polygen(QQ, 't')
2802
sage: p = t^12 - 7*t^4 + 28*t^2 - 456
2803
sage: C = companion_matrix(p, format='top')
2804
sage: q = C.minpoly(var=t); q
2805
t^12 - 7*t^4 + 28*t^2 - 456
2806
sage: p == q
2807
True
2808
2809
sage: p = t^3 + 3*t - 8
2810
sage: q = t^5 + t - 17
2811
sage: A = block_diagonal_matrix( companion_matrix(p),
2812
... companion_matrix(p^2),
2813
... companion_matrix(q),
2814
... companion_matrix(q) )
2815
sage: A.charpoly(var=t).factor()
2816
(t^3 + 3*t - 8)^3 * (t^5 + t - 17)^2
2817
sage: A.minpoly(var=t).factor()
2818
(t^3 + 3*t - 8)^2 * (t^5 + t - 17)
2819
2820
TESTS::
2821
2822
sage: companion_matrix([4, 5, 1], format='junk')
2823
Traceback (most recent call last):
2824
...
2825
ValueError: format must be 'right', 'left', 'top' or 'bottom', not junk
2826
2827
sage: companion_matrix(sin(x))
2828
Traceback (most recent call last):
2829
...
2830
TypeError: input must be a polynomial (not a symbolic expression, see docstring), or other iterable, not sin(x)
2831
2832
sage: companion_matrix([2, 3, 896])
2833
Traceback (most recent call last):
2834
...
2835
ValueError: polynomial (or the polynomial implied by coefficients) must be monic, not a leading coefficient of 896
2836
2837
sage: F.<a> = GF(2^2)
2838
sage: companion_matrix([4/3, a+1, 1])
2839
Traceback (most recent call last):
2840
...
2841
TypeError: unable to find common ring for coefficients from polynomial
2842
2843
sage: A = companion_matrix([1])
2844
sage: A.nrows(); A.ncols()
2845
0
2846
0
2847
2848
sage: A = companion_matrix([])
2849
Traceback (most recent call last):
2850
...
2851
ValueError: polynomial cannot be specified by an empty list
2852
2853
AUTHOR:
2854
2855
- Rob Beezer (2011-05-19)
2856
"""
2857
import sage.matrix.constructor
2858
if format not in ['right', 'left', 'top', 'bottom']:
2859
raise ValueError("format must be 'right', 'left', 'top' or 'bottom', not {0}".format(format))
2860
try:
2861
poly = list(poly)
2862
except TypeError:
2863
raise TypeError('input must be a polynomial (not a symbolic expression, see docstring), or other iterable, not {0}'.format(poly))
2864
n = len(poly) - 1
2865
if n == -1:
2866
raise ValueError('polynomial cannot be specified by an empty list')
2867
if not poly[n] == 1:
2868
raise ValueError('polynomial (or the polynomial implied by coefficients) must be monic, not a leading coefficient of {0}'.format(poly[n]))
2869
entries = [0]*(n*n)
2870
# 1's below diagonal, or above diagonal
2871
if format in ['right', 'top']:
2872
for i in range(n-1):
2873
entries[(i+1)*n + i] = 1
2874
else:
2875
for i in range(n-1):
2876
entries[i*n + i+1] = 1
2877
# right side, left side (reversed), bottom edge, top edge (reversed)
2878
if format == 'right':
2879
for i in range(n):
2880
entries[i*n + n-1] = -poly[i]
2881
elif format == 'left':
2882
for i in range(n):
2883
entries[(n-1-i)*n + 0] = -poly[i]
2884
elif format == 'bottom':
2885
for i in range(n):
2886
entries[(n-1)*n + i] = -poly[i]
2887
elif format == 'top':
2888
for i in range(n):
2889
entries[0*n + n-1-i] = -poly[i]
2890
try:
2891
M = sage.matrix.constructor.matrix(n, n, entries)
2892
except TypeError:
2893
raise TypeError("unable to find common ring for coefficients from polynomial")
2894
return M
2895
2896
def random_rref_matrix(parent, num_pivots):
2897
r"""
2898
Generate a matrix in reduced row-echelon form with a specified number of non-zero rows.
2899
2900
INPUT:
2901
2902
- ``parent`` - A matrix space specifying the base ring, dimensions and
2903
representation (dense/sparse) for the result. The base ring must be exact.
2904
2905
- ``num_pivots`` - The number of non-zero rows in the result, i.e. the rank.
2906
2907
OUTPUT:
2908
2909
A matrix in reduced row echelon form with ``num_pivots`` non-zero rows. If the
2910
base ring is `ZZ` or `QQ` then the entries are all integers.
2911
2912
.. note::
2913
2914
It is easiest to use this function via a call to the
2915
:func:`~sage.matrix.constructor.random_matrix`
2916
function with the ``algorithm='echelon_form'`` keyword. We provide
2917
one example accessing this function directly, while the remainder will
2918
use this more general function.
2919
2920
EXAMPLES:
2921
2922
Matrices generated are in reduced row-echelon form with specified rank. If the
2923
base ring is `QQ` the result has only integer entries. ::
2924
2925
sage: from sage.matrix.constructor import random_rref_matrix
2926
sage: matrix_space = sage.matrix.matrix_space.MatrixSpace(QQ, 5, 6)
2927
sage: A=random_rref_matrix(matrix_space, num_pivots=4); A # random
2928
[ 1 0 0 -6 0 -3]
2929
[ 0 1 0 2 0 3]
2930
[ 0 0 1 -4 0 -2]
2931
[ 0 0 0 0 1 3]
2932
[ 0 0 0 0 0 0]
2933
sage: A.base_ring()
2934
Rational Field
2935
sage: (A.nrows(), A.ncols())
2936
(5, 6)
2937
sage: A in sage.matrix.matrix_space.MatrixSpace(ZZ, 5, 6)
2938
True
2939
sage: A.rank()
2940
4
2941
sage: A==A.rref()
2942
True
2943
2944
Matrices can be generated over other exact rings. ::
2945
2946
sage: B=random_matrix(FiniteField(7), 4, 4, algorithm='echelon_form', num_pivots=3); B # random
2947
[1 0 0 0]
2948
[0 1 0 6]
2949
[0 0 1 4]
2950
[0 0 0 0]
2951
sage: B.rank() == 3
2952
True
2953
sage: B.base_ring()
2954
Finite Field of size 7
2955
sage: B==B.rref()
2956
True
2957
2958
TESTS:
2959
2960
Rank of a matrix must be an integer. ::
2961
2962
sage: random_matrix(QQ, 120, 56, algorithm='echelon_form', num_pivots=61/2)
2963
Traceback (most recent call last):
2964
...
2965
TypeError: the number of pivots must be an integer.
2966
2967
Matrices must be generated over exact fields. ::
2968
2969
sage: random_matrix(RR, 40, 88, algorithm='echelon_form', num_pivots=39)
2970
Traceback (most recent call last):
2971
...
2972
TypeError: the base ring must be exact.
2973
2974
Matrices must have the number of pivot columns be less than or equal to the number of rows. ::
2975
2976
sage: C=random_matrix(ZZ, 6,4, algorithm='echelon_form', num_pivots=7); C
2977
Traceback (most recent call last):
2978
...
2979
ValueError: number of pivots cannot exceed the number of rows or columns.
2980
2981
Matrices must have the number of pivot columns be less than or equal to the number of columns. ::
2982
2983
sage: D=random_matrix(QQ, 1,3, algorithm='echelon_form', num_pivots=5); D
2984
Traceback (most recent call last):
2985
...
2986
ValueError: number of pivots cannot exceed the number of rows or columns.
2987
2988
Matrices must have the number of pivot columns be greater than zero. ::
2989
2990
sage: random_matrix(QQ, 5, 4, algorithm='echelon_form', num_pivots=-1)
2991
Traceback (most recent call last):
2992
...
2993
ValueError: the number of pivots must be zero or greater.
2994
2995
AUTHOR:
2996
2997
Billy Wonderly (2010-07)
2998
"""
2999
3000
import sage.gsl.probability_distribution as pd
3001
from sage.misc.prandom import randint
3002
3003
try:
3004
num_pivots=ZZ(num_pivots)
3005
except TypeError:
3006
raise TypeError("the number of pivots must be an integer.")
3007
if num_pivots<0:
3008
raise ValueError("the number of pivots must be zero or greater.")
3009
ring = parent.base_ring()
3010
if not ring.is_exact():
3011
raise TypeError("the base ring must be exact.")
3012
num_row = parent.nrows()
3013
num_col = parent.ncols()
3014
if num_pivots>num_row or num_pivots>num_col:
3015
raise ValueError("number of pivots cannot exceed the number of rows or columns.")
3016
else:
3017
one=ring.one()
3018
# Create a matrix of the desired size to be modified and then returned.
3019
return_matrix=copy(parent.zero_matrix())
3020
pivots=[0] #Force first column to be a pivot. No harm if no pivots at all.
3021
# Probability distribution for the placement of leading one's.
3022
pivot_generator=pd.RealDistribution("beta",[1.6,4.3])
3023
while len(pivots)<num_pivots:
3024
pivot_column=int(pivot_generator.get_random_element()*num_col)
3025
if pivot_column not in pivots:
3026
pivots.append(pivot_column)
3027
pivots.sort()
3028
pivot_row=0
3029
# Use the list of pivot columns to set the pivot entries of the return_matrix to leading ones.
3030
while pivot_row<num_pivots:
3031
return_matrix[pivot_row,pivots[pivot_row]]=one
3032
pivot_row+=1
3033
if ring==QQ or ring==ZZ:
3034
# Keep track of the non-pivot columns by using the pivot_index, start at the first column to
3035
# the right of the initial pivot column, go until the first column to the left of the next
3036
# pivot column.
3037
for pivot_index in range(num_pivots-1):
3038
for non_pivot_column_index in range(pivots[pivot_index]+1,pivots[pivot_index+1]):
3039
entry_generator1=pd.RealDistribution("beta",[6,4])
3040
# Experimental distribution used to generate the values.
3041
for non_pivot_column_entry in range(pivot_index+1):
3042
sign1=(2*randint(0,1)-1)
3043
return_matrix[non_pivot_column_entry,non_pivot_column_index]=sign1*int(entry_generator1.get_random_element()*((1-non_pivot_column_entry/return_matrix.ncols())*7))
3044
# Use index to fill entries of the columns to the right of the last pivot column.
3045
for rest_non_pivot_column in range(pivots[num_pivots-1]+1,num_col):
3046
entry_generator2=pd.RealDistribution("beta",[2.6,4])
3047
# experimental distribution to generate small values.
3048
for rest_entries in range(num_pivots):
3049
sign2=(2*randint(0,1)-1)
3050
return_matrix[rest_entries,rest_non_pivot_column]=sign2*int(entry_generator2.get_random_element()*5)
3051
else:
3052
for pivot_index in range(num_pivots-1):
3053
for non_pivot_column_index in range(pivots[pivot_index]+1,pivots[pivot_index+1]):
3054
for non_pivot_column_entry in range(pivot_index+1):
3055
return_matrix[non_pivot_column_entry,non_pivot_column_index]=ring.random_element()
3056
for rest_non_pivot_column in range(pivots[num_pivots-1]+1,num_col):
3057
for rest_entries in range(num_pivots):
3058
return_matrix[rest_entries,rest_non_pivot_column]=ring.random_element()
3059
return return_matrix
3060
3061
def random_echelonizable_matrix(parent, rank, upper_bound=None):
3062
r"""
3063
Generate a matrix of a desired size and rank, over a desired ring, whose reduced
3064
row-echelon form has only integral values.
3065
3066
INPUT:
3067
3068
- ``parent`` - A matrix space specifying the base ring, dimensions and
3069
representation (dense/sparse) for the result. The base ring must be exact.
3070
3071
- ``rank`` - Rank of result, i.e the number of non-zero rows in the
3072
reduced row echelon form.
3073
3074
- ``upper_bound`` - If designated, size control of the matrix entries is desired.
3075
Set ``upper_bound`` to 1 more than the maximum value entries can achieve.
3076
If None, no size control occurs. (default: None)
3077
3078
OUTPUT:
3079
3080
A matrix not in reduced row-echelon form with the desired dimensions and properties.
3081
3082
.. note::
3083
3084
It is easiest to use this function via a call to the
3085
:func:`~sage.matrix.constructor.random_matrix`
3086
function with the ``algorithm='echelonizable'`` keyword. We provide
3087
one example accessing this function directly, while the remainder will
3088
use this more general function.
3089
3090
EXAMPLES:
3091
3092
Generated matrices have the desired dimensions, rank and entry size. The
3093
matrix in reduced row-echelon form has only integer entries. ::
3094
3095
sage: from sage.matrix.constructor import random_echelonizable_matrix
3096
sage: matrix_space = sage.matrix.matrix_space.MatrixSpace(QQ, 5, 6)
3097
sage: A=random_echelonizable_matrix(matrix_space, rank=4, upper_bound=40); A # random
3098
[ 1 -1 1 -3 -4 6]
3099
[ 5 -4 0 8 4 19]
3100
[ -3 3 -2 4 7 -16]
3101
[ -4 5 -7 26 31 -31]
3102
[ 2 -3 4 -11 -14 17]
3103
sage: A.rank()
3104
4
3105
sage: max(map(abs,A.list()))<40
3106
True
3107
sage: A.rref()==A.rref().change_ring(ZZ)
3108
True
3109
3110
An example with default settings (i.e. no entry size control). ::
3111
3112
sage: C=random_matrix(QQ, 6, 7, algorithm='echelonizable', rank=5); C # random
3113
[ 1 0 5 -2 -26 -16 0]
3114
[ -3 1 -19 6 97 61 1]
3115
[ 0 4 -15 -1 71 50 3]
3116
[ 2 4 -9 0 39 25 8]
3117
[ 2 2 3 -3 -18 -9 3]
3118
[ -3 -4 -2 14 14 -6 4]
3119
sage: C.rank()
3120
5
3121
sage: C.rref()==C.rref().change_ring(ZZ)
3122
True
3123
3124
A matrix without size control may have very large entry sizes. ::
3125
3126
sage: D=random_matrix(ZZ, 7, 8, algorithm='echelonizable', rank=6); D # random
3127
[ 9 -53 -255 45 -1519 4043 9819 3324]
3128
[ 3 -14 -64 8 -369 972 2350 810]
3129
[ 2 -14 -65 9 -377 1000 2420 829]
3130
[ 4 -24 -116 21 -693 1846 4485 1516]
3131
[ -3 14 68 -16 426 -1134 -2767 -919]
3132
[ -5 21 92 -13 548 -1432 -3466 -1183]
3133
[ 1 -9 -42 7 -254 670 1624 547]
3134
3135
Matrices can be generated over any exact ring. ::
3136
3137
sage: F.<a>=GF(2^3)
3138
sage: B=random_matrix(F, 4, 5, algorithm='echelonizable', rank=4, upper_bound=None); B # random
3139
[ a + 1 a^2 + a + 1 a^2 0 1]
3140
[ 1 a a + 1 a^2 a^2 + a]
3141
[ a a^2 a^2 + a + 1 a + 1 1]
3142
[ 1 0 a^2 + a + 1 0 a^2 + 1]
3143
sage: B.rank()
3144
4
3145
3146
Square matrices over ZZ or QQ with full rank are always unimodular. ::
3147
3148
sage: E=random_matrix(QQ, 7, 7, algorithm='echelonizable', rank=7); E # random
3149
[ 1 -1 5 12 -24 -41 47]
3150
[ 0 1 -1 3 0 -11 40]
3151
[ 1 -1 6 6 -19 -20 -11]
3152
[ -2 1 -10 -12 35 44 -4]
3153
[ 3 -1 9 7 -35 -40 -18]
3154
[ 0 0 0 -4 4 13 -32]
3155
[ 3 -3 11 6 -33 -31 -35]
3156
sage: det(E)
3157
1
3158
3159
TESTS:
3160
3161
Matrices must have a rank zero or greater zero. ::
3162
3163
sage: random_matrix(QQ, 3, 4, algorithm='echelonizable', rank=-1)
3164
Traceback (most recent call last):
3165
...
3166
ValueError: matrices must have rank zero or greater.
3167
3168
The base ring must be exact. ::
3169
3170
sage: random_matrix(RR, 3, 3, algorithm='echelonizable', rank=2)
3171
Traceback (most recent call last):
3172
...
3173
TypeError: the base ring must be exact.
3174
3175
AUTHOR:
3176
3177
Billy Wonderly (2010-07)
3178
"""
3179
3180
from sage.misc.prandom import randint
3181
3182
ring = parent.base_ring()
3183
rows = parent.nrows()
3184
if rank<0:
3185
raise ValueError("matrices must have rank zero or greater.")
3186
matrix = random_rref_matrix(parent, rank)
3187
# Entries of matrices over the ZZ or QQ can get large, entry size is regulated by finding the largest
3188
# entry of the resultant matrix after addition of scalar multiple of a row.
3189
if ring==QQ or ring==ZZ:
3190
# If upper_bound is not set, don't control entry size.
3191
if upper_bound==None:
3192
upper_bound=50
3193
size=False
3194
else:
3195
size=True
3196
if size:
3197
for pivots in range(len(matrix.pivots())-1,-1,-1):
3198
# keep track of the pivot column positions from the pivot column with the largest index to
3199
# the one with the smallest.
3200
row_index=0
3201
while row_index<rows:
3202
# To each row in a pivot column add a scalar multiple of the pivot row.
3203
# for full rank, square matrices, using only this row operation preserves the determinant of 1.
3204
if pivots!=row_index:
3205
# To ensure a leading one is not removed by the addition of the pivot row by its
3206
# additive inverse.
3207
matrix_copy=matrix.with_added_multiple_of_row(row_index,matrix.pivot_rows()[pivots],randint(-5,5))
3208
# Range for scalar multiples determined experimentally.
3209
if max(map(abs,matrix_copy.list()))<upper_bound:
3210
# Continue if the the largest entry after a row operation is within the bound.
3211
matrix=matrix_copy
3212
row_index+=1
3213
# The leading one in row one has not been altered, so add a scalar multiple of a random row
3214
# to row one.
3215
row1=0
3216
if rows>1:
3217
while row1<1:
3218
matrix_copy=matrix.with_added_multiple_of_row(0,randint(1,rows-1),randint(-3,3))
3219
if max(map(abs,matrix_copy.list()))<upper_bound:
3220
matrix=matrix_copy
3221
row1+=1
3222
# If size control is not desired, the routine will run slightly faster, particularly with large matrices.
3223
else:
3224
for pivots in range(rank-1,-1,-1):
3225
row_index=0
3226
while row_index<rows:
3227
if pivots==row_index:
3228
row_index+=1
3229
if pivots!=row_index and row_index!=rows:
3230
matrix.add_multiple_of_row(row_index,matrix.pivot_rows()[pivots],randint(-5,5))
3231
row_index+=1
3232
if rows>1:
3233
matrix.add_multiple_of_row(0,randint(1,rows-1),randint(-3,3))
3234
# If the matrix generated over a different ring, random elements from the designated ring are used as and
3235
# the routine is run similarly to the size unchecked version for rationals and integers.
3236
else:
3237
for pivots in range(rank-1,-1,-1):
3238
row_index=0
3239
while row_index<rows:
3240
if pivots==row_index:
3241
row_index+=1
3242
if pivots!=row_index and row_index!=rows:
3243
matrix.add_multiple_of_row(row_index,matrix.pivot_rows()[pivots],ring.random_element())
3244
row_index+=1
3245
if rows>1:
3246
matrix.add_multiple_of_row(0,randint(1,rows-1),ring.random_element())
3247
return matrix
3248
3249
def random_subspaces_matrix(parent, rank=None):
3250
r"""
3251
Create a matrix of the designated size and rank whose right and
3252
left null spaces, column space, and row space have desirable
3253
properties that simplify the subspaces.
3254
3255
INPUT:
3256
3257
- ``parent`` - A matrix space specifying the base ring, dimensions, and
3258
representation (dense/sparse) for the result. The base ring must be exact.
3259
3260
- ``rank`` - The desired rank of the return matrix (default: None).
3261
3262
OUTPUT:
3263
3264
A matrix whose natrual basis vectors for its four subspaces, when
3265
computed, have reasonably sized, integral valued, entries.
3266
3267
.. note::
3268
3269
It is easiest to use this function via a call to the
3270
:func:`~sage.matrix.constructor.random_matrix`
3271
function with the ``algorithm='subspaces'`` keyword. We provide
3272
one example accessing this function directly, while the remainder will
3273
use this more general function.
3274
3275
EXAMPLES:
3276
3277
A 6x8 matrix with designated rank of 3. The four subspaces are
3278
determined using one simple routine in which we augment the
3279
original matrix with the equal row dimension identity matrix. The
3280
resulting matrix is then put in reduced row-echelon form and the
3281
subspaces can then be determined by analyzing subdivisions of this
3282
matrix. See the four subspaces routine in [BEEZER]_ for more. ::
3283
3284
sage: from sage.matrix.constructor import random_subspaces_matrix
3285
sage: matrix_space = sage.matrix.matrix_space.MatrixSpace(QQ, 6, 8)
3286
sage: B=random_subspaces_matrix(matrix_space, rank=3); B # random
3287
[ 113 339 -46 218 -243 641 -269 -306]
3288
[ -33 -99 13 -63 69 -185 77 90]
3289
[ 35 105 -14 67 -74 197 -82 -95]
3290
[ -18 -54 7 -34 37 -100 41 49]
3291
[ -26 -78 10 -49 53 -144 59 71]
3292
[ -8 -24 3 -15 16 -44 18 22]
3293
sage: B.rank()
3294
3
3295
sage: B.nullity()
3296
3
3297
sage: (B.nrows(), B.ncols())
3298
(6, 8)
3299
sage: all([x in ZZ for x in B.list()])
3300
True
3301
sage: B_expanded=B.augment(identity_matrix(6)).rref()
3302
sage: all([x in ZZ for x in B_expanded.list()])
3303
True
3304
sage: B_expanded # random
3305
[ 1 3 0 0 1 1 3 -2 0 0 -3 0 -9 16]
3306
[ 0 0 1 0 3 -2 -1 -3 0 0 2 0 11 -27]
3307
[ 0 0 0 1 -1 2 -3 -1 0 0 2 0 7 -14]
3308
[ 0 0 0 0 0 0 0 0 1 0 -5 0 -3 2]
3309
[ 0 0 0 0 0 0 0 0 0 1 1 0 1 -3]
3310
[ 0 0 0 0 0 0 0 0 0 0 0 1 -1 1]
3311
3312
Check that we fixed Trac #10543 (echelon forms should be immutable)::
3313
3314
sage: B_expanded.is_immutable()
3315
True
3316
3317
We want to modify B_expanded, so replace it with a copy::
3318
3319
sage: B_expanded = copy(B_expanded)
3320
sage: B_expanded.subdivide(B.nrows()-B.nullity(),B.ncols());B_expanded # random
3321
[ 1 3 0 0 1 1 3 -2| 0 0 -3 0 -9 16]
3322
[ 0 0 1 0 3 -2 -1 -3| 0 0 2 0 11 -27]
3323
[ 0 0 0 1 -1 2 -3 -1| 0 0 2 0 7 -14]
3324
[-------------------------------+-----------------------]
3325
[ 0 0 0 0 0 0 0 0| 1 0 -5 0 -3 2]
3326
[ 0 0 0 0 0 0 0 0| 0 1 1 0 1 -3]
3327
[ 0 0 0 0 0 0 0 0| 0 0 0 1 -1 1]
3328
sage: C=B_expanded.subdivision(0,0)
3329
sage: C # random
3330
[ 1 3 0 0 1 1 3 -2]
3331
[ 0 0 1 0 3 -2 -1 -3]
3332
[ 0 0 0 1 -1 2 -3 -1]
3333
sage: L=B_expanded.subdivision(1,1)
3334
sage: L # random
3335
[ 1 0 -5 0 -3 2]
3336
[ 0 1 1 0 1 -3]
3337
[ 0 0 0 1 -1 1]
3338
sage: B.right_kernel()==C.right_kernel()
3339
True
3340
sage: B.row_space()==C.row_space()
3341
True
3342
sage: B.column_space()==L.right_kernel()
3343
True
3344
sage: B.left_kernel()==L.row_space()
3345
True
3346
3347
A matrix to show that the null space of the L matrix is the column space of the starting matrix. ::
3348
3349
sage: A=random_matrix(QQ, 5, 7, algorithm='subspaces', rank=None); A # random
3350
[-31 12 -9 -27 21 2 -15]
3351
[105 -24 6 103 -30 -34 79]
3352
[ 29 -9 5 26 -14 -5 17]
3353
[233 -55 16 228 -71 -73 173]
3354
[-42 10 -3 -41 13 13 -31]
3355
sage: (A.nrows(), A.ncols())
3356
(5, 7)
3357
sage: all([x in ZZ for x in A.list()])
3358
True
3359
sage: A.nullity() # random
3360
1
3361
sage: A_expanded=A.augment(identity_matrix(5)).rref()
3362
sage: A_expanded # random
3363
[ 1 0 0 0 0 1 0 0 3 7 25 151]
3364
[ 0 1 0 0 1 2 1 0 5 21 84 493]
3365
[ 0 0 1 0 -1 2 0 0 2 13 53 308]
3366
[ 0 0 0 1 0 -1 1 0 -2 -3 -9 -57]
3367
[ 0 0 0 0 0 0 0 1 -3 1 1 -2]
3368
sage: all([x in ZZ for x in A_expanded.list()])
3369
True
3370
sage: C=A_expanded.submatrix(0,0,A.nrows()-A.nullity(),A.ncols())
3371
sage: L=A_expanded.submatrix(A.nrows()-A.nullity(),A.ncols())
3372
sage: A.right_kernel()==C.right_kernel()
3373
True
3374
sage: A.row_space()==C.row_space()
3375
True
3376
sage: A.column_space()==L.right_kernel()
3377
True
3378
sage: A.left_kernel()==L.row_space()
3379
True
3380
3381
TESTS:
3382
3383
The designated rank of the L matrix cannot be greater than the number of desired rows. ::
3384
3385
sage: random_matrix(QQ, 19, 20, algorithm='subspaces', rank=21)
3386
Traceback (most recent call last):
3387
...
3388
ValueError: rank cannot exceed the number of rows or columns.
3389
3390
REFERENCES:
3391
3392
.. [BEEZER] `A First Course in Linear Algebra <http://linear.ups.edu/>`_.
3393
Robert A. Beezer, accessed 15 July 2010.
3394
3395
AUTHOR:
3396
3397
Billy Wonderly (2010-07)
3398
"""
3399
3400
import sage.gsl.probability_distribution as pd
3401
3402
ring = parent.base_ring()
3403
rows = parent.nrows()
3404
columns = parent.ncols()
3405
3406
if rank>rows or rank>columns:
3407
raise ValueError("rank cannot exceed the number of rows or columns.")
3408
# If rank is not designated, generate using probability distribution skewing to smaller numbers, always at least 1.
3409
if rank==None:
3410
left_nullity_generator=pd.RealDistribution("beta",[1.4,5.5])
3411
nullity=int(left_nullity_generator.get_random_element()*(rows-1)+1)
3412
rank=rows-nullity
3413
else:
3414
rank=rank
3415
nullity=rows-rank
3416
B=random_matrix(ring, rows, columns, algorithm='echelon_form', num_pivots=rank)
3417
# Create a nonsingular matrix whose columns will be used to stack a matrix over the L matrix, forming a nonsingular matrix.
3418
K_nonzero_columns=random_matrix(ring, rank, rank, algorithm='echelonizable', rank=rank)
3419
K=matrix(QQ,rank,rows)
3420
L=random_matrix(ring, nullity, rows, algorithm='echelon_form', num_pivots=nullity)
3421
for column in range(len(L.nonpivots())):
3422
for entry in range(rank):
3423
K[entry,L.nonpivots()[column]]=K_nonzero_columns[entry,column]
3424
J=K.stack(L)
3425
# by multiplying the B matrix by J.inverse() we hide the B matrix
3426
# of the solution using row operations required to change the solution
3427
# K matrix to the identity matrix.
3428
return J.inverse()*B
3429
3430
def random_unimodular_matrix(parent, upper_bound=None):
3431
"""
3432
Generate a random unimodular (determinant 1) matrix of a desired size over a desired ring.
3433
3434
INPUT:
3435
3436
- ``parent`` - A matrix space specifying the base ring, dimensions
3437
and representation (dense/sparse) for the result. The base ring
3438
must be exact.
3439
3440
- ``upper_bound`` - For large matrices over QQ or ZZ,
3441
``upper_bound`` is the largest value matrix entries can achieve.
3442
3443
OUTPUT:
3444
3445
An invertible matrix with the desired properties and determinant 1.
3446
3447
.. note::
3448
3449
It is easiest to use this function via a call to the
3450
:func:`~sage.matrix.constructor.random_matrix`
3451
function with the ``algorithm='unimodular'`` keyword. We provide
3452
one example accessing this function directly, while the remainder will
3453
use this more general function.
3454
3455
EXAMPLES:
3456
3457
A matrix size 5 over QQ. ::
3458
3459
sage: from sage.matrix.constructor import random_unimodular_matrix
3460
sage: matrix_space = sage.matrix.matrix_space.MatrixSpace(QQ, 5)
3461
sage: A=random_unimodular_matrix(matrix_space); A # random
3462
[ -8 31 85 148 -419]
3463
[ 2 -9 -25 -45 127]
3464
[ -1 10 30 65 -176]
3465
[ -3 12 33 58 -164]
3466
[ 5 -21 -59 -109 304]
3467
sage: det(A)
3468
1
3469
3470
A matrix size 6 with entries no larger than 50. ::
3471
3472
sage: B=random_matrix(ZZ, 7, algorithm='unimodular', upper_bound=50);B # random
3473
[ -1 0 3 1 -2 2 9]
3474
[ 1 2 -5 0 14 19 -49]
3475
[ -3 -2 12 5 -6 -4 24]
3476
[ 1 2 -9 -3 3 4 -7]
3477
[ -2 -1 7 2 -8 -5 31]
3478
[ 2 2 -6 -3 8 16 -32]
3479
[ 1 2 -9 -2 5 6 -12]
3480
sage: det(B)
3481
1
3482
3483
A matrix over the number Field in `y` with defining polynomial `y^2-2y-2`. ::
3484
3485
sage: y = var('y')
3486
sage: K=NumberField(y^2-2*y-2,'y')
3487
sage: C=random_matrix(K, 3, algorithm='unimodular');C # random
3488
[ 2*y - 33 681*y - 787 31*y - 37]
3489
[ y + 6 -155*y + 83 -7*y + 4]
3490
[ -y 24*y + 51 y + 3]
3491
sage: det(C)
3492
1
3493
3494
TESTS:
3495
3496
Unimodular matrices are square. ::
3497
3498
sage: random_matrix(QQ, 5, 6, algorithm='unimodular')
3499
Traceback (most recent call last):
3500
...
3501
TypeError: a unimodular matrix must be square.
3502
3503
Only matrices over ZZ and QQ can have size control. ::
3504
3505
sage: F.<a>=GF(5^7)
3506
sage: random_matrix(F, 5, algorithm='unimodular', upper_bound=20)
3507
Traceback (most recent call last):
3508
...
3509
TypeError: only matrices over ZZ or QQ can have size control.
3510
3511
AUTHOR:
3512
3513
Billy Wonderly (2010-07)
3514
"""
3515
3516
ring=parent.base_ring()
3517
size=parent.nrows()
3518
if parent.nrows()!=parent.ncols():
3519
raise TypeError("a unimodular matrix must be square.")
3520
if upper_bound!=None and (ring!=ZZ and ring!=QQ):
3521
raise TypeError("only matrices over ZZ or QQ can have size control.")
3522
if upper_bound==None:
3523
# random_echelonizable_matrix() always returns a determinant one matrix if given full rank.
3524
return random_matrix(ring, size, algorithm='echelonizable', rank=size)
3525
elif upper_bound!=None and (ring==ZZ or ring==QQ):
3526
return random_matrix(ring, size,algorithm='echelonizable',rank=size, upper_bound=upper_bound)
3527
3528
3529
def random_diagonalizable_matrix(parent,eigenvalues=None,dimensions=None):
3530
"""
3531
Create a random matrix that diagonalizes nicely.
3532
3533
To be used as a teaching tool. Return matrices have only real
3534
eigenvalues.
3535
3536
INPUT:
3537
3538
If eigenvalues and dimensions are not specified in a list,
3539
they will be assigned randomly.
3540
3541
- ``parent`` - the desired size of the square matrix.
3542
3543
- ``eigenvalues`` - the list of desired eigenvalues (default=None).
3544
3545
- ``dimensions`` - the list of dimensions corresponding to each
3546
eigenspace (default=None).
3547
3548
OUTPUT:
3549
3550
A square, diagonalizable, matrix with only integer entries. The
3551
eigenspaces of this matrix, if computed by hand, give basis
3552
vectors with only integer entries.
3553
3554
.. note::
3555
3556
It is easiest to use this function via a call to the
3557
:func:`~sage.matrix.constructor.random_matrix`
3558
function with the ``algorithm='diagonalizable'`` keyword. We provide
3559
one example accessing this function directly, while the remainder will
3560
use this more general function.
3561
3562
EXAMPLES:
3563
3564
A diagonalizable matrix, size 5. ::
3565
3566
sage: from sage.matrix.constructor import random_diagonalizable_matrix
3567
sage: matrix_space = sage.matrix.matrix_space.MatrixSpace(QQ, 5)
3568
sage: A=random_diagonalizable_matrix(matrix_space); A # random
3569
[ 10 18 8 4 -18]
3570
[ 20 10 8 4 -16]
3571
[-60 -54 -22 -12 18]
3572
[-60 -54 -24 -6 6]
3573
[-20 -18 -8 -4 8]
3574
sage: A.eigenvalues() # random
3575
[10,6,2,-8,-10]
3576
sage: S=A.right_eigenmatrix()[1]; S # random
3577
[ 1 1 1 1 0]
3578
[ 1 1 1 0 1]
3579
[-3 -3 -4 -3 -3]
3580
[-3 -4 -3 -3 -3]
3581
[-1 -1 -1 -1 -1]
3582
sage: S_inverse=S.inverse(); S_inverse # random
3583
[ 1 1 1 1 -5]
3584
[ 0 0 0 -1 3]
3585
[ 0 0 -1 0 3]
3586
[ 0 -1 0 0 -1]
3587
[-1 0 0 0 -1]
3588
sage: S_inverse*A*S # random
3589
[ 10 0 0 0 0]
3590
[ 0 6 0 0 0]
3591
[ 0 0 2 0 0]
3592
[ 0 0 0 -8 0]
3593
[ 0 0 0 0 -10]
3594
3595
A diagonalizable matrix with eigenvalues and dimensions designated,
3596
with a check that if eigenvectors were calculated by hand
3597
entries would all be integers. ::
3598
3599
sage: B=random_matrix(QQ, 6, algorithm='diagonalizable', eigenvalues=[-12,4,6],dimensions=[2,3,1]); B # random
3600
[ -52 32 240 -464 -96 -520]
3601
[ 6 4 -48 72 36 90]
3602
[ 46 -32 -108 296 -12 274]
3603
[ 24 -16 -64 164 0 152]
3604
[ 18 -16 0 72 -48 30]
3605
[ 2 0 -16 24 12 34]
3606
sage: all([x in ZZ for x in (B-(-12*identity_matrix(6))).rref().list()])
3607
True
3608
sage: all([x in ZZ for x in (B-(4*identity_matrix(6))).rref().list()])
3609
True
3610
sage: all([x in ZZ for x in (B-(6*identity_matrix(6))).rref().list()])
3611
True
3612
sage: S=B.right_eigenmatrix()[1]; S_inverse=S.inverse(); S_inverse*B*S # random
3613
[ 6 0 0 0 0 0]
3614
[ 0 -12 0 0 0 0]
3615
[ 0 0 -12 0 0 0]
3616
[ 0 0 0 4 0 0]
3617
[ 0 0 0 0 4 0]
3618
[ 0 0 0 0 0 4]
3619
3620
TESTS:
3621
3622
Eigenvalues must all be integers. ::
3623
3624
sage: random_matrix(QQ,3,algorithm='diagonalizable', eigenvalues=[2+I,2-I,2],dimensions=[1,1,1])
3625
Traceback (most recent call last):
3626
...
3627
TypeError: eigenvalues must be integers.
3628
3629
Diagonal matrices must be square. ::
3630
3631
sage: random_matrix(QQ, 5, 7, algorithm='diagonalizable', eigenvalues=[-5,2,-3], dimensions=[1,1,3])
3632
Traceback (most recent call last):
3633
...
3634
TypeError: a diagonalizable matrix must be square.
3635
3636
A list of eigenvalues must be accompanied with a list of dimensions. ::
3637
3638
sage: random_matrix(QQ,10,algorithm='diagonalizable',eigenvalues=[4,8])
3639
Traceback (most recent call last):
3640
...
3641
ValueError: the list of eigenvalues must have a list of dimensions corresponding to each eigenvalue.
3642
3643
A list of dimensions must be accompanied with a list of eigenvalues. ::
3644
3645
sage: random_matrix(QQ, 10,algorithm='diagonalizable',dimensions=[2,2,4,2])
3646
Traceback (most recent call last):
3647
...
3648
ValueError: the list of dimensions must have a list of corresponding eigenvalues.
3649
3650
The sum of the eigenvalue dimensions must equal the size of the matrix. ::
3651
3652
sage: random_matrix(QQ,12,algorithm='diagonalizable',eigenvalues=[4,2,6,-1],dimensions=[2,3,5,1])
3653
Traceback (most recent call last):
3654
...
3655
ValueError: the size of the matrix must equal the sum of the dimensions.
3656
3657
Each eigenspace dimension must be at least 1. ::
3658
3659
sage: random_matrix(QQ,9,algorithm='diagonalizable',eigenvalues=[-15,22,8,-4,90,12],dimensions=[4,2,2,4,-3,0])
3660
Traceback (most recent call last):
3661
...
3662
ValueError: eigenspaces must have a dimension of at least 1.
3663
3664
Each eigenvalue must have a corresponding eigenspace dimension. ::
3665
3666
sage: random_matrix(QQ,12,algorithm='diagonalizable',eigenvalues=[4,2,6,-1],dimensions=[4,3,5])
3667
Traceback (most recent call last):
3668
...
3669
ValueError: each eigenvalue must have a corresponding dimension and each dimension a corresponding eigenvalue.
3670
3671
Each dimension must have an eigenvalue paired to it. ::
3672
3673
sage: random_matrix(QQ,12,algorithm='diagonalizable',eigenvalues=[4,2,6],dimensions=[2,3,5,2])
3674
Traceback (most recent call last):
3675
...
3676
ValueError: each eigenvalue must have a corresponding dimension and each dimension a corresponding eigenvalue.
3677
3678
TODO:
3679
3680
Modify the routine to allow for complex eigenvalues.
3681
3682
AUTHOR:
3683
3684
Billy Wonderly (2010-07)
3685
"""
3686
3687
from sage.misc.prandom import randint
3688
3689
size=parent.nrows()
3690
if parent.nrows()!=parent.ncols():
3691
raise TypeError("a diagonalizable matrix must be square.")
3692
if eigenvalues!=None and dimensions==None:
3693
raise ValueError("the list of eigenvalues must have a list of dimensions corresponding to each eigenvalue.")
3694
if eigenvalues==None and dimensions!=None:
3695
raise ValueError("the list of dimensions must have a list of corresponding eigenvalues.")
3696
if eigenvalues==None and dimensions==None:
3697
values=[]
3698
#create a list with "size" number of entries
3699
for eigen_index in range(size):
3700
eigenvalue=randint(-10,10)
3701
values.append(eigenvalue)
3702
values.sort()
3703
dimensions=[]
3704
eigenvalues=[]
3705
#create a list with no duplicate values to be the eigenvalues
3706
for eigenvalue in range(size):
3707
if values[eigenvalue] not in eigenvalues:
3708
eigenvalues.append(values[eigenvalue])
3709
for dimension in range(len(eigenvalues)):
3710
#dimension is equal to how many times an eigenvalue was generated in the 'values' list
3711
dimensions.append(values.count(eigenvalues[dimension]))
3712
size_check=0
3713
for check in range(len(dimensions)):
3714
size_check=size_check+dimensions[check]
3715
if not map(lambda x: x in ZZ, eigenvalues)==[True]*len(eigenvalues):
3716
raise TypeError("eigenvalues must be integers.")
3717
if size!=size_check:
3718
raise ValueError("the size of the matrix must equal the sum of the dimensions.")
3719
if min(dimensions)<1:
3720
raise ValueError("eigenspaces must have a dimension of at least 1.")
3721
if len(eigenvalues)!=len(dimensions):
3722
raise ValueError("each eigenvalue must have a corresponding dimension and each dimension a corresponding eigenvalue.")
3723
#sort the dimensions in order of increasing size, and sort the eigenvalues list in an identical fashion, to maintain corresponding values.
3724
dimensions_sort=zip(dimensions,eigenvalues)
3725
dimensions_sort.sort()
3726
dimensions=[x[0] for x in dimensions_sort]
3727
eigenvalues=[x[1] for x in dimensions_sort]
3728
#Create the matrix of eigenvalues on the diagonal. Use a lower limit and upper limit determined by the eigenvalue dimensions.
3729
diagonal_matrix=matrix(QQ,size)
3730
up_bound=0
3731
low_bound=0
3732
for row_index in range(len(dimensions)):
3733
up_bound=up_bound+dimensions[row_index]
3734
for entry in range(low_bound,up_bound):
3735
diagonal_matrix[entry,entry]=eigenvalues[row_index]
3736
low_bound=low_bound+dimensions[row_index]
3737
# Create a matrix to hold each of the eigenvectors as its columns, begin with an identity matrix so that after row and column
3738
# operations the resulting matrix will be unimodular.
3739
eigenvector_matrix=matrix(QQ,size,size,1)
3740
upper_limit=0
3741
lower_limit=0
3742
#run the routine over the necessary number of columns corresponding eigenvalue dimension.
3743
for dimension_index in range(len(dimensions)-1):
3744
upper_limit=upper_limit+dimensions[dimension_index]
3745
lowest_index_row_with_one=size-dimensions[dimension_index]
3746
#assign a one to the row that is the eigenvalue dimension rows up from the bottom row then assign ones diagonally down to the right.
3747
for eigen_ones in range(lower_limit,upper_limit):
3748
eigenvector_matrix[lowest_index_row_with_one,eigen_ones]=1
3749
lowest_index_row_with_one+=1
3750
lower_limit=lower_limit+dimensions[dimension_index]
3751
#Create a list to give the eigenvalue dimension corresponding to each column.
3752
dimension_check=[]
3753
for i in range(len(dimensions)):
3754
for k in range(dimensions[i]):
3755
dimension_check.append(dimensions[i])
3756
#run routine over the rows that are in the range of the protected ones. Use addition of column multiples to fill entries.
3757
for dimension_multiplicity in range(max(dimensions),min(dimensions),-1):
3758
highest_one_row=size-dimension_multiplicity
3759
highest_one_column=0
3760
#find the column with the protected one in the lowest indexed row.
3761
while eigenvector_matrix[highest_one_row,highest_one_column]==0:
3762
highest_one_column+=1
3763
#dimension_check determines if column has a low enough eigenvalue dimension to take a column multiple.
3764
for bottom_entry_filler in range(len(dimension_check)):
3765
if dimension_check[bottom_entry_filler]<dimension_multiplicity and eigenvector_matrix[highest_one_row,bottom_entry_filler]==0:
3766
# randint range determined experimentally to keep entries manageable.
3767
eigenvector_matrix.add_multiple_of_column(bottom_entry_filler,highest_one_column,randint(-4,4))
3768
#Fill remaining rows using scalar row addition.
3769
for row in range(size-max(dimensions),size):
3770
for upper_row in range(size-max(dimensions)):
3771
# range of multiplier determined experimentally so that entries stay manageable for small matrices
3772
eigenvector_matrix.add_multiple_of_row(upper_row,row,randint(-4,4))
3773
return eigenvector_matrix*diagonal_matrix*(eigenvector_matrix.inverse())
3774
3775
def vector_on_axis_rotation_matrix(v, i, ring=None):
3776
r"""
3777
Return a rotation matrix `M` such that `det(M)=1` sending the vector
3778
`v` on the i-th axis so that all other coordinates of `Mv` are zero.
3779
3780
.. NOTE::
3781
3782
Such a matrix is not uniquely determined. This function returns one
3783
such matrix.
3784
3785
INPUT:
3786
3787
- ``v``` - vector
3788
- ``i`` - integer
3789
- ``ring`` - ring (optional, default: None) of the resulting matrix
3790
3791
OUTPUT:
3792
3793
A matrix
3794
3795
EXAMPLES::
3796
3797
sage: from sage.matrix.constructor import vector_on_axis_rotation_matrix
3798
sage: v = vector((1,2,3))
3799
sage: vector_on_axis_rotation_matrix(v, 2) * v
3800
(0, 0, sqrt(14))
3801
sage: vector_on_axis_rotation_matrix(v, 1) * v
3802
(0, sqrt(14), 0)
3803
sage: vector_on_axis_rotation_matrix(v, 0) * v
3804
(sqrt(14), 0, 0)
3805
3806
::
3807
3808
sage: x,y = var('x,y')
3809
sage: v = vector((x,y))
3810
sage: vector_on_axis_rotation_matrix(v, 1)
3811
[ y/sqrt(x^2 + y^2) -x/sqrt(x^2 + y^2)]
3812
[ x/sqrt(x^2 + y^2) y/sqrt(x^2 + y^2)]
3813
sage: vector_on_axis_rotation_matrix(v, 0)
3814
[ x/sqrt(x^2 + y^2) y/sqrt(x^2 + y^2)]
3815
[-y/sqrt(x^2 + y^2) x/sqrt(x^2 + y^2)]
3816
sage: vector_on_axis_rotation_matrix(v, 0) * v
3817
(x^2/sqrt(x^2 + y^2) + y^2/sqrt(x^2 + y^2), 0)
3818
sage: vector_on_axis_rotation_matrix(v, 1) * v
3819
(0, x^2/sqrt(x^2 + y^2) + y^2/sqrt(x^2 + y^2))
3820
3821
::
3822
3823
sage: v = vector((1,2,3,4))
3824
sage: vector_on_axis_rotation_matrix(v, 0) * v
3825
(sqrt(30), 0, 0, 0)
3826
sage: vector_on_axis_rotation_matrix(v, 0, ring=RealField(10))
3827
[ 0.18 0.37 0.55 0.73]
3828
[-0.98 0.068 0.10 0.14]
3829
[ 0.00 -0.93 0.22 0.30]
3830
[ 0.00 0.00 -0.80 0.60]
3831
sage: vector_on_axis_rotation_matrix(v, 0, ring=RealField(10)) * v
3832
(5.5, 0.00098, 0.00098, 0.00)
3833
3834
AUTHORS:
3835
3836
Sebastien Labbe (April 2010)
3837
"""
3838
dim = len(v)
3839
v = vector(v)
3840
m = identity_matrix(dim, sparse=True)
3841
L = range(i-1, -1, -1) + range(dim-1,i,-1)
3842
for i in L:
3843
rot = ith_to_zero_rotation_matrix(v, i, ring=ring)
3844
v = rot * v
3845
m = rot * m
3846
return m
3847
3848
def ith_to_zero_rotation_matrix(v, i, ring=None):
3849
r"""
3850
Return a rotation matrix that sends the i-th coordinates of the
3851
vector v to zero by doing a rotation with the (i-1)-th coordinate.
3852
3853
INPUT:
3854
3855
- ``v``` - vector
3856
- ``i`` - integer
3857
- ``ring`` - ring (optional, default: None) of the resulting matrix
3858
3859
OUTPUT:
3860
3861
A matrix
3862
3863
EXAMPLES::
3864
3865
sage: from sage.matrix.constructor import ith_to_zero_rotation_matrix
3866
sage: v = vector((1,2,3))
3867
sage: ith_to_zero_rotation_matrix(v, 2)
3868
[ 1 0 0]
3869
[ 0 2/13*sqrt(13) 3/13*sqrt(13)]
3870
[ 0 -3/13*sqrt(13) 2/13*sqrt(13)]
3871
sage: ith_to_zero_rotation_matrix(v, 2) * v
3872
(1, sqrt(13), 0)
3873
3874
::
3875
3876
sage: ith_to_zero_rotation_matrix(v, 0)
3877
[ 3/10*sqrt(10) 0 -1/10*sqrt(10)]
3878
[ 0 1 0]
3879
[ 1/10*sqrt(10) 0 3/10*sqrt(10)]
3880
sage: ith_to_zero_rotation_matrix(v, 1)
3881
[ 1/5*sqrt(5) 2/5*sqrt(5) 0]
3882
[-2/5*sqrt(5) 1/5*sqrt(5) 0]
3883
[ 0 0 1]
3884
sage: ith_to_zero_rotation_matrix(v, 2)
3885
[ 1 0 0]
3886
[ 0 2/13*sqrt(13) 3/13*sqrt(13)]
3887
[ 0 -3/13*sqrt(13) 2/13*sqrt(13)]
3888
3889
::
3890
3891
sage: ith_to_zero_rotation_matrix(v, 0) * v
3892
(0, 2, sqrt(10))
3893
sage: ith_to_zero_rotation_matrix(v, 1) * v
3894
(sqrt(5), 0, 3)
3895
sage: ith_to_zero_rotation_matrix(v, 2) * v
3896
(1, sqrt(13), 0)
3897
3898
Other ring::
3899
3900
sage: ith_to_zero_rotation_matrix(v, 2, ring=RR)
3901
[ 1.00000000000000 0.000000000000000 0.000000000000000]
3902
[ 0.000000000000000 0.554700196225229 0.832050294337844]
3903
[ 0.000000000000000 -0.832050294337844 0.554700196225229]
3904
sage: ith_to_zero_rotation_matrix(v, 2, ring=RDF)
3905
[ 1.0 0.0 0.0]
3906
[ 0.0 0.554700196225 0.832050294338]
3907
[ 0.0 -0.832050294338 0.554700196225]
3908
3909
On the symbolic ring::
3910
3911
sage: x,y,z = var('x,y,z')
3912
sage: v = vector((x,y,z))
3913
sage: ith_to_zero_rotation_matrix(v, 2)
3914
[ 1 0 0]
3915
[ 0 y/sqrt(y^2 + z^2) z/sqrt(y^2 + z^2)]
3916
[ 0 -z/sqrt(y^2 + z^2) y/sqrt(y^2 + z^2)]
3917
sage: ith_to_zero_rotation_matrix(v, 2) * v
3918
(x, y^2/sqrt(y^2 + z^2) + z^2/sqrt(y^2 + z^2), 0)
3919
3920
TESTS::
3921
3922
sage: ith_to_zero_rotation_matrix((1,0,0), 0)
3923
[ 0 0 -1]
3924
[ 0 1 0]
3925
[ 1 0 0]
3926
sage: ith_to_zero_rotation_matrix((1,0,0), 1)
3927
[1 0 0]
3928
[0 1 0]
3929
[0 0 1]
3930
sage: ith_to_zero_rotation_matrix((1,0,0), 2)
3931
[1 0 0]
3932
[0 1 0]
3933
[0 0 1]
3934
3935
AUTHORS:
3936
3937
Sebastien Labbe (April 2010)
3938
"""
3939
if not ring is None:
3940
# coerce the vector so that computations
3941
# are done in that ring
3942
v = vector(ring, v)
3943
dim = len(v)
3944
i = i % dim
3945
j = (i-1) % dim
3946
a, b = v[j], v[i]
3947
if b == 0:
3948
return identity_matrix(dim, sparse=True)
3949
from sage.functions.all import sqrt
3950
norm = sqrt(a*a + b*b)
3951
aa = a / norm
3952
bb = b / norm
3953
entries = {}
3954
for k in range(dim):
3955
entries[(k, k)] = 1
3956
entries.update({(j,j):aa, (j,i):bb, (i,j):-bb, (i,i):aa})
3957
return matrix(entries, nrows=dim, ring=ring)
3958
3959
3960
3961
3962