Dense matrices over \(\ZZ/n\ZZ\) for \(n < 2^{23}\) using LinBox’s Modular<double>

AUTHORS:

  • Burcin Erocal

  • Martin Albrecht

class sage.matrix.matrix_modn_dense_double.Matrix_modn_dense_double

Bases: sage.matrix.matrix_modn_dense_double.Matrix_modn_dense_template

Dense matrices over \(\ZZ/n\ZZ\) for \(n < 2^{23}\) using LinBox’s Modular<double>

These are matrices with integer entries mod n represented as floating-point numbers in a 64-bit word for use with LinBox routines. This allows for n up to \(2^{23}\). The analogous Matrix_modn_dense_float class is used for smaller moduli.

Routines here are for the most basic access, see the matrix_modn_dense_template.pxi file for higher-level routines.

class sage.matrix.matrix_modn_dense_double.Matrix_modn_dense_template

Bases: sage.matrix.matrix_dense.Matrix_dense

Create a new matrix.

INPUT:

  • parent – a matrix space

  • entries – see matrix()

  • copy – ignored (for backwards compatibility)

  • coerce - perform modular reduction first?

EXAMPLES:

sage: A = random_matrix(GF(3),1000,1000)
sage: type(A)
<type 'sage.matrix.matrix_modn_dense_float.Matrix_modn_dense_float'>
sage: A = random_matrix(Integers(10),1000,1000)
sage: type(A)
<type 'sage.matrix.matrix_modn_dense_float.Matrix_modn_dense_float'>
sage: A = random_matrix(Integers(2^16),1000,1000)
sage: type(A)
<type 'sage.matrix.matrix_modn_dense_double.Matrix_modn_dense_double'>
charpoly(var='x', algorithm='linbox')

Return the characteristic polynomial of self.

INPUT:

  • var - a variable name

  • algorithm - ‘generic’, ‘linbox’ or ‘all’ (default: linbox)

EXAMPLES:

sage: A = random_matrix(GF(19), 10, 10); A
[ 3  1  8 10  5 16 18  9  6  1]
[ 5 14  4  4 14 15  5 11  3  0]
[ 4  1  0  7 11  6 17  8  5  6]
[ 4  6  9  4  8  1 18 17  8 18]
[11  2  0  6 13  7  4 11 16 10]
[12  6 12  3 15 10  5 11  3  8]
[15  1 16  2 18 15 14  7  2 11]
[16 16 17  7 14 12  7  7  0  5]
[13 15  9  2 12 16  1 15 18  7]
[10  8 16 18  9 18  2 13  5 10]

sage: B = copy(A)
sage: char_p = A.characteristic_polynomial(); char_p
x^10 + 2*x^9 + 18*x^8 + 4*x^7 + 13*x^6 + 11*x^5 + 2*x^4 + 5*x^3 + 7*x^2 + 16*x + 6
sage: char_p(A) == 0
True
sage: B == A              # A is not modified
True

sage: min_p = A.minimal_polynomial(proof=True); min_p
x^10 + 2*x^9 + 18*x^8 + 4*x^7 + 13*x^6 + 11*x^5 + 2*x^4 + 5*x^3 + 7*x^2 + 16*x + 6
sage: min_p.divides(char_p)
True
sage: A = random_matrix(GF(2916337), 7, 7); A
[ 514193 1196222 1242955 1040744   99523 2447069   40527]
[ 930282 2685786 2892660 1347146 1126775 2131459  869381]
[1853546 2266414 2897342 1342067 1054026  373002   84731]
[1270068 2421818  569466  537440  572533  297105 1415002]
[2079710  355705 2546914 2299052 2883413 1558788 1494309]
[1027319 1572148  250822  522367 2516720  585897 2296292]
[1797050 2128203 1161160  562535 2875615 1165768  286972]

sage: B = copy(A)
sage: char_p = A.characteristic_polynomial(); char_p
x^7 + 1274305*x^6 + 1497602*x^5 + 12362*x^4 + 875330*x^3 + 31311*x^2 + 1858466*x + 700510
sage: char_p(A) == 0
True
sage: B == A               # A is not modified
True

sage: min_p = A.minimal_polynomial(proof=True); min_p
x^7 + 1274305*x^6 + 1497602*x^5 + 12362*x^4 + 875330*x^3 + 31311*x^2 + 1858466*x + 700510
sage: min_p.divides(char_p)
True

sage: A = Mat(Integers(6),3,3)(range(9))
sage: A.charpoly()
x^3

ALGORITHM: Uses LinBox if self.base_ring() is a field, otherwise use Hessenberg form algorithm.

determinant()

Return the determinant of this matrix.

EXAMPLES:

sage: A = random_matrix(GF(7), 10, 10); A
[3 1 6 6 4 4 2 2 3 5]
[4 5 6 2 2 1 2 5 0 5]
[3 2 0 5 0 1 5 4 2 3]
[6 4 5 0 2 4 2 0 6 3]
[2 2 4 2 4 5 3 4 4 4]
[2 5 2 5 4 5 1 1 1 1]
[0 6 3 4 2 2 3 5 1 1]
[4 2 6 5 6 3 4 5 5 3]
[5 2 4 3 6 2 3 6 2 1]
[3 3 5 3 4 2 2 1 6 2]

sage: A.determinant()
6
sage: A = random_matrix(GF(7), 100, 100)
sage: A.determinant()
2

sage: A.transpose().determinant()
2

sage: B = random_matrix(GF(7), 100, 100)
sage: B.determinant()
4

sage: (A*B).determinant() == A.determinant() * B.determinant()
True
sage: A = random_matrix(GF(16007), 10, 10); A
[ 5037  2388  4150  1400   345  5945  4240 14022 10514   700]
[15552  8539  1927  3870  9867  3263 11637   609 15424  2443]
[ 3761 15836 12246 15577 10178 13602 13183 15918 13942  2958]
[ 4526 10817  6887  6678  1764  9964  6107  1705  5619  5811]
[13537 15004  8307 11846 14779   550 14113  5477  7271  7091]
[13338  4927 11406 13065  5437 12431  6318  5119 14198   496]
[ 1044   179 12881   353 12975 12567  1092 10433 12304   954]
[10072  8821 14118 13895  6543 13484 10685 14363  2612 11070]
[15113   237  2612 14127 11589  5808   117  9656 15957 14118]
[15233 11080  5716  9029 11402  9380 13045 13986 14544  5771]

sage: A.determinant()
10207
sage: A = random_matrix(GF(16007), 100, 100)
sage: A.determinant()
3576


sage: A.transpose().determinant()
3576

sage: B = random_matrix(GF(16007), 100, 100)
sage: B.determinant()
4075

sage: (A*B).determinant() == A.determinant() * B.determinant()
True

Parallel computation:

sage: A = random_matrix(GF(65521),200)
sage: B = copy(A)
sage: Parallelism().set('linbox', nproc=2)
sage: d = A.determinant()
sage: Parallelism().set('linbox', nproc=1) # switch off parallelization
sage: e = B.determinant()
sage: d==e
True
echelonize(algorithm='linbox_noefd', **kwds)

Put self in reduced row echelon form.

INPUT:

  • self - a mutable matrix

  • algorithm

    • linbox - uses the LinBox library (wrapping fflas-ffpack)

    • linbox_noefd - uses the FFPACK directly, less memory and faster (default)

    • gauss - uses a custom slower \(O(n^3)\) Gauss elimination implemented in Sage.

    • all - compute using both algorithms and verify that the results are the same.

  • **kwds - these are all ignored

OUTPUT:

  • self is put in reduced row echelon form.

  • the rank of self is computed and cached

  • the pivot columns of self are computed and cached.

  • the fact that self is now in echelon form is recorded and cached so future calls to echelonize return immediately.

EXAMPLES:

sage: A = random_matrix(GF(7), 10, 20); A
[3 1 6 6 4 4 2 2 3 5 4 5 6 2 2 1 2 5 0 5]
[3 2 0 5 0 1 5 4 2 3 6 4 5 0 2 4 2 0 6 3]
[2 2 4 2 4 5 3 4 4 4 2 5 2 5 4 5 1 1 1 1]
[0 6 3 4 2 2 3 5 1 1 4 2 6 5 6 3 4 5 5 3]
[5 2 4 3 6 2 3 6 2 1 3 3 5 3 4 2 2 1 6 2]
[0 5 6 3 2 5 6 6 3 2 1 4 5 0 2 6 5 2 5 1]
[4 0 4 2 6 3 3 5 3 0 0 1 2 5 5 1 6 0 0 3]
[2 0 1 0 0 3 0 2 4 2 2 4 4 4 5 4 1 2 3 4]
[2 4 1 4 3 0 6 2 2 5 2 5 3 6 4 2 2 6 4 4]
[0 0 2 2 1 6 2 0 5 0 4 3 1 6 0 6 0 4 6 5]

