Basic question on Julia symbolic. How to keep exp(1) as is and not convert it to a floating point number?

I am converting some symbolic integrals to see if I can evaluate them in Julia symbolic. Some of these have things like exp(1) but Julia automatically convert this to number 2.718281828459045

What do I need to keep it as exp(1)? Here is an example

using Symbolics
@syms x 

julia> x*exp(1)
2.718281828459045x

Thanks
–Nasser

1 Like

How about ‘@syms o’ and ‘exp(o)‘ whenever you want to prevent evaluation?

Are you saying I should make 1 as @syms 1 ? I do not understand.
Could you please show in code how your suggestion will work for the example I’ve given so that the result will come out as x*exp(1)

julia> SymbolicUtils.Term(exp, [x])
exp(x)

julia> log(SymbolicUtils.Term(exp, [x]))
log(exp(x))
2 Likes
julia> using Symbolics

julia> Symbolics.Term(exp, 1)
exp(1)

julia> ans / ans
1

julia> Symbolics.Term(exp, ans)
exp(1)

julia> Symbolics.Term(exp, [ans])
exp(exp(1))

There are earlier threads on the same topic, btw:

2 Likes

Thanks, This helps a little. But for what I am doing, I see two problems.

I am trying to use the symbolic integrator at Home · SymbolicNumericIntegration.jl and when called with x*exp(1) it changes it back to floating point. Here is the code

using Symbolics
using SymbolicNumericIntegration
using SymbolicUtils

@syms x
expr=x*Symbolics.Term(exp,[1])

Gives x*exp(1) which is good. But now

julia> SymbolicNumericIntegration.integrate(expr,x)
(1.3591409142295223(x^2), 0, 2.220446049250313e-16)

So it changed it back to floating point.

Second issue. I am reading hundreds of integrals. with exp(1) and exp(25) and any other such expressions.

Is there a way to automate this, so that it automatically replaces exp( a_numeric_value) to Symbolics.Term(exp,[ a_numeric_value ]) so I do not have to manually edit hundreds of expressions and do this by hand for each case?

btw, thanks for the link you gave. I tried to replace the numbers with SymbolicValue(1) but it said it could not find SymbolicValue

julia> exp(SymbolicValue(1))
ERROR: UndefVarError: SymbolicValue not defined
Stacktrace:
 [1] top-level scope
   @ REPL[33]:1

julia> exp(Symbolics.SymbolicValue(1))
ERROR: UndefVarError: SymbolicValue not defined
Stacktrace:
 [1] getproperty(x::Module, f::Symbol)
   @ Base ./Base.jl:31
 [2] top-level scope
   @ REPL[34]:1

julia> exp(SymbolicUtils.SymbolicValue(1))
ERROR: UndefVarError: SymbolicValue not defined
Stacktrace:
 [1] getproperty(x::Module, f::Symbol)
   @ Base ./Base.jl:31
 [2] top-level scope
   @ REPL[35]:1

julia>

ps. I am newbie in Julia symbolics.

Fyi, tried this trick below, but it seems to broke things

>julia
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.8.0 (2022-08-17)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |


julia> using Symbolics
julia> using SymbolicNumericIntegration
julia> @syms x
(x,)

julia> exp(1)
2.718281828459045

julia> import Base: exp
julia> typeof(1)
Int64

julia> exp(x::Int64) = Symbolics.Term(exp,[x])
exp (generic function with 43 methods)

julia> exp(1)
exp(1)

julia> SymbolicNumericIntegration.integrate(x*exp(1),x)
ERROR: MethodError: no method matching zero(::Type{SymbolicUtils.Term{Real, Nothing}})
Closest candidates are:
  zero(::Union{Type{P}, P}) where P<:Dates.Period at /usr/share/julia/stdlib/v1.8/Dates/src/periods.jl:53
  zero(::Union{AbstractAlgebra.Generic.LaurentSeriesFieldElem{T}, AbstractAlgebra.Generic.LaurentSeriesRingElem{T}} where T<:AbstractAlgebra.RingElement) at ~/.julia/packages/AbstractAlgebra/ElVzc/src/generic/LaurentSeries.jl:466
  zero(::Union{AbstractAlgebra.Generic.LaurentSeriesFieldElem{T}, AbstractAlgebra.Generic.LaurentSeriesRingElem{T}} where T<:AbstractAlgebra.RingElement, ::String; cached) at ~/.julia/packages/AbstractAlgebra/ElVzc/src/generic/LaurentSeries.jl:480
  ...
Stacktrace:
 [1] DataDrivenDiffEq.STLSQ(threshold::Vector{SymbolicUtils.Term{Real, Nothing}})
   @ DataDrivenDiffEq ~/.julia/packages/DataDrivenDiffEq/s9jl3/src/optimizers/stlsq.jl:32
 [2] integrate(eq::SymbolicUtils.Mul{Number, Int64, Dict{Any, Number}, Nothing}, x::SymbolicUtils.Sym{Number, Nothing})
   @ SymbolicNumericIntegration ~/.julia/packages/SymbolicNumericIntegration/OUbIs/src/integral.jl:36
 [3] top-level scope
   @ REPL[9]:1

That’s not a thing. What are you trying to do?

"That’s not a thing. "

Did you check the link given in the answer where I was replying to which uses it there? I just copied it. Here is the link again

someone used SymbolicValue there. I have no idea where it came from.

That was proposed pseudocode, not actual code. That issue in DataDrivenDiffEq.jl is probably solvable if the element type is allowed to be set directly. The issue is that it’s exp(1) * x so exp(1) is the coefficient which is assumed to be numeric, and that is then used to set the numeric type in the STLSQ sparse regression, but since it’s symbolic it does not have numeric operations.

OK.
But back to main issue which is still not resolved.
How to make Julia not convert exp(1) to floating point? Would you know of a solution?

Few replies above I showed that once I call

SymbolicNumericIntegration.integrate(expr,x)

Then it converts exp(1) back to number looking at the result.

This is not how other CAS systems work.

Symbolics.Term(exp,[1])

That’s a SymbolicNumericIntegration issue because it’s a numerical algorithm, not a symbolic one.

Why not Symbolics.Term(exp, 1)?

They are always supposed to have an array of arguments (SymbolicUtils.jl/types.jl at master · JuliaSymbolics/SymbolicUtils.jl · GitHub)

Well, it says " hybrid symbolic/numerical integration package that works on the Julia Symbolics expressions."

Do you know of a different symbolic Julia integrator than the above? It is the only one I found when googling.

But I just opened an issue for the above package. Here is the link

That’s the only one right now.

Yes, and it’s symbolic-numeric, as in, it uses numerical methods to solve for the symbolic equation. So it needs to numerically evaluate, and it cannot keep a closed representation of transcendentals (nor algebraic variables, I think it can do rationals in some sense though?)

But it should be able to see that exp(1) is clearly a constant and keep it as is.

Hopefully in the future Julia will get a symbolic integrator added to it.

no, because a numerical integration methods cannot keep that as constant.

It will, it just hasn’t been done because they are generally slower and less robust than this new thing.

It’s neither here nor there: it has some upsides over other methods, and downsides over others. It’s just that given the SciML ecosystem, algorithms like this are extremely easy to write so it came first. There are some in Risch and rule-based methods in development, but of course those then have major trade-offs in speed and types of integrals they tend to fail on.

Is it expected that Symbolics.Term(exp, [1] ) is 100x slower than Symbolics.Term(exp, 1)?