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 |> 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)
first(a,3)
3-element Vector{Int64}:
1
2
3
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
stack([A A])
2×4 Matrix{Int64}:
1 2 1 2
3 4 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]
for i = axes(AA, 1)
println("$(AA[i,:])")
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
[ 2i+3 for i in 1:7 if i%3 == 0]
2-element Vector{Int64}:
9
15
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 = []
push!(A, 1)
1-element Vector{Any}:
1
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
map( x -> 2x+1 , a )
3×2 Matrix{Float64}:
1.0 1.0
3.82843 1.0
1.0 1.0
g(x) = 2x+1
g (generic function with 1 method)
g.(a)
3×2 Matrix{Float64}:
1.0 1.0
3.82843 1.0
1.0 1.0
a = ComplexF64.(a)
3×2 Matrix{ComplexF64}:
0.0+0.0im 0.0+0.0im
1.41421+0.0im 0.0+0.0im
0.0+0.0im 0.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.596195 0.995888 ⋅ ⋅ ⋅
0.995888 0.0915333 0.96164 ⋅ ⋅
⋅ 0.96164 0.325559 0.281823 ⋅
⋅ ⋅ 0.281823 0.0580011 0.818569
⋅ ⋅ ⋅ 0.818569 0.814168
det(A)
0.5940315482568199
tr(A)
1.8854572089080275
eigvals(A)
5-element Vector{Float64}:
-1.1471357975742635
-0.48185818356519805
0.47076037068002313
1.3397105997246765
1.7039802196427891
inv(A)
5×5 Matrix{Float64}:
0.928377 0.44835 -1.00412 -0.369917 0.371917
0.44835 -0.268408 0.601121 0.221453 -0.22265
-1.00412 0.601121 0.982661 0.362013 -0.363969
-0.369917 0.221453 0.362013 -1.17384 1.18018
0.371917 -0.22265 -0.363969 1.18018 0.0416864
b = collect(1:5); #résolution du système Ax=b
x = A \ b
5-element Vector{Float64}:
-0.8073607245130343
1.4874604752324947
2.77431260680225
2.3645866975061125
3.7638690954987677
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
maximum(1:5)
5
?max
search: max map argmax map! eigmax minmax imag mark
max(x, y, ...)
Return the maximum of the arguments, with respect to isless
. If any of the arguments is missing
, return missing
. See also the maximum
function to take the maximum element from a collection.
Examples
julia> max(2, 5, 1)
5
julia> max(5, missing, 6)
missing
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=9, length=10)
0.0:1.0:9.0
b.offset, b.step, b.len
(1, Base.TwicePrecision{Float64}(1.0, 0.0), 10)
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
c.lendiv
9
collect(b)
10-element Vector{Float64}:
0.0
1.0
2.0
3.0
4.0
5.0
6.0
7.0
8.0
9.0
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)
display(A)
U, D, Vt = svd(A)
5×5 Matrix{Float64}:
0.45212 0.763946 0.321369 0.831543 0.451148
0.644975 0.25924 0.629856 0.474678 0.883872
0.954511 0.617385 0.790909 0.0154513 0.587455
0.904441 0.916117 0.80773 0.557855 0.804184
0.130696 0.673001 0.866445 0.279696 0.814844
SVD{Float64, Float64, Matrix{Float64}, Vector{Float64}}
U factor:
5×5 Matrix{Float64}:
-0.376949 0.769359 0.252357 -0.105813 -0.437167
-0.413076 -0.0907311 -0.0956054 0.897896 -0.0760163
-0.444158 -0.629893 0.35609 -0.268589 -0.454991
-0.569283 0.0547333 0.240927 -0.16583 0.766405
-0.40733 -0.00961577 -0.861586 -0.288005 -0.093345
singular values:
5-element Vector{Float64}:
3.160584859379253
0.7576582320223484
0.6224526623621192
0.46417008239217245
0.014960414255275447
Vt factor:
5×5 Matrix{Float64}:
-0.452107 -0.463501 -0.488948 -0.299912 -0.501745
-0.348008 0.289064 -0.359277 0.811446 -0.0883688
0.799456 0.0461337 -0.400665 0.101832 -0.433405
0.188044 -0.774792 -0.138691 0.346878 0.474107
-0.0004548 0.314926 -0.67237 -0.347728 0.57256
A'A
5×5 Matrix{Float64}:
2.36659 2.01843 2.15026 1.23796 2.16861
2.01843 2.32418 2.22018 1.46715 2.22159
2.15026 2.22018 2.52869 1.27137 2.5219
1.23796 1.46715 1.27137 1.30645 1.48031
2.16861 2.22159 2.5219 1.48031 2.64055
U * Diagonal(D) * Vt
5×5 Matrix{Float64}:
0.209659 0.487396 -0.990667 -0.71759 0.0918338
0.526789 0.794147 -0.980133 -0.0399562 -0.126619
0.788302 0.170384 -1.24285 0.0285756 -0.259234
0.738247 0.520793 -1.50941 -0.412534 -0.0536239
0.888435 0.530245 -0.827688 -0.209097 0.404567
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
A = collect(1:5)
vecs = [copy(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}}:
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
A .*= -1
5-element Vector{Int64}:
-2
-3
-4
-5
-6
B
5-element Vector{Int64}:
2
3
4
5
6
B .= A
5-element Vector{Int64}:
-2
-3
-4
-5
-6
vecs[1] .*= 2
5-element Vector{Int64}:
2
4
6
8
10
vecs
3-element Vector{Vector{Int64}}:
[2, 4, 6, 8, 10]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
Dictionnaire#
typeof(:A)
Symbol
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.
s = 0
for x in 1:1000
if x %3 == 0 || x % 5 == 0
s += x
end
end
println(s)
234168
sum( x for x in 1:1000 if (x%3 == 0 || x % 5 ==0))
234168
sum(filter(x -> (x%3 == 0 || x % 5 ==0), 1:1000))
234168