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