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.

#
#
# 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