Engee documentation

Arrays, vectors and matrices in Engee

Introduction

Arrays, vectors and matrices are used in Engee to handle data, parameters and complex structures. These structures, implemented in the language Julia, allow efficient storage and processing of numerical information, including computational results, signals, and parameters of models. This paper discusses the features of each of them.

In Julia, the numbering of elements of arrays, vectors, and matrices begins with 1 rather than 0 as in some other languages. The last element has the index end. This is in keeping with the mathematical tradition, where indexing also starts with one. For example, the first element of the array a = [1, 2, 3] is accessed by a[1], and the last element by a[end]. See below for more details.

An array is a generalised multidimensional container that can contain elements of any type. Arrays in Julia support any number of dimensions, making them a versatile tool for storing and manipulating data:

A = rand(2, 2, 3)
Output
2×2×3 Array{Float64, 3}:
[:, :, 1] =
 0.159525  0.787948
 0.358068  0.124023

[:, :, 2] =
 0.228296  0.292929
 0.712896  0.0253828

[:, :, 3] =
 0.3547    0.837655
 0.474441  0.201402

Arrays are dynamic and static:

  • Dynamic arrays are arrays whose size can change during programme execution. They are stored in memory with an eye to possible expansion, making them more flexible but less optimal for computationally intensive tasks. Example:

    dynamic_array = [1, 2, 3]
    dynamic_array[2] = 5 # Присваивание значения
    push!(dynamic_array, 4) # Добавление элемента
    deleteat!(dynamic_array, 3) # Удаление элемента с индексом 3
    Output
    4-element Vector{Int64}:
     1
     5
     3
     4
  • Static arrays are arrays of a fixed size that is set at the creation stage. They are stored in memory as a continuous block of data, which allows operations to be performed faster by minimising memory management overhead.

    Static arrays are efficient when their size is smaller than 100-200 elements. If the size is larger than 100-200 elements, dynamic arrays are usually used.

    In Julia, static arrays are provided by the StaticArrays.jl package. Therefore, to use them, you must connect this package using the using StaticArrays command. Example:

    using StaticArrays
    static_array = @SVector [1, 2, 3]
    Output
    3-element SVector{3, Int64} with indices SOneTo(3):
     1
     2
     3

    The code used a macro[1]@SVector, which creates a static one-dimensional array (vector) of fixed size. There are other useful macros for static arrays:

    Static Array Macros.
    • @SVector - creates an immutable static vector of fixed size. Example: @SVector [1, 2, 3].

    • @MVector - creates a mutable static vector of fixed size. Example: @MVector [1, 2, 3].

    • @SMatrix - creates a mutable static matrix of fixed size. Example: @SMatrix [1 2; 3 4].

    • @MMatrix - creates a mutable static matrix of fixed size. Example: @MMatrix [1 2; 3 4].

    • @SizedArray - converts a regular array into a static array with a fixed size. Example: @SisedArray rand(2, 2).

    • @SArray - creates a common fixed-size static array, which can be a vector, matrix, or a higher dimensional array. Example: @SArray rand(2, 2, 2, 2).

    • @MArray - creates a common mutable static array. Example: @MArray rand(2, 2, 2, 2).

    • @StaticArray - a generic macro that creates immutable arrays of any shape. Example: @StaticArray rand(2, 2, 2).

    • @MutableStaticArray is a universal macro for creating mutable static arrays. Example: @MutableStaticArray rand(2, 2).

    • @zeros - creates a static array filled with zeros. Example: @zeros(SVector, 3) creates a vector of three zeros.

    • @ones - creates a static array filled with ones. Example: @ones(SMatrix, 2, 2) creates a 2×2 matrix of ones.

    • @fill - creates a static array filled with the given value. Example: @fill(SVector, 3, 42) creates a vector of three elements with the value 42.

    • @static - optimises the execution of code blocks at the compilation stage by applying the properties of static arrays. Example:

      @static if length(SVector(1, 2, 3)) == 3
      println("Размер вектора равен 3")
      end

Unlike C++, arrays in Julia can store elements of different types. If element types can be reduced to a common type (e.g. Rational and Complex), Julia will automatically perform type conversion. For example:

