sets.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772
  1. """
  2. Handlers for predicates related to set membership: integer, rational, etc.
  3. """
  4. from sympy.assumptions import Q, ask
  5. from sympy.core import Add, Basic, Expr, Mul, Pow, S
  6. from sympy.core.numbers import (AlgebraicNumber, ComplexInfinity, Exp1, Float,
  7. GoldenRatio, ImaginaryUnit, Infinity, Integer, NaN, NegativeInfinity,
  8. Number, NumberSymbol, Pi, pi, Rational, TribonacciConstant, E)
  9. from sympy.core.logic import fuzzy_bool
  10. from sympy.functions import (Abs, acos, acot, asin, atan, cos, cot, exp, im,
  11. log, re, sin, tan)
  12. from sympy.core.numbers import I
  13. from sympy.core.relational import Eq
  14. from sympy.functions.elementary.complexes import conjugate
  15. from sympy.matrices import Determinant, MatrixBase, Trace
  16. from sympy.matrices.expressions.matexpr import MatrixElement
  17. from sympy.multipledispatch import MDNotImplementedError
  18. from .common import test_closed_group
  19. from ..predicates.sets import (IntegerPredicate, RationalPredicate,
  20. IrrationalPredicate, RealPredicate, ExtendedRealPredicate,
  21. HermitianPredicate, ComplexPredicate, ImaginaryPredicate,
  22. AntihermitianPredicate, AlgebraicPredicate)
  23. # IntegerPredicate
  24. def _IntegerPredicate_number(expr, assumptions):
  25. # helper function
  26. try:
  27. i = int(expr.round())
  28. if not (expr - i).equals(0):
  29. raise TypeError
  30. return True
  31. except TypeError:
  32. return False
  33. @IntegerPredicate.register_many(int, Integer) # type:ignore
  34. def _(expr, assumptions):
  35. return True
  36. @IntegerPredicate.register_many(Exp1, GoldenRatio, ImaginaryUnit, Infinity,
  37. NegativeInfinity, Pi, Rational, TribonacciConstant)
  38. def _(expr, assumptions):
  39. return False
  40. @IntegerPredicate.register(Expr)
  41. def _(expr, assumptions):
  42. ret = expr.is_integer
  43. if ret is None:
  44. raise MDNotImplementedError
  45. return ret
  46. @IntegerPredicate.register_many(Add, Pow)
  47. def _(expr, assumptions):
  48. """
  49. * Integer + Integer -> Integer
  50. * Integer + !Integer -> !Integer
  51. * !Integer + !Integer -> ?
  52. """
  53. if expr.is_number:
  54. return _IntegerPredicate_number(expr, assumptions)
  55. return test_closed_group(expr, assumptions, Q.integer)
  56. @IntegerPredicate.register(Mul)
  57. def _(expr, assumptions):
  58. """
  59. * Integer*Integer -> Integer
  60. * Integer*Irrational -> !Integer
  61. * Odd/Even -> !Integer
  62. * Integer*Rational -> ?
  63. """
  64. if expr.is_number:
  65. return _IntegerPredicate_number(expr, assumptions)
  66. _output = True
  67. for arg in expr.args:
  68. if not ask(Q.integer(arg), assumptions):
  69. if arg.is_Rational:
  70. if arg.q == 2:
  71. return ask(Q.even(2*expr), assumptions)
  72. if ~(arg.q & 1):
  73. return None
  74. elif ask(Q.irrational(arg), assumptions):
  75. if _output:
  76. _output = False
  77. else:
  78. return
  79. else:
  80. return
  81. return _output
  82. @IntegerPredicate.register(Abs)
  83. def _(expr, assumptions):
  84. return ask(Q.integer(expr.args[0]), assumptions)
  85. @IntegerPredicate.register_many(Determinant, MatrixElement, Trace)
  86. def _(expr, assumptions):
  87. return ask(Q.integer_elements(expr.args[0]), assumptions)
  88. # RationalPredicate
  89. @RationalPredicate.register(Rational)
  90. def _(expr, assumptions):
  91. return True
  92. @RationalPredicate.register(Float)
  93. def _(expr, assumptions):
  94. return None
  95. @RationalPredicate.register_many(Exp1, GoldenRatio, ImaginaryUnit, Infinity,
  96. NegativeInfinity, Pi, TribonacciConstant)
  97. def _(expr, assumptions):
  98. return False
  99. @RationalPredicate.register(Expr)
  100. def _(expr, assumptions):
  101. ret = expr.is_rational
  102. if ret is None:
  103. raise MDNotImplementedError
  104. return ret
  105. @RationalPredicate.register_many(Add, Mul)
  106. def _(expr, assumptions):
  107. """
  108. * Rational + Rational -> Rational
  109. * Rational + !Rational -> !Rational
  110. * !Rational + !Rational -> ?
  111. """
  112. if expr.is_number:
  113. if expr.as_real_imag()[1]:
  114. return False
  115. return test_closed_group(expr, assumptions, Q.rational)
  116. @RationalPredicate.register(Pow)
  117. def _(expr, assumptions):
  118. """
  119. * Rational ** Integer -> Rational
  120. * Irrational ** Rational -> Irrational
  121. * Rational ** Irrational -> ?
  122. """
  123. if expr.base == E:
  124. x = expr.exp
  125. if ask(Q.rational(x), assumptions):
  126. return ask(~Q.nonzero(x), assumptions)
  127. return
  128. if ask(Q.integer(expr.exp), assumptions):
  129. return ask(Q.rational(expr.base), assumptions)
  130. elif ask(Q.rational(expr.exp), assumptions):
  131. if ask(Q.prime(expr.base), assumptions):
  132. return False
  133. @RationalPredicate.register_many(asin, atan, cos, sin, tan)
  134. def _(expr, assumptions):
  135. x = expr.args[0]
  136. if ask(Q.rational(x), assumptions):
  137. return ask(~Q.nonzero(x), assumptions)
  138. @RationalPredicate.register(exp)
  139. def _(expr, assumptions):
  140. x = expr.exp
  141. if ask(Q.rational(x), assumptions):
  142. return ask(~Q.nonzero(x), assumptions)
  143. @RationalPredicate.register_many(acot, cot)
  144. def _(expr, assumptions):
  145. x = expr.args[0]
  146. if ask(Q.rational(x), assumptions):
  147. return False
  148. @RationalPredicate.register_many(acos, log)
  149. def _(expr, assumptions):
  150. x = expr.args[0]
  151. if ask(Q.rational(x), assumptions):
  152. return ask(~Q.nonzero(x - 1), assumptions)
  153. # IrrationalPredicate
  154. @IrrationalPredicate.register(Expr)
  155. def _(expr, assumptions):
  156. ret = expr.is_irrational
  157. if ret is None:
  158. raise MDNotImplementedError
  159. return ret
  160. @IrrationalPredicate.register(Basic)
  161. def _(expr, assumptions):
  162. _real = ask(Q.real(expr), assumptions)
  163. if _real:
  164. _rational = ask(Q.rational(expr), assumptions)
  165. if _rational is None:
  166. return None
  167. return not _rational
  168. else:
  169. return _real
  170. # RealPredicate
  171. def _RealPredicate_number(expr, assumptions):
  172. # let as_real_imag() work first since the expression may
  173. # be simpler to evaluate
  174. i = expr.as_real_imag()[1].evalf(2)
  175. if i._prec != 1:
  176. return not i
  177. # allow None to be returned if we couldn't show for sure
  178. # that i was 0
  179. @RealPredicate.register_many(Abs, Exp1, Float, GoldenRatio, im, Pi, Rational,
  180. re, TribonacciConstant)
  181. def _(expr, assumptions):
  182. return True
  183. @RealPredicate.register_many(ImaginaryUnit, Infinity, NegativeInfinity)
  184. def _(expr, assumptions):
  185. return False
  186. @RealPredicate.register(Expr)
  187. def _(expr, assumptions):
  188. ret = expr.is_real
  189. if ret is None:
  190. raise MDNotImplementedError
  191. return ret
  192. @RealPredicate.register(Add)
  193. def _(expr, assumptions):
  194. """
  195. * Real + Real -> Real
  196. * Real + (Complex & !Real) -> !Real
  197. """
  198. if expr.is_number:
  199. return _RealPredicate_number(expr, assumptions)
  200. return test_closed_group(expr, assumptions, Q.real)
  201. @RealPredicate.register(Mul)
  202. def _(expr, assumptions):
  203. """
  204. * Real*Real -> Real
  205. * Real*Imaginary -> !Real
  206. * Imaginary*Imaginary -> Real
  207. """
  208. if expr.is_number:
  209. return _RealPredicate_number(expr, assumptions)
  210. result = True
  211. for arg in expr.args:
  212. if ask(Q.real(arg), assumptions):
  213. pass
  214. elif ask(Q.imaginary(arg), assumptions):
  215. result = result ^ True
  216. else:
  217. break
  218. else:
  219. return result
  220. @RealPredicate.register(Pow)
  221. def _(expr, assumptions):
  222. """
  223. * Real**Integer -> Real
  224. * Positive**Real -> Real
  225. * Real**(Integer/Even) -> Real if base is nonnegative
  226. * Real**(Integer/Odd) -> Real
  227. * Imaginary**(Integer/Even) -> Real
  228. * Imaginary**(Integer/Odd) -> not Real
  229. * Imaginary**Real -> ? since Real could be 0 (giving real)
  230. or 1 (giving imaginary)
  231. * b**Imaginary -> Real if log(b) is imaginary and b != 0
  232. and exponent != integer multiple of
  233. I*pi/log(b)
  234. * Real**Real -> ? e.g. sqrt(-1) is imaginary and
  235. sqrt(2) is not
  236. """
  237. if expr.is_number:
  238. return _RealPredicate_number(expr, assumptions)
  239. if expr.base == E:
  240. return ask(
  241. Q.integer(expr.exp/I/pi) | Q.real(expr.exp), assumptions
  242. )
  243. if expr.base.func == exp or (expr.base.is_Pow and expr.base.base == E):
  244. if ask(Q.imaginary(expr.base.exp), assumptions):
  245. if ask(Q.imaginary(expr.exp), assumptions):
  246. return True
  247. # If the i = (exp's arg)/(I*pi) is an integer or half-integer
  248. # multiple of I*pi then 2*i will be an integer. In addition,
  249. # exp(i*I*pi) = (-1)**i so the overall realness of the expr
  250. # can be determined by replacing exp(i*I*pi) with (-1)**i.
  251. i = expr.base.exp/I/pi
  252. if ask(Q.integer(2*i), assumptions):
  253. return ask(Q.real((S.NegativeOne**i)**expr.exp), assumptions)
  254. return
  255. if ask(Q.imaginary(expr.base), assumptions):
  256. if ask(Q.integer(expr.exp), assumptions):
  257. odd = ask(Q.odd(expr.exp), assumptions)
  258. if odd is not None:
  259. return not odd
  260. return
  261. if ask(Q.imaginary(expr.exp), assumptions):
  262. imlog = ask(Q.imaginary(log(expr.base)), assumptions)
  263. if imlog is not None:
  264. # I**i -> real, log(I) is imag;
  265. # (2*I)**i -> complex, log(2*I) is not imag
  266. return imlog
  267. if ask(Q.real(expr.base), assumptions):
  268. if ask(Q.real(expr.exp), assumptions):
  269. if expr.exp.is_Rational and \
  270. ask(Q.even(expr.exp.q), assumptions):
  271. return ask(Q.positive(expr.base), assumptions)
  272. elif ask(Q.integer(expr.exp), assumptions):
  273. return True
  274. elif ask(Q.positive(expr.base), assumptions):
  275. return True
  276. elif ask(Q.negative(expr.base), assumptions):
  277. return False
  278. @RealPredicate.register_many(cos, sin)
  279. def _(expr, assumptions):
  280. if ask(Q.real(expr.args[0]), assumptions):
  281. return True
  282. @RealPredicate.register(exp)
  283. def _(expr, assumptions):
  284. return ask(
  285. Q.integer(expr.exp/I/pi) | Q.real(expr.exp), assumptions
  286. )
  287. @RealPredicate.register(log)
  288. def _(expr, assumptions):
  289. return ask(Q.positive(expr.args[0]), assumptions)
  290. @RealPredicate.register_many(Determinant, MatrixElement, Trace)
  291. def _(expr, assumptions):
  292. return ask(Q.real_elements(expr.args[0]), assumptions)
  293. # ExtendedRealPredicate
  294. @ExtendedRealPredicate.register(object)
  295. def _(expr, assumptions):
  296. return ask(Q.negative_infinite(expr)
  297. | Q.negative(expr)
  298. | Q.zero(expr)
  299. | Q.positive(expr)
  300. | Q.positive_infinite(expr),
  301. assumptions)
  302. @ExtendedRealPredicate.register_many(Infinity, NegativeInfinity)
  303. def _(expr, assumptions):
  304. return True
  305. @ExtendedRealPredicate.register_many(Add, Mul, Pow) # type:ignore
  306. def _(expr, assumptions):
  307. return test_closed_group(expr, assumptions, Q.extended_real)
  308. # HermitianPredicate
  309. @HermitianPredicate.register(object) # type:ignore
  310. def _(expr, assumptions):
  311. if isinstance(expr, MatrixBase):
  312. return None
  313. return ask(Q.real(expr), assumptions)
  314. @HermitianPredicate.register(Add) # type:ignore
  315. def _(expr, assumptions):
  316. """
  317. * Hermitian + Hermitian -> Hermitian
  318. * Hermitian + !Hermitian -> !Hermitian
  319. """
  320. if expr.is_number:
  321. raise MDNotImplementedError
  322. return test_closed_group(expr, assumptions, Q.hermitian)
  323. @HermitianPredicate.register(Mul) # type:ignore
  324. def _(expr, assumptions):
  325. """
  326. As long as there is at most only one noncommutative term:
  327. * Hermitian*Hermitian -> Hermitian
  328. * Hermitian*Antihermitian -> !Hermitian
  329. * Antihermitian*Antihermitian -> Hermitian
  330. """
  331. if expr.is_number:
  332. raise MDNotImplementedError
  333. nccount = 0
  334. result = True
  335. for arg in expr.args:
  336. if ask(Q.antihermitian(arg), assumptions):
  337. result = result ^ True
  338. elif not ask(Q.hermitian(arg), assumptions):
  339. break
  340. if ask(~Q.commutative(arg), assumptions):
  341. nccount += 1
  342. if nccount > 1:
  343. break
  344. else:
  345. return result
  346. @HermitianPredicate.register(Pow) # type:ignore
  347. def _(expr, assumptions):
  348. """
  349. * Hermitian**Integer -> Hermitian
  350. """
  351. if expr.is_number:
  352. raise MDNotImplementedError
  353. if expr.base == E:
  354. if ask(Q.hermitian(expr.exp), assumptions):
  355. return True
  356. raise MDNotImplementedError
  357. if ask(Q.hermitian(expr.base), assumptions):
  358. if ask(Q.integer(expr.exp), assumptions):
  359. return True
  360. raise MDNotImplementedError
  361. @HermitianPredicate.register_many(cos, sin) # type:ignore
  362. def _(expr, assumptions):
  363. if ask(Q.hermitian(expr.args[0]), assumptions):
  364. return True
  365. raise MDNotImplementedError
  366. @HermitianPredicate.register(exp) # type:ignore
  367. def _(expr, assumptions):
  368. if ask(Q.hermitian(expr.exp), assumptions):
  369. return True
  370. raise MDNotImplementedError
  371. @HermitianPredicate.register(MatrixBase) # type:ignore
  372. def _(mat, assumptions):
  373. rows, cols = mat.shape
  374. ret_val = True
  375. for i in range(rows):
  376. for j in range(i, cols):
  377. cond = fuzzy_bool(Eq(mat[i, j], conjugate(mat[j, i])))
  378. if cond is None:
  379. ret_val = None
  380. if cond == False:
  381. return False
  382. if ret_val is None:
  383. raise MDNotImplementedError
  384. return ret_val
  385. # ComplexPredicate
  386. @ComplexPredicate.register_many(Abs, cos, exp, im, ImaginaryUnit, log, Number, # type:ignore
  387. NumberSymbol, re, sin)
  388. def _(expr, assumptions):
  389. return True
  390. @ComplexPredicate.register_many(Infinity, NegativeInfinity) # type:ignore
  391. def _(expr, assumptions):
  392. return False
  393. @ComplexPredicate.register(Expr) # type:ignore
  394. def _(expr, assumptions):
  395. ret = expr.is_complex
  396. if ret is None:
  397. raise MDNotImplementedError
  398. return ret
  399. @ComplexPredicate.register_many(Add, Mul) # type:ignore
  400. def _(expr, assumptions):
  401. return test_closed_group(expr, assumptions, Q.complex)
  402. @ComplexPredicate.register(Pow) # type:ignore
  403. def _(expr, assumptions):
  404. if expr.base == E:
  405. return True
  406. return test_closed_group(expr, assumptions, Q.complex)
  407. @ComplexPredicate.register_many(Determinant, MatrixElement, Trace) # type:ignore
  408. def _(expr, assumptions):
  409. return ask(Q.complex_elements(expr.args[0]), assumptions)
  410. @ComplexPredicate.register(NaN) # type:ignore
  411. def _(expr, assumptions):
  412. return None
  413. # ImaginaryPredicate
  414. def _Imaginary_number(expr, assumptions):
  415. # let as_real_imag() work first since the expression may
  416. # be simpler to evaluate
  417. r = expr.as_real_imag()[0].evalf(2)
  418. if r._prec != 1:
  419. return not r
  420. # allow None to be returned if we couldn't show for sure
  421. # that r was 0
  422. @ImaginaryPredicate.register(ImaginaryUnit) # type:ignore
  423. def _(expr, assumptions):
  424. return True
  425. @ImaginaryPredicate.register(Expr) # type:ignore
  426. def _(expr, assumptions):
  427. ret = expr.is_imaginary
  428. if ret is None:
  429. raise MDNotImplementedError
  430. return ret
  431. @ImaginaryPredicate.register(Add) # type:ignore
  432. def _(expr, assumptions):
  433. """
  434. * Imaginary + Imaginary -> Imaginary
  435. * Imaginary + Complex -> ?
  436. * Imaginary + Real -> !Imaginary
  437. """
  438. if expr.is_number:
  439. return _Imaginary_number(expr, assumptions)
  440. reals = 0
  441. for arg in expr.args:
  442. if ask(Q.imaginary(arg), assumptions):
  443. pass
  444. elif ask(Q.real(arg), assumptions):
  445. reals += 1
  446. else:
  447. break
  448. else:
  449. if reals == 0:
  450. return True
  451. if reals in (1, len(expr.args)):
  452. # two reals could sum 0 thus giving an imaginary
  453. return False
  454. @ImaginaryPredicate.register(Mul) # type:ignore
  455. def _(expr, assumptions):
  456. """
  457. * Real*Imaginary -> Imaginary
  458. * Imaginary*Imaginary -> Real
  459. """
  460. if expr.is_number:
  461. return _Imaginary_number(expr, assumptions)
  462. result = False
  463. reals = 0
  464. for arg in expr.args:
  465. if ask(Q.imaginary(arg), assumptions):
  466. result = result ^ True
  467. elif not ask(Q.real(arg), assumptions):
  468. break
  469. else:
  470. if reals == len(expr.args):
  471. return False
  472. return result
  473. @ImaginaryPredicate.register(Pow) # type:ignore
  474. def _(expr, assumptions):
  475. """
  476. * Imaginary**Odd -> Imaginary
  477. * Imaginary**Even -> Real
  478. * b**Imaginary -> !Imaginary if exponent is an integer
  479. multiple of I*pi/log(b)
  480. * Imaginary**Real -> ?
  481. * Positive**Real -> Real
  482. * Negative**Integer -> Real
  483. * Negative**(Integer/2) -> Imaginary
  484. * Negative**Real -> not Imaginary if exponent is not Rational
  485. """
  486. if expr.is_number:
  487. return _Imaginary_number(expr, assumptions)
  488. if expr.base == E:
  489. a = expr.exp/I/pi
  490. return ask(Q.integer(2*a) & ~Q.integer(a), assumptions)
  491. if expr.base.func == exp or (expr.base.is_Pow and expr.base.base == E):
  492. if ask(Q.imaginary(expr.base.exp), assumptions):
  493. if ask(Q.imaginary(expr.exp), assumptions):
  494. return False
  495. i = expr.base.exp/I/pi
  496. if ask(Q.integer(2*i), assumptions):
  497. return ask(Q.imaginary((S.NegativeOne**i)**expr.exp), assumptions)
  498. if ask(Q.imaginary(expr.base), assumptions):
  499. if ask(Q.integer(expr.exp), assumptions):
  500. odd = ask(Q.odd(expr.exp), assumptions)
  501. if odd is not None:
  502. return odd
  503. return
  504. if ask(Q.imaginary(expr.exp), assumptions):
  505. imlog = ask(Q.imaginary(log(expr.base)), assumptions)
  506. if imlog is not None:
  507. # I**i -> real; (2*I)**i -> complex ==> not imaginary
  508. return False
  509. if ask(Q.real(expr.base) & Q.real(expr.exp), assumptions):
  510. if ask(Q.positive(expr.base), assumptions):
  511. return False
  512. else:
  513. rat = ask(Q.rational(expr.exp), assumptions)
  514. if not rat:
  515. return rat
  516. if ask(Q.integer(expr.exp), assumptions):
  517. return False
  518. else:
  519. half = ask(Q.integer(2*expr.exp), assumptions)
  520. if half:
  521. return ask(Q.negative(expr.base), assumptions)
  522. return half
  523. @ImaginaryPredicate.register(log) # type:ignore
  524. def _(expr, assumptions):
  525. if ask(Q.real(expr.args[0]), assumptions):
  526. if ask(Q.positive(expr.args[0]), assumptions):
  527. return False
  528. return
  529. # XXX it should be enough to do
  530. # return ask(Q.nonpositive(expr.args[0]), assumptions)
  531. # but ask(Q.nonpositive(exp(x)), Q.imaginary(x)) -> None;
  532. # it should return True since exp(x) will be either 0 or complex
  533. if expr.args[0].func == exp or (expr.args[0].is_Pow and expr.args[0].base == E):
  534. if expr.args[0].exp in [I, -I]:
  535. return True
  536. im = ask(Q.imaginary(expr.args[0]), assumptions)
  537. if im is False:
  538. return False
  539. @ImaginaryPredicate.register(exp) # type:ignore
  540. def _(expr, assumptions):
  541. a = expr.exp/I/pi
  542. return ask(Q.integer(2*a) & ~Q.integer(a), assumptions)
  543. @ImaginaryPredicate.register_many(Number, NumberSymbol) # type:ignore
  544. def _(expr, assumptions):
  545. return not (expr.as_real_imag()[1] == 0)
  546. @ImaginaryPredicate.register(NaN) # type:ignore
  547. def _(expr, assumptions):
  548. return None
  549. # AntihermitianPredicate
  550. @AntihermitianPredicate.register(object) # type:ignore
  551. def _(expr, assumptions):
  552. if isinstance(expr, MatrixBase):
  553. return None
  554. if ask(Q.zero(expr), assumptions):
  555. return True
  556. return ask(Q.imaginary(expr), assumptions)
  557. @AntihermitianPredicate.register(Add) # type:ignore
  558. def _(expr, assumptions):
  559. """
  560. * Antihermitian + Antihermitian -> Antihermitian
  561. * Antihermitian + !Antihermitian -> !Antihermitian
  562. """
  563. if expr.is_number:
  564. raise MDNotImplementedError
  565. return test_closed_group(expr, assumptions, Q.antihermitian)
  566. @AntihermitianPredicate.register(Mul) # type:ignore
  567. def _(expr, assumptions):
  568. """
  569. As long as there is at most only one noncommutative term:
  570. * Hermitian*Hermitian -> !Antihermitian
  571. * Hermitian*Antihermitian -> Antihermitian
  572. * Antihermitian*Antihermitian -> !Antihermitian
  573. """
  574. if expr.is_number:
  575. raise MDNotImplementedError
  576. nccount = 0
  577. result = False
  578. for arg in expr.args:
  579. if ask(Q.antihermitian(arg), assumptions):
  580. result = result ^ True
  581. elif not ask(Q.hermitian(arg), assumptions):
  582. break
  583. if ask(~Q.commutative(arg), assumptions):
  584. nccount += 1
  585. if nccount > 1:
  586. break
  587. else:
  588. return result
  589. @AntihermitianPredicate.register(Pow) # type:ignore
  590. def _(expr, assumptions):
  591. """
  592. * Hermitian**Integer -> !Antihermitian
  593. * Antihermitian**Even -> !Antihermitian
  594. * Antihermitian**Odd -> Antihermitian
  595. """
  596. if expr.is_number:
  597. raise MDNotImplementedError
  598. if ask(Q.hermitian(expr.base), assumptions):
  599. if ask(Q.integer(expr.exp), assumptions):
  600. return False
  601. elif ask(Q.antihermitian(expr.base), assumptions):
  602. if ask(Q.even(expr.exp), assumptions):
  603. return False
  604. elif ask(Q.odd(expr.exp), assumptions):
  605. return True
  606. raise MDNotImplementedError
  607. @AntihermitianPredicate.register(MatrixBase) # type:ignore
  608. def _(mat, assumptions):
  609. rows, cols = mat.shape
  610. ret_val = True
  611. for i in range(rows):
  612. for j in range(i, cols):
  613. cond = fuzzy_bool(Eq(mat[i, j], -conjugate(mat[j, i])))
  614. if cond is None:
  615. ret_val = None
  616. if cond == False:
  617. return False
  618. if ret_val is None:
  619. raise MDNotImplementedError
  620. return ret_val
  621. # AlgebraicPredicate
  622. @AlgebraicPredicate.register_many(AlgebraicNumber, Float, GoldenRatio, # type:ignore
  623. ImaginaryUnit, TribonacciConstant)
  624. def _(expr, assumptions):
  625. return True
  626. @AlgebraicPredicate.register_many(ComplexInfinity, Exp1, Infinity, # type:ignore
  627. NegativeInfinity, Pi)
  628. def _(expr, assumptions):
  629. return False
  630. @AlgebraicPredicate.register_many(Add, Mul) # type:ignore
  631. def _(expr, assumptions):
  632. return test_closed_group(expr, assumptions, Q.algebraic)
  633. @AlgebraicPredicate.register(Pow) # type:ignore
  634. def _(expr, assumptions):
  635. if expr.base == E:
  636. if ask(Q.algebraic(expr.exp), assumptions):
  637. return ask(~Q.nonzero(expr.exp), assumptions)
  638. return
  639. return expr.exp.is_Rational and ask(Q.algebraic(expr.base), assumptions)
  640. @AlgebraicPredicate.register(Rational) # type:ignore
  641. def _(expr, assumptions):
  642. return expr.q != 0
  643. @AlgebraicPredicate.register_many(asin, atan, cos, sin, tan) # type:ignore
  644. def _(expr, assumptions):
  645. x = expr.args[0]
  646. if ask(Q.algebraic(x), assumptions):
  647. return ask(~Q.nonzero(x), assumptions)
  648. @AlgebraicPredicate.register(exp) # type:ignore
  649. def _(expr, assumptions):
  650. x = expr.exp
  651. if ask(Q.algebraic(x), assumptions):
  652. return ask(~Q.nonzero(x), assumptions)
  653. @AlgebraicPredicate.register_many(acot, cot) # type:ignore
  654. def _(expr, assumptions):
  655. x = expr.args[0]
  656. if ask(Q.algebraic(x), assumptions):
  657. return False
  658. @AlgebraicPredicate.register_many(acos, log) # type:ignore
  659. def _(expr, assumptions):
  660. x = expr.args[0]
  661. if ask(Q.algebraic(x), assumptions):
  662. return ask(~Q.nonzero(x - 1), assumptions)