Tutorial: Julia Overview
Julia overview.
- 2018-08-11 Julia 0.7.0 Jeff Fessler (based on 2017 version by David Hong)
- 2019-01-20 Julia 1.0.3 and add note about line breaks
- 2020-08-05 Julia 1.5.0
- 2021-08-23 Julia 1.6.2
- 2023-09-03 Julia 1.9.2, Literate
This page comes from a single Julia file: 1-intro.jl.
You can access the source code for such Julia documentation using the 'Edit on GitHub' link in the top right. You can view the corresponding notebook in nbviewer here: 1-intro.ipynb, or open it in binder here: 1-intro.ipynb.
Setup
Add the Julia packages used in this demo. Change false to true in the following code block if you are using any of the following packages for the first time.
if false
import Pkg
Pkg.add([
"InteractiveUtils"
"LinearAlgebra"
])
endTell Julia to use the following packages. Run Pkg.add() in the preceding code block first, if needed.
# using InteractiveUtils: versioninfo
using LinearAlgebra: Diagonal, det, dot, trNumbers, arithmetic, types
Define a real number:
r = 3.03.0Variables in Julia have a type:
typeof(r)Float64i = 33typeof(i)Int64c = 3. + 2im3.0 + 2.0imtypeof(c)ComplexF64 (alias for Complex{Float64})We can add, subtract, multiply and divide like usual:
4. + 59.04. - 5-1.04. * 312.02. / 30.6666666666666666Dividing Int values with / produces a Float:
2/30.66666666666666664/22.0This is different from Python 2, but similar to Python 3.
To divide integers with rounding, use ÷ instead. Type \div then hit tab:
5 ÷ 22More info about numbers here:
Vectors and matrices (i.e., arrays)
Make a vector of real numbers:
\[x = \begin{bmatrix} 1.0 \\ 3.5 \\ 2 \end{bmatrix}\]
x = [1, 3.5, 2]3-element Vector{Float64}:
1.0
3.5
2.0Note the type: Vector{Float64}.
Having just one real number in the array sufficed for the array have all Float64 elements.
This is a true one-dimensional array of Float64 values.
(Matlab does not have 1D arrays; it fakes it using 2D arrays of size N × 1.)
size(x) # returns a tuple(3,)length(x)3x_ints = [1,3,2]3-element Vector{Int64}:
1
3
2This is a one-dimensional array of Int64 values. We use these less often.
size(x_ints)(3,)length(x_ints)3Make a matrix using a semicolon to separate rows:
\[A = \begin{bmatrix} 1.1 & 1.2 & 1.3 \\ 2.1 & 2.2 & 2.3 \end{bmatrix}\]
A = [1.1 1.2 1.3; 2.1 2.2 2.3]2×3 Matrix{Float64}:
1.1 1.2 1.3
2.1 2.2 2.3This is a two-dimensional array (aka a matrix) of Float64 values.
size(A)(2, 3)length(A)6Different from Matlab, length always returns the total number of elements.
Make vectors and matrices of all zeros.
zeros(3)3-element Vector{Float64}:
0.0
0.0
0.0Different from Matlab! Do not write zeros(3,1) because Julia has proper 1D arrays. zeros(3,1) and zeros(3) are different!
zeros(2,3)2×3 Matrix{Float64}:
0.0 0.0 0.0
0.0 0.0 0.0And ones:
ones(3)3-element Vector{Float64}:
1.0
1.0
1.0ones(2,3)2×3 Matrix{Float64}:
1.0 1.0 1.0
1.0 1.0 1.0The "identity matrix" $I$ in Julia's LinearAlgebra package is sophisticated.
Look at the following examples:
using LinearAlgebra: I
ones(3,3) - I3×3 Matrix{Float64}:
0.0 1.0 1.0
1.0 0.0 1.0
1.0 1.0 0.0ones(2,2) * I2×2 Matrix{Float64}:
1.0 1.0
1.0 1.0I(3)3×3 LinearAlgebra.Diagonal{Bool, Vector{Bool}}:
1 ⋅ ⋅
⋅ 1 ⋅
⋅ ⋅ 1If that $I$ seems too fancy, then you could make your own eye function akin to Matlab as follows (but it should not be needed and it uses unnecessary memory):
eye = n -> Matrix(1.0*I(n))
eye(2)2×2 Matrix{Float64}:
1.0 0.0
0.0 1.0Make diagonal matrices using the Diagonal function in LinearAlgebra:
Diagonal(3:6)4×4 LinearAlgebra.Diagonal{Int64, UnitRange{Int64}}:
3 ⋅ ⋅ ⋅
⋅ 4 ⋅ ⋅
⋅ ⋅ 5 ⋅
⋅ ⋅ ⋅ 6This is far more memory efficient than Matlab's diag command or Julia's LinearAlgebra.diagm method. Avoid using those!
Make random vectors and matrices.
\[x = \begin{bmatrix} \mathcal{N}(0,1) \\ \mathcal{N}(0,1) \\ \mathcal{N}(0,1) \end{bmatrix} \qquad \text{i.e.,} \quad x_i \overset{\text{iid}}{\sim} \mathcal{N}(0,1)\]
\[A = \begin{bmatrix} \mathcal{N}(0,1) & \mathcal{N}(0,1) & \mathcal{N}(0,1) \\ \mathcal{N}(0,1) & \mathcal{N}(0,1) & \mathcal{N}(0,1) \end{bmatrix} \qquad \text{i.e., } \quad A_{ij} \overset{\text{iid}}{\sim} \mathcal{N}(0,1)\]
x = randn(3)3-element Vector{Float64}:
1.2279155478089312
-0.7191164963758667
0.4492095190865325A = randn(2,3)2×3 Matrix{Float64}:
-0.432146 0.481701 -0.0648589
0.383437 0.69246 0.515749Matrix operations
Indexing is done with square brackets (like in C and Python, unlike Matlab).
Index and begins at 1 (like in Matlab and counting) not 0 (like in C or Python).
A = [1.1 1.2 1.3; 2.1 2.2 2.3]2×3 Matrix{Float64}:
1.1 1.2 1.3
2.1 2.2 2.3A[1,1]1.1A[1,2:3]2-element Vector{Float64}:
1.2
1.3This row-slice is a one-dimensional slice (!) not a 1×2 matrix:
A[1:2,1]2-element Vector{Float64}:
1.1
2.1A[2,:]3-element Vector{Float64}:
2.1
2.2
2.3Vector dot product:
x = randn(3)
xdx = x'x0.8363276902372421xdx = dot(x,x)0.8363276902372421xdx = x'*x0.8363276902372421Different from Matlab! The output is a scalar, not a 1×1 "matrix:"
typeof(xdx)Float64Matrix times vector:
A = randn(2,3)
x = randn(3)
A*x2-element Vector{Float64}:
1.5970634461495923
0.3104134114222107Matrix times matrix:
A = randn(2,3)
B = randn(3,4)
A*B2×4 Matrix{Float64}:
0.828522 -0.467953 0.2653 2.02024
0.900295 -0.963707 0.332957 1.82185Matrix transpose (conjugate and non-conjugate):
A = 10*reshape(1:6, 2, 3) + im * reshape(1:6, 2, 3)2×3 Matrix{Complex{Int64}}:
10+1im 30+3im 50+5im
20+2im 40+4im 60+6imconjugate transpose, could also use adjoint(A):
A'3×2 adjoint(::Matrix{Complex{Int64}}) with eltype Complex{Int64}:
10-1im 20-2im
30-3im 40-4im
50-5im 60-6imFor complex arrays, rarely do we need a non-conjugate transpose. Usually we need A' instead. But if we do:
transpose(A) # essentially sets a flag about transpose without reordering data3×2 transpose(::Matrix{Complex{Int64}}) with eltype Complex{Int64}:
10+1im 20+2im
30+3im 40+4im
50+5im 60+6imMatrix determinant:
A = Diagonal(2:4)
det(A)24B = randn(3,3)
[det(A*B) det(A)*det(B)]1×2 Matrix{Float64}:
8.62008 8.62008Matrix trace:
A = ones(3,3)
tr(A) # in Matlab would be "trace(A)"3.0More info in Julia manual
Getting help
Julia analogue of Matlab's help is ?.
Type ?pwd in the REPL to get help on the pwd function.
It does not work in this online documentation so we use @doc instead:
@doc pwdpwd() -> String
Get the current working directory.
Examples
julia> pwd()
"/home/JuliaUser"
julia> cd("/home/JuliaUser/Projects/julia")
julia> pwd()
"/home/JuliaUser/Projects/julia"
- Full documentation
- Searching Julia's Github repo can sometimes also uncover similar issues.
- Lots of neat talks on their YouTube channel
- Here is an interesting one about vector transpose
Ranges
Ranges are different from (and much more efficient than) Matlab!
myrange = -2:3-2:3typeof(myrange)UnitRange{Int64}Not an Array! But it can be indexed:
myrange[1]-2Used often in for loops:
for a in myrange
println(a)
end-2
-1
0
1
2
3Form an array by using collect if needed (use rarely):
collect(myrange)6-element Vector{Int64}:
-2
-1
0
1
2
3Other ways to make ranges:
srange = 1:-1:-51:-1:-5typeof(srange)StepRange{Int64, Int64}lrange = range(0, 2, 10)0.0:0.2222222222222222:2.0typeof(lrange)StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}Yet another option that looks the most like linspace:
LinRange(0,10,6)6-element LinRange{Float64, Int64}:
0.0, 2.0, 4.0, 6.0, 8.0, 10.0Comprehensions
A convenient way to create arrays!
comp = [i+0.1 for i in 1:5]5-element Vector{Float64}:
1.1
2.1
3.1
4.1
5.1comp = [10i + j for i in 1:5, j in 1:4]5×4 Matrix{Int64}:
11 12 13 14
21 22 23 24
31 32 33 34
41 42 43 44
51 52 53 54Defining functions
Way 1:
function f1(x,y)
z = x+y
return z
endf1 (generic function with 1 method)Way 2:
f2(x,y) = x+yf2 (generic function with 1 method)Way 3: Anonymous function:
f3 = (x,y) -> x+y#7 (generic function with 1 method)Functions can return multiple outputs:
function f_mult(x, y)
add = x + y
sub = x - y
return add, sub
end;
f_mult(2,3)(5, -1)The output is a Tuple of the returned values:
out_tuple = f_mult(2,3)(5, -1)typeof(out_tuple)Tuple{Int64, Int64}Convenient way to split out the outputs:
out1, out2 = f_mult(2,3)(5, -1)out15out2-1Broadcast
Any Julia function can be "vectorized" using "broadcast"
myquad = x -> (x+1)^2#9 (generic function with 1 method)myquad(1)4try
myquad([1,2,3]) # this does not work!
catch
"failed, as expected"
end"failed, as expected"This particular function was not designed to be applied to vector input arguments! But it can be used with vectors (or arrays) by adding a . to tell Julia to apply it element-wise. This is called broadcasting.
myquad.([1,2,3])3-element Vector{Int64}:
4
9
16Conditionals
if else end for
Generally similar to Matlab. Optional use of in instead of = in the for loop.
for j in 1:3
if j == 2
println("$j is a two! ^^")
else
println("$j is not a two. :(")
end
end1 is not a two. :(
2 is a two! ^^
3 is not a two. :(Julia has the convenient ternary operator:
mystring = 2 > 3 ? "2 is greater than 3" : "2 is not greater than 3""2 is not greater than 3"Plotting
Suggested package: Plots.jl with its default gr backend.
Note: Usually slower the first time you plot due to precompiling. You must add the "Plots" package first. In a regular Julia REPL you do this by using the ] key to enter the package manager REPL, and then type add Plots then wait.
In a Jupyter notebook, type using Pkg then add Plots and wait.
using Plots
backend()Plots.GRBackend()Plot values from a vector. (The labels are optional arguments.)
x = range(-5,5,101)
y = x.^2
plot(x, y, xlabel="x", ylabel="y", label="parabola")heatmap
x = range(-2, 2, 101)
y = range(-1.1, 1.1, 103)
A = x.^2 .+ 30 * (y.^2)'
F = exp.(-A)
p1 = heatmap(x, y, F', # for F(x,y)
color=:grays, aspect_ratio=:equal, xlabel="x", ylabel="y", title="bump")Using the jim function the MIRTjim.jl package simplifies the display of 2D images, among other features. See its examples.
Plotting functions
Plots.jl allows you to pass in the domain and a function. It does the rest. :) This is one many examples of how Julia exploits "multiple dispatch."
plot(range(0,1,100), abs2, label="x^2")heatmap(range(-2,2,102), range(-1.1,1.1,100),
(x,y) -> exp(-x^2-30*y^2), aspect_ratio=1)More info about plotting at https://juliaplots.github.io
Caution: line breaks (newlines)
If you want an expression to span multiple lines, then be sure to enclose it in parentheses.
Compare the following 3 (actually 4) expressions:
x = 9
- 7-7y = 9 -
72z = (9
- 7)2(x,y,z)(9, 2, 2)Submitting homework
This part is just for EECS 551 students at UM.
A quick example to try submitting problems.
Task: Implement a function that takes two inputs and outputs them in reverse order.
function template1(x, y)
return (y, x)
end;
template1(2, 3)(3, 2)Copy the above function code into a file named template1.jl and email to eecs551@autograder.eecs.umich.edu.
Make sure that:
- All reasonable input types can be handled. Internally trying to convert a
Float64to anInt64can produceInexactError - File extension is
.jl. Watch out for hidden extensions! - File has just the Julia function.
- (Your HW solutions can also contain
usingstatements.)
An undocumented function is bad programming practice. Julia supports docstrings for comments like this:
"""
template2(x,y)
This function reverses the order of the two input arguments.
"""
function template2(x,y)
return (y,x)
endMain.var"Main".template2You can see the docstring by using the ? key or @doc:
@doc template2template2(x,y)
This function reverses the order of the two input arguments.
This page was generated using Literate.jl.