sage: A.echelon_form()
[1 0 0 0 0 0 0 0 0 0 6 2 6 0 1 1 2 5 6 2]
[0 1 0 0 0 0 0 0 0 0 0 4 5 4 3 4 2 5 1 2]
[0 0 1 0 0 0 0 0 0 0 6 3 4 6 1 0 3 6 5 6]
[0 0 0 1 0 0 0 0 0 0 0 3 5 2 3 4 0 6 5 3]
[0 0 0 0 1 0 0 0 0 0 0 6 3 4 5 3 0 4 3 2]
[0 0 0 0 0 1 0 0 0 0 1 1 0 2 4 2 5 5 5 0]
[0 0 0 0 0 0 1 0 0 0 1 0 1 3 2 0 0 0 5 3]
[0 0 0 0 0 0 0 1 0 0 4 4 2 6 5 4 3 4 1 0]
[0 0 0 0 0 0 0 0 1 0 1 0 4 2 3 5 4 6 4 0]
[0 0 0 0 0 0 0 0 0 1 2 0 5 0 5 5 3 1 1 4]
sage: A = random_matrix(GF(13), 10, 10); A
[ 8  3 11 11  9  4  8  7  9  9]
[ 2  9  6  5  7 12  3  4 11  5]
[12  6 11 12  4  3  3  8  9  5]
[ 4  2 10  5 10  1  1  1  6  9]
[12  8  5  5 11  4  1  2  8 11]
[ 2  6  9 11  4  7  1  0 12  2]
[ 8  9  0  7  7  7 10  4  1  4]
[ 0  8  2  6  7  5  7 12  2  3]
[ 2 11 12  3  4  7  2  9  6  1]
[ 0 11  5  9  4  5  5  8  7 10]

sage: MS = parent(A)
sage: B = A.augment(MS(1))
sage: B.echelonize()
sage: A.rank()
10
sage: C = B.submatrix(0,10,10,10); C
[ 4  9  4  4  0  4  7 11  9 11]
[11  7  6  8  2  8  6 11  9  5]
[ 3  9  9  2  4  8  9  2  9  4]
[ 7  0 11  4  0  9  6 11  8  1]
[12 12  4 12  3 12  6  1  7 12]
[12  2 11  6  6  6  7  0 10  6]
[ 0  7  3  4  7 11 10 12  4  6]
[ 5 11  0  5  3 11  4 12  5 12]
[ 6  7  3  5  1  4 11  7  4  1]
[ 4  9  6  7 11  1  2 12  6  7]

sage: ~A == C
True
sage: A = random_matrix(Integers(10), 10, 20)
sage: A.echelon_form()
Traceback (most recent call last):
...
NotImplementedError: Echelon form not implemented over 'Ring of integers modulo 10'.
sage: A = random_matrix(GF(16007), 10, 20); A
[15455  1177 10072  4693  3887  4102 10746 15265  6684 14559  4535 13921  9757  9525  9301  8566  2460  9609  3887  6205]
[ 8602 10035  1242  9776   162  7893 12619  6660 13250  1988 14263 11377  2216  1247  7261  8446 15081 14412  7371  7948]
[12634  7602   905  9617 13557  2694 13039  4936 12208 15480  3787 11229   593 12462  5123 14167  6460  3649  5821  6736]
[10554  2511 11685 12325 12287  6534 11636  5004  6468  3180  3607 11627 13436  5106  3138 13376  8641  9093  2297  5893]
[ 1025 11376 10288   609 12330  3021   908 13012  2112 11505    56  5971   338  2317  2396  8561  5593  3782  7986 13173]
[ 7607   588  6099 12749 10378   111  2852 10375  8996  7969   774 13498 12720  4378  6817  6707  5299  9406 13318  2863]
[15545   538  4840  1885  8471  1303 11086 14168  1853 14263  3995 12104  1294  7184  1188 11901 15971  2899  4632   711]
[  584 11745  7540 15826 15027  5953  7097 14329 10889 12532 13309 15041  6211  1749 10481  9999  2751 11068    21  2795]
[  761 11453  3435 10596  2173  7752 15941 14610  1072  8012  9458  5440   612 10581 10400   101 11472 13068  7758  7898]
[10658  4035  6662   655  7546  4107  6987  1877  4072  4221  7679 14579  2474  8693  8127 12999 11141   605  9404 10003]
sage: A.echelon_form()
[    1     0     0     0     0     0     0     0     0     0  8416  8364 10318  1782 13872  4566 14855  7678 11899  2652]
[    0     1     0     0     0     0     0     0     0     0  4782 15571  3133 10964  5581 10435  9989 14303  5951  8048]
[    0     0     1     0     0     0     0     0     0     0 15688  6716 13819  4144   257  5743 14865 15680  4179 10478]
[    0     0     0     1     0     0     0     0     0     0  4307  9488  2992  9925 13984 15754  8185 11598 14701 10784]
[    0     0     0     0     1     0     0     0     0     0   927  3404 15076  1040  2827  9317 14041 10566  5117  7452]
[    0     0     0     0     0     1     0     0     0     0  1144 10861  5241  6288  9282  5748  3715 13482  7258  9401]
[    0     0     0     0     0     0     1     0     0     0   769  1804  1879  4624  6170  7500 11883  9047   874   597]
[    0     0     0     0     0     0     0     1     0     0 15591 13686  5729 11259 10219 13222 15177 15727  5082 11211]
[    0     0     0     0     0     0     0     0     1     0  8375 14939 13471 12221  8103  4212 11744 10182  2492 11068]
[    0     0     0     0     0     0     0     0     0     1  6534   396  6780 14734  1206  3848  7712  9770 10755   410]
sage: A = random_matrix(Integers(10000), 10, 20)
sage: A.echelon_form()
Traceback (most recent call last):
...
NotImplementedError: Echelon form not implemented over 'Ring of integers modulo 10000'.

