Introduction à Scilab

extrait d'un document de Jean-Marc Steyaert
LIX, Polytechnique

Prononcer saïlab pour Sci-{entific} Lab...
Logiciel développé à l'INRIA (projet Méta), concurrent (clone?) gratuit de MATLAB
Outil de calcul numérique, pas de calcul formel, conçu pour aider à faire des simulations

Les objets de base

Le type des objets n'est pas déclaré explicitement; Scilab attribue automatiquement un type aux variables en fonction de leur première affectation :

Nombre
Booléen
Chaîne de caractères

Exemples :
Des constantes            %e, %pi, %i. %eps. %inf
Des nombres réels       -2, 1.1414, .3183098
Des booléens               %t et %f (vrai et faux)
Des chaînes                 "entrez la valeur de x"
"c''est la vie" -> c'est la vie

Scilab transforme et arrondit les nombres en nombres décimaux et livre ses valeurs avec discrétion

-->f=(sqrt(5)-1)/2
 f  =
    0.6180340  
-->f-0.6180340
 ans  =
  - 1.125E-08  

-->f-.61803398874989
 ans  =
    4.885E-15  
-->f-.6180339887498948
 ans  =
    1.110E-16  
-->f-.6180339887498949
 ans  =
    0.  
-->f-.618033988749894885
 ans  =
    0.  
-->\%eps
 \%eps  =
    4.441E-16

Scilab les assemble en tableaux de dimensions quelconques

-->b=3 
 b  =
    3.  
-->b(2,1)=5
 b  =
!   3. !
!   5. !
-->b(2,2)=7 
 b  =
!   3.    0. !
!   5.    7. !

On note que c'est toujours la même variable !

c=[1,2,3;4,5,6;..
7,8,9;10,11,12]
 c  =
!   1.     2.     3.  !
!   4.     5.     6.  !
!   7.     8.     9.  !
!   10.    11.    12. !

La matrice identit\'e
-->c=eye(3,3)
 c  =
!   1.    0.    0. !
!   0.    1.    0. !
!   0.    0.    1. !
-->c=eye(2,3)
 c  =
!   1.    0.    0. !
!   0.    1.    0. !
-->c=eye(3)
 c  =
    1.  
-->c=eye(2,2,2)
             !--error    42 
incompatible RHS  (right hand side)

De la place en g\'en\'eral
--> a=[1 2 3;4 5 6]
 a  =
!   1.    2.    3. !
!   4.    5.    6. !
--> matrix(a,1,6)
 ans  =
!   1.    4.    2.    5.    3.    6. !
--> matrix(a,3,2)
 ans  =
!   1.    5. !
!   4.    3. !
!   2.    6. !

Pour voir grand
-->z=zeros(100,100,10); 

-->z=zeros(100,100,100);
 !--error    17 
stack size exceeded! (Use stacksize function 
to increase it)
Memory used for variables :      6439
Intermediate memory needed:   1000007
Total  memory available   :   1000001
at line      11 of function zeros    called by :  
at line    15 of function zeros         called by :  
z=zeros(100,100,100);

Les expressions arithmétiques

Opérateurs de base : +, -, *, /, ^ sur les réels (comme en Java)

Etendus aux tableaux, dans leur sens usuel des mathématiciens : A*B produit matriciel, produit scalaire, produit extérieur selon les dimensions de A et B

Variantes pour traiter élément par élément : A.*B

Opérateurs sur les matrices : A' transposition, inv(A) inverse, A\b système linéaire, spec(A) spectre, etc.

Les expressions booléennes

Opérateurs de comparaison : == , < , > , <= , >= , <>

Opérateurs logiques : & , | , ~

Les primitives de contrôle

Conditionnelle :
if condition then
instruction, instruction,... else
instruction, instruction,... end

Conditionnelle en cascade avec elseif

Branchement :
select var_test,
case val1, instruction, instruction,...
case val2, instruction, instruction,...
...
else instruction, instruction,...
end

La suite d'instructions correspondant à la valeur de var_test est sélectionnée et exécutée.

L'usage du end est nécessaire dans les fonctions.

