matrices.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. from sympy.assumptions import Predicate
  2. from sympy.multipledispatch import Dispatcher
  3. class SquarePredicate(Predicate):
  4. """
  5. Square matrix predicate.
  6. Explanation
  7. ===========
  8. ``Q.square(x)`` is true iff ``x`` is a square matrix. A square matrix
  9. is a matrix with the same number of rows and columns.
  10. Examples
  11. ========
  12. >>> from sympy import Q, ask, MatrixSymbol, ZeroMatrix, Identity
  13. >>> X = MatrixSymbol('X', 2, 2)
  14. >>> Y = MatrixSymbol('X', 2, 3)
  15. >>> ask(Q.square(X))
  16. True
  17. >>> ask(Q.square(Y))
  18. False
  19. >>> ask(Q.square(ZeroMatrix(3, 3)))
  20. True
  21. >>> ask(Q.square(Identity(3)))
  22. True
  23. References
  24. ==========
  25. .. [1] https://en.wikipedia.org/wiki/Square_matrix
  26. """
  27. name = 'square'
  28. handler = Dispatcher("SquareHandler", doc="Handler for Q.square.")
  29. class SymmetricPredicate(Predicate):
  30. """
  31. Symmetric matrix predicate.
  32. Explanation
  33. ===========
  34. ``Q.symmetric(x)`` is true iff ``x`` is a square matrix and is equal to
  35. its transpose. Every square diagonal matrix is a symmetric matrix.
  36. Examples
  37. ========
  38. >>> from sympy import Q, ask, MatrixSymbol
  39. >>> X = MatrixSymbol('X', 2, 2)
  40. >>> Y = MatrixSymbol('Y', 2, 3)
  41. >>> Z = MatrixSymbol('Z', 2, 2)
  42. >>> ask(Q.symmetric(X*Z), Q.symmetric(X) & Q.symmetric(Z))
  43. True
  44. >>> ask(Q.symmetric(X + Z), Q.symmetric(X) & Q.symmetric(Z))
  45. True
  46. >>> ask(Q.symmetric(Y))
  47. False
  48. References
  49. ==========
  50. .. [1] https://en.wikipedia.org/wiki/Symmetric_matrix
  51. """
  52. # TODO: Add handlers to make these keys work with
  53. # actual matrices and add more examples in the docstring.
  54. name = 'symmetric'
  55. handler = Dispatcher("SymmetricHandler", doc="Handler for Q.symmetric.")
  56. class InvertiblePredicate(Predicate):
  57. """
  58. Invertible matrix predicate.
  59. Explanation
  60. ===========
  61. ``Q.invertible(x)`` is true iff ``x`` is an invertible matrix.
  62. A square matrix is called invertible only if its determinant is 0.
  63. Examples
  64. ========
  65. >>> from sympy import Q, ask, MatrixSymbol
  66. >>> X = MatrixSymbol('X', 2, 2)
  67. >>> Y = MatrixSymbol('Y', 2, 3)
  68. >>> Z = MatrixSymbol('Z', 2, 2)
  69. >>> ask(Q.invertible(X*Y), Q.invertible(X))
  70. False
  71. >>> ask(Q.invertible(X*Z), Q.invertible(X) & Q.invertible(Z))
  72. True
  73. >>> ask(Q.invertible(X), Q.fullrank(X) & Q.square(X))
  74. True
  75. References
  76. ==========
  77. .. [1] https://en.wikipedia.org/wiki/Invertible_matrix
  78. """
  79. name = 'invertible'
  80. handler = Dispatcher("InvertibleHandler", doc="Handler for Q.invertible.")
  81. class OrthogonalPredicate(Predicate):
  82. """
  83. Orthogonal matrix predicate.
  84. Explanation
  85. ===========
  86. ``Q.orthogonal(x)`` is true iff ``x`` is an orthogonal matrix.
  87. A square matrix ``M`` is an orthogonal matrix if it satisfies
  88. ``M^TM = MM^T = I`` where ``M^T`` is the transpose matrix of
  89. ``M`` and ``I`` is an identity matrix. Note that an orthogonal
  90. matrix is necessarily invertible.
  91. Examples
  92. ========
  93. >>> from sympy import Q, ask, MatrixSymbol, Identity
  94. >>> X = MatrixSymbol('X', 2, 2)
  95. >>> Y = MatrixSymbol('Y', 2, 3)
  96. >>> Z = MatrixSymbol('Z', 2, 2)
  97. >>> ask(Q.orthogonal(Y))
  98. False
  99. >>> ask(Q.orthogonal(X*Z*X), Q.orthogonal(X) & Q.orthogonal(Z))
  100. True
  101. >>> ask(Q.orthogonal(Identity(3)))
  102. True
  103. >>> ask(Q.invertible(X), Q.orthogonal(X))
  104. True
  105. References
  106. ==========
  107. .. [1] https://en.wikipedia.org/wiki/Orthogonal_matrix
  108. """
  109. name = 'orthogonal'
  110. handler = Dispatcher("OrthogonalHandler", doc="Handler for key 'orthogonal'.")
  111. class UnitaryPredicate(Predicate):
  112. """
  113. Unitary matrix predicate.
  114. Explanation
  115. ===========
  116. ``Q.unitary(x)`` is true iff ``x`` is a unitary matrix.
  117. Unitary matrix is an analogue to orthogonal matrix. A square
  118. matrix ``M`` with complex elements is unitary if :math:``M^TM = MM^T= I``
  119. where :math:``M^T`` is the conjugate transpose matrix of ``M``.
  120. Examples
  121. ========
  122. >>> from sympy import Q, ask, MatrixSymbol, Identity
  123. >>> X = MatrixSymbol('X', 2, 2)
  124. >>> Y = MatrixSymbol('Y', 2, 3)
  125. >>> Z = MatrixSymbol('Z', 2, 2)
  126. >>> ask(Q.unitary(Y))
  127. False
  128. >>> ask(Q.unitary(X*Z*X), Q.unitary(X) & Q.unitary(Z))
  129. True
  130. >>> ask(Q.unitary(Identity(3)))
  131. True
  132. References
  133. ==========
  134. .. [1] https://en.wikipedia.org/wiki/Unitary_matrix
  135. """
  136. name = 'unitary'
  137. handler = Dispatcher("UnitaryHandler", doc="Handler for key 'unitary'.")
  138. class FullRankPredicate(Predicate):
  139. """
  140. Fullrank matrix predicate.
  141. Explanation
  142. ===========
  143. ``Q.fullrank(x)`` is true iff ``x`` is a full rank matrix.
  144. A matrix is full rank if all rows and columns of the matrix
  145. are linearly independent. A square matrix is full rank iff
  146. its determinant is nonzero.
  147. Examples
  148. ========
  149. >>> from sympy import Q, ask, MatrixSymbol, ZeroMatrix, Identity
  150. >>> X = MatrixSymbol('X', 2, 2)
  151. >>> ask(Q.fullrank(X.T), Q.fullrank(X))
  152. True
  153. >>> ask(Q.fullrank(ZeroMatrix(3, 3)))
  154. False
  155. >>> ask(Q.fullrank(Identity(3)))
  156. True
  157. """
  158. name = 'fullrank'
  159. handler = Dispatcher("FullRankHandler", doc="Handler for key 'fullrank'.")
  160. class PositiveDefinitePredicate(Predicate):
  161. r"""
  162. Positive definite matrix predicate.
  163. Explanation
  164. ===========
  165. If $M$ is a :math:`n \times n` symmetric real matrix, it is said
  166. to be positive definite if :math:`Z^TMZ` is positive for
  167. every non-zero column vector $Z$ of $n$ real numbers.
  168. Examples
  169. ========
  170. >>> from sympy import Q, ask, MatrixSymbol, Identity
  171. >>> X = MatrixSymbol('X', 2, 2)
  172. >>> Y = MatrixSymbol('Y', 2, 3)
  173. >>> Z = MatrixSymbol('Z', 2, 2)
  174. >>> ask(Q.positive_definite(Y))
  175. False
  176. >>> ask(Q.positive_definite(Identity(3)))
  177. True
  178. >>> ask(Q.positive_definite(X + Z), Q.positive_definite(X) &
  179. ... Q.positive_definite(Z))
  180. True
  181. References
  182. ==========
  183. .. [1] https://en.wikipedia.org/wiki/Positive-definite_matrix
  184. """
  185. name = "positive_definite"
  186. handler = Dispatcher("PositiveDefiniteHandler", doc="Handler for key 'positive_definite'.")
  187. class UpperTriangularPredicate(Predicate):
  188. """
  189. Upper triangular matrix predicate.
  190. Explanation
  191. ===========
  192. A matrix $M$ is called upper triangular matrix if :math:`M_{ij}=0`
  193. for :math:`i<j`.
  194. Examples
  195. ========
  196. >>> from sympy import Q, ask, ZeroMatrix, Identity
  197. >>> ask(Q.upper_triangular(Identity(3)))
  198. True
  199. >>> ask(Q.upper_triangular(ZeroMatrix(3, 3)))
  200. True
  201. References
  202. ==========
  203. .. [1] http://mathworld.wolfram.com/UpperTriangularMatrix.html
  204. """
  205. name = "upper_triangular"
  206. handler = Dispatcher("UpperTriangularHandler", doc="Handler for key 'upper_triangular'.")
  207. class LowerTriangularPredicate(Predicate):
  208. """
  209. Lower triangular matrix predicate.
  210. Explanation
  211. ===========
  212. A matrix $M$ is called lower triangular matrix if :math:`M_{ij}=0`
  213. for :math:`i>j`.
  214. Examples
  215. ========
  216. >>> from sympy import Q, ask, ZeroMatrix, Identity
  217. >>> ask(Q.lower_triangular(Identity(3)))
  218. True
  219. >>> ask(Q.lower_triangular(ZeroMatrix(3, 3)))
  220. True
  221. References
  222. ==========
  223. .. [1] http://mathworld.wolfram.com/LowerTriangularMatrix.html
  224. """
  225. name = "lower_triangular"
  226. handler = Dispatcher("LowerTriangularHandler", doc="Handler for key 'lower_triangular'.")
  227. class DiagonalPredicate(Predicate):
  228. """
  229. Diagonal matrix predicate.
  230. Explanation
  231. ===========
  232. ``Q.diagonal(x)`` is true iff ``x`` is a diagonal matrix. A diagonal
  233. matrix is a matrix in which the entries outside the main diagonal
  234. are all zero.
  235. Examples
  236. ========
  237. >>> from sympy import Q, ask, MatrixSymbol, ZeroMatrix
  238. >>> X = MatrixSymbol('X', 2, 2)
  239. >>> ask(Q.diagonal(ZeroMatrix(3, 3)))
  240. True
  241. >>> ask(Q.diagonal(X), Q.lower_triangular(X) &
  242. ... Q.upper_triangular(X))
  243. True
  244. References
  245. ==========
  246. .. [1] https://en.wikipedia.org/wiki/Diagonal_matrix
  247. """
  248. name = "diagonal"
  249. handler = Dispatcher("DiagonalHandler", doc="Handler for key 'diagonal'.")
  250. class IntegerElementsPredicate(Predicate):
  251. """
  252. Integer elements matrix predicate.
  253. Explanation
  254. ===========
  255. ``Q.integer_elements(x)`` is true iff all the elements of ``x``
  256. are integers.
  257. Examples
  258. ========
  259. >>> from sympy import Q, ask, MatrixSymbol
  260. >>> X = MatrixSymbol('X', 4, 4)
  261. >>> ask(Q.integer(X[1, 2]), Q.integer_elements(X))
  262. True
  263. """
  264. name = "integer_elements"
  265. handler = Dispatcher("IntegerElementsHandler", doc="Handler for key 'integer_elements'.")
  266. class RealElementsPredicate(Predicate):
  267. """
  268. Real elements matrix predicate.
  269. Explanation
  270. ===========
  271. ``Q.real_elements(x)`` is true iff all the elements of ``x``
  272. are real numbers.
  273. Examples
  274. ========
  275. >>> from sympy import Q, ask, MatrixSymbol
  276. >>> X = MatrixSymbol('X', 4, 4)
  277. >>> ask(Q.real(X[1, 2]), Q.real_elements(X))
  278. True
  279. """
  280. name = "real_elements"
  281. handler = Dispatcher("RealElementsHandler", doc="Handler for key 'real_elements'.")
  282. class ComplexElementsPredicate(Predicate):
  283. """
  284. Complex elements matrix predicate.
  285. Explanation
  286. ===========
  287. ``Q.complex_elements(x)`` is true iff all the elements of ``x``
  288. are complex numbers.
  289. Examples
  290. ========
  291. >>> from sympy import Q, ask, MatrixSymbol
  292. >>> X = MatrixSymbol('X', 4, 4)
  293. >>> ask(Q.complex(X[1, 2]), Q.complex_elements(X))
  294. True
  295. >>> ask(Q.complex_elements(X), Q.integer_elements(X))
  296. True
  297. """
  298. name = "complex_elements"
  299. handler = Dispatcher("ComplexElementsHandler", doc="Handler for key 'complex_elements'.")
  300. class SingularPredicate(Predicate):
  301. """
  302. Singular matrix predicate.
  303. A matrix is singular iff the value of its determinant is 0.
  304. Examples
  305. ========
  306. >>> from sympy import Q, ask, MatrixSymbol
  307. >>> X = MatrixSymbol('X', 4, 4)
  308. >>> ask(Q.singular(X), Q.invertible(X))
  309. False
  310. >>> ask(Q.singular(X), ~Q.invertible(X))
  311. True
  312. References
  313. ==========
  314. .. [1] http://mathworld.wolfram.com/SingularMatrix.html
  315. """
  316. name = "singular"
  317. handler = Dispatcher("SingularHandler", doc="Predicate fore key 'singular'.")
  318. class NormalPredicate(Predicate):
  319. """
  320. Normal matrix predicate.
  321. A matrix is normal if it commutes with its conjugate transpose.
  322. Examples
  323. ========
  324. >>> from sympy import Q, ask, MatrixSymbol
  325. >>> X = MatrixSymbol('X', 4, 4)
  326. >>> ask(Q.normal(X), Q.unitary(X))
  327. True
  328. References
  329. ==========
  330. .. [1] https://en.wikipedia.org/wiki/Normal_matrix
  331. """
  332. name = "normal"
  333. handler = Dispatcher("NormalHandler", doc="Predicate fore key 'normal'.")
  334. class TriangularPredicate(Predicate):
  335. """
  336. Triangular matrix predicate.
  337. Explanation
  338. ===========
  339. ``Q.triangular(X)`` is true if ``X`` is one that is either lower
  340. triangular or upper triangular.
  341. Examples
  342. ========
  343. >>> from sympy import Q, ask, MatrixSymbol
  344. >>> X = MatrixSymbol('X', 4, 4)
  345. >>> ask(Q.triangular(X), Q.upper_triangular(X))
  346. True
  347. >>> ask(Q.triangular(X), Q.lower_triangular(X))
  348. True
  349. References
  350. ==========
  351. .. [1] https://en.wikipedia.org/wiki/Triangular_matrix
  352. """
  353. name = "triangular"
  354. handler = Dispatcher("TriangularHandler", doc="Predicate fore key 'triangular'.")
  355. class UnitTriangularPredicate(Predicate):
  356. """
  357. Unit triangular matrix predicate.
  358. Explanation
  359. ===========
  360. A unit triangular matrix is a triangular matrix with 1s
  361. on the diagonal.
  362. Examples
  363. ========
  364. >>> from sympy import Q, ask, MatrixSymbol
  365. >>> X = MatrixSymbol('X', 4, 4)
  366. >>> ask(Q.triangular(X), Q.unit_triangular(X))
  367. True
  368. """
  369. name = "unit_triangular"
  370. handler = Dispatcher("UnitTriangularHandler", doc="Predicate fore key 'unit_triangular'.")