Parallel computation:

sage: A = random_matrix(GF(65521),100,200)
sage: Parallelism().set('linbox', nproc=2)
sage: E = A.echelon_form()
sage: Parallelism().set('linbox', nproc=1) # switch off parallelization
sage: F = A.echelon_form()
sage: E==F
True
hessenbergize()

Transforms self in place to its Hessenberg form.

EXAMPLES:

sage: A = random_matrix(GF(17), 10, 10, density=0.1); A
[ 0  0  0  0 12  0  0  0  0  0]
[ 0  0  0  4  0  0  0  0  0  0]
[ 0  0  0  0  2  0  0  0  0  0]
[ 0 14  0  0  0  0  0  0  0  0]
[ 0  0  0  0  0 10  0  0  0  0]
[ 0  0  0  0  0 16  0  0  0  0]
[ 0  0  0  0  0  0  6  0  0  0]
[15  0  0  0  0  0  0  0  0  0]
[ 0  0  0 16  0  0  0  0  0  0]
[ 0  5  0  0  0  0  0  0  0  0]
sage: A.hessenbergize(); A
[ 0  0  0  0  0  0  0 12  0  0]
[15  0  0  0  0  0  0  0  0  0]
[ 0  0  0  0  0  0  0  2  0  0]
[ 0  0  0  0 14  0  0  0  0  0]
[ 0  0  0  4  0  0  0  0  0  0]
[ 0  0  0  0  5  0  0  0  0  0]
[ 0  0  0  0  0  0  6  0  0  0]
[ 0  0  0  0  0  0  0  0  0 10]
[ 0  0  0  0  0  0  0  0  0  0]
[ 0  0  0  0  0  0  0  0  0 16]
lift()

Return the lift of this matrix to the integers.

EXAMPLES:

sage: A = matrix(GF(7),2,3,[1..6])
sage: A.lift()
[1 2 3]
[4 5 6]
sage: A.lift().parent()
Full MatrixSpace of 2 by 3 dense matrices over Integer Ring

sage: A = matrix(GF(16007),2,3,[1..6])
sage: A.lift()
[1 2 3]
[4 5 6]
sage: A.lift().parent()
Full MatrixSpace of 2 by 3 dense matrices over Integer Ring

Subdivisions are preserved when lifting:

sage: A.subdivide([], [1,1]); A
[1||2 3]
[4||5 6]
sage: A.lift()
[1||2 3]
[4||5 6]
minpoly(var='x', algorithm='linbox', proof=None)

Returns the minimal polynomial of`` self``.

INPUT:

  • var - a variable name

  • algorithm - generic or linbox (default: linbox)

  • proof – (default: True); whether to provably return the true minimal polynomial; if False, we only guarantee to return a divisor of the minimal polynomial. There are also certainly cases where the computed results is frequently not exactly equal to the minimal polynomial (but is instead merely a divisor of it).

