JuliaInterop/MathLink.jl

W2Julia expects an Expr, not a WExpr.

Opened this issue · 6 comments

W2Julia expects an Expr to be returned, not WExpr.

Expr(:call , funcDict[ wexpr.head.name],[W2Julia(arg) for arg in wexpr.args])

or use W2JuliaExpr instead

W2JuliaExpr(wexpr::WExpr)=Expr(
    :call, 
    haskey(funcDict, wexpr.head.name) ? funcDict[wexpr.head.name] : wexpr.head.name, 
    [W2JuliaExpr(arg) for arg in wexpr.args]...
    )
W2JuliaExpr(wexpr::WSymbol) = Symbol(wexpr.name)
W2JuliaExpr(wexpr::Number) = wexpr

add Expr2Fcn to convert WExpr into a usable function.

getSymbols(sym::Symbol) = sym in values(funcDict) ? Vector{Symbol}() : [sym]
getSymbols(sym::Number) = Vector{Symbol}()
function getSymbols(expr::Expr)
    r = [getSymbols(exp) for exp in expr.args]
    rnew = []
    for rr in r::Vector
        append!(rnew, rr)
    end
    unique(rnew)
end

Expr2Fcn(expr::Expr,vars::Expr) = eval(Expr(:(->), vars, expr))
Expr2Fcn(expr::Expr) = Expr2Fcn(expr, Expr(:tuple, getSymbols(expr)...))
Expr2Fcn(wexpr::WExpr)= Expr2Fcn(W2JuliaExpr(wexpr))
Expr2Fcn(weval(W`mathematica expression`))

Hi @L2Fish:
I think there is some misunderstanding as to the usage to W2Julia here (probably because of the name)

W2Julia is designed primarily to convert wolfram structures to Julia structures. This includes conversions of Mathematica lists to Julia vectors and Mathematica associations to Julia dictionaries.

Some examples or tests that will evaluate to true:

using Test
@test W2Julia(W`{1,2,3}`) == [1,2,3]
@test W2Julia([1,2,3]) == [1,2,3]
@test W2Julia(W`{1,2,3}`) == [1,2,3]
@test W2Julia(W`{1,a,{1,2}}`) == [1,W"a",[1,2]]
@test W2Julia([.1,W`{1,a,3}`]) == [.1,[1,W"a",3]]

@test W2Julia(Dict( 1 => "A" , "B" => 2)) ==Dict( 1 => "A" , "B" => 2)

@test W2Julia(W`Association["A" -> "B", "C" -> "D"]`) == Dict( "A" => "B" , "C" => "D")

@test W2Julia(W`Association["A" -> {1,a,3}, "B" -> "C"]`) == Dict( "A" => [1,W"a",3] , "B" => "C")

W2Julia does not convert expressions to Julia functions, as not all functions will be able to evaluate when WSymbols are present.

Can you give an example test case of how you would like W2Julia to work for you?

as described here
How to copy Mathematica expression into a Julia function
They used PyCall to solve the problem.
However, I am looking forward to MathLink supporting this feature or even replacing SymEngine.
They haven’t implemented many functions yet, such as Eigenvalues, where mathmatica is very powerful.

@L2Fish I see what you want. I have now taken the first step and renamed W2Julia => W2JuliaStruct and introduced W2JuliaExpr as a new function. This is released as MathLink 0.6.0.

Below are some of the tests documenting its usage

        @test W2JuliaExpr(W`a+b`) == :(a+b)
        @test W2JuliaExpr(W`a*b`) == :(a*b)
        @test W2JuliaExpr(W`Sin[a]`) == :(sin(a))
        @test W2JuliaExpr(W`Sin[a+b]`) == :(sin(a+b))
        @test W2JuliaExpr(W`Cos[a^b]`) == :(cos(a^b))
        @test W2JuliaExpr(W`a/b`) == :(a*(b^-1))
        @test W2JuliaExpr(W`a^b`) == :(a^b)
        @test W2JuliaExpr(W`Exp[a]`) == :(exp(a))

I seems good to also do the second step and introduce the functions. Stay tuned.

@L2Fish I see what you want. I have now taken the first step and renamed W2Julia => W2JuliaStruct and introduced W2JuliaExpr as a new function. This is released as MathLink 0.6.0.

Below are some of the tests documenting its usage

        @test W2JuliaExpr(W`a+b`) == :(a+b)
        @test W2JuliaExpr(W`a*b`) == :(a*b)
        @test W2JuliaExpr(W`Sin[a]`) == :(sin(a))
        @test W2JuliaExpr(W`Sin[a+b]`) == :(sin(a+b))
        @test W2JuliaExpr(W`Cos[a^b]`) == :(cos(a^b))
        @test W2JuliaExpr(W`a/b`) == :(a*(b^-1))
        @test W2JuliaExpr(W`a^b`) == :(a^b)
        @test W2JuliaExpr(W`Exp[a]`) == :(exp(a))

I seems good to also do the second step and introduce the functions. Stay tuned.

believe that MathLink.jl will perform better.

I looked into it and i'm not sure how much automation one really wants to build in here. One can in principle build a function that automatically detects all the argument as creates a function for it. However, it seems to me that the user would need to know what the argument are in ny case in order to be able to sue it properly, and the code do construct such a functin is also a short oneliner :

ex = W2JuliaExpr(W`Sin[a]`)
fun = @eval (a) -> $ex
@test fun(0)  == sin(0)
@test fun(1)  == sin(1)

I'm thinking wrapping the fun = @eval (a) -> $ex in a function might just complicate things.

I'm thinking wrapping the fun = @eval (a) -> $ex in a function might just complicate things.

you're right.
I have two suggestions, one is to trigger a warning when automatically obtaining symbol variables, and the other is to add it as a reference suggestion in the readme file.