|
16 | 16 | environment. |
17 | 17 | """ |
18 | 18 |
|
| 19 | +import sympy |
| 20 | + |
19 | 21 | from mathics.core.attributes import ( |
20 | 22 | A_HOLD_ALL, |
21 | 23 | A_HOLD_REST, |
22 | 24 | A_PROTECTED, |
23 | 25 | A_READ_PROTECTED, |
24 | 26 | ) |
25 | | -from mathics.core.builtin import Builtin, InfixOperator, IterationFunction |
| 27 | +from mathics.core.builtin import ( |
| 28 | + Builtin, |
| 29 | + InfixOperator, |
| 30 | + IterationFunction, |
| 31 | + SympyFunction, |
| 32 | +) |
26 | 33 | from mathics.core.evaluation import Evaluation |
27 | 34 | from mathics.core.expression import Expression |
28 | 35 | from mathics.core.interrupt import ( |
@@ -365,7 +372,7 @@ def eval(self, start, test, incr, body, evaluation): |
365 | 372 | return SymbolNull |
366 | 373 |
|
367 | 374 |
|
368 | | -class If(Builtin): |
| 375 | +class If(SympyFunction): |
369 | 376 | """ |
370 | 377 | <url>:WMA link:https://reference.wolfram.com/language/ref/If.html</url> |
371 | 378 |
|
@@ -443,6 +450,26 @@ def eval_with_false_and_other(self, condition, t, f, u, evaluation): |
443 | 450 | else: |
444 | 451 | return u.evaluate(evaluation) |
445 | 452 |
|
| 453 | + def to_sympy(self, expr, **kwargs): |
| 454 | + if len(expr.elements) == 3: |
| 455 | + sympy_cond = expr.elements[0].to_sympy(**kwargs) |
| 456 | + sympy_true = expr.elements[1].to_sympy(**kwargs) |
| 457 | + sympy_false = expr.elements[2].to_sympy(**kwargs) |
| 458 | + if sympy_cond is None: |
| 459 | + return |
| 460 | + # sympy.Piecewise is is picky as to what type of conds it will accept, |
| 461 | + # allowing Boolean, Relational, and Symbol (as an honorary Boolean, |
| 462 | + # accompanied by a comment in the code that this isn't really correct). |
| 463 | + # Seems an attempt at early typechecking, but maybe too restrictive - |
| 464 | + # what about Exprs in general that might or might not evaluate to Boolean? |
| 465 | + # See similar code in mathics.builtin.arithmetic.ConditionalExpression. |
| 466 | + if ( |
| 467 | + sympy_cond.is_Boolean |
| 468 | + or sympy_cond.is_Relational |
| 469 | + or sympy_cond.is_Symbol |
| 470 | + ): |
| 471 | + return sympy.Piecewise((sympy_true, sympy_cond), (sympy_false, True)) |
| 472 | + |
446 | 473 |
|
447 | 474 | class Interrupt(Builtin): |
448 | 475 | r""" |
@@ -648,7 +675,7 @@ def eval_with_tag( |
648 | 675 | raise WLThrowInterrupt(value, tag) |
649 | 676 |
|
650 | 677 |
|
651 | | -class Which(Builtin): |
| 678 | +class Which(SympyFunction): |
652 | 679 | """ |
653 | 680 | <url> |
654 | 681 | :WMA link: |
@@ -710,6 +737,15 @@ def eval(self, items, evaluation): |
710 | 737 | items = items[2:] |
711 | 738 | return SymbolNull |
712 | 739 |
|
| 740 | + def to_sympy(self, expr, **kwargs): |
| 741 | + if len(expr.elements) % 2 == 0: |
| 742 | + args = [] |
| 743 | + for cond, value in zip(expr.elements[::2], expr.elements[1::2]): |
| 744 | + sympy_cond = cond.to_sympy(**kwargs) |
| 745 | + sympy_value = value.to_sympy(**kwargs) |
| 746 | + args.append((sympy_value, sympy_cond)) |
| 747 | + return sympy.Piecewise(*args) |
| 748 | + |
713 | 749 |
|
714 | 750 | class While(Builtin): |
715 | 751 | """ |
|
0 commit comments