Tableaux et matrices#
La définition de tableaux i.e. vecteurs, matrices, hypermatrices est un élément essentiel de Julia.
Julia ne possède qu’un seul type de tableau : Array on peut définir son nombre d’entrées (1 entrée= 1 dimension …) et son contenu de façon assez générale. Un tableau peut contenir des matrices à chaque élément.
Une particularité est que les indices de tableaux commencent à 1, et l’accès aux éléments se fera à l’aide de [
]
et non (
)
qui est réservé aux fonctions.
Avant de rentrer dans la construction et manipulation de tableau regardons une autre classe
Iterateur#
Julia possède un Type particulier fait à l’aide du “:”
a = 1:5
1:5
a .+ 1
2:6
typeof(a)
UnitRange{Int64}
b = 0:0.5:2
0.0:0.5:2.0
typeof(b)
StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}
Ce type “formel” permet d’avoir une définition et une méthode associée sans stocker l’ensemble des valeurs. Attention celui-ci peut être vide :
d=1:0 # itérateur formel mais correspond à un ensemble vide de valeurs
1:0
collect(1:10)
10-element Vector{Int64}:
1
2
3
4
5
6
7
8
9
10
d = 1:10 |> collect |> sum
55
Tableau#
On vient de voir que l’on peut transformer l’itérateur précédent en tableau à l’aide de la commande “collect”
a = 1:5
aa = collect(complex.(a)) .+ 1im
5-element Vector{Complex{Int64}}:
1 + 1im
2 + 1im
3 + 1im
4 + 1im
5 + 1im
collect(aa')
1×5 Matrix{Complex{Int64}}:
1-1im 2-1im 3-1im 4-1im 5-1im
transpose(aa)
1×5 transpose(::Vector{Complex{Int64}}) with eltype Complex{Int64}:
1+1im 2+1im 3+1im 4+1im 5+1im
a = collect(1:5)
5-element Vector{Int64}:
1
2
3
4
5
a' * a
55
typeof(aa)
Vector{Complex{Int64}} (alias for Array{Complex{Int64}, 1})
La réponse est de la forme Array{Type,dim} un tableau de Type à dim entrées (1 pour vecteur, 2 pour matrices …)
A remarquer :
l’indexation des tableaux commence à 1.
un tableau à une entrée est vu comme un vecteur colonne par défaut.
le crochet [ ] sert à extraire ou affecter une valeur ou un bloc de valeur. Attention le crochet [ ] sert également de “concatenateur” et constructeur de tableau (voir suite)
Il est possible de faire des tableaux de n’importe quoi (fonction, tableau, …).
aa[1]
1 + 1im
aa[begin] # pour accèder au premier élément
1 + 1im
aa[end] # pour accèder au dernier élément
5 + 1im
first(a), last(a)
(1, 5)
aa[end-2:end] .= 1 ; println(aa)
Complex{Int64}[1 + 1im, 2 + 1im, 1 + 0im, 1 + 0im, 1 + 0im]
Les crochets permettent la construction explicite de tableaux (ou leur concaténation)
A = [1 2 ; 3 4] # {espace} = séparateur de colonne
2×2 Matrix{Int64}:
1 2
3 4
AA=[A A] # concaténation par bloc
2×4 Matrix{Int64}:
1 2 1 2
3 4 3 4
hcat(A, A) # commande équivalent à la précédente [A A]
2×4 Matrix{Int64}:
1 2 1 2
3 4 3 4
AA = [A ; A]
4×2 Matrix{Int64}:
1 2
3 4
1 2
3 4
vcat(A,A) # commande équivalent à la précédente [A ; A]
4×2 Matrix{Int64}:
1 2
3 4
1 2
3 4
On peut accéder à tout ou partie d’un tableau à l’aide de 2 indices
A[2,1]
3
A[2,:]
2-element Vector{Int64}:
3
4
A[:,2]
2-element Vector{Int64}:
2
4
A[end,end]
4
AA
4×2 Matrix{Int64}:
1 2
3 4
1 2
3 4
sum(AA, dims=2)
4×1 Matrix{Int64}:
3
7
3
7
B = [1 2 3 4]
1×4 Matrix{Int64}:
1 2 3 4
B = [1;2;3;4]
4-element Vector{Int64}:
1
2
3
4
for i in eachindex(AA)
println(i)
end
1
2
3
4
5
6
7
8
for row ∈ eachrow(AA)
println("$row")
end
[1, 2]
[3, 4]
[1, 2]
[3, 4]
A noter que l’on peut faire des tableaux de tout type voir de les mélanger (Any)
a=["un";"deux"]
2-element Vector{String}:
"un"
"deux"
b=[1>2,true,false]
3-element Vector{Bool}:
0
1
0
c=["un"; 2 ; true]
3-element Vector{Any}:
"un"
2
true
Le crochet [ ] permet également la construction rapide de matrice ou tableau comme le montre l’exemple ci-dessous pour construire une matrice de VanderMonde
x = 0:0.2:1
V = [ x[i]^(j-1) for i=1:6, j=1:6] # ligne et colonne
6×6 Matrix{Float64}:
1.0 0.0 0.0 0.0 0.0 0.0
1.0 0.2 0.04 0.008 0.0016 0.00032
1.0 0.4 0.16 0.064 0.0256 0.01024
1.0 0.6 0.36 0.216 0.1296 0.07776
1.0 0.8 0.64 0.512 0.4096 0.32768
1.0 1.0 1.0 1.0 1.0 1.0
V = zeros(Float64, 6,6)
for j in 1:6, i in 1:6
V[i,j] = x[i]^(j-1)
end
V
6×6 Matrix{Float64}:
1.0 0.0 0.0 0.0 0.0 0.0
1.0 0.2 0.04 0.008 0.0016 0.00032
1.0 0.4 0.16 0.064 0.0256 0.01024
1.0 0.6 0.36 0.216 0.1296 0.07776
1.0 0.8 0.64 0.512 0.4096 0.32768
1.0 1.0 1.0 1.0 1.0 1.0
D=[ u*v for u=1:0.5:3, v=1:0.5:4]
5×7 Matrix{Float64}:
1.0 1.5 2.0 2.5 3.0 3.5 4.0
1.5 2.25 3.0 3.75 4.5 5.25 6.0
2.0 3.0 4.0 5.0 6.0 7.0 8.0
2.5 3.75 5.0 6.25 7.5 8.75 10.0
3.0 4.5 6.0 7.5 9.0 10.5 12.0
On peux évidemment faire des tableaux à 3,4… entrèes.
Manipulation de Tableau#
push!#
Le fonction push permet d’ajouter à un tableau une valeur supplémentaire
a = Int[]
push!(a,1) # => [1]
push!(a,2) # => [1,2]
push!(a,4) # => [1,2,4]
push!(a,6) # => [1,2,4,6]
4-element Vector{Int64}:
1
2
4
6
append!#
Cette fonction permet de mettre bout à bout 2 tableaux
append!(a,a)
8-element Vector{Int64}:
1
2
4
6
1
2
4
6
A noté le Array{Any,1} !
a = ComplexF64[]
push!(a,1) # => [1]
push!(a,2) # => [1,2]
push!(a,4) # => [1,2,4]
push!(a,6)
4-element Vector{ComplexF64}:
1.0 + 0.0im
2.0 + 0.0im
4.0 + 0.0im
6.0 + 0.0im
a = zeros(0)
Float64[]
a = zeros(Int32,1)
1-element Vector{Int32}:
0
ones(3)
3-element Vector{Float64}:
1.0
1.0
1.0
fill(5, (6,6))
6×6 Matrix{Int64}:
5 5 5 5 5 5
5 5 5 5 5 5
5 5 5 5 5 5
5 5 5 5 5 5
5 5 5 5 5 5
5 5 5 5 5 5
Attention sur la conversion de type !#
a = collect(1:5)
5-element Vector{Int64}:
1
2
3
4
5
a = fill(0.,3,2)
3×2 Matrix{Float64}:
0.0 0.0
0.0 0.0
0.0 0.0
a[2] = sqrt(2)
1.4142135623730951
a = map( x -> 2x+1 , a )
3×2 Matrix{Float64}:
1.0 1.0
3.82843 1.0
1.0 1.0
a = ComplexF64.(a)
3×2 Matrix{ComplexF64}:
1.0+0.0im 1.0+0.0im
3.82843+0.0im 1.0+0.0im
1.0+0.0im 1.0+0.0im
Algèbre linéaire#
On retrouve beaucoup (toutes) de fonctions usuelles de l’algèbre linéaire
using LinearAlgebra
A = SymTridiagonal(rand(5), rand(4))
5×5 SymTridiagonal{Float64, Vector{Float64}}:
0.847034 0.307827 ⋅ ⋅ ⋅
0.307827 0.898 0.0554185 ⋅ ⋅
⋅ 0.0554185 0.825485 0.063353 ⋅
⋅ ⋅ 0.063353 0.763637 0.134202
⋅ ⋅ ⋅ 0.134202 0.927218
det(A)
0.3750274106551066
tr(A)
4.261373765642171
eigvals(A)
5-element Vector{Float64}:
0.5577547428227645
0.6695570133399208
0.839919198728379
1.007956036262465
1.1861867744886425
b = collect(1:5); #résolution du système Ax=b
x = A \ b
5-element Vector{Float64}:
0.5058104234190263
1.8567601832194116
3.1925664157211275
4.130619194095755
4.794623364454379
Fonctions scientifiques et opérations#
L’usage des fonction scientifiques se fait termes à termes pour l’ensemble des valeurs du tableau (sauf pour les fonctions matricielles comme exp
, log
…). L’usage des opérations +
,-
,*
,^
,/
et \
(résolution) est disponible à condition de respecter les contraintes de dimension (multiplication matricielle par exemple). Sont ajouté des opérations termes à termes .*
,.^
,./
et .
toujours avec une contrainte de dimensions compatibles.
A=[1 2;3 4]
exp(A)
2×2 Matrix{Float64}:
51.969 74.7366
112.105 164.074
exp.(A) # exponentielle matricielle
2×2 Matrix{Float64}:
2.71828 7.38906
20.0855 54.5982
De plus les tableaux possèdes des opérations de multiplication, division, puissance termes à termes
A^2 #Multiplication Matricielle
2×2 Matrix{Int64}:
7 10
15 22
A.^2 #Multiplication terme à terme
2×2 Matrix{Int64}:
1 4
9 16
A ./ [2 3 ; 4 5] #Division terme à terme
2×2 Matrix{Float64}:
0.5 0.666667
0.75 0.8
A./2
2×2 Matrix{Float64}:
0.5 1.0
1.5 2.0
Opérateurs booléens sur les tableaux#
A = collect(1:5)
A .> 2
5-element BitVector:
0
0
1
1
1
collect(1:5) .> [0;2;3;4;5]
5-element BitVector:
1
0
0
0
0
collect(1:5).>[0 2 3 4 5]
5×5 BitMatrix:
1 0 0 0 0
1 0 0 0 0
1 1 0 0 0
1 1 1 0 0
1 1 1 1 0
Particularité max, maximum, min, minimum#
max(2,3)
3
max(1,2,3)
3
max(1:5...)
5
?max
max.(1:5,2:6)
5-element Vector{Int64}:
2
3
4
5
6
Constructeurs#
Enfin il est possible de construire rapidement certaines matrices
a = fill(0.,2,3)
2×3 Matrix{Float64}:
0.0 0.0 0.0
0.0 0.0 0.0
a=fill(2,2)
2-element Vector{Int64}:
2
2
b = range(0, stop=2pi, length=10)
0.0:0.6981317007977318:6.283185307179586
c = LinRange(0, 2π, 10)
10-element LinRange{Float64, Int64}:
0.0, 0.698132, 1.39626, 2.0944, …, 4.18879, 4.88692, 5.58505, 6.28319
collect(b)
10-element Vector{Float64}:
0.0
0.6981317007977318
1.3962634015954636
2.0943951023931953
2.792526803190927
3.490658503988659
4.1887902047863905
4.886921905584122
5.585053606381854
6.283185307179586
A=ones(3)
3-element Vector{Float64}:
1.0
1.0
1.0
A=zeros(3)
3-element Vector{Float64}:
0.0
0.0
0.0
using Random
rng = Xoshiro(111)
B = randn(rng, 5) # loi normale centrée de variance 1
5-element Vector{Float64}:
-1.2141570148792402
0.8728141561713048
-0.4473225480452905
0.14532188192398446
-0.8369753246696554
minimum(B), maximum(B)
(-1.2141570148792402, 0.8728141561713048)
extrema(B)
(-1.2141570148792402, 0.8728141561713048)
B = [ones(3,2) zeros(3,2)] # concaténation de tableaux
3×4 Matrix{Float64}:
1.0 1.0 0.0 0.0
1.0 1.0 0.0 0.0
1.0 1.0 0.0 0.0
hcat(ones(3,2), zeros(3,2))
3×4 Matrix{Float64}:
1.0 1.0 0.0 0.0
1.0 1.0 0.0 0.0
1.0 1.0 0.0 0.0
B=[ones(3,2); zeros(3,2)] # , ou ; jouent le rôle de retour à la ligne
6×2 Matrix{Float64}:
1.0 1.0
1.0 1.0
1.0 1.0
0.0 0.0
0.0 0.0
0.0 0.0
vcat(ones(3,2), zeros(3,2))
6×2 Matrix{Float64}:
1.0 1.0
1.0 1.0
1.0 1.0
0.0 0.0
0.0 0.0
0.0 0.0
C = Diagonal(ones(3,3))
3×3 Diagonal{Float64, Vector{Float64}}:
1.0 ⋅ ⋅
⋅ 1.0 ⋅
⋅ ⋅ 1.0
A = rand(5,5)
U, D, Vt = svd(A'A)
SVD{Float64, Float64, Matrix{Float64}, Vector{Float64}}
U factor:
5×5 Matrix{Float64}:
-0.463543 -0.293881 0.0810887 0.470752 -0.685987
-0.37719 -0.31532 0.0182981 -0.849448 -0.190799
-0.46022 -0.101653 -0.792201 0.144199 0.359845
-0.463886 0.869596 0.0914905 -0.0901132 -0.110102
-0.46461 -0.218351 0.597609 0.167082 0.592795
singular values:
5-element Vector{Float64}:
5.039741452325593
0.95604231508676
0.47342133951040216
0.09810077368527008
0.01592566168359706
Vt factor:
5×5 Matrix{Float64}:
-0.463543 -0.37719 -0.46022 -0.463886 -0.46461
-0.293881 -0.31532 -0.101653 0.869596 -0.218351
0.0810887 0.0182981 -0.792201 0.0914905 0.597609
0.470752 -0.849448 0.144199 -0.0901132 0.167082
-0.685987 -0.190799 0.359845 -0.110102 0.592795
A'A
5×5 Matrix{Float64}:
1.19782 0.933319 1.07601 0.839931 1.17092
0.933319 0.883594 0.885522 0.628307 0.938472
1.07601 0.885522 1.37852 0.955203 0.880463
0.839931 0.628307 0.955203 1.81241 0.928034
1.17092 0.938472 0.880463 0.928034 1.31089
U * Diagonal(D) * Vt
5×5 Matrix{Float64}:
1.15486 0.813783 -0.227291 -0.86153 1.65842
1.03096 0.581025 -0.175963 -0.630546 1.37203
1.27517 0.761444 0.111975 -1.0637 1.4765
0.7551 0.4132 -0.210532 -1.80001 1.46064
1.02194 0.737384 -0.410679 -0.884052 1.75168
diag(C) # extraction d'une diagonale
3-element Vector{Float64}:
1.0
1.0
1.0
diagm(ones(3))
3×3 Matrix{Float64}:
1.0 0.0 0.0
0.0 1.0 0.0
0.0 0.0 1.0
Matrix(I, 3, 3)
3×3 Matrix{Bool}:
1 0 0
0 1 0
0 0 1
type sparse#
Julia possède un type sparse i.e. des matrices creuses, ces dernières ayant un comportement identique aux matrices elles ne diffèrent que dans leur définition (et leur stockage).
using SparseArrays
A = spzeros(3,3)
3×3 SparseMatrixCSC{Float64, Int64} with 0 stored entries:
⋅ ⋅ ⋅
⋅ ⋅ ⋅
⋅ ⋅ ⋅
A = spdiagm(0 => 1:3)
3×3 SparseMatrixCSC{Int64, Int64} with 3 stored entries:
1 ⋅ ⋅
⋅ 2 ⋅
⋅ ⋅ 3
A = A + spdiagm(1 => 1:2)
3×3 SparseMatrixCSC{Int64, Int64} with 5 stored entries:
1 1 ⋅
⋅ 2 2
⋅ ⋅ 3
nonzeros(A), nnz(A)
([1, 1, 2, 2, 3], 5)
sparse([0 1 2; 2 0 0]) # pour rendre sparse une matrice "full"
2×3 SparseMatrixCSC{Int64, Int64} with 3 stored entries:
⋅ 1 2
2 ⋅ ⋅
det(A)
6.0
Affectation et copie#
Attention julia à un mode de passage de valeur qui fonctionne différemment suivant une variable type ou un tableau.
Pour une variable scalaire
a = 1
b = a
b += 1
2
a
1
b
2
a
1
Par contre maintenant si la variable est un tableau
A = collect(1:5)
B = A
B .+= 1
5-element Vector{Int64}:
2
3
4
5
6
A
5-element Vector{Int64}:
2
3
4
5
6
B
5-element Vector{Int64}:
2
3
4
5
6
Pour avoir un comportement il faut copier le tableau A
A = collect(1:5)
B = copy(A)
B .= B .+ 1
5-element Vector{Int64}:
2
3
4
5
6
A
5-element Vector{Int64}:
1
2
3
4
5
B
5-element Vector{Int64}:
2
3
4
5
6
Il faut faire attention à ce comportement lorsque l’on utilise des vecteurs de vecteurs
vecs = [A for i in 1:3]
3-element Vector{Vector{Int64}}:
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
A .+= 1
vecs
3-element Vector{Vector{Int64}}:
[2, 3, 4, 5, 6]
[2, 3, 4, 5, 6]
[2, 3, 4, 5, 6]
Dictionnaire#
d = Dict(:key1 => "val1", :key2 => "val2")
Dict{Symbol, String} with 2 entries:
:key2 => "val2"
:key1 => "val1"
keys(d) # Toutes clés (itérateur)
KeySet for a Dict{Symbol, String} with 2 entries. Keys:
:key2
:key1
values(d) # Toutes valeurs (itérateur)
ValueIterator for a Dict{Symbol, String} with 2 entries. Values:
"val2"
"val1"
for (k,v) in d # Itérer par paire clé-valeur
println("key: $k, value: $v")
end
key: key2, value: val2
key: key1, value: val1
haskey(d, :k) # Vérifier la présence de la clé :k
false
Les dictionnaires sont muables; quand des symboles sont utilisés comme clés, les clés sont immuables.