In today’s world, mathematical and scientific computation has grown to be increasingly important, especially in the context of the growth of the fields of data science, machine learning, deep learning and AI over the last few years. The language of choice for most of these fields is Python, which has grown massively over the last decade and has a vast library framework that makes implementation of these fields very easy.
However, one of the major drawbacks with Python is the fact that it is an interpreted language — i.e. code is executed by an interpreter without being converted into machine code. This makes it much slower in comparison to compiled languages such as C or C++. The result is that for computations that require more speed, such as handling large arrays or machine learning, Python libraries such as NumPy or TensorFlow rely on code written in C/C++ for speed optimizations. Despite this, code written in native Python tends to slow the program down.
Julia is a programming language that has recently gained traction for mathematical and scientific computation. Unlike Python, Julia is compiled with a Just-In-Time (JIT) compiler — so code is converted first to bytecode, an intermediate instruction set which is portable across systems, which is then converted to machine code by the JIT compiler as and when required during runtime. This is in contrast to interpreted languages that do not convert source code to machine code at all, or ahead-of-time compiled languages like C which convert the whole program to machine code before running it. And despite blazing speed, the syntax is very user-friendly and retains Python-like readability.
Julia has found usage in many areas, including packages that provide a state-of-the-art differential equations ecosystem (DifferentialEquations.jl), optimization tools (JuMP.jl and Optim.jl), iterative linear solvers (IterativeSolvers.jl), Fast Fourier transforms (AbstractFFTs.jl), and much more. General purpose simulation frameworks are available for Scientific Machine Learning, Quantum computing and much more.
Julia also offers a number of domain-specific ecosystems, such as in biology (BioJulia), operations research (JuMP Dev), image processing (JuliaImages), quantum physics (QuantumBFS), nonlinear dynamics (JuliaDynamics), quantitative economics (QuantEcon), astronomy (JuliaAstro) and ecology (EcoJulia).
Over the course of this series, I hope to give the uninitiated a taste of programming in Julia. I will go over the installation of the language and its integration with Jupyter Notebooks as well as with a reactive notebook framework designed specifically for Julia, Pluto.jl. I will also discuss the implementation of variables and arrays, as well as one of Julia’s most oft touted features, multiple dispatch. Finally, I will demonstrate how we can use one of Julia’s libraries to implement a photo filter with ease. While this is not meant to be a comprehensive course by any means, I do hope that it will inspire more people to take up programming in Julia. Let’s get started!
The latest version of Julia can be found at https://julialang.org/downloads/. It is available for install on all of the common operating systems and architectures, so you can download the installer specific to your system and run it with ease. While a native version for Apple Silicon has not been released yet, work is underway. In the meanwhile, the language works smoothly with Rosetta 2 emulation.
After install is complete, you can either double-click the Julia executable or run
julia in the command line:
This opens up the Julia REPL. REPL stands for “read-eval-print loop” and is the interactive interface that comes packaged along with the language itself. Single statements can be executed in the REPL, and it is a great tool for experimenting with the language. It is very similar to the Python interactive prompt.
When run in interactive mode,
julia displays a banner and prompts the user for input. Once the user has entered a complete expression, such as
1 + 2, and hits enter, the interactive session evaluates the expression and shows its value. If an expression is entered into an interactive session with a trailing semicolon, its value is not shown. The variable
ans is bound to the value of the last evaluated expression whether it is shown or not. The
ans variable is only bound in interactive sessions, not when Julia code is run in other ways.
However, using the REPL for larger programs will prove to be cumbersome. To remedy this, there are several options:
- Code editors such as Sublime and Visual Studio Code offer plugins that offer syntax highlighting, code auto-completion, debugging and much more.
- Julia integrates with Jupyter notebooks for those who have them already installed for usage with Python. We can use Julia’s built-in package manager for installing
IJulia, which is a package that integrates Julia with Jupyter notebooks:
After IJulia is installed, The process for opening a new notebook with Julia is the same as with Python— run
jupyter notebook in the terminal. When the notebook opens in the browser, in the drop-down menu for creating a new file, Julia should show up as an option now.
3. The option that I personally prefer for working with Julia is Pluto.jl, the notebook interface designed specifically for Julia. Pluto notebooks are similar to Jupyter notebooks in that they have options for both text and code, organized into cells.
What Pluto offers beyond Jupyter, however, is that Pluto notebooks are stored as pure Julia files and the code in them can be imported normally just as for a file written in a regular editor. Pluto is also reactive, meaning that any changes in the code reflect immediately in all cells and deleted code leaves no mark.
Apart from this, Pluto offers HTML interaction via a bind macro to create a live bond between an HTML object and a Julia variable. For beginners who are unaware of how HTML works, the
PlutoUI package contains within it the implementation of common interactive elements such as sliders and buttons. But for more experienced programmers, this opens up a world of opportunities to implement advanced interactive features like widgets in Pluto notebooks to make them reader-friendly.
And finally, Pluto has live documentation enabled, meaning that you can look up the syntax of functions without having to leave the page.
To install Pluto, we run the following commands in the REPL:
Pluto will open in your browser, and we are all ready to begin actual programming!
Note on working with Pluto Notebooks: Markdown
For text mode in Pluto notebooks (to take notes or describe code), we can use the syntax
md""" to enable markdown editing in the cells. Once the text is complete, closing the triple quotes and hiding the code cell by clicking on the button of the eye on the right enables the notebook to remain clean and look presentable.
Variables and Numerical Types
We can define a variable using
= (assignment). Julia is dynamically typed, and so the type of the variable is inferred automatically from the definition. Then we can use its value in other expressions:
By default Julia displays the output of the last operation. We can suppress the output by adding
; (a semicolon) at the end.
We can ask what type a variable has using
Integers and Floating-Point numbers
The following are Julia’s primitive numeric types:
It is apparent from this that there is a vast variety of numeric data types to choose from. The default value is usually either 32-bit or 64-bit depending on the system’s architecture. In most cases we will not have to change this, but on certain occasions a particular type of data might give better results for the execution of the code.
Special Floating-Point Values
There are three specified standard floating-point values that do not correspond to any point on the real number line:
Floating-point numbers are compared according to the IEEE 754 standard:
- Finite numbers are ordered in the usual manner.
- Positive zero is equal but not greater than negative zero.
Infis equal to itself and greater than everything else except
-Infis equal to itself and less then everything else except
NaNis not equal to, not less than, and not greater than anything, including itself.
Some examples of expressions in which
-Inf may be returned:
Point number 5 is especially surprising, and the following results are obtained in the REPL:
This is a source of potentially buggy code if not kept in mind, and hence I have drawn attention to the same here.
For more specifics on the implementation of numerical values in Julia, you can consult the documentation.
Complex and Rational Numbers
Julia also provides in-built data types for handling both complex and rational values.
Complex numbers are defined as
real + imaginary(im) . Rational numbers, on the other hand, are defined as
numerator // denominator :
Note that the use of
// , the double backslash, is to distinguish it from
/ , or the division operator. Also note that the rational number is not stored as a floating point value in the system — it is stored as it is i.e. a numerator upon a denominator and mathematical operations have been defined to be consistent with the same.
In this article, I introduced Julia as a programming language and went over some basic expressions and types, especially for numerical values. In the next article, I will be covering range objects and multi-dimensional arrays.