如何将 Reduce 输出转换为 Julia 符号表达式?

how to convert Reduce output to Julia symbolic expression?

在 Julia 中,我使用 Reduce 包进行集成,因为 Julia Symbolics.jl 中没有集成命令。

但我不知道如何将输出(反导数)转换为 Julia 符号表达式,因此我可以在 Julia 符号中使用它,而不是使用 Reduce 包。

这是我试过的

               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.7.1 (2021-12-22)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> using Symbolics    
julia> using Reduce    
julia> @variables x
1-element Vector{Num}:
 x

#use Reduce to do the integration
julia> output = :(int(sin(x),x)) |> rcall
:(-(cos(x)))

 julia> typeof(output)
 Expr

现在,我想使用 Julia Symbolics 将输出 -cos(x) 用作符号表达式。如何转换?

现在它按原样给出错误

julia> Symbolics.simplify(output^2)
ERROR: MethodError: no method matching ^(::Expr, ::Int64)
Closest candidates are:
  ^(::Union{AbstractChar, AbstractString}, ::Integer) at G:\nabbasi\data\CDROM\JULIA_language\julia-1.7.1-win64\julia-1.7.1\share\julia\base\strings\basic.jl:721
  ^(::LinearAlgebra.Diagonal, ::Integer) at G:\nabbasi\data\CDROM\JULIA_language\julia-1.7.1-win64\julia-1.7.1\share\julia\stdlib\v1.7\LinearAlgebra\src\diagonal.jl:196
  ^(::LinearAlgebra.Diagonal, ::Real) at G:\nabbasi\data\CDROM\JULIA_language\julia-1.7.1-win64\julia-1.7.1\share\julia\stdlib\v1.7\LinearAlgebra\src\diagonal.jl:195
  ...
Stacktrace:
 [1] literal_pow(f::typeof(^), x::Expr, #unused#::Val{2})
   @ Base .\intfuncs.jl:325
 [2] top-level scope
   @ REPL[9]:1

这是相同的输出,但现在是 Julia Symbolics 表达式:

julia> f=-cos(x)
-cos(x)

julia> typeof(f)
Num

julia> Symbolics.simplify( f^2)
cos(x)^2

如何将 Reduce 表达式的输出转换为 Julia Symbolics 表达式,以便进一步处理?

可以将 Reduce 输出转换为字符串

julia> g=string(output)
"-(cos(x))"

但现在不知道如何将上面的字符串转换为Symbolics 表达式。 parse 不起作用。可能有不同的命令?

参考资料

减少 Julia 包 https://docs.juliahub.com/Reduce/wEGBP/1.2.5/

Julia 符号包 https://symbolics.juliasymbolics.org/dev/

所以看起来这两个包(Reduce 和 Symbolics)在它们的符号表达式中使用了相当不同的格式。 Reduce 使用 Julia 的原生 Expr 类型,与用于表示 Julia 代码本身的类型相同,而 Symbolics 使用一种方法,在一个或多个指定为 @variables 的特殊变量上调用函数将 return 记录对这些变量执行的操作的对象:

julia> using Reduce, Symbolics

julia> a = :(-(cos(x)))
:(-(cos(x)))

julia> @variables x;

julia> b = -(cos(x))
-cos(x)

julia> typeof(a)
Expr

julia> typeof(b)
Num

要查看和比较这两个不同对象 ab 中的实际内容,我们可以使用 Julia 非常有用的 dump 函数:

julia> dump(a)
Expr
  head: Symbol call
  args: Array{Any}((2,))
    1: Symbol -
    2: Expr
      head: Symbol call
      args: Array{Any}((2,))
        1: Symbol cos
        2: Symbol x

julia> dump(b)
Num
  val: SymbolicUtils.Mul{Real, Int64, Dict{Any, Number}, Nothing}
    coeff: Int64 -1
    dict: Dict{Any, Number}
      slots: Array{UInt8}((16,)) UInt8[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00]
      keys: Array{Any}((16,))
        1: #undef
        2: #undef
        3: #undef
        4: #undef
        5: #undef
        ...
        12: #undef
        13: SymbolicUtils.Term{Real, Nothing}
          f: cos (function of type typeof(cos))
          arguments: Array{SymbolicUtils.Sym{Real, Base.ImmutableDict{DataType, Any}}}((1,))
            1: SymbolicUtils.Sym{Real, Base.ImmutableDict{DataType, Any}}
              name: Symbol x
              metadata: Base.ImmutableDict{DataType, Any}
                parent: Base.ImmutableDict{DataType, Any}
                key: Symbolics.VariableSource <: Any
                value: Tuple{Symbol, Symbol}
          metadata: Nothing nothing
          hash: Base.RefValue{UInt64}
            x: UInt64 0xd47301bdec8cde1c
        14: #undef
        15: #undef
        16: #undef
      vals: Array{Number}((16,)) Number[#undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef, 1, #undef, #undef, #undef]
      ndel: Int64 0
      count: Int64 1
      age: UInt64 0x0000000000000001
      idxfloor: Int64 13
      maxprobe: Int64 0
    sorted_args_cache: Base.RefValue{Any}
      x: Array{Any}((2,))
        1: Int64 -1
        2: SymbolicUtils.Term{Real, Nothing}
          f: cos (function of type typeof(cos))
          arguments: Array{SymbolicUtils.Sym{Real, Base.ImmutableDict{DataType, Any}}}((1,))
            1: SymbolicUtils.Sym{Real, Base.ImmutableDict{DataType, Any}}
              name: Symbol x
              metadata: Base.ImmutableDict{DataType, Any}
                parent: Base.ImmutableDict{DataType, Any}
                key: Symbolics.VariableSource <: Any
                value: Tuple{Symbol, Symbol}
          metadata: Nothing nothing
          hash: Base.RefValue{UInt64}
            x: UInt64 0xd47301bdec8cde1c
    hash: Base.RefValue{UInt64}
      x: UInt64 0x0000000000000000
    metadata: Nothing nothing

而且确实很不一样

但这并不是说您不能同时使用这两个包。由于 Expr 是用于将 Julia 代码表示为数据的类型,因此您需要做的就是 评估 Expr 以获得与您拥有的结果相同的结果调用其中的函数(不过,换一种方式是另一回事!)。所以我们可以这样写:

julia> output = :(int(sin(x),x)) |> rcall
:(-(cos(x)))

julia> output = eval(output)
-cos(x)

julia> Symbolics.simplify(output^2)
cos(x)^2

或者,您可以将 ^2 添加到 output,同时通过使用 Julia 的多种操作 Expr 的方法之一将其保持在 Expr 形式,并且仅稍后 eval 当你需要将它传递给 Symbolics:

julia> output = :(int(sin(x),x)) |> rcall
:(-(cos(x)))

julia> output_squared = :($output^2) # interpolate one Expr into another
:((-(cos(x))) ^ 2)

julia> Symbolics.simplify(eval(output_squared))
cos(x)^2

可能还有更多我不知道的高效方法,因为我没有广泛使用这两个包,并且使用 eval 可以说是有点 hack。但是,如果 Reduce 表达式中的函数定义为 Symbolics 知道的 Julia 函数(并且只要您在正确的范围内评估它们),这应该可以正常工作。