Intro Matlab09
Intro Matlab09
Intro Matlab09
David Poulin
Département de Physique, Université de Sherbrooke, Qc, Canada
[email protected]
4 février 2010
2 Le mode interactif 4
4 Les scripts 17
5 Les fonctions 20
5.1 Fonctions anonymes . . . . . . . . . . . . . . . . . . . . . . . . . 21
1
nous devons résoudre un certain problème une seule fois ou lorsque les ressources
requises par le calcul ne sont pas très importantes.
À titre d’exemple, supposons que l’on désire résoudre le problème d’équations
linéaires suivant
3 1 3 x1 −1
1 5 9 x2 = 3 . (1)
2 6 5 x3 −3
Une petite recherche sur Google nous permet de trouver un programme écrit en
C++ qui accomplit cette tâche (source, http ://seehuhn.de/pages/linear)
#include <stdio.h>
#include <atlas_enum.h>
#include "clapack.h"
double m[] = {
3, 1, 3,
1, 5, 9,
2, 6, 5
};
double x[] = {
-1, 3, -3
};
int
main()
{
int ipiv[3];
int i, j;
int info;
return 0;
}
Ce code doit ensuite être compilé avec la commande gcc programme.c -o
a.out -llapack atlas -llapack -lblas -latlas -lm, sans oublier d’avoir
bien installé le fichier clapack.h. On l’exécute ensuite à l’aide de la commande
./a.out. Voici maintenant un code MATLAB effectuant la même tâche :
>> A = [3 1 3; 1 5 9; 2 6 5];
>> x = [-1; 3;-3];
>> y = A\x
2
Il y a évidemment une différence notable entre la taille de ces deux pro-
grammes. On observe en particulier que la majorité des commandes du code
en C++ servent à «mettre la table» en ce sens qu’elles ne s’attaquent pas
au problème mais définissent les paramètres du calcul. En particulier, un bon
nombre de commandes définissent les bibliothèques utilisées par le programme
ou définissent le type de chaque variable. Par exemple, la variable x qui contient
la solution à notre système d’équations est un tableau de type entier. En MAT-
LAB par contre, l’appel des bibliothèques nécessaires et la déclaration de type se
fait automatiquement. Nous n’avons pas à spécifier le type ou même la taille des
tableaux : ceux-ci sont extraits du contexte. Ainsi, la même ligne de commande
MATLAB pourrait résoudre un système d’équations linéaires avec coefficients
complexes, alors qu’une routine différente serait requise en C++.
Cela illustre quelques uns des nombreux avantages d’un langage de haut ni-
veau tel que MATLAB. En contrepartie, un langage interprété est généralement
plus lent qu’un langage compilé. Pour toutes les opérations matricielles, MAT-
LAB utilise la bibliothèque LAPACK, tout comme la majorité des programmes
développés dans le langage C++. Ainsi, MATLAB est tout aussi rapide que
le C++ pour les opérations matricielles, tant que l’on l’utilise correcte-
ment. Afin d’illustrer l’importance d’utiliser les fonctions pré-définies, com-
parons les performances d’une de ces fonctions à celles d’une fonction «faite
maison». Définissons d’abord deux vecteurs aléatoires de taille 1 000 000 :
>> X = rand(1000000,1);
>> Y = rand(1000000,1);
On peut additionner ces vecteurs tout simplement avec le symbole +. Dans ce
qui suit, nous mesurons la performance du calcul à l’aide de la fonction cputime
qui retourne le temps en secondes utilisé par le processeur
>> t = cputime; Z = X+Y; cputime-t
ans =
0.0200
ans =
55.490000000000009
3
Puisqu’elle ne fait pas appel aux fonctions matricielles pré-définies dans MAT-
LAB, la seconde méthode requière 2000 fois plus de temps ! (Note : le temps
d’exécution de la seconde commande est très instable... peut fluctuer considérablement
d’une machine à l’autre.)
Le département de physique possède une dizaine de licences MATLAB qui
peuvent être utilisées simultanément. Le programme Octave (http ://www.gnu.org/software/octave/)
est en gros une version gratuite de MATLAB. Il existe quelques petites différences
au niveau de la syntaxe, mais elles sont très rares et en général Octave est plus
permissif que MATLAB. Tous les programmes que nous présentons dans ces
notes peuvent aussi bien être exécutés avec Octave qu’avec MATLAB.
Bien que MATLAB soit équipé d’une bibliothèque pour le calcul symbolique,
il est principalement utilisé (et performant) pour le calcul numérique. Pour le
calcul symbolique, les programmes Mathematica ou Maple sont habituellement
plus puissants.
2 Le mode interactif
Il existe trois façons d’utiliser MATLAB, soit en mode interactif, à l’aide
de scripts ou de fonctions. Nous abordons d’abord le mode interactif, les deux
autres méthodes seront discutées aux sections 4 et 5 respectivement. En mode
interactif, on inscrit directement les commandes dans un terminal et celles-ci
sont exécutées dès que l’on appuie sur la touche «enter». Le symbole >> (ou
octave-3.0.1 :1> avec Octave) apparaı̂t lorsque le terminal est prêt à recevoir
une commande, c’est-à-dire lorsque l’exécution de la commande précédente est
terminée. Voici quelques exemples d’exécution en mode interactif :
>> 5+6
ans =
11
>> a = 3 + 2
a =
>> b = 1+4;
>> a+b
ans =
10
4
On remarque une différence entre la commande a = 3 + 2 et b = 1 + 4 ;.
Dans le premier cas, la réponse a = 5 est affichée au terminal alors que dans
le second elle ne l’est pas. C’est l’effet du point-virgule. Si l’on désire faire une
opération sans voir le résultat immédiatement, on ajoute un point-virgule à la
fin de la commande. On peut toujours afficher la valeur d’une variable plus tard
en entrant son nom comme ligne de commande, par exemple
>> b
b =
5
Le nom des variables doit débuter par une lettre et peut être suivi par une
combinaison arbitraire d’au plus 32 chiffres et lettres. Il est important d’essayer
de choisir des noms de variables qui expliquent du mieux possible le rôle de
chaque variable. On observe qu’il n’est pas nécessaire d’assigner de type aux
variables. Toute variable en MATLAB est une matrice (ou tenseur) dont le type
(complexe, réel, entier) est déterminé par le contexte et se modifie automati-
quement au besoin. On peut connaı̂tre toutes les variables en mémoire à l’aide
de la commande whos :
>> whos
Name Size Bytes Class Attributes
A 3x3 72 double
X 10000000x1 80000000 double
Y 10000000x1 80000000 double
Z 10000000x1 80000000 double
a 1x1 8 double
ans 1x1 8 double
b 1x1 8 double
t 1x1 8 double
x 3x1 24 double
y 3x1 24 double
ce qui correspond bien aux variables que nous avons définies jusqu’à maintenant.
On vide le contenu d’une variable à l’aide de la commande clear suivi du nom
de la variable et clear all pour libérer toute la mémoire.
5
particulier, on retrouve au bas de chaque page d’aide une liste de fonctions si-
milaires ou reliées de quelconque façon à la fonction principale. C’est ainsi que
de fil en aiguille on arrive généralement à identifier la fonction qu’il nous faut.
Un autre outil indispensable pour la recherche de fonctions MATLAB est bien
entendu Google. Par exemple, une simple recherche «matlab valeurs propres»
ou encore «matlab intégrale» nous enseigne comment diagonaliser les matrices
ou intégrer des fonctions.
Un certain nombre de constantes sont pré-définies : pi est le nombre π, inf
est le résultat de la division par 0, eps est la précision numérique qui dépend
de l’ordinateur, realmax et realmin sont le plus grand et le plus petit nombre
qu’on peut représenter
√ dans MATLAB, NAN est résultat de 0/0 et i et j sont
tous deux égaux à −1. Il faut faire attention car on peut écraser ces valeurs en
les utilisant en tant que variables et en leur assignant de nouvelles valeurs, par
exemple i=3. Il en va de même de toutes les fonctions pré-définies en MATLAB,
on peut les détruire si on n’est pas prudent. Par exemple sin = 4 nous empêche
d’utiliser subséquemment la fonction sinus. Vaut mieux éviter d’utiliser les noms
pré-assignés en tant que variables sinon on se réserve de belles surprises !
3.1 Matrices
3.1.1 Créer une matrice
Nous avons déjà vu comment définir une matrice en MATLAB, il suffit de
mettre ses éléments entre crochets [ ]. Les éléments d’une même ligne sont
séparés d’un espace et un point-virgule marque la fin d’une ligne. Les vecteurs
ligne sont définis en tant que matrices de taille 1 × m alors que les vecteurs
colonne sont de taille m × 1. La matrice nulle de taille m × n s’obtient avec la
commande zeros(m,n). Lorsque m = n, on utilise plus simplement zeros(m),
ce qui sous-entend une matrice carrée. La matrice identité de taille n s’obtient
avec eye(n). On peut obtenir une matrice dont les éléments sont aléatoirement
distribués dans l’intervalle [0, 1] à l’aide de rand :
>> A = rand(4)
A =
Il est à noter qu’avant l’exécution de cette commande, la variable A était une ma-
trice de taille 3×3 puisque nous l’avions définie ainsi dans un exemple précédent
et ne l’avions pas libérée. Cela n’est pas un problème, MATLAB se charge de
libérer la mémoire et de donner à A les bonnes dimensions. Bien entendu, la
valeur précédente de A est perdue. Les dimensions d’une matrice sont données
par la fonction size, qui retourne un vecteur [m n] contenant les dimensions.
6
On peut donc combiner cette fonction comme eye(size(A)) qui retourne la
matrice identité de taille 4 × 4.
On peut créer un vecteur contenant les entiers de k à h comme suit
>> c = 5:13
c =
5 6 7 8 9 10 11 12 13
On peut également spécifier un espacement différent entre chaque valeur, par
exemple
>> c = 5:-0.3:2.9
c =
C =
0.6500 0.7586
0.7829 0.2753
0.2136 0.2930
0.9265 0.4861
>> A+B
ans =
7
13.0453 14.1185 15.6286 16.3511
>> 2.2*C
ans =
1.4300 1.6688
1.7224 0.6056
0.4698 0.6445
2.0383 1.0693
>> B^2
ans =
>> A*C
ans =
0.8693 0.7548
1.9673 1.4182
1.0013 0.6428
0.5817 0.4217
>> A+3
ans =
8
correspondant de la matrice B
>> A.*B
ans =
>> A*B
ans =
ans =
>> A^2
ans =
9
3.1.4 Conjugaison, transposition et adjoint
On obtient donc des matrices complexes à l’aide du nombre imaginaire i,
par exemple
>> D = A+i*B
D =
ans =
>> transpose(D)
ans =
>> D’
ans =
3.1.5 Diagonalisation
Une matrice normale, c’est-à-dire une matrice qui commute avec son adjoint,
possède une décomposition en valeur propre : D = U ΛU † ou Λ est une matrice
10
diagonale et U U † = U † U = I est une matrice unitaire. MATLAB permet d’ob-
tenir la décomposition spectrale comme suit (dans cet exemple, on s’assure que D
est normale en l’additionnant à son adjoint de sorte à ce qu’elle soit Hermitique)
>> D = D+D’;
>> [U,Lambda] = eig(D)
U =
Lambda =
-11.4616 0 0 0
0 -0.1216 0 0
0 0 0.6080 0
0 0 0 15.6906
On remarque ici que la fonction eig produit deux réponses (la matrice contenant
les valeurs propres et celle contenant les vecteurs propres). Cette fonction permet
d’utiliser un nombre variable de sorties, si on ne veut que les valeurs propres,
on utilise plutôt
>> Lambda2 = eig(D)
Lambda2 =
-11.4616
-0.1216
0.6080
15.6906
Cette fois, la fonction ne retourne que la diagonale de la matrice puisque les
autres éléments sont tous nuls. On passe facilement d’une représentation à
l’autre à l’aide de la fonction diag
>> diag(Lambda)
ans =
-11.4616
-0.1216
0.6080
15.6906
11
>> diag(Lambda2)
ans =
-11.4616 0 0 0
0 -0.1216 0 0
0 0 0.6080 0
0 0 0 15.6906
Pour une matrice non-diagonalisable, eig retourne les vecteurs et valeurs
propres comme nous l’avons vu. Par contre, les vecteurs propres ne sont pas
linéairement indépendants, donc la matrice U ne serait pas unitaire, ni même
inversible.
>> A = A+eye(size(A))*abs(min(eig(A)));
>> norm(sqrtm(A*A)-A)
ans =
1.8119e-15
>> norm(sqrt(A*A)-A)
ans =
1.8502
12
>> A(2,3)
ans =
0.7314
>> A(2,3) = 3
A =
>> A(:,2)
ans =
0.1538
0.6031
0.7876
0.1185
>> A(3,:)
ans =
>> A([2:4],[1,3])
ans =
0.8035 3.0000
0.1124 0.9797
0.0453 0.6286
qui retourne l’intersection des lignes 2 à 4 et des colonnes 1 et 3.
13
3.1.8 Matrices éparses
Lorsque la majorité des éléments d’une matrice sont nuls, il est plus pratique
de mettre la matrice en mémoire sous une autre forme. En gros, plutôt que de
spécifier la valeur de chaque élément, on spécifie uniquement que la valeur des
éléments non-nuls ainsi que leur emplacement.
>> C = [0 3.1 0 0 1.3; 2 0 0 0 0; 0 0 0 2.9 0]
C =
0 3.1000 0 0 1.3000
2.0000 0 0 0 0
0 0 0 2.9000 0
>> sparse(C)
ans =
(2,1) 2.0000
(1,2) 3.1000
(3,4) 2.9000
(1,5) 1.3000
14
>> txt = fopen(’fichier.txt’,’w’);
>> fprintf(txt,’voici la matrice A:’);
>> fprintf(txt,’%10.5f %10.5f %10.5f %10.5f \n’,A);
>> fclose(txt);
produisent un fichier fichier.txt dans le répertoire courant dont on devine le
contenu.
3.3 Graphique
MATLAB possède un riche environnement graphique. La fonction plot sert
à tracer des courbes à partir de données stockées dans des vecteurs ou matrices.
>> clear all;
>> x=[0:0.1:20];
>> plot(x, [cos(x); 1./(2+sin(x)).^2]);
15
La rubrique d’aide de la fonction plot est un bon point de départ pour
apprendre les différentes options graphiques. Il est à noter que l’environnement
graphique de Octave n’offre pas la possibilité de contrôler les paramètres d’un
graphique avec la souris : il faut donc tout spécifier à partir de la console.
Sous l’onglet «File» de la fenêtre graphique, on retrouve la commande «Ge-
nerate M-file» qui génère les commandes de terminal nécessaires pour repro-
duire le graphique. Cela constitue une bonne façon d’apprendre les commandes
graphiques et est très pratique lorsque l’on doit produire plusieurs graphiques
avec des données différentes mais suivant toutes le même style. Dans ce cas, on
peaufine un premier graphique, génère les commandes de terminal qui lui sont
associées et pouvons ainsi automatiser la production des autres graphiques.
MATLAB offre également la possibilité de générer des graphiques en trois
dimensions. Les fonctions plot3, contour, contour3, bar3, mesh et surf en
sont quelques exemples.
>> f = @(x,y)(exp(-(x-1).^2-(y-1).^2) - 0.3*exp(-(x+y).^2));
>> [X,Y] = meshgrid(-3:0.1:3,-3:0.1:3);
>> surfc(X,Y,f(X,Y))
On peut générer une image en une variété de formats à partir d’un graphique
à partir de l’onglet «File» et «Save As». On peut créer une seconde fenêtre
graphique sans affecter le contenu d’une première à l’aide de la commande
figure(2) et ainsi de suite.
16
4 Les scripts
Un script est simplement une séquence de commandes que l’on regroupent
dans un fichier plutôt que de les entrer au terminal. Le nom du fichier doit se
terminer par «.m». Une bonne habitude consiste à choisir un nom de script
qui nous informe du contenu de celui-ci et de bien commenter les scripts. Il est
également important d’éviter des noms de fonctions pré-définies dans MATLAB
afin d’éviter les conflits. Le contenu du fichier doit être sauvegardé en format
ascii, comme le permet tout éditeur de texte de base. La séquence de commandes
est exécutée en entrant le nom du script dans le terminal MATLAB. Il est
nécessaire pour cela de se trouver dans le même répertoire que le script ou
d’indiquer le chemin complet du répertoire où se situe le script. Par exemple,
nous pouvons créer un fichier «/user/home/mon script.m» et y inscrire les lignes
suivantes :
A =
1 2
3 4
B =
0.1000 0.3000
-0.1000 2.2000
C =
1.1000 2.3000
2.9000 6.2000
17
E =
-21.8000 10.8000
-57.5000 28.5000
On remarque que la ligne D = A*B ; n’a pas générée d’écriture au terminal, ce
qui s’explique par le point-virgule. Les lignes débutant par le symbole % sont
des commentaires. Il est important de bien commenter les scripts afin de s’y re-
trouver soi-même et afin qu’ils soient compréhensibles pour d’autres utilisateurs
potentiels.
Afin de répéter l’exécution d’un certain nombre de commandes un grand
nombre de fois, on peut utiliser une boucle for. Par exemple, le script suivant
calcule
P∞ une approximation au cosinus basée sur la série de Taylor cos(x) =
j (
j=0 (−1) x 2j)/j!.
cos_n = 1;
for j=1:n
cos_n = cos_n + (-1)^j * x^(2*j)/factorial(2*j);
end
cos_n
Dans cet exemple, nous avons défini les paramètres n et x à l’intérieur du script.
Il est également possible de définir ces paramètres dans le terminal avant de faire
appel au script. Cela est un aspect très important des scripts qui les distinguent
des fonctions : les variables utilisées dans les scripts et celles utilisées en
mode interactif sont les mêmes. Ainsi, un script peut accéder aux variables
définies en mode interactif et modifier leurs valeurs. À l’inverse, toutes les va-
riables définies dans un script demeurent accessibles en mode interactif suite à
l’exécution du script. Par exemple, si on tape j au terminal suite à l’exécution
du script ci-haut, on obtient ans = 5, ce qui correspond bien à la dernière va-
leur assignée à j par le script. Cette possibilité d’accéder de façon interactive
aux variables d’un script est très utile au développement et déverminage d’un
programme.
De façon plus générale, on peut utiliser la boucle for avec les paramètres
de boucle de forme j = j init:dj:j final qui représentent respectivement la
valeur initiale, l’incrément et la valeur finale de j dans la boucle. La commande
while est utilisée lorsque la boucle doit être répétée conditionnellement à la
valeur d’un énoncé. Par exemple, on peut modifier le script précédent afin de
calculer le cosinus à une précision donnée.
% Série de taylor pour l’approximation de cos(x), précision requise
18
precision = 1.0e-18; % Précision requise
x = 0.22; % Point où est évaluée la fonction
cos_n = 1;
dcos = 1;
j = 0;
while abs(dcos) > precision
j = j+1;
dcos = (-1)^j * x^(2*j)/factorial(2*j);
cos_n = cos_n + dcos;
end
cos_n
j
L’appel du script produit cos n = 0.9759 et j = 7. La boucle se termine
lorsque la condition abs(dcos) > presision retourne la valeur 0, ce qui cor-
respond à faux. Une condition est en général une variable binaire que l’on peut
construire à l’aide de relations entre expressions arithmétiques. Les opérateurs
de relation sont == pour l’égalité, <= pour plus petit ou égal, ∼= pour la non-
égalité, etc. Les conditions peuvent également se combiner à l’aide d’opérateurs
logiques «et» &, «ou» | et la négation ∼.
Finalement, les commandes if, else et elseif permettent d’exécuter un
ensemble de commandes conditionnellement à une condition :
% Vérifie si le nombre N est composé ou premier
N_max = 1000; % facteur maximal
facteurs = [];
M = N;
j=2; % premier facteur que l’on vérifie
while j < min(N_max,ceil(sqrt(M))) %Facteurs sont inférieurs à la racine carré du nombre
if mod(M,j) == 0
facteur = 1;
facteurs = [facteurs,j];
M = M/j;
else
j = j+1;
end
end
19
[facteurs,M]
end
On tape N = 103857 et appel ce script, ce qui produit ans = 3 13 2663, alors
que l’entrée N = 13 produit ans = N est premier et finalement N = 2∧20-3
donne ans = N est premier ou ses facteurs sont plus grand que Nmax.
Il est à noter que les commandes for, if et while peuvent être utilisées en mode
interactif également, quoi que cela est moins naturel. Comme nous l’avons vu,
les boucles sont très lentes. Il est donc préférable d’utiliser des opérations ma-
tricielles lorsque cela est possible. Par exemple, le script calculant les n premiers
termes de la série de Taylor du cosinus est beaucoup plus rapide sous la forme
% Série de taylor pour l’approximation de cos(x), nombre fixe de termes
j = [1:n];
cos_n = 1 + sum((-1).^j .* x.^(2*j) ./ factorial(2*j))
5 Les fonctions
Nous avons déjà rencontré un bon nombre de fonctions pré-définies dans
MATLAB, par exemple la fonction cos. Il est également possible de définir ses
propres fonctions. Cela est très similaire à la création d’un script. Toutefois, les
variables définies à l’intérieur d’une fonction sont distinctes de celles définies en
mode interactif ou dans des scripts et elles sont détruites lorsque l’exécution de
la fonction est terminée. Ainsi, une fonction doit avoir des entrées et des sorties
bien définies. Cela se fait à la première ligne du fichier contenant la descrip-
tion de la fonction qui doit être de la forme fonction variable de sortie =
nom de la fonction(variables entrée). Le nom du fichier doit être le même
que le nom de la fonction, suivi de l’extension .m. Par exemple, on peut transfor-
mer notre script calculant les n premiers termes de la série de Taylor du cosinus
et en faire une fonction
% Série de taylor pour l’approximation de cos(x), nombre fixe de termes
function y = cos_n(x,n)
% x est le point où est évaluée la fonction
% n est le nombre de termes dans la série
% y retourne le résultat
j = [1:n];
y = 1 + sum((-1).^j .* x.^(2*j) ./ factorial(2*j));
À partir du terminal, on peut faire l’appel w = cos n(0.22,5), ce qui produit
le résultat y = 0.9759. La variable j n’est pas affectée par l’exécution de cette
fonction.
20
Il est également possible de créer des fonctions à plusieurs variables de sorties.
Nous avons déjà rencontré la fonction eig qui retourne les vecteurs propres et les
valeurs propres d’une matrice. De façon générale, il suffit de placer les multiples
variables de sortie entre crochets dans la définition et dans l’appel de la fonction.
Par exemple, on peut déterminer les racines d’une fonction quadratique à l’aide
de la fonction
% Trouver les racines d’une fonction quadratique
% ax^2 + bx + c étant donnés les coefficients a, b et c.
function [x1,x2] = racine_quad(a,b,c)
d = b*b-4*a*c;
r1 = (-b+sqrt(d))/(2*a);
r2 = (-b-sqrt(d))/(2*a);
que l’on appelle avec la commande [r1,r2] = racine quad(a,b,c).
ans =
-0.8751
ans =
0.5084
21