Skip to content

Commit

Permalink
allow keywords to be passed to weval and WSymbol/WExpr (JuliaInterop#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
simonbyrne authored and fgerick committed Jun 2, 2021
1 parent 23723d2 commit 74412ff
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 11 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This package provides access to Mathematica/Wolfram Engine via the MathLink libr

## Installation

The package requires a [Mathematica](http://www.wolfram.com/mathematica/) or [Wolfram Engine](https://www.wolfram.com/engine/) installation. It will attempt to find the installation at build time; if this fails, you will need to set the following environment variables:
The package requires an installation of either [Mathematica](http://www.wolfram.com/mathematica/) or the free [Wolfram Engine](https://www.wolfram.com/engine/). It will attempt to find the installation at build time; if this fails, you will need to set the following environment variables:
- `JULIA_MATHKERNEL`: the path of the MathKernel executable
- `JULIA_MATHLINK`: the path of the MathLink dynamic library named
- `libML64i4.so`/ `libML32i4.so` on Linux
Expand Down Expand Up @@ -48,7 +48,11 @@ julia> weval(W"Integrate"(sinx, (W"x", 0, 1)))
W"Plus"(1, W"Times"(-1, W"Cos"(1)))
```


Keyword arguments can be used to pass local variables
```julia
julia> weval(sinx; x=2.0)
0.9092974268256817
```

## Notes

Expand Down
26 changes: 22 additions & 4 deletions src/eval.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,37 @@ function handle_packets(link::Link, T)
end
end

function weval(link::Link, T, expr)
function weval(link::Link, T, expr; vars...)
if !isempty(vars)
expr = W"With"([W"Set"(WSymbol(k), v) for (k,v) in vars], expr)
end
put(link, W"EvaluatePacket"(expr))
endpacket(link)
handle_packets(link, T)
end

"""
weval([T,] expr)
weval([T,] expr; vars...)
Evaluate expression `expr`, returning a value of type `T` (default = `Any`).
If keyword arguments `vars` are provided, then `expr` is wrapped by a
[`With`](https://reference.wolfram.com/language/ref/With.html) block with `vars` assigned
as local constants.
```
julia> weval(W`Sin[x+2]`)
W"Sin"(W"Plus"(2, W"x"))
julia> weval(W`Sin[x+2]`; x=3)
W"Sin"(5)
julia> weval(W`Sin[x+2]`; x=3.0)
-0.9589242746631385
```
"""
weval(T, expr) = weval(_defaultlink(), T, expr)
weval(expr) = weval(Any, expr)
weval(T, expr; vars...) = weval(_defaultlink(), T, expr; vars...)
weval(expr; vars...) = weval(Any, expr; vars...)


function wevalstr(link, T, str::AbstractString)
Expand Down
66 changes: 61 additions & 5 deletions src/types.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,32 @@
"""
WSymbol
WSymbol(name::Union{String, Symbol})
W"..."
A Wolfram language symbol. The `W""` string macro can be used as a short form.
A `WSymbol` object is callable, which can be used to construct [`WExpr`](@ref)s (but doesn't evaluate it):
```julia
julia> W"Sin"
W"Sin"
julia> W"Sin"(1.0)
W"Sin"(1.0)
julia> weval(W"Sin"(1.0))
0.8414709848078965
```
Keyword arguments are passed as options:
```julia
julia> ex = W`Sqrt[x^2]`
W"Sqrt"(W"Power"(W"x", 2))
julia> assume = W`x<0`
W"Less"(W"x", 0)
julia> weval(W"Simplify"(ex, Assumptions=assume))
W"Times"(-1, W"x")
```
"""
struct WSymbol
name::String
Expand All @@ -14,20 +39,41 @@ macro W_str(str)
WSymbol(str)
end

"""
WReal(str::String)
A Wolfram arbitrary-precision real number.
"""
struct WReal
value::String
end
Base.show(io::IO, x::WReal) = print(io, x.value)

"""
WReal(str::String)
A Wolfram arbitrary-precision integer.
"""
struct WInteger
value::String
end
Base.show(io::IO, x::WInteger) = print(io, x.value)

"""
WExpr
WExpr(head, args)
A Wolfram language expression. Like [`WSymbol`](@ref) it is callable to construct more complicated expressions.
```julia
julia> W`Function[x,x+1]`
W"Function"(W"x", W"Plus"(W"x", 1))
julia> W`Function[x,x+1]`(2)
W"Function"(W"x", W"Plus"(W"x", 1))(2)
A Wolfram language expression.
julia> weval(W`Function[x,x+1]`(2))
3
```
"""
struct WExpr
head
Expand All @@ -50,5 +96,15 @@ function Base.show(io::IO, w::WExpr)
end


(w::WSymbol)(args...) = WExpr(w, args)
(w::WExpr)(args...) = WExpr(w, args)
function (w::WSymbol)(args...; kwargs...)
if !isempty(kwargs)
args = [args..., [W"Rule"(WSymbol(k), v) for (k,v) in kwargs]...]
end
WExpr(w, args)
end
function (w::WExpr)(args...; kwargs...)
if !isempty(kwargs)
args = [args..., [W"Rule"(WSymbol(k), v) for (k,v) in kwargs]...]
end
WExpr(w, args)
end
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import MathLink: WExpr, WSymbol
@test_throws MathLink.MathLinkError weval(Int, w)
@test weval(BigInt, w) == factorial(big(30))
@test weval(W"Factorial"(20)) === factorial(20)
@test weval(W`Factorial[x]`; x=20) === factorial(20)

@test weval(Float64, W"N"(W"Log"(factorial(big(30))),100)) == log(Float64(factorial(big(30))))
@test weval(BigFloat, W"N"(W"Log"(factorial(big(30))),100)) == log(factorial(big(30)))
Expand Down

0 comments on commit 74412ff

Please sign in to comment.