Warning

If proof=True, minpoly is insanely slow compared to proof=False. This matters since proof=True is the default, unless you first type proof.linear_algebra(False).

EXAMPLES:

sage: A = random_matrix(GF(17), 10, 10); A
[ 2 14  0 15 11 10 16  2  9  4]
[10 14  1 14  3 14 12 14  3 13]
[10  1 14  6  2 14 13  7  6 14]
[10  3  9 15  8  1  5  8 10 11]
[ 5 12  4  9 15  2  6 11  2 12]
[ 6 10 12  0  6  9  7  7  3  8]
[ 2  9  1  5 12 13  7 16  7 11]
[11  1  0  2  0  4  7  9  8 15]
[ 5  3 16  2 11 10 12 14  0  7]
[16  4  6  5  2  3 14 15 16  4]

sage: B = copy(A)
sage: min_p = A.minimal_polynomial(proof=True); min_p
x^10 + 13*x^9 + 10*x^8 + 9*x^7 + 10*x^6 + 4*x^5 + 10*x^4 + 10*x^3 + 12*x^2 + 14*x + 7
sage: min_p(A) == 0
True
sage: B == A
True

sage: char_p = A.characteristic_polynomial(); char_p
x^10 + 13*x^9 + 10*x^8 + 9*x^7 + 10*x^6 + 4*x^5 + 10*x^4 + 10*x^3 + 12*x^2 + 14*x + 7
sage: min_p.divides(char_p)
True
sage: A = random_matrix(GF(1214471), 10, 10); A
[ 160562  831940   65852  173001  515930  714380  778254  844537  584888  392730]
[ 502193  959391  614352  775603  240043 1156372  104118 1175992  612032 1049083]
[ 660489 1066446  809624   15010 1002045  470722  314480 1155149 1173111   14213]
[1190467 1079166  786442  429883  563611  625490 1015074  888047 1090092  892387]
[   4724  244901  696350  384684  254561  898612   44844   83752 1091581  349242]
[ 130212  580087  253296  472569  913613  919150   38603  710029  438461  736442]
[ 943501  792110  110470  850040  713428  668799 1122064  325250 1084368  520553]
[1179743  791517   34060 1183757 1118938  642169   47513   73428 1076788  216479]
[ 626571  105273  400489 1041378 1186801  158611  888598 1138220 1089631   56266]
[1092400  890773 1060810  211135  719636 1011640  631366  427711  547497 1084281]

sage: B = copy(A)
sage: min_p = A.minimal_polynomial(proof=True); min_p
x^10 + 384251*x^9 + 702437*x^8 + 960299*x^7 + 202699*x^6 + 409368*x^5 + 1109249*x^4 + 1163061*x^3 + 333802*x^2 + 273775*x + 55190

sage: min_p(A) == 0
True
sage: B == A
True

sage: char_p = A.characteristic_polynomial(); char_p
x^10 + 384251*x^9 + 702437*x^8 + 960299*x^7 + 202699*x^6 + 409368*x^5 + 1109249*x^4 + 1163061*x^3 + 333802*x^2 + 273775*x + 55190

sage: min_p.divides(char_p)
True

EXAMPLES:

sage: R.<x>=GF(3)[]
sage: A = matrix(GF(3),2,[0,0,1,2])
sage: A.minpoly()
x^2 + x

sage: A.minpoly(proof=False) in [x, x+1, x^2+x]
True
randomize(density=1, nonzero=False)

Randomize density proportion of the entries of this matrix, leaving the rest unchanged.

INPUT:

  • density - Integer; proportion (roughly) to be considered

    for changes

  • nonzero - Bool (default: False); whether the new

    entries are forced to be non-zero

OUTPUT:

  • None, the matrix is modified in-space

EXAMPLES:

sage: A = matrix(GF(5), 5, 5, 0)
sage: A.randomize(0.5); A
[0 0 0 2 0]
[0 3 0 0 2]
[4 0 0 0 0]
[4 0 0 0 0]
[0 1 0 0 0]

sage: A.randomize(); A
[3 3 2 1 2]
[4 3 3 2 2]
[0 3 3 3 3]
[3 3 2 2 4]
[2 2 2 1 4]

The matrix is updated instead of overwritten:

sage: A = random_matrix(GF(5), 100, 100, density=0.1)
sage: A.density()
961/10000

sage: A.randomize(density=0.1)
sage: A.density()
801/5000
rank()

Return the rank of this matrix.

