7. Programmation : interaction, debugging, structures de contrôle,
scripts, fonctions, entrées-sorties fichier, GUI

7.1 Généralités

Les "M-files" sont des fichiers au format texte (donc "lisibles") contenant des instructions MATLAB/Octave et portant l'extension *.m. On a vu la commande diary (au chapitre "Workspace") permettant d'enregistrer un "journal de session" qui, mis à part l'output des commandes, pourrait être considéré comme un M-file. Mais la manière la plus efficace de créer des M-files (c'est-à-dire "programmer" en langage MATLAB/Octave) consiste bien entendu à utiliser un éditeur de texte ou de programmation.

On distingue fondamentalement deux types de M-files : les scripts (ou programmes) et les fonctions. Les scripts travaillent dans le workspace, et toutes les variables créées/modifiées lors de l'exécution d'un script sont donc visibles dans le workspace et accessibles ensuite interactivement ou par d'autres scripts. Les fonctions, quant à elles, n'interagissent avec le workspace ou avec le script appelant essentiellement au moyen des "paramètres" d'entrée/sortie, les autres variables manipulées restant internes (locales) aux fonctions.

MATLAB/Octave est un langage interprété (comme les langages Perl, Python, Ruby, PHP, les shell Unix...), c'est-à-dire que les M-files (scripts ou fonctions) sont directement exécutables, donc n'ont pas besoin d'être préalablement compilés avant d'être utilisés (comme c'est le cas des langage classiques C/C++, Java, Fortran...). A l'exécution, des fonctionnalités interactives de debugging et de profiling permettent d'identifier les bugs et optimiser le code.

MATLAB et Octave étant de véritables progiciels, le langage MATLAB/Octave est de "haut niveau" et offre toutes les facilités classiques permettant de développer rapidement des applications interactives évoluées. Nous décrivons dans les chapitres qui suivent les principales possibilités de ce langage dans les domaines suivants :

7.2 Éditeurs

Les M-files étant des fichiers-texte, il est possible de les créer et les éditer avec n'importe quel éditeur de texte/programmation de votre choix. Idéalement, celui-ci devrait notamment offrir des fonctionnalités d'indentation automatique, de coloration syntaxique...

7.2.1 Commandes relatives à l'édition

Pour passer dans l'éditeur, depuis la fenêtre de commande MATLAB/Octave, afin de créer ou éditer un M-file :
edit M-file   ou   edit('M-file')   ou   open M-file   ou   open('M-file')
Bascule dans l'éditeur et ouvre le M-file spécifié. Si celui-ci n'existe pas, il est proposé de créer un fichier de ce nom (sauf sous MATLAB où open retourne une erreur).
Il est obligatoire de passer un nom de fichier à la commande open. S'agissant de edit, si l'on ne spécifie pas de M-file cela ouvre une fenêtre d'édition de fichier vide.

Sous MATLAB et sous Octave GUI, c'est l'éditeur intégré à ces IDE's qui est bien entendu utilisé. Si vous utilisez Octave-CLI (Octave en ligne de commande dans une fenêtre terminal), ce sera l'éditeur défini par la fonction EDITOR (voir plus bas).

Depuis les interfaces graphiques MATLAB et Octave GUI, on peut bien entendu aussi faire :

7.2.2 Éditeur/débugger intégré à MATLAB

MATLAB fournit un IDE complet comportant un éditeur (illustration ci-dessous) offrant également des possibilités de debugging.


Éditeur intégré de MATLAB R2014 (ici sous Windows)

Quelques fonctionnalités utiles de l'éditeur intégré de MATLAB :

7.2.3 Éditeurs pour GNU Octave

Éditeur/débugger intégré à Octave GUI

Avec l'arrivée de l'interface graphique Octave GUI (Octave Graphical User Interface), Octave ≥ 3.8 fournit également un IDE complet comportant un éditeur permettant de faire de la coloration syntaxique, autocomplétion, debugging (définition de breakpoints, exécution step-by-step...).


Éditeur intégré de GNU Octave 4.0 (ici sous Windows)

Quelques fonctionnalités utiles de l'éditeur intégré de Octave GUI :

Autres éditeurs pour Octave

Il est cependant possible (et nécessaire lorsqu'on utilise Octave en ligne de commande depuis une fenêtre terminal) de faire appel à d'autres éditeurs de programmation. La situation dépend du système d'exploitation (voir notre chapitre "Installation/configuration GNU Octave") : On spécifie quel éditeur doit être invoqué lorsque l'on travaille avec Octave-CLI (i.e. lorsque l'on passe la commande edit) avec la fonction built-in EDITOR('path/editeur') que l'on intègre généralement dans son prologue .octaverc
Ex: Le morceau de script multi-plateforme ci-dessous teste sur quelle plateforme on se trouve et redéfinit ici "Gedit" comme éditeur par défaut dans le cas où l'on est sous Linux :
if ~isempty(findstr(computer,'linux'))
  EDITOR('gedit')        % définition de l'éditeur par défaut
  edit('mode','async')   % passer la commande "edit" de façon détachée
else
  % on n'est pas sous Linux, ne rien faire de particulier
end

Système Éditeur conseillé Définition de l'éditeur
    (pour prologue .octaverc)
Indenter à droite,
    désindenter à gauche
Commenter,
    décommenter
Multiplateforme Atom EDITOR('atom') Edit>Lines>Indent (ou tab, ou alt-cmd-6)
Edit>Lines>Outdent (ou maj-tab, ou alt-cmd-5)
Edit>Toggle Comments (ou maj-cmd-7)
Windows Notepad++ EDITOR
('path/notepad++.exe')
Edit>Indent>Increase (ou tab)
Edit>Indent>Decrease (ou maj-tab)
Edit>Comment/Uncom.> Toggle Block Comment (ou ctrl-Q)
Linux Gedit (GNOME) EDITOR('gedit') tab

maj-tab

Edit>Comment Code (ou ctrl-M)
Edit>Uncomment Code (ou ctrl-maj-M)
(voir cependant ci-dessous)
macOS TextWrangler EDITOR('edit') Text>Shift Right (ou cmd-])
Text>Shift Left (ou cmd-[)
Il est nécessaire d'élaborer un "script TextWrangler"...



Éditeur de programmation libre Notepad++ sous Windows

Conseils relatifs à l'éditeur Gedit sous Linux

En premier lieu, enrichissez votre éditeur Gedit par un jeu de "plugins" supplémentaires déjà packagés : Activation de la coloration syntaxique : Affichage des numéros de lignes : via Edit > Preferences, puis dans l'onglet "View" activer "Display line numbers"

Pour pouvoir mettre en commentaire un ensemble de lignes sélectionnées :

Fermeture automatique des parenthèses, crochets, acollades, apostrophes ... : en activant simplement le plugin "Bracket Completion"

Affichage des caractères spéciaux tab, espace ... : en activant (et configurant) le plugin "Draw Spaces"

Pour automatiser certaines insertions (p.ex. structures de contrôles...) :

7.3 Interaction écran/clavier, warnings et erreurs

Pour être en mesure de développer des scripts MATLAB/Octave interactifs (affichage de messages, introduction de données au clavier...) et les "débugger", MATLAB et Octave offrent bon nombre de fonctionnalités utiles décrites dans ce chapitre.

7.3.1 Affichage de texte et de variables

disp(variable)
disp('chaîne')
Affiche la variable ou la chaîne de caractère spécifiée. Avec cette commande, et par oposition au fait de frapper simplement variable, seul le contenu de la variable est affiché et pas son nom. Les nombres sont formatés conformément à ce qui a été défini avec la commande format (présentée au chapitre "Fenêtre de commande").

Ex: les commandes M=[1 2;3 5] ; disp('La matrice M vaut :') , disp(M) produisent l'affichage du texte "La matrice M vaut :" sur une ligne, puis celui des valeurs de la matrice M sur les lignes suivantes

{count=} fprintf('format', variable(s)...)
{count=} printf('format', variable(s)...)
Affiche, de façon formatée, la(les) variable(s) spécifiées (et retourne facultativement le nombre count de caractères affichés). Cette fonction ainsi que la syntaxe du format, repris du langage de programmation C, sont décrits en détails au chapitre "Entrées-sorties".
L'avantage de cette méthode d'affichage, par rapport à disp, est que l'on peut afficher plusieurs variables, agir sur leur formatage (nombre de chiffres après le point décimal, justification...) et entremêler texte et variables sur la même ligne de sortie.

Ex: si l'on a les variables v=444; t='chaîne de car.';, l'instruction fprintf('variable v= %6.1f et variable t= %s \n',v,t) affiche, sur une seule ligne : "variable v= 444.0 et variable t= chaîne de car."


7.3.2 Affichage et gestion des avertissements et erreurs, beep

Les erreurs sont des évènements qui provoquent l'arrêt d'un script ou d'une fonction, avec l'affichage d'un message explicatif.
Les avertissements (warnings) consistent en l'affichage d'un message sans que le déroulement soit interrompu.

warning( {'id',} 'message')
warning( {'id',} 'format', variable(s)...)
Affiche le message spécifié sous la forme "warning: message", puis continue (par défaut) l'exécution du script ou de la fonction.
Le message peut être spécifié sous la forme d'un format (voir spécification des "Formats d'écriture" au chapitre "Entrées-sorties"), ce qui permet alors d'incorporer une(des) variable(s) dans le message !
L'identificateur id du message prend la forme composant{:composant}:mnémonique , où :
  - le premier composant spécifie p.ex. le nom du package
  - le second composant spécifie p.ex. le nom de la fonction
  - le mnémonique est une notation abrégée du message
L'identificateur id est utile pour spécifier les conditions de traitement de l'avertissement (voir ci-dessous).
Sous Octave, une description de tous les types de warnings prédéfinis est disponible avec help warning_ids
struct = warning
Passée sans paramètre, cette fonction indique de quelle façon sont traités les différents types de messages d'avertissements (warnings). Les différents états possibles sont :
    on= affichage du message d'avertissement, puis continuation de l'exécution
    off= pas d'affichage de message d'avertissement et continuation de l'exécution
    error= condition traitée comme une erreur, donc affichage du message d'avertissement puis interruption !
warning('on|off|error', 'id' )
Changement de la façon de traiter les avertissements du type id spécifié. Voir ci-dessus la signification des conditions on, off et error. On arrive ainsi à désactiver (off) certains types d'avertissements, les réactiver (on), ou même les faire traiter comme des erreurs (error) !
warning('query', 'id' )
Récupère le statut courant de traitement des warnings de type id
{string=}lastwarn
Affiche (ou récupère sur la variable string) le dernier message d'avertissement (warning)
      Ex:
X=123; S='abc'; warning('Demo:test','X= %u et chaine S= %s', X, S)
  affiche l'avertissement : 'warning: X= 123 et chaîne S= abc'
• puis si l'on fait warning('off','Demo:test')
  et que l'on exécute à nouveau le warning ci-dessus, il n'affiche plus rien
• puis si l'on fait warning('error','Demo:test')
  et que l'on exécute à nouveau le warning ci-dessus, cela affiche cette fois-ci une erreur : 'error: X vaut: 123 et la chaîne S: abc'

error('message')
error('format', variable(s)...)
Affiche le message indiqué sous la forme "error: message", puis interrompt l'exécution du script ou de la fonction dans le(la)quel(le) cette instruction a été placée, ainsi que l'exécution du script ou de la fonction appelante. Comme pour warning, le message peut être spécifié sous la forme d'un format, ce qui permet alors d'incorporer une(des) variable(s) dans le message.

Sous Octave, si l'on veut éviter qu'à la suite du message d'erreur soit affiché un "traceback" de tous les appels de fonction ayant conduit à cette erreur, il suffit de terminer la chaîne message par le caractère "newline", c'est-à-dire définir error("message... \n"). Mais comme on le voit, la chaîne doit alors être définie entre guillemets et non pas entre apostrophes, ce qui pose problème à MATLAB. Une façon de contourner ce problème pour faire du code portable pour Octave et MATLAB est de définir error(sprintf('message... \n'))

Remarque générale : Lorsque l'on programme une fonction, si l'on doit prévoir des cas d'interruption pour cause d'erreur, il est important d'utiliser error(...) et non pas disp('message'); return, afin que les scripts utilisant cette fonction puissent tester les situations d'erreur (notamment avec la structure de contrôle try...catch...end).

{string=}lasterr
Affiche (ou récupère sur la variable string) le dernier message d'erreur
beep
Émet un beep sonore

7.3.3 Entrée d'information au clavier

a) variable=input('prompt') ;
b) chaîne=input('prompt', 's') ;
MATLAB/Octave affiche le prompt ("invite") spécifié, puis attend que l'utilisateur entre quelque-chose au clavier terminé par la touche enter

a) En l'absence du paramètre 's', l'information entrée par l'utilisateur est "interprétée" (évaluée) par MATLAB/Octave, et c'est la valeur résultante qui est affectée à la variable spécifiée. L'utilisateur peut donc, dans ce cas, saisir une donnée de n'importe quel type et dimension (nombre, vecteur, matrice...) voire toute expression valide !
On peut, après cela, éventuellement détecter si l'utilisateur n'a rien introduit (au cas où il aurait uniquement frappé enter) avec : isempty(variable), ou length(variable)==0
b) Si l'on spécifie le second paramètre 's' (signifiant string), le texte entré par l'utilisateur est affecté tel quel (sans évaluation) à la variable chaîne indiquée. C'est donc cette forme-là que l'on utilise pour saisir interactivement du texte.

