Tableaux et matrices

La définition de tableaux i.e. vecteurs, matrices, hypermatrices est un élément essentiel du Julia.

Julia ne possède qu'un seul type de tableau : Array on peut définir sont nombre d'entrées (1 entrée= 1 dimension ...) et sont 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 ":"


In [1]:
a=1:5


Out[1]:
1:5

In [2]:
a.+1


Out[2]:
2:6

In [3]:
typeof(a)


Out[3]:
UnitRange{Int64}

In [4]:
b=0:0.5:2


Out[4]:
0.0:0.5:2.0

In [5]:
typeof(b)


Out[5]:
StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}

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 :


In [6]:
d=1:0 # itérateur formel mais correspond à un ensemble vide de valeurs


Out[6]:
1:0

In [7]:
d=collect(d)


Out[7]:
0-element Array{Int64,1}

Tableau

On vient de voir que l'on peut transformer l'itérateur précédent en tableau à l'aide de la commande "collect"


In [8]:
a=1:5
aa=collect(a)


Out[8]:
5-element Array{Int64,1}:
 1
 2
 3
 4
 5

In [9]:
collect(a')


Out[9]:
1×5 Array{Int64,2}:
 1  2  3  4  5

In [10]:
typeof(aa)


Out[10]:
Array{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, ...).

In [11]:
aa[1]


Out[11]:
1

In [12]:
aa[end] # pour accèder au dernier élément


Out[12]:
5

In [13]:
aa[end-2:end].=1; println(aa)


[1, 2, 1, 1, 1]

Les crochets permettent la construction explicite de tableaux (ou leur concaténation)


In [14]:
A=[1 2 ; 3 4] # {espace} = séparateur de colonne


Out[14]:
2×2 Array{Int64,2}:
 1  2
 3  4

In [15]:
AA=[A  A] # concaténation par bloc


Out[15]:
2×4 Array{Int64,2}:
 1  2  1  2
 3  4  3  4

In [16]:
hcat(A,A) # commande équivalent à la précédente [A  A]


Out[16]:
2×4 Array{Int64,2}:
 1  2  1  2
 3  4  3  4

In [17]:
AA=[A ; A]


Out[17]:
4×2 Array{Int64,2}:
 1  2
 3  4
 1  2
 3  4

In [18]:
vcat(A,A) # commande équivalent à la précédente [A  ; A]


Out[18]:
4×2 Array{Int64,2}:
 1  2
 3  4
 1  2
 3  4

On peut accéder à tout ou partie d'un tableau à l'aide de 2 indices


In [19]:
A[2,1]


Out[19]:
3

In [20]:
A[2,:]


Out[20]:
2-element Array{Int64,1}:
 3
 4

In [21]:
A[:,2]


Out[21]:
2-element Array{Int64,1}:
 2
 4

In [22]:
A[end,end]


Out[22]:
4

In [23]:
B=[1 2 3 4]


Out[23]:
1×4 Array{Int64,2}:
 1  2  3  4

In [24]:
B=[1;2;3;4]


Out[24]:
4-element Array{Int64,1}:
 1
 2
 3
 4

A noter que l'on peut faire des tableaux de tout type voir de les mélanger (Any)


In [25]:
a=["un";"deux"]


Out[25]:
2-element Array{String,1}:
 "un"  
 "deux"

In [26]:
b=[1>2,true,false]


Out[26]:
3-element Array{Bool,1}:
 false
  true
 false

In [27]:
c=["un"; 2 ; true]


Out[27]:
3-element Array{Any,1}:
     "un"
    2    
 true    

Le crochet [ ] permet également la construction rapide de matrice ou tableau comme le montre l'exemple si dessous pour construire une matrice de VanderMonde

$$ V_{i,j}=x_i^{j-1}$$

In [28]:
x=0:0.2:1;
V=[ x[i]^(j-1) for i=1:6, j=1:6] # ligne et colonne


Out[28]:
6×6 Array{Float64,2}:
 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    

In [29]:
D=[ u*v for u=1:0.5:3, v=1:0.5:4]


Out[29]:
5×7 Array{Float64,2}:
 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


In [30]:
a=[]
push!(a,1)     # => [1]
push!(a,2)     # => [1,2]
push!(a,4)     # => [1,2,4]
push!(a,6)     # => [1,2,4,6]


Out[30]:
4-element Array{Any,1}:
 1
 2
 4
 6

append!

Cette fonction permet de mettre bout à bout 2 tableaux


In [31]:
append!(a,a)


Out[31]:
8-element Array{Any,1}:
 1
 2
 4
 6
 1
 2
 4
 6

A noté le Array{Any,1} !


In [32]:
a=zeros(Int32,1)
push!(a,1)     # => [1]
push!(a,2)     # => [1,2]
push!(a,4)     # => [1,2,4]
push!(a,6)


Out[32]:
5-element Array{Int32,1}:
 0
 1
 2
 4
 6

In [33]:
a=zeros(0)


Out[33]:
0-element Array{Float64,1}

In [34]:
a=zeros(Int32,1)


Out[34]:
1-element Array{Int32,1}:
 0

Attention sur la conversion de type !


In [35]:
a=collect(1:5)


Out[35]:
5-element Array{Int64,1}:
 1
 2
 3
 4
 5

In [36]:
a=fill(0.,3,2)


Out[36]:
3×2 Array{Float64,2}:
 0.0  0.0
 0.0  0.0
 0.0  0.0

In [37]:
a[2]=sqrt(2)


Out[37]:
1.4142135623730951

In [38]:
a=map(Float64,a)


Out[38]:
3×2 Array{Float64,2}:
 0.0      0.0
 1.41421  0.0
 0.0      0.0

In [39]:
a=Float64.(a)


Out[39]:
3×2 Array{Float64,2}:
 0.0      0.0
 1.41421  0.0
 0.0      0.0

Algèbre linéaire

On retrouve beaucoup (toutes) de fonctions usuelles de l'algèbre linéaire


In [40]:
using LinearAlgebra

In [41]:
A=[1 2 ; 3 4]
size(A)


Out[41]:
(2, 2)

In [42]:
det(A)


Out[42]:
-2.0

In [43]:
tr(A)


Out[43]:
5

In [44]:
eigvals(A)


Out[44]:
2-element Array{Float64,1}:
 -0.3722813232690143
  5.372281323269014 

In [45]:
A=[1 2;3 4];b=[2 ; 3]; #résolution du système Ax=b
x=A\b


Out[45]:
2-element Array{Float64,1}:
 -1.0
  1.5

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 +,-,*</code>,^,/ 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.


In [46]:
A=[1 2;3 4]
exp(A)


Out[46]:
2×2 Array{Float64,2}:
  51.969   74.7366
 112.105  164.074 

In [47]:
exp.(A) # exponentielle matricielle


Out[47]:
2×2 Array{Float64,2}:
  2.71828   7.38906
 20.0855   54.5982 

De plus les tableaux possèdes des opérations de multiplication, division, puissance termes à termes


In [48]:
A^2 #Multiplication Matricielle


Out[48]:
2×2 Array{Int64,2}:
  7  10
 15  22

In [49]:
A.^2 #Multiplication terme à terme


Out[49]:
2×2 Array{Int64,2}:
 1   4
 9  16

In [50]:
A./[2 3 ; 4 5] #Division terme à terme


Out[50]:
2×2 Array{Float64,2}:
 0.5   0.666667
 0.75  0.8     

In [51]:
A./2


Out[51]:
2×2 Array{Float64,2}:
 0.5  1.0
 1.5  2.0

Opérateurs booléens sur les tableaux


In [52]:
collect(1:5)>2


MethodError: no method matching isless(::Int64, ::Array{Int64,1})
Closest candidates are:
  isless(!Matched::Missing, ::Any) at missing.jl:70
  isless(::Real, !Matched::AbstractFloat) at operators.jl:149
  isless(::Real, !Matched::Real) at operators.jl:338
  ...

Stacktrace:
 [1] <(::Int64, ::Array{Int64,1}) at ./operators.jl:260
 [2] >(::Array{Int64,1}, ::Int64) at ./operators.jl:286
 [3] top-level scope at In[52]:1

In [53]:
collect(1:5).>2


Out[53]:
5-element BitArray{1}:
 false
 false
  true
  true
  true

In [54]:
collect(1:5).>[0;2;3;4;5]


Out[54]:
5-element BitArray{1}:
  true
 false
 false
 false
 false

In [55]:
collect(1:5).>[0 2 3 4 5]


Out[55]:
5×5 BitArray{2}:
 true  false  false  false  false
 true  false  false  false  false
 true   true  false  false  false
 true   true   true  false  false
 true   true   true   true  false

Particularité max, maximum, min, minimum


In [56]:
max(2,3)


Out[56]:
3

In [57]:
max(1,2,3)


Out[57]:
3

In [58]:
max(1:5)


MethodError: no method matching max(::UnitRange{Int64})
Closest candidates are:
  max(::Any, !Matched::Missing) at missing.jl:107
  max(::Any, !Matched::Any) at operators.jl:400
  max(::Any, !Matched::Any, !Matched::Any, !Matched::Any...) at operators.jl:502
  ...

Stacktrace:
 [1] top-level scope at In[58]:1

In [59]:
maximum(1:5)


Out[59]:
5

In [60]:
max.(1:5,2:6)


Out[60]:
5-element Array{Int64,1}:
 2
 3
 4
 5
 6

Constructeurs

Enfin il est possible de construire rapidement certaines matrices


In [61]:
a=fill(0.,2,3)


Out[61]:
2×3 Array{Float64,2}:
 0.0  0.0  0.0
 0.0  0.0  0.0

In [62]:
a=fill(2,2)


Out[62]:
2-element Array{Int64,1}:
 2
 2

In [63]:
b=range(0,stop=2*pi,length=10)


Out[63]:
0.0:0.6981317007977318:6.283185307179586

In [64]:
collect(b)


Out[64]:
10-element Array{Float64,1}:
 0.0               
 0.6981317007977318
 1.3962634015954636
 2.0943951023931953
 2.792526803190927 
 3.490658503988659 
 4.1887902047863905
 4.886921905584122 
 5.585053606381854 
 6.283185307179586 

In [65]:
A=ones(3)


Out[65]:
3-element Array{Float64,1}:
 1.0
 1.0
 1.0

In [66]:
A=zeros(3)


Out[66]:
3-element Array{Float64,1}:
 0.0
 0.0
 0.0

In [67]:
B=randn(5) # loi normale centrée de variance 1


Out[67]:
5-element Array{Float64,1}:
  0.12480414163059872
 -0.9203450973136945 
 -0.45273261732703646
 -1.3877539011518276 
 -0.3842163305360006 

In [68]:
B=[ones(3,2) zeros(3,2)] # concaténation de tableaux


Out[68]:
3×4 Array{Float64,2}:
 1.0  1.0  0.0  0.0
 1.0  1.0  0.0  0.0
 1.0  1.0  0.0  0.0

In [69]:
B=[ones(3,2); zeros(3,2)] # , ou ; jouent le rôle de retour à la ligne


Out[69]:
6×2 Array{Float64,2}:
 1.0  1.0
 1.0  1.0
 1.0  1.0
 0.0  0.0
 0.0  0.0
 0.0  0.0

In [70]:
C=Diagonal(ones(3,3))


Out[70]:
3×3 Diagonal{Float64,Array{Float64,1}}:
 1.0   ⋅    ⋅ 
  ⋅   1.0   ⋅ 
  ⋅    ⋅   1.0

In [71]:
diag(C) # extraction d'une diagonale


Out[71]:
3-element Array{Float64,1}:
 1.0
 1.0
 1.0

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).