Exemples :

-->if 3<0 then
-->x=3 else   
-->x=5, y=7   
 x  =
    5.  
 y  =
    7.  


-->num=17
 num  =
    17.  
-->select num, case 1, y="",
-->case 17, y="ouf", z=2
 y  =
   ouf   
 z  =
    2.

Les primitives de contrôle : les boucles

Itération bornée :
for var=tableau,
instructions,
...
instructions,
end

Le tableau est fabriqué par un des constructeurs :
var = [1,2,3,5,7,11,13,17,19]
var = 1:.1:2      ([1,1.1,1.2,1.3,...,2])
var = rand(3,3)

La variable var est interne à la boucle : sa valeur est non définie dès la sortie de la boucle.

Dans le cas d'une itération matricielle, varprend successivement les valeurs des colonnes de la matrice.

Itération conditionnelle :
while condition,
instructions,
...
instructions,
end

Exemple (Syracuse) :
while x<>1,
if pmodulo(x,2)==0 then x=x/2
else x=floor((3*x+1)/2) end,
disp(x),
end

De l'usage du break dans les itérations : break fait sortir de la boucle qui le contient ;

while %t,           {%t == vrai}
if pmodulo(x,2)==0 then x=x/2
else x=floor((3*x+1)/2) end,
disp(x),
if x==1 then break end,
end

Idem pour les boucles for

Les fonctions

* Difficiles à utiliser à la console
* À définir sous Emacs puis télécharger

Forme générale de déclaration :
function [y1,y2,...,yk] = nomfonction(x1,x2,...,xl)
.....
corps de la fonction
.....
y1=..., instructions, ..., yk=...,
endfunction

Exemple :
function [y1,y2]=f(x1,x2)
y1=x1-x2
y2=x1+x2
endfunction

function bonjour(x)
for i=1:1:x
disp("Bonjour")
end
endfunction

Fonctions : les variables

Arguments : non modifiables
Résultats : seul moyen de passer de nouvelles valeurs
Variables internes : inconnues de l'extérieur

Exemple :
function [y]=testargs(x)
y=x+g          // g doit être globale
disp(g,"g = ") // pour les curieux
g(5,2)=17      // rien à voir avec l'autre !!
disp(g,"g = ") // bien sûr
endfunction

à essayer avec g=11...

Fonctions utiles en probas

L'aléatoire :
rand(n,m) -> matrice nxm
rand("loi"), loi=normal, uniform -> loi normale, uniforme
rand("seed",germe) pour changer le point de départ du générateur congruentiel.

la fonction grand permet de traiter encore plus de cas de lois (beta, binomial, chi, gamma, poisson, etc.)

Les affichages :
histplot(n,X,opts) -> n est un entier (nombre de classes) ou le vecteur des valeurs seuils, X est le tableau des valeurs, opts les paramètres comme dans plot2d
plot2d(X,Y,opts) -> X est le tableau des abscisses, Y est le tableau des ordoonnées, opts les paramètres comme dans histplot.

En général, si f est une fonction bien programmée, et si X est un vecteur, Y=f(X) sera le vecteur des ordonnées.

Comment ça s'utilise?

1. Ouvrir une fenêtre xterm, se mettre dans le répertoire désiré (Probas), ouvrir une fenêtre emacs et une fenêtre scilab.

2. Dans la fenêtre scilab lancer la commande
diary(td1.dia)
qui enregistrera le contenu de la session jusqu'à
diary(0)

3. Tester sous scilab le scénario de calcul, le traduire en fonctions dans la fenêtre emacs dans un fichier td1.sci; revenir dans scilab pour lire ce fichier et définir les fonctions qu'il contient
readf(td1.sci).


Les commandes Scilab

Petit résumé des principales commandes Scilab utiles
avec référence dans le manuel de Bruno Pinçon
par Jean-Marc Steyaert (steyaert@polytechnique.fr)