EXAMPLES:

sage: A = random_matrix(GF(3), 100, 100)
sage: B = copy(A)
sage: A.rank()
99
sage: B == A
True

sage: A = random_matrix(GF(3), 100, 100, density=0.01)
sage: A.rank()
63

sage: A = matrix(GF(3), 100, 100)
sage: A.rank()
0

Rank is not implemented over the integers modulo a composite yet.:

sage: M = matrix(Integers(4), 2, [2,2,2,2])
sage: M.rank()
Traceback (most recent call last):
...
NotImplementedError: Echelon form not implemented over 'Ring of integers modulo 4'.
sage: A = random_matrix(GF(16007), 100, 100)
sage: B = copy(A)
sage: A.rank()
100
sage: B == A
True
sage: MS = A.parent()
sage: MS(1) == ~A*A
True
right_kernel_matrix(algorithm='linbox', basis='echelon')

Returns a matrix whose rows form a basis for the right kernel of self, where self is a matrix over a (small) finite field.

INPUT:

  • algorithm – (default: 'linbox') a parameter that is passed on to self.echelon_form, if computation of an echelon form is required; see that routine for allowable values

  • basis – (default: 'echelon') a keyword that describes the format of the basis returned, allowable values are:

    • 'echelon': the basis matrix is in echelon form

    • 'pivot': the basis matrix is such that the submatrix obtained

      by taking the columns that in self contain no pivots, is the identity matrix

    • 'computed': no work is done to transform the basis; in

      the current implementation the result is the negative of that returned by 'pivot'

OUTPUT:

A matrix X whose rows are a basis for the right kernel of self. This means that self * X.transpose() is a zero matrix.

The result is not cached, but the routine benefits when self is known to be in echelon form already.

EXAMPLES:

sage: M = matrix(GF(5),6,6,range(36))
sage: M.right_kernel_matrix(basis='computed')
[4 2 4 0 0 0]
[3 3 0 4 0 0]
[2 4 0 0 4 0]
[1 0 0 0 0 4]
sage: M.right_kernel_matrix(basis='pivot')
[1 3 1 0 0 0]
[2 2 0 1 0 0]
[3 1 0 0 1 0]
[4 0 0 0 0 1]
sage: M.right_kernel_matrix()
[1 0 0 0 0 4]
[0 1 0 0 1 3]
[0 0 1 0 2 2]
[0 0 0 1 3 1]
sage: M * M.right_kernel_matrix().transpose()
[0 0 0 0]
[0 0 0 0]
[0 0 0 0]
[0 0 0 0]
[0 0 0 0]
[0 0 0 0]
submatrix(row=0, col=0, nrows=- 1, ncols=- 1)

Return the matrix constructed from self using the specified range of rows and columns.

INPUT:

  • row, col – index of the starting row and column. Indices start at zero

  • nrows, ncols – (optional) number of rows and columns to take. If not provided, take all rows below and all columns to the right of the starting entry

See also

The functions matrix_from_rows(), matrix_from_columns(), and matrix_from_rows_and_columns() allow one to select arbitrary subsets of rows and/or columns.

EXAMPLES:

Take the \(3 \times 3\) submatrix starting from entry \((1,1)\) in a \(4 \times 4\) matrix:

sage: m = matrix(GF(17),4, [1..16])
sage: m.submatrix(1, 1)
[ 6  7  8]
[10 11 12]
[14 15 16]

Same thing, except take only two rows:

sage: m.submatrix(1, 1, 2)
[ 6  7  8]
[10 11 12]

And now take only one column:

sage: m.submatrix(1, 1, 2, 1)
[ 6]
[10]

You can take zero rows or columns if you want:

sage: m.submatrix(0, 0, 0)
[]
sage: parent(m.submatrix(0, 0, 0))
Full MatrixSpace of 0 by 4 dense matrices over Finite Field of size 17
transpose()

Return the transpose of self, without changing self.

EXAMPLES:

We create a matrix, compute its transpose, and note that the original matrix is not changed.

sage: M = MatrixSpace(GF(41),  2)
sage: A = M([1,2,3,4])
sage: B = A.transpose()
sage: B
[1 3]
[2 4]
sage: A
[1 2]
[3 4]

.T is a convenient shortcut for the transpose:

sage: A.T
[1 3]
[2 4]
sage: A.subdivide(None, 1); A
[1|2]
[3|4]
sage: A.transpose()
[1 3]
[---]
[2 4]