Dans les 2 cas, on place généralement, à la fin de cette commande, un ; pour que MATLAB/Octave "travaille silencieusement", c'est-à-dire ne quittance pas à l'écran la valeur qu'il a affectée à la variable.

      Ex:
• la commande v1=input('Entrer v1 (scalaire, vecteur, matrice, expression, etc...) : ') ; affiche "Entrer v1 (scalaire, vecteur, matrice, expression, etc...) : " puis permet de saisir interactivement la variable numérique "v1" (qui peut être de n'importe quel type/dimension)
• la commande nom=input('Entrez votre nom : ', 's') ; permet de saisir interactivement un nom (contenant même des espace...)
a) pause
b) pause(secondes)   ou   sleep(secondes)
a) Lorsque le script rencontre cette instruction sans paramètre, il effectue une pause, c'est-à-dire attend que l'utilisateur frappe n'importe quelle touche au clavier pour continuer son exécution.
b) Si une durée secondes est spécifiée, le script reprend automatiquement son exécution après cette durée.
Sous MATLAB, on peut passer la commande pause off pour désactiver les éventuelles pauses qui seraient effectuées par un script (puis pause on pour rétablir le mécanisme des pauses).

7.4 Debugging, optimisation, profiling

7.4.1 Debugging

Lorsqu'il s'agit de débuguer un script ou une fonction qui pose problème, la première idée qui vient à l'esprit est de parsemer le code d'instructions d'affichages intermédiaires. Plutôt que de faire des disp, on peut alors avantageusement utiliser la fonction warning présentée plus haut, celle-ci permettant en une seule instruction d'afficher du texte et des variables ainsi que de désactiver/réactiver aisément l'affichage de ces warnings. Mais il existe des fonctionnalités de debugging spécifiques présentées ci-après.

Commandes de debugging simples

echo   on | off
echo   on all | off all
• Active (on) ou désactive (off, c'est le cas par défaut) l'affichage/écho de toutes les commandes exécutées par les scripts
• Active (on all) ou désactive (off all, c'est le cas par défaut) l'affichage/écho de toutes les commandes exécutées par les fonctions

Petites différences de comportement entre Octave et MATLAB :
L'affichage est plus agréable dans Octave, chaque commande exécutée étant clairement identifiée par un signe + (signe que l'on peut changer avec la fonction PS4)

keyboard
keyboard('prompt ')
Placée à l'intérieur d'un M-file, cette commande invoque le mode de debugging "keyboard" de MATLAB/Octave : l'exécution du script est suspendue, et un prompt spécifique s'affiche (K>>, respectivement debug> ou le prompt spécifié). L'utilisateur peut alors travailler normalement en mode interactif dans MATLAB/Octave (visualiser ou changer des variables, passer des commandes...). Puis il a le choix de :
• continuer l'exécution du script en frappant en toutes lettres la commande return
• ou avorter la suite du script en frappant la commande dbquit sous MATLAB ou Octave
Ce mode "keyboard" permet ainsi d'analyser manuellement certaines variables en cours de déroulement d'un script.

Debugging en mode graphique

Les éditeurs/débuggers intégrés de MATLAB et de Octave GUI (depuis Octave 3.8) permettent de placer visuellement des breakpoints (points d'arrêt) dans vos scripts/fonctions, puis d'exécuter ceux-ci en mode step-by-step (instructions pas à pas). L'intérêt réside dans le fait que lorsque l'exécution est suspendue sur un breakpoint ou après un step, vous pouvez, depuis la fenêtre de console à la suite du prompt K>> ou debug>, passer interactivement toute commande MATLAB/Octave (p.ex. vérifier la valeur d'une variable, la modifier...), puis poursuivre l'exécution.

Les boutons décrits ci-dessous se cachent dans l'onglet EDITOR du bandeau MATLAB, et dans palette d'outils de l'éditeur intégré de Octave GUI.

A) Mise en place de breakpoints :

B) Puis exécution step-by-step :

Fonctions de debugging

Les fonctions ci-dessous sont implicitement appelées lorsque l'on fait du debugging en mode graphique (chapitre précédent), mais vous pouvez aussi les utiliser depuis la console MATLAB/Octave.

A) Mise en place de breakpoints :

dbstop in script|fonction at no
dbstop('script|fonction', no {, no, no...} )   ou dbstop('script|fonction', vecteur_de_nos)
Défini (ajoute), lors de l'exécution ultérieure du script ou de la fonction indiquée, des breakpoints au début des lignes de no spécifié
L'avantage, par rapport à l'instruction keyboard décrite précédemment, est qu'ici on ne "pollue" pas notre code, les breakpoints étant définis interactivement avant l'exécution
dbclear in script|fonction at no   respectivement dbclear in script|fonction
dbclear('script|fonction', no {, no, no...} )   respectivement dbclear('script|fonction')
Supprime, dans le script ou la fonction indiquée, les breakpoints précédemment définis aux lignes de no spécifié.
Dans sa seconde forme, cette instruction supprime tous les breakpoints relatif au script/fonction spécifié.
struct = dbstatus {script|fonction}
struct = dbstatus {('script|fonction')}
Affiche (ou retourne sur une structure) les vecteurs contenant les nos de ligne sur lesquels sont couramment définis des breakpoints. Si on ne précise pas de script/fonction, retourne les breakpoints de tous les scripts/fonctions
B) Puis exécution en mode step-by-step à l'aide des fonctions MATLAB/Octave suivantes : S'agissant d'exécution de scripts/fonctions imbriqués, on peut encore utiliser les commandes de debugging dbup, dbdown, dbstack...

7.4.2 Optimisation

Il existe de nombreuses techniques pour optimiser un code MATLAB/Octave en terme d'utilisation des ressources processeur et mémoire. Nous donnons ci-après quelques conseils de base. Notez cependant qu'il faut parfois faire la balance entre en optimisation et lisibilité du code.

Optimisation du temps de calcul (CPU)

Optimisation de l'utilisation mémoire (RAM)

7.4.3 Profiling

Sous le terme de "profiling" on entend l'analyse des performances d'un programme (script, fonctions) afin d'identifier les parties de code qui pourraient être optimisées dans le but d'améliorer les performances globales du programme. Les outils de profiling permettent ainsi de comptabiliser de façon fine (au niveau script, fonctions et même instructions) le temps consommé lors de l'exécution du programme, puis de présenter les résultats de cette analyse sous forme de tableaux et d'explorer ces données.

Pour déterminer le temps CPU utilisé dans certaines parties de vos scripts ou fonctions, une alternative aux outils de profiling ci-dessous serait d'ajouter manuellement dans votre code des fonctions de "timing" (chronométrage du temps consommé) décrites au chapitre "Dates et temps", sous-chapitre "Fonctions de timing et de pause".

Commandes liées au profiling

Enclencher/déclencher le processus de profiling :

profile on   ou   profile('on')
profile resume   ou   profile('resume')
Démarre le profiling, c'est-à-dire la comptabilisation du temps consommé :
• avec on : efface les données de profiling précédemment collectées
• avec resume : reprend le profiling qui a été précédemment suspendu avec profile off, sans effacer données collectées
profile off   ou   profile('off')
Interrompt ou suspend la collecte de données de profiling, afin d'en exploiter les données
stats_struct = profile('status')
Retourne la structure stats_struct dans laquelle le champ ProfilerStatus indique si le profiling est couramment activé (on) ou stoppé (off)
prof_struct = profile('info')
Récupère sur la structure prof_struct les données de profiling collectées
profile clear
Efface toutes les données de profiling collectées
Explorer sous MATLAB les données de profiling :
profile viewer   ou   profile('viewer')   ou   profview
Interrompt le profiling (effectue implicitement un profile off) et ouvre l'explorateur de profiling (le "Profiler"). Il s'agit d'une fenêtre MATLAB spécifique dans laquelle les données de profiling sont hiérarchiquement présentées sous forme HTML à l'aide de liens hyper-textes.
Examiner sous Octave les données de profiling :
profshow(prof_struct {, N })
Affiche sous forme de tableau, dans l'ordre descendant du temps consommé, les données de profiling prof_struct. On peut spécifier le nombre N de fonctions/instructions affichées. Si N n'est pas spécifié, ce sera par défaut 20.
profexplore(prof_struct)
Explore interactivement, dans la fenêtre de commande Octave, les données hiérarchiques de profiling prof_struct
help : aide en-ligne sur les commandes disponibles
opt : descend d'un niveau dans l'option opt spécifiée
up {nb_niv} : remonte d'un niveau, ou de nb_niv niveaux ; si l'on est au premier niveau, retourne au prompt Octave
exit : interrompt cette exploration interactive

Illustration par un exemple

Soit le script et les 2 fonctions suivants :

Script demo_profiling.m :
%DEMO_PROFILING   Script illustrant, par
%  profiling, l'utilité de vectoriser son code !

t0=cputime;      % compteur temps CPU consommé

% Génération matrice aléatoire
nb_l = 1000;
nb_c =  500;
v_min = -10 ;
v_max =  30 ;
mat = matrice_alea(nb_l, nb_c, v_min, v_max) ;

% Extraction de certains éléments de mat
vmin =  0 ;
vmax = 20 ;
vec = extrait_matrice(mat, vmin, vmax) ;

% Calcul de la moyenne des éléments extraits
if CODE_VECTORISE  % Code vectorisé  :-)
  moyenne_vect = mean(vec) ;
else               % Code non vectorisé  :-(
  somme_elem = 0 ;
  for indice=1:length(vec)
    somme_elem = somme_elem + vec(indice) ;
  end
  moyenne_vect = somme_elem / length(vec) ;
end

% Affichages...
moyenne_vect
duree_calcul=cputime-t0
Fonction matrice_alea.m :
function [matrice]=matrice_alea(nb_l,nb_c,v_min,v_max)
% MATRICE_ALEA(NB_L, NB_C, V_MIN, V_MAX)
%   Generation matrice de dimension (NB_L, NB_C)
%   de nb aleatoires compris entre V_MIN et V_MAX

  global CODE_VECTORISE
  v_range = v_max - v_min ;
  
  if CODE_VECTORISE  % Code vectorisé  :-)
    matrice = (rand(nb_l, nb_c) * v_range) + v_min ;
  
  else               % Code non vectorisé  :-(
    for lig=1:nb_l
      for col=1:nb_c
        matrice(lig,col) = (rand()*v_range) + v_min ;
      end
    end
  end
return
Fonction extrait_matrice.m :
function [vecteur] = extrait_matrice(mat, vmin, vmax)
% EXTRAIT_MATRICE(MAT, VMIN, VMAX)
%   Extrait de la matrice MAT, parcourue col. apres
%   colonne, tous les elements dont la val. est
%   comprise entre VMIN et VMAX, et les retourne
%   sur un vecteur colonne

  global CODE_VECTORISE

  if CODE_VECTORISE  % Code vectorisé (index. logique) :-)
    vecteur=mat(mat>=vmin & mat<=vmax);
  
  else               % Code non vectorisé  :-(
    indice = 1;
    for col=1:size(mat,2)
      for lig=1:size(mat,1)
        if (mat(lig,col) >= vmin) && (mat(lig,col) <= vmax)
          vecteur(indice) = mat(lig,col) ;
          indice = indice + 1 ;
        end
      end
    end
    vecteur = vecteur' ;
  end
return

Vous constatez que, pour les besoins de l'exemple, ces codes comportent du code vectorisé (usage de fonctions vectorisées, indexation logique...) et du code non vectorisé (usage de boucles for/end). Nous avons délimité ces deux catégories de codes par des structures if/else/end s'appuyant sur une variable globale nommée CODE_VECTORISE.

Réalisons maintenant le profiling de ce code. En premier lieu, il faut rendre globale au niveau workspace et du script la variable CODE_VECTORISE (ceci est déjà fait dans les fonctions), avec l'instruction :

Les durées d'exécution indiquées ci-dessous se rapportent à une machine Intel Pentium Core 2 Duo E6850 @ 3 GHz avec MATLAB R2012 et GNU Octave 3.6.2 MinGW.

Commençons par l'examen du code non vectorisé :

  1. CODE_VECTORISE=false; % on choisit donc d'utiliser ici le code non vectorisé
  2. profile on % démarrage du profiling
  3.     profile status % contrôle du statut du profiling (il est bien à on)
  4. demo_profiling % exécution de notre script
  5. profile off % interruption de la collecte de données de profiling
  6.     profile status % contrôle du statut du profiling (il est bien à off)

  7. Sous MATLAB :
      profile viewer % ouverture de l'explorateur de profiling
      Constatations :
      - le script s'est exécuté en 9 sec sous Linux/Ubuntu, et étonnamment en 1 sec sous Windows !
      - le profiler de cette version MATLAB sous Linux/Ubuntu donne des timing erronés, et l'exploitation des hyper-liens est impossible (retourne des erreurs) !

  8. Sous Octave :
      prof_struct=profile('info'); % récupération des données de profiling
      profshow(prof_struct) % affichage tabulaire des 20 plus importants données (en temps) de profiling
      profexplore(prof_struct) % exploration interactive des données de profiling ; "descendre" ensuite avec 1 dans "demo_profiling", puis dans les fonctions "matrice_alea" et "extrait_matrice" ...
      Constatations :
      - le script s'est exécuté en 14 sec sous Linux, et en 23 sec sous Windows
      - sous Windows p.ex. 12 sec sont consommées par la fonction "matrice_alea" (dont 4.5 sec par la fonction "rand"), 9 sec par la fonction "extrait_matrice"
      - on constate notamment que la fonction "rand" est appelée 500'000x
      - on voit donc ce qu'il y a lieu d'optimiser...
Essayez de relancer ce script sans profiling. Vous constaterez qu'il s'exécute un peu plus rapidement, ce qui montre que le profiling lui-même consomme du temps CPU, et donc qu'il ne faut l'activer que si l'objectif est bien de collecter des données de performance !

Poursuivons maintenant avec l'examen du code vectorisé (remplacement des boucles par des fonctions vectorisées et l'indexation logique) :

  1. CODE_VECTORISE=true; % on choisit donc d'utiliser ici le code vectorisé
  2. profile on % démarrage du profiling
  3. demo_profiling % exécution de notre script
  4. profile off % interruption de la collecte de données de profiling

  5. Sous MATLAB :
      profile viewer % ouverture de l'explorateur de profiling
      Constatations :
      - le script s'est exécuté en 0.1 sec sous Linux/Ubuntu et sous Windows !
      - on a donc gagné d'un facteur de plus de 100x par rapport à la version non vectorisée !

  6. Sous Octave :
      prof_struct=profile('info'); % récupération des données de profiling
      profshow(prof_struct) % affichage tabulaire des 20 plus importants données (en temps) de profiling
      profexplore(prof_struct) % exploration interactive des données de profiling...
      Constatations :
      - le script s'est exécuté en 0.1 sec sous Windows, et 0.05 sec sous Linux/Ubuntu !
      - on a donc gagné d'un facteur de plus de 200x par rapport à la version non vectorisée !

