Baniere Saphir Control
http://www.saphir-control.fr/

bar


BACK
Scilab : un logiciel libre pour le calcul scientifique
cinquième partie :


mise au point de programmes et debug en Scilab



Tous ces articles en ligne sur Scilab ont été écrits pour LINUX MAGAZINE FRANCE par les développeurs du Scilab Group. Les articles sont sous licence FDL (Free Documentation Licence)

Avec les articles précédents sur Scilab, nous savons maintenant écrire des fonctions en langage Scilab et interfacer du code (C ou Fortran) compilé. Tout programmeur sait bien que l'écritue de code s'accompagne inévitablement de bugs qui commencent avec l'erreur de syntaxe pour aller à un résultat faux sans qu'il soit toujours évident de trier entre une erreur de programmation (le programme "ne fait pas ce que je crois") et une erreur d'algorithme (ce que j'ai écrit est correct, fais bien ce que je souhaitais mais ne résout pas le problème que je souhaitais résoudre). Enfin il y a parfois à comprendre plus précisèment ce que fait une fonction de Scilab et même (sait-on jamais ?!) à découvrir un bug de Scilab.

Il y a dans Scilab un certain nombre de fonctions qui permettent de suivre l'exécution de programmes et de localiser les erreurs. On va prendre un exemple très simple de fonction :


function [y]=bisq(x,a,b,c)
xx=x.*x;
y=a*xx**2+b*xx+c;
return


-->  a=1;b=2;c=-4; 
 
-->xres=fsolve(100,bisq)
 xres  =
 
    1.1117859 
 
La première fonctionalité consiste à interrompre l'exécution d'une fonction écrite en langage Scilab. Il y a pour cela 3 possibilités : une commande clavier et deux commandes programmées. La commande clavier est Ctrl-c et les commandes programmées sont setbpt et pause. La commande pause doit être insérée dans le code de la fonction (ce qui nécessite un nouveau chargement de la fonction) à l'endroit souhaité alors que la commande setbpt (place un point d'arrêt ou breakpoint) est une commande extérieure à la fonction qui ne modifie pas son code source.

a=1;b=2;c=-4;x=10;
-->bisq(x,a,b,c)
 ans  =
 
    10196.  
-->setbpt('bisq',2)

-->bisq(x,a,b,c)
Stop after row     2 in function bisq :
 
 

-1->

Le prompt -1-> signifie que nous sommes maintenant au niveau 1 d'interruption (on peut donc avoir plusieurs niveaux). A ce niveau on se trouve dans la situation de départ d'une nouvelle session de Scilab. On peut faire toutes les manipulations souhaitées sans affecter le niveau inférieur. Ce qui est essentiel c'est que l'on a accès ``en lecture'' à toutes les variables du niveau inférieur. La commande setbpt('bisq',2) a eu le même effet que l'insertion de la commande pause après la deuxième ligne de la fonction bisq.

Les variables du niveau inférieur doivent être "remontées" au niveau d'interruption : la manière la plus simple consiste à taper leur nom suivi de ; pour éviter l'affichage :


-1->a;

On redescend au niveau inférieur et on reprend l'exécution interrompue par la commande resume (ou return ) :

 
-1->resume
 ans  =
 
    10196.
  
Mais on peut modifier des variables du niveau inférieur à partir du niveau d'interruption par la commande resume en lui donnant comme paramètre les noms des variables modifiées; dans le cas précédent on peu faire :


-->y=bisq(x,a,b,c)
Stop after row     2 in function bisq :
 
 
-1->a=5;b=0.;
 
-1->[a,b]=resume(a,b)
 y  =
 
    49996.  

On peut revenir directement au niveau 0 par la commande abort.

Les points d'arrêt sont listés par la commande dispbpt et libérés par la commande delbpt :

 
-->dispbpt()
 breakpoints of  function :bisq                    
 
         2
 
-->delbpt('bisq',2)  
 
Lorsqu'on utilise Ctrl-c pour interrompre l'exécution de longs programmes il est utile de localiser l'endroit où l'interruption s'est produite par la commande whereami :


-1->whereami()
whereami called under pause
pause    called at line 3 of macro bisq

ou la commande where :


-1->[linenum,mac]=where()
 mac  =
 
!pause  !
!       !
!bisq   !
 linenum  =
 
!   0. !
!   3. !
Si la fonction est une fonction des librairies Scilab on peut localiser cette fonction par :

 
-->whereis('median')
 ans  =
 
 elemlib 
  
On peut alors connaître le chemin d'accès à cette librairie ainsi que la liste de toutes les fonctions de la librairie en tapant simplement le nom de la librairie :


-->elemlib 
 elemlib  =
 
 Functions files location :SCI/macros/elem/
 
 and       atanm     atanhm    atanh     asinhm    asinh     asinm     
 asin      acoshm    acosh     acosm     acos      cosm      cothm     
 coth      cotg      coshm     cosh      erfcx     erfc      erf       
 fix       GLoad     intersect           isnan     isinf     inttrap   
 intsplin  integrate           intc      intl      interpln  lex_sort  
 logm      log10     mean      median    modulo    null      or        
 pertrans  setdiff   st_deviation        spones    sprand    spzeros   
 speye     squarewave          smooth    sqrtm     sinm      signm     
 sinhm     sinh      toeplitz  tanhm     tanh      tanm      tan       
 union     unique
    
