PART I: Intro. to Julia

Presentation

Outline

The presentation will give a short tour about essential ideas behind Julia. Though this tutorial put emphasis on the Scientific Machine Learning, Julia is designed for generic purpose

What is Julia?

Julia is a high-level programming language that well suited for computational science. It supports Just-in-time (JIT) and multiple dispatch to create static

Why Julia is fast?

  1. Just-in-Time
  2. Multiple dispatch
  3. Type inference
  Activating project at `~/Documents/GitHub/Julia-for-SciML/hands-on/tutorial`

Multiple Dispatch

function multiply(a,b)
    return a*b
end
multiply (generic function with 1 method)
@code_llvm multiply(1,1)
;  @ In[3]:1 within `multiply`
define i64 @julia_multiply_2730(i64 signext %0, i64 signext %1) #0 {
top:
;  @ In[3]:2 within `multiply`
; ┌ @ int.jl:88 within `*`
   %2 = mul i64 %1, %0
; └
  ret i64 %2
}
@code_llvm multiply(1., 1.)
;  @ In[3]:1 within `multiply`
define double @julia_multiply_2753(double %0, double %1) #0 {
top:
;  @ In[3]:2 within `multiply`
; ┌ @ float.jl:385 within `*`
   %2 = fmul double %0, %1
; └
  ret double %2
}

Avoid allocation

@code_llvm multiply([1.], [1.])
;  @ In[3]:1 within `multiply`
; Function Attrs: noreturn
define nonnull {}* @julia_multiply_2755({}* nonnull align 16 dereferenceable(40) %0, {}* nonnull align 16 dereferenceable(40) %1) #0 {
top:
  %2 = alloca [2 x {}*], align 8
  %.sub = getelementptr inbounds [2 x {}*], [2 x {}*]* %2, i64 0, i64 0
;  @ In[3]:2 within `multiply`
  store {}* %0, {}** %.sub, align 8
  %3 = getelementptr inbounds [2 x {}*], [2 x {}*]* %2, i64 0, i64 1
  store {}* %1, {}** %3, align 8
  %4 = call nonnull {}* @ijl_apply_generic({}* inttoptr (i64 5204665952 to {}*), {}** nonnull %.sub, i32 2)
  call void @llvm.trap()
  unreachable
}

Mutated function

function multiply!(s, a,b, i)
    s[i] = a[i] * b[i]
    return s
end
multiply! (generic function with 1 method)
s = zeros(1)
a = [1.]
b = [1.];

@btime multiply(a[1], b[1])
@btime multiply!(s, a, b, 1)
  48.245 ns (3 allocations: 48 bytes)
  13.360 ns (0 allocations: 0 bytes)
1-element Vector{Float64}:
 1.0

Vandermonde Matrics

function vander(x::AbstractVector{T}, n=length(x)) where T
  m = length(x)
  V = zeros(T, m,n)
  for j = 1:m
    V[j,1] = one(x[j])
  end
  for i = 2:n
    for j = 1:m
      V[j,i] = x[j] * V[j,i-1]
    end
  end
  return V
end
vander (generic function with 2 methods)
x = [1., 2., 3., 4.]
vander(x)
4×4 Matrix{Float64}:
 1.0  1.0   1.0   1.0
 1.0  2.0   4.0   8.0
 1.0  3.0   9.0  27.0
 1.0  4.0  16.0  64.0
x2 = [1+1im, 2+7im, 3+4im]
vander(x2)
3×3 Matrix{Complex{Int64}}:
 1+0im  1+1im    0+2im
 1+0im  2+7im  -45+28im
 1+0im  3+4im   -7+24im

Version

This tutorial is using Julia in version of

v"1.8.2"