7.5 Structures de contrôle

Les "structures de contrôle" sont, dans un langage de programmation, des constructions permettant d'exécuter des blocs d'instructions de façon itérative (boucle) ou sous condition (test). MATLAB/Octave offre les structures de contrôle de base typiques présentées dans le tableau ci-dessous et qui peuvent bien évidemment être "emboîtées" les unes dans les autres. Notez que la syntaxe est différente des structures analogues dans d'autres langages (C, Java, Python).

Comme MATLAB/Octave permet de travailler en "format libre" (les caractères espace et tab ne sont pas significatifs), on recommande aux programmeurs MATLAB/Octave de bien "indenter" leur code, lorsqu'ils utilisent des structures de contrôle, afin de faciliter la lisibilité et la maintenance du programme.

Octave propose aussi des variations aux syntaxes présentées plus bas, notamment : endfor, endwhile, endif, endswitch, end_try_catch, ainsi que d'autres structures telles que:
      unwind_protect body... unwind_protect_cleanup cleanup... end_unwind_protect
Nous vous recommandons de vous en passer pour que votre code reste portable !

Structure Description
Boucle for...end

for var = tableau
   instructions...
end
Considérons d'abord le cas général où tableau est une matrice 2D (de nombres, de caractères, ou cellulaire... peu importe). Dans ce cas, l'instruction for parcourt les différentes colonnes de la matrice (c'est-à-dire matrice(:,i)) qu'il affecte à la variable var qui sera ici un vecteur colonne. À chaque "itération" de la boucle, la colonne suivante de matrice est donc affectée à var, et le bloc d'instructions est exécuté.

Si tableau est un vecteur, ce n'est qu'un cas particulier :
• dans le cas où c'est un vecteur ligne (p.ex. une série), la variable var sera un scalaire recevant à chaque itération l'élément suivant de ce vecteur
• si c'est un vecteur colonne, la variable var sera aussi un vecteur colonne qui recevra en une fois toutes les valeurs de ce vecteur, et le bloc d'instructions ne sera ainsi exécuté qu'une seule fois puis on sortira directement de la boucle !

Si l'on a tableau à 3 dimensions, for examinera d'abord les colonnes de la 1ère "couche" du tableau, puis celles de la seconde "couche", etc...

Ex:

  • for n=10:-2:0 , n^2, end affiche successivement les valeurs 100 64 36 16 4 et 0
  • for n=[1 5 2;4 4 4] , n, end affiche successivement les colonnes [1;4] [5;4] et [2;4]
Boucle parfor...end

parfor (var=deb:fin {, max_threads})
   instructions...
end
Variante simplifiée mais parallélisée de la boucle for...end :
• le bloc d'instructions est exécuté en parallèle par différents threads (au maximum max_threads) et l'ordre d'itération n'est pas garanti
deb et fin doivent être des entiers, et fin > deb
Boucle while...end
("tant que" la condition n'est pas fausse)

while expression_logique
   instructions...
end
Si tous les éléments de l'objet résultant de l'expression_logique (qui n'est donc pas nécessairement scalaire mais peut être un tableau de dimension quelconque) sont Vrais (c'est-à-dire différents de "0"), l'ensemble d'instructions spécifiées est exécuté, puis l'on reboucle sur le test. Si un ou plusieurs éléments sont Faux (c'est-à-dire égaux à "0"), on saute aux instructions situées après le end.
On modifie en général, dans la boucle, des variables constituant l'expression_logique, sinon la boucle s'exécutera sans fin (et on ne peut dans ce cas en sortir qu'avec un ctrl-C !)
Ex:
  • n=1 ; while (n^2 < 100) , disp(n^2) , n=n+1 ; end affiche les valeurs n^2 depuis n=1 et tant que n^2 est inférieur à 100, donc affiche les valeurs 1 4 9 16 25 36 49 64 81 puis s'arrête
Boucle do...until
("jusqu'à ce que" une condition se vérifie)

do
   instructions...
until expression_logique
Spécifique à Octave, cette structure de contrôle classique permet d'exécuter des instructions en boucle jusqu'à ce qu'une expression_logique soit vraie.

La différence essentielle par rapport à la boucle while est que l'on vérifie la condition après avoir une fois (au moins) exécuté le bloc d'instructions. Pour atteindre le même but sous MATLAB, on pourrait faire une boucle sans fin de type while true instructions... end à l'intérieur de laquelle on sortirait par un test et l'instruction break (voir plus bas).

Test if...{{elseif...}else...}end
("si, sinon si, sinon")

  if expression_logique_1
     instructions_1...      
{ elseif expression_logique_i
     instructions_i...      }
{ else
     autres_instructions... }
  end
Si tous les éléments résultant de l'expression_logique_1 (qui n'est donc pas nécessairement un scalaire mais peut être un tableau) sont Vrais (c'est-à-dire différents de "0"), le bloc instructions_1 est exécuté, puis on saute directement au end.
Sinon (si un ou plusieurs éléments de expression_logique_1 sont Faux, c'est-à-dire égaux à "0"), MATLAB/Octave examine les éventuelles clauses elseif (de d'autres expression_logique_i, avec exécution le cas échéant du bloc instructions_i correspondant, puis saute à end).
Si aucune expression testée n'a été satisfaite, on saute à l'éventuelle instruction else pour exécuter le bloc autres_instructions.
Noter que les blocs elseif ainsi que le bloc else sont donc facultatifs.

Ex:

  • Soit le bloc d'instructions if n==1, disp('un'), elseif n==2, disp('deux'), else, disp('autre'), end. Si l'on affecte n=1, l'exécution de ces instructions affiche "un", si l'on affecte n=2 il affiche "deux", et si "n" est autre que 1 ou 2 il affiche "autre"
Construction switch...case...{otherwise...}end

switch variable
   case val1
      instructions_a...
   case {val2, val3 ...}
      instructions_b...
   otherwise
      autres_instructions...
end
Cette construction réalise ce qui suit : si la variable spécifiée est égale à la valeur val1, seul le bloc de instructions_a spécifié est exécuté ; si elle est égale à la valeur val2 ou val3, seul le bloc de instructions_b spécifié est exécuté. Et ainsi de suite... Si elle n'est égale à rien de tout ça, c'est le bloc des autres_instructions spécifiées qui est exécuté.
Important : notez bien que si, dans une clause case, vous définissez plusieurs valeurs val possibles, il faut que celles-ci soient définies sous la forme de tableau cellulaire, c'est-à-dire entre caractères { }.
Contrairement au "switch" du langage C, il n'est pas nécessaire de définir des break à la fin de chaque bloc
On peut avoir autant de blocs case que l'on veut, et la partie otherwise est facultative.
En lieu et place de variable et de val1, val2... on peut bien entendu aussi mettre des expressions.

Ex:

  • Tester d'une réponse rep contenant : Non, non, No, no, N, n, Oui, oui, O, o, Yes, yes, Y, y :
    switch lower(rep(1))
        case 'n'
            disp('non')
        case { 'o' 'y' }
            disp('oui')
        otherwise
            disp('reponse incorrecte')
    end
  • L'exemple précédent réalisé avec if-elseif-else pourrait être ainsi reprogrammé avec une structure switch-case : switch n, case 1, disp('un'), case 2, disp('deux'), otherwise, disp('autre'), end
Construction try...catch...end

try
   instructions_1...
catch
   instructions_2...
end
autres_instructions...
Cette construction sert à implémenter des traitements d'erreur.

Les instructions comprises entre try et catch (bloc instructions_1) sont exécutées jusqu'à ce qu'une erreur se produise, auquel cas MATLAB/Octave passe automatiquement à l'exécution des instructions comprises entre catch et end (bloc instructions_2). Le message d'erreur ne s'affiche pas mais peut être récupéré avec la commande lasterr.

Si le premier bloc de instructions_1 s'exécute absolument sans erreur, le second bloc de instructions_2 n'est pas exécuté, et le déroulement se poursuit avec autres_instructions

Sortie anticipée d'une boucle

break

A l'intérieur d'une boucle for, while ou do, cette instruction permet, par exemple suite à un test, de sortir prématurément de la boucle et de poursuivre l'exécution des instructions situées après la boucle. Si 2 boucles sont imbriquées l'une dans l'autre, un break placé dans la boucle interne sort de celle-ci et continue l'exécution dans la boucle externe.
A ne pas confondre avec return (voir plus bas) qui sort d'une fonction, respectivement interrompt un script !

Ex: sortie d'une boucle for :

for k=1:100
  k2=k^2;
  fprintf('carré de %3d = %5d \n',k,k2)
  if k2 > 200 break, end  % sortir boucle lorsque k^2 > 200
end
fprintf('\nsorti de la boucle à k = %d\n',k)

Ex: sortie d'une boucle while :

k=1;
while true    % à priori boucle sans fin !
  fprintf('carré de %3d = %5d \n', k, k^2)
  if k >= 10 break, else k=k+1; end
  % ici on sort lorsque k > 10
end
Sauter le reste des instructions d'une boucle et continuer d'itérer

continue

A l'intérieur d'une boucle (for ou while), cette instruction permet donc, par exemple suite à un test, de sauter le reste des instructions de la boucle et passer à l'itération suivante de la même boucle.

Ex:

start=1; stop=100; fact=8;
fprintf('Nb entre %u et %u divisibles par %u : ',start,stop,fact)

for k=start:1:stop
  if rem(k,fact) ~= 0
    continue
  end
  fprintf('%u, ', k)
end

disp('fin')
Le code ci-dessus affiche: "Nb entre 1 et 100 divisibles par 8 : 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, fin"
double(var) Cette instruction permet de convertir en double précision la variable var qui, dans certaines constructions for, while, if, peut n'être qu'en simple précision



Les structures de contrôle sont donc des éléments de langage extrêmement utiles. Mais dans MATLAB/Octave, il faut "penser instructions matricielles" (on dit aussi parfois "vectoriser" son algorithme) avant d'utiliser à toutes les sauces ces structures de contrôle qui, du fait que MATLAB est un langage interprété, sont beaucoup moins rapides que les opérateurs et fonctions matriciels de base !

Ex: l'instruction y=sqrt(1:100000); est beaucoup plus efficace/rapide que la boucle for n=1:100000, y(n)=sqrt(n); end (bien que, dans les 2 cas, ce soit un vecteur de 100'000 éléments qui est créé contenant les valeurs de la racine de 1 jusqu'à la racine de 100'000). Testez vous-même !

7.6 Autres commandes et fonctions utiles en programmation

Nous énumérons encore ici quelques commandes ou fonctions supplémentaires qui peuvent être utiles dans la programmation de scripts ou de fonctions.

return
Termine l'exécution de la fonction ou du script. Un script ou une fonction peut renfermer plusieurs return (sorties contrôlées par des structures de contrôle...). Une autre façon de sortir proprement en cas d'erreur est d'utiliser la fonction error (voir plus haut).
On ne sortira jamais avec exit ou quit qui non seulement terminerait le script ou la fonction mais fermerait aussi la session MATLAB/Octave !
var= nargin
A l'intérieur d'une fonction, retourne le nombre d'arguments d'entrée passés lors de l'appel à cette fonction. Permet par exemple de donner des valeurs par défaut aux paramètres d'entrée manquant.
Utile sous Octave pour tester si le nombre de paramètres passés par l'utilisateur à la fonction est bien celui attendu par la fonction (ce test n'étant pas nécessaire sous MATLAB ou le non respect de cette condition est automatiquement détecté).
Voir aussi la fonction nargchk qui permet aussi l'implémentation simple d'un message d'erreur.

