Main syntax differences

  • Julia's arrays default to column vector behaviour

  • Julia's indexes start at 1 and you can access elements using brackets

  • Slices are inclusive of endpoints, and end means the last component.

  • Steps can be informed in the middle

x = [1, 2, 3, 4, 5]
x * 2
ones(5) + x
x[2]
x[1:2]
x[2:end]
x[1:2:end]
length(x)
5
  • Matrices are first-class citizens.

  • Create a matrix with brackets, spaces to change columns, and ; to change lines.

  • Only in vectors , can be used instead of spaces (compat. Python).

  • You can concatenate matrices, vectors, and numbers with the same syntax.

A = [3 2 4; -1 0 1]
A * ones(3)
B = rand(3, 3)
A * B
B * A'
A[1:2, 1:2]
[
  B A';
  A ones(2,2)
]
5×5 Matrix{Float64}:
  0.676612  0.651401  0.615329  3.0  -1.0
  0.162237  0.803453  0.446101  2.0   0.0
  0.406989  0.044929  0.407312  4.0   1.0
  3.0       2.0       4.0       1.0   1.0
 -1.0       0.0       1.0       1.0   1.0
  • Linear systems can be solved with \

  • The LinearAlgebra stdlib module contains useful linear algebra tools, functions, and elements.

A = randn(50, 50)
b = A * ones(50)
x = A \ b
using LinearAlgebra
norm(b - A * x)
norm(x .- 1)
1.1464145426955781e-12
  • Everything has a concrete type, every type derives from some abstract type.

  • There is no implicit conversion, but sometimes it looks like there is.

typeof(2)
typeof(2.0)
Float64 |> supertype
Float64 |> supertype |> supertype
typeof(2 + 2.0)
typeof([2, 2.0])
typeof([2, true])
typeof([2, "a"])
Vector{Any} (alias for Array{Any, 1})
  • There are 3 approaches to write functions

function foo(a, b)
  return (a + 1) * (b - 1)
end
foo(2, 3)
bar(x) = x^2 - 2
bar(5)
anon = (a, b, c) -> sqrt(a^2 + b^2 + c^2)
anon(-1, 0, 1)
1.4142135623730951
  • if CONDITION ... elseif ... else ... end

  • while CONDITION ... end

  • for VARIABLE in SET|RANGE|ITERATOR ... end

  • You can specify types

function myfactorial(n::Int)
  if n < 0
    error("Nay nay")
  end
  prod = 1
  for i = 2:n
    prod *= i
  end
  return prod
end
myfactorial(4)
24
  • You can insert unicode characters with \something[TAB].

function machine_eps(x::AbstractFloat)
  ϵ = x
  while x + ϵ != x
    ϵ /= 2
  end
  return 2ϵ
end
machine_eps(1.0), machine_eps(1e4), machine_eps(Float16(1.0)), machine_eps(1.0f0)
(2.220446049250313e-16, 1.1102230246251565e-12, Float16(0.000977), 1.1920929f-7)
  • you can create a different signature

function machine_eps(x::Integer)
  return zero(x)
end
machine_eps(1), machine_eps(0x05), machine_eps(typemax(1))
(0, 0x00, 0)
  • you can set default positional arguments and keyword arguments

function newton(f, fder, x = 0.0; atol = 1e-6, rtol = 1e-6, max_iter = 1000)
  fx = f(x)
  iter = 0
  ϵ = atol + rtol * abs(fx)
  solved = abs(fx) < ϵ
  tired = iter ≥ max_iter
  while !(solved || tired)
    slope = fder(x)
    if abs(slope) < 1e-12
      error("0 derivative at x = $x")
    end
    x -= fx / slope
    fx = f(x)
    iter += 1
    solved = abs(fx) < ϵ
    tired = iter ≥ max_iter
  end
  return x, fx, iter
end
newton(x -> x - exp(-x), x -> 1 + exp(-x), 1.0)
(0.567143285989123, -6.927808993140161e-9, 3)
  • You can use parametric types

  • The type must be inferred from somewhere, so x is not optional anymore

function newton_parametric(f, fder, x :: T; atol :: T = √eps(T), rtol :: T = √eps(T), max_iter :: Int = 1000) where T
  fx = f(x)
  iter = 0
  ϵ = atol + rtol * abs(fx)
  slope_ϵ = (√√eps(T))^3 # ϵₘ^(3/4)
  solved = abs(fx) < ϵ
  tired = iter ≥ max_iter
  while !(solved || tired)
    slope = fder(x)
    if abs(slope) < slope_ϵ
      error("0 derivative at x = $x")
    end
    x -= fx / slope
    fx = f(x)
    iter += 1
    solved = abs(fx) < ϵ
    tired = iter ≥ max_iter
  end
  return x, fx, iter
end
for T in [Float16, Float32, Float64, BigFloat]
  x, fx, iter = newton_parametric(x -> x^2 - 2, x -> 2x, one(T))
  println("√2 ≈ $x")
end
√2 ≈ 1.417
√2 ≈ 1.4142157
√2 ≈ 1.4142135623746899
√2 ≈ 1.41421356237309504880168872420969807856967187537723400156101313311326525563035
  • Formatted printing is possible with the Printf stdlib

  • @printf is a macro. Interpolation ("$x") is not possible.

using Printf
for T in [Float16, Float32, Float64, BigFloat]
  x, fx, iter = newton_parametric(x -> x^2 - 2, x -> 2x, one(T))
  @printf("√2 ≈ %20.16e, (√2)² - 2 ≈ %20.16e\n", x, x^2 - 2)
end
√2 ≈ 1.4169921875000000e+00, (√2)² - 2 ≈ 7.8125000000000000e-03
√2 ≈ 1.4142156839370728e+00, (√2)² - 2 ≈ 5.9604644775390625e-06
√2 ≈ 1.4142135623746899e+00, (√2)² - 2 ≈ 4.5106141044470860e-12
√2 ≈ 1.4142135623730950e+00, (√2)² - 2 ≈ 8.0872759798342835e-49
  • In the REPL, ? access the help mode.

  • apropos can be used to search among the docstrings


Exercises

  1. Given v and w vectors, verify that [v w] and [v, w] are different. Notice the type of the second object.

  2. Search for "dot product" using the apropos function.

  3. Create a function that orthogonalizes a list of vectors following the given theorem:

Theorem: Given nn linear independent vector v1,v2,,vnv_1, v_2, \dots, v_n, define qi=vij=1i1(viqj)qj,  i=1,,n\displaystyle q_i = v_i - \sum_{j = 1}^{i-1} (v_i \cdot q_j) q_j, \ \forall \ i = 1,\dots,n. The vectors q1,q2,,qnq_1, q_2, \dots, q_n are orthogonal.