Julia for Evolutionary Computation

An extensive collection of resources for those who wish to start implementing evolutionary computation solvers and algorithms in Julia.

Why Julia?

Julia was designed and built specifically for numerical and scientific computing. It started at the MIT, and aims to solve the two language problem: you can get high speed as in compiled languages (like C or C++), and simplicity as in interpreted languages (like Python and R). In fact, Julia’s syntax reads a bit like a mixture of MATLAB and Python+NumPy.

Julia uses dynamic typing, multiple-dispatch, and JIT compilation, and it can be used for High-Performance Computing. In fact, it is one of the four languages in the petaFLOP-club—languages that can exceed 10^15 FLoating Point Operations per Second—along with C, C++ and Fortran.

My experience with Julia

I have been using Julia for over three years now as my main programming language, and I have been pretty satisfied with my workflow. Here I describe some of the reasons why I think it is a very solid choice for evolutionary computation and artificial intelligence in general.

Why do you recommend Julia for coding EAs?

There are two main reasons why I recommend using Julia for research in evolutionary computation. The first reason is ease of modelling.

When working with evolutionary algorithms (EAs), we deal with a lot of loops, functions and collections. And all of these elements can be easily modelled in Julia almost as directly as their mathematical counterparts. Take for example the $\text{Jump}$ function. In Julia:

function jumpk(x; k=6)
    s = sum(x)
    n = length(x)
    return s  (1:n-k)  n ? s : -s
end

And its mathematical form:

\[\text{Jump}_k(\boldsymbol{x}) = \begin{cases} \Vert \boldsymbol{x} \Vert_1 \quad \text{if } \Vert \boldsymbol{x} \Vert_1 \in [0 .. n - k] \cup {n},\\ -\Vert \boldsymbol{x} \Vert_1 \quad \text{otherwise} \end{cases}\]

Functions can also be defined as one-liners:

f(x) = sin(x)

binary_vector_pop(n, l; rng=Random.GLOBAL_RNG) = [bitrand(rng, l) for _ in 1:n]

But perhaps the most important point for me was focusing on evolutionary operators, which for mathematical purposes are considered functions and not methods. That is, mutation is a function, operating on an individual, and crossover is a function operating on two individuals. selection is a function operating on the whole population, and so on.

Of course, you can absolutely use vectorised approaches in Numpy, as well as objects to represent your population or individuals. But the bridge between theory and implementation feels more natural when you use functions, sets and loops.

The second reason I migrated to Julia is because of its speed.

for loops are famously very slow in Python, and although it is possible to compile using third-parties to get some speed, there is usually a lot of refactoring needed (especially when you do not want to use objects). This is why Java was out of the question for me as well.

And while C and C++ are great options for speed, I really did not want to worry about memory addresses anymore, so Julia did the trick for me. I have been able to model my solutions in Julia, and then deploy them in an HPC Cluster without having to change my programming language.

Have you used Julia in your publications?

Yes. I have used Julia in several of my publications. I have used it to model evolutionary algorithms, for descriptive statistics and tests, for parallel ML workflows, and for creating figures and visualizations—both for papers and posters.

Other advantages

Some caveats

Further reading