Ex: voir ci-après

varargin
A l'intérieur d'une fonction, tableau cellulaire permettant de récupérer un nombre d'arguments quelconque passé à la fonction

Ex: soit la fonction test_vararg.m suivante :

function []=test_vararg(varargin)
fprintf('Nombre d''arguments passes a la fonction : %d \n',nargin)
for no_argin=1:nargin
  fprintf('- argument %d:\n', no_argin)
  disp( varargin{no_argin} )
end
        si on l'invoque avec test_vararg(111,[22 33;44 55],'hello !',{'ca va ?'}) elle retourne :
Nombre d'arguments passes a la fonction : 4 
- argument 1:
   111
- argument 2:
   22   33
   44   55
- argument 3:
   hello !
- argument 4:
   { [1,1] = ca va ? }
string= inputname(k)
A l'intérieur d'une fonction, retourne le nom de variable du k-ème argument passé à la fonction
var= nargout
A l'intérieur d'une fonction, retourne le nombre de variables de sortie auxquelles la fonction est affectée lors de l'appel. Permet par exemple d'éviter de calculer les paramètres de sortie manquants....
Voir aussi la fonction nargoutchk qui permet aussi l'implémentation simple d'un message d'erreur.

Ex: A l'intérieur d'une fonction-utilisateur mafonction :
  • lorsqu'on l'appelle avec mafonction(...) : nargout vaudra 0
  • lorsqu'on l'appelle avec out1 = mafonction(...) : nargout vaudra 1
  • lorsqu'on l'appelle avec [out1 out2] = mafonction(...) : nargout vaudra 2, etc...

string= mfilename
A l'intérieur d'une fonction ou d'un script, retourne le nom du M-file de cette fonction ou script, sans son extension .m

Ex d'instruction dans une fonction : warning(['La fonction ' mfilename ' attend au moins un argument'])

global variable(s)
Définit la(les) variable(s) spécifiée(s) comme globale(s). Cela peut être utile lorsque l'on veut partager des données entre le workspace et certaines fonctions sans devoir passer ces données en paramètre lors de l'appel à ces fonctions. Il est alors nécessaire de déclarer ces variables globales, avant de les utiliser, à la fois dans le workspace et à l'intérieur des fonctions.
Une bonne habitude serait d'identifier clairement les variables globales de fonctions, par exemple en leur donnant un nom en caractères majuscules.

Ex : la fonction fct1.m ci-dessous mémorise (et affiche) le nombre de fois qu'elle a été appelée :

function []=fct1()
global COMPTEUR
COMPTEUR=COMPTEUR+1;
fprintf('fonction appelee %04u fois \n',COMPTEUR)
return
Pour tester cela, il faut passer les instructions suivantes dans la fenêtre de commande MATLAB/Octave :
global COMPTEUR   % cela déclare le compteur également global dans le workspace
COMPTEUR = 0 ;    % initialisation du compteur
fct1              % => cela affiche "fonction appelee   1 fois"
fct1              % => cela affiche "fonction appelee   2 fois"
persistent variable(s)
Utilisable dans les fonctions seulement, cette déclaration définit la(les) variable(s) spécifiée(s) comme statique(s), c'est-à-dire conservant de façon interne leurs dernières valeurs entre chaque appel à la fonction. Ces variables ne sont cependant pas visibles en-dehors de la fonction (par opposition aux variables globales).

Ex : la fonction fct2.m ci-dessous mémorise (et affiche) le nombre de fois qu'elle a été appelée. Contrairement à l'exemple de la fonction fct1.m ci-dessus, la variable compteur n'a pas à être déclarée dans la session principale (ou dans le script depuis lequel on appelle cette fonction), et le compteur doit ici être initialisé dans la fonction.

function []=fct2()
persistent compteur
% au premier appel, après cette déclaration persistent compteur existe et vaut []
if isempty(compteur)
  compteur=0 ;
end
compteur=compteur+1 ;
fprintf('fonction appelee %04u fois \n',compteur)
return
Pour tester cela, il suffit de passer les instructions suivantes dans la fenêtre de commande MATLAB/Octave :
fct2              % => cela affiche "fonction appelee   1 fois"
fct2              % => cela affiche "fonction appelee   2 fois"
eval('expression1', {'expression2'})
Évalue et exécute l'expression1 MATLAB/Octave spécifiée. En cas d'échec, évalue l'expression2.

Ex: le petit script suivant permet de grapher n'importe quelle fonction y=f(x) définie interactivement par l'utilisateur :

fonction = input('Quelle fonction y=fct(x) voulez-vous grapher : ','s');
min_max  = input('Indiquez [xmin xmax] : ');
x = linspace(min_max(1),min_max(2),100);
eval(fonction,'error(''fonction incorrecte'')');
plot(x,y)
class(objet)
Retourne la "classe" de objet (double, struct, cell, char).
typeinfo(objet)
Sous Octave seulement, retourne le "type" de objet (scalar, range, matrix, struct, cell, list, bool, sq_string, char matrix, file...).

7.7 Scripts (programmes), mode batch

7.7.1 Principes de base relatifs aux scripts

Un "script" ou "programme" MATLAB/Octave n'est rien d'autre qu'une suite de commandes MATLAB/Octave valides (par exemple un "algorithme" exprimé en langage MATLAB/Octave) sauvegardées dans un M-file, c'est-à-dire un fichier avec l'extension .m.

Par opposition aux "fonctions" (voir chapitre suivant), les scripts sont invoqués par l'utilisateur sans passer d'arguments, car ils opèrent directement dans le workspace principal. Un script peut donc lire et modifier des variables préalablement définies (que ce soit interactivement ou via un autre script), ainsi que créer de nouvelles variables qui seront accessibles dans le workspace (et à d'autres scripts) une fois le script exécuté.

Il est important de noter qu'il n'est pas possible de définir de fonctions à l'intérieur d'un script (même si l'on ne souhaite utiliser celles-ci que par le script).

Il est possible (et vivement conseillé) de documenter le fonctionnement du script vis-à-vis du système d'aide en ligne help de MATLAB/Octave. Il suffit, pour cela, de définir, au tout début du script, des lignes de commentaire (lignes débutant par le caractère %). La commande help M-file affichera alors automatiquement le 1er bloc de lignes de commentaire contiguës du M-file. On veillera à ce que la toute première ligne de commentaire (appelée "H1-line") indique le nom du script (en majuscules) et précise brièvement ce que fait le script, étant donné que c'est cette ligne qui est affichée lorsque l'on fait une recherche de type lookfor mot-clé.

Pour exécuter un script, on peut utiliser l'une des méthodes suivantes, selon que l'on soit dans l'éditeur intégré, dans la console MATALAB/Octave ou depuis un autre script :

a) Run, Save File and Run ou F5
b) script enter
c) run('{chemin/}script{.m}') ou run {chemin/}script{.m}
d) source('{chemin/}script.m') ou source {chemin/}script.m

a) Lancement de l'exécution depuis l'éditeur intégré MATLAB ou Octave GUI
b) Le script doit obligatoirement se trouver dans le répertoire courant ou dans le path de recherche MATLAB/Octave (voir chapitre "Environnement"). Il ne faut pas spécifier l'extension .m du script
c) Cette forme permet d'exécuter un script situé en dehors du répertoire courant en indiquant le chemin d'accès (absolu ou relatif). On peut omettre ou spécifier l'extension .m du script
d) Cette forme est propre à Octave. Dans ce cas l'extension .m doit obligatoirement être indiquée

En phase de debugging, on peut activer l'affichage des commandes exécutées par le script en passant la commande echo on avant de lancer le script, puis désactiver ce "traçage" avec echo off une fois le script terminé.


Exemple de script: Le petit programme ci-dessous réalise la somme et le produit de 2 nombres, vecteurs ou matrices (de même dimension) demandés interactivement. Notez bien la 1ère ligne de commentaire (H1-line) et les 2 lignes qui suivent fournissant le texte pour l'aide en-ligne. On exécute ce programme en frappant somprod (puis répondre aux questions interactives...), ou l'on obtient de l'aide sur ce script en frappant help somprod.

%SOMPROD Script réalisant la somme et le produit de 2 nombres, vecteurs ou matrices
%
% Ce script est interactif, c'est-à-dire qu'il demande interactivement les 2 nombres,
% vecteurs ou matrices dont il faut faire la somme et le produit (élément par élément)

V1=input('Entrer 1er nombre (ou expression, vecteur ou matrice) : ') ;
V2=input('Entrer 2e  nombre (ou expression, vecteur ou matrice) : ') ;

if ~ isequal(size(V1),size(V2))
  error('les 2 arguments n''ont pas la meme dimension')
end

%{
  1ère façon d'afficher les résultats (la plus propre au niveau affichage,
  mais ne convenant que si V1 et V2 sont des scalaires) :
      fprintf('Somme = %6.1f  Produit = %6.1f \n', V1+V2, V1.*V2)

  2ème façon d'afficher les résultats :
      Somme = V1+V2
      Produit = V1.*V2
%}

% 3ème façon (basique) d'afficher les résultats
     disp('Somme =') ,   disp(V1+V2)
     disp('Produit =') , disp(V1.*V2)

return  % Sortie du script (instruction ici pas vraiment nécessaire,
        %                   vu qu'on a atteint la fin du script !)

7.7.2 Exécuter un script en mode batch

Pour autant qu'il ne soit pas interactif, on peut exécuter un script depuis un shell (dans fenêtre de commande du système d'exploitation) ou en mode batch (p.ex. environnement GRID), c'est-à-dire sans devoir démarrer l'interface-utilisateur MATLAB/Octave, de la façon décrite ici.

Avec MATLAB :


Avec Octave :


En outre avec Octave, si vous ne désirez exécuter en "batch" que quelques commandes sans faire de script, vous pouvez procéder ainsi :


7.7.3 Tester si un script s'exécute sous MATLAB ou sous Octave

Étant donné les différences qui peuvent exister entre MATLAB et Octave (p.ex. fonctions implémentées différemment ou non disponibles...), si l'on souhaite réaliser des scripts portables (i.e. qui tournent à la fois sous MATLAB et Octave, ce qui est conseillé !) on peut implémenter du code conditionnel relatif à chacun de ces environnements en réalisant, par exemple, un test via une fonction built-in appropriée.

Ex: on test ici l'existence de la fonction built-in OCTAVE_VERSION (n'existant que sous Octave) :

  if ~ exist('OCTAVE_VERSION')  % MATLAB
    % ici instruction(s) pour MATLAB
  else                          % Octave
    % ici instruction(s) équivalente(s) pour Octave
  end

7.8 Fonctions, P-Code

7.8.1 Principes de base relatifs aux fonctions

Également programmées sous forme de M-files, les "fonctions" MATLAB se distinguent des "scripts" par leur mode d'invocation qui est fondamentalement différent :
        variable(s)_de_sortie = nom_fonction(argument(s)_d_entree, ...)

Le mécanisme de passage des paramètres à la fonction se fait "par valeur" (c'est-à-dire copie) et non pas "par référence". La fonction ne peut donc pas modifier les variables d'entrée au niveau du script appelant ou du workspace principal.

Les variables créées à l'intérieur de la fonction sont dites "locales" car elles sont, par défaut, inaccessibles en dehors de la fonction (que ce soit dans le workspace principal ou dans d'autres fonctions ou scripts). Chaque fonction travaille donc dans son propre workspace local.

Contrairement aux scripts dans lesquels on n'a pas le droit de définir de fonctions internes, il est possible, dans un M-file de fonction, de définir plusieurs fonctions à la suite les unes des autres. Cependant seule la première fonction du M-file, appelée fonction principale (main function), sera accessible de l'extérieur. Les autres, appelées fonctions locales (ou subfunctions), ne pourront être appelées que par la fonction principale ou les autres fonctions locales du M-file.

