Skip to content
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

LambertW not defined in SymPyCore #554

Closed
runjaj opened this issue Jan 17, 2025 · 3 comments
Closed

LambertW not defined in SymPyCore #554

runjaj opened this issue Jan 17, 2025 · 3 comments

Comments

@runjaj
Copy link

runjaj commented Jan 17, 2025

My system is running Julia 1.11.2 and SymPy.jl 2.2.1.

I solve the equation $x^x = t$ and want to plot $x$ versus $y$.

I solve the equation and I create a variable with it. I can use that variable as a function, but if I try to plot it, I get an error. I am pretty sure that I'm missing something.

This is what I do:

julia> @syms x t
(x, t)

julia> X = solve(x^x ~ t, x)[1]
 W(log(t))
ℯ         

julia> X(10) |> N
2.5061841455887692

julia> plot(X, 1, 10)
ERROR: UndefVarError: `LambertW` not defined in `SymPyCore`
Suggestion: check for spelling errors or missing imports.
Stacktrace:
  [1] var"##236"(t::Float64)
    @ SymPyCore ./none:0
  [2] #invokelatest#2
    @ ./essentials.jl:1055 [inlined]
  [3] invokelatest
    @ ./essentials.jl:1052 [inlined]
  [4] #151
    @ ~/.julia/packages/SymPyCore/1YJGM/src/lambdify.jl:380 [inlined]
  [5] call_composed (repeats 2 times)
    @ ./operators.jl:1053 [inlined]
  [6] (::ComposedFunction{ComposedFunction{…}, RecipesPipeline.var"#3#4"{…}})(x::Float64; kw::@Kwargs{})
    @ Base ./operators.jl:1050
  [7] ComposedFunction
    @ ./operators.jl:1050 [inlined]
  [8] (::PlotUtils.var"#23#25"{ComposedFunction{ComposedFunction{}, RecipesPipeline.var"#3#4"{}}})(x::Float64)
    @ PlotUtils ~/.julia/packages/PlotUtils/dVEMd/src/adapted_grid.jl:49
  [9] _broadcast_getindex_evalf
    @ ./broadcast.jl:673 [inlined]
 [10] _broadcast_getindex
    @ ./broadcast.jl:646 [inlined]
 [11] getindex
    @ ./broadcast.jl:605 [inlined]
 [12] copy(bc::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{…}, Tuple{…}, PlotUtils.var"#23#25"{…}, Tuple{…}})
    @ Base.Broadcast ./broadcast.jl:906
 [13] materialize
    @ ./broadcast.jl:867 [inlined]
 [14] adapted_grid(f::Any, minmax::Tuple{Float64, Float64}; max_recursions::Int64, max_curvature::Float64, n_points::Int64)
    @ PlotUtils ~/.julia/packages/PlotUtils/dVEMd/src/adapted_grid.jl:60
 [15] adapted_grid(f::Any, minmax::Tuple{Float64, Float64})
    @ PlotUtils ~/.julia/packages/PlotUtils/dVEMd/src/adapted_grid.jl:14
 [16] _scaled_adapted_grid(f::Function, xscale::Symbol, yscale::Symbol, xmin::Int64, xmax::Int64)
    @ RecipesPipeline ~/.julia/packages/RecipesPipeline/BGM3l/src/user_recipe.jl:322
 [17] macro expansion
    @ ~/.julia/packages/RecipesPipeline/BGM3l/src/user_recipe.jl:265 [inlined]
 [18] apply_recipe(plotattributes::AbstractDict{Symbol, Any}, f::Function, xmin::Number, xmax::Number)
    @ RecipesPipeline ~/.julia/packages/RecipesBase/BRe07/src/RecipesBase.jl:300
 [19] _process_userrecipes!(plt::Any, plotattributes::Any, args::Any)
    @ RecipesPipeline ~/.julia/packages/RecipesPipeline/BGM3l/src/user_recipe.jl:38
 [20] recipe_pipeline!(plt::Any, plotattributes::Any, args::Any)
    @ RecipesPipeline ~/.julia/packages/RecipesPipeline/BGM3l/src/RecipesPipeline.jl:72
 [21] _plot!(plt::Plots.Plot, plotattributes::Any, args::Any)
    @ Plots ~/.julia/packages/Plots/Ec1L1/src/plot.jl:223
 [22] plot(::Any, ::Vararg{Any}; kw...)
    @ Plots ~/.julia/packages/Plots/Ec1L1/src/plot.jl:102
 [23] plot(::Any, ::Any, ::Any)
    @ Plots ~/.julia/packages/Plots/Ec1L1/src/plot.jl:93
 [24] top-level scope
    @ REPL[36]:1
Some type information was truncated. Use `show(err)` to see complete types.

Fortunately, there is an easy solution:

julia> tt = 1:.1:10
1.0:0.1:10.0

julia> XX = X.(tt);

julia> plot(tt, XX)

Thanks in advance and have a nice weekend!

@jverzani
Copy link
Collaborator

Thanks.

The issue is the plot recipe calls lambdify which has a pretty basic translation of SymPy function (like LambertW to a corresponding Julia counter part. (This allows the computation of the values to be fast) As there isn't one here, it just assumes the same name in Julia and goes from there. This is why the error is thrown, there isn't such a function. When you evaluate XX = X.(t) that computation is done on the SymPy side where the LambertW function is defined and then the values are brought back to julia to plot.

I can think of a few possible fixes in this case:

  • It appears there is a package to compute this value in Julia, we could add this as a dependency and solve this problem and leave the others that will come up for another day.,
  • we could avoid lambdify in the plot recipe, though this might really slow things down it would be more general.
  • Maybe lambdify could be smarter about checking for missing symbols when the expression is evaluated and default to some slow function instead.

Something to think about

@runjaj
Copy link
Author

runjaj commented Jan 17, 2025

If it cannot be easily fixed, maybe this situation could just raise a warning explaining the problem.

@jverzani
Copy link
Collaborator

I just added a fix to give a warning when this is attempted. Thanks for bringing it to my attention.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants