Débuter avec MATLAB

nextpreviouscontents
Suivant: Graphisme Précédent:Les entrées sorties
Voir:  Table des matièreIndex - Accueil


Programmer sous MATLAB


Scripts et fonctions

Il est possible d'enregistrer une séquence d'instructions dans un fichier (appelé un M-file  ) et de les faire exécuter par MATLAB. Un tel fichier doit obligatoirement avoir une extension de la forme .m (d'où le nom M-file) pour être considéré par MATLAB comme un fichier d'instructions. On distingue 2 types de M-file, les fichiers de scripts et les fichiers de fonctions. Un script est un ensemble d'instructions MATLAB qui joue le rôle de programme principal. Si le script est écrit dans le fichier de nom nom.m on l'exécute dans la fenêtre MATLAB en tapant nom. Même si l'on ne souhaite pas à proprement parler écrire de programme, utiliser un script est très utile. Il est en effet beaucoup plus simple de modifier des instructions dans un fichier à l'aide d'un éditeur de texte que de retaper un ensemble d'instructions MATLAB dans la fenêtre de commande.
 

Les fichiers de fonctions ont deux rôles. Ils permettent à l'utilisateur de définir des fonctions qui ne figurent pas parmi les fonctions incorporées de MATLAB (<< built-in functions >>) et de les utiliser de la même manière que ces dernières (ces fonctions sont nommées fonctions utilisateur).   Ils sont également un élément important dans la programmation d'applications où les fonctions jouent le rôle des fonctions et procédures des langages de programmation usuels.
 

On définit la fonction fonc de la manière suivante:

function [vars1, ..., varsm] = fonc(vare_1, ..., varen)

séquence d'instructions

Le fichier doit impérativement commencer par le mot-clé function. Suit entre crochets les variables de sortie de la fonction, le symbole =, le nom de la fonction et enfin les variables d'entrée entre parenthèses. Si la fonction ne possède qu'une seule variable de sortie, les crochets sont inutiles. Il est impératif que la fonction ayant pour nom fonc soit enregistrée dans un fichier de nom fonc.m sans quoi cette fonction ne sera pas << visible >> par MATLAB.
 

Dans l'exemple qui suit, on définit une fonction modulo qui calcule la valeur de a modulo n en prenant pour système de résidus {1, 2, ..., n} au lieu de {0, 1, ..., n-1} (système de résidus considéré par la fonction incorporée mod). Les lignes qui suivent doivent être enregistrées dans un fichier de nom modulo.m.

function [r,q] = modulo(a,n)

% Calcule la valeur de a modulo n en prenant pour systeme de residus
% 1, ... , n au lieu de 0, ... , n-1.
%
% appel : [r,q] = modulo(a,n)
%
% Arguments de sortie :
%  r : le residu
%  q : le quotient

q = floor(a./n);
r = a - n*q;

% si le reste de la division entiere vaut 0, le residu vaut par convention n 
if r == 0, r = n; end
Les lignes précédées du symbole % sont des lignes de commentaire. Les lignes de commentaire situées entre la ligne function ... et la 1-ere ligne d'instructions sont affichées si l'on demande de l'aide sur la fonction modulo.
>> help modulo

 Calcule la valeur de a modulo n en prenant pour systeme de residus
 1, ... , n au lieu de 0, ... , n-1.

 appel : [r,q] = modulo(a,n)

 Arguments de sortie :
  r : le residu
  q : le quotient

>>
L'appel d'une fonction utilisateur s'effectue de la même façon que l'appel de n'importe quelle fonction MATLAB:
>> b = 10 ; m = 4;
>> [r,q] = modulo(b,m)
r =
     2
q =
     2  
>> modulo(10,5)
ans =
     5
>>


Remarques:

  1. Il n'y a pas de mot-clé (par exemple end) pour indiquer la fin de la fonction. La fonction est supposée se terminer à la fin du fichier. Il est toutefois possible de provoquer un retour au programme appelant dans le corps de la fonction grâce à la commande return.
  2. On ne peut écrire qu'une seule fonction par fichier (qui doit porter le nom de cette fonction). Toutefois dans la version 5 de MATLAB existe la notion de << sous-fonction >>. Une sous-fonction est une fonction écrite dans le même fichier qu'une autre fonction (dite principale) et qui ne sera utilisable que par cette fonction principale (une sous-fonction ne peut pas être appelée par un autre sous-programme que la fonction principale).
  3. Si le fichier ne commence pas par le mot-clé function on a tout simplement écrit un script!


La gestion des variables d'entrée et de sortie est très souple sous MATLAB. Si l'on n'est intéressé que par le résidu et pas par le quotient, on peut se contenter de ne mettre qu'une seule variable de sortie, v = modulo(10,4). Dans cet appel la variable v contiendra le résidu (la première variable de sortie). Par contre, même si l'on ne souhaite recueillir que le quotient, on est obligé d'effectuer un appel de la forme [r,q] = modulo(10,4) et donc de définir une variable inutile. Aussi, d'une manière générale, il est bon de ranger les variables de sortie par ordre << d'importance >>. Il est également possible d'appeler une fonction donnée avec moins de variables d'entrée que le nombre indiqué pour la définition de la fonction (il faut bien entendu que le corps de la fonction soit programmé de sorte de prévoir cette éventualité). Il existe deux fonctions MATLAB utiles pour gérer cette situation: nargin qui retourne le nombre de variables d'entrée utilisés lors de l'appel et nargout qui retourne le nombre de variables de sortie prévues lors de l'appel. Voici un petit exemple venant illustrer ces possibilités.

function [A,rang] = matale(T,m,n)

% Construit une matrice A de m lignes et n colonnes ayant des elements
% entiers generes de maniere aleatoire entre 0 et T.
% Calcule le rang de la matrice si l'appel est effectue avec 2 arguments
% de sortie.
% Si la matrice est carree, le parametre n peut etre omis.
%
% Appels:
%       [A,r] = Matale(T,m,n)
%       [A,r] = Matale(T,m)
%           A = Matale(T,m,n)
%           A = Matale(T,m)

if nargin == 2
  A = fix(T*rand(m));
else
  A = fix(T*rand(m,n));
end

if nargout == 2
 rang = rank(A);
end
Dans cet exemple, on gère les variables d'entrée de la fonction de sorte de ne pas avoir besoin de donner lors de l'appel le nombre de lignes et de colonnes si la matrice est carrée. On gère aussi les variables de sortie afin de ne pas calculer le rang de la matrice si aucune variable de sortie pour le résultat n'est prévue lors de l'appel.
>> [A,r] = matale(20,3,4)
A =
    16    13    13    10
    10    16     7    14
     4     0    16     8
r =
     3   
>> [A,r] = matale(20,3)
A =
    12     0    18
     5    14     9
     3     8     8
r =
     3 
>> A = matale(20,3)
A =
     8     7     2
    17    16     4
     1     0     3    
>>


Un point important concerne la gestion des variables entre le programme principal (ou le workspace) et les fonctions de l'utilisateur. Toutes les variables définies à l'intérieur d'une fonction sont des variables locales à cette fonction. La communication avec des variables du programme principal (ou du workspace) ou avec des variables d'autres fonctions se fait uniquement par les variables d'entrée et sortie de la fonction. Une alternative existe toutefois: il est possible de déclarer certaines variables comme des variables globales . Une variable globale peut être partagée entre un programme principal et plusieurs fonctions sans qu'il soit besoin de la spécifier parmi les variables d'entrée-sortie des différentes fonctions. On déclare une variable globale grâce au mot clé global. Par exemple pour déclarer la variable numex globale on écrit global numex. Attention, la déclaration global numex doit être reprise dans chaque fonction utilisant numex comme variable.

Opérateurs de comparaison et opérateurs logiques

Les opérateurs de comparaison sont:
 
==  : égal à (x == y)
> : strictement plus grand que (x > y)
< : strictement plus petit que (x < y)
>= : plus grand ou égal à (x >= y)
<= : plus petit ou égal à (x <= y)
~ =  : différent de (x ~ = y)

Les opérateurs logiques sont:
 
 
: et (x & y)
: ou (x | y)
~ : non (~ x)

Les opérateurs de comparaison et les opérateurs logiques sont utilisés essentiellement dans les instructions de contrôle, voir le paragraphe 5.3.

  
Instructions de contrôle

Les instructions de contrôle sous MATLAB sont très proches de celles existant dans d'autres langages de programmation.

  
Boucle FOR : parcours d'un intervalle

Une première possibilité pour exécuter une séquence d'instructions de manière répétée consiste à effectuer une boucle pour les valeurs d'un indice, incrémenté à chaque itération, variant entre deux bornes données. Ce processus est mis en oeuvre par la boucle for.

Syntaxe :

forindice=borne_inf:borne_sup

séquence d'instructions

end





Interprétation :
Si borne_inf est plus petit ou égal àborne_sup, le traitement séquence d'instructions est exécuté borne_sup - borne_inf fois, pour les valeurs de la variable indice égales à borne_inf, borne_inf+1, ..., borne_sup. Si borne_inf est strictement plus grand que borne_sup, on passe à l'instruction qui suit immédiatement l'instruction de fin de boucle (end).
 

Remarque :
L'indice de boucle ne prend pas nécessairement des valeurs entières. D'autre part il n'est pas nécessaire que l'indice de la boucle apparaisse dans le corps de la boucle; par contre il est interdit de modifier sa valeur s'il apparaît. Il est possible d'imbriquer des boucles mais elles ne doivent pas se recouvrir. On peut utiliser un incrément (pas) autre que 1 (valeur par défaut). La syntaxe est alors borne_inf: pas : borne_sup. Le pas peut être négatif. Attention à bien gérer la borne supérieure! Voici un exemple (idiot) venant illustrer les possibilités de variations de l'indice de la boucle

>> for r=1.1:-0.1:0.75
     disp(['r = ', num2str(r)]);
   end
r = 1.1
r = 1
r = 0.9
r = 0.8  
>>
Voici un exemple d'utilisation d'une boucle pour calculer n! (le lecteur attentif sait calculer n! plus simplement ... par exemple en exécutant prod([1:n])).
>> n = 4;
>> nfac = 1;
>> for k = 1:n
     nfac = nfac*k;
   end
>> nfac
nfac =
    24
>>

  
Boucle WHILE : tant que . . . faire

Une seconde possibilité pour exécuter une séquence d'instructions de manière répétée consiste à effectuer une boucle tant qu'une condition reste vérifiée. On arrête de boucler dès que cette condition n'est plus satisfaite. Ce processus est mis en oeuvre par la boucle while.

Syntaxe :

whileexpression logique

séquence d'instructions

end


Interprétation :
Tant que expression logique est vraie le traitement séquence d'instructionsest exécuté sous forme d'une boucle. Lorsque expression logique devient faux, on passe à l'instruction qui suit immédiatement l'instruction de fin de boucle (end).
 

Remarque :
expression logique est en général le résultat d'un test (par exemple i < Imax) ou le résultat d'une fonction logique (par exemple all(x)). Il est impératif que le traitement de la séquence d'instructions agisse sur le résultat de expression logique sans quoi on boucle indéfiniment (-:.
 

Voici comment calculer n! avec une boucle while:

>> n = 4;
>> k = 1; nfac = 1;
>> while k <= n
     nfac = nfac*k;
     k = k+1;   
   end
>> nfac
nfac =
    24
>>

  
L'instruction conditionnée IF

On a parfois besoin d'exécuter une séquence d'instructions seulement dans le cas où une condition donnée est vérifiée au préalable. Différentes formes d'instruction conditionnée existent sous MATLAB.
 

L'instruction conditionnée la plus simple a la forme suivante:

Syntaxe :

ifexpression logique

séquence d'instructions

end


Interprétation:
la séquence d'instructions n'est exécutée que si le résultat de l'évaluation de l'expression logique est vraie (c'est-à-dire vaut 1). Dans le cas contraire on exécute l'instruction qui suit le mot clé end. Dans le cas où l'expression logique est vraie, après exécution de la séquence d'instructions on reprend le programme à l'instruction qui suit le mot clé end.
 

Remarque :
Contrairement à certains langages de programmation, il n'y a pas de mot clé << then >> dans cette instruction conditionnée. Notez également que la marque de fin de bloc conditionné est le mot clé end et non pas<< endif >>.
 

Il existe une séquence conditionnée sous forme d'alternatives:

Syntaxe :

ifexpression logique

séquence d'instructions 1

else

séquence d'instructions 2

end


Interprétation :
Si expression logique est vraie la séquence d'instructions 1 est exécutée, sinon c'est la séquence d'instructions 2 qui est exécutée. Le déroulement du programme reprend ensuite à la première instruction suivant le mot clé end.
 

Il est bien entendu possible d'imbriquer des séquences d'instructions conditionnées (au sens où la séquence d'instruction conditionnée contient des séquences d'instructions conditionnée). Pour une meilleure lisibilité, il est recommandé d'utiliser des indentations afin de mettre en évidence l'imbrication des séquences d'instructions conditionnées.
 

Il est possible d'effectuer un choix en cascade:

Syntaxe :

ifexpression logique 1

séquence d'instructions 1

elseif expression logique 2

séquence d'instructions 2

...

elseif expression logique N

séquence d'instructions N

else

séquence d'instructions par défaut

end




Interprétation :
Si expression logique 1 est vraie la séquence d'instructions 1 est exécutée et le programme reprend ensuite à la première instruction suivant le mot clé end, sinon si expression logique 2 est vraie la séquence d'instructions 2 est exécutée et le programme reprend ensuite à la première instruction suivant le mot clé end, etc. Si aucune des expressions logiques 1 à N n'est vraie alors séquence d'instructions par défaut est exécutée.
 

Remarque :
Attention à ne pas laisser d'espace entre else et if; le mot clé est elseif.
 

On utilise fréquemment un choix en cascade lors d'initialisation de données. Par exemple, on initialise une matrice A en fonction de la valeur d'une variable numex (numéro d'exemple) de la manière suivante:

if numex == 1
 A = ones(n);
elseif numex == 2
 A = magic(n);
elseif numex == 3 | numex == 4
 A = rand(n);
else
 error('numero d''exemple non prevu ...');
end

  
Choix ventilé, l'instruction switch

Une alternative à l'utilisation d'une séquence d'instructions conditionnées pour effectuer un choix en cascade existe. Il s'agit de l'instruction switch.
 

Syntaxe :

switch var

casecst1,

séquence d'instructions 1

casecst2,

séquence d'instructions 2

...

casecstN,

séquence d'instructions N

otherwise

séquence d'instructions par défaut

end


Interprétation :
Si la variable var est égale à l'une des constantes cst1, ..., cstN, (par exemple csti) alors la séquence d'instructions correspondante (ici séquence d'instructions i) est exécutée. Le programme reprend ensuite à la première instruction suivant le mot-clé end. Si la variable var n'est égale à aucune des constantes la séquence d'instructions par défaut est exécutée.
 

Remarque :
La variable var doit bien entendu être du même type que les constantes cst1, ..., cstN.
Il n'est pas nécessaire de prévoir un cas par défaut (bien que cela soit préférable). S'il n'y a pas de cas par défaut et si la variable var n'est égale à aucune des constantes, alors le programme continue à la première instruction suivant le mot-clé end.
Il est possible de regrouper plusieurs << cas >> si la séquence d'instructions à exécuter est la même pour ces différents cas. La syntaxe est alors,

case{ cstk , cstl , ...}

séquence d'instructions commune






Reprenons l'exemple où l'on souhaite initialiser une matrice A en fonction de la valeur prise par une variable numérique numex (numéro d'exemple). En utilisant un choix ventilé on obtient:

function  A = initA(n,numex)

switch numex
  case 1,
    A = ones(n)
  case 2,
    A = magic(n);
  case {3,4},
    A = rand(n);
  otherwise
    error('numero d''exemple non prevu ...');
end
Voici un exemple de choix ventilé portant sur une variable de type chaîne de caractères.
rep = input('Votre reponse (oui, non, chepas) :');

switch rep
  case {'oui','o'},
    disp('bravo ...');
  case {'non','n'}
    disp('perdu ...');
  case 'chepas'
    disp('c''est pourtant facile ...');
end

Interruption d'une boucle de contrôle

Il est possible de provoquer une sortie prématurée d'une boucle de contrôle. L'instruction break permet de sortir d'une boucle for ou d'une boucle while. L'exécution se poursuit alors séquentiellement à partir de l'instruction suivant le mot clé endfermant la boucle. En cas de boucles imbriquées, on interrompt seulement l'exécution de la boucle intérieure contenant l'instruction break. L'instruction return provoque un retour au programme appelant (ou au clavier). Les instructions suivant le return ne sont donc pas exécutées. L'instruction return est souvent utilisée conjointement avec une instruction conditionnée par exemple pour tester dans le corps d'une fonction si les paramètres d'entrée ont les valeurs attendues.
 

L'instruction errorpermet d'arrêter un programme et d'afficher un message d'erreur. La syntaxe est error(' message d''erreur '). L'instruction warning permet d'afficher un message de mise en garde sans suspendre l'exécution du programme. La syntaxe est warning(' message de mise en garde '). Il est possible d'indiquer à MATLAB de ne pas afficher les messages de mise en garde d'un programme en tapant warning off dans la fenêtre de commandes. On rétablit l'affichage en tapant warning on.
 

On peut ainsi améliorer la fonction matale de la manière suivante:

function [A,rang] = matale(T,m,n)
% Construit une matrice A de m lignes et n colonnes ayant des elements
% entiers generes de maniere aleatoire entre 0 et T.
% Calcule le rang de la matrice si l'appel est effectue avec 2 arguments
% de sortie.
% Si la matrice est carree, le parametre n peut etre omis.
%
% Appels:
%       [A,r] = Matale(T,m,n)
%       [A,r] = Matale(T,m)
%           A = Matale(T,m,n)
%           A = Matale(T,m)

% si la fonction est appelee avec un nombre d'arguments d'entree
% different de 2 ou 3, on arrete tout ...
if nargin ~= 2 &  nargin ~= 3,
   error(' La fonction matale doit avoir 2 ou 3 arguments d''entree ');
end

if nargin == 2
  A = fix(T*rand(m));
else
  A = fix(T*rand(m,n));
end

if nargout == 2
  rang = rank(A);
  if nargin == 2,
    rangx = m;
  else
    rangx = min([m,n]);
  end
  if rang ~= rangx, warning(' Le rang n''est pas maximum '); end;
end
On obtient alors les messages suivants:
>> A = matale(3);
??? Error using ==> matale
 La fonction matale doit avoir 2 ou 3 arguments d'entree
 
>> A = matale(20,3)
A =
     8    18     8
    12    14    18
    15     3    18 
>> [A,r] = matale(20,3)

Warning:  Le rang n'est pas maximum
> In /home0/maths/balac/DOCMATLAB/matale.m at line 34
A =
     1     4     3
    10    15    11
     3    12     9
r =
     2  
>>
La commande pause permet d'interrompre l'exécution du programme. L'exécution normale reprend dès que l'utilisateur enfonce une touche du clavier. L'instruction pause(n) suspend l'exécution du programme pendant n secondes.

Un exemple complet

Une technique de construction de carrés magiques d'ordre impair a été proposée par Manuel Moschopoulos au début du XIV siècle. Cette technique est décrite dans [Histoire d'Algorithmes, du caillou à la puce, J.L. Chabert éditeur, Belin 1994].
 

Notons l(x) le numéro de la ligne et c(x) le numéro de la colonne du carré sur lequel se trouve l'entier x. Partant d'un carré d'ordre impair n=2k+1, la technique de Moschopoulos peut se formuler comme suit:

l(1) = k + 2
c(1) = k + 1
l(x+1) = 1 + l(x) modulo(n)
c(x+1) = 1 + c(x) modulo(n)


Dans ces règles pour la prise du modulo, le système de résidus que l'on considère est 1, 2, ..., n et non pas 0, 1, ..., n-1.
 

La fonction magik met en oeuvre la méthode de Moschopoulos.

function M = magik(n)
%
% Calcule le carre magique d'ordre n selon la methode
% de Moschopoulous. 
%
% Entree: 
%  n : ordre du carre (entier impair)
% Sortie:
%  M : le carre magique
%

if rem(n,2) == 0,
  msg = ['la methode de Moschopoulous ne construit que des carres' ...
       ,' d''ordre impair'];
  error(msg)
end

k = (n-1)/2;
l(1) = k+2;
c(1) = k+1;
M(l(1),c(1)) = 1;

for x = 2:n.^2
  [l(x),c(x)] = pos(x-1,l(x-1),c(x-1),n);
  M(l(x),c(x)) = x;               
% ou plus simplement M(pos(x,l(x-1),c(x-1))) = x;
end
La fonction utilise la fonction pos. Cette dernière fonction peut soit être écrite à la suite de la fonction magik si l'on dispose de la version 5 de MATLAB (dans ce cas il s'agira d'une sous-fonction qui ne sera visible que de la fonction magik) soit être sauvegardée dans un fichier pos.m.
function [ly,cy] = pos(x,lx,cx,n)
%
% Retourne la position (indice de ligne ly et indice de colonne cy)
% dans le carre magique d'ordre n de l'entier y = x+1 selon la 
% regle de Moschopoulous. 
%
% Entree: 
%  n : ordre du carre (entier impair)
%  x : l'entier considere
% lx : indice de ligne de l'entier x dans le carre magique
% cx : indice de colonne de l'entier x dans le carre magique
%
% Sortie:
%  ly : indice de ligne de l'entier y=x+1 dans le carre magique
%  cy : indice de colonne de l'entier y=x+1 dans le carre magique
%

if rem(x,n) == 0
  ly = modulo(2+lx,n);
  cy = modulo(cx,n);
else
  ly = modulo(1+lx,n);
  cy = modulo(1+cx,n);
end


Voici quelques exemples d'utilisation de la fonction magik. On vérifie que la somme des éléments des différentes lignes ainsi que la somme des éléments des différentes colonnes sont bien constantes. Pour calculer la somme des éléments diagonaux c'est un peu plus compliqué. On remarque que le carré magique construit diffère du carré magique retourné par la fonction MATLAB incorporée magic.

>> magik(4)
??? Error using ==> magik
la methode de Moschopoulous ne construit que des carres d'ordre impair
>> magik(5)
ans =
    11    24     7    20     3
     4    12    25     8    16
    17     5    13    21     9
    10    18     1    14    22
    23     6    19     2    15
>> sum(magik(5),1)
ans =
    65    65    65    65    65
>>  sum(magik(5),2)
ans =
    65
    65
    65
    65
    65  
>> magic(5)
ans =
    17    24     1     8    15
    23     5     7    14    16
     4     6    13    20    22
    10    12    19    21     3
    11    18    25     2     9

nextpreviouscontents
Suivant: Graphisme Précédent:Les entrées sorties
Voir:  Table des matièreIndex - Accueil


(c) Stéphane Balac - Centre de Mathématiques - INSA de Lyon