Ce résumé doit vous permettre de traduire vos modes de pensée algorithmique (acquis en Java dans le cours de Programmation) dans le langage de programmation Scilab sans pour autant en devenir un expert. Le style qui en résulte n'est souvent pas le meilleur possible, mais il a le mérite d'être sûr, clair et compréhensif. En l'absence d'outils de débogage commodes, mieux vaut déclarer soigneusement les tableaux avec leurs dimensions, ne pas utiliser les raccourcis Scilab qui risquent de vous perdre en cas de débordement ou de généralisation hasardeuse. En conséquence, il sera judicieux de considérer les tableaux comme des tableaux Java et non comme les objets matriciels ou vectoriels complexes de Scilab, sauf quand on on fait de l'algèbre linéaire. On fera juste une exception pour les tableaux mono-dimensionnels (assimilables à des vecteurs ligne ou colonne.

1. Constantes et types de base

Tous les nombres manipulés sont construits sur les réels; les entiers ne le sont que par initialisation ou par « hasard »:
->3*(1+1.E-50)-3 = 0.

Les constantes numériques de base sont %e, %pi, %i, %eps ainsi que les constantes boolénnes %t, %f pour vrai et faux. Le calcul sur les nombres complexes se fait de façon usuelle, sous la forme 2+3*%i par exemple. La constante %eps définit la précision relative des calculs: deux nombres qui diffèrent de moins du quart de cette constante (!) sont indiscernables. Elle vaut 4.441E-16.

2. Structures de données

2.1 Tableaux (p. 7-10)

La structure de base est le tableau initialisé et déclaré par exemple par
tableau=zeros(5,3) pour un tableau de zéros à 5 lignes et 3 colonnes,
tableau=eye(5,5) pour la matrice unité 5 x 5,
tableau=ones(5,1) pour un tableau de uns à 5 lignes et 1 colonne,
tableau=ones(1,5) pour un tableau de uns à 1 ligne et 5 colonnes.

Dans le cas des tableaux T de type (n,1) ou (1,n), on peut utiliser pour l'indexation le raccourci T(k) au lieu de T(k,1) ou T(1,k). Dans tous les autres cas une telle écriture produira des effets scabreux. C'est le seul raccourci que je conseille d'utiliser dans l'utilisation élémentgaire de Scilab.

On peut aussi déclarer des tableaux à trois dimensions et plus.

Scilab permet de manipuler les matrices ligne à ligne ou colonne par colonne. Je déconseille formellement d'utiliser ce genre de raccourci au moins au début.

2.2 Structures de données diverses (p. 32-38)

Les chaînes de caractères (p. 32) se définissent comme il est d'usage entre apostrophes doubles: "vive l''info". Je recommande vivement d'utiliser les apostrophes doubles pour définir les chaînes de caractères et de réserver l'apostrophe au symbole ou à l'opérateur de transposition matricielle.

Une structure de liste, un peu fourre-tout, est disponible, mais qu'on ne devrait pas avoir à utiliser (p. 33-36).

3. Opérations de base

On rencontre les mêmes que dans tous les autres langages de programmation.

Les expressions arithmétiques étendues aux matrices (p. 21-27):
- opérateurs de base : +, -, *, / sur les réels (comme en Java), ^ étant l'opérateur puissance
- opérateurs étendus aux tableaux, dans leur sens usuel des mathématiciens : A*B produit matriciel, produit scalaire, produit extérieur selon les dimensions de A et B
- variantes pour traiter élément par élément : A.*B
- opérateurs sur les matrices : A' transposition de A, inv(A) inverse de A,
A\b résolution du système linéaire Ax=b, spec(A) spectre, etc.
- les opérateurs de somme sum et de produit prod sur les éléments d'un tableau (p. 24).

Les expressions booléennes:
- opérateurs de comparaison : == , < , > , <= , >= , <>
- opérateurs logiques : & , | , ~

Des fonctions mathématiques usuelles : p. 12

Des fonctions de génération aléatoire :
- rand pour la plus simple (p. 79)
- grand qui permet plus de paramétrages (p. 84).
Une variable est associée à chaque générateur qui sert à avancer dans le calcul de la séquence pseudo-aléatoire; on l'appelle semence (seed), on la découvre par l'opération semence=rand("seed") et on peut la modifier, par exemple pour recommencer les simulations avec le même jeu de valeurs, au moyen de rand("seed",valeur). (p. 80)
Un mécanisme semblable, mais plus complexe existe pour la fonction grand. (p. 85)

