sets.py 25 KB

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