After launching Julia, execute using IJulia
followed by jupyterlab()
at the command prompt to launch Jupyter in your default browser. Julia has an extensive set of built-in functions as well as additional packages that consist of functions related to more specialized topics. It can be used in two different ways: as a traditional programming environment and as an interactive calculator. In calculator mode (running Julia either in Jupyter or at the command prompt), the built-in and package functions provide a convenient means of performing one-off calculations and graphical plotting; in programming mode, running Julia in an IDE like Visual Studio Code (VS Code) with Julia extensions, provides a programming environment (editor, debugger, and profiler) that enables the user to write their own functions and scripts.
Julia scripting language:
In Julia, integer and real-valued scalars are distinguished, and vectors and matrices are special 1- and 2-dimensional cases of an n-dimensional array:
Int64
integer variableFloat64
real-valued variableArray{Int64,1}
1-dimensional integer array2×4 Array{Int64,2}
2-dimensional integer array.Scalar variables and arrays can be created as follows (#
is used for comments in code, Markdown is used for this comment since it is in a separate non-code cell):
n = 1 # Integer number
1
x = 1. # Real (or floating point) number
1.0
Int(x) # Convert real to integer
1
Float64(n) # Convert integer to real
1.0
a = [1, 2, 3]
3-element Vector{Int64}: 1 2 3
A = [1 2 3 4; 5 6 7 8]
2×4 Matrix{Int64}: 1 2 3 4 5 6 7 8
In Julia, the case of a variable matters; e.g., the arrays a
and A
are different variables. The last expression in a cell is displayed. To suppress the output, end the expression with a semicolon (;
):
A = [1 2 3 4; 5 6 7 8];
The macro @show
can be used to display an expression. An empty array is considered of type Any
:
@show a = []
a
a = [] = Any[]
Any[]
The following operators and functions can be used to automatically create basic structured arrays:
a = collect(1:5)
a = [1:5;] # Note: the ';' is used to indicate that the 5-element array should be generated
5-element Vector{Int64}: 1 2 3 4 5
@show typeof([1:5;])
@show [1:5] # [1:5] only creates a 1-element UnitRange variable (used for iteration, efficient since [1:5000000000] would also be a 1-element variable)
typeof(1:5)
typeof([1:5;]) = Vector{Int64} [1:5] = UnitRange{Int64}[1:5]
UnitRange{Int64}
a = [1:2:5;]
3-element Vector{Int64}: 1 3 5
a = [10:-2:1;]
5-element Vector{Int64}: 10 8 6 4 2
a = ones(5) # Default is floating point
5-element Vector{Float64}: 1.0 1.0 1.0 1.0 1.0
a = Int(a) # Convert to integer array => Error: function Int only works on scalar variables, not array variables
MethodError: no method matching Int64(::Vector{Float64}) Closest candidates are: (::Type{T})(::AbstractChar) where T<:Union{AbstractChar, Number} at char.jl:50 (::Type{T})(::BigInt) where T<:Union{Int128, Int16, Int32, Int64, Int8} at gmp.jl:356 (::Type{T})(::Base.TwicePrecision) where T<:Number at twiceprecision.jl:243 ... Stacktrace: [1] top-level scope @ In[14]:1 [2] eval @ .\boot.jl:360 [inlined] [3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String) @ Base .\loading.jl:1116
a = Int.(a) # Convert to integer array => Need to use "." after function name to apply it each element in array
5-element Vector{Int64}: 1 1 1 1 1
a = ones(5,1) # 5x1 is different from a 5-element array (2-D vs. 1-D)
5×1 Matrix{Float64}: 1.0 1.0 1.0 1.0 1.0
a = zeros(5)
5-element Vector{Float64}: 0.0 0.0 0.0 0.0 0.0
The rand
function generates random numbers between 0 and 1. (Each time it is run, it generates different numbers.)
a = rand(3)
3-element Vector{Float64}: 0.19072908804018018 0.8504511168939277 0.5871408251928645
b = rand(3)
3-element Vector{Float64}: 0.39805050625441774 0.5551704155549042 0.6577878845881842
B = rand(2,3)
2×3 Matrix{Float64}: 0.438207 0.395669 0.925078 0.984743 0.679984 0.19319
A random permutation of the integers 1 to n can be generates using the randperm(n)
function, which is in the Random
package and using Random
is used to load it the first time it is called:
using Random
randperm(5)
5-element Vector{Int64}: 2 1 3 4 5
varinfo()
name | size | summary |
---|---|---|
A | 104 bytes | 2×4 Matrix{Int64} |
B | 88 bytes | 2×3 Matrix{Float64} |
Base | Module | |
Core | Module | |
Main | Module | |
a | 64 bytes | 3-element Vector{Float64} |
b | 64 bytes | 3-element Vector{Float64} |
n | 8 bytes | Int64 |
x | 8 bytes | Float64 |
Variables cannot be removed from the worspace and, instead, can be set equal to nothing
to that the memory they were using is freed:
A = nothing
a = nothing
varinfo()
name | size | summary |
---|---|---|
A | 0 bytes | Nothing |
B | 88 bytes | 2×3 Matrix{Float64} |
Base | Module | |
Core | Module | |
Main | Module | |
a | 0 bytes | Nothing |
b | 64 bytes | 3-element Vector{Float64} |
n | 8 bytes | Int64 |
x | 8 bytes | Float64 |
a = [10:15;]
a[3] # Select single element
12
a[[2,4]] # Select multiple elements
2-element Vector{Int64}: 11 13
idx = [2,4] # Use index array
a[idx]
2-element Vector{Int64}: 11 13
using Random
Random.seed!(1234) # Set seed to allow replication
x = rand(3) # Array of random values
3-element Vector{Float64}: 0.5908446386657102 0.7667970365022592 0.5662374165061859
x[1]
0.5908446386657102
Random.seed!(1234)
x = rand(1) # Want single random value, but returned as 1-element array
1-element Vector{Float64}: 0.5908446386657102
Random.seed!(1234)
x = rand(1)[] # Returned as single value
0.5908446386657102
The colon operator :
is used to select an entire row or column:
A = [1 2 3 4; 5 6 7 8]
A[:,:]
2×4 Matrix{Int64}: 1 2 3 4 5 6 7 8
A[1,2] # Select single element
2
A[1,:] # Select single row
4-element Vector{Int64}: 1 2 3 4
A[:,1] # Select single column
2-element Vector{Int64}: 1 5
A[:,[1,3]] # Select two columns
2×2 Matrix{Int64}: 1 3 5 7
The vector $ \left[ {\begin{array}{c} 1,3 \end{array}} \right] $ is an index array, where each element corresponds to a column index number of the original matrix A. The keyword end
can be used to indicate the last row or column:
A[:,end]
2-element Vector{Int64}: 4 8
A[:,end-1]
2-element Vector{Int64}: 3 7
The selected portion of the one array can be assigned to a new array:
B = A[:,3:end]
2×2 Matrix{Int64}: 3 4 7 8
a = [1:5;]
5-element Vector{Int64}: 1 2 3 4 5
a[2] = 6
a
5-element Vector{Int64}: 1 6 3 4 5
Assign a value to multiple locations:
a[[1,3]] = 0 # Error: need to use dot so that assignment is made to multiple elements in array
ArgumentError: indexed assignment with a single value to many locations is not supported; perhaps use broadcasting `.=` instead? Stacktrace: [1] setindex_shape_check(::Int64, ::Int64) @ Base .\indices.jl:261 [2] _unsafe_setindex!(#unused#::IndexLinear, A::Vector{Int64}, x::Int64, I::Vector{Int64}) @ Base .\multidimensional.jl:896 [3] _setindex! @ .\multidimensional.jl:887 [inlined] [4] setindex!(A::Vector{Int64}, v::Int64, I::Vector{Int64}) @ Base .\abstractarray.jl:1267 [5] top-level scope @ In[41]:1 [6] eval @ .\boot.jl:360 [inlined] [7] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String) @ Base .\loading.jl:1116
a[[1,3]] .= 0 # Note: '.=' is used instead of '=' to assign to mulitple locations
a
5-element Vector{Int64}: 0 6 0 4 5
a[[1,3]] .= [7,8]
a
5-element Vector{Int64}: 7 6 8 4 5
A[1,2] = 100
A
2×4 Matrix{Int64}: 1 100 3 4 5 6 7 8
splice!(a,3) # Note: the "!" at end of function name is used to signify that the values of input
a # variables are changed by the function (don't need to assign output)
4-element Vector{Int64}: 7 6 4 5
splice!(a,[1,4])
a
2-element Vector{Int64}: 6 4
Delete and return last element:
a = [1:5;]
b = pop!(a),
a
(5, [1, 2, 3, 4])
b = popfirst!(a), # Delete and return first element
a
(1, [2, 3, 4])
a = [3:5;]
insert!(a,2,8) # Insert scalar value 8 into array at location 2
4-element Vector{Int64}: 3 8 4 5
push!(a,6) # Insert 6 at end of array
5-element Vector{Int64}: 3 8 4 5 6
pushfirst!(a,7) # Insert 7 at beginning of array
6-element Vector{Int64}: 7 3 8 4 5 6
b = [10:12;]
append!(a,b) # Append another array to end of array
9-element Vector{Int64}: 7 3 8 4 5 6 10 11 12
c = ones(3)
append!(a,c) # Append another array to end of array
12-element Vector{Int64}: 7 3 8 4 5 6 10 11 12 1 1 1
The following operators and functions can be used to manipulate arrays:
A = [1 3 4; 5 7 8]
transpose(A)
A' # (Transpose)
3×2 adjoint(::Matrix{Int64}) with eltype Int64: 1 5 3 7 4 8
reverse(A, dims = 2) # (Flip columns)
2×3 Matrix{Int64}: 4 3 1 8 7 5
reverse(A, dims = 1) # (Flip rows)
2×3 Matrix{Int64}: 5 7 8 1 3 4
[A B] # (Concatenate matrices)
2×5 Matrix{Int64}: 1 3 4 3 4 5 7 8 7 8
[A [10 20]'; [30:10:60;]']
3×4 Matrix{Int64}: 1 3 4 10 5 7 8 20 30 40 50 60
a = A[:] # (Convert matrix to vector)
6-element Vector{Int64}: 1 5 3 7 4 8
A = reshape(a,2,3) # (Convert vector to matrix)
2×3 Matrix{Int64}: 1 3 4 5 7 8
A = [1 3 4; 5 7 8]
2 + A # Error: '+' used instead of '.+'
MethodError: no method matching +(::Int64, ::Matrix{Int64}) For element-wise addition, use broadcasting with dot syntax: scalar .+ array Closest candidates are: +(::Any, ::Any, ::Any, ::Any...) at operators.jl:560 +(::T, ::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} at int.jl:87 +(::LinearAlgebra.UniformScaling, ::AbstractMatrix{T} where T) at C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\LinearAlgebra\src\uniformscaling.jl:154 ... Stacktrace: [1] top-level scope @ In[61]:2 [2] eval @ .\boot.jl:360 [inlined] [3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String) @ Base .\loading.jl:1116
2 .+ A # Note: '.+' is used instead of '+'
2×3 Matrix{Int64}: 3 5 6 7 9 10
B = 2 * A # Note: '*' OK for multiplication; reason?, see next cell
2×3 Matrix{Int64}: 2 6 8 10 14 16
B = 2A # Don't need '*' if multipying a number and variable
2×3 Matrix{Int64}: 2 6 8 10 14 16
Arrays are multiplied together in two different ways: matrix multiplication, where the inner dimensions of the arrays must be the same, and element-by-element multiplication, also called broadcasting, indicated by the use of a dot (.) along with the operator, where the arrays must have compatible sizes: two arrays have compatible sizes if each respective dimension either (a) has the same size, or (b) the size of one of the arrays is one, in which case the array with the size-one dimension is automatically duplicated so that it matches the size of the other array, resulting in an output array with a dimension is equal to the non-one size dimension; i.e.,
$ \begin{eqnarray}\textsf{Matrix multiplication:}\;\; {{\bf{A}}_{m \times n}}\;*\;{{\bf{B}}_{n \times p}} &=& {{\bf{C}}_{m \times p}}\\ \textsf{Element-by-element multiplication:}\;\; {{\bf{A}}_{m \times n}}\,.*\;{{\bf{B}}_{m \times n}} &=& {{\bf{C}}_{m \times n}}\\ {{\bf{A}}_{m \times n}}\,.*\;{{\bf{b}}_{1 \times n}} &=& {{\bf{C}}_{m \times n}}\\ {{\bf{a}}_{m \times 1}}\,.*\;{{\bf{B}}_{m \times n}} &=& {{\bf{C}}_{m \times n}}\\ {{\bf{a}}_{m \times 1}}\,.*\;{{\bf{b}}_{1 \times n}} &=& {{\bf{C}}_{m \times n}}\\ {{\bf{a}}_{1 \times n}}\,.*\;{{\bf{b}}_{m \times 1}} &=& {{\bf{C}}_{m \times n}}\end{eqnarray} $
A * B # (Error: 2x3 * 2x3 ≠ 2x3)
DimensionMismatch("matrix A has dimensions (2,3), matrix B has dimensions (2,3)") Stacktrace: [1] _generic_matmatmul!(C::Matrix{Int64}, tA::Char, tB::Char, A::Matrix{Int64}, B::Matrix{Int64}, _add::LinearAlgebra.MulAddMul{true, true, Bool, Bool}) @ LinearAlgebra C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\LinearAlgebra\src\matmul.jl:814 [2] generic_matmatmul!(C::Matrix{Int64}, tA::Char, tB::Char, A::Matrix{Int64}, B::Matrix{Int64}, _add::LinearAlgebra.MulAddMul{true, true, Bool, Bool}) @ LinearAlgebra C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\LinearAlgebra\src\matmul.jl:802 [3] mul! @ C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\LinearAlgebra\src\matmul.jl:302 [inlined] [4] mul! @ C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\LinearAlgebra\src\matmul.jl:275 [inlined] [5] *(A::Matrix{Int64}, B::Matrix{Int64}) @ LinearAlgebra C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\LinearAlgebra\src\matmul.jl:153 [6] top-level scope @ In[65]:1 [7] eval @ .\boot.jl:360 [inlined] [8] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String) @ Base .\loading.jl:1116
C = A * B' # (2x3 * 3x2 = 2x2)
2×2 Matrix{Int64}: 52 116 116 276
C = A' * B # (3x2 * 2x3 = 3x3)
3×3 Matrix{Int64}: 52 76 88 76 116 136 88 136 160
a = [1:3;]
a' * a # (1x3 * 3x1 = 1x1)
14
A * a # (2x3 * 3x1 = 2x1)
2-element Vector{Int64}: 19 43
C = A .* B # (2x3 .* 2x3 = 2x3)
2×3 Matrix{Int64}: 2 18 32 50 98 128
b = [2, 4, 6] # Assuming 3-element = 3x1 array
A .* b # Error: 2x3 .* 3x1 => Not compatible sizes
DimensionMismatch("arrays could not be broadcast to a common size; got a dimension with lengths 2 and 3") Stacktrace: [1] _bcs1 @ .\broadcast.jl:501 [inlined] [2] _bcs @ .\broadcast.jl:495 [inlined] [3] broadcast_shape @ .\broadcast.jl:489 [inlined] [4] combine_axes @ .\broadcast.jl:484 [inlined] [5] instantiate @ .\broadcast.jl:266 [inlined] [6] materialize(bc::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{2}, Nothing, typeof(*), Tuple{Matrix{Int64}, Vector{Int64}}}) @ Base.Broadcast .\broadcast.jl:883 [7] top-level scope @ In[71]:2 [8] eval @ .\boot.jl:360 [inlined] [9] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String) @ Base .\loading.jl:1116
A .* b' # 2x3 .* 1x3 => 2x3 (compatible sizes)
2×3 Matrix{Int64}: 2 12 24 10 28 48
c = [3,5] # Assuming 2-element = 2x1 array
A .* c # 2x3 .* 2x1 => 2x3 (compatible sizes)
2×3 Matrix{Int64}: 3 9 12 25 35 40
b .* c' # 3x1 .* 1x2 => 3x2 (compatible sizes)
3×2 Matrix{Int64}: 6 10 12 20 18 30
Arrays are added together element by element; thus, each array must be the same size or a compatible size; i.e.,
$ \begin{eqnarray}\textsf{Addition:}\;\; {{\bf{A}}_{m \times n}}+{{\bf{B}}_{m \times n}} &=& {{\bf{C}}_{m \times n}}\\ {{\bf{A}}_{m \times n}}+{{\bf{b}}_{1 \times n}} &=& {{\bf{C}}_{m \times n}}\\ {{\bf{a}}_{m \times 1}}+{{\bf{B}}_{m \times n}} &=& {{\bf{C}}_{m \times n}}\\ {{\bf{a}}_{m \times 1}}+{{\bf{b}}_{1 \times n}} &=& {{\bf{C}}_{m \times n}}\\ {{\bf{a}}_{1 \times n}}+{{\bf{b}}_{m \times 1}} &=& {{\bf{C}}_{m \times n}}\end{eqnarray} $
C = A + B # (2x3 + 2x3 = 2x3)
2×3 Matrix{Int64}: 3 9 12 15 21 24
The 3-element array a is by default a 3 × 1 column vector that is not compatible with A:
a = [1:3;]
a .+ A # (Error: 3x1 + 2x3 ≠ 2x3)
DimensionMismatch("arrays could not be broadcast to a common size; got a dimension with lengths 3 and 2") Stacktrace: [1] _bcs1 @ .\broadcast.jl:501 [inlined] [2] _bcs @ .\broadcast.jl:495 [inlined] [3] broadcast_shape @ .\broadcast.jl:489 [inlined] [4] combine_axes @ .\broadcast.jl:484 [inlined] [5] instantiate @ .\broadcast.jl:266 [inlined] [6] materialize(bc::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{2}, Nothing, typeof(+), Tuple{Vector{Int64}, Matrix{Int64}}}) @ Base.Broadcast .\broadcast.jl:883 [7] top-level scope @ In[76]:2 [8] eval @ .\boot.jl:360 [inlined] [9] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String) @ Base .\loading.jl:1116
Convert a to a row vector so that it is compatible with A:
a' .+ A # (1x3 + 2x3 = 2x3)
2×3 Matrix{Int64}: 2 5 7 6 9 11
b = [4:5;]
b .+ a' # (2x1 + 1x3 = 2x3)
2×3 Matrix{Int64}: 5 6 7 6 7 8
The elements of a single array can be added together using
the sum
and cumsum
functions. Since only the last expression in a cell is displayed, the macro @show
can be used to display an expression that is not the last:
@show a = [1:5;]
sum(a) # (Array summation)
a = [1:5;] = [1, 2, 3, 4, 5]
15
cumsum(a) # (Cumulative summation)
5-element Vector{Int64}: 1 3 6 10 15
By default, Julia sums all the elements in a matrix. To sum each row or column of a matrix, the dimension must be specified:
A = [1 3 4; 5 7 8]
sum(A) # (Sum entire matrix)
28
sum(A, dims = 1) # (Sum along columns)
1×3 Matrix{Int64}: 6 10 12
sum(A, dims = 2) # (Sum along rows)
2×1 Matrix{Int64}: 8 20