Des exemples d'opérations sur les tableaux (p. 12-14):
produit scalaire, produit matriciel, produit extérieur, transposition, et multiplication/division élément par élément

Des exemples de résolution de systèmes linéaires: p. 15-17.

4. Fonctionnelles de calcul

Ce sont les mêmes qu'en Java. Seule la syntaxe change un peu.

Conditionnelles (p. 31):
if (<condition>)
<liste d'instructions>,
else <liste d'instructions>, end
où une liste d'instructions est une suite d'instructions séparés par des virgules et se termine toujours par une virgule. Par exemple:
if (x>5), y=4,z=5, else z=2,y=2, end

ou encore mieux, plus lisible et plus sûr:
if (x>5),
y=4,z=5,
else
z=2,y=2,
end

Plus généralement on peut mettre en cascade les conditionnelles avec des elseif comme par exemple:
if (<condition>)
<liste d'instructions>,
elseif (<condition>),
<liste d'instructions>,
...
elseif (<condition>),
<liste d'instructions>,
else <liste d'instructions>,
end

Attention! Je déconseille l'usage du then car il est source d'ennuis lors de l'exécution s'il est mal placé sur la ligne (les then ne doivent jamais se trouver en début de ligne, il faut les mettre sur la même ligne que la condition).
Je conseille de plus de mettre la condition entre parenthèses pour plus de clarté.

Aiguillages sur une variable entière (p. 31):
select var_test,
case expr1 <liste d'instructions>,
case expr2 <liste d'instructions>,
...
else <liste d'instructions>,
end

