Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion test/core/convert/test_lambdify_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,13 @@
dict(name="Which", args=[False, 1, True, 2]),
dict(name="Which", args=[False, 1, True, 2, False, 3]),
#
# Certain procedure constructs can be handled provided the initial
# evaluation in lambdify_compile is able to expand them to a
# non-procedural expression
#
dict(name="Module[{sum=0, i}, For[i=1, i<=3, i++, sum += Sin[i #]]; sum]&", args=[1]),
Copy link
Contributor

@mmatera mmatera Dec 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, this case works. But what about

Module[{sum=0, i}, For[i=1, i<=#, i++,  sum += Sin[i #]]; sum]&

?
This shuld be something equivalent to Sum[Sin[i*x],{i,1,x}], however, if it is evaluated before giving a value to x, the result is 0.. This expression tricks lambdify_compile. Ideally, when an expression like this is passed to Plot or to Compile, a wrapper function should be returned, that carries the regular evaluation of the expression, when the argument takes a numerical value.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, thanks. I think I see where I went wrong. Because an If expression like this is left unevaluated if n does not have a value and therefore the conditional can't be evaluated:

In[1]:= If[0<n,3,4]
Out[1]= If[0 < n, 3, 4]

I thought the same would apply to the Module - the whole thing would remain unevaluated because the conditional in the For couldn't be evaluated, and therefore the Module would remain after evaluation and the compilation would fail, rather than giving the wrong answer. But now I see that isn't the case, for example (swapping out If for For for simplicity):

(* n is not bound so If can't be evaluated, but still Module presses on *)
In[2]:= Module[{sum=0},If[0<n,sum:=17, sum:=18];sum]
Out[2]= 0

(* everything can now be evaluated, side effects are different, result is different *)
In[3]:= Module[{sum=0},If[0<1,sum:=17, sum:=18];sum]
Out[3]= 17

(* verifying that the If is not evaluated *)
In[6]:= Module[{sum=0},If[0<n,sum:=17, sum:=18]]
Out[6]= If[0 < n, sum$3 := 17, sum$3 := 18]

In other words, even though the If inside the Module remains unevaluated, that doesn't stop Module from
evaluating everything else in the Module that it can, local side effects and all, ignoring the fact that those local side effects might be different if everything could be evaluated.

So given that this test case relies on accidentally correct behavior, I'll withdraw it. Handling compilation of Module correctly doesn't seem high priority to me from the perspective of my main concern, plotting.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handling compilation of Module correctly doesn't seem high priority to me from the perspective of my main concern, plotting.

Handling compilation has been identified as something to work on. From: FUTURE, Other stuff:

Major components that still need revision/rewrite

Efficient pattern matching
Documentation
Start a real instruction-driven interpreter
Compile system
Rewrite how Graphics Routines are implemented and implement a robust API for extending

The situation, however, is that each of these may need deeper thought and a bit of work, and we are severely limited in the number of people and time available to work on these projects.

For example, right now, the agreed-upon priority has been to get boxing more like WMA, and that work has been lagging. With respect to the item "Rewrite how Graphics Routines are implemented and implement a robust API for extending", while I appreciate this bumps into "Compile system" and "Start a real instruction-driven interpreter", the aspect implement a robust API for extended part could be worked on.

#
#
# Following have no sympy_name and no mpmath_name,
# but do have "number" or "numeric" in their path.
# Some may be possible candidates for building out compilation
Expand Down Expand Up @@ -447,7 +454,7 @@ def failure(name, msg):
elif fail:
raise Exception(f"unexpected success: result {result}, expected {expected}")
else:
# print(f"{name} succeeds: expected {expected.value}, got {result}")
# print(f"{name} succeeds: expected {expected}, got {result}")
pass


Expand Down
Loading