The Julia programming language

Numerical Analysis

Urbain Vaes

NYU Paris

Julia, a good language for scientific computing?

Python Matlab Julia C
Libre? ✔️ ✔️ ✔️
Fast? ✔️ ✔️
Easy? ✔️ ✔️ ✔️
Math-friendly? ✔️ ✔️
Ecosystem? ✔️ ✔️
  • Julia is easy to learn, read and maintain

  • Julia is fast: “As simple as Python with the speed of C++”

  • Julia is well-suited for numerical mathematics

  • Julia is libre software

A bit of history

  • Created in 2009 by J. Bezanson, S. Karpinski, V. B. Shah, and A. Edelman

  • Excerpt from the Julia Manifesto:

We want a language that’s open source, with a liberal license. We want the speed of C with the dynamism of Ruby. We want a language that’s homoiconic, with true macros like Lisp, but with obvious, familiar mathematical notation like Matlab. We want something as usable for general programming as Python, as easy for statistics as R, as natural for string processing as Perl, as powerful for linear algebra as Matlab, as good at gluing programs together as the shell. Something that is dirt simple to learn, yet keeps the most serious hackers happy. We want it interactive and we want it compiled.

Adoption of Julia is rapidly increasing

Performance benchmark

Julia is a great fit for numerical mathematics

  • Elegant syntax to define functions
f(x) = cos(x) + sin(x)
f(1)
"Int 1"
  • The syntax for anonymous functions is equally elegant:
import Plots
Plots.plot(x -> cos(x) + sin(x))
  • Use of unicode characters:
ω = 1  # ⚠️ Even emojis work!
f(t) = sin*t)
∇f(t) = ω * cos*t)
(t) = f(t) * f(t)
  • Compiled just in time (for loops allowed!):
@elapsed sum(1/n^2 for n  1:10^8)
0.198119684

In comparison, Python takes about 10 seconds…

  • Contains most math functions out of the box:
π, Float64(), randn(), √2
(π, 2.718281828459045, -1.003693228380129, 1.4142135623730951)
  • Concise syntax, MATLAB-like syntax for matrices:
M = [1 2 3; 4 5 6]
2×3 Matrix{Int64}:
 1  2  3
 4  5  6
M[:, [1, 3]]
2×2 Matrix{Int64}:
 1  3
 4  6
  • Great syntax for array broadcasting:
broadcast(gcd, 6, [9, 8, 7])
gcd.(6, [9 8 7])
1×3 Matrix{Int64}:
 3  2  1
1 .+ [1; 2; 3] .+ [1 1 1; 1 1 1; 1 1 1]
3×3 Matrix{Int64}:
 3  3  3
 4  4  4
 5  5  5

  • Dynamic types by default…
x = 1 ; y = π ; z = 1//2 ; t = x + y + z
4.641592653589793
for v  (x, y, z, t)
    println("$v is a $(typeof(v))")
end
1 is a Int64
π is a Irrational{:π}
1//2 is a Rational{Int64}
4.641592653589793 is a Float64
  • … but static typing allowed
f(x) = 2x
f(x::Float64) = 3x
@show f(1)
@show f(1.) ;
f(1) = "Int 1"
f(1.0) = 3.0
  • Array comprehension (for within array)
A = [63/(i+2j) for i  1:3, j  1:3]
3×3 Matrix{Float64}:
 21.0   12.6  9.0
 15.75  10.5  7.875
 12.6    9.0  7.0
  • Built-in linear solver
x = [1.2, 3.4, 5.6]
b = A*x
A\b
3-element Vector{Float64}:
 1.2000000000000222
 3.3999999999999084
 5.600000000000077
@show A\b == x
@show A\b  x ;
A \ b == x = false
A \ b ≈ x = true
  • Array indices start at 1
a = [1, 2, 3]
@show a[1]
@show a[2]
@show a[3]
a[1] = 1
a[2] = 2
a[3] = 3
3
  • New binary operators
(α,β) = α + β
5  7
12

Julia’s programming paradigm: multiple dispatch

Wikipedia definition: paradigm in which a function or method can be dynamically dispatched based on the run-time type.

  • Example:
f(x::Int) = "Int $x"
f(x::Float64) = "Float: $x"
f(x::Any) = "Generic fallback"
f(1.2)
"Float: 1.2"
  • Makes it simple to extend existing packages:
import Base.-
function -(s1::String, s2::String)
    return s1[1:length(s1)-length(s2)]
end
"julia" - "ia"
"jul"
  • Python, in comparison, uses single dispach.

The REPL and Julia programs

  • REPL = read–eval–print loop = “command line”
  • To access the REPL,

    • either type julia in a terminal window;

    • or launch it from VSCode by typing Shift+Ctrl+P then Julia: Start REPL

  • Useful shortcuts in the REPL:

    • ] to access package mode

    • ; to access shell mode

    • ? to access help mode

    • to return to normal mode

    • Tab for automatic completion

    • up and down arrows to navigate history

  • To write a julia program

    • either write a .jl file, which can be run using Shift+Enter

    • Or write a Jupyter notebook with .ipynb extension.

Package management

To install a new package

  • Enter package mode with ;

  • Type add followed by the package name, e.g.

    add Plots
  • You only need to do this once

To use an installed package

  • Either use import

    import Plots
    Plots.plot(cos)
  • or use using (no need to prepend package name later)

    using Plots
    plot(cos)

Additional references