Il y a, bien sûr, quelques commandes qui donnent des renseignements sur les variables utilisées :


-->who
your variables are...
 
 typeof    whos      y         x         xres      c         b         
 a         bisq      startup   ierr      MODE_X    scicos_pal          
 %helps    MSDOS     home      PWD       TMPDIR    percentlib          
 fraclablib          soundlib  xdesslib  utillib   tdcslib   siglib    
 s2flib    roblib    optlib    metalib   elemlib   commlib   polylib   
 autolib   armalib   alglib    intlib    mtlblib   SCI       %F        
 %T        %z        %s        %nan      %inf      old       
 newstacksize        $         %t        %f        %eps      %io       
 %i        %e        


 using       6196 elements  out of    1000000.
          and         54 variables out of       1071

La commande who fournit la liste des variables et librairies utilisées ainsi que la place mémoire utilisée dans la pile (avec la taille de cette dernière qui peut être également obtenue par stacksize() ).

La commande whos est plus précise : elle donne en plus le type des variables, fonctions et librairies utilisées avec leur taille et la place mémoire occupée.


-->whos()
Name                     Type                Size                Bytes        

 
typeof                   compiled function                       3088         
whos                     compiled function                       5736         
y                        constant matrix     1 by 1              24           
x                        constant matrix     1 by 1              24           
xres                     constant matrix     1 by 1              24      
.................................
TMPDIR                   string              1 by 1              80           
percentlib               library                                 8920         
fraclablib               library                                 1504         
soundlib                 library                                 272     
.................................

Lors de l'écriture de programmes multiples il peut être intéressant de savoir si un nom de variable est déja utilisé ou quel est le type d'une variable :


-->exists('x')

 ans  =
 
    1.  
 
-->type(x)
 ans  =
 
    1.  
 
-->typeof(x)
 ans  =
 
 constant
   
On peut également libérer la place mémoire occupée par un variable en la détruisant par la commande clear.

Certaines erreurs dépendent de l'environnement, c'est à dire qu'elles ne se produisent que pour certaines valeurs des paramètres. Or, pour corriger une erreur il faut pouvoir la reproduire : pour cette opération il est commode d'utiliser les fonctions save et load. En utilisation courante ces fonctions permettent d'écrire et de recharger des résultats de manière efficace (en format binaire). L'appel le plus simple save('nom de fichier') permet de sauver toutes les variables utilisées pour recharger ensuite cet environnement et reproduire une erreur éventuelle.

Il y a également la manipulation des erreurs. La commande errcatch est un handler d'erreur : elle permet donc de définir une action exécutée si une erreur de type donné se produit. L'existence de l'erreur en question peut être vérifiée par la commande iserror et l'action définie par errcatch peut être annulée par errclear. L'insertion de messages d'erreur dans ses propres fonctions se fait par la commande error en spécifiant le message que l'on veut passer à l'utilisateur. Signalons également la commande execstr qui permet d'exécuter des instructions par évaluation de strings et de gérer les erreurs en utilisant le flag 'errcatch' dans son appel.

Une fonction Scilab utilise des variables locales; elle peut lire n'importe quelle variable de la base globale. Il est parfois utile de pouvoir utiliser une variable unique connue de toutes les fonctions : ceci est une variable globale définie par la commande global que l'on peut tester par isglobal et supprimer par clearglobal. Ces variables sont stockées dans une partie spécifique de la pile que l'on peut interroger et modifier par la commande gstacksize.

Après un usage un peu consistant on obtient un ensemble de fonctions dans un répertoire et des fichiers de données à manipuler. On peut alors utiliser getd qui permet de charger simultanèment toutes les fonctions d'un répertoire et meof est parfois utile pour savoir si toutes les données d'un fichier ont été lues.

Pour les problèmes vraiment récalcitrants il reste encore les manipulations du sorcier. La commande clearfun permet de supprimer une primitive et de la remplacer par son propre programme pour localiser une erreur éventuelle. Enfin il y a l'invocation à 4 niveaux du chef des sorciers : debug .

Quand le répertoire est bien rempli par des fonctions déboguées, efficaces, commentées... il reste à utiliser genlib pour en faire une librairie. La suite consiste à écrire les ``man'', la documentation pour pouvoir recevoir enfin la reconnaissance du monde entier.

``Tout s'écoule et se meut'' disait Protagoras; c'est pourquoi il faut souvent jouer avec les systèmes dynamiques pour comprendre ce qui nous entoure. On peut le faire avec Scilab mais c'est une autre histoire...

Scilab Group
Scilab@inria.fr
http://www-rocq.inria.fr/scilab/


This document was translated from LATEX by HEVEA.