Julia Express
Julia Express
Bogumi Kaminski
Contents
1 Introduction
2 Getting around
4.1 Tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.4 Dictionaries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5 Strings
6 Programming constructs
7 Variable scoping
8 Modules
10
9 Operators
10
11
11
12 Random numbers
12
12
14 Plotting
12
15 Macros
12
13
1 Introduction
The Purpose of this document is to introduce programmers to Julia programming by example. This is a simplified
exposition of the language.1
It is best to execute these examples by copying them to a file and next running them using include function.
If some packages are missing on your system use Pkg.add to require installing them. There are many add-on packages
which you can browse at http://pkg.julialang.org/.
Major stuff not covered (please see the documentation):
1)
2)
3)
4)
5)
6)
7)
8)
parametric types;
parallel and distributed processing;
advanced I/O operations;
package management; see Pkg;
interaction with system shell; see run;
exception handling; see try;
creation of coroutines; see Task;
two-way integration with C and Fortran.
Remember that you can expect every major version of Julia to introduce breaking changes.
Check https://github.com/JuliaLang/julia/blob/master/NEWS.md for release notes.
All sugestions how this guide can be improved are welcomed. Please contact me at [email protected].
2 Getting around
Running julia invokes interactive (REPL) mode. In this mode some useful commands are:
1)
2)
3)
4)
5)
^D (exits Julia);
^C (interrupts computations);
? (enters help mode)
; (enters system shell mode)
putting ; after the expression will disable showing of its value.
Examples of some essential functions in REPL (they can be also invoked in scripts):
apropos("apropos")
@less(max(1,2))
# show the definition of max function when invoked with arguments 1 and 2
whos()
cd("D:/")
pwd()
include("file.jl")
exit(1)
clipboard([1,2])
clipboard()
workspace()
# 1 is not a prime
# conditional evaluation
1.0::Float64
true::Bool
c::Char
"s"::AbstractString
All basic types are immutable. Specifying type assertion is optional (and usually it is not needed, but I give it to show
how you can do it). Type assertions for variables are made in the same way and may improve code performance.
If you do not specify type assertion Julia will choose a default. Note that defaults might be different on 32-bit and
64-bit versions of Julia. A most important difference is for integers which are Int32 and Int64 respectively. This means
that 1::Int32 assertion will fail on 64-bit version. Notably Int is either Int64 or Int64 depending on version (the same
with UInt).
There is no automatic type conversion (especially important in function calls). Has to be explicit:
Int64(a)
# character to integer
Int64(2.0)
# float to integer
Int64(1.3)
# inexact error
Int64("a")
Float64(1)
# integer to float
Bool(1)
Bool(0)
Bool(2)
# conversion error
Char(89)
# integer to char
string(true)
# cast bool to string (works with other types, note small caps)
string(1,true) # string can take more than one argument and concatenate them
zero(10.0)
one(Int64)
Automatic promotion of many arguments to common type (if any) using promote:
promote(true, BigInt(1)//3, 1.0) # tuple (see Tuples) of BigFloats, true promoted to 1.0
promote("a", 1)
Many operations (arithmetic, assignment) are defined in a way that performs automatic type promotion.
One can verify type of argument:
Number
Complex{T<:Real}
Irrational{sym}
Real
Rational{T<:Integer}
Integer
AbstractFloat
Float16
Bool
Signed
Unsigned
Int8
UInt8
Int16
UInt16
Int32
UInt32
Int64
UInt64
Int128
UInt128
BigInt
Float32
Float64
BigFloat
typeof("abc")
isa(1.0, Float64)
# true
isa(1.0, Number)
super(Int64)
# supertype of Int64
subtypes(Real)
# big integer
Additionally #undef indicates an incompletely initialized instance (see documentation for details).
4.1 Tuples
Tuples are immutable sequences indexed from 1:
()
# empty tuple
(1,)
("a", 1)
# 1 (element)
x[1:2]
# (1, 2) (tuple)
x[4]
# bounds error
x[1] = 1
a, b = x
4.2 Arrays
Arrays are mutable and passed by reference. Array creation:
Array(Char, 2, 3, 4) # 2x3x4 array of Chars
Array{Int64}(0, 0)
cell(2, 3)
zeros(5)
ones(5)
ones(Int64, 2, 1)
trues(3), falses(3)
eye(3)
1:10
# iterable from 1 to 10
1:2:10
reshape(1:12, 3, 4)
fill("a", 2, 2)
resize!(x, 5)
[1]
[1 2]
[1, 2]
[1; 2]
[1 2 3; 1 2 3]
[1; 2] == [1 2]
[(1, 2)]
# 1-element vector
collect((1, 2))
[[1 2] 3]
[[1; 2]; 3]
# type of elements in a
length(a)
# number of elements in a
size(a)
vec(a)
squeeze(a, 2)
sum(a, 3)
count(x -> x > 0, a) # count number of times a predicate is true, similar: all, any
Access functions:
a = linspace(0, 1)
# LinSpace{Float64} of length 50
a[1]
a[end]
a[1:2:end]
sub(a, 1:2:50)
endof(a)
# 3-element vector
a[1, :]
# 1x4 matrix
Array assignment:
x = reshape(1:8, 2, 4)
x[:,2:3] = [1 2]
# OK
# shallow copy
# identical as x
# contents to original x
# vector of Any
[1 2]::Array{Int64, 2}
# matrix of Int64
# access field
p.meta = 2
p.x = 1.5
p.z = 1
fieldnames(p)
You can define type to be immutable by replacing type by immutable. There are also union types (see documentation
for details).
4.4 Dictionaries
Associative collections (key-value dictionaries):
x = Dict{Float64, Int64}()
y = Dict("a"=>1, "b"=>2)
# filled dictionary
y["a"]
# element retrieval
y["c"]
# error
y["c"] = 3
# added element
haskey(y, "b")
keys(y), values(y)
delete!(y, "b")
get(y,"c","default")
Julia also supports operations on sets and dequeues, priority queues and heaps (please refer to documentation).
5 Strings
String operations:
"Hi " * "there!"
"Ho " ^ 3
# string concatenation
repr(123.3)
# repeat string
x = 123
"$x + 3 = $(x+3)"
"\$199"
ismatch(r, "CD")
m = match(r, "ACBD") # find first regexp match, see documentation for details
6 Programming constructs
The simplest way to create new variable is by assignment:
x = 1.0
# x is Float64
x = 1
# after: y = 9; b = 3
z = 1
elseif 1==2
z = 2
else
a = 3
end
break
end
end
for x in 1:10
if 3 < x < 6
continue # skip one iteration
end
println(x)
end
f(3, 2)
f(3)
# 13 returned
# type restriction
# explicit return of a tuple
end
g(x::Int, y::Bool) = x * y
g(2, true)
methods(g)
(x -> x^2)(3)
() -> 0
# result is 0
x = (2, 3)
# tuple
f(x)
# error
f(x...)
# OK - tuple unpacking
t()
# 2 returned
t()
q(f::Function, x) = 2 * f(x)
q(x -> 2x, 10)
q(10) do x
2 * x
end
m = reshape(1:12, 3, 4)
map(x -> x ^ 2, m)
As a convention functions with name ending with ! change their arguments in-place. See for example resize! in this
document.
Default function argument beasts:
y = 10
f1(x=y) = x; f1()
# 10
f2(x=y,y=1) = x; f2()
# 10
f3(y=1,x=y) = x; f3()
# 1
f4(;x=y) = x; f4()
# 10
7 Variable scoping
The following constructs introduce new variable scope: function, while, for, try/catch, let, type.
You can define variables as:
global: use variable from global scope;
local: define new variable in current scope;
const: ensure variable type is constant (global only).
Special cases:
t
f() = global t = 1
f()
function f1(n)
x = 0
for i = 1:n
x = i
end
x
end
f1(10)
function f2(n)
x = 0
for i = 1:n
local x
x = i
end
x
end
f2(10)
function f3(n)
for i = 1:n
local x
x = i
end
x
end
f3(10)
const x = 2
x = 3 # warning, value changed
x = 3.0 # error, wrong type
function fun() # no warning
const x = 2
x = true
end
fun()
# true, no warning
10
i += 1
end
Fs[1](), Fs[2]() # (2, 2); the same binding for j
Fs = cell(2)
i = 1
while i <= 2
let j = i
Fs[i] = () -> j
end
i += 1
end
Fs[1](), Fs[2]() # (1, 2); new binding for j
Fs = cell(2)
i = 1
for i in 1:2
j = i
Fs[i] = () -> j
end
Fs[1](), Fs[2]() # (1, 2); for loops and comprehensions rebind variables
end
8 Modules
Modules encapsulate code. Can be reloaded, which is useful to redefine functions and types, as top level functions
and types are defined as constants.
module M # module name
export x # what module exposes for the world
x = 1
y = 2 # hidden variable
end
whos(M) # list exported variables
x
M.y
9 Operators
Julia follows standard operators with the following quirks:
true || false
[1 2] & [2 1]
1 < 2 < 3
[1 2] .< [2 1]
x = [1 2 3]
2x + 2(x+1)
y = [1, 2, 3]
x + y
# error
11
x + y # 1x3 matrix
x * y # array multiplication, 1-element vector (not scalar)
x .* y # element-wise multiplication, 3x3 array
x == [1 2 3]
# error
z .+ x # x broadcasted vertically
z .+ y # y broadcasted horizontally
# explicit broadcast of singelton dimensions
# function + is called for each array element
broadcast(+, [1 2], [1; 2])
nextfloat(2.0)
# false
# true
isequal(1, 1.0)
# true
1 == 1.0
# true
1 === 1.0
# false
isfinite(Inf)
ntuple(x->2x, 3)
isdefined(:x)
isempty("abc")
b in "abc"
12
12 Random numbers
Basic random numbers:
srand(1)
rand()
rand(3, 4)
b = Beta(0.4, 0.8)
mean(b)
rand(b, 100)
# contains value
# OK
get(x2)
# error - missing
isnull(x1)
# false
isnull(x2)
# true
14 Plotting
There are several plotting packages for Julia: Winston, Gadfly and PyPlot. Here we show how to use on Winston.
using Winston # load Winston plotting package
x = linspace(0, 1, 100)
y = sin(4x*pi) .* exp(-5x)
p = FramedPlot(title="4x\\pi",xlabel="x", ylabel="f(x)")
add(p, Curve(x, y))
savefig(p, "fun.pdf")
srand(1) # second plot
x, y = randn(10000), randn(10000)
plothist2d([x y], 100)
15 Macros
You can define macros (see documentation for details). Useful standard macros.
Assertions:
@assert 1 == 2 "ERROR"
using Base.Test
@test 1 == 2
# similar to assert; error
@test_approx_eq 1 1.1
# error
@test_approx_eq_eps 1 1.1 0.2 # no error
Function vectorization:
13
# OK
# OK
# OK
# OK
Benchmarking:
@time [x for x in 1:10^6].
# return time
# start timer
toc()
toq()
0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8