Julia - first contact

Resources

Hint for starting

Use the Cheat Sheet to see a compact and rather comprehensive list of basic things Julia. This notebook tries to discuss some concepts behind Julia.

2.2 ms

Open Source

  • Julia is an Open Source project started at MIT

  • Julia itself is distributed under an MIT license

    • packages often have different licenses

  • Development takes place on github

  • As of October 2020, more than 1000 contributors to the code

  • The Open Source paradigm corresponds well to the fundamental requirement that scientific research should be transparent and reproducible

11.6 μs

How to install and run Julia

  • Installation:

    • Download from julialang.org (recommended by Julia creators)

    • Installation via system package manager (yast, apt-get, homebrew...)

  • Running:

    • From command line: Edit source code in any editor

    • Julia plugin of Visual Studio code editor

    • Pluto notebooks in the browser

    • Jupyter notebooks in the browser

11.2 μs

REPL: Read-Evaluation-Print-Loop

Start REPL by calling julia in terminal

REPL modes:

  • Default mode: julia> prompt. Type backspace in other modes to enter default mode.

  • Help mode: help?> prompt. Type ? to enter help mode. Search via ?search_term

  • Shell mode: shell> prompt. Type ; to enter shell mode.

  • Package mode: Pkg> prompt. Type ] to enter package mode.

Helpful commands in REPL

  • quit() or Ctrl+D: exit Julia.

  • Ctrl+C: interrupt execution.

  • Ctrl+L: clear screen.

  • Append ; to suppress displaying output from a command

  • include("filename.jl"): source a Julia code file.

12.8 μs

Package management

  • Julia has an evolving package ecosystem developed by a growing community

  • Packages provide functionality which is not part of the core Julia installation

  • Each package is a git repository

    • Mostly on github as Package.jl, e.g. AbstractTrees

    • Packages can be added to and removed from Julia installation

    • Any packages can be installed via a git URL

  • Packages can be registered in package registries which are themselves git repositories containing metadata of registered packages.

    • By default, the General Registry is used

    • Registered packages are added by name

13 μs
Importing the package manager

In order to install(add) or remove a package, Julia has a package manager which itself is a package installed by default. We nee to import it in order to use it. The import statement makes all functions from the package available via qualified names, i.e. the function names need to be prefixed with the package name like Pkg.activate.

3.6 μs
146 μs
Environments

list of packages currently used is stored in a package environment. A particular directory can be activated by the package manager as the current package environment. The file Project.toml in that directory contains the list of packages installed, and the file Manifest.toml contains the particular versions ot the installed packages and those installed additionally as dependencies.

Here, we activate a temporary directory as package environment:

1.2 ms
250 μs
  • If we skip this step, a global environment stored in .julia/environments/vX.Y under the user home directory will be used. All packages from that global environment will be visible in the activated local evironments.

  • Environments allow to separate lists of packages with possibly different versions used in different projects

  • The pluto notebooks provided during the course always will use this type of temporary environment as created above.

2 ms
Adding and using packages

Now, we can add packages, possibly downloading them if necessary:

3.5 μs
5.6 s

The using statements makes all exported functions from a package available without the need to prefix their names with the name of the package:

7.1 μs

Add another package: AbstractTrees

2.4 μs

            
  Resolving package versions...
Updating `/tmp/jl_dxAEn7/Project.toml`
  [1520ce14] + AbstractTrees v0.3.3
Updating `/tmp/jl_dxAEn7/Manifest.toml`
  [1520ce14] + AbstractTrees v0.3.3
170 ms

List installed packages:

2.3 μs
Status `/tmp/jl_dxAEn7/Project.toml`
  [1520ce14] AbstractTrees v0.3.3
  [7f904dfe] PlutoUI v0.6.9
3.5 ms

Remove package:

2.1 μs
Status `/tmp/jl_dxAEn7/Project.toml`
  [7f904dfe] PlutoUI v0.6.9
Updating `/tmp/jl_dxAEn7/Project.toml`
  [1520ce14] - AbstractTrees v0.3.3
Updating `/tmp/jl_dxAEn7/Manifest.toml`
  [1520ce14] - AbstractTrees v0.3.3
102 ms
Updating packages

Packages can be updated to their newest version:

3.1 μs
[?25l[?25hStatus `/tmp/jl_dxAEn7/Project.toml`
  [7f904dfe] PlutoUI v0.6.9
   Updating registry at `~/.julia/registries/General`
   Updating registry at `~/.julia/registries/PackageNursery`
   Updating git-repo `git@github.com:j-fu/PackageNursery`
No Changes to `/tmp/jl_dxAEn7/Project.toml`
No Changes to `/tmp/jl_dxAEn7/Manifest.toml`
1.6 s
Pinning (fixing) package versions

Sometimes, it is a good idea to fix the version of a package installed. This can be achieved by specifying its version during Pkg.add()

3.1 μs
44.5 ms
Local copies of packages
  • Upon installation, local copies of the package source code is downloaded from git repository

  • By default located in .julia/packages subdirectory of your home folder

4.7 μs

Standard number types

  • Julia is a strongly typed language, so any variable has a type.

  • Standard number types allow fast execution because they are supported in the instruction set of the processors

  • Default types are autodected from expression

  • The typeof function allows to detect the type of a variable

5.9 μs

Integers

2.8 μs
i
1
832 ns
Int64
3.3 μs

Floating point

2.7 μs
x
10.0
957 ns
Float64
1.5 μs

Rational

2.8 μs
r
3//7
14.7 ms
Rational{Int64}
1.3 μs

Irrational

2.7 μs
p
π = 3.1415926535897...
2.5 μs
Irrational{:π}
1.7 μs

Complex

2.7 μs
z
17.5 + 3.0im
9.2 ms
Complex{Float64}
1.2 μs

Vectors

  • Elements of a given type stored contiguously in memory

  • Vectors and 1-dimensional arrays are the same

  • Vectors can be created for any element type

  • Element type can be determined by eltype method

6.1 μs
  • Construction by explicit list of elements:

3.5 μs
v1
2 μs
Int64
22 μs

We can create a vector of floats:

4.3 μs
v1f
6.7 ms
  • If one element in the initializer is float, the vector becomes float:

3.1 μs
v2
20.4 ms
  • Create vector of zeros for given type:

2.9 μs
v3
7.8 ms
  • Fill vector with constant data:

4 μs
6.7 ms

Ranges

  • Ranges describe sequences of numbers and can be used in loops, array constructors etc.

  • They contain the recipe for the sequences, not the full data.

5.1 μs
r1
1:10
3.7 μs
UnitRange{Int64}
1.5 μs
  • We can collect the sequence from a range into a vector:

2.8 μs
w1
2.4 ms
Array{Int64,1}
1.6 μs
  • We can add a step size to a range:

2.9 μs
r2
1.0:0.8:9.8
66 ms
StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}
1.5 μs
  • Create a vector from a list comprehension containing a range:

2.8 μs
v4
80.3 ms

Create a random vector of given size:

5.1 μs
v5
42.5 ms

Vector dimensions

4.2 μs
v6
10.1 ms
  • size is a tuple of dimensions

4.5 μs
2 ms
  • length describes the overall length:

3.2 μs
10
2 ms

Subarrays

  • Copies of parts of arrays:

3.6 μs
v7
5.5 μs
subv7
6.5 ms
2.3 μs
  • Views:

2.9 μs
v8
6.4 μs
subv8
5.1 μs
2.2 μs
  • The @views macro can turn a copy statement into a view

3.6 μs
v9
8 μs
3.9 μs
3.5 μs

Dot operations

  • element-wise operations on arrays

8.7 μs
v10
21.7 ms
32.1 ms
37 ms

Matrices

  • Elements of a given type stored contiguously in memory, with two-dimensional access

  • Matrices and 2-dimensional arrays are the same

4.5 μs
  • Zero initialization:

2.9 μs
m1
5×6 Array{Float64,2}:
 0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0
7.1 ms
  • undef initialization:

3.1 μs
m2
3×3 Array{Float64,2}:
 6.36599e-314  8.48798e-314  5.0e-324
 6.36599e-314  1.061e-313    0.0
 1.9098e-313   2.122e-314    0.0
2 ms
  • list comprehension:

3.1 μs
m3
6×5 Array{Float64,2}:
  0.367879    0.606531    1.0        1.64872    2.71828
 -0.153092   -0.252406   -0.416147  -0.68611   -1.1312
 -0.240462   -0.396455   -0.653644  -1.07768   -1.77679
  0.353227    0.582373    0.96017    1.58305    2.61001
 -0.0535265  -0.0882502  -0.1455    -0.239889  -0.39551
 -0.308677   -0.508923   -0.839072  -1.3834    -2.28083
92.9 ms
  • The size of a matrix is the tuple of the two matrix dimensions:

5.8 μs
2.6 ms

The length of a matrix is the length of the contiguous storage array in memory:

5.6 μs
30
1.8 ms

Linear Algebra

2.4 μs
7.3 ms

Let us create some linear algebra objects:

4.9 μs
n
10
3.3 μs
w
5 μs
u
2.2 μs
A
10×10 Array{Float64,2}:
 0.824022   0.399623  0.52761     0.800789   …  0.339729   0.251542  0.787242
 0.950459   0.614287  0.00529413  0.704582      0.520941   0.799017  0.901162
 0.0783334  0.302962  0.0757998   0.341549      0.305228   0.847785  0.442627
 0.185168   0.356941  0.386134    0.359076      0.980641   0.308131  0.385319
 0.865389   0.389219  0.0832434   0.0502272     0.0805102  0.306361  0.183116
 0.117851   0.366842  0.27298     0.0425427  …  0.333443   0.665354  0.447239
 0.416079   0.301092  0.357823    0.864643      0.295109   0.442502  0.343804
 0.398784   0.92582   0.507028    0.844632      0.160503   0.579967  0.367731
 0.193747   0.302114  0.345443    0.393442      0.890489   0.409108  0.0393411
 0.382147   0.272667  0.504316    0.880203      0.196281   0.246422  0.821393
3.7 μs
  • Mean square norm ||u||2=i=1nui2

3.1 μs
1.684103735769847
3.4 μs
  • Dot product: (u,w)=i=1nuiwi

6.2 μs
2.0555931450006275
3.3 μs
  • Matrix vector product

2.9 μs
5.2 μs
  • Trace (sum of main diagonal elements), determinant, inverse

3.1 μs
25.4 μs

Control structures

2.1 μs
  • Conditional execution

3.1 μs
cond1
false
774 ns
cond2
true
965 ns
"cond2"
1.2 μs
  • '?' operator for writing shorter code (borrowed from C)

5.5 μs
"nothing"
584 ns
  • for loop:

6.9 μs
1
2
3
4
5
26.6 ms
  • Preliminary exit of loop

3.1 μs
1
2
3
4
5
6
5.5 ms
  • Skipping iterations

2.9 μs
1
2
3
4
6
7
8
9
10
5.9 ms

Functions

  • All arguments to functions are passed by reference

  • Function name ending with ! indicates that the function mutates at least one argument, typically the first. This is a convention, not a syntax rule.

  • Function objects can be assigned to variables

Structure of function definition

 function func(req1, req2; key1=dflt1, key2=dflt2)
    # do stuff
     return out1, out2, out3
 end
  • Required arguments are separated with a comma and use the positional notation

  • Optional arguments need a default value in the signature

  • Return statement is optional, by default, the result of the last statement is returned

  • Multiple outputs can be returned as a tuple, e.g., return out1, out2, out3.

19.1 μs
func0 (generic function with 1 method)
36.3 μs
1
2.2 ms
201
7.6 ms
  • One line function definition

6 μs
g (generic function with 1 method)
15 μs
1.151562836514535
2.7 ms
  • Nested function definitions

3.3 μs
outerfunction (generic function with 1 method)
29.4 μs
1
2
3
4
5
6
7
8
9
10
11
12
13
5.8 ms
  • Functions are variables, too

2.8 μs
1.151562836514535
3.8 μs
  • Functions as function parameters

3 μs
F (generic function with 1 method)
13.6 μs
1.151562836514535
2.4 ms
  • Anonymous functions (convenient in function parameters):

3 μs
0.1411200080598672
2.5 ms
  • Do-block syntax: the body of first parameter is in the do ... end block:

3.5 μs
1.151562836514535
2.6 ms

Functions and vectors

  • Dot syntax can be used to make any function work on vectors

3.8 μs
v11
8.9 μs
26.1 ms
  • map function on vector

2.9 μs
40.8 ms
  • mapreduce: apply operator to each element and collect data

6.3 μs
0.0
33.2 ms
5.5
21.7 ms
5.5
22.1 ms

Macros

Julia allows to define macros which allow to modify Julia statements before they are compiled and executed. This capability is similar to the preprocessor in C or C++. Macro names start with @. Occasionally we will use predefined macros, e.g. @elapsed for returning the time used by some statement.

3.4 μs
0.000258831
259 μs