[1//2, 3 + 4im]  # Автоматически преобразуется в 2-element Vector{Complex{Rational{Int64}}}:

If the element types cannot be reduced to a common type (e.g. number and string), Julia will cast the array to type Any, which is the union of all types:

[1, "строка"]  # Тип массива — Vector{Any}

This makes arrays in Julia flexible, but it is worth remembering that usage of Any can reduce performance as the compiler will not be able to optimise the code for a particular type. For more information, see Conversion and Promotion.

A Vector is a one-dimensional array that is a sequence of elements accessed using indices. In Julia, a vector can be created as a vector-column or vector-string, but their syntax and data type will be different:

  • A column vector is created by usage of commas or column entries:

    v = [1, 2, 3]  # Вектор-столбец

    or

    v = [1
         2
         3]  # Вектор-столбец
    Output
    3-element Vector{Int64}:
     1
     2
     3
  • Julia does not have a separate type for a vector string. Instead, a string of numbers is represented as a matrix of dimension 1 × N:

    r = [1 2 3]  # Матрица 1 × 3
    Output
    1×3 Matrix{Int64}:
     1  2  3

In Julia, delimiters in arrays define their structure:

  • The comma (,) is used to create vectors (one-dimensional arrays). Elements are separated by commas:

    v = [1, 2, 3]  # Вектор-столбец
  • The semicolon (;) is used to create matrices (two-dimensional arrays). It separates strings, similar to the vcat function:

    m = [1 2 3; 4 5 6]  # Матрица 2 × 3

A Matrix is a two-dimensional array representing a table of numbers or other objects organised into rows and columns. In Julia, matrices are created as arrays with two dimensions:

M = [1 2 3; 4 5 6]
Output
2×3 Matrix{Int64}:
 1  2  3
 4  5  6

The separation into vectors and matrices in Julia allows for efficient organisation of data in memory, which is important for fast numerical calculations. Vectors use one-dimensional storage, making it easier to work with sequences of data, while matrices are organised in two-dimensional form, making it easier to perform linear algebra (multiplication and transpose). This separation helps optimise usage of cache memory and CPU resources, making computations more productive.

Differences between arrays, vectors and matrices

Dimensionality:

  • An array is a container with an arbitrary number of dimensions. Arrays have an arbitrary number of dimensions, and size(A) can return, for example, (2, 2, 3).

  • A vector is a one-dimensional array. Vectors always have one dimension, and the function size(v) returns the tuple (n,), where n is the length of the vector.

  • A matrix is a two-dimensional array. Matrices have a dimensionality of two, and size(M) returns the tuple (n, m), where n is the number of rows and m is the number of columns.

A tuple is an immutable data structure that can contain multiple elements of different types. In Julia, tuples are used to represent values that are logically related but do not require modification. For example, the result of the size() function is always returned as a tuple.

Unlike a vector and a matrix, a tuple is not an array and is not designed to perform arithmetic operations. It has a fixed number of elements and an immutable structure, making it useful for returning multiple values from functions or passing parameters.

  1. Implementation Features:

    • Methods and functions for working with arrays are applicable to both vectors and matrices. However, there are different optimised algorithms for each type of data.

    • In Julia, vectors and matrices are special cases of arrays, where a vector has dimension 1 and a matrix has dimension 2.

  2. Initialisation and syntax:

    • An array with arbitrary dimensionality is created by the Array function or by using generators (expressions in the form […​ for …​]). For example, for Array:

      A = Array{Float64}(undef, 2, 2, 3)

      Here undef is a keyword used to create an array without initialising the elements. This means that memory for the array will be allocated, but the values of its elements will remain undefined (may be random).

      Example with generators:

      array = [i^2 for i in 1:5] # Каждый элемент массива – квадрат числа от 1 до 5
    • A vector is created as a one-dimensional array, elements are enumerated using commas:

      v = [1, 2, 3]
    • A matrix is written as semicolon-separated rows (;), and the elements in the rows are separated by spaces or tabs:

      M = [1 2 3; 4 5 6]
  3. Memory storage:

    • Arrays with a large number of dimensions use a more general storage approach, which can increase the overhead of operations.


The differences described above form specific application areas:

  • Array is used for modelling more complex data: three-dimensional models, image arrays or multidimensional time series.

  • A vector is most often used for one-dimensional data: time series, coordinates, signals.

  • A matrix represents two-dimensional structures: images, tables, systems of linear equations.

Basic functions for working with arrays, vectors and matrices

Julia provides a wide set of functions for working with arrays, including vectors and matrices. Read more about the functions and their signatures in Arrays.

Functions marked with * are not part of the standard library. To work with them, install the appropriate Julia package:

import Pkg
Pkg.add("имя пакета")

The import and using operators and the package name are used to provide access to elements of such functions. Read more at Working with Julia packages.

Below is a list of basic functions with brief descriptions and examples:

Creation
Creation

Function name

Description

Example

zeros.

Creates an array whose elements are equal to zero.

The type of the created object depends on the passed arguments: one-dimensional array (vector), two-dimensional array (matrix) or multidimensional array.

[source,julia].

zeros(3)
zeros(2, 2)
zeros(2, 2, 3)

here:

  • zeros(3) - creates a vector [0.0, 0.0, 0.0, 0.0]

  • zeros(2, 2) - creates a 2x2 matrix

  • zeros(2, 2, 3) - creates a three-dimensional array

ones

Creates an array whose elements are equal to one.

The type of the created object depends on the passed arguments: one-dimensional array (vector), two-dimensional array (matrix) or multidimensional array.

[source,julia].

ones(3)
ones(2, 2)
ones(2, 2, 3)

here:

  • ones(3) - creates a vector [1.0, 1.0, 1.0, 1.0] (of three elements, all equal to 1.0).

  • ones(2, 2) - creates a 2x2 matrix:

    2×2 Matrix{Float64}:
     1.0  1.0
     1.0  1.0
  • ones(2, 2, 3) - creates a three-dimensional array of size 2x2x3, where all elements are equal to 1.0:

    2×2×3 Array{Float64, 3}:
    [:, :, 1] =
     1.0  1.0
     1.0  1.0
    
    [:, :, 2] =
     1.0  1.0
     1.0  1.0
    
    [:, :, 3] =
     1.0  1.0
     1.0  1.0

rand.

Creates an array filled with random numbers with uniform distribution in the interval [0, 1). The type of the created object depends on the passed arguments: one-dimensional array (vector), two-dimensional array (matrix) or multidimensional array.

[source,julia].

rand(3)
rand(2, 2)
rand(2, 2, 3)

here:

  • rand(3) - creates a vector of three random numbers, for example [0.574, 0.225, 0.639].

    3-element Vector{Float64}:
     0.5741275064461032
     0.2253528689201394
     0.6398495562276317
  • rand(2, 2) - creates a 2x2 matrix filled with random numbers, for example:

    2×2 Matrix{Float64}:
     0.526635  0.885571
     0.674019  0.869255
  • rand(2, 2, 3) - creates a three-dimensional array of size 2x2x3, where elements are random numbers, e.g.:

    2×2×3 Array{Float64, 3}:
    [:, :, 1] =
     0.300142  0.594199
     0.125753  0.834848
    
    [:, :, 2] =
     0.707155  0.859128
     0.296165  0.0470918
    
    [:, :, 3] =
     0.220695  0.124332
     0.217407  0.616591

fill.

Creates an array filled with the specified value. The type of the created object depends on the passed arguments: one-dimensional array (vector), two-dimensional array (matrix) or multidimensional array.

[source,julia].

fill(7, 3)
fill(5, 2, 2)
fill(75, 2, 2, 3)

here:

  • fill(7, 3) - creates a vector of three elements where each element is 7, e.g. [7, 7, 7, 7].

  • fill(5, 2, 2, 2) - creates a 2x2 matrix filled with the value 5:

    2×2 Matrix{Int64}:
     5  5
     5  5
  • fill(75, 2, 2, 2, 3) - creates a three-dimensional 2x2x3 array where each element is equal to 75:

    2×2×3 Array{Int64, 3}:
    [:, :, 1] =
     75  75
     75  75
    
    [:, :, 2] =
     75  75
     75  75
    
    [:, :, 3] =
     75  75
     75  75

collect.

Creates an array by converting the given range or iterated object. The type of object created depends on the input used.

[source,julia].

collect(1:3)
collect(reshape(1:4, 2, 2))
collect(reshape(1:12, 2, 2, 3))

Here:

  • collect(1:3) - converts the range 1:3 to a vector [1, 2, 3].

  • collect(reshape(1:4, 2, 2)) - converts the range 1:4 into a 2x2 matrix:

    2×2 Matrix{Int64}:
     1  3
     2  4
  • collect(reshape(1:12, 2, 2, 3)) - converts the range 1:12 into a three-dimensional 2x2x3 array:

    2×2×3 Array{Int64, 3}:
    [:, :, 1] =
     1  3
     2  4
    
    [:, :, 2] =
     5  7
     6  8
    
    [:, :, 3] =
      9  11
     10  12
Change of structure
Structure change

Function name

Description

Example

push!.

Adds an element to the end of a one-dimensional array (vector). Applies only to modifiable (dynamic) arrays.

The end index can also be used to add an element (Array indexing).

[source,julia].

v = [1, 2, 3]
push!(v, 4)

m = reshape(1:6, 2, 3)
# push! нельзя применить к матрице или многомерному массиву.

here:

  • v = [1, 2, 3] - creates a vector [1, 2, 3].

  • push!(v, 4) - adds the element 4 to the end of the vector. After the operation: [1, 2, 3, 4].

  • push! cannot be applied to a m matrix or a multidimensional array, as they have fixed sizes and require changing the data structure to add elements (the system will generate the error MethodError: no method matching push!).

pop!.

Deletes and returns the last element from a one-dimensional array (vector). Applies only to modifiable (dynamic) arrays.

[source,julia].

v = [1, 2, 3, 4]
last_element = pop!(v)

m = reshape(1:6, 2, 3)
# pop! нельзя применить к матрице или многомерному массиву.

here:

  • v = [1, 2, 3, 4] - creates a vector [1, 2, 3, 4].

  • last_element = pop!(v) - removes the last element of the vector (4) and returns it. After the operation, v becomes [1, 2, 3] and the variable last_element is equal to 4.

  • pop! cannot be applied to a m matrix or a multidimensional array, because their size is fixed (the system will generate the error MethodError: no method matching pop!).

insert!.

Inserts an element at the specified position of a one-dimensional array (vector). Applies only to modifiable (dynamic) arrays.

[source,julia].

v = [1, 2, 4, 5]
insert!(v, 3, 3)

m = reshape(1:6, 2, 3)
# insert! нельзя применить к матрице или многомерному массиву.

here:

  • v = [1, 2, 4, 5] - creates a vector [1, 2, 4, 5].

  • insert!(v, 3, 3, 3) - inserts the element 3 into the position with index 3. After the operation v becomes [1, 2, 3, 4, 5].

  • insert! cannot be applied to a m matrix or multidimensional array because their structure is fixed and does not support dynamic change.

deleteat!.

Deletes an element at the specified index from a one-dimensional array (vector). Applies only to modifiable (dynamic) arrays.

[source,julia].

v = [1, 2, 3, 4, 5]
deleteat!(v, 3)

m = reshape(1:6, 2, 3)
# deleteat! нельзя применить к матрице или многомерному массиву.

here:

  • v = [1, 2, 3, 4, 5] - creates a vector [1, 2, 3, 4, 5].

  • deleteat!(v, 3) - removes the element with index 3 (value 3) from the vector. After the operation v becomes [1, 2, 4, 5].

  • deleteat! cannot be applied to a m matrix or multidimensional array, because their structure is fixed and does not support deleting elements (the system will generate the error MethodError: no method matching deleteat!).

Working with dimensions
Working with dimensions

Function name

Description

Example

size.

Returns the size of an array, matrix or vector as a tuple, where each value corresponds to a size on a particular dimension.

[source,julia].

v = [1, 2, 3]
size(v)

m = reshape(1:6, 2, 3)
size(m)

a = zeros(2, 2, 3)
size(a)

Here:

  • v = [1, 2, 3] - creates a vector [1, 2, 3].

  • size(v) - returns the tuple (3,), where 3 is the length of the vector.

  • m = reshape(1:6, 2, 3) - creates a 2x3 matrix:

    2×3 reshape(::UnitRange{Int64}, 2, 3) with eltype Int64:
     1  3  5
     2  4  6
  • size(m) - returns a tuple (2, 3), where 2 is the number of rows and 3 is the number of columns.

  • a = zeros(2, 2, 3) - creates a three-dimensional array of size 2x2x3 filled with zeros.

  • size(a) - returns the tuple (2, 2, 3) corresponding to the array size on each dimension.

resize!.

Changes the size of a one-dimensional array (vector). If the new size is larger than the current size, the new elements are initialised with the default value 0.0. If smaller, the array is trimmed to the specified size.

[source,julia].

v = [1, 2, 3]
resize!(v, 5)
resize!(v, 2)

m = reshape(1:6, 2, 3)
# resize! нельзя применить к матрице или многомерному массиву.

Here:

  • v = [1, 2, 3] - creates vector [1, 2, 3].

  • resize!(v, 5) - increases the size of the vector to 5 by adding elements with the value 0.0. After the operation, v becomes [1, 2, 3, 0.0, 0.0].

  • resize!(v, 2) - reduces the size of the vector to 2. After the operation, v becomes [1, 2].

  • resize! cannot be applied to a m matrix or a multidimensional array, because their structure is fixed (the system will generate the error MethodError: no method matching resize!).

length.

Returns the total number of elements in an array, vector or matrix, regardless of their dimensionality.

[source,julia].

v = [1, 2, 3]
length(v)

m = reshape(1:6, 2, 3)
length(m)

a = zeros(2, 2, 3)
length(a)

here:

  • v = [1, 2, 3] - creates a vector [1, 2, 3].

  • length(v) - returns 3 since the vector contains three elements.

  • m = reshape(1:6, 2, 3) - creates a 2x3 matrix:

    2×3 reshape(::UnitRange{Int64}, 2, 3) with eltype Int64:
     1  3  5
     2  4  6
  • length(m) - returns 6 since the matrix contains 6 elements (product of rows and columns).

  • a = zeros(2, 2, 3) - creates a three-dimensional array of size 2x2x3.

  • length(a) - returns 12, since the array contains 12 elements (product of sizes in all dimensions).

ndims.

Returns the number of dimensions (dimensions) of an array, vector or matrix.

[source,julia].

v = [1, 2, 3]
ndims(v)

m = reshape(1:6, 2, 3)
ndims(m)

a = zeros(2, 2, 3)
ndims(a)

here:

  • v = [1, 2, 3] - creates a vector [1, 2, 3].

  • ndims(v) - returns 1 since the vector has one dimension.

  • m = reshape(1:6, 2, 3) - creates a 2x3 matrix:

    2×3 reshape(::UnitRange{Int64}, 2, 3) with eltype Int64:
     1  3  5
     2  4  6
  • ndims(m) - returns 2 since the matrix has two dimensions (rows and columns).

  • a = zeros(2, 2, 3) - creates a three-dimensional array of size 2x2x3.

  • ndims(a) - returns 3 since the array has three dimensions.

reshape.

Changes the dimensionality of an array, matrix or vector, converting it to a new array with the specified number of rows and columns. The number of elements in the new array must match the number of elements in the original array.

v = [1, 2, 3, 4, 5, 6]
m = reshape(v, 2, 3)

a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
b = reshape(a, 3, 3)

c = reshape(a, 1, 9)

here:

  • v = [1, 2, 3, 4, 5, 6] - creates a vector of 6 elements.

  • reshape(v, 2, 3) - converts the vector into a matrix of size 2x3 containing the elements:

    2×3 Matrix{Int64}:
     1  3  5
     2  4  6
  • a = [1, 2, 3, 4, 5, 6, 7, 8, 9] - creates a vector of 9 elements.

  • reshape(a, 3, 3) - converts the vector into a 3x3 matrix:

    3×3 Matrix{Int64}:
     1  4  7
     2  5  8
     3  6  9
  • reshape(a, 1, 9) - converts the vector into a string of length 9 elements:

    1×9 Matrix{Int64}:
     1  2  3  4  5  6  7  8  9
Linear Algebra
Linear algebra

Function name

Description

Example

transpose.

Returns a transposed array or matrix where the rows swap places with the columns. For a one-dimensional array (vector), the result depends on its orientation.

[source,julia].

v = [1, 2, 3]
vt = transpose(v)

m = [1 2; 3 4; 5 6]
mt = transpose(m)

Here:

  • v = [1, 2, 3] - creates a column vector [1 2 3].

  • transpose(v) - transposes the vector, turning it into a string vector:

    1×3 transpose(::Vector{Int64}) with eltype Int64:
     1  2  3
  • m = [1 2; 3 4; 5 6] - creates a 3x2 matrix:

    3×2 Matrix{Int64}:
     1  2
     3  4
     5  6
  • transpose(m) - transposes the matrix, turning it into a 2x3 matrix:

    2×3 transpose(::Matrix{Int64}) with eltype Int64:
     1  3  5
     2  4  6

*det.

Calculates the determinant of a square matrix. It is a part of LinearAlgebra package (requires package installation).

The determinant is a scalar quantity that characterises the properties of a matrix (e.g. its reversibility).

m1 = [2 3; 1 4]
det(m1)

m2 = [1 2 3; 4 5 6; 7 8 10]
det(m2)

m3 = [0 1; 2 3]
det(m3)

here:

  • m1 = [2 3; 1 4] creates a 2x2 matrix:

    2×2 Matrix{Int64}:
     2  3
     1  4
  • det(m1) - returns 5.0 since the determinant is calculated using the formula for 2×2 matrices ((2*4)-(3*1) = 8-3 = 5).

  • m2 = [1 2 3; 4 5 6; 7 8 10] - creates a 3x3 matrix:

    3×3 Matrix{Int64}:
     1  2   3
     4  5   6
     7  8  10
  • det(m2) - returns -3.0 as it is calculated via Laplace decomposition or other algorithms for larger matrices.

  • m3 = [0 1; 2 3] - creates a 2x2 matrix:

    2×2 Matrix{Int64}:
     0  1
     2  3
  • det(m3) - returns -2.0 since the determinant is equal to: (0*3) - (1*2) = 0-2 = -2).

