@@ -3533,17 +3533,34 @@ def factor_sqf(p):
35333533
35343534def _all_matrices ():
35353535 """Return a list of matrix types and scalar types."""
3536+ # Prime modulus
35363537 R163 = flint .fmpz_mod_ctx (163 )
35373538 R127 = flint .fmpz_mod_ctx (2 ** 127 - 1 )
35383539 R255 = flint .fmpz_mod_ctx (2 ** 255 - 19 )
3540+
3541+ # Composite modulus
3542+ R164_C = flint .fmpz_mod_ctx (164 )
3543+ R127_C = flint .fmpz_mod_ctx (2 ** 127 )
3544+ R255_C = flint .fmpz_mod_ctx (2 ** 255 )
3545+
35393546 return [
3540- # (matrix_type, scalar_type, is_field)
3541- (flint .fmpz_mat , flint .fmpz , False ),
3542- (flint .fmpq_mat , flint .fmpq , True ),
3543- (lambda * a : flint .nmod_mat (* a , 17 ), lambda x : flint .nmod (x , 17 ), True ),
3544- (lambda * a : flint .fmpz_mod_mat (* a , R163 ), lambda x : flint .fmpz_mod (x , R163 ), True ),
3545- (lambda * a : flint .fmpz_mod_mat (* a , R127 ), lambda x : flint .fmpz_mod (x , R127 ), True ),
3546- (lambda * a : flint .fmpz_mod_mat (* a , R255 ), lambda x : flint .fmpz_mod (x , R255 ), True ),
3547+ # (matrix_type, scalar_type, is_field, characteristic)
3548+
3549+ # Z and Q
3550+ (flint .fmpz_mat , flint .fmpz , False , 0 ),
3551+ (flint .fmpq_mat , flint .fmpq , True , 0 ),
3552+
3553+ # Z/pZ
3554+ (lambda * a : flint .nmod_mat (* a , 17 ), lambda x : flint .nmod (x , 17 ), True , 17 ),
3555+ (lambda * a : flint .fmpz_mod_mat (* a , R163 ), lambda x : flint .fmpz_mod (x , R163 ), True , 163 ),
3556+ (lambda * a : flint .fmpz_mod_mat (* a , R127 ), lambda x : flint .fmpz_mod (x , R127 ), True , 2 ** 127 - 1 ),
3557+ (lambda * a : flint .fmpz_mod_mat (* a , R255 ), lambda x : flint .fmpz_mod (x , R255 ), True , 2 ** 255 - 19 ),
3558+
3559+ # Z/nZ (n composite)
3560+ (lambda * a : flint .nmod_mat (* a , 16 ), lambda x : flint .nmod (x , 16 ), False , 16 ),
3561+ (lambda * a : flint .fmpz_mod_mat (* a , R164_C ), lambda x : flint .fmpz_mod (x , R164_C ), False , 164 ),
3562+ (lambda * a : flint .fmpz_mod_mat (* a , R127_C ), lambda x : flint .fmpz_mod (x , R127_C ), False , 2 ** 127 ),
3563+ (lambda * a : flint .fmpz_mod_mat (* a , R255_C ), lambda x : flint .fmpz_mod (x , R255_C ), False , 2 ** 255 ),
35473564 ]
35483565
35493566
@@ -3664,7 +3681,7 @@ def _poly_type_from_matrix_type(mat_type):
36643681
36653682
36663683def test_matrices_eq ():
3667- for M , S , is_field in _all_matrices ():
3684+ for M , S , is_field , characteristic in _all_matrices ():
36683685 A1 = M ([[1 , 2 ], [3 , 4 ]])
36693686 A2 = M ([[1 , 2 ], [3 , 4 ]])
36703687 B = M ([[5 , 6 ], [7 , 8 ]])
@@ -3689,7 +3706,7 @@ def test_matrices_eq():
36893706
36903707
36913708def test_matrices_constructor ():
3692- for M , S , is_field in _all_matrices ():
3709+ for M , S , is_field , characteristic in _all_matrices ():
36933710 assert raises (lambda : M (), TypeError )
36943711
36953712 # Empty matrices
@@ -3761,7 +3778,7 @@ def _matrix_repr(M):
37613778
37623779
37633780def test_matrices_strrepr ():
3764- for M , S , is_field in _all_matrices ():
3781+ for M , S , is_field , characteristic in _all_matrices ():
37653782 A = M ([[1 , 2 ], [3 , 4 ]])
37663783 A_str = "[1, 2]\n [3, 4]"
37673784 A_repr = _matrix_repr (A )
@@ -3784,7 +3801,7 @@ def test_matrices_strrepr():
37843801
37853802
37863803def test_matrices_getitem ():
3787- for M , S , is_field in _all_matrices ():
3804+ for M , S , is_field , characteristic in _all_matrices ():
37883805 M1234 = M ([[1 , 2 ], [3 , 4 ]])
37893806 assert M1234 [0 , 0 ] == S (1 )
37903807 assert M1234 [0 , 1 ] == S (2 )
@@ -3800,7 +3817,7 @@ def test_matrices_getitem():
38003817
38013818
38023819def test_matrices_setitem ():
3803- for M , S , is_field in _all_matrices ():
3820+ for M , S , is_field , characteristic in _all_matrices ():
38043821 M1234 = M ([[1 , 2 ], [3 , 4 ]])
38053822
38063823 assert M1234 [0 , 0 ] == S (1 )
@@ -3826,7 +3843,7 @@ def setbad(obj, key, val):
38263843
38273844
38283845def test_matrices_bool ():
3829- for M , S , is_field in _all_matrices ():
3846+ for M , S , is_field , characteristic in _all_matrices ():
38303847 assert bool (M ([])) is False
38313848 assert bool (M ([[0 ]])) is False
38323849 assert bool (M ([[1 ]])) is True
@@ -3837,14 +3854,14 @@ def test_matrices_bool():
38373854
38383855
38393856def test_matrices_pos_neg ():
3840- for M , S , is_field in _all_matrices ():
3857+ for M , S , is_field , characteristic in _all_matrices ():
38413858 M1234 = M ([[1 , 2 ], [3 , 4 ]])
38423859 assert + M1234 == M1234
38433860 assert - M1234 == M ([[- 1 , - 2 ], [- 3 , - 4 ]])
38443861
38453862
38463863def test_matrices_add ():
3847- for M , S , is_field in _all_matrices ():
3864+ for M , S , is_field , characteristic in _all_matrices ():
38483865 M1234 = M ([[1 , 2 ], [3 , 4 ]])
38493866 M5678 = M ([[5 , 6 ], [7 , 8 ]])
38503867 assert M1234 + M5678 == M ([[6 , 8 ], [10 , 12 ]])
@@ -3864,7 +3881,7 @@ def test_matrices_add():
38643881
38653882
38663883def test_matrices_sub ():
3867- for M , S , is_field in _all_matrices ():
3884+ for M , S , is_field , characteristic in _all_matrices ():
38683885 M1234 = M ([[1 , 2 ], [3 , 4 ]])
38693886 M5678 = M ([[5 , 6 ], [7 , 8 ]])
38703887 assert M1234 - M5678 == M ([[- 4 , - 4 ], [- 4 , - 4 ]])
@@ -3884,7 +3901,7 @@ def test_matrices_sub():
38843901
38853902
38863903def test_matrices_mul ():
3887- for M , S , is_field in _all_matrices ():
3904+ for M , S , is_field , characteristic in _all_matrices ():
38883905 M1234 = M ([[1 , 2 ], [3 , 4 ]])
38893906 M5678 = M ([[5 , 6 ], [7 , 8 ]])
38903907 assert M1234 * M5678 == M ([[19 , 22 ], [43 , 50 ]])
@@ -3910,18 +3927,24 @@ def test_matrices_mul():
39103927
39113928
39123929def test_matrices_pow ():
3913- for M , S , is_field in _all_matrices ():
3930+ for M , S , is_field , characteristic in _all_matrices ():
39143931 M1234 = M ([[1 , 2 ], [3 , 4 ]])
3932+
39153933 assert M1234 ** 0 == M ([[1 , 0 ], [0 , 1 ]])
39163934 assert M1234 ** 1 == M1234
39173935 assert M1234 ** 2 == M ([[7 , 10 ], [15 , 22 ]])
39183936 assert M1234 ** 3 == M ([[37 , 54 ], [81 , 118 ]])
3937+
39193938 if is_field :
39203939 assert M1234 ** - 1 == M ([[- 4 , 2 ], [3 , - 1 ]]) / 2
39213940 assert M1234 ** - 2 == M ([[22 , - 10 ], [- 15 , 7 ]]) / 4
39223941 assert M1234 ** - 3 == M ([[- 118 , 54 ], [81 , - 37 ]]) / 8
39233942 Ms = M ([[1 , 2 ], [3 , 6 ]])
39243943 assert raises (lambda : Ms ** - 1 , ZeroDivisionError )
3944+ else :
3945+ # XXX: Allow unimodular matrices?
3946+ assert raises (lambda : M1234 ** - 1 , DomainError )
3947+
39253948 Mr = M ([[1 , 2 , 3 ], [4 , 5 , 6 ]])
39263949 assert raises (lambda : Mr ** 0 , ValueError )
39273950 assert raises (lambda : Mr ** 1 , ValueError )
@@ -3931,31 +3954,49 @@ def test_matrices_pow():
39313954
39323955
39333956def test_matrices_div ():
3934- for M , S , is_field in _all_matrices ():
3957+
3958+ for M , S , is_field , characteristic in _all_matrices ():
39353959 M1234 = M ([[1 , 2 ], [3 , 4 ]])
3960+
39363961 if is_field :
39373962 assert M1234 / 2 == M ([[S (1 )/ 2 , S (1 )], [S (3 )/ 2 , 2 ]])
39383963 assert M1234 / S (2 ) == M ([[S (1 )/ 2 , S (1 )], [S (3 )/ 2 , 2 ]])
39393964 assert raises (lambda : M1234 / 0 , ZeroDivisionError )
39403965 assert raises (lambda : M1234 / S (0 ), ZeroDivisionError )
3966+ else :
3967+ assert raises (lambda : M1234 / 2 , DomainError )
3968+ if characteristic == 0 :
3969+ assert (2 * M1234 ) / 2 == M1234
3970+ else :
3971+ assert raises (lambda : (2 * M1234 ) / 2 , DomainError )
3972+
39413973 raises (lambda : M1234 / None , TypeError )
39423974 raises (lambda : None / M1234 , TypeError )
39433975
39443976
39453977def test_matrices_inv ():
3946- for M , S , is_field in _all_matrices ():
3947- if is_field :
3948- M1234 = M ([[1 , 2 ], [3 , 4 ]])
3978+
3979+ for M , S , is_field , characteristic in _all_matrices ():
3980+
3981+ M1234 = M ([[1 , 2 ], [3 , 4 ]])
3982+ M1236 = M ([[1 , 2 ], [3 , 6 ]])
3983+ Mr = M ([[1 , 2 , 3 ], [4 , 5 , 6 ]])
3984+
3985+ if characteristic > 0 and not is_field :
3986+ assert raises (lambda : M ([[1 , 2 ], [3 , 4 ]]).inv (), DomainError )
3987+ elif is_field :
39493988 assert M1234 .inv () == M ([[- 2 , 1 ], [S (3 )/ 2 , - S (1 )/ 2 ]])
3950- M1236 = M ([[1 , 2 ], [3 , 6 ]])
39513989 assert raises (lambda : M1236 .inv (), ZeroDivisionError )
3952- Mr = M ([[1 , 2 , 3 ], [4 , 5 , 6 ]])
39533990 assert raises (lambda : Mr .inv (), ValueError )
3954- # XXX: Test non-field matrices. unimodular?
3991+ else :
3992+ # assert M1234.inv() == (M([[-4, 2], [3, -1]]), 2)
3993+ # assert M1236.inv() == (M([[-6, 2], [3, -1]]), 3)
3994+ # XXX: fmpz_mat.inv() return fmpq_mat...
3995+ assert M1234 .inv () * M1234 .det () == M ([[4 , - 2 ], [- 3 , 1 ]])
39553996
39563997
39573998def test_matrices_det ():
3958- for M , S , is_field in _all_matrices ():
3999+ for M , S , is_field , characteristic in _all_matrices ():
39594000 M1234 = M ([[1 , 2 ], [3 , 4 ]])
39604001 assert M1234 .det () == S (- 2 )
39614002 M9 = M ([[1 , 2 , 3 ], [4 , 5 , 6 ], [7 , 8 , 10 ]])
@@ -3965,7 +4006,7 @@ def test_matrices_det():
39654006
39664007
39674008def test_matrices_charpoly ():
3968- for M , S , is_field in _all_matrices ():
4009+ for M , S , is_field , characteristic in _all_matrices ():
39694010 P = _poly_type_from_matrix_type (M )
39704011 M1234 = M ([[1 , 2 ], [3 , 4 ]])
39714012 assert M1234 .charpoly () == P ([- 2 , - 5 , 1 ])
@@ -3976,18 +4017,21 @@ def test_matrices_charpoly():
39764017
39774018
39784019def test_matrices_minpoly ():
3979- for M , S , is_field in _all_matrices ():
4020+ for M , S , is_field , characteristic in _all_matrices ():
4021+ if characteristic > 0 and not is_field :
4022+ assert raises (lambda : M ([[1 , 2 ], [3 , 4 ]]).minpoly (), DomainError )
4023+ continue
39804024 P = _poly_type_from_matrix_type (M )
3981- M1234 = M ([[1 , 2 ], [3 , 4 ]])
3982- assert M1234 .minpoly () == P ([- 2 , - 5 , 1 ])
3983- M9 = M ([[2 , 1 , 0 ], [0 , 2 , 0 ], [0 , 0 , 2 ]])
3984- assert M9 .minpoly () == P ([4 , - 4 , 1 ])
3985- Mr = M ([[1 , 2 , 3 ], [4 , 5 , 6 ]])
3986- assert raises (lambda : Mr .minpoly (), ValueError )
4025+ assert M ([[1 , 2 ], [3 , 4 ]]).minpoly () == P ([- 2 , - 5 , 1 ])
4026+ assert M ([[2 , 1 , 0 ], [0 , 2 , 0 ], [0 , 0 , 2 ]]).minpoly () == P ([4 , - 4 , 1 ])
4027+ assert raises (lambda : M ([[1 , 2 , 3 ], [4 , 5 , 6 ]]).minpoly (), ValueError )
39874028
39884029
39894030def test_matrices_rank ():
3990- for M , S , is_field in _all_matrices ():
4031+ for M , S , is_field , characteristic in _all_matrices ():
4032+ if characteristic > 0 and not is_field :
4033+ assert raises (lambda : M ([[1 , 2 ], [3 , 4 ]]).rank (), DomainError )
4034+ continue
39914035 M1234 = M ([[1 , 2 ], [3 , 4 ]])
39924036 assert M1234 .rank () == 2
39934037 Mr = M ([[1 , 2 , 3 ], [4 , 5 , 6 ]])
@@ -3999,37 +4043,57 @@ def test_matrices_rank():
39994043
40004044
40014045def test_matrices_rref ():
4002- for M , S , is_field in _all_matrices ():
4003- if is_field :
4004- Mr = M ([[1 , 2 , 3 ], [4 , 5 , 6 ]])
4005- Mr_rref = M ([[1 , 0 , - 1 ], [0 , 1 , 2 ]])
4046+ for M , S , is_field , characteristic in _all_matrices ():
4047+
4048+ Mr = M ([[1 , 2 , 3 ], [4 , 5 , 6 ]])
4049+ Mr_rref = M ([[1 , 0 , - 1 ], [0 , 1 , 2 ]])
4050+
4051+ if characteristic > 0 and not is_field :
4052+ # Z/nZ (n composite) raises
4053+ assert raises (lambda : Mr .rref (), DomainError )
4054+ elif is_field :
4055+ # Q, Z/pZ and GF(p^d) return usual RREF
40064056 assert Mr .rref () == (Mr_rref , 2 )
40074057 assert Mr == M ([[1 , 2 , 3 ], [4 , 5 , 6 ]])
40084058 assert Mr .rref (inplace = True ) == (Mr_rref , 2 )
40094059 assert Mr == Mr_rref
4060+ else :
4061+ # Z returns RREF with divisor -3
4062+ d = - 3
4063+ assert Mr .rref () == (d * Mr_rref , d , 2 )
4064+ assert Mr == M ([[1 , 2 , 3 ], [4 , 5 , 6 ]])
4065+ assert Mr .rref (inplace = True ) == (d * Mr_rref , d , 2 )
4066+ assert Mr == d * Mr_rref
40104067
40114068
40124069def test_matrices_solve ():
4013- for M , S , is_field in _all_matrices ():
4014- if is_field :
4015- A = M ([[1 , 2 ], [3 , 4 ]])
4016- x = M ([[1 ], [2 ]])
4017- b = M ([[5 ], [11 ]])
4018- assert A * x == b
4070+ for M , S , is_field , characteristic in _all_matrices ():
4071+
4072+ A = M ([[1 , 2 ], [3 , 4 ]])
4073+ x = M ([[1 ], [2 ]])
4074+ b = M ([[5 ], [11 ]])
4075+ assert A * x == b
4076+
4077+ A2 = M ([[1 , 2 ], [2 , 4 ]])
4078+
4079+ if characteristic > 0 and not is_field :
4080+ assert raises (lambda : A .solve (b ), DomainError )
4081+ assert raises (lambda : A2 .solve (b ), DomainError )
4082+ else :
40194083 assert A .solve (b ) == x
4020- A22 = M ([[ 1 , 2 ], [ 3 , 4 ]] )
4021- A23 = M ([[ 1 , 2 , 3 ], [ 4 , 5 , 6 ]])
4022- b2 = M ([[5 ], [11 ]])
4023- b3 = M ([[5 ], [ 11 ], [17 ]])
4024- assert raises ( lambda : A22 . solve ( b3 ), ValueError )
4025- assert raises ( lambda : A23 . solve ( b2 ), ValueError )
4026- assert raises (lambda : A .solve (None ), TypeError )
4027- A = M ([[ 1 , 2 ], [ 2 , 4 ]] )
4028- assert raises (lambda : A .solve (b ), ZeroDivisionError )
4084+ assert raises ( lambda : A2 . solve ( b ), ZeroDivisionError )
4085+
4086+ A22 = M ([[1 , 2 ], [3 , 4 ]])
4087+ A23 = M ([[1 , 2 , 3 ], [4 , 5 , 6 ]])
4088+ b2 = M ([[ 5 ], [ 11 ]] )
4089+ b3 = M ([[ 5 ], [ 11 ], [ 17 ]] )
4090+ assert raises (lambda : A22 .solve (b3 ), ValueError )
4091+ assert raises ( lambda : A23 . solve ( b2 ), ValueError )
4092+ assert raises (lambda : A .solve (None ), TypeError )
40294093
40304094
40314095def test_matrices_transpose ():
4032- for M , S , is_field in _all_matrices ():
4096+ for M , S , is_field , characteristic in _all_matrices ():
40334097 M1234 = M ([[1 , 2 , 3 ], [4 , 5 , 6 ]])
40344098 assert M1234 .transpose () == M ([[1 , 4 ], [2 , 5 ], [3 , 6 ]])
40354099
0 commit comments