In [1]:
using SparseArrays

In [3]:
A=spzeros(3,3)


Out[3]:
3×3 SparseMatrixCSC{Float64,Int64} with 0 stored entries

In [5]:



Out[5]:
4-element Array{Int64,1}:
 1
 1
 1
 1

In [74]:
A=spdiagm(0 => 1:3)


Out[74]:
3×3 SparseMatrixCSC{Int64,Int64} with 3 stored entries:
  [1, 1]  =  1
  [2, 2]  =  2
  [3, 3]  =  3

In [75]:
A=A+spdiagm(1 => 1:2)


Out[75]:
3×3 SparseMatrixCSC{Int64,Int64} with 5 stored entries:
  [1, 1]  =  1
  [1, 2]  =  1
  [2, 2]  =  2
  [2, 3]  =  2
  [3, 3]  =  3

In [76]:
sparse([0 1 2; 2 0 0]) # pour rendre sparse une matrice "full"


Out[76]:
2×3 SparseMatrixCSC{Int64,Int64} with 3 stored entries:
  [2, 1]  =  2
  [1, 2]  =  1
  [1, 3]  =  2

In [77]:
det(A)


Out[77]:
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 varibla scalire


In [78]:
a=1
b=a
b+=1


Out[78]:
2

In [79]:
a


Out[79]:
1

In [80]:
b


Out[80]:
2

Par contre maintenant si la variable est un tableau


In [81]:
A=collect(1:5)
B=A
B.+=1


Out[81]:
5-element Array{Int64,1}:
 2
 3
 4
 5
 6

In [82]:
A


Out[82]:
5-element Array{Int64,1}:
 2
 3
 4
 5
 6

In [83]:
B


Out[83]:
5-element Array{Int64,1}:
 2
 3
 4
 5
 6

Pour avoir un comportement il faut copier le tableau A


In [84]:
A=collect(1:5)
B=copy(A)
B.+=1


Out[84]:
5-element Array{Int64,1}:
 2
 3
 4
 5
 6

In [85]:
A


Out[85]:
5-element Array{Int64,1}:
 1
 2
 3
 4
 5

In [86]:
B


Out[86]:
5-element Array{Int64,1}:
 2
 3
 4
 5
 6