inv.

Computes the inverse matrix for a square matrix. The inverse matrix exists only for matrices with non-zero determinant, that is, for those that are reversible.

The inv function returns an inverse matrix that is of type Matrix{Float64}, even if the source matrix has integer values (Matrix{Int64}).

[source,julia].

m1 = [2 3; 1 4]
inv(m1)

m2 = [1 2 3; 0 1 4; 5 6 0]
inv(m2)

m3 = [1 2; 3 4]
inv(m3)

Here:

  • m1 = [2 3; 1 4] creates a 2x2 matrix:

    2×2 Matrix{Int64}:
     2  3
     1  4
  • inv(m1) - returns the inverse matrix:

    2×2 Matrix{Float64}:
      0.8  -0.6
     -0.2   0.4
  • m2 = [1 2 3; 0 1 4; 5 6 0] - creates a 3x3 matrix:

    3×3 Matrix{Int64}:
     1  2  3
     0  1  4
     5  6  0
  • inv(m2) - returns the inverse matrix:

    3×3 Matrix{Float64}:
     -24.0   18.0   5.0
      20.0  -15.0  -4.0
      -5.0    4.0   1.0
  • m3 = [1 2; 3 4] - creates a 2x2 matrix:

    2×2 Matrix{Int64}:
     1  2
     3  4
  • inv(m3) - returns the inverse matrix:

    2×2 Matrix{Float64}:
     -2.0   1.0
      1.5  -0.5

