12/10/2013

about 2 months ago

27 commits

The `Mathematica.jl`

package provides an interface for using Wolfram Mathematica™ from the Julia language. You cannot use `Mathematica.jl`

without having purchased and installed a copy of Mathematica™ from Wolfram Research. This package is available free of charge and in no way replaces or alters any functionality of Wolfram's Mathematica product.

The package provides is a no-hassle Julia interface to Mathematica. It aims to follow Julia's philosophy of combining high-level expressiveness without sacrificing low-level optimisation.

```
Pkg.add("Mathematica")
```

Provided Mathematica is installed, its usage is as simple as:

```
using Mathematica
Fibonacci(1000)
#=> 43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875
```

All of Mathematica's functions are available as both functions and macros, and splicing (`$`

) works as you would expect:

```
Integrate(:(x^2), :x) # or
@Integrate(x^2, x)
#=> :(*(1//3,^(x,3)))
@Integrate(log(x), {x,0,2})
#=> :(+(-2,log(4)))
eval(ans) # or
@N($ans) # or
N(ans) # or
@N(Integrate(log(x), {x,0,2}))
#=> -0.6137056388801094
```

Including those that return Mathematica data:

```
@Plot(x^2, {x,0,2})
#=> Graphics[{{{},{},{Hue[0.67, 0.6, 0.6],Line[{{4.081632653061224e-8,1.6659725114535607e-15},...}]}}}, {:AspectRatio->Power[:GoldenRatio, -1],:Axes->true, ...}]
```

Mathematical data can participate in Julia functions directly, with no wrapping required. For example -

```
using MathLink
d = BinomialDistribution(10,0.2) #=> BinomialDistribution[10, 0.2]
probability(b::MExpr{:BinomialDistribution}) = b.args[2]
probability(d) #=> 0.2
```

Julia compatible data (e.g. lists, complex numbers etc.) will all be converted automatically, and you can extend the conversion to other types.

Note that Mathematica expressions are *not* converted to Julia expressions by default. Functions/macros with the `::Expr`

hint (see below) will convert their result, but for others you must use `convert`

or `MathLink.to_expr`

.

```
Log(-1) #=> Times[0 + 1im, :Pi]
convert(Expr, ans) #=> :(*(0 + 1im,Pi))
N(Log(-1)) #=> 0.0 + 3.141592653589793im
```

Printing and warnings are also supported:

```
Print("hi")
#=> hi
@Print(x^2/3)
#=> 2
# x
# --
# 3
Binomial(10)
#=> WARNING: Binomial::argr: Binomial called with 1 argument; 2 arguments are expected.
#=> Binomial[10]
```

Finally, of course:

```
WolframAlpha("hi") #=>
2-element Array{Any,1}:
{{"Input",1},"Plaintext"}->"Hello."
{{"Result",1},"Plaintext"}->"Hello, human."
```

In the file `Mathematica.jl`

, you'll see a listing of function and macro specifications, each in one of these formats:

```
Function::ReturnType # or
Function(Arg1Type, Arg2Type, ...)::ReturnType # (functions only)
```

For example:

```
Integrate::Expr
RandomReal(Number)::Float64
RandomReal(Number, Integer)::Vector{Float64}
```

The return type hint here is an optimisation; it allows `MathLink.jl`

to grab the value from Mathematica without first doing a type check, and makes the function type stable - for example, `RandomReal(10, 5)`

would return an `Any`

array if not for this definition. The argument types allow type checking and multiple definitions.

Not many functions have type signatures yet, so providing them for the functions you want to use is an easy way to contribute.

The Mathematica data expression `Head[x,y,z,...]`

is represented in Julia as `MExpr{:Head}(args = {x,y,z,...})`

. We can extend `Mathematica.jl`

to support custom types by overloading `MathLink.to_mma`

and `MathLink.from_mma`

.

For example, we can pass a Julia Dict straight through Mathematica with just two lines of definitions:

```
using MathLink; import MathLink: to_mma, from_mma
d = [:a => 1, :b => 2]
to_mma(d::Dict) = MExpr{:Dict}(map(x->MExpr(:Rule, x[1], x[2]),d))
Identity(d) #=> Dict[:b->2, :a->1]
from_mma(d::MExpr{:Dict}) = Dict(map(x->x.args[1], d.args), map(x->x.args[2], d.args))
Identity(d) #=> {:b=>2,:a=>1}
```

```
using Mathematica
```

This should work so long as either `math`

is on the path (normally true on linux). `Mathematica.jl`

will also look for `math.exe`

on Windows, which should work for Mathematica versions 8 or 9 installed in default locations. If it doesn't work for you, open an issue (in particular I don't know how this will behave on Macs).

- Error handling: Error checking is currently reasonable, but the only way to reset the current link once an error is encountered is to restart Julia.
- Passing native arrays and matrices is not currently supported.
- MRefs: see the MVars section of clj-mma
- Connect to a running session and injecting callbacks to Julia functions would be really cool, but would probably require a C extension for Mathematica.