Comme d'habitude on exécute la suite d'instructions qui correspond à la premi`ere expression rencontrée dont la valeur est celle de la variable de test; par défaut on exécute celle du else.

Itération bornée (p. 29):
for var=tableau
<liste d'instructions>,
end

La variable var, qui doit être une variable scalaire pour ne pas compliquer les choses, prend toutes les valeurs stockées dans l'expression tableau, successivement selon l'ordre induit par les colonnes du tableau. Le tableau le plus couramment utilisé est de type vecteur: (debut:pas:fin) qui en extension donne la suite d, d+p, d+2p,..., f, où d, p, f sont les valeurs respectives des expressions debut, pas et fin. On peut omettre pas lorsqu'il vaut 1.

Attention! La variable de boucle n'est active que pendant l'exécution de la boucle; elle est ignorée en dehors. Si on veut récupérer sa valeur, il faut le faire explicitement au moyen d'une autre variable.
Si par hasard la variable de boucle était de type tableau, l'exécution se ferait en mode vectoriel: à éviter absolument pour commencer!

Itération conditionnelle (p. 30):
while condition,
<liste d'instructions>,
end

Cette instruction est, en tous points, semblable à celle de Java. La seule erreur serait d'oublier les virgules nécessaires après la condition et avant le end.

L'instruction break permet de sortir d'une quelconque de ces primitives.

6. Fonctions (p. 38-43)

Elles sont difficiles à définir à la console; il faut les définir sous Emacs ou Nedit puis les importer dans la fenêtre Scilab par getf. Le résultat, s'il y en a un, est indiqué sous la forme d'une liste (au sens de 2.2).

Forme générale de déclaration :
function [y1,y2,...,yk] = nomfonction(x1,x2,...,xl)
.....
corps de la fonction
.....
y1=..., instructions, ..., yk=...,
endfunction

Exemple :
function [y1,y2]=f(x1,x2)
y1=x1-x2
y2=x1+x2
endfunction

Exemple :
function bonjour(x)
for i=1:1:x
disp("Bonjour")
end
endfunction

Il est impératif de donner une valeur aux diverses variables qui vont former le résultat. Cependant, il importe aussi de respecter un format de sortie qui est celui d'une liste hétérogène (voir 2.2). Avec le format complexe
function [y1,y2,...,yk] = nomfonction(x1,x2,...,xl)
il est impératif de donner au résultat, dans l'appel de la fonction, le format attendu: [z1,z2,...,zk] = nomfonction(x1,x2,...,xl),
comme le montrent les exemples suivants. (Voir aussi les p. 93-94 pour d'autres commentaires.)

-->function [y]= titi(x) -->y=[x,x,x] -->endfunction -->titi(3) ans = ! 3. 3. 3. ! -->function y=tata(x) -->y=[x,x,x] -->endfunction -->tata(3) ans = ! 3. 3. 3. ! -->titi(3)==tata(3) ans = ! T T T ! // pour s'amuser, on fait du boole'en -->function [y1,y2]=tutu(z) -->y1=z+2 -->y2=z-2 -->endfunction -->tutu(3) ans = 5. -->[x1,x2]=tutu(3) x2 = 1. x1 = 5.

Pour le passage des arguments, c'est un avatar des conventions de Java, et on les trouvera dans les résumés du cours ainsi qu'aux p. 40-41.

Enfin la fonction error(message) permet de sortir proprement d'une fonction en imprimant un message (p. 43).

Attention! L'usage de listes complexes et hétérogènes en sortie conduit à des erreurs d'exécution.

7. Fonctions d'affichage

7.1 Les principes

Pour déboguer une fonction ou un ensemble de fonctions, il faut placer dans le corps du texte des instructions supplémentaires qui permettront d'ob server les valeurs des variables importantes. En cours d'exécution on verra apparaître ces valeurs sur la console Scilab:
disp(liste_variable) imprime sur la fenêtre de travail les valeurs des variables de la liste qui s'imprime en sens inverse (de droite à gauche). En aucun cas cette instruction ne permet-elle d'affecter un résultat à une fonction.

Très importantes sont les fonctions d'affichage graphique qui permettent représenter des graphes fonctionnels et des histogrammes. Fondamentalement, elles sont de deux types:
- les fonctions plot2d(vx,vy,options) et leurs variantes (p. 58-62) qui prennent les deux tableaux vx et vy,qui doivent être de même dimension, et qui construisent alors le graphe de la fonction vy en fonction de vx, tout en suivant les directives de couleurs, de pointillés, etc. indiquées dans les options. - la fonction histplot(vx,vy,options) qui procède semblablement mais répartit les éléments de vy selon le découpage imposé par vx. (cf. p. 83).

Ne pas oublier que les graphiques se superposent dans une même fenêtre et qu'on peut la nettoyer au moyen de la fonction xbasc(). D'autres fonctions de gestion des fenêtres graphiques sont explicitées p. 57.

7.2 Exemples

Pour terminer cette section, voici quelques explications complémentaires concoctés par Michel Delasnerie.

La fonction 'plot2d2( x, y)' trace une fonction 'en escalier', les vecteurs 'x' et 'y' doivent être de même type (ligne ou colonne) et de même dimension : le graphe est horizontal de 'x(1)' à 'x(2)' d'altitude 'y(1)' et ainsi de suite... mais d'après le célèbre théorème "piquets/intervalles" la dernière valeur de 'y' - à savoir 'y($)' - n'est représentée que comme une verticale d'abscisse 'x($)' de 'y($-1)' à 'y($)' et non par un trait horizontal, la dernière marche manque ! Pour la tracer il faut rajouter - à droite de 'x' un piquet de plus de valeur appropriée ; - à droite de 'y' une valeur fictive ( 0 ou 'y($)'). (remplacer 'a droite' par 'en bas', dans le cas de colonnes)

Exemple :
-->x = 1:4
 x  =
 
!   1.    2.    3.    4. !
 
-->[x,5]
 ans  =
 
!   1.    2.    3.    4.    5. !

--> y = x;

-->y($)
 ans  =
 
    4.  
 
-->[y, y($)]
 ans  =
 
!   1.    2.    3.    4.    4. !


-->xbasc(); plot2d2( x, y, 1, "011", " ", ..
                     [0,0,6,5], [0,6,0,5])           

--> // Il manque la dernie`re marche (que le saut)
 