*eigvals / *eigvecs.

Calculation of eigenvalues and vectors of a matrix. For example:

  • `eigvals(m) - returns eigenvalues of matrix m.

  • eigvecs(m) - returns the eigenvectors of matrix m.

[source,julia].

m1 = [4 1; 2 3]
eigvals(m1)
eigvecs(m1)

m2 = [1 2 3; 4 5 6; 7 8 9]
eigvals(m2)
eigvecs(m2)

here:

  • m1 = [4 1; 2 3] - creates a 2x2 matrix:

    2×2 Matrix{Int64}:
     4  1
     2  3
  • eigvals(m1) - returns eigenvalues:

    2-element Vector{Float64}:
     2.0
     5.0
  • eigvecs(m1) - returns eigenvectors:

    2×2 Matrix{Float64}:
     -0.447214  0.707107
      0.894427  0.707107
  • m2 = [1 2 3; 4 5 6; 7 8 9] - creates a 3x3 matrix:

    3×3 Matrix{Int64}:
     1  2  3
     4  5  6
     7  8  9
  • eigvals(m2) - returns eigenvalues:

    3-element Vector{Float64}:
     -1.1168439698070416
     -9.759184829871139e-16
     16.116843969807043
  • eigvecs(m2) - returns eigenvectors:

    3×3 Matrix{Float64}:
     -0.78583     0.408248  -0.231971
     -0.0867513  -0.816497  -0.525322
      0.612328    0.408248  -0.818673

norm.

Calculates the norm of a vector or matrix.

The norm is a numerical characteristic that measures the "size" of a vector or matrix. By default, the Euclidean norm is calculated.

v = [3, 4]
norm(v)

m = [1 2; 3 4]
norm(m)

norm(v, 1) # 3 + 4 = 7.0
norm(m, Inf) #√30 ≈ 5.477

here:

  • norm(v) - calculates the Euclidean norm for a vector.

  • norm(v, 1) - calculates the norm of the 1st order (sum of moduli of elements).

  • norm(m) - calculates the Euclidean norm for a matrix (Frobenius norm).

  • norm(m, Inf) - calculates the norm of infinity (maximum row sum). In the example = 4.0.

Check.
Check

Function name

Description

Example

isempty.

Checks if an array, vector or matrix is empty. Returns true if the object is empty and false otherwise.

# Проверка пустого и непустого вектора
v1 = []
v2 = [1, 2, 3]
isempty(v1)
isempty(v2)

# Проверка пустой и непустой матрицы
m1 = reshape([], 0, 0)
m2 = [1 2; 3 4]
isempty(m1)
isempty(m2)

# Проверка пустого и непустого массива
a1 = Int[]
a2 = [1, 2, 3, 4]
isempty(a1
isempty(a2)

Here:

  • For a vector:

    • isempty(v1) returns true since v1 contains no elements.

    • isempty(v2) returns false since the vector v2 contains three elements [1, 2, 3].

  • For the matrix:

    • isempty(m1) returns true since the matrix m1 has size 0×0.

    • isempty(m2) returns false since the matrix m2 has size 2×2.

  • For an array:

    • isempty(a1) returns true since the array a1 is empty.

    • isempty(a2) returns false since the array a2 contains four elements.

iszero.

Checks whether the object is null. Returns true if the object is null, and false otherwise.

Supports numeric types as well as arrays, matrices and vectors (in Julia, an object is null if all its elements are zero).

[source,julia].

# Проверка числа
x = 0
y = 5
iszero(x)  # true
iszero(y)  # false

# Проверка вектора
v1 = [0, 0, 0]
v2 = [0, 1, 0]
iszero(v1)  # true
iszero(v2)  # false

# Проверка матрицы
m1 = zeros(2, 2)нулями
m2 = [1 0; 0 0]элементом
iszero(m1)  # true
iszero(m2)  # false

# Проверка многомерного массива
a1 = zeros(2, 2, 2)
a2 = reshape([1, 0, 0], 1, 3)
iszero(a1)  # true
iszero(a2)  # false

here:

For numbers:

  • iszero(x) returns true since x = 0.

  • iszero(y) returns false since y = 5.

For vectors:

  • iszero(v1) returns true since all elements of vector v1 are 0.

  • iszero(v2) returns false since the second element of vector v2 is equal to 1.

For matrices:

  • iszero(m1) returns true since all elements of matrix m1 are equal to 0.

  • iszero(m2) returns false since the matrix m2 contains a non-zero element 1.

For multidimensional arrays:

  • iszero(a1) returns true since all elements of array a1 are equal to 0.

  • iszero(a2) returns false since the first element of array a2 is equal to 1.

issymmetric.

Checks whether the matrix is symmetric. Returns true if the matrix is equal to its transposed copy, and false otherwise. Works with square matrices only; returns false for other formats.

[source,julia].

# Симметричная матрица
m1 = [1 2 3; 2 4 5; 3 5 6]
issymmetric(m1)  # true

# Несимметричная матрица
m2 = [1 0 0; 0 4 5; 3 5 6]
issymmetric(m2)  # false

# Квадратная, но несимметричная матрица
m3 = [1 2; 3 4]
issymmetric(m3)  # false

# Несимметричная прямоугольная матрица
m4 = [1 2; 2 3; 3 4]
issymmetric(m4)  # false

Here:

  • For matrix m1:

    The matrix m1 is equal to its transposed copy:

    [1 2 3]       [1 2 3]
    [2 4 5]  ->   [2 4 5]
    [3 5 6]       [3 5 6]

    issymmetric(m1) returns true.

  • For the matrix m2:

    The matrix m2 is not equal to its transposed copy:

    [1 0 0]       [1 0 3]
    [0 4 5]  ->   [0 4 5]
    [3 5 6]       [0 5 6]

    issymmetric(m2) returns false.

  • For matrix m3:

    The matrix m3 is square but asymmetric:

    [1 2]       [1 3]
    [3 4]  ->   [2 4]

    issymmetric(m3) returns false.

  • For matrix m4:

    The matrix m4 is rectangular (not square), so issymmetric(m4) returns false.

Transformation.
Transformation

Function name

Description

Example

vec.

Converts a matrix or multidimensional array to a vector. It returns a one-dimensional array in which the elements are taken from the columns of the original matrix or array. If the argument is already a vector, it returns unchanged.

[source,julia].

# Преобразование матрицы в вектор
m = [1 2; 3 4]
v1 = vec(m)  # [1, 3, 2, 4]

# Преобразование трехмерного массива в вектор
a = zeros(2, 2, 2)
a[:, :, 1] .= [1 2; 3 4]
a[:, :, 2] .= [5 6; 7 8]
v2 = vec(a)  # [1, 3, 2, 4, 5, 7, 6, 8]

# Преобразование вектора (без изменений)
v = [1, 2, 3]
v3 = vec(v)  # [1, 2, 3]
  • The matrix m has the form:

    2×2 Matrix{Int64}:
     1  2
     3  4

    The function vec converts it into a vector by sequentially extracting elements from each column:

    [1, 3, 2, 4]
  • For a three-dimensional array a:

    The original array a looks like this (by layers):

    #Слой 1
    [1 2]
    [3 4]
    
    #Слой 2
    [5 6]
    [7 8]

    vec converts it into a vector:

    [1, 3, 2, 4, 5, 7, 6, 8]

    For the vector v:

    If the object is already a vector, vec returns it unchanged:

    3-element Vector{Int64}:
     1
     2
     3

permutedims.

Rearrangement of measurements (axes) of a multidimensional array. Allows you to change the order of measurements without changing the data itself, creating a new array with rearranged axes.

A = reshape(collect(1:6), 2, 3)  # 2×3 массив
B = permutedims(A, (2, 1))  # Меняем местами оси 1 и 2

here:

  • permutedims(A, (2, 1)) - swaps rows and columns, i.e. transposes the matrix.

  • The function creates a new array without changing A (unlike transpose, which works only with 2D matrices).

  • You can transpose any number of dimensions, e.g. permutedims(A, (2, 1, 3)) for 3D arrays.

hcat / vcat.

Horizontal and vertical joining of arrays (Concatenation).

  • hcat (horizontal concatenation) - combines arrays or vectors horizontally (by columns) to form a new matrix or array.

  • vcat (vertical concatenation) - combines arrays or vectors vertically (across rows) to form a new matrix or array.

[source,julia].

# Горизонтальное объединение (hcat)
v1 = [1, 2, 3]
v2 = [4, 5, 6]
h_result = hcat(v1, v2)

# Вертикальное объединение (vcat)
v3 = [7, 8, 9]
v_result = vcat(v1, v3)

# Объединение матриц
m1 = [1 2; 3 4]
m2 = [5 6; 7 8]
hcat_result = hcat(m1, m2)
vcat_result = vcat(m1, m2)

here:

  • h_result = hcat(v1, v2) is horizontally concatenated into a 3x2 matrix:

    3×2 Matrix{Int64}:
     1  4
     2  5
     3  6
  • v_result = vcat(v1, v3) union into a vector:

    6-element Vector{Int64}:
     1
     2
     3
     7
     8
     9
  • hcat_result = hcat(m1, m2) combining into a 2x4 matrix:

    2×4 Matrix{Int64}:
     1  2  5  6
     3  4  7  8
  • vcat_result = vcat(m1, m2) combines into a 4x2 matrix:

    4×2 Matrix{Int64}:
     1  2
     3  4
     5  6
     7  8

copy.

creates an independent copy of an array, vector or matrix. Changes made to the copy do not affect the original object and vice versa.

[source,julia].

v = [1, 2, 3]
v_copy = copy(v)
v[1] = 10  # Изменяем оригинал
println(v)       # [10, 2, 3]
println(v_copy)  # [1, 2, 3]

Here:

  • changing an element in the original (v[1] = 10) does not affect the copy v_copy.

deepcopy.

creates a deep copy of the array, recursively copying all nested structures. Changes to the copy do not affect the original. In Julia, the assignment by default passes an object reference rather than a value. If you need to create an independent copy, there are two ways:

  • copy - makes a shallow copy (new container, but references the same items).

  • deepcopy - makes a deep copy (everything is copied recursively).

[source,julia].

A = [[1, 2], [3, 4]]
B = copy(A)       # Неглубокая копия
C = deepcopy(A)   # Глубокая копия

B[1][1] = 99
println(A)  # [[99, 2], [3, 4]]  — A изменился, потому что B и A связаны
println(C)  # [[1, 2], [3, 4]]  — Глубокая копия не изменилась

here:

  • changing the nested element in the original (v[1][1] = 10) does not affect the deep copy of v_deepcopy.

broadcast.

Allows operations on array elements with automatic size matching (broadcasting). For more details see. here.

[source,julia].

# Пример с вектором
v = [1, 2, 3]
v_squared = broadcast(x -> x^2, v)

# Пример с матрицей
m = [1 2; 3 4]
m_doubled = broadcast(x -> x * 2, m)

# Пример с разными размерами массивов
a = [1, 2, 3]
b = [4, 5]
result = broadcast(+, a, b')

here:

  • v_squared = broadcast(x -> x^2, v) forms:

    3-element Vector{Int64}:
     1
     4
     9
  • m_doubled = broadcast(x -> x * 2, m) forms:

    2×2 Matrix{Int64}:
     2  4
     6  8
  • result = broadcast(+, a, b') forms:

    3×2 Matrix{Int64}:
     5  6
     6  7
     7  8

    b' is a transposed vector.

  • broadcast(x -> x^2, v) - squares of vector elements

Appropriateness of using arrays

Arrays are a convenient and flexible tool for working with data, but Julia has other structures that may be better suited for certain tasks. See below for more details.

  • Fast access to elements by index - arrays store elements sequentially in memory, allowing instant access to any element by its index. For example, arr[3] will immediately return the third element of the array. This is called random access (random access), and it runs in O(1) time (the operation takes a constant amount of time regardless of the size of the input data, i.e. accessing an element by index takes the same amount of time no matter how large the array is).

  • Efficient add and remove at the end - if you need to frequently add or remove elements at the end of an array, then use the push! (add an element) and pop! (remove the last element) functions. These operations are very fast because they do not require rearranging other elements.

  • Working with a fixed amount of data - If you know in advance how many elements will be stored, arrays work particularly efficiently. They allocate memory all at once, which minimises resizing overhead.

  • Vector Computing and Linear Algebra - Julia is optimised for working with arrays, especially numeric arrays. If you work with matrices, vectors, or perform linear algebra operations, arrays are the best choice. For example, functions for working with matrices, such as dot, cross, or array operations via broadcast (.+, .*), work faster with arrays.

  • Frequent addition or deletion of elements in the middle or beginning - if you need to frequently insert or delete elements in the beginning or middle of an array. For example, the insert! (insert) and deleteat! (delete) functions require shifting all subsequent elements, making them inefficient for large arrays. Alternative: use Deque from the DataStructures.jl package, which is optimised for insertion and deletion at both ends.

  • Find items by key - if you need to quickly find items by unique keys (e.g. user name or ID), arrays are not suitable, because they are searched by searching all items (which is quite time-consuming). Alternative: use Dict (dictionary), which allows you to quickly find items by key.

  • Frequent resizing of the structure - if the structure of the data changes frequently (e.g. elements are added or removed at arbitrary locations), arrays will be ineffective. Alternative: consider usage of Set, Dict or list structures such as List from the link:https://juliacollections.github.io/DataStructures.jl/latest/ package [DataStructures.jl].

  • Working with immutable data - arrays in Julia are mutable, meaning their elements can be changed after they are created. If you need an immutable data structure, it is better to use tuples (Tuple). They do not allow you to change their elements, which makes them convenient for storing constant data. For example:

    t = (1, 2, 3)
    t[1] = 10  # Ошибка! Кортежи неизменяемы

Arrays, matrices and vectors of strings and symbols

In Julia, arrays, matrices, and vectors can contain strings or symbols, just like numbers.

# Вектор строк
v = ["apple", "banana", "cherry"]
println(v[1])  # apple

# Матрица символов
m = ['a' 'b'; 'c' 'd']
println(m[1, 2])  # b

# Трехмерный массив строк
a = [["a", "b"], ["c", "d"]]
println(a[1][2])  # "b"
  • String vector - each string is stored as an element of a one-dimensional array.

  • Character matrix - a two-dimensional array where each element is a character.

  • Three-dimensional array of strings - any number of dimensions with text data is supported.

Arrays in Julia are dynamic by default, but their length is fixed until explicitly changed. This means that when an array is created, its current length remains unchanged until special methods such as push!, append!, or resize! are used. This is done to improve performance: fixed-length operations are faster because they do not require constant memory reallocation.

More complex constructs with end, such as end+1, do not allow you to directly assign a value to an array element, because such operations go beyond the current length. To add new elements, you must explicitly increase the size of the array. For example, you can use resize!:

a = [10, 20, 30]
resize!(a, length(a) + 1)  # Расширяем массив на 1 элемент
a[end] = 40  # Присваиваем значение новому элементу
println(a)  # [10, 20, 30, 40]

Constructions with end are available for indexing and performing arithmetic operations on indexes inside existing array boundaries. For example:

  • a[end] - access to the last element.

  • a[end-1] - access to the second element from the end.

  • a[1:end] - get the whole array.

  • a[1:end-1] - get all elements except the last one.

In Julia you cannot directly assign a value to an element with index end+1 or any index beyond the current length of the array. To resize an array, you must use special methods such as resize!, push!, or append!.

Array indexing

Indexing in Julia starts from one, i.e. the first element of an array has index 1. A special end index is also supported, which denotes the last element of the array or the size of the corresponding dimension. Indexing example:

a = [10, 20, 30, 40]
println(a[1])  # 10 — первый элемент
println(a[end])  # 40 — последний элемент

# Индексация матриц
m = [1 2; 3 4]
println(m[1, end])  # 2 — последний элемент первой строки
  • The index 1 always points to the first element.

  • end is used to refer to the last element in one-dimensional and multidimensional arrays.

  • For matrices, the first index is the row number, the second index is the column number.

*Other indexing variations:

  • You can refer to multiple elements of an array at once by usage of ranges:

    b = [1, 2, 3, 4, 5]
    println(b[2:end])  # [2, 3, 4, 5] — элементы со второго до последнего
  • Selecting elements in specific increments:

    b = [1, 2, 3, 4, 5]
    println(b[1:2:end])  # [1, 3, 5] — элементы с шагом 2

    In Julia, expressions of the form 1:2:end are called ranges. A range is a structure that describes a sequence of numbers with a beginning, a step, and an end. For example, 1:2:5 creates a sequence from 1 to 5 in increments of 2: [1, 3, 5].

    In this example, 1:2:end indicates that the selection starts at the first element of the array (1), proceeds in increments of 2, and ends at the last element of the array (end). Ranges are used to work with array and matrix indices in a convenient and efficient manner. Examples of usage of ranges:

    # Простые диапазоны
    r1 = 1:5           # Создает последовательность [1, 2, 3, 4, 5]
    r2 = 1:2:10        # Создает последовательность [1, 3, 5, 7, 9]
    
    # Использование диапазона для индексации
    a = [10, 20, 30, 40, 50]
    println(a[2:4])    # [20, 30, 40]
    println(a[1:2:end]) # [10, 30, 50]
    
    # Диапазон с "end"
    println(a[3:end])  # [30, 40, 50]
  • Selecting items that fulfil certain conditions (see section for details). Logical indexing):

    b = [1, 2, 3, 4, 5]
    println(b[b .> 3])  # [4, 5] — элементы больше 3

In Julia, ranges can be set not only directly, but also by usage of variables. For example:

arr = [10, 20, 30, 40, 50]
a = 1:2:5         # Задаем диапазон в переменной
println(arr[a])   # [10, 30, 50]

Logical indexing

Logical indexing in Julia allows you to select array elements based on conditions that return a logical array (true/false) of the same dimension as the original array. This method is useful for filtering data. Example:

# Исходный массив
a = [10, 20, 30, 40, 50]

# Условие: выбрать элементы больше 25
filtered = a[a .> 25]  # [30, 40, 50]
println(filtered)

# Условие: элементы, которые кратны 10
filtered = a[a .% 10 .== 0]  # [10, 20, 30, 40, 50]
println(filtered)

Here:

  • . operator before a condition (.>, .==) means a piecewise operation. A more detailed description of such operations is given in the article Vectorisation and logical indexing.

  • logical array [false, false, true, true, true, true] will be used to select the corresponding elements.

Example with a multidimensional array:

# Матрица 2x3
m = [1 2 3; 4 5 6]

# Условие: выбрать элементы больше 3
filtered = m[m .> 3]  # [4, 5, 6]
println(filtered)

Operators for working with arrays, vectors and matrices

Julia provides operators to simplify working with arrays - whether they are one-dimensional (vectors), two-dimensional (matrices), or more complex multidimensional structures. Here are the main operators used for indexing, transforming, and combining data:

  • The : operator is used to select all elements of an array along a particular dimension or to create ranges. Example:

    # Исходный массив
    m = [1 2 3; 4 5 6; 7 8 9]
    
    # Все элементы первой строки
    println(m[1, :])  # [1, 2, 3]
    
    # Все элементы второго столбца
    println(m[:, 2])  # [2, 5, 8]
    
    # Диапазон индексов
    println(m[1:2, 1:2])  # [1 2; 4 5]
  • The ' operator is used for conjugation (transpose for real numbers). It works only with numeric arrays. Example:

    # Вектор-строка
    v = [1 2 3]
    
    # Транспонирование в столбец
    println(v')  # [1; 2; 3;;]
    To transpose arrays with complex numbers, the ' operator also returns a complex-conjugate result. If you need only row-to-column transposition (without conjugation), use the transpose function.

To transpose arrays with non-numeric elements (such as strings or user-defined types), use the permutedims function. Unlike transpose, which is for numeric data, permutedims works with any type.

If you apply the ' operator to a non-numeric array, it will cause an error. In Julia, the ` operator calls adjoint (conjugate transpose), which is designed to work with numeric and complex arrays. For strings and other objects, it is not defined and will cause a MethodError. For example:

