Comments¶
Comments are non-coding parts in the source code. Although the compiler does not read comments, comments are important notes for humans, making the code more readable (hopefully).
# One line comments
# Multiline commentsVariables and expressions¶
The assignment operator = binds a name to a piece of data.
To see the data content:
@show expressionto show the expression and its resultprintln(data): good old print function.@printf: C-like formatted output.Inline display: content of the last expression. A semicolon
;at the end will suppress inline output.
An integer (64 bit)
x = 11A (64-bit) floating-point number
y = 1.01.0A 32-bit floating-point number. less accurate but calculates faster. Often used in GPU computing.
y = 1.0f01.0f0Complex number
z = 3 + 5im3 + 5imUnicode names are supported. For example, \alpha<tab>
α = 3.743.74Strings (Text) are surrounded by double quotes.
s = "Julia""Julia"Characters are surrounded by single quotes.
c = ' '' ': ASCII/Unicode U+0020 (category Zs: Separator, space)Fractions (rational numbers)
station = 9 + 3//439//4Constants will emit a warning if you try to change it after its creation
const theUltimateAnswer = 4242Print content to the terminal
println("Hello World")Hello World
println("Hello ", s)Hello Julia
println(1, 2, 3)123
@show will print x = val
@show x 1+1 2-2 3*3;x = 1
1 + 1 = 2
2 - 2 = 0
3 * 3 = 9
Types of the data
@show typeof(x) typeof(y) typeof(c) typeof(s) typeof(z) typeof(1//2);typeof(x) = Int64
typeof(y) = Float32
typeof(c) = Char
typeof(s) = String
typeof(z) = Complex{Int64}
typeof(1 // 2) = Rational{Int64}
convert(T,x) converts x to type T
typeof(convert(Float64, x))Float64There is also Type(x)
typeof(Float64(x))Float64Converts numbers to floating numbers
typeof(float(x))Float64Math expressions¶
Julia supports basic arithmetic operations and essential math functions by default.
Basic arithmetic¶
Multiple assignment
a, b = 2, 3(2, 3)Addition
a + b5Subtraction
a - b-1Multiplication
a * b6Division
b / a1.5Fraction
b // a3//2integer division: \div<tab>, the same as div(a, b)
a ÷ b0Modulus
b % a1Power
a^b8Comparison¶
Returns a boolean value (true or false)
a, b = 2, 3(2, 3)a < 1falseb > 2truea <= btruea != btruea == b + 1falseChained comparisons are supported
1 < a <= btrueApproximation operator \approx<TAB> for floating point number equivalence
1e10 + 1.0 ≈ 1e10trueThe same as
isapprox(1e10 + 1.0, 1e10)trueMath functions¶
How to type π : \pi<TAB>
sin(0.5*π)1.0More precise
sinpi(1//2)1.0cos(0.5*π)6.123233995736766e-17More precise
cospi(1//2)0.0\sqrt<TAB>
sqrt(π) ≈ √πtrueNatural log
log(10)2.302585092994046Common log
log10(10)1.0Natural exponent
exp(-5)0.006737946999085467expm1(x) is more accurate that exp(x) - 1 when x is very close to zero.
exp(1e-12) - 1, expm1(1e-12)(1.000088900582341e-12, 1.0000000000005e-12)Strings¶
A string is a sequence of characters.
" ... "for one line strings.Three double quotes surround multiline string.
str1*str2*...to concatenate stringsstring(str1, str2, ...)to convert the data (if needed) and make a string.^to repeat a string:str^3to repeatstrthree times.[idx]to access an individual character.$to insert (or interpolate) a value into a string.
Although string(x, y) looks less streamlined, it is generally faster than interpolation $ or concatenation *.
"I am a string.""I am a string.""""
I am a multiline
string.
Hello Julia!
""""I am a multiline\nstring.\n\nHello Julia!\n"A character is different from a string
'a' == "a"falseHow to insert contents into a string
str1 = "BEBI"
str2 = "5009"
string("The class is ", str1, '-', str2, ".")"The class is BEBI-5009."String interpolation $
"The class is $(str1)-$(str2).""The class is BEBI-5009."String concatenation *
str1*"-"*str2"BEBI-5009"Compound expressions (Code blocks)¶
A begin block
begin...endsquashes multiple expressions into one.A let block
let...endis similar to a begin block but variables inside will be discarded outside the block.
a1 and a2 are available after begin block ends
begin
a1 = 2
a2 = 35
a1 = a1 * a2
end70x, y, z are NOT available after let block ends
let
x = 1
y = 2
z = 3
x + y * z
end7Control flow¶
Conditional statements¶
The
elseifandelseblocks are optional.ifandendare mandatory.ifblocks return a value. Capturing the value is optional.ifblocks are “leaky”, i.e. they do not introduce a local scope. (The same as Python)Only boolean (true / false) could be evaluated in
ifblocks. Using other types (e.g. Int) will generate an error.
Ternary operator¶
cond ? T:F
ifelse function¶
A no-branching alternative. All the arguments are evaluated first in ifelse(cond, tvalue, fvalue).
short circuit evaluation¶
&& (logical and) and || (logical or) operators support short circuit evaluation.
In the expression
a && b, the expressionbwould be evaluated only ifaevaluates totrue.In the expression
a || b, the expressionbwould be evaluated only ifaevaluates tofalse.
Short circuit and && evaluates and returns the second argument if the first is true
(2 > 1) && println("Hi")Hi
otherwise it returns false
(2 < 1) && println("Hi")falseA if block can return value(s)
let score = 10
response = if 80 < score <= 100
"Good"
elseif 60 < score <= 80
"Okay"
else
"Uh-Oh"
end
response
end"Uh-Oh"Ternary operator
1 > 2 ? "True" : "False""False"Loops¶
Repeated evaluations in a code block.
While loop (we will use it to solve stochastic simulations)
while cond
expr
endFor loop (we will use it to solve ODEs)
for i in seq
expr
endLoop controls:
break: exit the loop immediately.continue: move on to the predicate immediately.
Hailstone sequence (3n+1 problem) in a while loop
let n = 1025489
step = 0
while n > 1
if iseven(n)
n ÷= 2
else
n = 3n + 1
end
step += 1
end
step
end77Summation
let n = 100
s = 0
for i in 1:n
s += i
end
s
end5050How continue and break work
for x in 1:9
if x == 5
continue ## jump to `x in 1:9`
elseif x >=8
break ## jump to the end of loop
end
println(x, "^2 = ", x^2)
end1^2 = 1
2^2 = 4
3^2 = 9
4^2 = 16
6^2 = 36
7^2 = 49
You can use enumerate(seq) to get a pair of index number and the element.
for (i, x) in enumerate([2, 3, 5, 7, 9, 11, 13])
println("xs[", i, "] = ", x)
endxs[1] = 2
xs[2] = 3
xs[3] = 5
xs[4] = 7
xs[5] = 9
xs[6] = 11
xs[7] = 13
Multiple nested for loops can be combined into a single outer loop, forming the cartesian product of its iterables.
for i = 'x':'z', j = '1':'3'
println(i, j)
endx1
x2
x3
y1
y2
y3
z1
z2
z3
Functions¶
In Julia, a function is an object that maps a tuple of argument values to a return value. Julia docs
Functions could do:
Code reuse and encapsulation.
Specializations of Methods for different data types.
Notes:
Functions are first-class objects and can be passed into a higher-order function.
The arguments are “passed-by-sharing” (Similar to Python). Modifications to mutable argument values (such as
Arrays) will be reflected to the caller.By convention, functions that will update the arguments are named with a bang
!. (e.g.sort(arr)vssort!(arr))For element-wise operations, use the broadcast (dot) syntax. e.g.
sqrt.(arr)You can write multiple functions with the same name provided they have distinct parameters. Julia will choose the most appropriate one according to the input.
Standard form¶
"Michaelis-Menton function" ## Function documentations
function mm(x, k) ## function name and parameter list
result = x / (x +k) ## Doing stuff
return result ## Return statement
end ## End of functionMain.var"##225".mmCall the function
mm(1, 0.5)0.6666666666666666One-liner form¶
f(x, y) = x + y
f(1, 2)3And you can also reuse previously-defined functions
mm(x) = mm(x, one(x))
mm(1)0.5Anonymous functions¶
Anonymous functions are often used with other functions that take in another function. e.g. map(func, seq)
g = x->x^2
g(3)9map(x->x^2, 1:3)3-element Vector{Int64}:
1
4
9Use the do block for long anonymous functions.
val = rand(-6:6, 10)
map(val) do x
res = if x < 0 && iseven(x)
zero(x)
elseif x == 0
one(x)
else
x
end
res
end10-element Vector{Int64}:
1
-3
2
5
6
4
0
5
3
3The same as
map(x -> begin
res = if x < 0 && iseven(x)
zero(x)
elseif x == 0
one(x)
else
x
end
res
end, val)Optional arguments¶
Optional (positional) arguments are listed after mandatory ones.
function func(a, b, c=1)
## do_stuff
endAnd they are called with func(a, b) or func(a, b, 3)
Keyword arguments¶
Keyword arguments are listed after ;. They are called by name rather than order.
function plot(x, y; style="solid", width=1, color="black")
## do_stuff
endAnd they are called with plot(x, y, width=2) or plot(x, y; width=2)
Collections¶
Using built-in collections is the simplest way to group and organize data.
The values in a immutable collection cannot be updated after its creation, while in a mutable collection can.
The elements in sequential collections are accessed by integer indices, while those in associative collection are accessed by keys.
Sequential collections¶
General rules for sequential collections:
1-based indexing, as in R, MATLAB, and Fortran.
Elements are accessed by an integer index
seq[i]or an integer rangeseq[1:2:end-1].length(seq)returns the total sizeSplat operator
...passes the inner contents in the collection as positional function arguments.Dot syntax (e.g. a .+ b) performs element-wise / broadcasting operations.
Ranges¶
start[:step]:end
Immutable
Sequential
Cheap
Evenly-spaced numerical sequences
A simple range starts from one, and stops at ten, with a step size of two,.
1:2:101:2:9Length of a sequence
length(1:2:10)5Show its content
dump(1:2:10)StepRange{Int64, Int64}
start: Int64 1
step: Int64 2
stop: Int64 9
Explicit range function
range(1, 10, length=10)1.0:1.0:10.0Pick an element
(1:10)[3]3Pick elements by a range of indices
(1:10)[3:end]3:10Tuples¶
immutable
sequential collections
efficient for heterogenous data of various types
stack-allocated
tuple(1, 'a', 3.14)(1, 'a', 3.14)Tuples are usually written as
(1, 'a', 3.14)(1, 'a', 3.14)Pick elements You cannot change the elements once its created. (immutable)
t1 = (1, 2, 3)
t1[1]1t2 = (1, 'a', 3.14)
dump(t2)Tuple{Int64, Char, Float64}
1: Int64 1
2: Char 'a'
3: Float64 3.14
Merging multiple tuples using the splat (...) operator
tuple(t1..., t2...)
# Tuples could be used to swap elements
let x = 1, y = 2, z = 3
x, y, z = z, x, y
@show x, y, z
end;(x, y, z) = (3, 1, 2)
Tuple can return multiple values from a function
neighbors(x) = x+1, x-1
neighbors(0)(1, -1)extrema([1, 5, 6, 7, -1, -3, 0])(-3, 7)sincospi(1//2)(1.0, 0.0)Arrays¶
[seq...] / collect(seq)
Arrays are the bread and butter for scientific computing, similar to numpy’s ndarrays.
Column-major (Fortran style) rather than row-major (C and numpy style)
Assignments and updating may cause unwanted editing due to memory sharing.
Some useful functions for arrays:
length(A)the number of elements in Andims(A)the number of dimensions of Asize(A)a tuple containing the dimensions of Asize(A,n)the size of A along dimension neachindex(A)an efficient iterator for visiting each position in A
1D array (column vector)
x = [5, 6, 7]3-element Vector{Int64}:
5
6
7np.arange() equivalent
collect(1:10)10-element Vector{Int64}:
1
2
3
4
5
6
7
8
9
10Array with all zeroes
zeros(2, 5, 2)2×5×2 Array{Float64, 3}:
[:, :, 1] =
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
[:, :, 2] =
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0Array with all ones
ones(2, 5)2×5 Matrix{Float64}:
1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 1.0Uninitialized array with the same data type and dims as x
similar(x)3-element Vector{Int64}:
127162464105584
127162464107312
0np.zeros_like()
zero(x)3-element Vector{Int64}:
0
0
0Array of random numbers
rand(1:6, 10)10-element Vector{Int64}:
6
1
6
1
4
2
3
2
2
6rand(1:6, 2, 2)2×2 Matrix{Int64}:
3 6
4 5Reshape an array
reshape(1:12, 3, 4)3×4 reshape(::UnitRange{Int64}, 3, 4) with eltype Int64:
1 4 7 10
2 5 8 11
3 6 9 12Reshape A to an (1D) vector
vec(rand(1:6, 2, 2))4-element Vector{Int64}:
4
6
5
3repeat the array 3x2 times
repeat([1 2; 3 4], 3, 2)6×4 Matrix{Int64}:
1 2 1 2
3 4 3 4
1 2 1 2
3 4 3 4
1 2 1 2
3 4 3 4comprehension for 1D array
[i^2 for i in 1:10 if i >= 5]6-element Vector{Int64}:
25
36
49
64
81
1002D comprehension for a 2x3 array
[x * y for x in 1:2, y in 1:3]2×3 Matrix{Int64}:
1 2 3
2 4 6casting comprehension result element type to Float64
Float64[x^2 for x in 1:4]4-element Vector{Float64}:
1.0
4.0
9.0
16.0This is a 1-element tuple containing a vector
tuple([1,2,3])([1, 2, 3],)How to convert vector to tuple
Tuple([1,2,3])(1, 2, 3)2D array (matrix) A space is a shorthand for hcat() A semicolon is a shorthand for vcat()
A = [1 2 3;
4 5 6]2×3 Matrix{Int64}:
1 2 3
4 5 6Accessing elements
A[1, 2]2Accessing a range of elements
A[1:2, 2:3]2×2 Matrix{Int64}:
2 3
5 6Array total length
length(A)6axes(A)(Base.OneTo(2), Base.OneTo(3))size(A)(2, 3)ndims(A)2transpose(A)3×2 transpose(::Matrix{Int64}) with eltype Int64:
1 4
2 5
3 6(Conjugate transpose) Adjoint
A'3×2 adjoint(::Matrix{Int64}) with eltype Int64:
1 4
2 5
3 6Matrix-vector multiplication
b = A * x2-element Vector{Int64}:
38
92Find x for Ax = b, using left division operator /
A\b ≈ xtrueFlatten A to an (1D) vector
vec(A)6-element Vector{Int64}:
1
4
2
5
3
6Arrays are mutable (i.e. you can update the contents) objects You should make a copy if you want the original one intact
A[1, 1] = 0
A2×3 Matrix{Int64}:
0 2 3
4 5 6Associative collections¶
d[key]accesses values by keysd[key] = valuesets a key-value pair for a mutable dictionary.delete!(d, key)deletes the kay (and its partner) from a mutable dictionary.keys(d)returns a series of keysvalues(d)returns a series of valuespairs(d)returns a series of (key => value) pairsmerge(d1, d2, ...)return combinations of several dicts.merge!(d1, d2, ...)combine several dicts and update the first one.get(d, key, default)returns the value stored for the given key, or the given default value if no mapping for the key is present.
Named tuples¶
Namedtuples are tuples with key-value pairs.
nt = (a=1, b=2, c=4)(a = 1, b = 2, c = 4)nt[1]1nt.a == nt[:a] == nt[1]trueHow to fill a named tuple elegantly
a = 1
b = 2
c = 3
nt = (; a, b, c)(a = 1, b = 2, c = 3)Dictionaries¶
Dictionaries are mutable mappings of key => value.
eng2sp = Dict("one" => "uno", "two" => "dos", "three" => "tres")Dict{String, String} with 3 entries:
"two" => "dos"
"one" => "uno"
"three" => "tres"eng2sp["two"]"dos"eng2sp["five"] = "cinco""cinco"keys(eng2sp)KeySet for a Dict{String, String} with 4 entries. Keys:
"two"
"one"
"three"
"five"values(eng2sp)ValueIterator for a Dict{String, String} with 4 entries. Values:
"dos"
"uno"
"tres"
"cinco"get(eng2sp, "one", "N/A")"uno"get(eng2sp, "four", "N/A")"N/A"haskey(eng2sp, "one")trueElements are not ordered
for (k ,v) in eng2sp
println(k, " => ", v)
endtwo => dos
one => uno
three => tres
five => cinco
Creating a dict from an array of tuples
Dict([('a', 1), ('c', 3), ('b', 2)])Dict{Char, Int64} with 3 entries:
'a' => 1
'c' => 3
'b' => 2Creating a Dict via a generator (similar to comprehensions)
Dict(i => i^2 for i = 1:10)Dict{Int64, Int64} with 10 entries:
5 => 25
4 => 16
6 => 36
7 => 49
2 => 4
10 => 100
9 => 81
8 => 64
3 => 9
1 => 1Dict(zip("abc", 1:3))Dict{Char, Int64} with 3 entries:
'a' => 1
'c' => 3
'b' => 2Broadcasting (Dot) syntax¶
Broadcasting turns scalar operations into vector ones.
[1, 2, 3] .+ [4, 5, 6]3-element Vector{Int64}:
5
7
9[1, 2, 3] .+ 43-element Vector{Int64}:
5
6
7Element-wise operation
sinpi.([0.5, 1.0, 1.5, 2.0])4-element Vector{Float64}:
1.0
0.0
-1.0
0.0Create a dictionary with a list of keys and a list of values
ks = (:a, :b, :c)
vs = (1, 2, 3)
Dict(ks .=> vs)Dict{Symbol, Int64} with 3 entries:
:a => 1
:b => 2
:c => 3How to do logspace() in Julia
exp10.(range(-3.0, 3.0, 50))50-element Vector{Float64}:
0.001
0.0013257113655901094
0.0017575106248547913
0.002329951810515372
0.0030888435964774815
0.004094915062380423
0.005428675439323859
0.0071968567300115215
0.009540954763499945
0.012648552168552958
⋮
104.81131341546852
138.94954943731375
184.20699693267164
244.20530945486522
323.74575428176433
429.1934260128778
568.9866029018299
754.3120063354615
1000.0Make a 9*9 multiplication table
collect(1:9) .* transpose(collect(1:9))9×9 Matrix{Int64}:
1 2 3 4 5 6 7 8 9
2 4 6 8 10 12 14 16 18
3 6 9 12 15 18 21 24 27
4 8 12 16 20 24 28 32 36
5 10 15 20 25 30 35 40 45
6 12 18 24 30 36 42 48 54
7 14 21 28 35 42 49 56 63
8 16 24 32 40 48 56 64 72
9 18 27 36 45 54 63 72 81Custom data structures and Methods¶
https://
struct or mutable struct
struct Point
x
y
endDefine a default constructor
Point() = Point(0.0, 0.0)Main.var"##225".Pointp1 = Point(1.0, 2.0)
p2 = Point(-3.0, 2.0)Main.var"##225".Point(-3.0, 2.0)Define a method for our custom type
add(a::Point, b::Point) = Point(a.x + b.x, a.y + b.y)add (generic function with 1 method)add(p1, p2)Main.var"##225".Point(-2.0, 4.0)Methods¶
You can overload the same function with different argument types/numbers. Julia will try to find the right function for the argument type(s).
func(a::Int) = a + 2
func(a::AbstractFloat) = a/2
func(a::Rational) = a//11
func(a::Complex) = sqrt(a)
func(a, b::String) = "$a, $b"func (generic function with 5 methods)func(1)3func(3.0)1.5func(33//4)3//4func(-2 + 0im)0.0 + 1.4142135623730951imfunc(true, "it just works")"true, it just works"This notebook was generated using Literate.jl.