-
-
Notifications
You must be signed in to change notification settings - Fork 61
adding evaluate_without_side_effects for helping compile expressions.
#1539
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
| self.var = var | ||
|
|
||
|
|
||
| def evaluate_without_side_effects( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if this is the right place for this function.
| for name, defin in SIDE_EFFECT_BUILTINS.items(): | ||
| # Change the definition by a temporal definition setting | ||
| # just the name and the attributes. | ||
| definitions.builtin[name] = Definition( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe these definitions can be stored in some place, and then each time we compile something, bring them up, instead of constructing them each time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The two obvious places to start alternate representations or approximate computations of an expression (where a symbol is considered to be an expression) are either inside the compound Expression object or inside a definitions entry.
I suspect we'll need to make a pass over the definitions table at some point. As with so many other things, it is one of those dark areas where, I suspect, things are a bit unconventional from both the conventional compiler standpoint as well as how WMA thinks of scoping.
| = 2.18888 | ||
| Loops and variable assignments are supported usinv Python builtin "compile" function: | ||
| >> Compile[{{a, _Integer}, {b, _Integer}}, While[b != 0, {a, b} = {b, Mod[a, b]}]; a] (* GCD of a, b *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test was wrong in many ways. On the one hand, this expression shows the following warning in WMA:
Compile::argset:
The assignment to a is illegal; it is not valid to assign a value to an
argument.
Then, if we try to evaluate the compiled function, we get more errors, and an unfinished loop.
The expected result is also wrong in another way: it expects the wrong behaviour, where the expression is fully evaluated before compiling, to get a. The new test is something that actually works in WMA, and produces the expected behavior.
| """ | ||
|
|
||
| attributes = A_HOLD_ALL | A_PROTECTED | A_N_HOLD_ALL | A_READ_PROTECTED |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These attributes are very important: they prevent the evaluation of the original compiled expression.
|
I have this sinking gut feeling that this kind of piecemeal approach will not serve us well in the long term. How we handle scope and variables is probably something that needs more thought. I know how complation is handled definitely needs more thought. So, probably we should come back to this after the dust settles with vectorizing for graphs. |
…nto evaluate_without_side_effects
In that vein, isn't it the case that what needs to be banned here is not all side effects, but side effects at global scope? Side effects within a Module should be fine, right? Since we don't support Modules in plot_compile at this point banning all side effects doesn't lose us anything, from the perspective of Plot. It would be (low priority) cool if someday we could do something like this example that ChatGPT helped me come up with when I asked for a cool demo that uses procedural programming to generate a plot. This creates fractal-ish landscapes by superimposing sine waves. I had it working in a hacky demo-level sort of way in an early prototype of plot_compile, but I jettisoned it when I found out about lambdify. This would need some kind of hybrid approach. |
What I am trying to address here is the problem that all these side effects should not be handled in the evaluation previous to a sympy conversion. Then, there is another problem related with how to handle these side effects at the level of sympy. Conditional expressions can be handled using |
I get that. What I suggest then is to study how this kind of thing is done in a compiler using symbol tables and scopes instead of trying to reinvent it through writing some code. While I know, first hand, it can be fun to learn stuff this way through trial and error, using a large shared codebase to do it on is distracting and can be painful for others. |
The problem is understanding when there is a side effect, which scope it is at, and how this changes things aliased via rewrite rules. My own experience with this code base is that I don't trust that it has been thought out carefully. And WMA probably adds its own idiosyncrasies, because, well, it can. There's no written-down standard that WMA has to follow, and if there's a deviation from standard practice, it can declare however it coded things as "standard" without even needing to explain its implementation. |
I don't know if it will help, but right now |
|
Sorry for the noise. It seems I screw up my |
|
I take it back - it turns out that the above example with a To take a simpler example, this function after the initial evaluation has been expanded into the non-procedural expression which converts to the sympy expression and compiles to the Python function (This works in the If you want to try it for yourself, in https://github.com/bdlucas1/mathics-m3d
|

This PR adds a helper function for evaluating expressions, keeping unevaluated those expressions that could have side effects, like changing the value of a variable. This could be useful to convert (compile) expressions into Python functions.
Let' s consider the following WL code:
F[x,y]is a convoluted way to write (x+IntegerPart[y]), but I imagine more complicated cases where this kind of construction is needed.If we use the vectorized version of
Plot3D,F[x,y]is compiled to a vectorized Python function through the functionplot_compile.plot_compile(evaluation,expr, ...)tryies to convertF[x,y]into a Sympy expression. To do that, it needs to evaluate firstF[x,y]into an expression involving justx,y, and built-in symbols. In the current implementation, this is done by first evaluating the expressionexpr(expr = expr.evaluate(evaluation)), and then trying to convert it to sympy. But in the case of the example, evaluatingF[x,y]results inx, and leaves assigned the symbolawith the symbolx, which is an undesired side effect.This PR should avoid the evaluation of
Do,Set, andCompoundExpression. This makes the conversion to sympy fail, forcing the evaluation to use the standard method.In another round, we could also provide suitable conversions to SymPy for these symbols, allowing a proper vectorized implementation.