arr = ["a" "b"; "c" "d"] # Матрица строк (2×2)
arr_transposed = permutedims(arr, (2, 1)) # Меняем строки и столбцы местами
arr_wrong = arr' # Ошибка!
  • The ; operator is used to merge arrays vertically, that is, to add rows. Example:

    # Исходные векторы
    a = [1, 2, 3]
    b = [4, 5, 6]
    
    # Вертикальная конкатенация
    result = [a; b]
    println(result)  # 6-element Vector{Int64}:[1; 2; 3; 4; 5; 6]

Iterate over arrays using for

In Julia, arrays can be conveniently iterated over using the for loop. Let’s look at the basic ways of working with arrays via for. The following syntax is used to loop through all elements of an array:

arr = [10, 20, 30, 40]

for x in arr
    println(x)
end
Output
10
20
30
40

Sometimes it is necessary to get not only values, but also their indexes. For this purpose, eachindex is used, which automatically selects the optimal indexing method:

arr = ["a", "b", "c"]

for i in eachindex(arr)
    println("Элемент ", i, ": ", arr[i])
end
Output
Элемент 1: a
Элемент 2: b
Элемент 3: c

An alternative way to get the index and value is the enumerate function:

arr = ["apple", "banana", "cherry"]

for (i, val) in enumerate(arr)
    println("$i: $val")
end
Output
1: apple
2: banana
3: cherry

For multidimensional arrays, you can use nested loops:

matrix = [1 2 3; 4 5 6]

for i in 1:size(matrix, 1)  # Проход по строкам
    for j in 1:size(matrix, 2)  # Проход по столбцам
        println("matrix[$i, $j] = ", matrix[i, j])
    end
end
Output
matrix[1, 1] = 1
matrix[1, 2] = 2
matrix[1, 3] = 3
matrix[2, 1] = 4
matrix[2, 2] = 5
matrix[2, 3] = 6

Instead of nested loops, you can use for directly:

matrix = [1 2 3; 4 5 6]

for x in matrix
    println(x)
end
Output
1
4
2
5
3
6

Julia traverses elements by columns, not by rows. To bypass the array by rows, you can use permutedims or eachrow:

for row in eachrow(matrix)
    println(row)
end
Output
[1, 2, 3]
[4, 5, 6]

1. Macros in Julia are special constructs beginning with the @ symbol that transform code before it is executed.