Il est finalement possible de définir des fonctions à l'intérieur du corps d'une fonction. Ces fonctions imbriquées (nested function) ne pourront cependant être invoquées que depuis la fonction dans laquelle elles sont définies.


Toute fonction débute par une ligne de déclaration de fonction qui définit son nom_fonction et ses arguments args_entree et args_sortie (séparés par des virgules), selon la syntaxe :

      function [argument(s)_de_sortie, ...] = nom_fonction(argument(s)_d_entree, ...)
      (les crochets ne sont pas obligatoires s'il n'y a qu'un arg_sortie)

Octave affiche un warning si le nom de la fonction principale (tel que défini dans la 1ère déclaration de fonction) est différent du nom du M-file. Sous MATLAB, le fait que les 2 noms soient identiques n'est pas obligatoire mais fait partie des règles de bonne pratique.

Se succèdent donc, dans le code d'une fonction (et dans cet ordre) :

  1. déclaration de la fonction principale (ligne function... décrite ci-dessus)
  2. lignes de commentaires (commençant par le caractère %) décrivant la fonction pour le système d'aide en-ligne, à savoir :
    • la "H1-line" précisant le nom de la fonction et indiquant des mots-clé (ligne qui sera retournée par la commande lookfor mot-clé)
    • les lignes du texte d'aide (qui seront affichées par la commande help nom_fonction)
  3. déclarations d'éventuelles variables globale ou statique
  4. code proprement dit de la fonction (qui va affecter les variables argument(s)_de_sortie)
  5. éventuelle(s) instruction(s) return définissant de(s) point(s) de sortie de la fonction
  6. instruction end signalant la fin de la fonction
L'instruction end peut être omise, sauf lorsque l'on définit plusieurs fonctions dans un même M-file. Les templates de fonctions Octave se terminent par endfunction, mais nous vous suggérons d'éliminer cette instruction afin que vos fonctions soient compatibles à la fois pour MATLAB et Octave.


Exemple de fonction: On présente, ci-dessous, deux façons de réaliser une petite fonction retournant le produit et la somme de 2 nombres, vecteurs ou matrices. Dans les deux cas, le M-file doit être nommé fsomprod.m (c'est-à-dire identique au nom de la fonction). On peut accéder à l'aide de la fonction avec help fsomprod, et on affiche la première ligne d'aide en effectuant par exemple une recherche lookfor produit. Dans ces 2 exemples, mis à part les arrêts en cas d'erreurs (instructions error), la sortie s'effectue à la fin du code mais aurait pu intervenir ailleurs (instructions return) !

Fonction Appel de la fonction
function [resultat]=fsomprod(a,b)
%FSOMPROD somme et produit de 2 nombres ou vecteurs-ligne
%   Usage: R=FSOMPROD(V1,V2)
%      Retourne matrice R contenant: en 1ère ligne la
%      somme de V1 et V2, en seconde ligne le produit de
%      V1 et V2 élément par élément

if nargin~=2
   error('cette fonction attend 2 arguments')
end

sa=size(a); sb=size(b);
if ~ isequal(sa,sb)
  error('les 2 arguments n'ont pas la même dimension')
end
if sa(1)~=1 || sb(1)~=1
  error('les arg. doivent être scalaires ou vecteurs-ligne')
end

resultat(1,:)=a+b;   % 1ère ligne de la matrice-résultat
resultat(2,:)=a.*b;  % 2ème ligne de la matrice-résultat,
                     %      produit élément par élément !
return     % sortie de la fonction (instruction ici pas
           % nécessaire vu qu'on a atteint fin fonction)
end  % pas nécessaire si le fichier ne contient que cette fct
Remarque : cette façon de retourner le résultat (sur une seule variable) ne permet pas de passer à cette fonction des matrices.

r=fsomprod(4,5)
retourne la vecteur-colonne r=[9 ; 20]

r=fsomprod([2 3 1],[1 2 2])
retourne la matrice r=[3 5 3 ; 2 6 2]

function [somme,produit]=fsomprod(a,b)
%FSOMPROD somme et produit de 2 nombres, vecteurs ou matrices
%   Usage: [S,P]=FSOMPROD(V1,V2)
%      Retourne matrice S contenant la somme de V1 et V2,
%      et matrice P contenant le produit de V1 et V2
%      élément par élément

if nargin~=2
   error('cette fonction attend 2 arguments')
end
if ~ isequal(size(a),size(b))
  error('les 2 arg. n'ont pas la même dimension')
end

somme=a+b;
produit=a.*b;  % produit élément par élément !
return         % sortie de la fonction (instruction ici pas
               % nécessaire vu qu'on a atteint fin fonction)
end  % pas nécessaire si le fichier ne contient que cette fct
Remarque : cette façon de retourner le résultat (sur deux variable) rend possible le passage de matrices à cette fonction !

[s,p]=fsomprod(4,5)
retourne les scalaires s=9 et p=20

[s,p]=fsomprod([2 3;1 2],[1 2; 3 3])
retourne les matrices s=[3 5 ; 4 5] et p=[2 6 ; 3 6]

7.8.2 P-Code

Lorsque du code MATLAB est exécuté, il est automatiquement interprété et traduit ("parsing") dans un langage de plus bas niveau qui s'appelle le P-Code (pseudo-code). Sous MATLAB seulement, s'agissant d'une fonction souvent utilisée, on peut éviter que cette "passe de traduction" soit effectuée lors de chaque appel en sauvegardant le P-Code sur un fichier avec la commande pcode nom_fonction. Un fichier de nom nom_fonction.p est alors déposé dans le répertoire courant (ou dans le dossier où se trouve le M-file si l'on ajoute à la commande pcode le paramètre -inplace), et à chaque appel la fonction pourra être directement exécutée sur la base du P-Code de ce fichier sans traduction préalable, ce qui peut apporter des gains de performance.

Le mécanisme de conversion d'une fonction ou d'un script en P-Code offre également la possibilité de distribuer ceux-ci à d'autres personnes sous forme binaire en conservant la maîtrise du code source.

7.9 Entrées-sorties formatées, manipulation de fichiers

Lorsqu'il s'agit de charger, dans MATLAB/Octave, une matrice à partir de données externes stockées dans un fichier-texte, les commandes load -ascii et dlmread/dlmwrite, présentées au chapitre "Workspace MATLAB/Octave", sont suffisantes. Mais lorsque les données à importer sont dans un format plus complexe ou qu'il s'agit d'importer du texte ou d'exporter des données vers d'autres logiciels, les fonctions présentées ci-dessous s'avèrent nécessaires.

7.9.1 Vue d'ensemble des fonctions d'entrée/sortie de base

Le tableau ci-dessous donne une vision synthétique des principales fonctions d'entrée/sortie (présentées en détail dans les chapitres qui suivent). Notez que :

  Écriture Lecture
Interactivement Écriture à l'écran (sortie standard)
• non formaté: disp(variable|chaîne)
  (avec un seul paramètre !)
• formaté: fprintf(format, variable(s))
  (ou printf...)
Lecture au clavier (entrée standard)
• non formaté:   var = input(prompt {, 's'} )

• formaté:   var = scanf(format)
Sur chaîne de caractères string = sprintf(format, variable(s))

• autres fonctions : mat2str ...
var|mat = sscanf(string, format {,size})

• autres fonctions : strread, textscan ...
Sur fichier texte fprintf(file_id, format, variable(s)... )

• autres fonctions : save -ascii, dlmwrite ...
var = fscanf(file_id, format {,size})
line = fgetl(file_id)
string = fgets(file_id {,nb_car})

• autres fonctions : load(fichier), textread, textscan, fileread, dlmread ...
Via internet
(protocoles HTTTP, FTP ou FILE)
string = urlread(url, method, param)
urlwrite(url, fichier, method, param)
  (pour url de type HTTP, method : 'get' ou 'post')
string = urlread(url)
urlwrite(url, fichier)
Sur fichier binaire • autres fonctions : fwrite, xlswrite ... • autres fonctions : fread, xlsread ...



7.9.2 Formats de lecture/écriture

Les différentes fonctions de lecture/écriture sous forme texte présentées ci-dessous font appel à des "formats" (parfois appelés "templates" dans la documentation). Le but de ceux-ci est de :

Les formats MATLAB/Octave utilisent un sous-ensemble des conventions et spécifications de formats du langage C.

Les formats sont des chaînes de caractères se composant de "spécifications de conversion" dont la syntaxe est décrite dans le tableau ci-dessous.

ATTENTION : dans un format de lecture (sscanf, fscanf), on ne préfixera en principe pas les "spécifications de conversion" de nombres (u d i o x X f e E g G) par des valeurs n (taille du champ) et m (nombre de décimales), car le comportement de MATLAB et de Octave peut alors conduire à des résultats différents (découpage avec MATLAB, et aucun effet sous Octave).

      Ex: sscanf('560001','%4f') retourne : sous MATLAB le vecteur [5600 ; 1] , et sous Octave la valeur 560001

Spécifications Description
espace • En lecture (sscanf, fscanf) : les caractères espace dans un format sont ignorés (i.e. n'ont aucune signification) !
• En écriture (sprintf, fprintf) : les caractères espace dans un format sont écrits dans la chaîne résultante !
%u

  %nu

Correspond à un nombre entier positif (non signé)

• En lecture:
      Ex: sscanf('100 -5','%u') => 100 et 4.295e+09 (!)
• En écriture: si n est spécifié, le nombre sera justifié à droite dans un champ de n car. au min.
      Ex: sprintf('%5u ', 100, -5) => '  100 -5.000000e+000' et '  100     -5'

%d   %i

%nd   %ni

Correspond à un nombre entier positif ou négatif

• En lecture:
      Ex: sscanf('100 -5','%d') => 100 et -5
• En écriture: si n est spécifié, le nombre sera justifié à droite dans un champ de n car. au min.
      Ex: sprintf('%d %03d ', 100, -5) => '100 -05'

%o

  %no

Correspond à un nombre entier positif en base octale

• En lecture:
      Ex: sscanf('100 -5','%o') => 64 et 4.295e+09 (!)
• En écriture: si n est spécifié, le nombre sera justifié à droite dans un champ de n car. au min.
      Ex: sprintf('%04o ', 64, -5) => '0100 -5.000000e+000' et '0100 -005'

%x   %X

  %nx   %nX

Correspond à un nombre entier positif en base hexadécimale

• En lecture:
      Ex: sscanf('100 -5','%x') => 256 et 4.295e+09 (!)
• En écriture: si n est spécifié, le nombre sera justifié à droite dans un champ de n car. au min.
      Ex: sprintf('%x %04X ', 255, 255, -5) => 'ff 00FF -5.000000e+000' et 'ff 00FF -5'

%f

%nf   %n.mf

Correspond à un nombre réel sans exposant (de la forme {-}mmm.nnn)

• En lecture:
      Ex: sscanf('5.6e3 xy -5','%f xy %f') => [5600 ; -5]
• En écriture: si n est spécifié, le nombre sera justifié à droite dans un champ de n car. au min., et affiché avec m chiffres après la virgule.
      Ex: sprintf('%f %0.2f ', 56e002, -78e-13, -5) => '5600.000000 -0.00 -5.000000'

%e   %E

%ne   %nE

  %n.me   %n.mE

Correspond à un nombre réel en notation scientifique (de la forme {-}m.nnnnnE{+|-}xxx)

• En lecture:
      Ex: sscanf('5.6e3 xy -5','%e %*s %e') => [5600 ; -5]
• En écriture: si n est spécifié, le nombre sera justifié à droite dans un champ de n car. au min., et affiché avec m chiffres après la virgule. Avec e, le caractère 'e' de l'exposant sera en minuscule ; avec E il sera en majuscule.
      Ex: sprintf('%e %0.2E ', 56e002, -78e-13, -5) => '5.600000e+003   -7.80E-12   -5.000000e+00'

%g   %G

  %ng   %nG

Correspond à un nombre réel en notation scientifique compacte (de la forme {-}m.nnnnnE{+|-}x)

• En lecture:
      Ex: sscanf('5.6e3 xy -5','%g %*2c %g') => [5600 ; -5]
• En écriture: donne lieu à une forme plus compacte que %f et %e. Si n est spécifié, le nombre sera justifié à droite dans un champ de n car. au min. Avec g, le caractère 'e' de l'exposant sera en minuscule ; avec G il sera en majuscule.
      Ex: sprintf('%g %G ', 56e002, -78e-13, -5) => '5600   -7.8E-12   -5'

%c

  %nc

Correspond à 1 ou n caractère(s), y compris d'éventuels caractères espace

• En lecture:
      Ex: sscanf('ab1 2cd3 4ef', '%2c %*3c') => 'abcdef'
• En écriture:
      Ex: sprintf(' %c: (ASCII: %3d)\n', 'aabbcc') => cela affiche :
            a: (ASCII: 97)
            b: (ASCII: 98)
            c: (ASCII: 99)

%s

  %ns

Correspond à une chaîne de caractères

• En lecture: les chaînes sont délimitées par un ou plusieurs caractères espace
      Ex: sscanf('123   abcd', '%2s %3s') => '123abcd'
• En écriture: si n est spécifié, la chaîne sera justifiée à droite dans un champ de n car. au min.
      Ex: sprintf('%s|%5s|%-5s|', 'blahblah...', 'abc', 'XYZ')
      => 'blahblah...|   abc|XYZ   |'

Caractères
    spéciaux
Pour faire usage de certains caractères spéciaux, il est nécessaire de les encoder de la façon suivante :
\n pour un saut à la ligne suivante (new line)
\t pour un tab horizontal
%% pour le caractère "%"
\\ pour le caractère "\"

  Tout autre
  caractère
Tout autre caractère (ne faisant pas partie d'une spécification %...) sera utilisé de la façon suivante :

• En lecture: le caractère "matché" sera sauté. Exception: les caractères espace dans un format de lecture sont ignorés
      Ex: sscanf('12 xy 34.5 ab 67', '%f xy %f ab %f') => [12.0 ; 34.5 ; 67.0]
• En écriture: le caractère sera écrit tel quel dans la chaîne de sortie
      Ex: article='stylos' ; fprintf('Total: %d %s \n', 4, article) => 'Total: 4 stylos'


De plus, les "spécifications de conversion" peuvent être modifiées (préfixées) de la façon suivante :

Spécifications Description
%-n... • En écriture: l'élément sera justifié à gauche (et non à droite) dans un champ de n car. au min.

      Ex: sprintf('|%-5s|%-5.1f|', 'abc', 12) => '|abc  |12.0 |'

%0n... • En écriture: l'élément sera complété à gauche par des '0' (chiffres zéros, et non caractères espace) dans un champ de n car. au min.

      Ex: sprintf('|%05s|%05.1f|', 'abc', 12) => '|00abc|012.0|'

%*... • En lecture: saute l'élément qui correspond à la spécification qui suit

      Ex: sscanf('12 blabla 34.5 67.8', '%d %*s %*f %f') => [12 ; 67.8]

7.9.3 Lecture/écriture formatée de chaînes

Lecture/décodage de chaîne

La fonction sscanf ("string scan formated") permet, à l'aide d'un format de lecture, de décoder le contenu d'une chaîne de caractère et d'en récupérer les données sur un vecteur ou une matrice. La lecture s'effectue en "format libre" en ce sens que sont considérés, comme séparateurs d'éléments dans la chaîne, un ou plusieurs espace ou tab. Si la chaîne renferme davantage d'éléments qu'il n'y a de "spécifications de conversion" dans le format, le format sera "réutilisé" autant de fois que nécessaire pour lire toute la chaîne. Si, dans le format, on mélange des spécifications de conversion numériques et de caractères, il en résulte une variable de sortie (vecteur ou matrice) entièrement numérique dans laquelle les caractères des chaînes d'entrée sont stockés, à raison d'un caractère par élément de vecteur/matrice, sous forme de leur code ASCII.

vec = sscanf(string, format)
[vec, count] = sscanf(string, format)
Décode la chaîne string à l'aide du format spécifié, et retourne le vecteur-colonne vec dont tous les éléments seront de même type. La seconde forme retourne en outre, sur count, le nombre d'éléments générés.

Ex:
vec=sscanf('abc 1 2 3 4 5 6', '%*s %f %f') => vec=[1;2;4;5]
    Notez que, en raison de la "réutilisation" du format, les nombres 3 et 6 sont ici sautés par le %*s !
vec=sscanf('1001 1002 abc', '%f %f %s') => vec=[1001;1002;87;98;99]
    Mélange de spécifications de conversion numériques et de caractères => la variable 'vec' est de type nombre, et la chaîne 'abc' y est stockée par le code ASCII de chacun de ses caractères

mat = sscanf(string, format, size)
[mat, count] = sscanf(string, format, size)
Permet de remplir une matrice mat, colonne après colonne. La syntaxe du paramètre size est :
nb => provoque la lecture des nb premiers éléments, et retourne un vecteur colonne
[nb_row, nb_col] => lecture de nb_row x nb_col éléments, et retourne une matrice de dimension nb_row x nb_col

Ex:
vec=sscanf('1 2 3 4 5 6', '%f', 4) => vec=[1;2;3;4]
[mat,ct]=sscanf('1 2 3 4 5 6', '%f', [3,2]) => mat=[1 4 ; 2 5 ; 3 6], ct=6
[mat,ct]=sscanf('1 2 3 4 5 6', '%f', [2,3]) => mat=[1 3 5 ; 2 4 6], ct=6

[var1, var2, var3 ...] = sscanf(string, format, 'C')
(Proche du langage C, cette forme très flexible n'est disponible que sous Octave)
À chaque "spécification de conversion" du format utilisé est associée une variable de sortie var-i. Le type de chacune de ces variables peut être différent !

Ex: • [str,nb1,nb2]=sscanf('abcde 12.34 45.3e14 fgh', '%3c %*s %f %f', 'C') => str='abc', nb1=12.34, nb2=4.53e+15



Si une chaîne ne contient que des nombres, on peut aussi aisément récupérer ceux-ci à l'aide de la fonction str2num présentée au chapitre sur les "Chaînes de caractères".

Il existe encore la fonction de décodage de chaîne strread qui est extrêmement puissante ! Nous vous laissons la découvrir via l'aide ou la documentation.

Voyez aussi textscan qui est capable de lire des chaînes mais aussi des fichiers !

Écriture formatée de variables sur une chaîne

La fonction sprintf ("string print formated") lit les variables qu'on lui passe et les retourne, de façon formatée, sur une chaîne de caractère. S'il y a davantage d'éléments parmi les variables que de "spécifications de conversion" dans le format, le format sera "réutilisé" autant de fois que nécessaire.

string = sprintf(format, variable(s)... )
La variable string (de type chaîne) reçoit donc la(les) variable(s) formatée(s) à l'aide du format spécifié. Si, parmi les variables, il y a une ou plusieurs matrice(s), les éléments sont envoyés colonne après colonne.

Ex:
nb=4 ; prix=10 ; disp(sprintf('Nombre d''articles: %04u     Montant: %0.2f Frs', nb, nb*prix))
ou, plus simplement: fprintf('Nombre d''articles: %04u     Montant: %0.2f Frs \n', nb, nb*prix)
    => affiche: Nombre d'articles: 0004     Montant: 40.00 Frs

La fonction mat2str ("matrix to string") décrite ci-dessous (et voir chapitre "chaînes de caractères") est intéressante pour sauvegarder de façon compacte sur fichier des matrices sous forme texte (en combinaison avec fprintf) que l'on pourra relire sous MATLAB/Octave (lecture-fichier avec fscanf, puis affectation a une variable avec eval).

string = mat2str(mat {,n})
Convertit la matrice mat en une chaîne de caractère string incluant les crochets [ ] et qui serait dont "évaluable" avec la fonction eval. L'argument n permet de définir la précision (nombre de chiffres).

Ex:
str_mat = mat2str(eye(3,3)) produit la chaîne "[1 0 0;0 1 0;0 0 1]"
• et pour affecter ensuite les valeurs d'une telle chaîne à une matrice x, on ferait eval(['x=' str_mat])

Voir aussi les fonctions plus primitives int2str (conversion nombre entier->chaîne) et num2str (conversion nombre réel->chaîne).

7.9.4 Lecture/écriture formatée de fichiers

Lecture de données numériques structurées

S'il s'agit de lire/écrire des fichiers au format texte contenant des données purement numériques et avec le même nombre de données dans chaque ligne du fichier (i.e. des tableaux de nombres), la technique la plus efficace consiste à utiliser les fonctions suivantes décrites plus en détail au chapitre "Sauvegarde et chargement de données numériques via des fichiers-texte" :


Lecture intégrale d'un fichier sur une chaîne

string = fileread('file_name')
Cette fonction lit d'une traite l'intégralité du fichier-texte nommé file_name et retourne son contenu sur un vecteur colonne string de type chaîne

Ex: Dans l'exemple ci-dessous, la première instruction "avale" le fichier essai.txt sur le vecteur ligne de type chaîne fichier_entier (vecteur ligne, car on transpose le résultat de fileread). La seconde découpe ensuite cette chaîne selon les sauts de ligne (\n) de façon à charger le tableau cellulaire tabcel_lignes à raison d'une ligne du fichier par cellule.

fichier_entier = fileread('essai.txt')' ;
tabcel_lignes  = strread(fichier_entier, '%s', 'delimiter', '\n') ; 
[status, string] = dos('type file_name')
[status, string] = unix('cat file_name')
Ces instructions lisent également l'intégralité du fichier-texte nommé file_name, mais le retournent sur un vecteur ligne string de type chaîne. On utilisera la première forme sous Windows, et la seconde sous Linux ou macOS.


Fonction textread

[vec1, vec2, vec3 ...] = textread(file_name, format {,n})
Fonction simple et efficace de lecture d'un fichier-texte nommé file_name dont l'ensemble des données répond à un format homogène. Les données peuvent être délimitées par un ou plusieurs espace, tab, voire même saut(s) de ligne newline. La lecture s'effectue ainsi en "format libre" (comme avec sscanf et fscanf).
• Le vecteur-colonne vec1 recevra la 1ère "colonne" du fichier, le vecteur vec2 recevra la 2e colonne, vec3 la 3e, et ainsi de suite... La lecture s'effectue jusqu'à la fin du fichier, à moins que l'on spécifie le nombre n de fois que le format doit être réutilisé.
• Le nombre de variables vec1 vec2 vec3... et leurs types respectifs découlent directement du format
• Si vec-i réceptionne des chaînes de caractères, il sera de type "tableau cellulaire", en fait vecteur-colonne cellulaire

Les "spécifications de conversion" de format %f, %s, %u et %d peuvent être utilisées avec textread sous MATLAB et Octave.
Sous Octave seulement on peut en outre utiliser les spécifications %o et %x.
Sous MATLAB, les spécifications %u et %d génèrent un vecteur réel double précision. Mais ATTENTION, sous Octave elles génèrent un vecteur entier 32 bits !
Sous MATLAB seulement on peut encore utiliser :
      %[...] : lit la plus longue chaîne contenant les caractères énumérés entre [ ]
      %[^...] : lit la plus longue chaîne non vide contenant les caractèrens non énumérés entre [ ]

Ex:
Soit le fichier-texte de données ventes.txt suivant :

10001     Dupond    Livres       12    23.50
10002     Durand    Classeurs    15     3.95
10003     Muller    DVDs          5    32.00
10004     Smith     Stylos       65     2.55
10005     Rochat    CDs          25    15.50
10006     Leblanc   Crayons     100     0.60
10007     Lenoir    Gommes       70     2.00
et le script MATLAB/Octave suivant :
[No_client, Nom, Article, Nb_articles, Prix_unit] = textread('ventes.txt', '%f %s %s %f %f') ;

Montant = Nb_articles .* Prix_unit ;

disp('     Client [No   ]      Nb  Articles     Prix unit.         Montant  ')
disp('  --------- -------   -----  ---------   -----------      ------------')
format = ' %10s [%d]   %5d  %-10s %8.2f Frs      %8.2f Frs\n' ;

for no=1:1:length(No_client)
  fprintf(format, Nom{no}, No_client(no), Nb_articles(no), Article{no}, Prix_unit(no), Montant(no) ) ;
end

fprintf('\n\n                                               TOTAL      %8.2f Frs \n', sum(Montant) ) 
Attention : bien noter, ci-dessus, les accolades pour désigner éléments de Nom{} et de Article{}. Ce sont des "tableaux cellulaires" dont on pourrait aussi récupérer les éléments, sous forme de chaîne, avec : char(Nom(no)), char(Article(no)).

L'exécution de ce script: lit le fichier, calcule les montants, et affiche ce qui suit :

     Client [No   ]      Nb  Articles     Prix unit.         Montant  
  --------- -------   -----  ---------   -----------      ------------
     Dupond [10001]      12  Livres        23.50 Frs        282.00 Frs
     Durand [10002]      15  Classeurs      3.95 Frs         59.25 Frs
     Muller [10003]       5  DVDs          32.00 Frs        160.00 Frs
      Smith [10004]      65  Stylos         2.55 Frs        165.75 Frs
     Rochat [10005]      25  CDs           15.50 Frs        387.50 Frs
    Leblanc [10006]     100  Crayons        0.60 Frs         60.00 Frs
     Lenoir [10007]      70  Gommes         2.00 Frs        140.00 Frs
 
                                               TOTAL       1254.50 Frs

Fonctions classiques de manipulation de fichiers (de type ANSI C)

file_id = fopen(file_name, mode)
[file_id, message_err ] = fopen(file_name, mode)
Ouvre le fichier de nom défini par la variable/chaîne file_name, et retourne l'identifiant file_id qui permettra de le manipuler par les fonctions décrites plus bas.

Si file_name ne définit qu'un nom de fichier, celui-ci est recherché dans le répertoire courant. Si l'on veut ouvrir un fichier se trouvant dans un autre répertoire, il faut bien entendu faire précéder le nom du fichier de son chemin d'accès (path) relatif ou absolu. S'agissant du séparateur de répertoire, bien que celui-ci soit communément \ sous Windows, nous vous conseillons de toujours utiliser / (accepté par MATBAL/Octave sous Windows) pour que vos scripts/fonctions soient portables, c'est-à-dire utilisables dans les 3 mondes Windows, macOS et GNU/Linux.

Le mode d'accès au fichier sera défini par l'une des chaînes suivantes :
'rt' ou 'rb' ou 'r' : lecture seule (read)
'wt' ou 'wb' ou 'w' : écriture (write), avec création du fichier si nécessaire, ou écrasement s'il existe
'at' ou 'ab' ou 'a' : ajout à la fin du fichier (append), avec création du fichier si nécessaire
'rt+' ou 'rb+' ou 'r+' : lecture et écriture, sans création
'wt+' ou 'wb+' ou 'w+' : lecture et écriture avec écrasement du contenu
'at+' ou 'ab+' ou 'a+' : lecture et ajout à la fin du fichier, avec création du fichier si nécessaire
Le fait de spécifier t ou b ou aucun de ces deux caractères dans le mode a la signification suivante :
t : ouverture en mode "texte"
b ou rien : ouverture en mode "binaire" (mode par défaut)
Sous Windows ou macOS, il est important d'utiliser le mode d'ouverture "texte" si l'on veut que les fins de ligne soient correctement interprétées !

En cas d'échec (fichier inexistant en lecture, protégé en écriture, etc...), file_id reçoit la valeur "-1". On peut aussi récupérer un message d'erreur sous forme de texte explicite sur message_err

Identifiants prédéfinis (toujours disponibles, correspondant à des canaux n'ayant pas besoin d'être "ouverts") :
1 ou stdout : correspond à la sortie standard (standard output, c'est-à-dire fenêtre console MATLAB/Octave), pouvant donc être utilisé pour l'affichage à l'écran
2 ou stderr : correspond au canal erreur standard (standard error, par défaut aussi la fenêtre console), pouvant aussi être utilisé par le programmeur pour l'affichage d'erreurs
0 ou stdin : correspond à l'entrée standard (standard input, c'est-à-dire saisie au clavier depuis console MATLAB/Octave).

Pour offrir à l'utilisateur la possibilité de désigner le nom et emplacement du fichier à ouvrir/créer à l'aide d'une fenêtre de dialogue classique (interface utilisateur graphique), on se réfèrera aux fonctions uigetfile (lecture de fichier), uiputfile (écriture de fichier) et zenity_file_selection présentées au chapitre "Interfaces-utilisateur graphiques". Pour sélectionner un répertoire, on utilisera la fonction uigetdir.

[file_name, mode] = fopen(file_id)
Pour un fichier déjà ouvert avec l'identifiant file_id spécifié, retourne son nom file_name et le mode d'accès.
freport()
Affiche la liste de tous les fichiers ouverts, avec file_id, mode et file_name.
On voit que les canaux stdin, stdout et stderr sont toujours pré-ouverts
{status=} fclose(file_id)
fclose('all')
Referme le fichier ayant l'identifiant file_id (respectivement tous les fichiers ouverts). Le status retourné est "0" en cas de succès, et "-1" en cas d'échec.
A la fin de l'exécution d'un script ayant ouvert des fichiers, tous ceux-ci sont automatiquement refermés, même en l'absence de fclose.
variable = fscanf(file_id, format {,size})
[variable, count] = fscanf(file_id, format {,size})
Fonction de lecture formatée ("file scan formated") du fichier-texte spécifié par son identifiant file_id. Fonctionne de façon analogue à la fonction sscanf vue plus haut (à laquelle on renvoie le lecteur pour davantage de précision), sauf qu'on lit ici sur un fichier et non pas sur une chaîne de caractères.
Remarque importante : en l'absence du paramètre size (décrit plus haut sous sscanf), fscanf tente de lire (avaler, "slurp") l'intégralité du fichier (et non pas seulement de la ligne courante comme fgetl ou fgets).

Ex:
Soit le fichier-texte suivant :

10001     Dupond
  Livres      12    23.50
10002     Durand
  Classeurs   15     3.95
La lecture des données de ce fichier avec fscanf s'effectuerait de la façon suivante :
file_id = fopen('fichier.txt', 'rt') ;
no = 1 ;
while ~ feof(file_id)
  No_client(no)   = fscanf(file_id,'%u',1) ;
  Nom{no,1}       = fscanf(file_id,'%s',1) ;
  Article{no,1}   = fscanf(file_id,'%s',1) ;
  Nb_articles(no) = fscanf(file_id,'%u',1) ;
  Prix_unit(no)   = fscanf(file_id,'%f',1) ;
  no = no + 1 ;
end
status = fclose(file_id) ;
[variable, count] = scanf(format {,size})
Fonction spécifiquement Octave de lecture formatée sur l'entrée standard (donc au clavier, identifiant 0). Pour le reste, cette fonction est identique à fscanf.
line = fgetl(file_id)
Lecture, ligne par ligne ("file get line"), du fichier-texte spécifié par l'identifiant file_id. A chaque appel de cette fonction on récupère, sur la variable line de type chaîne, la ligne suivante du fichier (sans le caractère de fin de ligne).
string = fgets(file_id {,nb_car})
Lecture, par groupe de nb_car ("file get string"), du fichier-texte spécifié par l'identifiant file_id. En l'absence du paramètre nb_car, on récupère, sur la variable string, la ligne courante inclu le(s) caractère(s) de fin de ligne (<cr> <lf> dans le cas de Windows).
{count=} fskipl(file_id ,nb_lignes)
Avance dans le fichier file_id en sautant nb_lignes ("file skip lines"). Retourne le nombre count de lignes sautées (qui peut être différent de nb_lignes si l'on était près de la fin du fichier).
{status=} feof(file_id)
Test si l'on a atteint la fin du fichier spécifié par l'identifiant file_id : retourne "1" si c'est le cas, "0" si non. Utile pour implémenter une boucle de lecture d'un fichier.

Ex: voir l'usage de cette fonction dans l'exemple fscanf ci-dessus

frewind(file_id)
Se (re)positionne au début du fichier spécifié par l'identifiant file_id.
Pour un positionnement précis à l'intérieur d'un fichier, voyez les fonctions :
fseek(file_id, offset, origin) : positionnement offset octets après origin
position = ftell(file_id) : retourne la position courante dans le fichier
{count=} fprintf(file_id, format, variable(s)... )
Fonction d'écriture formatée ("file print formated") sur un fichier-texte spécifié par l'identifiant file_id, et retourne le nombre count de caractères écrits. Fonctionne de façon analogue à la fonction sprintf vue plus haut (à laquelle on renvoie le lecteur pour davantage de précision), sauf qu'on écrit ici sur un fichier et non pas sur une chaîne de caractères.
{count=} fprintf(format, variable(s)... )
{count=} printf(format, variable(s)... )
Utiliser fprintf en omettant le file_id (qui est est identique à utiliser le file_id "1" représentant la sortie standard) ou printf (spécifique à Octave), provoque une écriture/affichage à l'écran (i.e. dans la fenêtre de commande MATLAB/Octave).

Ex: affichage de la fonction y=exp(x) sous forme de tableau avec :
x=0:0.05:1 ; exponentiel=[x;exp(x)] ; fprintf('   %4.2f   %12.8f \n',exponentiel)

{status=} fflush(file_id)
Pour garantir de bonnes performances, Octave utilise un mécanisme de mémoire tampon (buffer) pour les opérations d'écriture. Les écritures ainsi en attente sont périodiquement déversées sur le canal de sortie, au plus tard lorsque l'on fait un fclose. Avec la fonction fflush, on force le vidage (flush) du buffer sur le canal de sortie.
Dans des scripts interactifs ou affichant des résultats en temps réel dans la fenêtre console, il peut être utile dans certaines situations de flusher la sortie standard avec fflush(stdout). Voyez aussi la fonction page_output_immediately pour carrément désactiver le buffering.

Fonction textscan

Cette fonction est capable à la fois de lire un fichier ou de décoder une chaîne.
vec_cel = textscan(file_id, format {,n})
Lecture formatée d'un fichier-texte spécifié par l'identifiant file_id (voir ci-dessus) et dont l'ensemble des données répond à un format homogène.
La lecture s'effectue jusqu'à la fin du fichier, à moins que l'on spécifie le nombre n de fois que le format doit être réutilisé.
Dans le format, on peut notamment utiliser \r, \n ou \r\n pour matcher respectivement les caractères de fin de lignes "carriage-return" (macOS), "line-feed" (Unix/Linux) ou "carriage-return + line-feed (Windows)
La fonction retourne un vecteur-ligne cellulaire vec_cel dont la longueur correspond au nombre de spécifications du format. Chaque cellule contient un vecteur-colonne de type correspondant à la spécification de format correspondante.

Ex: on peut lire le fichier ventes.txt ci-dessus avec :

file_id = fopen('ventes.txt', 'rt');
  vec_cel = textscan(file_id, '%u %s %s %u %f');
fclose(file_id);
et l'on récupère alors dans vec_cel{1} le vecteur de nombre des No, dans vec_cel{2} le vecteur cellulaire des Clients, dans vec_cel{3} le vecteur cellulaire des Articles, etc...
vec_cel = textscan(string, format {,n})
Opère ici sur la chaîne string

7.9.5 Fonctions de lecture/écriture de fichiers spécifiques/binaires

fread(...) et fwrite(...)
Fonctions de lecture/écriture binaire (non formatée) de fichiers, pour un stockage plus compact qu'avec des fichiers en format texte. Voyez l'aide pour davantage d'information.
xlsread(...) et xlswrite(...)
Fonctions de lecture/écriture de classeurs Excel (binaire). Voyez l'aide pour davantage d'information.
odsread(...) et odswrite(...)
Fonctions de lecture/écriture de classeurs OpenOffice/LibreOffice (binaire). Voyez l'aide pour davantage d'information.

7.10 Réalisation d'interfaces-utilisateur graphiques (GUI)

7.10.1 Fonctions GUI communes à MATLAB et GNU Octave

Désignation de fichiers et de répertoires

[file_name, path] = uigetfile('filtre' {,'titre_dialogue'} {,x,y} )
Fait apparaître à l'écran une fenêtre graphique de dialogue standard de désignation de fichier (selon figures ci-dessous). Fonction utilisée pour désigner un fichier à ouvrir en lecture, en suite de laquelle on utilise en principe la fonction fopen... Une fois le fichier désigné par l'utilisateur (validé par bouton Ouvrir ou OK), le nom du fichier est retourné sur la variable file_name, et le chemin d'accès complet de son dossier sur la variable path. Si l'utilisateur referme cette fenêtre avec le bouton Annuler ou Cancel, cette fonction retourne file_name = path = 0
• La chaîne titre_dialogue s'inscrit dans la barre de titre de cette fenêtre
• Le filtre permet de spécifier le type des fichiers apparaissant dans cette fenêtre. Par exemple *.dat ne présentera que les fichiers ayant l'extension .dat (à moins que l'utilisateur ne choisisse All files (*.*) dans le menu déroulant Fichiers de type:)
• La fenêtre sera positionnée à l'écran de façon que son angle supérieur gauche soit aux coordonnées x,y par rapport à l'angle supérieur gauche de l'écran

Ex: le code ci-dessous fait désigner par l'utilisateur un fichier, puis affiche son contenu
(pour les fonctions fopen, feof, fgetl, fprintf et fclose, voir le chapitre Entrées-sorties...)

[fichier, chemin] = uigetfile('*.dat','Choisir le fichier à ouvrir :');
if fichier == 0
   disp('Aucun fichier n''a été désigné !')
else
   fid = fopen([chemin fichier], 'rt');  % entre crochets, concaténation
                                         % du chemin et du nom de fichier
   while ~ feof(fid)
      ligne = fgetl(fid);
      fprintf('%s\n', ligne)
   end
   status=fclose(fid);
end

Fenêtre uigetfile sous Windows 7 Fenêtre uigetfile sous Linux/Ubuntu
(remarquez l'option et la zone "preview")

[file_name, path] = uiputfile('fname' {,'titre_dialogue'} {,x,y} )
Fait apparaître une fenêtre de dialogue standard de sauvegade de fichier (en suite de laquelle on fait en principe un fopen...). Le nom de fichier fname sera pré-inscrit dans la zone "Nom de fichier" de cette fenêtre. De façon analogue à la fonction uigetfile, le nom de fichier défini par l'utilisateur sera retourné sur la variable file_name, et le chemin complet d'accès au dossier sélectionné sur la variable path. Si un fichier de même nom existe déjà, MATLAB/Octave demandera une confirmation d'écrasement.

Ex: [fichier, chemin] = uiputfile('resultats.dat','Sauver sous :');

path = uigetdir( {'path_initial' {,'titre_dialogue' } } )
Fait apparaître à l'écran une fenêtre graphique de dialogue standard de sélectionnement de répertoire, et retourne le chemin de celui-ci sur path
• Le path_initial permet de positionner la recherche à partir du path ainsi spécifié. Si ce paramètre est omis, le positionnement initial s'effectue sur le répertoire courant
• La chaîne titre_dialogue s'inscrit dans la barre de titre de cette fenêtre

Fenêtres de dialogue standards

Les fonctions présentées ici permettent d'afficher des fenêtres de dialogues standards. Elles sont toutes "modale", c'est-à-dire que le programme est suspendu tant que l'utilisateur n'a pas répondu à la sollicitation de la fenêtre.

Nous les présentons sous forme d'exemples, et les illustrations proviennent de Octave sous Windows 7.

S'agissant de Octave, ces fonctions apparaissent avec la version 3.8 et s'appuient sur le package Java qui est désormais intégré à Octave Core.

Fenêtre d'information :

msg={'Message d''information', 'sur plusieurs lignes'};
    
msgbox(msg, 'Titre fenetre', 'none'); 

Le premier paramètre msg peut être une chaîne simple (qui sous Octave peut contenir \n pour générer un saut à la ligne) ou un vecteur cellulaire de chaînes (chaque élément étant alors affiché dans la fenêtre sur une nouvelle ligne).
Le 3e paramètre peut être 'warn', 'help' ou 'error' (=> affichage d'une icône dans la fenêtre), ou être ignoré ou valoir 'none' (=> pas d'icône).

Remarque : notez la différence de comportement entre MATLAB et Octave :
Sous Octave, l'affichage de cette fenêtre suspend le programme qui redémarre une fois qu'on a cliqué OK
Cette fenêtre ne suspend pas l'exécution du programme (pour cela il faudrait faire uiwait(msgbox(...)))

Fenêtre d'avertissement :

msg={'Message d''avertissement', 'sur plusieurs lignes'};
    
warndlg(msg, 'Titre fenetre'); 

Cette fonction fournit le même résultat que msgbox(msg, titre, 'warn')

Remarque : cette fonction suspend l'exécution du programme sous Octave 3.8, mais pas sous MATLAB (idem que pour msgbox)

Fenêtre d'aide :

msg={'Message d''aide', 'sur plusieurs lignes'};
    
helpdlg(msg, 'Titre fenetre'); 

Cette fonction fournit le même résultat que msgbox(msg, titre, 'help')

Remarque : cette fonction suspend l'exécution du programme sous Octave 3.8, mais pas sous MATLAB (idem que pour msgbox)

Fenêtre d'erreur :

msg={'Message d''erreur', 'sur plusieurs lignes'};
    
errordlg(msg, 'Titre fenetre'); 

Cette fonction fournit le même résultat que msgbox(msg, titre, 'error')

Remarque : cette fonction suspend l'exécution du programme sous Octave 3.8, mais pas sous MATLAB (idem que pour msgbox)

Fenêtre de question :

Cette fonction suspend l'exécution du programme et affiche une fenêtre de question. L'exécution se poursuit lorsque l'on a cliqué sur l'un des 3 boutons.

msg={'Question sur', 'plusieurs lignes'};
    
bouton = questdlg(msg, 'Titre fenetre','Yes') 

Avec la première forme ci-dessus, affiche en-dessous du message msg les 3 boutons Cancel, No et Yes. Le 3e paramètres (facultatif, 'Yes' dans l'exemple ci-dessus) indique quel bouton est pré-sélectionné et sera activé si l'on presse enter. Retourne sur bouton la chaîne de caractère correspondant au nom du bouton pressé.
Différence de comportement entre MATLAB et Octave 3.8 si on utilise la case de fermeture : MATLAB retourne une chaîne vide, Octave retourne 'Cancel'

bouton = questdlg(msg, 'Titre fenetre', ...
                'Annuler', 'Non', 'Oui', 'Annuler') 
Avec la seconde forme ci-dessus, on spécifie le nom des boutons. Il peut y en avoir 2 ou 3 (ici 3), et on doit obligatoirement indiquer une chaîne supplémentaire spécifiant le nom du bouton activé par défaut si l'on presse enter.

Fenêtre de saisie de champs de texte :

Cette fonction suspend l'exécution du programme et affiche une fenêtre de saisie multi-champs. L'exécution se poursuit lorsque l'on a cliqué sur l'un des 2 boutons.

labels  = {'Prenom', 'Nom', 'Pays', 'Commentaire'};
li_cols = [1, 15; 1, 15; 1, 12; 2, 20];
val_def = {'', '', 'Suisse', ''};

vec_cel = inputdlg(labels, 'Titre fenetre', li_cols, val_def)

Affiche les champs de saisie étiquetés par les chaînes du vecteur cellulaire labels.

Le paramètre li_cols (facultatif, mais nécessaire si on veut passer le paramètre val_def) permet de définir la taille des champs :
• scalaire : nombre de lignes de tous les champs
vecteur à 2 éléments [lignes, colonnes] : nombre de lignes et de colonnes de tous les champs
• vecteur (avec autant d'éléments que labels) : nombre de lignes de chaque champ
• matrice (de 2 colonnes et autant de lignes que d'éléments dans labels) : nombre de lignes et de colonnes de chaque champ
Notez que sous MATLAB le paramètre colonnes affecte non seulement la largeur du champ mais aussi la largeur d'affichage des étiquettes labels !

Le vecteur cellulaire de chaînes val_def (paramètre facultatif) permet de pré-remplir les champs par des valeurs par défaut (ici le Pays Suisse).

Lorsque l'on clique Ok, la fonction retourne les données saisies dans les différents champs sur un vecteur cellulaire de chaînes vec_cel.

Fenêtre de sélection dans une liste :

Cette fonction suspend l'exécution du programme et affiche une fenêtre de sélection. L'exécution se poursuit lorsque l'on a cliqué sur l'un des 2 boutons inférieurs.

valeurs={'pommes','poires','cerises','kiwis','oranges'};
    
[sel_ind, ok] = listdlg('ListString', valeurs, ...
        'Name', 'Vos fruits', ...
        'PromptString', 'Fruits preferes :', ...
        'SelectionMode', 'Multiple', ...
        'ListSize', [100 140], ...
        'InitialValue', [1, 3], ...
        'OKString', 'J''ai choisi', ...
        'CancelString', 'Annuler');
if ok
  fprintf('Fruits choisis: ')
  for ind = 1:numel(sel_ind)
    fprintf([valeurs{sel_ind(ind)} ' '])
  end
  fprintf('\n')
end

Les paramètres d'entrée de listdlg sont définis par paire : 'mot-clé', valeur

Paramètre d'entrée obligatoire :
'ListString' réfère le vecteur cellulaire valeurs des éléments à afficher dans la liste

Paramètres d'entrée facultatifs :
'Name' définit le titre de la fenêtre
'PromptString' définit l'invite affichés au haut de la liste
'SelectionMode' peut être 'Multiple' (sélection possible de plusieurs valeurs avec ctrl-clic, mode par défaut) ou 'Single'
'ListSize' définit en pixels la taille [largeur, hauteur] de la zone d'affichage des valeurs
'InitialValue' réfère un vecteur contenant les indices des éléments de valeurs qu'il faut pré-sélectionner
'OKString' permet de redéfinir le texte du bouton Ok
'CancelString' permet de redéfinir le texte du bouton Cancel

Paramètres de sortie :
sel_ind est un vecteur ligne contenant les indices des éléments de valeurs que l'on a sélectionnés
ok retourne 1 si on a cliqué Ok, et 0 si on a cliqué Cancel




Autres accessoires GUI

choix = menu('Titre','element1','element2',...)

Implémente un menu retournant dans choix le numéro d'ordre de l'élément sélectionné :
  • MATLAB : ce menu apparaît sous forme d'une fenêtre dans laquelle chaque élement fait l'objet d'un bouton (voir figure de gauche ci-contre). Il suffit de cliquer sur un bouton pour refermer la fenêtre et continuer l'exécution du programme.

  • Octave : Sous Octave ≥ 4.0, ce menu est implémenté par une fenêtre analogue à celle de la fonction listdlg (voir figure de droite ci-contre). Le bouton Select All est désactivé. Il faut sélectionner l'élément désiré puis cliquer sur Ok pour refermer la fenêtre et continuer l'exécution du programme.

    Sous Octave ≤ 3.8, ce menu apparaissait sous forme texte dans la fenêtre de commande, et il fallait répondre en frappant le numéro de la ligne de menu désirée, celle-ci étant alors retournés sur choix.

Si vous souhaitez implémenter un choix permettant de sélectionner plusieurs éléments, utilisez la fonction listdlg présentée au chapitre "Interfaces-utilisateur graphiques"

handle=waitbar(x {,'texte'} )
Affiche une barre de progression ("thermomètre") de longueur définie par le paramètre x dont la valeur doit être comprise entre 0.0 (barre vide) et 1.0 (barre pleine). On utilise cette fonction pour faire patienter l'utilisateur en lui indiquant la progression d'un traitement d'une certaine durée.
Cette barre se présente sous la forme d'une fenêtre graphique que l'on pourra refermer avec close(handle). Attention, seul le 1er appel à waitbar peut contenir le paramètre texte (qui s'affichera au-dessus de la barre), sinon autant de fenêtre seront crées que d'appels à cette fonction !

Sous Octave, voyez aussi la fonction analogue zenity_progress

Ex
barre = waitbar(0,'Patientez...');
for k=1:50
   pause(0.1)
     % pour les besoins de l'exemple, on
     %    fait ici une pause en lieu et
     %    place d'autres instructions...
   waitbar(k/50)
end
close(barre)
Ci-contre effet de ce code sous Octave Windows avec backend FLTK

Fonctions GUI propres aux fenêtres de figures

Chapitre en cours d'élaboration... Merci de patienter !

Pour développer de véritables interfaces graphiques sous MATLAB ou Octave, on réalise généralement cela dans des fenêtres de figures. Notez que ces possibilités apparaissent progressivement sous Octave depuis la version 3.8 et ne sont disponibles qu'avec les backends graphiques Qt et FLTK.

Nous énumérons ci-après les fonctions principales disponibles à la fois sous MATLAB et Octave en vous renvoyant à l'aide pour plus de détails :

7.10.2 Fonctions GUI spécifiques à GNU Octave

Possibilités offertes par Zenity

Zenity est un outil du monde GNU/Linux sous GNOME permettant d'afficher aisément, depuis des scripts, des widgets basées sur les librairies GTK+ et Glade. Un package Octave-Forge, également nommé zenity, permet d'accéder aux possibilités de cet outil via des fonctions Octave nommées zenity_*

Pour plus de détails (installation, possibilités, utilisation...) :  

7.11 "Publier" un code MATLAB/Octave

Se rapprochant du concept de notebook, la fonction publish permet d'exécuter un script MATLAB/Octave en produisant un rapport comportant 3 parties :
publish('script{.m}' {, 'format','fmt_rapport', 'imageFormat','fmt_images', 'showCode',true|false, 'evalCode',true|false } )
Avec Octave, le rapport est créé dans le répertoire courant ; sous MATLAB, dans un sous-répertoire nommé "html".
Les paramètres optionnels sont :

Ex: Soit le script ci-dessous nommé code.m :
% Exécution/publish de ce code sous Octave

% Données
    x= 4*rand(1,50) -2       % val. aléatoires entre -2 et +2
    y= 4*rand(1,50) -2       % val. aléatoires entre -2 et +2
    z= x.*exp(-x.^2 - y.^2)  % Z en ces points

% Premier graphique (double, de type multiple plots)
    figure(1)
    subplot(1,2,1)
    plot(x,y,'o')
    title('semis de points aleatoire')
    grid('on')
    axis([-2 2 -2 2])
    axis('equal')
    subplot(1,2,2)
    tri_indices= delaunay(x, y);   % form. triangles => matr. indices
    trisurf(tri_indices, x, y, z)  % affichage triangles
    title('z = x * exp(-x^2 - y^2) % sur ces points')
    zlim([-0.5 0.5])
    set(gca,'ztick',-0.5:0.1:0.5)
    view(-30,10)

% Second graphique (simple)
    figure(2)
    xi = -2:0.2:2 ;
    yi = xi';
    [XI,YI,ZI] = griddata(x,y,z,xi,yi,'nearest');  % interp. grille
    surfc(XI,YI,ZI)
    title('interpolation sur grille')
    

Son exécution avec la commande :

  publish('code.m', 'format','html', 'imageFormat','png')

produit le rapport accessible sous ce lien




Documentation CC BY-SA 4.0 / J.-D. BONJOUR () / EPFL-ENAC-IT / Rév. 18-11-2016       ↵ Table des matières