Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/matrix/benchmark.py
8815 views
1
"""
2
Benchmarks for matrices
3
4
This file has many functions for computing timing benchmarks
5
of various methods for random matrices with given bounds for
6
the entries. The systems supported are Sage and Magma.
7
8
The basic command syntax is as follows::
9
10
sage: import sage.matrix.benchmark as b
11
sage: print "starting"; import sys; sys.stdout.flush(); b.report([b.det_ZZ], 'Test', systems=['sage'])
12
starting...
13
======================================================================
14
Test
15
======================================================================
16
...
17
======================================================================
18
"""
19
from constructor import random_matrix, Matrix
20
from sage.rings.all import ZZ, QQ, GF
21
from sage.misc.misc import alarm, cancel_alarm, cputime
22
from sage.ext.c_lib import AlarmInterrupt
23
24
verbose = False
25
26
timeout = 60
27
28
def report(F, title, systems = ['sage', 'magma'], **kwds):
29
"""
30
Run benchmarks with default arguments for each function in the list F.
31
32
INPUT:
33
34
- ``F`` - a list of callables used for benchmarking
35
- ``title`` - a string describing this report
36
- ``systems`` - a list of systems (supported entries are 'sage' and 'magma')
37
- ``**kwds`` - keyword arguments passed to all functions in ``F``
38
39
EXAMPLES::
40
41
sage: import sage.matrix.benchmark as b
42
sage: print "starting"; import sys; sys.stdout.flush(); b.report([b.det_ZZ], 'Test', systems=['sage'])
43
starting...
44
======================================================================
45
Test
46
======================================================================
47
...
48
======================================================================
49
"""
50
import os
51
if len(systems) > 2:
52
raise NotImplementedError, "at most two systems ('sage' or 'magma')"
53
print '='*70
54
print ' '*10 + title
55
print '='*70
56
os.system('uname -a')
57
print '\n'
58
for f in F:
59
print "-"*70
60
print f.__doc__.strip()
61
print ('%15s'*len(systems))%tuple(systems)
62
w = []
63
for s in systems:
64
alarm(timeout)
65
try:
66
t = f(system=s, **kwds)
67
except AlarmInterrupt:
68
t = -timeout
69
cancel_alarm()
70
w.append(float(t))
71
if len(w) > 1:
72
if w[1] == 0:
73
w.append(0.0)
74
else:
75
w.append(w[0]/w[1])
76
77
w = tuple(w)
78
print ('%15.3f'*len(w))%w
79
print '='*70
80
81
82
#######################################################################
83
# Dense Benchmarks over ZZ
84
#######################################################################
85
86
def report_ZZ(**kwds):
87
"""
88
Reports all the benchmarks for integer matrices and few
89
rational matrices.
90
91
INPUT:
92
93
- ``**kwds`` - passed through to :func:`report`
94
95
EXAMPLES::
96
97
sage: import sage.matrix.benchmark as b
98
sage: print "starting"; import sys; sys.stdout.flush(); b.report_ZZ(systems=['sage']) # long time (15s on sage.math, 2012)
99
starting...
100
======================================================================
101
Dense benchmarks over ZZ
102
======================================================================
103
...
104
======================================================================
105
"""
106
F = [vecmat_ZZ, rank_ZZ, rank2_ZZ, charpoly_ZZ, smithform_ZZ,
107
det_ZZ, det_QQ, matrix_multiply_ZZ, matrix_add_ZZ,
108
matrix_add_ZZ_2,
109
nullspace_ZZ]
110
111
title = 'Dense benchmarks over ZZ'
112
report(F, title, **kwds)
113
114
# Integer Nullspace
115
116
def nullspace_ZZ(n=200, min=0, max=2**32, system='sage'):
117
"""
118
Nullspace over ZZ:
119
Given a n+1 x n matrix over ZZ with random entries
120
between min and max, compute the nullspace.
121
122
INPUT:
123
124
- ``n`` - matrix dimension (default: ``200``)
125
- ``min`` - minimal value for entries of matrix (default: ``0``)
126
- ``max`` - maximal value for entries of matrix (default: ``2**32``)
127
- ``system`` - either 'sage' or 'magma' (default: 'sage')
128
129
EXAMPLES::
130
131
sage: import sage.matrix.benchmark as b
132
sage: ts = b.nullspace_ZZ(200)
133
sage: tm = b.nullspace_ZZ(200, system='magma') # optional - magma
134
"""
135
if system == 'sage':
136
A = random_matrix(ZZ, n+1, n, x=min, y=max+1).change_ring(QQ)
137
t = cputime()
138
v = A.kernel()
139
return cputime(t)
140
elif system == 'magma':
141
code = """
142
n := %s;
143
A := RMatrixSpace(RationalField(), n+1,n)![Random(%s,%s) : i in [1..n*(n+1)]];
144
t := Cputime();
145
K := Kernel(A);
146
s := Cputime(t);
147
"""%(n,min,max)
148
if verbose: print code
149
magma.eval(code)
150
return float(magma.eval('s'))
151
else:
152
raise ValueError, 'unknown system "%s"'%system
153
154
155
def charpoly_ZZ(n=100, min=0, max=9, system='sage'):
156
"""
157
Characteristic polynomial over ZZ:
158
Given a n x n matrix over ZZ with random entries between min and
159
max, compute the charpoly.
160
161
INPUT:
162
163
- ``n`` - matrix dimension (default: ``100``)
164
- ``min`` - minimal value for entries of matrix (default: ``0``)
165
- ``max`` - maximal value for entries of matrix (default: ``9``)
166
- ``system`` - either 'sage' or 'magma' (default: 'sage')
167
168
EXAMPLES::
169
170
sage: import sage.matrix.benchmark as b
171
sage: ts = b.charpoly_ZZ(100)
172
sage: tm = b.charpoly_ZZ(100, system='magma') # optional - magma
173
"""
174
if system == 'sage':
175
A = random_matrix(ZZ, n, n, x=min, y=max+1)
176
t = cputime()
177
v = A.charpoly()
178
return cputime(t)
179
elif system == 'magma':
180
code = """
181
n := %s;
182
A := MatrixAlgebra(IntegerRing(), n)![Random(%s,%s) : i in [1..n^2]];
183
t := Cputime();
184
K := CharacteristicPolynomial(A);
185
s := Cputime(t);
186
"""%(n,min,max)
187
if verbose: print code
188
magma.eval(code)
189
return float(magma.eval('s'))
190
else:
191
raise ValueError, 'unknown system "%s"'%system
192
193
194
def rank_ZZ(n=700, min=0, max=9, system='sage'):
195
"""
196
Rank over ZZ:
197
Given a n x (n+10) matrix over ZZ with random entries
198
between min and max, compute the rank.
199
200
INPUT:
201
202
- ``n`` - matrix dimension (default: ``700``)
203
- ``min`` - minimal value for entries of matrix (default: ``0``)
204
- ``max`` - maximal value for entries of matrix (default: ``9``)
205
- ``system`` - either 'sage' or 'magma' (default: 'sage')
206
207
EXAMPLES::
208
209
sage: import sage.matrix.benchmark as b
210
sage: ts = b.rank_ZZ(300)
211
sage: tm = b.rank_ZZ(300, system='magma') # optional - magma
212
"""
213
if system == 'sage':
214
A = random_matrix(ZZ, n, n+10, x=min, y=max+1)
215
t = cputime()
216
v = A.rank()
217
return cputime(t)
218
elif system == 'magma':
219
code = """
220
n := %s;
221
A := RMatrixSpace(IntegerRing(), n, n+10)![Random(%s,%s) : i in [1..n*(n+10)]];
222
t := Cputime();
223
K := Rank(A);
224
s := Cputime(t);
225
"""%(n,min,max)
226
if verbose: print code
227
magma.eval(code)
228
return float(magma.eval('s'))
229
else:
230
raise ValueError, 'unknown system "%s"'%system
231
232
def rank2_ZZ(n=400, min=0, max=2**64, system='sage'):
233
"""
234
Rank 2 over ZZ:
235
Given a (n + 10) x n matrix over ZZ with random entries
236
between min and max, compute the rank.
237
238
INPUT:
239
240
- ``n`` - matrix dimension (default: ``400``)
241
- ``min`` - minimal value for entries of matrix (default: ``0``)
242
- ``max`` - maximal value for entries of matrix (default: ``2**64``)
243
- ``system`` - either 'sage' or 'magma' (default: 'sage')
244
245
EXAMPLES::
246
247
sage: import sage.matrix.benchmark as b
248
sage: ts = b.rank2_ZZ(300)
249
sage: tm = b.rank2_ZZ(300, system='magma') # optional - magma
250
"""
251
if system == 'sage':
252
A = random_matrix(ZZ, n+10, n, x=min, y=max+1)
253
t = cputime()
254
v = A.rank()
255
return cputime(t)
256
elif system == 'magma':
257
code = """
258
n := %s;
259
A := RMatrixSpace(IntegerRing(), n+10, n)![Random(%s,%s) : i in [1..n*(n+10)]];
260
t := Cputime();
261
K := Rank(A);
262
s := Cputime(t);
263
"""%(n,min,max)
264
if verbose: print code
265
magma.eval(code)
266
return float(magma.eval('s'))
267
else:
268
raise ValueError, 'unknown system "%s"'%system
269
270
# Smith Form
271
272
def smithform_ZZ(n=128, min=0, max=9, system='sage'):
273
"""
274
Smith Form over ZZ:
275
Given a n x n matrix over ZZ with random entries
276
between min and max, compute the Smith normal form.
277
278
INPUT:
279
280
- ``n`` - matrix dimension (default: ``128``)
281
- ``min`` - minimal value for entries of matrix (default: ``0``)
282
- ``max`` - maximal value for entries of matrix (default: ``9``)
283
- ``system`` - either 'sage' or 'magma' (default: 'sage')
284
285
EXAMPLES::
286
287
sage: import sage.matrix.benchmark as b
288
sage: ts = b.smithform_ZZ(100)
289
sage: tm = b.smithform_ZZ(100, system='magma') # optional - magma
290
"""
291
if system == 'sage':
292
A = random_matrix(ZZ, n, n, x=min, y=max+1)
293
t = cputime()
294
v = A.elementary_divisors()
295
return cputime(t)
296
elif system == 'magma':
297
code = """
298
n := %s;
299
A := MatrixAlgebra(IntegerRing(), n)![Random(%s,%s) : i in [1..n^2]];
300
t := Cputime();
301
K := ElementaryDivisors(A);
302
s := Cputime(t);
303
"""%(n,min,max)
304
if verbose: print code
305
magma.eval(code)
306
return float(magma.eval('s'))
307
else:
308
raise ValueError, 'unknown system "%s"'%system
309
310
311
def matrix_multiply_ZZ(n=300, min=-9, max=9, system='sage', times=1):
312
"""
313
Matrix multiplication over ZZ
314
Given an n x n matrix A over ZZ with random entries
315
between min and max, inclusive, compute A * (A+1).
316
317
INPUT:
318
319
- ``n`` - matrix dimension (default: ``300``)
320
- ``min`` - minimal value for entries of matrix (default: ``-9``)
321
- ``max`` - maximal value for entries of matrix (default: ``9``)
322
- ``system`` - either 'sage' or 'magma' (default: 'sage')
323
- ``times`` - number of experiments (default: ``1``)
324
325
EXAMPLES::
326
327
sage: import sage.matrix.benchmark as b
328
sage: ts = b.matrix_multiply_ZZ(200)
329
sage: tm = b.matrix_multiply_ZZ(200, system='magma') # optional - magma
330
"""
331
if system == 'sage':
332
A = random_matrix(ZZ, n, n, x=min, y=max+1)
333
B = A + 1
334
t = cputime()
335
for z in range(times):
336
v = A * B
337
return cputime(t)/times
338
elif system == 'magma':
339
code = """
340
n := %s;
341
A := MatrixAlgebra(IntegerRing(), n)![Random(%s,%s) : i in [1..n^2]];
342
B := A + 1;
343
t := Cputime();
344
for z in [1..%s] do
345
K := A * B;
346
end for;
347
s := Cputime(t);
348
"""%(n,min,max,times)
349
if verbose: print code
350
magma.eval(code)
351
return float(magma.eval('s'))/times
352
else:
353
raise ValueError, 'unknown system "%s"'%system
354
355
def matrix_add_ZZ(n=200, min=-9, max=9, system='sage', times=50):
356
"""
357
Matrix addition over ZZ
358
Given an n x n matrix A and B over ZZ with random entries between
359
``min`` and ``max``, inclusive, compute A + B ``times`` times.
360
361
INPUT:
362
363
- ``n`` - matrix dimension (default: ``200``)
364
- ``min`` - minimal value for entries of matrix (default: ``-9``)
365
- ``max`` - maximal value for entries of matrix (default: ``9``)
366
- ``system`` - either 'sage' or 'magma' (default: 'sage')
367
- ``times`` - number of experiments (default: ``50``)
368
369
EXAMPLES::
370
371
sage: import sage.matrix.benchmark as b
372
sage: ts = b.matrix_add_ZZ(200)
373
sage: tm = b.matrix_add_ZZ(200, system='magma') # optional - magma
374
"""
375
if system == 'sage':
376
A = random_matrix(ZZ, n, n, x=min, y=max+1)
377
B = random_matrix(ZZ, n, n, x=min, y=max+1)
378
t = cputime()
379
for z in range(times):
380
v = A + B
381
return cputime(t)/times
382
elif system == 'magma':
383
code = """
384
n := %s;
385
min := %s;
386
max := %s;
387
A := MatrixAlgebra(IntegerRing(), n)![Random(min,max) : i in [1..n^2]];
388
B := MatrixAlgebra(IntegerRing(), n)![Random(min,max) : i in [1..n^2]];
389
t := Cputime();
390
for z in [1..%s] do
391
K := A + B;
392
end for;
393
s := Cputime(t);
394
"""%(n,min,max,times)
395
if verbose: print code
396
magma.eval(code)
397
return float(magma.eval('s'))/times
398
else:
399
raise ValueError, 'unknown system "%s"'%system
400
401
def matrix_add_ZZ_2(n=200, bits=16, system='sage', times=50):
402
"""
403
Matrix addition over ZZ.
404
Given an n x n matrix A and B over ZZ with random ``bits``-bit
405
entries, compute A + B.
406
407
INPUT:
408
409
- ``n`` - matrix dimension (default: ``200``)
410
- ``bits`` - bitsize of entries
411
- ``system`` - either 'sage' or 'magma' (default: 'sage')
412
- ``times`` - number of experiments (default: ``50``)
413
414
EXAMPLES::
415
416
sage: import sage.matrix.benchmark as b
417
sage: ts = b.matrix_add_ZZ_2(200)
418
sage: tm = b.matrix_add_ZZ_2(200, system='magma') # optional - magma
419
"""
420
b = 2**bits
421
return matrix_add_ZZ(n=n, min=-b, max=b,system=system, times=times)
422
423
def det_ZZ(n=200, min=1, max=100, system='sage'):
424
"""
425
Dense integer determinant over ZZ.
426
Given an n x n matrix A over ZZ with random entries
427
between min and max, inclusive, compute det(A).
428
429
INPUT:
430
431
- ``n`` - matrix dimension (default: ``200``)
432
- ``min`` - minimal value for entries of matrix (default: ``1``)
433
- ``max`` - maximal value for entries of matrix (default: ``100``)
434
- ``system`` - either 'sage' or 'magma' (default: 'sage')
435
436
EXAMPLES::
437
438
sage: import sage.matrix.benchmark as b
439
sage: ts = b.det_ZZ(200)
440
sage: tm = b.det_ZZ(200, system='magma') # optional - magma
441
"""
442
if system == 'sage':
443
A = random_matrix(ZZ, n, n, x=min, y=max+1)
444
t = cputime()
445
d = A.determinant()
446
return cputime(t)
447
elif system == 'magma':
448
code = """
449
n := %s;
450
A := MatrixAlgebra(IntegerRing(), n)![Random(%s,%s) : i in [1..n^2]];
451
t := Cputime();
452
d := Determinant(A);
453
s := Cputime(t);
454
"""%(n,min,max)
455
if verbose: print code
456
magma.eval(code)
457
return float(magma.eval('s'))
458
else:
459
raise ValueError, 'unknown system "%s"'%system
460
461
462
def det_QQ(n=300, num_bound=10, den_bound=10, system='sage'):
463
"""
464
Dense rational determinant over QQ.
465
Given an n x n matrix A over QQ with random entries
466
with numerator bound and denominator bound, compute det(A).
467
468
INPUT:
469
470
- ``n`` - matrix dimension (default: ``200``)
471
- ``num_bound`` - numerator bound, inclusive (default: ``10``)
472
- ``den_bound`` - denominator bound, inclusive (default: ``10``)
473
- ``system`` - either 'sage' or 'magma' (default: 'sage')
474
475
EXAMPLES::
476
477
sage: import sage.matrix.benchmark as b
478
sage: ts = b.det_QQ(200)
479
sage: ts = b.det_QQ(10, num_bound=100000, den_bound=10000)
480
sage: tm = b.det_QQ(200, system='magma') # optional - magma
481
"""
482
if system == 'sage':
483
A = random_matrix(QQ, n, n, num_bound=num_bound, den_bound=den_bound)
484
t = cputime()
485
d = A.determinant()
486
return cputime(t)
487
elif system == 'magma':
488
code = """
489
n := %s;
490
A := MatrixAlgebra(RationalField(), n)![Random(%s,%s)/Random(1,%s) : i in [1..n^2]];
491
t := Cputime();
492
d := Determinant(A);
493
s := Cputime(t);
494
"""%(n,-num_bound, num_bound, den_bound)
495
if verbose: print code
496
magma.eval(code)
497
return float(magma.eval('s'))
498
else:
499
raise ValueError, 'unknown system "%s"'%system
500
501
502
def vecmat_ZZ(n=300, min=-9, max=9, system='sage', times=200):
503
"""
504
Vector matrix multiplication over ZZ.
505
506
Given an n x n matrix A over ZZ with random entries
507
between min and max, inclusive, and v the first row of A,
508
compute the product v * A.
509
510
INPUT:
511
512
- ``n`` - matrix dimension (default: ``300``)
513
- ``min`` - minimal value for entries of matrix (default: ``-9``)
514
- ``max`` - maximal value for entries of matrix (default: ``9``)
515
- ``system`` - either 'sage' or 'magma' (default: 'sage')
516
- ``times`` - number of runs (default: ``200``)
517
518
EXAMPLES::
519
520
sage: import sage.matrix.benchmark as b
521
sage: ts = b.vecmat_ZZ(300) # long time
522
sage: tm = b.vecmat_ZZ(300, system='magma') # optional - magma
523
"""
524
if system == 'sage':
525
A = random_matrix(ZZ, n, n, x=min, y=max+1)
526
v = A.row(0)
527
t = cputime()
528
for z in range(times):
529
w = v * A
530
return cputime(t)/times
531
elif system == 'magma':
532
code = """
533
n := %s;
534
A := MatrixAlgebra(IntegerRing(), n)![Random(%s,%s) : i in [1..n^2]];
535
v := A[1];
536
t := Cputime();
537
for z in [1..%s] do
538
K := v * A;
539
end for;
540
s := Cputime(t);
541
"""%(n,min,max,times)
542
if verbose: print code
543
magma.eval(code)
544
return float(magma.eval('s'))/times
545
else:
546
raise ValueError, 'unknown system "%s"'%system
547
548
549
550
#######################################################################
551
# Dense Benchmarks over GF(p), for small p.
552
#######################################################################
553
554
def report_GF(p=16411, **kwds):
555
"""
556
Runs all the reports for finite field matrix operations, for
557
prime p=16411.
558
559
INPUT:
560
561
- ``p`` - ignored
562
- ``**kwds`` - passed through to :func:`report`
563
564
.. note::
565
566
right now, even though p is an input, it is being ignored! If
567
you need to check the performance for other primes, you can
568
call individual benchmark functions.
569
570
EXAMPLES::
571
572
sage: import sage.matrix.benchmark as b
573
sage: print "starting"; import sys; sys.stdout.flush(); b.report_GF(systems=['sage'])
574
starting...
575
======================================================================
576
Dense benchmarks over GF with prime 16411
577
======================================================================
578
...
579
======================================================================
580
"""
581
F = [rank_GF, rank2_GF, nullspace_GF, charpoly_GF,
582
matrix_multiply_GF, det_GF]
583
title = 'Dense benchmarks over GF with prime %i' % p
584
report(F, title, **kwds)
585
586
# Nullspace over GF
587
588
def nullspace_GF(n=300, p=16411, system='sage'):
589
"""
590
Given a n+1 x n matrix over GF(p) with random
591
entries, compute the nullspace.
592
593
INPUT:
594
595
- ``n`` - matrix dimension (default: 300)
596
- ``p`` - prime number (default: ``16411``)
597
- ``system`` - either 'magma' or 'sage' (default: 'sage')
598
599
EXAMPLES::
600
601
sage: import sage.matrix.benchmark as b
602
sage: ts = b.nullspace_GF(300)
603
sage: tm = b.nullspace_GF(300, system='magma') # optional - magma
604
"""
605
if system == 'sage':
606
A = random_matrix(GF(p), n, n+1)
607
t = cputime()
608
v = A.kernel()
609
return cputime(t)
610
elif system == 'magma':
611
code = """
612
n := %s;
613
A := Random(RMatrixSpace(GF(%s), n, n+1));
614
t := Cputime();
615
K := Kernel(A);
616
s := Cputime(t);
617
"""%(n,p)
618
if verbose: print code
619
magma.eval(code)
620
return magma.eval('s')
621
else:
622
raise ValueError, 'unknown system "%s"'%system
623
624
625
# Characteristic Polynomial over GF
626
627
def charpoly_GF(n=100, p=16411, system='sage'):
628
"""
629
Given a n x n matrix over GF with random entries, compute the
630
charpoly.
631
632
INPUT:
633
634
- ``n`` - matrix dimension (default: 100)
635
- ``p`` - prime number (default: ``16411``)
636
- ``system`` - either 'magma' or 'sage' (default: 'sage')
637
638
EXAMPLES::
639
640
sage: import sage.matrix.benchmark as b
641
sage: ts = b.charpoly_GF(100)
642
sage: tm = b.charpoly_GF(100, system='magma') # optional - magma
643
"""
644
if system == 'sage':
645
A = random_matrix(GF(p), n, n)
646
t = cputime()
647
v = A.charpoly()
648
return cputime(t)
649
elif system == 'magma':
650
code = """
651
n := %s;
652
A := Random(MatrixAlgebra(GF(%s), n));
653
t := Cputime();
654
K := CharacteristicPolynomial(A);
655
s := Cputime(t);
656
"""%(n,p)
657
if verbose: print code
658
magma.eval(code)
659
return magma.eval('s')
660
else:
661
raise ValueError, 'unknown system "%s"'%system
662
663
def matrix_add_GF(n=1000, p=16411, system='sage',times=100):
664
"""
665
Given two n x n matrix over GF(p) with random entries, add them.
666
667
INPUT:
668
669
- ``n`` - matrix dimension (default: 300)
670
- ``p`` - prime number (default: ``16411``)
671
- ``system`` - either 'magma' or 'sage' (default: 'sage')
672
- ``times`` - number of experiments (default: ``100``)
673
674
EXAMPLES::
675
676
sage: import sage.matrix.benchmark as b
677
sage: ts = b.matrix_add_GF(500, p=19)
678
sage: tm = b.matrix_add_GF(500, p=19, system='magma') # optional - magma
679
"""
680
if system == 'sage':
681
A = random_matrix(GF(p), n, n)
682
B = random_matrix(GF(p), n, n)
683
t = cputime()
684
for n in range(times):
685
v = A + B
686
return cputime(t)
687
elif system == 'magma':
688
code = """
689
n := %s;
690
A := Random(MatrixAlgebra(GF(%s), n));
691
B := Random(MatrixAlgebra(GF(%s), n));
692
t := Cputime();
693
for z in [1..%s] do
694
K := A + B;
695
end for;
696
s := Cputime(t);
697
"""%(n,p,p,times)
698
if verbose: print code
699
magma.eval(code)
700
return magma.eval('s')
701
else:
702
raise ValueError, 'unknown system "%s"'%system
703
704
705
706
# Matrix multiplication over GF(p)
707
708
def matrix_multiply_GF(n=100, p=16411, system='sage', times=3):
709
"""
710
Given an n x n matrix A over GF(p) with random entries, compute
711
A * (A+1).
712
713
INPUT:
714
715
- ``n`` - matrix dimension (default: 100)
716
- ``p`` - prime number (default: ``16411``)
717
- ``system`` - either 'magma' or 'sage' (default: 'sage')
718
- ``times`` - number of experiments (default: ``3``)
719
720
EXAMPLES::
721
722
sage: import sage.matrix.benchmark as b
723
sage: ts = b.matrix_multiply_GF(100, p=19)
724
sage: tm = b.matrix_multiply_GF(100, p=19, system='magma') # optional - magma
725
"""
726
if system == 'sage':
727
A = random_matrix(GF(p), n)
728
B = A + 1
729
t = cputime()
730
for n in range(times):
731
v = A * B
732
return cputime(t) / times
733
elif system == 'magma':
734
code = """
735
n := %s;
736
A := Random(MatrixAlgebra(GF(%s), n));
737
B := A + 1;
738
t := Cputime();
739
for z in [1..%s] do
740
K := A * B;
741
end for;
742
s := Cputime(t);
743
"""%(n,p,times)
744
if verbose: print code
745
magma.eval(code)
746
return float(magma.eval('s'))/times
747
else:
748
raise ValueError, 'unknown system "%s"'%system
749
750
751
def rank_GF(n=500, p=16411, system='sage'):
752
"""
753
Rank over GF(p):
754
Given a n x (n+10) matrix over GF(p) with random entries, compute the rank.
755
756
INPUT:
757
758
- ``n`` - matrix dimension (default: 300)
759
- ``p`` - prime number (default: ``16411``)
760
- ``system`` - either 'magma' or 'sage' (default: 'sage')
761
762
EXAMPLES::
763
764
sage: import sage.matrix.benchmark as b
765
sage: ts = b.rank_GF(1000)
766
sage: tm = b.rank_GF(1000, system='magma') # optional - magma
767
"""
768
if system == 'sage':
769
A = random_matrix(GF(p), n, n+10)
770
t = cputime()
771
v = A.rank()
772
return cputime(t)
773
elif system == 'magma':
774
code = """
775
n := %s;
776
A := Random(MatrixAlgebra(GF(%s), n));
777
t := Cputime();
778
K := Rank(A);
779
s := Cputime(t);
780
"""%(n,p)
781
if verbose: print code
782
magma.eval(code)
783
return float(magma.eval('s'))
784
else:
785
raise ValueError, 'unknown system "%s"'%system
786
787
def rank2_GF(n=500, p=16411, system='sage'):
788
"""
789
Rank over GF(p): Given a (n + 10) x n matrix over GF(p) with
790
random entries, compute the rank.
791
792
INPUT:
793
794
- ``n`` - matrix dimension (default: 300)
795
- ``p`` - prime number (default: ``16411``)
796
- ``system`` - either 'magma' or 'sage' (default: 'sage')
797
798
EXAMPLES::
799
800
sage: import sage.matrix.benchmark as b
801
sage: ts = b.rank2_GF(500)
802
sage: tm = b.rank2_GF(500, system='magma') # optional - magma
803
"""
804
if system == 'sage':
805
A = random_matrix(GF(p), n+10, n)
806
t = cputime()
807
v = A.rank()
808
return cputime(t)
809
elif system == 'magma':
810
code = """
811
n := %s;
812
A := Random(MatrixAlgebra(GF(%s), n));
813
t := Cputime();
814
K := Rank(A);
815
s := Cputime(t);
816
"""%(n,p)
817
if verbose: print code
818
magma.eval(code)
819
return float(magma.eval('s'))
820
else:
821
raise ValueError, 'unknown system "%s"'%system
822
823
def det_GF(n=400, p=16411 , system='sage'):
824
"""
825
Dense determinant over GF(p).
826
Given an n x n matrix A over GF with random entries compute
827
det(A).
828
829
INPUT:
830
831
- ``n`` - matrix dimension (default: 300)
832
- ``p`` - prime number (default: ``16411``)
833
- ``system`` - either 'magma' or 'sage' (default: 'sage')
834
835
EXAMPLES::
836
837
sage: import sage.matrix.benchmark as b
838
sage: ts = b.det_GF(1000)
839
sage: tm = b.det_GF(1000, system='magma') # optional - magma
840
"""
841
if system == 'sage':
842
A = random_matrix(GF(p), n, n)
843
t = cputime()
844
d = A.determinant()
845
return cputime(t)
846
elif system == 'magma':
847
code = """
848
n := %s;
849
A := Random(MatrixAlgebra(GF(%s), n));
850
t := Cputime();
851
d := Determinant(A);
852
s := Cputime(t);
853
"""%(n,p)
854
if verbose: print code
855
magma.eval(code)
856
return float(magma.eval('s'))
857
else:
858
raise ValueError, 'unknown system "%s"'%system
859
860
861
#######################################################################
862
# Dense Benchmarks over QQ
863
#######################################################################
864
865
def hilbert_matrix(n):
866
"""
867
Returns the Hilbert matrix of size n over rationals.
868
869
EXAMPLES::
870
871
sage: import sage.matrix.benchmark as b
872
sage: b.hilbert_matrix(3)
873
[ 1 1/2 1/3]
874
[1/2 1/3 1/4]
875
[1/3 1/4 1/5]
876
"""
877
A = Matrix(QQ,n,n)
878
for i in range(A.nrows()):
879
for j in range(A.ncols()):
880
A[i,j] = QQ(1)/((i+1)+(j+1)-1)
881
return A
882
883
# Reduced row echelon form over QQ
884
885
def echelon_QQ(n=100, min=0, max=9, system='sage'):
886
"""
887
Given a n x (2*n) matrix over QQ with random integer entries
888
between min and max, compute the reduced row echelon form.
889
890
INPUT:
891
892
- ``n`` - matrix dimension (default: ``300``)
893
- ``min`` - minimal value for entries of matrix (default: ``-9``)
894
- ``max`` - maximal value for entries of matrix (default: ``9``)
895
- ``system`` - either 'sage' or 'magma' (default: 'sage')
896
897
EXAMPLES::
898
899
sage: import sage.matrix.benchmark as b
900
sage: ts = b.echelon_QQ(100)
901
sage: tm = b.echelon_QQ(100, system='magma') # optional - magma
902
"""
903
if system == 'sage':
904
A = random_matrix(ZZ, n, 2*n, x=min, y=max+1).change_ring(QQ)
905
t = cputime()
906
v = A.echelon_form()
907
return cputime(t)
908
elif system == 'magma':
909
code = """
910
n := %s;
911
A := RMatrixSpace(RationalField(), n, 2*n)![Random(%s,%s) : i in [1..n*2*n]];
912
t := Cputime();
913
K := EchelonForm(A);
914
s := Cputime(t);
915
"""%(n,min,max)
916
if verbose: print code
917
magma.eval(code)
918
return float(magma.eval('s'))
919
else:
920
raise ValueError, 'unknown system "%s"'%system
921
922
# Invert a matrix over QQ.
923
924
def inverse_QQ(n=100, min=0, max=9, system='sage'):
925
"""
926
Given a n x n matrix over QQ with random integer entries
927
between min and max, compute the reduced row echelon form.
928
929
INPUT:
930
931
- ``n`` - matrix dimension (default: ``300``)
932
- ``min`` - minimal value for entries of matrix (default: ``-9``)
933
- ``max`` - maximal value for entries of matrix (default: ``9``)
934
- ``system`` - either 'sage' or 'magma' (default: 'sage')
935
936
EXAMPLES::
937
938
sage: import sage.matrix.benchmark as b
939
sage: ts = b.inverse_QQ(100)
940
sage: tm = b.inverse_QQ(100, system='magma') # optional - magma
941
"""
942
if system == 'sage':
943
A = random_matrix(ZZ, n, n, x=min, y=max+1).change_ring(QQ)
944
t = cputime()
945
v = ~A
946
return cputime(t)
947
elif system == 'magma':
948
code = """
949
n := %s;
950
A := MatrixAlgebra(RationalField(), n)![Random(%s,%s) : i in [1..n*n]];
951
t := Cputime();
952
K := A^(-1);
953
s := Cputime(t);
954
"""%(n,min,max)
955
if verbose: print code
956
magma.eval(code)
957
return float(magma.eval('s'))
958
else:
959
raise ValueError, 'unknown system "%s"'%system
960
961
962
# Matrix multiplication over QQ
963
def matrix_multiply_QQ(n=100, bnd=2, system='sage', times=1):
964
"""
965
Given an n x n matrix A over QQ with random entries
966
whose numerators and denominators are bounded by bnd,
967
compute A * (A+1).
968
969
INPUT:
970
971
- ``n`` - matrix dimension (default: ``300``)
972
- ``bnd`` - numerator and denominator bound (default: ``bnd``)
973
- ``system`` - either 'sage' or 'magma' (default: 'sage')
974
- ``times`` - number of experiments (default: ``1``)
975
976
EXAMPLES::
977
978
sage: import sage.matrix.benchmark as b
979
sage: ts = b.matrix_multiply_QQ(100)
980
sage: tm = b.matrix_multiply_QQ(100, system='magma') # optional - magma
981
"""
982
if system == 'sage':
983
A = random_matrix(QQ, n, n, num_bound=bnd, den_bound=bnd)
984
B = A + 1
985
t = cputime()
986
for z in range(times):
987
v = A * B
988
return cputime(t)/times
989
elif system == 'magma':
990
A = magma(random_matrix(QQ, n, n, num_bound=bnd, den_bound=bnd))
991
code = """
992
n := %s;
993
A := %s;
994
B := A + 1;
995
t := Cputime();
996
for z in [1..%s] do
997
K := A * B;
998
end for;
999
s := Cputime(t);
1000
"""%(n, A.name(), times)
1001
if verbose: print code
1002
magma.eval(code)
1003
return float(magma.eval('s'))/times
1004
else:
1005
raise ValueError, 'unknown system "%s"'%system
1006
1007
1008
# Determinant of Hilbert matrix
1009
def det_hilbert_QQ(n=80, system='sage'):
1010
"""
1011
Runs the benchmark for calculating the determinant of the hilbert
1012
matrix over rationals of dimension n.
1013
1014
INPUT:
1015
1016
- ``n`` - matrix dimension (default: ``300``)
1017
- ``system`` - either 'sage' or 'magma' (default: 'sage')
1018
1019
EXAMPLES::
1020
1021
sage: import sage.matrix.benchmark as b
1022
sage: ts = b.det_hilbert_QQ(50)
1023
sage: tm = b.det_hilbert_QQ(50, system='magma') # optional - magma
1024
"""
1025
if system == 'sage':
1026
A = hilbert_matrix(n)
1027
t = cputime()
1028
d = A.determinant()
1029
return cputime(t)
1030
elif system == 'magma':
1031
code = """
1032
h := HilbertMatrix(%s);
1033
tinit := Cputime();
1034
d := Determinant(h);
1035
s := Cputime(tinit);
1036
delete h;
1037
"""%n
1038
if verbose: print code
1039
magma.eval(code)
1040
return float(magma.eval('s'))
1041
1042
# inverse of Hilbert matrix
1043
def invert_hilbert_QQ(n=40, system='sage'):
1044
"""
1045
Runs the benchmark for calculating the inverse of the hilbert
1046
matrix over rationals of dimension n.
1047
1048
INPUT:
1049
1050
- ``n`` - matrix dimension (default: ``300``)
1051
- ``system`` - either 'sage' or 'magma' (default: 'sage')
1052
1053
EXAMPLES::
1054
1055
sage: import sage.matrix.benchmark as b
1056
sage: ts = b.invert_hilbert_QQ(30)
1057
sage: tm = b.invert_hilbert_QQ(30, system='magma') # optional - magma
1058
"""
1059
if system == 'sage':
1060
A = hilbert_matrix(n)
1061
t = cputime()
1062
d = A**(-1)
1063
return cputime(t)
1064
elif system == 'magma':
1065
code = """
1066
h := HilbertMatrix(%s);
1067
tinit := Cputime();
1068
d := h^(-1);
1069
s := Cputime(tinit);
1070
delete h;
1071
"""%n
1072
if verbose: print code
1073
magma.eval(code)
1074
return float(magma.eval('s'))
1075
1076
def MatrixVector_QQ(n=1000,h=100,system='sage',times=1):
1077
"""
1078
Compute product of square ``n`` matrix by random vector with num and
1079
denom bounded by ``h`` the given number of ``times``.
1080
1081
INPUT:
1082
1083
- ``n`` - matrix dimension (default: ``300``)
1084
- ``h`` - numerator and denominator bound (default: ``bnd``)
1085
- ``system`` - either 'sage' or 'magma' (default: 'sage')
1086
- ``times`` - number of experiments (default: ``1``)
1087
1088
EXAMPLES::
1089
1090
sage: import sage.matrix.benchmark as b
1091
sage: ts = b.MatrixVector_QQ(500)
1092
sage: tm = b.MatrixVector_QQ(500, system='magma') # optional - magma
1093
"""
1094
if system=='sage':
1095
V=QQ**n
1096
v=V.random_element(h)
1097
M=random_matrix(QQ,n)
1098
t=cputime()
1099
for i in range(times):
1100
w=M*v
1101
return cputime(t)
1102
elif system == 'magma':
1103
code = """
1104
n:=%s;
1105
h:=%s;
1106
times:=%s;
1107
v:=VectorSpace(RationalField(),n)![Random(h)/(Random(h)+1) : i in [1..n]];
1108
M:=MatrixAlgebra(RationalField(),n)![Random(h)/(Random(h)+1) : i in [1..n^2]];
1109
t := Cputime();
1110
for z in [1..times] do
1111
W:=v*M;
1112
end for;
1113
s := Cputime(t);
1114
"""%(n,h,times)
1115
if verbose: print code
1116
magma.eval(code)
1117
return float(magma.eval('s'))
1118
else:
1119
raise ValueError, 'unknown system "%s"'%system
1120
1121
1122
#######################################################################
1123
# Dense Benchmarks over machine reals
1124
# Note that the precision in reals for MAGMA is base 10, while in
1125
# sage it is in base 2
1126
#######################################################################
1127
1128
# Real Nullspace
1129
1130
def nullspace_RR(n=300, min=0, max=10, system='sage'):
1131
"""
1132
Nullspace over RR:
1133
Given a n+1 x n matrix over RR with random entries
1134
between min and max, compute the nullspace.
1135
1136
INPUT:
1137
1138
- ``n`` - matrix dimension (default: ``300``)
1139
- ``min`` - minimal value for entries of matrix (default: ``0``)
1140
- ``max`` - maximal value for entries of matrix (default: ``10``)
1141
- ``system`` - either 'sage' or 'magma' (default: 'sage')
1142
1143
EXAMPLES::
1144
1145
sage: import sage.matrix.benchmark as b
1146
sage: ts = b.nullspace_RR(100)
1147
sage: tm = b.nullspace_RR(100, system='magma') # optional - magma
1148
"""
1149
if system == 'sage':
1150
from sage.rings.real_mpfr import RR
1151
A = random_matrix(ZZ, n+1, n, x=min, y=max+1).change_ring(RR)
1152
t = cputime()
1153
v = A.kernel()
1154
return cputime(t)
1155
elif system == 'magma':
1156
code = """
1157
n := %s;
1158
A := RMatrixSpace(RealField(16), n+1,n)![Random(%s,%s) : i in [1..n*(n+1)]];
1159
t := Cputime();
1160
K := Kernel(A);
1161
s := Cputime(t);
1162
"""%(n,min,max)
1163
if verbose: print code
1164
magma.eval(code)
1165
return float(magma.eval('s'))
1166
else:
1167
raise ValueError, 'unknown system "%s"'%system
1168
1169
1170
def nullspace_RDF(n=300, min=0, max=10, system='sage'):
1171
"""
1172
Nullspace over RDF:
1173
Given a n+1 x n matrix over RDF with random entries
1174
between min and max, compute the nullspace.
1175
1176
INPUT:
1177
1178
- ``n`` - matrix dimension (default: ``300``)
1179
- ``min`` - minimal value for entries of matrix (default: ``0``)
1180
- ``max`` - maximal value for entries of matrix (default: `10``)
1181
- ``system`` - either 'sage' or 'magma' (default: 'sage')
1182
1183
EXAMPLES::
1184
1185
sage: import sage.matrix.benchmark as b
1186
sage: ts = b.nullspace_RDF(100) # long time
1187
sage: tm = b.nullspace_RDF(100, system='magma') # optional - magma
1188
"""
1189
if system == 'sage':
1190
from sage.rings.real_double import RDF
1191
A = random_matrix(ZZ, n+1, n, x=min, y=max+1).change_ring(RDF)
1192
t = cputime()
1193
v = A.kernel()
1194
return cputime(t)
1195
elif system == 'magma':
1196
code = """
1197
n := %s;
1198
A := RMatrixSpace(RealField(16), n+1,n)![Random(%s,%s) : i in [1..n*(n+1)]];
1199
t := Cputime();
1200
K := Kernel(A);
1201
s := Cputime(t);
1202
"""%(n,min,max)
1203
if verbose: print code
1204
magma.eval(code)
1205
return float(magma.eval('s'))
1206
else:
1207
raise ValueError, 'unknown system "%s"'%system
1208
1209
1210
1211