|
1 | | -import sys |
2 | 1 | import math |
3 | 2 | import operator |
4 | 3 | import pickle |
5 | | -import doctest |
6 | 4 | import platform |
| 5 | +import random |
7 | 6 |
|
8 | 7 | from flint.utils.flint_exceptions import DomainError, IncompatibleContextError |
9 | 8 |
|
@@ -1871,7 +1870,6 @@ def test_fmpz_mod_dlog(): |
1871 | 1870 | p = 2**e2 * 3**e3 + 1 |
1872 | 1871 | F = fmpz_mod_ctx(p) |
1873 | 1872 |
|
1874 | | - import random |
1875 | 1873 | for _ in range(10): |
1876 | 1874 | g = F(random.randint(0,p)) |
1877 | 1875 | for _ in range(10): |
@@ -4084,6 +4082,50 @@ def test_matrices_div(): |
4084 | 4082 | raises(lambda: None / M1234, TypeError) |
4085 | 4083 |
|
4086 | 4084 |
|
| 4085 | +def test_matrices_properties(): |
| 4086 | + for M, S, is_field in _all_matrices(): |
| 4087 | + # XXX: Add these properties to all matrix types |
| 4088 | + if M is not flint.fmpz_mat: |
| 4089 | + continue |
| 4090 | + |
| 4091 | + assert M([[1, 2], [3, 4]]).is_square() is True |
| 4092 | + assert M([[1, 2]]).is_square() is False |
| 4093 | + assert M(0, 2, []).is_square() is False |
| 4094 | + assert M(2, 0, []).is_square() is False |
| 4095 | + |
| 4096 | + assert M([[1, 2], [3, 4]]).is_empty() is False |
| 4097 | + assert M(0, 2, []).is_empty() is True |
| 4098 | + assert M(2, 0, []).is_empty() is True |
| 4099 | + |
| 4100 | + assert M([[1, 2], [3, 4]]).is_zero() is False |
| 4101 | + assert M([[0, 0], [0, 0]]).is_zero() is True |
| 4102 | + |
| 4103 | + assert M([[1, 0], [0, 1]]).is_one() is True |
| 4104 | + assert M([[1, 2], [3, 4]]).is_one() is False |
| 4105 | + assert M([[1, 0], [0, 1], [0, 0]]).is_one() is True # ?? |
| 4106 | + assert M(0, 0, []).is_one() is True |
| 4107 | + |
| 4108 | + assert M([[-1, 0], [0, -1]]).is_neg_one() is True |
| 4109 | + assert M([[-1, 0], [0, 1]]).is_neg_one() is False |
| 4110 | + assert M([[-1, -1], [-1, -1]]).is_neg_one() is False |
| 4111 | + assert M([[-1, 0], [0, -1], [0, 0]]).is_neg_one() is False # ?? |
| 4112 | + assert M(0, 0, []).is_neg_one() is True |
| 4113 | + |
| 4114 | + assert M([[2, 0], [0, 2]]).is_scalar() is True |
| 4115 | + assert M([[2, 0], [0, 3]]).is_scalar() is False |
| 4116 | + assert M([[1, 0], [0, 1], [0, 0]]).is_scalar() is False |
| 4117 | + |
| 4118 | + assert M([[1, 0], [0, 2]]).is_diagonal() is True |
| 4119 | + assert M([[1, 0], [1, 2]]).is_diagonal() is False |
| 4120 | + assert M([[1, 0], [0, 1], [0, 0]]).is_diagonal() is True |
| 4121 | + |
| 4122 | + assert M([[1, 1, 1], [0, 2, 2]]).is_upper_triangular() is True |
| 4123 | + assert M([[1, 1, 1], [1, 2, 2]]).is_upper_triangular() is False |
| 4124 | + |
| 4125 | + assert M([[1, 0, 0], [1, 2, 0]]).is_lower_triangular() is True |
| 4126 | + assert M([[1, 1, 0], [1, 2, 0]]).is_lower_triangular() is False |
| 4127 | + |
| 4128 | + |
4087 | 4129 | def test_matrices_inv(): |
4088 | 4130 | for M, S, is_field in _all_matrices(): |
4089 | 4131 | if is_field: |
@@ -4151,6 +4193,63 @@ def test_matrices_rref(): |
4151 | 4193 | assert Mr == Mr_rref |
4152 | 4194 |
|
4153 | 4195 |
|
| 4196 | +def test_matrices_fflu(): |
| 4197 | + |
| 4198 | + QQ = flint.fmpq_mat |
| 4199 | + shape = lambda A: (A.nrows(), A.ncols()) |
| 4200 | + |
| 4201 | + def is_permutation(P): |
| 4202 | + if not P.is_square(): |
| 4203 | + return False |
| 4204 | + n = P.nrows() |
| 4205 | + for i, row in enumerate(sorted(P.tolist(), reverse=True)): |
| 4206 | + if row != [int(i == j) for j in range(n)]: |
| 4207 | + return False |
| 4208 | + return True |
| 4209 | + |
| 4210 | + def check_fflu(A): |
| 4211 | + m, n = shape(A) |
| 4212 | + P, L, D, U = A.fflu() |
| 4213 | + Dq = QQ(D) |
| 4214 | + assert P*A == L*Dq.inv()*U |
| 4215 | + assert shape(P) == shape(L) == shape(D) == (m, m) |
| 4216 | + assert shape(A) == shape(U) == (m, n) |
| 4217 | + assert is_permutation(P) |
| 4218 | + assert L.is_lower_triangular() |
| 4219 | + assert U.is_upper_triangular() |
| 4220 | + assert D.is_diagonal() |
| 4221 | + |
| 4222 | + for M, S, is_field in _all_matrices(): |
| 4223 | + # XXX: Add this to more matrix types... |
| 4224 | + if M is not flint.fmpz_mat: |
| 4225 | + continue |
| 4226 | + |
| 4227 | + A = M([[1, 2], [3, 4]]) |
| 4228 | + P, L, D, U = A.fflu() |
| 4229 | + assert P == M([[1, 0], [0, 1]]) |
| 4230 | + assert L == M([[1, 0], [3, -2]]) |
| 4231 | + assert D == M([[1, 0], [0, -2]]) |
| 4232 | + assert U == M([[1, 2], [0, -2]]) |
| 4233 | + |
| 4234 | + check_fflu(M(0, 0, [])) |
| 4235 | + check_fflu(M(2, 0, [])) |
| 4236 | + check_fflu(M(0, 2, [])) |
| 4237 | + check_fflu(M([[1]])) |
| 4238 | + |
| 4239 | + check_fflu(M([[1, 2], [3, 4]])) |
| 4240 | + check_fflu(M([[1, 2, 3], [4, 5, 6]])) |
| 4241 | + check_fflu(M([[1, 2], [3, 4], [5, 6]])) |
| 4242 | + check_fflu(M([[1, 2], [2, 4]])) |
| 4243 | + check_fflu(M([[0, 0], [0, 0]])) |
| 4244 | + check_fflu(M([[1, 1, 1], [1, 1, 1]])) |
| 4245 | + |
| 4246 | + for _ in range(10): |
| 4247 | + for m in range(1, 5): |
| 4248 | + for n in range(1, 5): |
| 4249 | + A = M.randbits(m, n, 10) |
| 4250 | + check_fflu(A) |
| 4251 | + |
| 4252 | + |
4154 | 4253 | def test_matrices_solve(): |
4155 | 4254 | for M, S, is_field in _all_matrices(): |
4156 | 4255 | if is_field: |
@@ -4619,13 +4718,15 @@ def test_all_tests(): |
4619 | 4718 | test_matrices_mul, |
4620 | 4719 | test_matrices_pow, |
4621 | 4720 | test_matrices_div, |
| 4721 | + test_matrices_properties, |
4622 | 4722 | test_matrices_inv, |
4623 | 4723 | test_matrices_det, |
4624 | 4724 | test_matrices_charpoly, |
4625 | 4725 | test_matrices_minpoly, |
4626 | 4726 | test_matrices_rank, |
4627 | 4727 | test_matrices_rref, |
4628 | 4728 | test_matrices_solve, |
| 4729 | + test_matrices_fflu, |
4629 | 4730 |
|
4630 | 4731 | test_fq_default, |
4631 | 4732 | test_fq_default_poly, |
|
0 commit comments