I've been playing it for a few days now, and it's such a joy to work with. So many great forward-thinking libraries: (Reactive, Compose), excellent, readable code quality even down to the language implementation from very smart people...
If the language stack of the future looks something like Rust for systems, Julia for applications, and Elm for UI, I'll be a pretty happy developer :)
The second problem is also not clear. Is there a Kronecker substitution on the input? If so, what are the degrees? I'd like to see the code used.
The code is in the Benchmarks test in test/Benchmark-test.jl.
It's not surprising the first benchmark is faster in Maple, since Maple can make use of a true sparse representation, possibly quite a bit of vectorisation on the processor you have and possibly multiple cores. The benchmark here uses only a dense representation, a single core and there is no explicit vectorisation (possibly none at all).
Pihanha for example will do both of those first examples in a fraction of the time that Nemo will. But again, it uses sparse representation and again can use multiple cores.
We'll do a sparse representation in Nemo later on, perhaps even wrap Pirhana.
The main purpose of the benchmark is actually to show off what the really fast Julia generics do for us, not to actually do this particular benchmark as fast as is humanly possible. In order to do that as fairly as possible, we deliberately use univariate polynomials over other univariate polynomials in all systems (except Pari, as noted), rather than dedicated multivariate polynomial rings.
That first benchmark is pretty dense, so it's not at all unreasonable to use KS.
On the other hand, if we force it to use KS for Z[x][y][z][t] down to Z[x][y], then classical down to Z[x], then Flint for Z[x] itself, it gets marginally faster, with 40.6s.
Clearly neither of these approaches is an optimal strategy, as the Maple timings show.
>>> from sympy import *
>>> from time import clock
>>> var('x y z t')
(x, y, z, t)
>>> f = poly(1 + x + y + z + t)
>>> p = f ** 20
>>> t1=clock(); q=p*(p+1); clock()-t1
53.828634
julia> using Nemo
julia> Rx,x=PolynomialRing(ZZ,"x");
julia> Ry,y=PolynomialRing(Rx,"y");
julia> Rz,z=PolynomialRing(Ry,"z");
julia> Rt,t=PolynomialRing(Rz,"t");
julia> p = (1+x+y+z+t)^20;
julia> @time p*(p+1);
1.593379 seconds (129.24 k allocations: 6.758 MB, 0.82% gc time)
Edit: oops, I forgot a variable which made the benchmark totally unfair!Is it ? At least that's not the part that excites me most, although its a nice by product to have. Its a nice flexible language with good syntax and a good set of features. I still dislike 1 based indexing though.
Nemo uses some of the same libraries under the hood, but there's much less overhead. This is in part due to Julia being faster than Python (although Sage works around that to some extent by using Cython), and in part due to Nemo using tighter algorithms/code.
Note that Nemo is currently more geared towards purely algebraic computation, though. It doesn't currently have S-expressions with support for symbolic integration and the like (Sage mostly uses Pynac and Maxima for this).
Julia is JIT-compiled, a Lisp (under the hood) and (somewhat) dependently typed.
Is that enough to port (or even transpile) modules from the big open source CAS without an entire rewrite? Is there enough similarity between CAS to make "foreign" modules even a remote possibility?
Otherwise, Nemo will likely not achieve a great unification of math packages, since the required effort goes way beyond the resources of a small dedicated group.
Every expression is transformed internally to an AST representation that can be seen as a lisp-style s-expression. And this gets transformed, JIT-compiled, and so on. [1]
Furthermore, the Julia internals contain an entire lisp implementation (femtolisp [2]). That has influenced the metaprogramming capabilities.
> And I didn't see dependent types mentioned in the page below despite some things sounding similar.
Integer matrices can be represented as Array{Int64,2}. So the type of the matrix depends on the Int64 datatype and the dimensionality 2. But that's not necessarily what type theorists understand to be a dependent type. There was an epic discussion that led to the phrasing "dependent" being removed from the Julia docs. [2]
[1] http://julia.readthedocs.org/en/latest/manual/metaprogrammin...
[2] https://github.com/JuliaLang/julia/tree/master/src/flisp
Personally I want to know how to define algebraic number classes. I attempted and failed write my own algebraic number types in Python.
I should point out we actually spent some time speeding up that particular benchmark. The others are much more raw.
Having said that, we have an even faster way of doing it which will be in Nemo 0.4.
It's worth noting though that Pari doesn't have Jit compilation, so it would still be possible to beat something written in Pari/GP for example.
One of the big things with complex functionality like that in Pari is that years of mathematical knowledge have gone into it. One can't come along with some tricks like Jit compilation and expect to beat it with some simple scripts. It actually took months of work on the Antic library to get faster algebraic number field element arithmetic than what was already in Pari, and that's trivial functionality compared to the rest of Pari.
The winning strategy isn't actually to reimplement the whole of Pari (or Singular, or Gap, etc.) but to use them for complex functionality that they are actually good at, and then either improve Pari itself, or implement something even better over time, say by extending Antic.