-->xbasc(); plot2d2( [x,5], [y,y($)], 1, "011", ..
                     " ", [0,0,6,5], [0,6,0,5])
 
--> // Maintenant elle y est (en entier) !

Les arguments optionnels ont été délibérément choisis pour que le cadre déborde largement [de +1] tout autour du graphe.

La fonction 'hisplot( x, data)' a comme arguments principaux deux vecteurs (eventuellement de types distincts) - 'x' est une suite de piquets encadrant des intervalles ; - 'data' des données, aléatoires ou non, en quantité, en général, beaucoup plus grande que la taille de 'x'. 'hisplot' commence par calculer l'histogramme des 'data' en fonction des intervalles déterminés par 'x' comme à la page 18 du polycopié 'Aléatoire' de Francis Comets, puis en trace le graphe 'en rectangle'.

Ces deux fonctions ne font pas le même travail, 'histplot' en fait plus : pour que 'plot2d2' fasse la même chose l'argument 'y' doit être calculé avec la formule des histogrammes (les fréquences normalisées par les longueurs d'intervalle) à partir de données ou de tirages aléatoires.

8. Lecture et écriture sur fichier

Pour charger un fichier de définitions de fonctions on utilise la primitive getf ("nom_de_fichier"); si l'une des fonctions a été modifiée un avertissement le signale:
->getf("poisson.new.sci")
Warning :redefining function: loipoisson2

Pour sauver un ensemble de valeurs, ou en acquérir depuis un fichier, on utilisera les fonctions save et load qui permettent de sauver dans un fichier des variables, ou de les charger depuis une sauvegarde: voir p. 18:
- save("fichier", liste de variables)
- load("fichier", liste de noms de variables).

On peut aussi utiliser des mécanismes plus sophistiqués, inspirés de Fortran comme les fonctions write et read, dont la syntaxe type est la suivante:
write(unit,variable,format)
write(unit,nombres,format).
Dans ces expressions: - unit est un nom de fichier (éventuellement %io(1) pour la fenêtre Scilab en lecture et %io(2) pour la fenêtre Scilab en écriture);
- variable est une expression Scilab dont la valeur sera écrite dans le fichier;
- nombres est une suite d'entiers ou de variables entières) qui indique le nombre de lignes et/ou d'objets à lire dans le fichier;
- format indique comment les valeurs sont codées dans le fichier (ce paramètre est facultatif).

On trouvera des exemples commentés en section 3.5.7 (p. 48-51).

9. Les bidouilles au niveau exécution (le "toplevel")

Les commandes suivantes ont aussi leur intérêt:
- who : pour lister les variables actives (p. 19, p. 41)
- timer() : pour estimer un temps de calcul (p. 52)
- stacksize(taille) : pour changer la hauteur de pile (p.19)
- clear v : pour supprimer la variable v de l'environnement.

La barre de menus dans la fenêtre d'exécution Scilab comprend plusieurs touches utiles:
1. File :
- « file operations » permet de charger des fichiers,
- « kill » ferme la fenêtre,
- « quit » élimine le calcul courant suspendu;
2. Control :
- « stop » suspend le calcul (on augmente la pile d'exécution),
- « resume » le reprend,
- « abort » tue le calcul suspendu et replace au niveau inférieur,
- « restart » remet Scilab dans son environnement initial (et on perd tout);
3. Graphic Window : aide à la gestion des fenêtres;
4. Help : l'aide en ligne.

10. Les erreurs d'exécution

En voici un petit florilège qui ne manquera pas de prospérer.

error 8 : addition incohérente

error 10 : multiplication incohérente

error 21 : index invalide

error 42 : incompatible RHS (membre droit d'instruction)

error 58 : incorrect number of arguments in function call

error 241 : File exo1.sci does not exist or read access denied
Vous vous êtes trompé de fichier ou vous êtes sans doute dans un mauvais répertoire. Changez de fichier, ou bien fermez Scilab, changez de répertoire, relancer Scilab et recommencez.


Jean-Marc Steyaert 2002-05-30