Julia: A Fast Language for Numerical Computing
sinews.siam.org
sinews.siam.org
Now I'm instead trapped with Go, which lacks a REPL, and leaves a lot to wish in terms of metaprogramming capabilities needed to create a nice programmatic API.
The lack of the mentioned features is my biggest concern with Julia.
For example one could use a monadic style data structure such .NET's reactive Observable (which has an analog in many different languages) and allow you to compose a stream like definition independent of how it runs. You can then feed this definition (Observable) to an evaluator which could run it on Go using channels or it could run it on Go using a cluster of machines with ZeroMQ.
I think the selling point to your library is that it compiles to native code but my question is with out changing code can I switch to running it on a cluster instead of local (something I could do with a language with an abstract form of concurrency using monads or Observables or even just using the Actor model)? It looks like I can right?
That is, for multi-node jobs. As long as you can stay within the 16-32 or so cores on a typical HPC node (in our cluster at least), scipipe should be great for that. I think some means of simple resource management (to not overstress these 16-32 cores) is needed, but that can be done in a simple way by e.g. using a central go-routine that lends out "the right to use a cpu core" on demand.
Thanks for interesting feedback. I will think about this!
In either case I couldn't get my head around how to implement this.
In Go, the implementation is conceptually extremely simple (although the code might not always be the most readable).
From what I can see in the docs I'm getting afraid Dask does the same mistake as so many other recent tools: Allow only task dependencies, while what is needed in general scientific workflows is data dependencies (connect outports and inports of process). I have explained this difference in a blog post earlier: http://bionics.it/posts/workflows-dataflow-not-task-deps
(UPDATE: in all fairness, they seem to be doing something in-between, a little like Snakemake, in that they allow to specify data inputs based on a naming scheme. What we want is a totally naming scheme independent declarative way of explicitly connecting one output to one input, as that is the most generic and pluggable way you could do it.)
If they allow true data dependencies though, that would be very interesting.
How about this? https://github.com/shashi/ComputeFramework.jl
But I suspect it has the same problem.
Edit: There is also this https://github.com/JuliaDB/DataStreams.jl
http://docs.julialang.org/en/release-0.4/manual/parallel-com...
Which to me as Limbo programmer, look like channels, even across machines.
This is common practice in bioinformatics already, because of the large plethora of tools which would be too much to rewrite for any particular language.
Then, Go will probably be OK for more mundane tasks such as data pre-processing, filtering, etc etc.
Otherwise, there are in fact some scientific Go libraries already, including BioGo [1] and GoChem [2].
This would mean that we could automatically create true struct-based components with channel fields from the shell like syntax used in the examples in the README (like "echo > {o:foo}" to write to an out-port named "foo"), so that connecting an out-port to an in-port would go like:
Process2.InFoo = Process1.OutFoo
This is not possible with Go's reflection though, so right now, based on these shell like patterns, we can only populate maps (InPorts and OutPorts) of the process, such that the above code example becomes:
Process2.InPorts["foo"] = Process1.OutPorts["foo"]
I don't understand why you'd want to do that. That sounds like an architecture you are excited about, not a problem you are trying to solve. Can you give me some context?
I toyed around with it for a while, and really liked it. I wondered to myself "what makes this language specific to numerical computing? it seems generic enough to be used wherever I'd want to use Ruby or Haskell..."
But then I tried using it. And even though the language is generic enough, the standard library just plain assumes you're only doing numerical computing, and makes everything else needlessly hard by trivial omissions.
That was like 2013 though, so maybe things are different now?
Package management system is its only weak point IMO. It makes a lot of counter-intuitive decisions (having to build a package from the packages directory? that's just strange). Cargo / Bundler to me feel like the gold standard in package management... most alternatives I've seen would be better off just copying those workflows unless there's a really good reason to try something new.
So no huge projects, but I found Julia to be a very nice and versatile language to work in. I find I can write code which is clearer than its corresponding Python and Ruby version and which has less bugs because type info is a bit more explicit, but without getting too much in the way as is typical with statically typed languages.
I tried Haskell for some of the same projects, but I got to say Haskell takes way longer time to get proficient in. For the stuff I did I also found the way the Julia type system worked, made code reuse much easier than Haskell.
E.g. with the Julia Union type it was possible to define individual function across multiple specific types. E.g. I could make a particular implementation of f apply to type A, B and C, while another particular implementation of f applies to D and E. Function g could have a specific implementation of A and E. While another implementation of g is used for B and C.
That's one of my current obstacles to diving further into Julia.
I have found it an excellent language, as easy as Python to pick up and some great numerical primitives.
Using Juliabox in class means no installation woes and means whatever I do during lessons is available wherever I can get online. The ability to mix in markdown and code on the same page is brilliant for keeping notes. I realise that is not a feature of Julia but still, it is a benefit.
I've not done any heavy work in it but I'm really looking forward to doing so. I can dump Python, Octave and Limbo all at the same time.
Also, although this is of course a preference, 1-based indexing. I would rather have compatibility with C and Python and I don't care one bit about compatibility with Matlab.
These decisions make it seem that Julia just aspires to be "open source Matlab" when that already exists. It could instead aspire to be the good programming language that Matlab isn't.
Yup, we fixed that (deprecated in the latest release, will be switched over). It was super annoying.
There's been lots said on the 1-based indexing discussion, so I won't get into it here, but I can guarantee you that "open source Matlab" is not the ambition. Our ambition is to be the best possible programming language for technical computing and a great language for programming overall.
It's not a deal-breaker, I suppose. Still, the rationale I've heard -- "We have chosen 1 to be more similar to existing math software"[1] (as opposed to basically every modern programming language out there) just seems... weird. Perhaps "compatibility with traditional sequence notation in math and physics" (upon which presumably most software packages are based) would be a better statement of the case for 1-based indexing.
Advanced Julians actually go for 2-based indexing [1].
See [2] for more on this...
[1] https://github.com/simonster/TwoBasedIndexing.jl [2] https://groups.google.com/forum/?hl=en#!topic/julia-dev/tNN7...
The difference between the two is that when solving PDEs, accuracy is paramount, so even using single precision is a bit of a compromise, whereas in machine learning, the trend seems to be to use half-precision or lower, sacrificing accuracy for speed.
For classical numerical computing, e.g. solving PDEs or linear equations, Java may not be the best choice, e.g. see the following paper:
How Java's Floating Point Hurts Everyone Everywhere:
The speed depends on the blas implementation.
Nd4j has a concept of "backends". Nd4j backends allow us to sub in different blas implementations as well as different ways of doing operations.
We have a data buffer type that allows people to specify floating point or double. Those data buffers then have an allocation type that can be javacpp pointers,nio byte buffers (direct/offheap) or normal arrays
We are also currently working on surprassing the jvm's memory limits ourselves via javacpp's pointers. That allows us to have 64 bit addressing which people normally have access to in c++.
Every current jvm matrix lib that uses net lib java or jblas is going to have problems with jvm communications as well. The reason for this is passing around java arrays and byte buffers is slower than how we handle it which is via passing longs (raw pointer addresses) around that are addressed via unsafe or allocated in jni where we retain the pointer address directly. We expose that to our native operators.
We are solving this by writing our own c++ backend called libnd4j that supports cuda as well as normal openmp optimized for loops for computation.
We also offer a unified interface to cublas and cblas (which is implemented by openblas as well as mkl) FWIW, I more or less agree with you, but it doesn't mean it shouldn't exist.
JVM based environments can bypass the jvm just like python does now.
The fundamental problem with the jvm is no one just took what works on other platforms and mapped the concepts 1 to 1.
Our idea with nd4j is to not only allow people to write their own backends, but also provide a sane default platform for numerical computing on the jvm. Things like garbage collection shouldn't be a hindrance for what is otherwise a great platform for bigger workloads (hadoop,spark,kafka,..)
In summary, we know the jvm has been bad till now - it's our hope for fixing that.
I find it interesting in the Numpy comparison no mention of the BLAS Numpy is linked to is mentioned, but it is for Nd4j. Numpy is highly dependent on a good BLAS and the basic Netlib one isn't that great.
Yes we have double precision - we have a default data type with the data buffer.
If you're curious how we do storage: https://github.com/deeplearning4j/nd4j/blob/master/nd4j-buff...
We have allocation types and data types.
Data types are double/float/int (int is mainly for storage)
Allocation types are the storage medium which can be arrays,byte buffers or what have you.
If you have a problem with the docs - I highly suggest filing an issue on our site: https://github.com/deeplearning4j/nd4j/issues
We actually appreciate eedback like this thank you.
For net lib java, it links against any blas implementation you give it. It has this idea of a JNILoader which can dynamically link against the fallback blas (which you mentioned)
or typically openblas or mkl. The problem there can actually be licensing though. The spark project runs in to this: https://issues.apache.org/jira/browse/SPARK-4816
If we don't mention on the site, it's probably because we haven't thought about it or haven't gotten enough feedback on something.
Unfortunately, we're still in heavy development mode.
FWIW, we have one of the most active gitter channels out there. You can come find me anytime if you're interested in getting involved.
I'm aware the software engineering logistics that go into doing sparse right which is why I held off
We are mainly targeting deep learning with this but sparse is becoming important enough for us to add it.
As for disparate standards I managed to work past that for cublas/blas.
I'm not going to let it stop me from doing it right. If you want to help us fix it we are hiring ;).
There's the NIST sparse blas, and MKL has a similar but not exactly compatible version. These never really took off in adoption (MKL's widely used of course, but I'd wager these particular functions are not). What sparse lapack are you talking about?
> If you want to help us fix it we are hiring ;).
We were at the same dinner a couple weeks ago actually. I'm enjoying where I am using Julia and LLVM, not sure if you could pay me enough to make me want to work on the JVM.
[1] - http://spark.apache.org/docs/latest/mllib-data-types.html
We have this concept of a backend where we had net lib java and jblas, but both are horribly slow/limited and need some updating which is why we added our approach to this.
If a new matrix framework comes out, I will just write a backend for it and allow people to keep the same dsl.
Breeze also isn't usable from java: http://stackoverflow.com/questions/27246348/using-breeze-fro...
FWIW, we also support both row and column major (you can specify the data as well as ordering) very similar to numpy.
If you come use nd4j, it will mainly be for a dsl that encourages vectorization just like any other numerical language.
The JVM has a lot of matrix library fragmentation.
And the JVM's costs in terms of deployment and startup times aren't very attractive for scientific workloads. You wouldn't gain as much in a migration from Python or Matlab to Java (or any other JVM language) as you would to C++ (or increasingly Julia), since you'll likely still need access to the same native libraries and JNI is kind of a pain.
But in julia, its written in julia. There are even julia native tensor and matrix ops.