test_sdm.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. """
  2. Tests for the basic functionality of the SDM class.
  3. """
  4. from itertools import product
  5. from sympy.core.singleton import S
  6. from sympy.external.gmpy import HAS_GMPY
  7. from sympy.testing.pytest import raises
  8. from sympy.polys.domains import QQ, ZZ, EXRAW
  9. from sympy.polys.matrices.sdm import SDM
  10. from sympy.polys.matrices.ddm import DDM
  11. from sympy.polys.matrices.exceptions import (DMBadInputError, DMDomainError,
  12. DMShapeError)
  13. def test_SDM():
  14. A = SDM({0:{0:ZZ(1)}}, (2, 2), ZZ)
  15. assert A.domain == ZZ
  16. assert A.shape == (2, 2)
  17. assert dict(A) == {0:{0:ZZ(1)}}
  18. raises(DMBadInputError, lambda: SDM({5:{1:ZZ(0)}}, (2, 2), ZZ))
  19. raises(DMBadInputError, lambda: SDM({0:{5:ZZ(0)}}, (2, 2), ZZ))
  20. def test_DDM_str():
  21. sdm = SDM({0:{0:ZZ(1)}, 1:{1:ZZ(1)}}, (2, 2), ZZ)
  22. assert str(sdm) == '{0: {0: 1}, 1: {1: 1}}'
  23. if HAS_GMPY: # pragma: no cover
  24. assert repr(sdm) == 'SDM({0: {0: mpz(1)}, 1: {1: mpz(1)}}, (2, 2), ZZ)'
  25. else: # pragma: no cover
  26. assert repr(sdm) == 'SDM({0: {0: 1}, 1: {1: 1}}, (2, 2), ZZ)'
  27. def test_SDM_new():
  28. A = SDM({0:{0:ZZ(1)}}, (2, 2), ZZ)
  29. B = A.new({}, (2, 2), ZZ)
  30. assert B == SDM({}, (2, 2), ZZ)
  31. def test_SDM_copy():
  32. A = SDM({0:{0:ZZ(1)}}, (2, 2), ZZ)
  33. B = A.copy()
  34. assert A == B
  35. A[0][0] = ZZ(2)
  36. assert A != B
  37. def test_SDM_from_list():
  38. A = SDM.from_list([[ZZ(0), ZZ(1)], [ZZ(1), ZZ(0)]], (2, 2), ZZ)
  39. assert A == SDM({0:{1:ZZ(1)}, 1:{0:ZZ(1)}}, (2, 2), ZZ)
  40. raises(DMBadInputError, lambda: SDM.from_list([[ZZ(0)], [ZZ(0), ZZ(1)]], (2, 2), ZZ))
  41. raises(DMBadInputError, lambda: SDM.from_list([[ZZ(0), ZZ(1)]], (2, 2), ZZ))
  42. def test_SDM_to_list():
  43. A = SDM({0:{1: ZZ(1)}}, (2, 2), ZZ)
  44. assert A.to_list() == [[ZZ(0), ZZ(1)], [ZZ(0), ZZ(0)]]
  45. A = SDM({}, (0, 2), ZZ)
  46. assert A.to_list() == []
  47. A = SDM({}, (2, 0), ZZ)
  48. assert A.to_list() == [[], []]
  49. def test_SDM_to_list_flat():
  50. A = SDM({0:{1: ZZ(1)}}, (2, 2), ZZ)
  51. assert A.to_list_flat() == [ZZ(0), ZZ(1), ZZ(0), ZZ(0)]
  52. def test_SDM_to_dok():
  53. A = SDM({0:{1: ZZ(1)}}, (2, 2), ZZ)
  54. assert A.to_dok() == {(0, 1): ZZ(1)}
  55. def test_SDM_from_ddm():
  56. A = DDM([[ZZ(1), ZZ(0)], [ZZ(1), ZZ(0)]], (2, 2), ZZ)
  57. B = SDM.from_ddm(A)
  58. assert B.domain == ZZ
  59. assert B.shape == (2, 2)
  60. assert dict(B) == {0:{0:ZZ(1)}, 1:{0:ZZ(1)}}
  61. def test_SDM_to_ddm():
  62. A = SDM({0:{1: ZZ(1)}}, (2, 2), ZZ)
  63. B = DDM([[ZZ(0), ZZ(1)], [ZZ(0), ZZ(0)]], (2, 2), ZZ)
  64. assert A.to_ddm() == B
  65. def test_SDM_to_sdm():
  66. A = SDM({0:{1: ZZ(1)}}, (2, 2), ZZ)
  67. assert A.to_sdm() == A
  68. def test_SDM_getitem():
  69. A = SDM({0:{1:ZZ(1)}}, (2, 2), ZZ)
  70. assert A.getitem(0, 0) == ZZ.zero
  71. assert A.getitem(0, 1) == ZZ.one
  72. assert A.getitem(1, 0) == ZZ.zero
  73. assert A.getitem(-2, -2) == ZZ.zero
  74. assert A.getitem(-2, -1) == ZZ.one
  75. assert A.getitem(-1, -2) == ZZ.zero
  76. raises(IndexError, lambda: A.getitem(2, 0))
  77. raises(IndexError, lambda: A.getitem(0, 2))
  78. def test_SDM_setitem():
  79. A = SDM({0:{1:ZZ(1)}}, (2, 2), ZZ)
  80. A.setitem(0, 0, ZZ(1))
  81. assert A == SDM({0:{0:ZZ(1), 1:ZZ(1)}}, (2, 2), ZZ)
  82. A.setitem(1, 0, ZZ(1))
  83. assert A == SDM({0:{0:ZZ(1), 1:ZZ(1)}, 1:{0:ZZ(1)}}, (2, 2), ZZ)
  84. A.setitem(1, 0, ZZ(0))
  85. assert A == SDM({0:{0:ZZ(1), 1:ZZ(1)}}, (2, 2), ZZ)
  86. # Repeat the above test so that this time the row is empty
  87. A.setitem(1, 0, ZZ(0))
  88. assert A == SDM({0:{0:ZZ(1), 1:ZZ(1)}}, (2, 2), ZZ)
  89. A.setitem(0, 0, ZZ(0))
  90. assert A == SDM({0:{1:ZZ(1)}}, (2, 2), ZZ)
  91. # This time the row is there but column is empty
  92. A.setitem(0, 0, ZZ(0))
  93. assert A == SDM({0:{1:ZZ(1)}}, (2, 2), ZZ)
  94. raises(IndexError, lambda: A.setitem(2, 0, ZZ(1)))
  95. raises(IndexError, lambda: A.setitem(0, 2, ZZ(1)))
  96. def test_SDM_extract_slice():
  97. A = SDM({0:{0:ZZ(1), 1:ZZ(2)}, 1:{0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ)
  98. B = A.extract_slice(slice(1, 2), slice(1, 2))
  99. assert B == SDM({0:{0:ZZ(4)}}, (1, 1), ZZ)
  100. def test_SDM_extract():
  101. A = SDM({0:{0:ZZ(1), 1:ZZ(2)}, 1:{0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ)
  102. B = A.extract([1], [1])
  103. assert B == SDM({0:{0:ZZ(4)}}, (1, 1), ZZ)
  104. B = A.extract([1, 0], [1, 0])
  105. assert B == SDM({0:{0:ZZ(4), 1:ZZ(3)}, 1:{0:ZZ(2), 1:ZZ(1)}}, (2, 2), ZZ)
  106. B = A.extract([1, 1], [1, 1])
  107. assert B == SDM({0:{0:ZZ(4), 1:ZZ(4)}, 1:{0:ZZ(4), 1:ZZ(4)}}, (2, 2), ZZ)
  108. B = A.extract([-1], [-1])
  109. assert B == SDM({0:{0:ZZ(4)}}, (1, 1), ZZ)
  110. A = SDM({}, (2, 2), ZZ)
  111. B = A.extract([0, 1, 0], [0, 0])
  112. assert B == SDM({}, (3, 2), ZZ)
  113. A = SDM({0:{0:ZZ(1), 1:ZZ(2)}, 1:{0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ)
  114. assert A.extract([], []) == SDM.zeros((0, 0), ZZ)
  115. assert A.extract([1], []) == SDM.zeros((1, 0), ZZ)
  116. assert A.extract([], [1]) == SDM.zeros((0, 1), ZZ)
  117. raises(IndexError, lambda: A.extract([2], [0]))
  118. raises(IndexError, lambda: A.extract([0], [2]))
  119. raises(IndexError, lambda: A.extract([-3], [0]))
  120. raises(IndexError, lambda: A.extract([0], [-3]))
  121. def test_SDM_zeros():
  122. A = SDM.zeros((2, 2), ZZ)
  123. assert A.domain == ZZ
  124. assert A.shape == (2, 2)
  125. assert dict(A) == {}
  126. def test_SDM_ones():
  127. A = SDM.ones((1, 2), QQ)
  128. assert A.domain == QQ
  129. assert A.shape == (1, 2)
  130. assert dict(A) == {0:{0:QQ(1), 1:QQ(1)}}
  131. def test_SDM_eye():
  132. A = SDM.eye((2, 2), ZZ)
  133. assert A.domain == ZZ
  134. assert A.shape == (2, 2)
  135. assert dict(A) == {0:{0:ZZ(1)}, 1:{1:ZZ(1)}}
  136. def test_SDM_diag():
  137. A = SDM.diag([ZZ(1), ZZ(2)], ZZ, (2, 3))
  138. assert A == SDM({0:{0:ZZ(1)}, 1:{1:ZZ(2)}}, (2, 3), ZZ)
  139. def test_SDM_transpose():
  140. A = SDM({0:{0:ZZ(1), 1:ZZ(2)}, 1:{0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ)
  141. B = SDM({0:{0:ZZ(1), 1:ZZ(3)}, 1:{0:ZZ(2), 1:ZZ(4)}}, (2, 2), ZZ)
  142. assert A.transpose() == B
  143. A = SDM({0:{1:ZZ(2)}}, (2, 2), ZZ)
  144. B = SDM({1:{0:ZZ(2)}}, (2, 2), ZZ)
  145. assert A.transpose() == B
  146. A = SDM({0:{1:ZZ(2)}}, (1, 2), ZZ)
  147. B = SDM({1:{0:ZZ(2)}}, (2, 1), ZZ)
  148. assert A.transpose() == B
  149. def test_SDM_mul():
  150. A = SDM({0:{0:ZZ(2)}}, (2, 2), ZZ)
  151. B = SDM({0:{0:ZZ(4)}}, (2, 2), ZZ)
  152. assert A*ZZ(2) == B
  153. assert ZZ(2)*A == B
  154. raises(TypeError, lambda: A*QQ(1, 2))
  155. raises(TypeError, lambda: QQ(1, 2)*A)
  156. def test_SDM_mul_elementwise():
  157. A = SDM({0:{0:ZZ(2), 1:ZZ(2)}}, (2, 2), ZZ)
  158. B = SDM({0:{0:ZZ(4)}, 1:{0:ZZ(3)}}, (2, 2), ZZ)
  159. C = SDM({0:{0:ZZ(8)}}, (2, 2), ZZ)
  160. assert A.mul_elementwise(B) == C
  161. assert B.mul_elementwise(A) == C
  162. Aq = A.convert_to(QQ)
  163. A1 = SDM({0:{0:ZZ(1)}}, (1, 1), ZZ)
  164. raises(DMDomainError, lambda: Aq.mul_elementwise(B))
  165. raises(DMShapeError, lambda: A1.mul_elementwise(B))
  166. def test_SDM_matmul():
  167. A = SDM({0:{0:ZZ(2)}}, (2, 2), ZZ)
  168. B = SDM({0:{0:ZZ(4)}}, (2, 2), ZZ)
  169. assert A.matmul(A) == A*A == B
  170. C = SDM({0:{0:ZZ(2)}}, (2, 2), QQ)
  171. raises(DMDomainError, lambda: A.matmul(C))
  172. A = SDM({0:{0:ZZ(1), 1:ZZ(2)}, 1:{0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ)
  173. B = SDM({0:{0:ZZ(7), 1:ZZ(10)}, 1:{0:ZZ(15), 1:ZZ(22)}}, (2, 2), ZZ)
  174. assert A.matmul(A) == A*A == B
  175. A22 = SDM({0:{0:ZZ(4)}}, (2, 2), ZZ)
  176. A32 = SDM({0:{0:ZZ(2)}}, (3, 2), ZZ)
  177. A23 = SDM({0:{0:ZZ(4)}}, (2, 3), ZZ)
  178. A33 = SDM({0:{0:ZZ(8)}}, (3, 3), ZZ)
  179. A22 = SDM({0:{0:ZZ(8)}}, (2, 2), ZZ)
  180. assert A32.matmul(A23) == A33
  181. assert A23.matmul(A32) == A22
  182. # XXX: @ not supported by SDM...
  183. #assert A32.matmul(A23) == A32 @ A23 == A33
  184. #assert A23.matmul(A32) == A23 @ A32 == A22
  185. #raises(DMShapeError, lambda: A23 @ A22)
  186. raises(DMShapeError, lambda: A23.matmul(A22))
  187. A = SDM({0: {0: ZZ(-1), 1: ZZ(1)}}, (1, 2), ZZ)
  188. B = SDM({0: {0: ZZ(-1)}, 1: {0: ZZ(-1)}}, (2, 1), ZZ)
  189. assert A.matmul(B) == A*B == SDM({}, (1, 1), ZZ)
  190. def test_matmul_exraw():
  191. def dm(d):
  192. result = {}
  193. for i, row in d.items():
  194. row = {j:val for j, val in row.items() if val}
  195. if row:
  196. result[i] = row
  197. return SDM(result, (2, 2), EXRAW)
  198. values = [S.NegativeInfinity, S.NegativeOne, S.Zero, S.One, S.Infinity]
  199. for a, b, c, d in product(*[values]*4):
  200. Ad = dm({0: {0:a, 1:b}, 1: {0:c, 1:d}})
  201. Ad2 = dm({0: {0:a*a + b*c, 1:a*b + b*d}, 1:{0:c*a + d*c, 1: c*b + d*d}})
  202. assert Ad * Ad == Ad2
  203. def test_SDM_add():
  204. A = SDM({0:{1:ZZ(1)}, 1:{0:ZZ(2), 1:ZZ(3)}}, (2, 2), ZZ)
  205. B = SDM({0:{0:ZZ(1)}, 1:{0:ZZ(-2), 1:ZZ(3)}}, (2, 2), ZZ)
  206. C = SDM({0:{0:ZZ(1), 1:ZZ(1)}, 1:{1:ZZ(6)}}, (2, 2), ZZ)
  207. assert A.add(B) == B.add(A) == A + B == B + A == C
  208. A = SDM({0:{1:ZZ(1)}}, (2, 2), ZZ)
  209. B = SDM({0:{0:ZZ(1)}, 1:{0:ZZ(-2), 1:ZZ(3)}}, (2, 2), ZZ)
  210. C = SDM({0:{0:ZZ(1), 1:ZZ(1)}, 1:{0:ZZ(-2), 1:ZZ(3)}}, (2, 2), ZZ)
  211. assert A.add(B) == B.add(A) == A + B == B + A == C
  212. raises(TypeError, lambda: A + [])
  213. def test_SDM_sub():
  214. A = SDM({0:{1:ZZ(1)}, 1:{0:ZZ(2), 1:ZZ(3)}}, (2, 2), ZZ)
  215. B = SDM({0:{0:ZZ(1)}, 1:{0:ZZ(-2), 1:ZZ(3)}}, (2, 2), ZZ)
  216. C = SDM({0:{0:ZZ(-1), 1:ZZ(1)}, 1:{0:ZZ(4)}}, (2, 2), ZZ)
  217. assert A.sub(B) == A - B == C
  218. raises(TypeError, lambda: A - [])
  219. def test_SDM_neg():
  220. A = SDM({0:{1:ZZ(1)}, 1:{0:ZZ(2), 1:ZZ(3)}}, (2, 2), ZZ)
  221. B = SDM({0:{1:ZZ(-1)}, 1:{0:ZZ(-2), 1:ZZ(-3)}}, (2, 2), ZZ)
  222. assert A.neg() == -A == B
  223. def test_SDM_convert_to():
  224. A = SDM({0:{1:ZZ(1)}, 1:{0:ZZ(2), 1:ZZ(3)}}, (2, 2), ZZ)
  225. B = SDM({0:{1:QQ(1)}, 1:{0:QQ(2), 1:QQ(3)}}, (2, 2), QQ)
  226. C = A.convert_to(QQ)
  227. assert C == B
  228. assert C.domain == QQ
  229. D = A.convert_to(ZZ)
  230. assert D == A
  231. assert D.domain == ZZ
  232. def test_SDM_hstack():
  233. A = SDM({0:{1:ZZ(1)}}, (2, 2), ZZ)
  234. B = SDM({1:{1:ZZ(1)}}, (2, 2), ZZ)
  235. AA = SDM({0:{1:ZZ(1), 3:ZZ(1)}}, (2, 4), ZZ)
  236. AB = SDM({0:{1:ZZ(1)}, 1:{3:ZZ(1)}}, (2, 4), ZZ)
  237. assert SDM.hstack(A) == A
  238. assert SDM.hstack(A, A) == AA
  239. assert SDM.hstack(A, B) == AB
  240. def test_SDM_vstack():
  241. A = SDM({0:{1:ZZ(1)}}, (2, 2), ZZ)
  242. B = SDM({1:{1:ZZ(1)}}, (2, 2), ZZ)
  243. AA = SDM({0:{1:ZZ(1)}, 2:{1:ZZ(1)}}, (4, 2), ZZ)
  244. AB = SDM({0:{1:ZZ(1)}, 3:{1:ZZ(1)}}, (4, 2), ZZ)
  245. assert SDM.vstack(A) == A
  246. assert SDM.vstack(A, A) == AA
  247. assert SDM.vstack(A, B) == AB
  248. def test_SDM_applyfunc():
  249. A = SDM({0:{1:ZZ(1)}}, (2, 2), ZZ)
  250. B = SDM({0:{1:ZZ(2)}}, (2, 2), ZZ)
  251. assert A.applyfunc(lambda x: 2*x, ZZ) == B
  252. def test_SDM_inv():
  253. A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ)
  254. B = SDM({0:{0:QQ(-2), 1:QQ(1)}, 1:{0:QQ(3, 2), 1:QQ(-1, 2)}}, (2, 2), QQ)
  255. assert A.inv() == B
  256. def test_SDM_det():
  257. A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ)
  258. assert A.det() == QQ(-2)
  259. def test_SDM_lu():
  260. A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ)
  261. L = SDM({0:{0:QQ(1)}, 1:{0:QQ(3), 1:QQ(1)}}, (2, 2), QQ)
  262. #U = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(-2)}}, (2, 2), QQ)
  263. #swaps = []
  264. # This doesn't quite work. U has some nonzero elements in the lower part.
  265. #assert A.lu() == (L, U, swaps)
  266. assert A.lu()[0] == L
  267. def test_SDM_lu_solve():
  268. A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ)
  269. b = SDM({0:{0:QQ(1)}, 1:{0:QQ(2)}}, (2, 1), QQ)
  270. x = SDM({1:{0:QQ(1, 2)}}, (2, 1), QQ)
  271. assert A.matmul(x) == b
  272. assert A.lu_solve(b) == x
  273. def test_SDM_charpoly():
  274. A = SDM({0:{0:ZZ(1), 1:ZZ(2)}, 1:{0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ)
  275. assert A.charpoly() == [ZZ(1), ZZ(-5), ZZ(-2)]
  276. def test_SDM_nullspace():
  277. A = SDM({0:{0:QQ(1), 1:QQ(1)}}, (2, 2), QQ)
  278. assert A.nullspace()[0] == SDM({0:{0:QQ(-1), 1:QQ(1)}}, (1, 2), QQ)
  279. def test_SDM_rref():
  280. eye2 = SDM({0:{0:QQ(1)}, 1:{1:QQ(1)}}, (2, 2), QQ)
  281. A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ)
  282. assert A.rref() == (eye2, [0, 1])
  283. A = SDM({0:{0:QQ(1)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ)
  284. assert A.rref() == (eye2, [0, 1])
  285. A = SDM({0:{1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ)
  286. assert A.rref() == (eye2, [0, 1])
  287. A = SDM({0:{0:QQ(1), 1:QQ(2), 2:QQ(3)},
  288. 1:{0:QQ(4), 1:QQ(5), 2:QQ(6)},
  289. 2:{0:QQ(7), 1:QQ(8), 2:QQ(9)} }, (3, 3), QQ)
  290. Arref = SDM({0:{0:QQ(1), 2:QQ(-1)}, 1:{1:QQ(1), 2:QQ(2)}}, (3, 3), QQ)
  291. assert A.rref() == (Arref, [0, 1])
  292. A = SDM({0:{0:QQ(1), 1:QQ(2), 3:QQ(1)},
  293. 1:{0:QQ(1), 1:QQ(1), 2:QQ(9)}}, (2, 4), QQ)
  294. Arref = SDM({0:{0:QQ(1), 2:QQ(18), 3:QQ(-1)},
  295. 1:{1:QQ(1), 2:QQ(-9), 3:QQ(1)}}, (2, 4), QQ)
  296. assert A.rref() == (Arref, [0, 1])
  297. A = SDM({0:{0:QQ(1), 1:QQ(1), 2:QQ(1)},
  298. 1:{0:QQ(1), 1:QQ(2), 2:QQ(2)}}, (2, 3), QQ)
  299. Arref = SDM(
  300. {0: {0: QQ(1,1)}, 1: {1: QQ(1,1), 2: QQ(1,1)}},
  301. (2, 3), QQ)
  302. assert A.rref() == (Arref, [0, 1])
  303. def test_SDM_particular():
  304. A = SDM({0:{0:QQ(1)}}, (2, 2), QQ)
  305. Apart = SDM.zeros((1, 2), QQ)
  306. assert A.particular() == Apart
  307. def test_SDM_is_zero_matrix():
  308. A = SDM({0: {0: QQ(1)}}, (2, 2), QQ)
  309. Azero = SDM.zeros((1, 2), QQ)
  310. assert A.is_zero_matrix() is False
  311. assert Azero.is_zero_matrix() is True
  312. def test_SDM_is_upper():
  313. A = SDM({0: {0: QQ(1), 1: QQ(2), 2: QQ(3), 3: QQ(4)},
  314. 1: {1: QQ(5), 2: QQ(6), 3: QQ(7)},
  315. 2: {2: QQ(8), 3: QQ(9)}}, (3, 4), QQ)
  316. B = SDM({0: {0: QQ(1), 1: QQ(2), 2: QQ(3), 3: QQ(4)},
  317. 1: {1: QQ(5), 2: QQ(6), 3: QQ(7)},
  318. 2: {1: QQ(7), 2: QQ(8), 3: QQ(9)}}, (3, 4), QQ)
  319. assert A.is_upper() is True
  320. assert B.is_upper() is False
  321. def test_SDM_is_lower():
  322. A = SDM({0: {0: QQ(1), 1: QQ(2), 2: QQ(3), 3: QQ(4)},
  323. 1: {1: QQ(5), 2: QQ(6), 3: QQ(7)},
  324. 2: {2: QQ(8), 3: QQ(9)}}, (3, 4), QQ
  325. ).transpose()
  326. B = SDM({0: {0: QQ(1), 1: QQ(2), 2: QQ(3), 3: QQ(4)},
  327. 1: {1: QQ(5), 2: QQ(6), 3: QQ(7)},
  328. 2: {1: QQ(7), 2: QQ(8), 3: QQ(9)}}, (3, 4), QQ
  329. ).transpose()
  330. assert A.is_lower() is True
  331. assert B.is_lower() is False