| 542 | |
| 543 | ######################################################################## |
| 544 | # |
| 545 | # Automatic Creation of Variable Names |
| 546 | # |
| 547 | # See the docstring for automatic_names below for an explanation of how |
| 548 | # this works. |
| 549 | # |
| 550 | ######################################################################## |
| 551 | |
| 552 | _automatic_names = False |
| 553 | # We wrap everything in a try/catch, in case this is being imported |
| 554 | # without the sage library present, e.g., in FEMhub. |
| 555 | try: |
| 556 | from sage.symbolic.all import Expression, SR |
| 557 | class AutomaticVariable(Expression): |
| 558 | """ |
| 559 | An automatically created symbolic variable with an additional |
| 560 | __call__ method designed so that doing self(foo,...) results |
| 561 | in foo.self(...). |
| 562 | """ |
| 563 | def __call__(self, *args, **kwds): |
| 564 | """ |
| 565 | Call method such that self(foo, ...) is transformed into |
| 566 | foo.self(...). Note that self(foo=...,...) is not |
| 567 | transformed, it is treated as a normal symbolic |
| 568 | substitution. |
| 569 | """ |
| 570 | if len(args) == 0: |
| 571 | return Expression.__call__(self, **kwds) |
| 572 | return args[0].__getattribute__(str(self))(*args[1:], **kwds) |
| 573 | |
| 574 | def automatic_name_eval(s, globals, max_names=10000): |
| 575 | """ |
| 576 | Exec the string s in the scope of the globals dictionary, and |
| 577 | if any NameError's are raised, try to fix them by defining the |
| 578 | variable that caused the error to be raised, then eval again. |
| 579 | Try up to max_names times. |
| 580 | |
| 581 | INPUT: |
| 582 | |
| 583 | - `s` -- string |
| 584 | - ``globals`` -- a dictionary |
| 585 | - ``max_names`` -- a positive integer (default: 10000) |
| 586 | """ |
| 587 | # This entire automatic naming system really boils down to |
| 588 | # this bit of code below. We simply try to exec the string s |
| 589 | # in the globals namespace, defining undefined variables and |
| 590 | # functions until everything is defined. |
| 591 | for _ in range(max_names): |
| 592 | try: |
| 593 | exec s in globals |
| 594 | return |
| 595 | except NameError, msg: |
| 596 | # Determine if we hit a NameError that is probably |
| 597 | # caused by a variable or function not being defined: |
| 598 | if len(msg.args) == 0: raise # not NameError with specific variable name |
| 599 | v = msg.args[0].split("'") |
| 600 | if len(v) < 2: raise # also not NameError with specific variable name |
| 601 | # We did find an undefined variable: we simply define it and try again. |
| 602 | nm = v[1] |
| 603 | globals[nm] = AutomaticVariable(SR, SR.var(nm)) |
| 604 | raise NameError, "Too many automatic variable names and functions created (limit=%s)"%max_names |
| 605 | |
| 606 | def automatic_name_filter(s): |
| 607 | """ |
| 608 | Wrap the string `s` in a call that will cause evaluation of |
| 609 | `s` to automatically create undefined variable names. |
| 610 | |
| 611 | INPUT: |
| 612 | |
| 613 | - `s` -- a string |
| 614 | |
| 615 | OUTPUT: |
| 616 | |
| 617 | - a string |
| 618 | """ |
| 619 | return '_support_.automatic_name_eval(_support_.base64.b64decode("%s"),globals())'%base64.b64encode(s) |
| 620 | |
| 621 | def automatic_names(state=None): |
| 622 | """ |
| 623 | Turn automatic creation of variables and functional calling of |
| 624 | methods on or off. Returns the current state if no argument is |
| 625 | given. |
| 626 | |
| 627 | This ONLY works in the Sage notebook. It is not supported on the |
| 628 | command line. |
| 629 | |
| 630 | INPUT: |
| 631 | |
| 632 | - ``state`` -- None or bool |
| 633 | |
| 634 | EXAMPLES:: |
| 635 | |
| 636 | sage: automatic_names(True) # not tested |
| 637 | sage: x + y + z # not tested |
| 638 | x + y + z |
| 639 | |
| 640 | Here, trig_expand, y, and theta are all automatically |
| 641 | created:: |
| 642 | |
| 643 | sage: trig_expand((2*x + 4*y + sin(2*theta))^2) # not tested |
| 644 | 4*(sin(theta)*cos(theta) + x + 2*y)^2 |
| 645 | |
| 646 | IMPLEMENTATION: Here's how this works, internally. We define |
| 647 | an AutomaticVariable class derived from Expression. An |
| 648 | instance of AutomaticVariable is a specific symbolic variable, |
| 649 | but with a special call method. We overload the call method |
| 650 | so that ``foo(bar, ...)`` gets transformed to ``bar.foo(...)``. At |
| 651 | the same time, we still want expressions like `f^2 - b` to |
| 652 | work, i.e., we don't want to have to figure out whether a name |
| 653 | appearing in a NameError is meant to be a symbolic variable or |
| 654 | a function name. Instead, we just make an object that is both! |
| 655 | |
| 656 | This entire approach is very simple---we do absolutely no |
| 657 | parsing of the actual input. The actual real work amounts to |
| 658 | only a few lines of code. The primary catch to this approach |
| 659 | is that if you evaluate a big block of code in the notebook, |
| 660 | and the first few lines take a long time, and the next few |
| 661 | lines define 10 new variables, the slow first few lines will |
| 662 | be evaluated 10 times. Of course, the advantage of this |
| 663 | approach is that even very subtle code that might inject |
| 664 | surprisingly named variables into the namespace will just work |
| 665 | correctly, which would be impossible to guarantee with static |
| 666 | parsing, no matter how sophisticated it is. Finally, given |
| 667 | the target audience: people wanting to simplify use of Sage |
| 668 | for Calculus for undergrads, I think this is an acceptable |
| 669 | tradeoff, especially given that this implementation is so |
| 670 | simple. |
| 671 | """ |
| 672 | global _automatic_names |
| 673 | if state is None: |
| 674 | return _automatic_names |
| 675 | _automatic_names = bool(state) |
| 676 | |
| 677 | except ImportError: |
| 678 | |
| 679 | pass |
| 680 | |