Vous êtes sur la page 1sur 195

Maple expliqu

Francis Sergeraert

Chapitre 1
Premires sessions Maple
1.1 propos du systme d'exploitation utilis.
Le logiciel Maple est utilisable sur tout poste de travail Windows, Mac ou
Unix, aprs une installation du logiciel, trs simple, surtout sous Windows et Mac.
Une fois le logiciel install, les procdures d'utilisation sont les mmes, des dtails
minimes prs, qui ne concernent jamais l'essentiel de ce qui est fait avec ce logiciel.
Les micro-dirences sont dues aux traditions plus ou moins bien dnies pour
chaque environnement, et aussi aux ressources disponibles dans chaque systme
d'exploitation. Pour ne pas alourdir inutilement la prsentation, on ne considrera
ici que le cas de Maple utilis sous Windows.
Pour rassurer le lecteur angoiss, examinons immdiatement une telle dirence
an d'en mettre en vidence la futilit1 . Frquemment l'utilisateur doit ouvrir une
nouvelle fentre, il faut dire une nouvelle feuille de travail (worksheet). L'utilisateur
Windows a trois mthodes quivalentes pour le faire :
1. Il peut cliquer sur le premier bouton de la barre d'outils, dont l'icne reprsente une feuille vierge corne en haut droite. La feuille vierge souhaite
s'ouvre aussitt.

2. Il peut drouler le menu File, l'aide de la souris ou s'il prfre l'aide de


la touche Alt-F ; ensuite il slectionne l'option New de ce menu, nouveau
l'aide de la souris ou bien de la touche clavier N. La nouvelle feuille de
travail est alors ouverte.
1 Le

lecteur dbutant complet n'est pas concern par le reste de cette section.

3. L'indication Ctrl-N sur la ligne New du menu informe l'utilisateur qu'il


aurait obtenu exactement le mme rsultat avec la touche Ctrl-N. C'est,
indpendamment du logiciel utilis, le standard Windows en l'occurence ;
c'est facile retenir et c'est de loin la mthode la plus rapide.
Pour une session Maple sous Unix, le processus est exactement le mme
ceci prs que la troisime possibilit est exclue. L'utilisateur Unix prend donc vite
l'habitude d'utiliser la premire mthode ci-dessus, en utilisant le bouton page
vierge.
D'une faon gnrale les dirences entre Maple-Windows, Maple-Mac et
Maple-Unix ne concernent que des points trs accessoires de gestion d'dition,
de gestion de fentres et de chiers. Presque toujours les processus particuliers
tel systme d'exploitation respectent les habitudes de ces systmes ou encore, cas
de Maple-Unix, les traditions Emacs, considres comme les plus naturelles pour
les universitaires Unix. Par exemple, sous Maple-Unix, la touche Ctrl-N, au lieu
d'ouvrir une fentre, descend le curseur d'une ligne sur la feuille de travail active,
conformment la tradition Emacs.
On ne peut pas ne pas signaler que l'ensemble des raccourcis claviers standard
de Windows, bien conu, rend l'ergonomie Maple sensiblement meilleure sous Windows que sous Unix. On observe un autre inconvnient sous Maple-Unix : il est
relativement frquent que certains raccourcis claviers en principe valides sous Unix
deviennent soudain inoprants, sans raison connue. Le phnomne a t constat
sous des systmes Unix dirents, en particulier Linux. Esprons que quand le
prsent manuel paratra, ce problme sera x, selon l'anglicisme la mode.
Mais pour tous les points importants, notamment les points mathmatiques,
les trois environnements sont rigoureusement identiques et la question du systme
d'exploitation utilis est ds lors sans objet.

1.2 Description de la fentre Maple.


On peut lancer une session Maple de plusieurs faons :
1. En cliquant sur l'icne approprie dans un dossier ou sur le bureau Windows ;

2. En droulant les menus accessibles partir du bouton Dmarrer jusqu'


atteindre l'option citant Maple 62 ;
3. En entrant la commande 3 approprie dans une fentre de dialogue avec le
systme, par exemple la fentre Excuter.
4. En utilisant un raccourci clavier, selon la mthode banale sous Windows ;
c'est cette mthode qui est la plus commode si on envisage un usage relativement frquent de Maple.
Une fentre Maple est alors ouverte par le systme o l'utilisateur va pouvoir
dialoguer avec le programme Maple. Cette fentre est organise comme suit.

Le haut de la fentre est un bandeau contenant le titre :


Maple 6
Les releases (versions) actuellement en usage sont gnralement les releases 4, 5,
6 ou 7, la dernire tant la plus rcente4 . Les dirences entre les releases 4 et 5
sont assez signicatives5 , la release 4 devant devenir rapidement obsolte.
Du ct droit du mme bandeau, on trouve les mini-boutons usuels Windows,
savoir, de gauche droite :
1. Le bouton
servant faire disparatre provisoirement la fentre de l'cran,
en ne conservant que le bouton barre des tches pour une restauration ultrieure ;
2 Ou

l'indication correspondante pour une version dirente, plus ancienne ou plus rcente.
C:\Program Files\Maple 6\BIN.WNT\wmaple.exe, berk !
4 Ce manuel a t prpar avec la Release 6 ; pendant sa prparation, la release 7 est parue ;
les dirences avec la release 6 sont, pour ce qui concerne notre sujet, ngligeables.
5 Ces dirences ne sont pas anodines ; sur beaucoup de questions la release 5 est beaucoup
plus commode que la release 4. En particulier la release 5 permet la programmation fonctionnelle,
.
outil capital pour beaucoup de questions, qu'on examinera en temps utile, voir
3 Probablement

2. Le bouton
servant agrandir la fentre en plein cran ou au contraire
la rduire en cran partiel ;
3. Le bouton

terminant dnitivement la session Maple.

L'usage de ces boutons est banal et il n'y a pas lieu d'en parler. Si la fentre est
en cran partiel, sa taille et sa position peuvent tre modies par les procdures
habituelles.
Sous le bandeau titre, on trouve le bandeau des menus :

Le nombre et la nature des menus dpendent du contexte mais, en cours de


travail ordinaire, on voit les menus File, Edit, View, Insert, Format, Options,
Windows et Help. Les deux menus File et Help sont toujours prsents. On droule un menu avec la souris en cliquant sur son entte ou en entrant au clavier la
combinaison Alt- ? approprie, par exemple Alt-F pour le menu File. Quand le
menu souhait est droul, on active l'option souhaite par un clic de souris ; on
peut aussi, aprs avoir slectionn l'option souhaite l'aide de la touche directionnelle , activer cette option avec la touche <Entre>6 . Certaines options
ouvrent leur tour un sous-menu. Comme dj expliqu, de nombreuses options
de menus ont des raccourcis claviers indiqus en face de l'option correspondante
sur le menu, permettant d'obtenir le mme rsultat souvent plus facilement.
On trouve ensuite, sous le bandeau des menus, la barre d'outils :

C'est un ensemble de boutons-icnes disposs sur deux lignes, reprsentant de


faon image telle ou telle action qu'on peut obtenir aussi bien en gnral par menu
droulant ou par raccourci-clavier, mais pour donner une chance supplmentaire
l'utilisateur de trouver ce qu'il cherche, les actions les plus importantes ont presque
toutes un quivalent bouton. L'action correspondante est active en cliquant sur
le bouton appropri, quand il existe. La deuxime ligne de la barre d'outils dpend
du contexte.
Certains clics intempestifs ou accidentels mettent frquemment en srieuse difcult les utilisateurs dbutants, notamment quand le mode Texte est activ inopinment par le bouton

et qu'on ne sait pas le grer.

Conseil 1  Ne cliquez pas sur les boutons de la barre d'outils tant que vous

n'avez pas raisonnablement compris leur usage. Pour ce faire, faites en d'abord au
besoin l'exprience sparment dans une micro-session Maple ddie uniquement
cette question. Sinon, abstenez-vous prudemment.
6 <Return>

sur les claviers anglais.

Il peut vous tre utile dans ce registre d'activer l'option Balloon Help du menu
Help ; si ceci a t fait, le passage du pointeur souris sur un bouton provoque
l'achage d'une bulle explicative sur la nature du bouton. On avait montr un
exemple page 1. Cette explication n'est pas toujours susante pour le dbutant.
Certains boutons ont deux positions ; l'une o (bouton en attente) indique que
l'option correspondante est pour le moment inactive, l'autre on (bouton pouss)
indique au contraire que l'option est active. Par exemple le mode Text est inactif
si le bouton

est o :

Au contraire le mode Text est actif si le bouton

est on :

Noter que la ligne infrieure de la barre d'outils, la partie dite dpendante du


contexte, dpend de l'option en cours.
Si vous tes utilisateur dbutant, vitez soigneusement d'utiliser le mode Text,
servant prparer des commentaires sophistiqus pour les calculs prvus. Le chapitre
est entirement consacr ces questions, assez techniques, mais puissantes en moyens d'expression. Dans la premire phase o seuls les calculs Maple
vous intressent, le mode Text ne vous concerne pas.
Il peut arriver que vous activiez par mgarde le mode Text ! Vous vous en apercevez par le fait que les caractres entrs au clavier apparaissent mystrieusement
noirs sur l'cran :

Le plus simple est alors d'utiliser, plusieurs fois au besoin, la touche Ctrl-Z
(Undo Typing) jusqu' revenir au mode standard. Autre solution, on balaie la
zone trange avec la souris en dbordant un peu sur la zone standard :

puis on utilise la touche <Suppr> pour la faire disparatre.


D'o l'importance du conseil suivant.

Conseil 2  Pendant la phase de premire initiation Maple, n'utilisez pas le


mode Text. Vous pourrez insrer, si vous y tenez absolument, des commentaires

dans vos commandes Maple par le procd de tous les langages de programmation :
sur toute ligne de commande, le caractre #, sans changer de mode, indique
Maple que le texte qui le suit sur sa ligne est un commentaire. Ceci sut largement
pendant l'initiation.
Exemple de simple commentaire :

Exemple de commentaire sophistiqu :

Selon le contexte, d'autres mini-fentres s'ouvrent dans l'entte de la fentre


Maple, par exemple pour choisir une police et sa taille quand on est en mode Texte,
pour modier l'angle de vue d'un graphique 3D. Ces questions seront examines
en temps utile.
La partie principale de la fentre Maple est la feuille de travail (worksheet)
qu'on a encadre ici en rouge :
6

Une autre version de la disposition gnrale peut tre la suivante, o la feuille


de travail est plein cran par rapport la fentre Maple :

Il est important de bien comprendre dans un tel cas que les boutons Windows
de la feuille de travail sont achs sur la partie droite du bandeau des menus, juste
au-dessous des boutons analogues pour la fentre Maple entire, mthode gnrale
Windows trs commode l'usage mais qui surprend toujours les dbutants. On les
indique ici l'aide de notre che rouge :

On passe de la version cran partiel la version plein cran de la feuille de


travail en cliquant sur son bouton Windows
et inversement on revient l'afchage cran partiel en cliquant sur le bouton
. On procde de mme pour la
fentre entire Maple par rapport l'cran du moniteur en cliquant sur les boutons
analogues de la fentre Maple cette fois, l'extrme nord-est de la fentre.
Le bandeau infrieur de la fentre Maple donne droite un certain nombre
d'indications, sur le temps CPU dj consomm, sur l'espace mmoire dj mobilis, sur l'espace disque disponible. Sauf calculs d'envergure, ces indications sont
de peu d'utilit.

1.3 Premire session.


Le programme Maple permet comme la quasi-totalit des logiciels modernes de
mener de front plusieurs travaux, notamment par l'intermdiaire d'un systme de
multi-fentrage. Maple suit les traditions Windows maintenant bien tablies. On
en voque ici quelques aspects, juste pour indiquer au lecteur les grandes lignes
des disponiblits, assez secondaires par rapport notre sujet. L'exprience montre
que les prfrences des utilisateurs ce propos sont trs variables : chacun son
style.
Considrons la situation initiale standard :

Si l'utilisateur souhaite connatre une valeur numrique de sin(/5), il entre


au clavier evalf(sin(Pi/5)) ;, puis la touche <Entre> ; ne pas oublier la majuscule Pi et le point-virgule ` ;' terminal avant la touche <Entre>. Il obtient le
rsultat suivant :

Il peut alors dcider d'ouvrir une autre fentre avec la touche7 Ctrl-N :

puis dans cette nouvelle fentre demander de rsoudre l'quation x4 2 = 0 :

7 Voir

Section 1.1.

On voit que la deuxime fentre est active (foreground) alors que la premire est
passive (background) ; noter en particulier les couleurs des bandeaux des fentres
selon leur tat. On peut nanmoins prfrer voir simultanment les deux fentres ;
ceci est obtenu en demandant l'option Vertical du menu Window :

On voit que Maple rpartit exactement, verticalement, l'espace disponible entre


les fentres ouvertes.

10

Un systme d'aide l'utilisateur, trs riche, trs bien conu, est accessible par
le menu Help. Par exemple, si on souhaite voir la documentation de base de la
procdure Maple prdnie solve, on demande l'option Topic Search du menu
Help :

ce qui fait apparatre une fentre de dialogue o on peut entrer le nom de la


procdure pour laquelle la documentation est souhaite :

11

On obtient :

Sur la reproduction donne ici, la fentre aide est minuscule et l'aide est en
dnitive invisible moins de faire passer cette fentre en mode plein cran, en
:
cliquant sur son bouton

12

puis en faisant glisser le bouton ascenseur, montr ci-dessus par la che rouge, on
peut atteindre la partie qui nous intresse :

La jolie quation montre dans la documentation peut nous intresser, d'o


l'ide de l'essayer dans notre feuille de travail ; un balayage de souris permet de
slectionner cette quation :

13

puis la touche Ctrl-C ou le bouton


copie le texte slectionn dans le pressepapiers (clipboard), pour utilisation ultrieure.
On peut maintenant retourner la deuxime fentre en demandant l'option
2 Untitled(2) du menu Window :

et on retrouve bien notre fentre, qui est d'ailleurs passe aussi en mode plein
cran comme la fentre d'aide :

14

La touche Ctrl-V ou le bouton


permet alors de recopier notre quation l o
le curseur tait rest positionn dans la feuille de travail ; la touche <Entre>
demande l'valuation et donne le mme rsultat que celui qui tait montr dans la
documentation :

On apprendra plus tard qu'on a ainsi aect au symbole eq un objet equation ; on


peut maintenant demander la rsolution de cette quation comme il tait montr
dans la documentation :

15

Etc. etc. etc.


Il est absolument inutile de chercher ds le dbut connatre toutes les possibilits de ce systme de fentrage ; vous le dcouvrirez petit petit au gr de
vos expriences et aussi quelquefois en observant d'autres utilisateurs au travail,
exprience souvent bien utile.
Habituellement, au cours d'une session, l'utilisateur a une feuille de travail
principale, celle o il fait les calculs les plus importants, les organisant selon un
ordre squentiel logiquement dni. Souvent l'utilisateur voudra sauvegarder sa
feuille de travail, par exemple pour la rutiliser pour une dmonstration ; plus souvent il s'agira de continuer ultrieurement un travail commenc mais pas termin ;
d'autres fois il s'agira d'amliorer la feuille de travail pour y modier une mthode de calcul, en amliorer la prsentation, etc. On expliquera un peu plus loin
comment grer ces questions.
Nous supposerons toujours dans ce manuel qu'une seule feuille de travail est
active, ce qui nous permettra de parler sans ambigut de la feuille de travail.
C'est un espace de travail o l'utilisateur crit des commandes Maple, demande
Maple de les excuter, corrige telle commande, la fait rexcuter, ajoute une
nouvelle commande, la fait excuter, fait excuter l'ensemble de toute la feuille,
etc. De temps autre, la feuille de travail sera cache derrire une feuille d'aide,
demande par le menu Help ou un moyen quivalent.
Pendant la mme session l'utilisateur voudra de temps autre mener de petites
expriences annexes sans risquer de trop abmer sa feuille de travail principale.
Il ouvrira alors une ou plusieurs feuilles annexes dures de vie souvent assez
courtes qu'il sera rarement ncessaire de sauvegarder. Il peut aussi travailler en
parallle sur plusieurs feuilles de travail principales8 .
8 Dans

la conguration standard, les calculs eectus sur une feuille sont connus des autres
feuilles, et il ne s'agit donc pas d'un vrai paralllisme ; l'option -km p de la commande
systme lanant Maple demande au contraire que les direntes feuilles s'ignorent compltement
et plusieurs sessions direntes peuvent alors tre menes de front.

16

Frquemment notre utilisateur va devoir consulter l'aide en ligne de Maple.


Divers procds lui permettent d'acher des feuilles d'aide dcrivant l'usage de
telle ou telle procdure, comprenant presque toujours des exemples typiques pour
en expliquer plus facilement le fonctionnement.
L'utilisateur va devoir grer ses fentres. Acqurir assez rapidement un bon
style en la matire est important. Les dbutants ont tendance laisser ouvertes
beaucoup trop de feuilles d'aide ; ils sont alors aussi l'aise pour travailler que sur
un bureau ordinaire quand d'innombrables papiers, livres et canettes de bire y
sont entasss. . .

Conseil 3  Le plus souvent on peut s'organiser dans une session pour avoir une

seule feuille de travail principale, au plus une seule feuille de travail petite exprience, supprimer ds que la dite exprience est termine. Enn il est prfrable
de dtruire les feuilles d'aide ds que leur consultation est termine ; le cas chant
on peut les rouvrir trs facilement.

1.4 Deuxime session.


Si Maple est lanc directement9 , il apparat avec une seule feuille de travail
vierge intitule [Untitled-(1)], titre visible sur le bandeau-titre de la fentre. On
agrandit au besoin la grande fentre Maple en plein cran en cliquant sur le bouton
Windows
en haut droite de la fentre. On agrandit aussi la feuille de travail
en plein cran par le mme procd, l'aide de ses propres boutons :

Le curseur, un trait vertical, indpendant du pointeur souris, clignote au dbut


de la feuille de travail vierge derrire le prompt Maple, savoir les caractres [>.
9 Sous

Windows, Maple peut aussi tre lanc en ouvrant un chier feuille de travail, dont le
code extension est normalement .mws ; le cas chant, la feuille en question est pralablement
installe dans la session ; voir cependant ce qui est expliqu Section 1.5.

17

En fait le crochet ouvrant [ n'est pas un caractre, c'est une sorte d'accolade
pour indiquer la porte d'un groupe d'excution (Execution Group), notion qu'il
est inutile de dtailler pour le moment ; vous verrez clairement de quoi il s'agit par
la suite. Dans les exemples cits dans ce manuel, nous ne montrerons pas, sauf cas
trs particuliers, ces indicateurs. Le seul prompt Maple est en fait le caractre >.
Comme premier exemple de travail Maple, supposons qu'on souhaite valuer
l'intgrale suivante :
Z
1+x
dx,
1 + x2 + x4
1
Il faut entrer :
..................................................................................................................................

> int((1+x)/(1+x^2+x^4), x=1..infinity) ;|

..................................................................................................................................

Le texte entr est une expression Maple-Input, constitue d'une suite de caractres
ASCII, forme externe d'un objet Maple dont on s'apprte demander l'valuation.
Pour ce faire, aprs avoir entr le  ; terminal, indispensable, on tape la touche
<Entre>. Il est important de comprendre ce point que cette touche <Entre>
n'est en aucune faon le caractre de passage la ligne suivante comme dans
presque tous les traitements de texte. Conventionnellement, sous Maple, cette
touche demande Maple l'valuation de tous les objets du groupe d'excution
o le curseur est positionn ; ici ce groupe est rduit la seule ligne dnissant
l'intgrale cherche. Une fois que cette touche <Entre> est. . . entre, Maple
value l'intgrale demande et ache le rsultat comme suit :
..................................................................................................................................

> int((1+x)/(1+x^2+x^4), x=1..infinity) ;


5
1
3 ln(3)
36
4
> |

..................................................................................................................................

Les manuels grand public prfrent souvent montrer une copie bitmap de
la fentre obtenue :

18

On voit que c'est beaucoup plus encombrant et souvent nalement bien moins
prcis que ce qui est indiqu par une typographie standard simulant avec une bonne
approximation ce qui est observ dans la fentre Maple. On n'utilisera dsormais
une copie exacte d'une fentre Maple que dans des circonstances relativement
exceptionnelles.
On a donc obtenu le rsultat :
Z
1+x
5
1
dx =
3 ln 3,
2
4
1+x +x
36
4
1
dj pas si facile atteindre avec papier-crayon.
Trs souvent, comme la syntaxe requise pour entrer les expressions valuer est
relativement complexe et ne pardonne aucune imprcision, l'utilisateur Maple fait
des fautes de natures assez varies, demandant un minimum de lucidit, quelquefois
beaucoup, pour tre identies puis corriges. Supposons par exemple que nous
oublions dans l'entre de l'expression intgrale la premire parenthse fermante,
celle qui ferme le numrateur (1+x_ : Maple ache alors un message d'erreur en
petits caractres mauves, sur la ligne infrieure :
..................................................................................................................................

> int((1+x/(1+x^2+x^4), x=1..infinity) |;


`;` unexpected

..................................................................................................................................

Le curseur clignote devant le point-virgule terminant la ligne entre, pour indiquer


le point o une anomalie a t dtecte : il est incohrent de trouver un  ; terminant une instruction alors que la premire parenthse ouvrante n'a pas encore de
parenthse fermante associe. Comme c'est souvent le cas, Maple ne pouvait pas
deviner que la parenthse manquait aprs (1+x_. Continuons faire l'ne et insrons une nouvelle parenthse juste avant le point-virgule terminal. Ds que cette
parenthse est insre, on peut immdiatement taper <Entre> pour demander la
rexcution de la commande, quel que soit le point o le curseur y est positionn ;
il est en particulier inutile de repositionner le curseur aprs le point-virgule.
..................................................................................................................................

> int((1+x/(1+x^2+x^4), x=1..infinity)) ;

> |

..................................................................................................................................

Pas d'erreur dtecte, mais le rsultat n'est pas exactement celui qui est espr ! Vu
l'apparente correction du rsultat ( !), Maple a ouvert un nouveau groupe d'excution o il a positionn le curseur en attente de l'expression suivante valuer.
Notre intgrale semblait convergente, et pourtant Maple donne le rsultat ,
signiant au contraire qu'il l'a trouve divergente. Le mcanisme d'appel de procdure de Maple est trs puissant, mais de temps autre il implique que ce qui est
en fait une erreur d'entre russisse tre interprt d'une faon assez surprenante pour l'utilisateur non initi. Il se trouve qu'ici l'expression valuer, malgr
l'apparente faute de parenthsage, est tout--fait correcte pour Maple, sauf qu'il a
valu en fait :

Z
x
dx,
1+
1 + x2 + x4
1
19

qui est bien une intgrale divergente. Il n'est pas vraiment vident de comprendre
comment Maple a pu aboutir cette interprtation ; nous verrons ce point en temps
utile, voir page 115. On entre ici en debugging proprement dit. Il faut lucider
comment Maple a pu obtenir ce rsultat bien troublant. L'examen soigneux de
l'expression entre nit par faire comprendre que le numrateur 1+x de l'intgrande
n'est pas correctement parenths. On positionne le curseur derrire le x critique
par un clic de souris ou l'aide des touches directionnelles du clavier (,,
et ) et on ajoute la parenthse manquante ; on tape <Entre> et on obtient
ce rsultat :
..................................................................................................................................

> int((1+x)/(1+x^2+x^4), x=1..infinity))


| ;
`)` unexpected

..................................................................................................................................

On a cette fois une parenthse en trop ! On l'eace et on obtient enn un rsultat


correct :
..................................................................................................................................

> int((1+x)/(1+x^2+x^4), x=1..infinity) ;


5
1
3 ln(3)
36
4
> |

..................................................................................................................................

Chaque fois qu'un rsultat est (ou, pour Maple, parat) correct, Maple ouvre
aprs l'achage du rsultat un groupe d'excution o il positionne le curseur. Si
un tel groupe tait dj prsent, Maple ne cre pas un nouveau groupe, mais il
positionne le curseur au dbut de la dernire ligne du groupe d'excution suivant
celui qui vient d'tre excut. On ne montrera plus dsormais ce groupe suivant
dans nos exemples.
Notre calcul d'intgrale est cette fois russi, au moins pour un mathmaticien.
Le rsultat exact obtenu, ncessitant pour tre exprim le radical, le nombre
et le logarithme, n'est pas forcment celui qui est souhait par exemple par le
physicien, quand il cherche un rsultat numrique. Notre physicien pourra alors
pour atteindre le but recherch excuter :
..................................................................................................................................

> evalf(%) ;

.4810966632
..................................................................................................................................

Le symbole % reprsente le dernier rsultat obtenu, et la procdure evalf demande


la conversion en un ottant de l'objet dsign. Mais supposons qu'on ralise alors
qu'on voulait que la borne infrieure de l'intgrale soit 0 et non pas 1. Dans ce
cas on peut remonter le curseur pour modier la n de la commande d'intgration, y remplaant ..., x=1..inf... par ..., x=0..inf.... On rexcute la
commande en tapant <Entre>, le nouveau rsultat s'ache et le curseur est positionn au dbut du evalf(%) ; il sut alors de retaper <Entre> pour obtenir
la nouvelle valeur numrique de l'intgrale. On obtient ceci :

20

..................................................................................................................................

> int((1+x)/(1+x^2+x^4), x=0..infinity) ;


5
3
18
> evalf(%) ;
1.511499471

..................................................................................................................................

C'tait le but de cette session qu'il faut donc maintenant terminer, mais il est
peut-tre prfrable de la sauvegarder en vue d'une rutilisation ultrieure. Pour ce
faire on active l'option Save du menu File, ou encore on utilise le raccourci clacier
Ctrl-S ; une fentre de dialogue intitule Enregistrer sous s'ouvre, permettant
de prciser le chier de sauvegarde souhait. Il faut prendre son temps pour en
comprendre les possibilits.

Cinq mini-fentres sont incluses. La premire, une seule ligne o le curseur est
positionn, indique *.mws, ce texte apparaissant slectionn, c'est--dire surcharg
par une bande colore, bleue sous le standard Windows. La fentre juste infrieure
rappelle pour mmoire les chiers dj prsents dans le dossier en cours. A droite
de cette fentre se trouve justement une autre fentre qui indique la situation
actuelle par rapport l'ensemble des dossiers de l'unit de disque active. En haut,
les dossiers actifs sont ouverts. Ici le rpertoire en cours est donc :
D:\Program Files\Maple 6\Users\

C'est ce que vous trouverez10 la premire fois aprs installation de Maple. Il est
donc important de savoir comment grer cette situation. Il ne faut en aucune faon
sauvegarder son chier dans ce dossier considrer comme systme. La tradition
sous Windows consiste, en utilisant par exemple Windows-Explorer, crer dans le
dossier D:\Mes Documents\ un dossier Maple. Ceci fait, indpendamment de Maple,
il faut maintenant, dans Maple, remonter jusqu' C:\ en cliquant rapidement
deus fois dans la fentre de dialogue Maple sur cette indication ; on obtient quelque
chose comme :
10 L'installation

Windows du rdacteur prvoit le dossier systme Maple et son utilisation sur


le disque D:\ ; les installations les plus simples utilisent en gnral le disque C:\.

21

Puis il faut descendre pour atteindre notre dossier, donc cliquer d'abord
(deux fois) sur Mes Documents :

Le dossier Maple install, par exemple l'aide de Windows Explorer, sous le dossier
Mes Documents, peut tre slectionn par un clic de souris, ou par utilisation de la
touche directionnelle `', ou encore en entrant (deux fois) `m' au clavier :

22

Tapant <Entre> ou cliquant deux fois sur l'indication Maple, on ouvre ce


dossier, vide puisqu'il vient d'tre cr, comme indiqu par la fentre de gauche :

On va alors avec la souris dans la micro-fentre en haut gauche, on eace11


l'toile  et on le remplace par exemple par Integral-1 :

Enn on clique sur OK, ou on tape simplement <Entre>. La fentre de dialogue disparat, mais notre belle feuille de travail est enregistre comme le chier :
D:\Mes Documents\Maple\Integral-1.mws

On peut changer le disque actif l'aide de la mini-fentre intitule Lecteurs.


Le systme d'volution dans l'espace disque est trs commode, mais demande un
peu de temps pour tre bien compris. Ne ngligez pas cette question : il est frquent
de voir les dbutants persuads d'avoir perdu une feuille de travail, alors qu'en
fait elle a t sauvegarde dans un dossier bien dirent de celui qui tait prvu. . .
11 Eacement trs souvent oubli par les dbutants, auquel cas Maple refuse l'enregistrement,
sans autre explication.

23

Warning 4  Dans la fentre Enregistrer sous, bien noter que le dossier actif

est le dernier dossier visuellement ouvert de la mini-fentre de droite.

Ne changez rien la mini-fentre intitule Enregistrer au format : ; autrement dit considrez comme une norme sans exception que votre feuille de travail
est sauvegarde sous un nom de chier d'extension .mws, mnmonique de MapleWorkSheet.
Notez que quand votre feuille est sauvegarde, le nom choisi apparat dans
le bandeau titre de votre fentre Maple. D'une faon gnrale est ainsi dsigne
la feuille de travail actuellement active, [Untitled(x)] si c'est une feuille non
sauvegarde, le nombre x voluant au gr des crations de nouvelles feuilles de
travail. La liste des fentres actuellement existantes est disponible dans le menu
Windows, la fentre active tant marque X.
Vous pouvez alors, maintenant que votre feuille est sauvegarde, continuer votre
travail, entrer de nouvelles commandes, etc. Vous pouvez aussi fermer votre session
Maple, par exemple en cliquant sur le bouton Windows
en haut droite de la
fentre Maple.
Si vous tentez de terminer une session Maple et qu'une ou plusieurs fentres
ne sont pas sauvegardes, Maple vous demande de conrmer votre dcision pour
chaque fentre successivement. Prenez soin de rchir quelques secondes pour
viter de perdre un travail peut-tre prcieux.

1.5 Ractiver une feuille de travail sauvegarde.


Il y a plusieurs faons de procder. Le plus simple consiste utiliser l'Explorer Windows et ouvrir (double-clic) le chier correspondant. Une session Maple
s'ouvre o apparat votre feuille de travail, exactement dans l'tat o vous l'aviez
laisse, y compris la position du curseur. Autre mthode vous ouvrez comme prcdemment une session Maple, et vous utilisez le raccourci-clavier Ctrl-O ; une
fentre de dialogue s'ouvre, trs analogue celle qui servait la sauvegarde. Evoluant dans l'espace disque comme expliqu plus haut, vous nissez par faire apparatre le chier de sauvegarde dans la fentre gauche de la fentre de dialogue o
gurent les chiers du dossier en cours. Par double-clic sur le chier, la feuille de
travail s'ouvre.
Il a t dit ci-dessus que vous retrouvez votre feuille de travail exactement
dans l'tat o vous l'avez laisse ; visuellement oui, en fait pas du tout : les calculs
qui avaient t eectus dans la session prcdente sont perdus, moins d'en
demander explicitement la rexcution. Pour comprendre ce dont il s'agit, prparez
une feuille de travail avec cette mini-session :

24

..................................................................................................................................

> x := 34 ;

x := 34

> x + 3 ;
37

> |

..................................................................................................................................

Vous laissez le curseur l o il est positionn et vous sauvegardez cette feuille de travail ; vous terminez la session Maple et allez prendre un caf. Ceci fait, vous revenez
votre poste de travail, relancez une session Maple et ouvrez la feuille qui avait t
prcdemment sauvegarde. Le curseur est positionn toujours au dernier groupe
d'excution, pour le moment vide. Vous entrez au clavier x + 3 ;<Entre>.
Votre feuille de travail devient :
..................................................................................................................................

> x := 34 ;

x := 34

> x + 3 ;
37

> x + 3 ;
x+3
..................................................................................................................................

Dans la premire session, on avait aect au symbole x l'entier 34, puis on avait
valu l'objet x+3 ; on dtaillera bientt le fonctionnement de ces choses, mais il
est naturel de voir l 37 comme rsultat de l'valuation, compte tenu de la valeur
de x. La session est alors arrte aprs sauvegarde.
Ensuite on lance une autre session Maple ; on y ouvre la feuille de travail
sauvegarde la n de la session prcdente. On retrouve le curseur positionn
l o il tait au moment de la sauvegarde, mais ceci ne signie en aucune faon
que les instructions prcdentes ont t pralablement excutes. En particulier,
pour le symbole x, tout se passe comme si la valeur de la session prcdente, 34,
tait en fait perdue, et c'est pourquoi l'valuation de x+3 retourne seulement x+3 :
un symbole sans valeur a, sous Maple, lui-mme comme valeur, en fait valeur
par dfaut ; ce mcanisme est trs important en calcul symbolique et sera dtaill
plus loin. C'est pourquoi on a maintenant l'cran deux valuations apparemment
successives de x+3 avec des rsultats dirents.
Mais vous pouvez si vous le souhaitez faire rexcuter toute votre feuille. Activez l'option Execute Worksheet du menu Edit. Toute la feuille va tre rexcute et cette fois les deux valuations de x+3 donnent le rsultat 37, cause de
l'aectation pralable de 34 x. Autrement dit la feuille est inchange sauf que le
dernier rsultat est maintenant 37. Un corollaire est le conseil qui suit.

Conseil 5  Organisez vos feuilles de travail  conserver de telle faon qu'elles

soient entirement rexcutables sans incident. Sinon elles peuvent rapidement devenir dicilement utilisables. Pour que ce travail de mise au propre ne soit pas trop
pnible, faites la mise jour ncessaire de temps autre pendant votre session.
L'option Execute Worksheet du menu Edit vous permet de vrier rapide25

ment l'tat de votre feuille de travail ce propos. Toutes les commandes Maple de
votre feuille sont alors excutes squentiellement. Mme si une commande termine
sur erreur, Maple continue et lance aussitt l'excution de la commande suivante,
jusqu' la n de la feuille. Le dlement est tellement rapide qu'une telle erreur
peut passer visuellement inaperue, et votre feuille n'est peut-tre pas alors dans
l'tat que vous souhaitez. Mais vous pouvez lancer la recherche arrire12 de toutes
les occurences de Error dans votre feuille pour conclure ce propos.
Maple 6 est la premire version de ce logiciel possdant un mcanisme de sauvegarde automatique, voir l'option Autosave du menu Options et la page de
documentation worksheet,options,autosave. Il arrive en eet de temps autre
qu'un calcul trop complexe, ou encore demand de faon errone, provoque un
crash complet de la session Maple ; dans un tel cas, tous les calculs prcdemment prpars peuvent tre perdus. L'option Autosave permet de demander
Maple la sauvegarde systmatique, intervalles rguliers, de votre feuille de travail, sous un nom de chier particulier construit partir du nom du chier associ
en ajoutant _MAS (Maple AutoSave). Les risques de grosses pertes sont ainsi trs
sensiblement diminus. Pour tout travail d'envergure, il faut absolument utiliser
cette possibilit.

1.6 Le systme d'aide.


Le systme d'aide en ligne Maple est remarquablement bien fait et contribue
certainement son succs. Le systme d'aide est lui-mme autodocument, ce qui
dispense le rdacteur de ce manuel de s'tendre exagrment sur le sujet. Si vous
tes parfait dbutant Maple, vous devez d'abord ouvrir le menu Help et choisir
l'option Using Help. Vous verrez que les rubriques d'aide sont essentiellement :
1. New User's Tour : Dcoup son tour en plusieurs Tours spcialiss :
calculs numriques, calculs algbriques, graphiques, calculus, etc. Ces pages
d'aide contiennent de trs nombreux exemples de petits calculs Maple, calculs
au sens large, faciles rpter. Le caractre publicitaire n'est pas absent ; la
plupart des exemples sont assez impressionnants par leur ecacit apparente.
En gnral l'utilisateur est un peu abus : il est souvent victime ce stade
d'une fcheuse tendance croire que tout et n'importe quoi est facilement
faisable sous Maple ; pourtant ds qu'il cherche appliquer ce qu'il a observ
dans le New User's Tour pour le calcul apparemment voisin qui l'intresse,
il doit dchanter. . . La technique acqurir est en fait sensiblement plus
dicile que ce qui est suggr dans le New User's Tour !
2. Topic Search : C'est d'une certaine faon le symtrique du New User's
Tour ; c'est en eet le Reference Guide de Maple, trs complet, donc ncessairement assez indigeste pour une lecture linaire. Chaque procdure Maple
prdnie y est bien documente. La nature des arguments selon les dirents cas de gure est dtaille. De nombreux exemples pour chaque type
d'utilisation possible sont proposs, eux aussi facile rpter.
12 Raccourci

Ctrl-F, bouton Previous.

26

3. Full Text Search : Trs utile dans les cas diciles ; vous proposez un mot et
Maple cherche toutes les occurences de ce mot dans les feuilles d'aide ; elles
sont de plus classes par la frquence d'apparition. Voir ci-dessous un usage
frquent.
Malgr le ct forcment publicitaire du New User's Tour, il ne doit pas tre
nglig. Aprs plusieurs annes d'utilisation de Maple, on a la surprise d'y trouver
encore de temps autre des tuyaux utiles !

1.6.1 Le Reference Guide.


La principale source d'information est bien entendu le Reference Guide, accessible par l'option Topic Search du menu Help. La combinaison (Alt-H)+T13
est plus rapide et devient l'habitude. Une fentre de dialogue s'ouvre demandant
quelle est la page de documentation souhaite. En premire approximation, chaque
page correspond une procdure Maple prdnie. Par exemple pour obtenir la
documentation de la procdure GAMMA, chercher la page GAMMA. Quand on entre le
dbut du nom de la procdure, Maple ache immdiatement la liste des pages qui
pourraient correspondre ; on dcouvre ainsi souvent la bonne orthographe utiliser
pour des noms la devine. Sous Maple, minuscules et majuscules sont distingues,
et l'utilisateur est souvent hsitant ; mais l'outil de recherche Topic Search est
au contraire tolrant ce propos. Par exemple il n'est pas vident que pour la
fonction eulrienne (t) c'est la procdure GAMMA, tout en majuscules, qu'il faut
utiliser, mais on le dcouvre ainsi en entrant approximativement gam :

Au passage, les pages proposes peuvent donner des ides pour des sujets plus
ou moins connexes ; ainsi quand on cherche la documentation pour la fonction ,
13 Il

faut comprendre d'abord la combinaison simultane Alt-H, suivie de la touche T seule,


la touche Alt- tant alors relche.

27

on dcouvre en mme temps la page approprie pour la constante d'Euler , c'est


cette fois gamma qu'il faut utiliser.
Certaines pages de documentation portent sur des sujets et non sur des procdures particulires. Par exemple la demande pour gamma envoie en fait la page
initially-known names.
Si vous cliquez sur le bouton Apply de la fentre Topic Search, la page
slectionne est ache, mais la fentre de dialogue reste ouverte, vous permettant
de continuer explorer les autres possibilits.
Il arrive souvent qu'on soit certain de la procdure qu'il faut utiliser dans un cas
particulier, par contre la faon de l'utiliser n'est pas claire, notamment sur ce qu'il
faut prvoir pour ses arguments. Dans ce cas, on peut entrer sur sa feuille de travail
le nom de la procdure en question, mettons randmatrix ; la touche fonction F1
ouvre alors directement la feuille d'aide approprie. Dans le mme registe, la mthode antique consistant entrer la pseudo-commande  ?randmatrix fonctionne
toujours, mais n'a plus aucune raison d'tre ; ne laissez pas ces pseudo-commandes
dans votre feuille de travail : elles gneraient considrablement la rexcution entire de la feuille.
Inversement, si au contraire dans un cas particulier on a un doute sur la pertinence de la feuille d'aide examine, un autre lment d'information peut tre
utilis. Le Reference Guide est entirement structur comme un arbre14 cinq niveaux hirarchiques. Quand une feuille est ache, le chemin joignant votre feuille
la racine de l'arbre est dcrit dans un bandeau intercal entre votre feuille et la
barre d'outils :

Les branches voisines sont aussi aches, de sorte que l'exploration de cet arbre
permet quelquefois d'atteindre logiquement la feuille qui en fait tait approprie.
La manuvre usuelle de souris permet d'augmenter ou au contraire de diminuer
la hauteur de ce bandeau, et donc de s'adapter la situation du moment. Par
example, si vous cherchez eectuer une simplication visuellement possible dans
une expression rsultat complique, vous allez probablement tenter simplify, souvent sans succs. tout hasard vous explorez la page simplify sans rien y trouver
de nouveau par rapport ce que vous pensez connatre. En bout de course, pensez
alors explorer l'arborescence du systme d'aide. Pour ce faire examinez le bandeau o vous voyez que le chemin jusqu' simplify est :
14 Un

examen soigneux montre que ce n'est pas strictement parlant un arbre : il peut exister
plusieurs chemins de la racine vers une feuille, mais ce moteur de recherche n'en est que plus
intressant ;

28

..................................................................................................................................

Mathematics
Algebra
Expression Manipulation
Simplifying
Simplify

..................................................................................................................................

Explorant l'arbre, vous voyez qu'il y a beaucoup d'autres faons de simplier que
d'utiliser la procdure simplify ; par exemple les procdures normal, radnormal,
combine, qui souvent correspondent ce qui en fait est recherch. En dsespoir de
cause, on peut mme se demander si c'est vraiment une simplication qui est recherche. Au mme niveau de la hirarchie que Simplifying , on trouve par exemple
Factoring qui peut mener sur d'autres pistes. Cet outil de recherche ne doit jamais
tre nglig.
Une autre mthode peut encore tre exploite quand une feuille d'aide se rvle
inapproprie pour un problme particulier : la n de cette feuille ache frquemment un certain nombre de liens hypertextes vers des sujets voisins ; c'est souvent
de cette faon qu'on atteint enn la page cherche !

1.6.2 Le cas des packages.


Un package Maple est un ensemble cohrent de procdures sur un sujet plus ou
moins particulier, dont l'usage ne s'impose pas forcment d'emble l'utilisateur
ordinaire. Par exemple le package linalg (algbre linaire) contient les procdures
volues de manipulations matricielles. Le logiciel propose ses propres packages et
l'utilisateur peut en crer d'autres ou encore tendre les packages existants.
Un package n'est charg qu' la demande de l'utilisateur, par la procdure with,
sans quoi les procdures de ce package sont inaccessibles15 . Il est possible aussi de
charger seulement certaines procdures de tel ou tel package.
L'accs la documentation des procdures proposes par les divers packages
pose un problme qu'il n'est pas dicile de surmonter, mais qu'il faut connatre.
Si vous savez d'avance que la procdure qui vous intresse est dans tel package, il
faut entrer d'abord le nom du package avant celui de la procdure. Par exemple
si vous cherchez la page expliquant la procdure exponential du package linalg,
demandez sous Topic Search la page linalg,exponential. En particulier, ds
que vous avez entr linalg, toutes les procdures du package linalg sont aches
dans la fentre des possibilits, information souvent utile. Une page introductive
est aussi prvue pour chaque package, dont le nom est celui du package.
Si vous tes certain du nom de votre procdure, vous pouvez aussi directement
entrer le nom de la procdure ; le systme d'aide saura trouver votre page, mais il ne
vous aidera pas par une indication positive dans la fentre des possibilits. Essayez
pour eigenvalues. Il arrive que des procdures direntes, de mme nom, gurent
dans des packages dirents. Par exemple il existe deux procdures exponential,
l'une dans linalg calcule l'exponentielle d'une matrice, l'autre dans le sous-package
15 Plus

prcisment elles sont accessibles par un mcanisme assez lourd qui doit aussi citer le
nom du package.

29

random du package stats est un gnrateur de nombres alatoires correspondant


une loi exponentielle. Si vous demandez sous Topic Search la page exponential,
Maple vous ouvre une page auxiliaire vous proposant le choix par liens hypertextes
entre les pages linalg,exponential et stats,random ; en cliquant sur l'un de
ces liens, vous obtenez la page souhaite.

1.6.3 La recherche par mot (Full Text Search).


Un autre type de recherche de page d'aide est disponible, par mot, trs utile
dans les cas diciles. Vous y accdez par le menu Help, option Full Text Search,
ou, plus rapidement, par la combinaison (Alt-H)+F. nouveau une fentre de
dialogue est ouverte, vous demandant le ou les mots (Word(s)) que vous proposez.
Pendant la frappe, rien n'est ach dans la fentre des possibilits.
Quand le mot cl de la recherche est entr, vous tapez <Entre> ou cliquez le
bouton Search. La liste des possibilits est alors ache : c'est la liste des pages
o le mot cl est prsent, dans le texte ou dans les calculs. De plus les pages sont
classes par un indice de frquence d'apparition, de sorte que souvent la page que
vous cherchez gure parmi les premires aches.
C'est un puissant moyen d'exploration. Par exemple, si vous cherchez une procdure calculant le nombre chromatique d'un graphe, vous tentez d'abord votre
chance dans Topic Search avec chrom... mais la fentre des possibilits est vide.
tout hasard vous insistez et demandez la page chromatic : une fentre message
accompagne d'un op sonore vous indique que rien n'est accessible de cette faon.
C'est le moment d'essayer la recherche par mot. Un <Escape> eace la fentre
inutile et (Alt-H)+F ouvre la fentre Full Text Search. Vous proposez le mot
chromatic, puis <Entre> vous donne la liste des possibilits :

Il n'y en a que trois, la premire tant libelle networks,chrompoly. Vous en


30

dduisez qu'un package networks est disponible, contenant entre autres une procdure chrompoly, calculant trs probablement le polynme chromatique d'un graphe.
On sait que le nombre chromatique s'en dduit ; le package networks fournira tous
les outils ncessaires pour construire et manipuler les graphes ; le problme est
rsolu.

1.7 L'dition des feuilles de travail Maple.


Cette section peut ou mme doit tre omise en premire lecture : elle est trs
fastidieuse. Mais tt ou tard, si vous ne dcouvrez pas par vous-mme comment
procder dans telle ou telle circonstance, les informations qui y sont donnes devraient vous tre utiles. Dans l'ensemble, les techniques d'dition disponibles sous
Maple sont commodes, mais pas si simples. Quelques points sont mme franchement tranges et peuvent gner svrement les dbutants, tant qu'ils n'ont pas
bien compris l'architecture sous-jacente.
Maple a prvu le ncessaire pour que l'utilisateur puisse indniment modier
les instructions dj entres, excutes ou non, quelle que soit leur position dans
la feuille de travail. Ceci fait, il peut les rexcuter ou non. C'est trs souple, trs
riche en possibilits de mise au point, mais cre un espace de libert si vaste que
l'utilisateur dbutant y est un peu perdu !

1.7.1

<Return> ou <Shift-Return> ?

Considrons d'abord les groupes d'excution de plusieurs lignes. Soit crer


la procdure SquareSum16 prenant en argument une liste de donnes et retournant
la somme des carrs de ces donnes. On examinera plus loin le contexte thorique
o le problme est dni et comment il peut tre rsolu. Il s'agit ici d'examiner
seulement quelques points de traitement de texte, la cration de la procdure et
son utilisation. Voici une solution possible17 :
..................................................................................................................................

> SquareSum := proc(list)


RETURN(add(item^2, item=list))
end ;
SquareSum := proc ... end
> SquareSum([2,3,4]) ;
29
> SquareSum([a,b,c]) ;
a2 + b2 + c2

..................................................................................................................................

Si vous ne connaissez pas la technique ad hoc, vous aurez les plus grandes
dicults imiter exactement ce qui est montr ci-dessus. La procdure SquareSum
16 Noter

qu'en Maple majuscules et minuscules sont distingues dans les symboles, comme en
C ou Java.
17 La rponse (ouput) Maple pour la procdure entre est en fait un peu plus vaste ; l'achage
simpli prvu ici est susant ; on procdera presque toujours de mme dans la suite.

31

est organise sur trois lignes, de sorte qu'aprs avoir entr la premire ligne, vous
allez, quoi de plus naturel, actionner la touche <Entre> pour taper la ligne
suivante. Vous voyez alors Maple vous compliquer la vie comme suit :
..................................................................................................................................

> SquareSum := proc(list)


> |

Warning, premature end of input

..................................................................................................................................

Maple est eectivement pass la ligne suivante, a mme insr en dbut de ligne
un autre signal de prompt (>) ; de plus, sous cette ligne, il fait gurer en petits
caractres bleus un Warning signalant une n prmature d'input. Vous pouvez
maintenant entrer la deuxime ligne RETURN(add(item2, item=list)), puis taper
nouveau <Entre> ; un troisime prompt s'ache et le Warning descend pour
tre maintenant en quatrime ligne. Vous entrez le end ; terminal et quand pour
la troisime fois vous tapez la touche <Entre>, le Warning disparat comme par
enchantement et vous obtenez ceci :

..................................................................................................................................

> SquareSum := proc(list)


> RETURN(add(item^2, item=list))
> end ;
SquareSum := proc ... end

..................................................................................................................................

La seule dirence avec ce qui avait t montr au dbut comme solution de rfrence est la prsence de prompts au dbut de chaque ligne de texte source de la
procdure. Ce n'est pas franchement gnant, si bien que les utilisateurs dbutants
commencent en gnral par se contenter de cette faon de faire.
Pourtant, au fur et mesure que vous progresserez, vous crirez des procdures
de plus en plus longues ; pendant une mise au point, il arrive de temps autre qu'on
dcide de couper une instruction un peu longue sur une ligne de telle faon qu'elle
occupe deux lignes ou plus ; d'autres fois il faut insrer dans le texte de nouvelles
instructions devenues ncessaires, exprience faite. Considrons la procdure log2
ci-dessous, destine calculer le logarithme de base 2 d'un rel positif.
..................................................................................................................................

> log2 := proc(x)


> RETURN(evalf(ln(x)/ln(2)))
> end ;

log2 := proc ... end

> log2(3) ;
1.584962501

> log2(-3) ;
1.584962501 + 4.532360143 I
..................................................................................................................................

Cette procdure est correcte, mais retourne comme il se doit un complexe si l'argument x est ngatif. Il peut se faire, dans un contexte donn, que cette circonstance
soit exclue, auquel cas le programmeur prfrera le cas chant interrompre immdiatement l'excution avec un message d'erreur clair. La solution suivante18 peut
18 Il

est plus simple de typer le paramtre, voir page 80, mais le message d'erreur peut ne pas
tre celui qui est souhait.

32

tre adopte :
..................................................................................................................................

> log2 := proc(x)


> if x <= 0 then ERROR
>
("the argument of log2 must be positive.")
> fi ;
> RETURN(evalf(ln(n)/ln(2)))
> end ;
log2 := proc ... end
> log2(-3) ;
Error, (in log2) the argument of log2 must be positive.

..................................................................................................................................

Supposons donc que vous ayez d'abord entr la premire version, puis que vous
prfriez la deuxime. L'habitude des traitements de textes peut vous suggrer
pour la modication la solution suivante : positionner le curseur la n de la
premire ligne, puis entrer un retour chariot <Entre> pour intercaler la ligne
if x <= 0 ... ; vous pourrez le faire autant de fois que vous voulez, la disposition
reste absolument inchange ! ! De plus, chaque essai, la dnition de procdure
est value et le curseur va se positionner aprs le rsultat ach en bleu, au dbut
du groupe d'excution suivant.
Devant ce comportement trange de l'diteur Maple, vous allez probablement
tenter autre chose : positionner le curseur au dbut de la deuxime ligne, puis
entrer devant RETURN(... le dbut de l'instruction conditionnelle que vous voulez
insrer :
..................................................................................................................................

> log2 := proc(x)


> if x <= 0 then ERROR|RETURN(evalf(ln(n)/ln(2)))
> end ;

..................................................................................................................................

Ceci fait, vous tapez nouveau la touche <Entre> pour partager la longue ligne
en deux parties, esprant continuer de la mme faon sur la ligne suivante. Eh bien
non, la deuxime ligne refuse la sparation ! De plus le texte procdure est valu
dans son tat trs provisoire, incomprhensible pour Maple, d'o l'erreur :
..................................................................................................................................

> log2 := proc(x)


> if x <= 0 then ERRORRETURN(evalf(ln(n)/ln(2)))
end
| ;
reserved word `end` unexpected

..................................................................................................................................

La solution connatre absolument consiste taper non pas <Entre> comme


il semble si naturel, mais taper simultanment les touches 19 et <Entre>,
autrement dit ce qu'on appelle par abus de langage la touche <-Entre>. Alors
oui, au point o tait positionn le curseur, un retour chariot est insr. Ceci
est long terme si important qu'un nonc trs prcis est ncessaire.
1. La touche <Entre>, si elle est actionne quand le curseur est dans une
commande Maple, demande l'valuation du groupe d'excution englobant ;
19 Appele

aussi touche Maj (caractres majuscules) sur certains claviers, ou encore Shift
selon la terminologie anglaise.

33

de tout le groupe d'excution, quelle qu'en soit la taille. Ce n'est que trs
auxiliairement que Maple introduit un retour chariot la n du groupe
d'excution pour sparer l'entre (input) du groupe, en caractres tltypes
rouges, de la sortie (output), en petits caractres bleus. Cette touche n'introduit aucun retour chariot l o le curseur tait positionn.
2. La touche <-Entre> insre banalement un retour chariot l o le curseur est positionn, sans lancer quelque valuation que ce soit.
Ce choix des concepteurs de Maple est assez discutable, mais il est ainsi. En
consquence, quand une commande ncessite plusieurs lignes de texte, il est bien
meilleur de passer la ligne suivante l'aide de <-Entre>. Vous ne recevrez pas continuellement le Warning intempestif premature end of input, et vous
n'aurez logiquement qu'un seul prompt > au dbut de votre groupe d'excution. C'est seulement quand votre groupe d'excution sera entirement termin,
par exemple quand vous aurez entr le end ; terminal de votre procdure, c'est
seulement ce moment que vous taperez une touche <Entre> simple, sans ,
pour demander l'valuation. Ceci doit devenir rexe :
1. La touche <-Entre> pour le passage ordinaire la ligne suivante ;
2. la touche considrer comme spciale <Entre> pour la terminaison du
groupe et l'valuation.
Par ailleurs, les fautes de syntaxe dtectables seront dtectes exactement dans
les mmes conditions au moment de <Entre>, ce qui permet de mieux disjoindre
la phase d'criture du texte de celle de l'analyse syntaxique et correction.

1.7.2 Bien eacer, c'est d'abord bien slectionner.


L'tat de la feuille de travail devient quelquefois si anarchique que la seule
mthode de mise au propre adapte consiste en un srieux nettoyage o des eacements de segments de feuilles vont jouer un rle important. C'est une opration
qui n'est pas si facile pour le profane, parce que le curseur a tendance naviguer de faon assez erratique travers les blocs de programme surtout quand il
rencontre des zones contenant des rsultats (Maple-output). Un autre phnomne
vient compliquer ces manuvres : il est frquent pendant les manipulations d'effacement que les messages d'erreur se transforment subitement en zones de textes
commentaires ; les messages bleus ou mauves virent au noir sans crier gare et se
mlangent au texte source (Maple Input), auquel cas l'utilisateur ne sait plus trs
bien que faire.
Par exemple, si, compte tenu de ce qui est expliqu ci-dessus vous avez appris
entrer les lignes successives spares par des combinaisons <-Entre>, il peut
vous arriver d'entrer ce texte erron o le message d'erreur, pour une fois assez
clair, vous indique clairement que vous avez une parenthse en surnombre :

34

..................................................................................................................................

> SquareSum := proc(list)


RETURN(add(item^2, item=list)))
|
end ;
`)` unexpected

..................................................................................................................................

Le curseur est justement positionn l o il faut enlever la parenthse fautive,


mais vous avez le doigt un peu lourd, la touche <Suppr> mange non seulement
la parenthse mais la ligne end ; suivante et aspire bientt le message d'erreur.
Terroris, vous levez le doigt et votre feuille a alors l'allure suivante :
..................................................................................................................................

> SquareSum := proc(list)


RETURN(add(item^2, item=list))|`)` unexpected

..................................................................................................................................

o l'ex-message d'erreur est maintenant noir ! Dans ce genre de circonstance,


le plus simple est de poursuivre l'eacement, donc de rappuyer sur la touche
<Suppr> pour achever d'annihiler le message d'erreur. Si au lieu de cela vous
tapez <Entre> ou <-Entre>, le bout de message d'erreur reste vivace et
d'ailleurs n'a aucune inuence sur le calcul, sinon que sa prsence persistante est
esthtiquement bien dsagrable. En fait vous avez vraiment transform le message
d'erreur en un commentaire dit de type Texte. Le lecteur aura peut-tre un peu de
mal reproduire les accidents qui viennent d'tre dcrits, car l'exprience montre
que les types de fautes commises sont extrmement variables d'un utilisateur
l'autre, selon les habitudes de chacun, notamment selon les autres logiciels auparavant pratiqus : chaque logiciel donne peu peu ses utilisateurs des habitudes,
des rexes quelquefois, trs dirents d'un logiciel l'autre, dont il n'est pas si
facile de se dbarrasser.
En tout tat de cause vous serez amen assez frquemment entreprendre
des eacements plus ou moins complexes. Sauf les eacements faciles de quelques
caractres avant ou aprs le curseur, vous avez intrt d'abord slectionner la
zone eacer.
Une mthode de slection est le balayage avec la souris, utilise maintenant
dans la quasi-totalit des logiciels. On positionne le curseur au dbut de la zone
slectionner, on clique et, sans relcher la pression, on bouge la souris jusqu'
atteindre la n de la zone slectionner ; pendant le balayage, une zone colore
s'tend et visualise l'extension de la partie de la feuille qui est slectionne. On
peut mme tendre la zone balaye au del de ce qui est visible en positionnant la
souris, touche restant appuye, juste aprs la frontire de la fentre qui entre alors
en droulement pour rpondre ce qui est manifestement votre attente. Ensuite
on relche le clic et la zone nalement slectionne reste colore. Alors seulement,
vous appuyez sur la touche <Suppr> et la zone slectionne disparat. Ceci peut
tre aussi la phase initiale d'une opration coup-coll ou copi-coll. Le fait de
clairement sparer la phase de slection de la phase de suppression permet de
russir des eacements complexes, par exemple assez vastes, pouvant porter sur
plusieurs groupes d'excution, rsultats compris.
La phase de slection peut aussi tre ralise sans souris, avec le curseur, avec
35

une prcision encore meilleure. Le principe est simple : si pendant l'action des
touches de mouvement du curseur, quelles qu'elles soient, vous maintenez en plus
la touche  enfonce, la zone parcourue par le curseur est slectionne. Par
exemple, si, cas assez frquent, vous voulez eacer toute la feuille partir d'un point
donn, vous avez un moyen trs simple pour le faire : vous positionnez le curseur
au point coupure, puis vous actionnez simultanment les trois touches <Ctrl-Fin> ; ce seul geste slectionne la zone voulue. Ensuite un coup de <Suppr> et
la suppression est faite. Notez aussi dans ce registre que si vous tes positionn
en dbut de groupe d'excution, juste aprs le prompt Maple (>), vous pouvez en
actionnant deux fois la touche directionnelle  positionner le curseur avant le
prompt. Vous pouvez alors commencer la slection de ce point si vous souhaitez
entre autres eacer tout le groupe d'excution, prompt compris.

Conseil 6  Prenez l'habitude pour les eacements un peu complexes de slectionner d'abord, la souris ou au clavier, la zone eacer. Ceci fait vous pouvez
alors procder l'eacement ou encore un coup ou un copi pour un coll ultrieur.
Vous pouvez aussi eacer un paragraphe l'aide de la combinaison <CtrlSuppr> ; c'est quelquefois assez commode pour supprimer rapidement de grandes
zones de texte. Se mer toutefois d'un pige : aprs la suppression, il est frquent
que le curseur ne soit pas positionn aprs le paragraphe supprim, mais plus loin,
ce qui est un peu dsagrable. Un paragraphe est une zone de texte source (Maple
Input) situe entre deux prompts, ou le rsultat d'une instruction, ou encore un
segment de texte commentaire disjoint du texte source Maple.

1.7.3 Les ns de lignes tranges.


On a expliqu plus haut pourquoi il fallait prfrer <-Entre> <Entre>
pour le passage la ligne suivante, lors de l'entre d'une commande de plusieurs
lignes. Vous n'tes pas encore compltement tir d'aaire ! Il vous reste alors
amadouer les comportements exotiques du curseur en n de ligne, l'origine de
crises de nerfs mmorables. . .
Les textes sources Maple (Maple-Input) o les lignes sont spares par des
<-Entre> prsentent en eet une caractristique trange, assez droutante pour
les dbutants. Le dernier caractre d'une ligne termine, qui parat tre un blanc,
est en fait un sparateur de lignes. Ceci ne se produit que pour les lignes proprement
termines par <-Entre>. Une fois ceci bien compris, les consquences sont
logiques, mais il faut un certain temps pour acqurir les rexes ad hoc.
Reprenons notre procdure SquareSum pour mettre en vidence ces phnomnes.
Supposons qu'on oublie l'une des deux parenthses fermantes de la ligne 2 ;
l'valuation, on obtient le rsultat suivant ;

36

..................................................................................................................................

> SquareSum := proc(list)


RETURN(add(item^2, item=list)
end
| ;
reserved word `end` unexpected

..................................................................................................................................

Vu la position du curseur, pour atteindre le point fautif avec le clavier, on procde


en principe comme suit : on entre la touche directionnelle  pour atteindre la
ligne critique, puis la touche Fin pour aller la n de cette ligne, l o la parenthse
est manquante. Curieusement, le curseur se positionne en fait un caractre plus
loin, aprs ce qu'on croit tre un espace, qu'en fait on n'avait pas entr ! Selon
l'humeur du moment, si on ne connat pas la vritable nature de ce caractre
mystrieux, on choisit l'une de ces deux solutions :
1. On dcide d'eacer l'espace suppos par un BackSpace et on a la stupfaction de voir la ligne suivante end ; remonter derrire le curseur !
..................................................................................................................................

> SquareSum := proc(list)


RETURN(add(item^2, item=list)|

end ;

reserved word `end` unexpected

..................................................................................................................................

2. On dcide au contraire de laisser cet espace et on entre immdiatement la


parenthse manquante ) ; cette fois on a la surprise de la voir apparatre
en fait au dbut de la ligne suivante !
..................................................................................................................................

> SquareSum := proc(list)


RETURN(add(item^2, item=list)
)|
end ;
reserved word `end` unexpected

..................................................................................................................................

Mais qu'est-ce qui peut expliquer ces trangets ? On a tout compris quand on
sait que le caractre en n de ligne qu'on croyait tre un espace tait en fait un
sparateur de lignes, souvent appel retour chariot (Endline ou Return20 selon
la terminologie anglaise). Supposons donc que le curseur soit positionn en n de
ligne derrire ce caractre dguis en espace ; alors :
1. Si vous entrez un BackSpace, vous supprimez le sparateur de lignes et la
ligne suivante vient donc se positionner la n de la ligne en cours !
2. Si au contraire vous entrez un caractre banal, il est entr droite du sparateur de lignes, donc sur la ligne suivante !
C'est d'une logique imparable, au moins quand on sait. Que fallait-il donc faire
pour insrer notre parenthse diabolique la bonne position ? Il fallait, aprs avoir
positionn le curseur en n de ligne l'aide de la touche Fin, utiliser la touche
directionnelle  pour positionner le curseur avant le sparateur de lignes ; on
peut alors enn entrer la parenthse l o c'est ncessaire.
On vous conseille de consacrer l'occasion un quart d'heure ou une demi-heure
pour bien comprendre ces mcanismes. Une technique vous aidera grandement. Le
20 L'analyse

des chiers Maple montre que ce n'est en fait ni l'un ni l'autre, car Maple a ses
propres mthodes de codage pour les sparateurs de lignes.

37

bouton
de la barre d'outils rend visibles les caractres normalement invisibles
sur votre feuille de travail. Les phnomnes sotriques expliqus longuement dans
cette section seront alors trs clairs. Dans le mme registre, vous pouvez ainsi voir
que les touches <Entre> et <-Entre> ne produisent pas du tout le mme
rsultat.

1.7.4 Autres commandes d'dition.


Insertion d'un groupe d'excution.
Frquemment vous dciderez d'insrer un nouveau groupe d'excution entre
deux groupes dj existants. Ceci se fait l'aide de Ctrl-J (ajout aprs le groupe
o le curseur est positionn) ou Ctrl-K (ajout avant ). Rien n'empche de crer
successivement de la sorte plusieurs groupes vierges conscutifs, par exemple pour
complter la feuille de travail par de nouveaux calculs intermdiaires qui se rvlent
ncessaires. Noter que sous Unix, il est frquent que ces commandes dcident
d'tre inoprantes, ce qui est fort dsagrable. Il faut alors se rabattre sur la commande menu Insert|Execution Group.

Undo et redo.
Il est assez frquent qu'on souhaite dfaire ce qu'on vient de faire, surtout
quand ce qu'on vient de faire est une suppression, auquel cas il s'agit plutt
de refaire ce qu'on vient de dfaire. . . La commande Undo du menu Edit est
prvue cet eet. Le raccourci clavier Ctrl-Z est commode pour la rptition
de cette commande, autrement dit pour continuer dfaire ; mais la mmoire de
Maple dans ce registre est assez rduite. On peut inverser le mcanisme avec la
commande Redo.

Trouver.
La commande Find du menu Edit ouvre une fentre de dialogue vous demandant quelle chane de caractres vous voulez chercher ; le raccourci Ctrl-F est
disponible. Quand le texte chercher est dni dans la mini-fentre, vous avez
encore le choix de chercher en avant ou en arrire.
Cette technique est utile quand votre feuille de travail devient importante et
que vous n'avez pas une mmoire prcise du point o par exemple une modication doit tre eectue. C'est aussi un outil bien commode pour l'exploration des
feuilles d'aide un peu vastes ; on s'y sent souvent un peu noy dans la multitude
d'indications techniques concernant les nombreux cas d'utilisation prvus ; pensez
alors Ctrl-F : ce peut tre le moyen de localiser rapidement l'information qui
vous intresse.
Noter que la recherche n'est pas possible de cette faon dans les rsultats des
calculs (Maple output). C'est dommage, mais quand ceci devient quasiment indis38

pensable, par exemple pour rechercher l'occurence de telle chane dans un rsultat
euve occupant plusieurs dizaines d'crans, vous pouvez procder comme suit.
Choisissez l'option Maple Notation (menu Options, option Output Display),
et faites rexcuter l'instruction critique. Le rsultat est alors ach sous forme
d'une chane ASCII o la recherche devient possible. Vous pouvez ensuite revenir
l'option Standard Math Notation pour revenir aux achages sorties Maple
standard.
Comparer par exemple les achages suivants ; dans le premier cas, si l'achage
rsultat est Standard Math Notation, la recherche de la chane de caractres
Pi est inoprante :

alors que si l'achage choisi est Maple Notation :

le rsultat est beaucoup moins lisible, mais par contre la recherche de la chane Pi
russit. Dans ce petit exemple, la dirence est insigniante, mais, si, comme cela
arrive de temps en temps, un ou des rsultats occupent plusieurs crans, ce peut
tre le point cl pour localiser tel ingrdient particulier.
39

Copie output input.


Dans le mme ordre d'ides, il est quelquefois utile de savoir copier une zone
output de la feuille de travail vers une zone input. C'est notamment une astuce
connatre pour prparer des dmonstrations sophistiques o par exemple une
matrice input relativement grande est d'abord gnre de faon alatoire.
Montrons comment il faut procder. Supposons qu'on veuille commencer avec
une matrice 5 10 dont tous les termes sont compris entre 9 et +9 ; il est trs
fastidieux de crer soi-mme une telle matrice et on ne peut jamais simuler correctement que cette matrice est vraiment quelconque ; la seule faon d'y arriver
consiste utiliser un gnrateur alatoire. Une telle matrice peut tre obtenue
comme suit, en utilisant la procdure rand.
..................................................................................................................................

> MM := matrix(5, 10, rand(-9..+9)) ;

8 4 5 5 3 5 8 5 1 0
3 4 5 2 1 9 5 8
4 3

8
9
7
5
0
4
4
2
5 5
MM :=

9 9 4
0 8 5 4 7 9 5
7 8 3
5 9 4 0 1 5 5

..................................................................................................................................

Vous essayez la suite de votre dmonstration avec cette matrice tombe du ciel et
si elle correspond votre projet, vous pouvez vouloir donner l'impression que cette
matrice a t choisie par vous-mme ! Il est assez fastidieux de recopier soi-mme
l'instruction Maple ad hoc :
..................................................................................................................................

> MM := matrix([[8, 4, 5, ...

..................................................................................................................................

Pour viter ce travail pnible, vous pouvez balayer la souris l'output (bleu)
M M := . . . ; un gros pav noir surcharge votre output qui apparat maintenant
en jaune sur fond noir. Vous actionnez la combinaison clavier Ctrl-C ou CtrlInsert pour copier ce qui est slectionn dans ce que Microsoft-France appelle
le presse-papiers, actionnez ensuite Ctrl-J pour faire apparatre un nouveau
groupe d'xcution, puis Ctrl-V ou -Insert pour y copier le contenu du pressepapiers ; vous obtenez ainsi aprs quelques manuvres videntes d'dition quelque
chose comme :
..................................................................................................................................

> MM := matrix(
[[8, 4, -5, -5, 3, -5, 8, 5, -1, 0],
[3, -4, -5, -2, -1, -9, 5, 8, 4, -3],
[8, -9, 7, 5, 0, 4, 4, 2, 5, -5],
[9, -9, 4, 0, -8, -5, 4, 7, -9, 5],
[7, -8, 3, 5, -9, 4, 0, -1, -5, 5]]) ;

..................................................................................................................................

avec le mme rsultat que prcdemment l'valuation, condition de ne pas


avoir oubli d'ajouter le point-virgule indispensable en n d'instruction, absent
de l'output original. Ceci fait, vous pouvez maintenant supprimer de votre feuille
de travail l'instruction initiale ralisant la gnration alatoire de la matrice par
l'intermdiaire de la procdure rand. Vous obtenez ainsi une feuille de travail don40

nant l'impression que cette matrice a t choisie par vous-mme ! Cette technique
est quelquefois abolument indispensable quand la gnration devient vraiment ( !)
alatoire, par exemple quand on utilise la procdure randpoly pour la gnration
de polynmes alatoires.
On rutilisera cette technique de copie output input page 47 pour une
autre raison qui sera explique alors, essentiellement pour mettre en vidence la
dirence entre format externe d'un objet et objet proprement dit.
-o-o-o-o-o-o-o-

41

Chapitre 2
Le modle Read-Eval-Print de
Maple
2.1 Pourquoi un modle ?
L'architecture des grands logiciels n'est pas simple, leur utilisation non plus.
Mais la formation leur utilisation l'est encore moins ! On entend dire souvent,
quand il s'agit par exemple de planier un cours Maple semestriel, qu'on s'organisera pour se dbarrasser rapidement des technicits informatiques et aborder aussi
vite que possible la seule partie noble de cet enseignement, celle qui est consacre
aux vraies mathmatiques. Ceux qui tiennent ce discours ne savent pas de quoi
ils parlent.
L'utilisation srieuse de Maple, comme celle de tous les logiciels d'envergure, y
compris les plus populaires, ncessite une initiation informatique ne ngliger sous
aucun prtexte. L'outil usuel pour ce faire consiste prsenter, explicitement ou
implicitement, un modle de fonctionnement. Le modle est une version abstraite
ultra-simplife du logiciel permettant de dcrire de faon aussi lmentaire que
possible les grandes lignes de sa structure. Un logiciel a un noyau (kernel) qui
est en quelque sorte son cur1 . Le modle est de faon analogue le noyau de son
apprentissage. On utilisera ici le modle Read-Eval-Print, selon la terminologie
devenue usuelle pour prsenter la structure du fonctionnement de la machine Lisp.

2.2 Read-Eval-Print.
2.2.1 Cycle Input-Output.
L'utilisateur de Maple voit d'abord un cycle Input-Output. Pendant la phase
Input, il entre au clavier une instruction Maple ; cette phase est termine par l'entre d'un  ; et de <Entre>. La phase Output est alors lance, se terminant
1 Un

tymologiste amateur peut raisonnablement suspecter que la concidence sonore cur 


ker nel n'est pas accidentelle.

42

dans les bons cas par l'achage juste aprs l'instruction entre du rsultat obtenu. Un nouveau groupe d'excution est ouvert, et le curseur est positionn juste
aprs le prompt. Une nouvelle phase Input commence o l'utilisateur va entrer son
instruction suivante, etc.
..................................................................................................................................

> 4 ;

4
..................................................................................................................................

Dans l'exemple prcdent particulirement simple, l'utilisateur a entr l'unique


instruction 4 (Input) et la phase Output a produit l'objet 4. Dans l'exemple
d'intgration qui avait t un peu considr Section 1.4 :
..................................................................................................................................

> int((1+x)/(1+x^2+x^4), x=1..infinity) ;


1
5
3 ln(3)
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .36
. . . . . . . . . . . . . .4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

l'Input est la chane de caractres int(...infinity), alors que l'Output est la


jolie formule rsultat.
L'utilisateur peut en fait entrer plusieurs instructions Maple spares par pointvirgule, condition de ne jamais taper le caractre <Entre> qui demande l'excution, mais seulement la combinaison <-Entre> pour chaque n de ligne.
Autrement dit on peut empiler plusieurs phases Input avant de faire excuter
les direntes phases Output correspondantes :
..................................................................................................................................

> Int(x^2, x) = int(x^2,x) ;


Diff(Int(x^2, x), x) = diff(int(x^2, x), x) ;
Z
1
x2 dx = x3
3
Z

x2 dx = x2
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . x
............................................................................

Mais par rapport au modle qu'il s'agit de dcrire, ces considrations sont
secondaires.
R
Le calcul de l'intgrale 1 1+x1+x
2 +x4 dx demande sur un PC de puissance moyenne
environ une demi-seconde de calcul, et c'est prcisment l que Maple est utile.
C'est la phase d'valuation. L'valuateur Maple a considr l'Input entr par l'utilisateur (plonasme) ; l'valuateur tait missionn pour l'valuer. C'est un travail
qui peut tre trs bref, comme plus haut quand il s'agissait d'valuer l'Input 4 ;
Maple constate alors presque instantanment qu'il n'y a aucun travail digne de
ce nom eectuer, et il retourne aussitt l'Output 4 ; c'tait trs bref, mais
il est quand mme capital pour la suite de comprendre qu'il y a bien eu une
phase d'valuation. Au contraire, pour le calcul de l'intgrale, la phase d'valuation est fort complexe : de nombreuses recherches doivent tre faites par Maple
pour comprendre qu'il doit eectuer une intgration, qu'il doit examiner la nature
de l'intgrande, voir si l'intgrale est dnie ou indnie, adopter une stratgie
pour trouver une primitive, la mettre en uvre, etc. C'est un travail sophistiqu,
mettant en uvre des ressources trs varies, mais peu importe, tout ceci est quand
mme une phase d'valuation.
43

2.2.2 L'valuateur.
Il est donc indispensable d'enrichir le cycle Input-Output pour en faire un cycle
trois temps que, compte tenu d'une trs ancienne tradition provenant de Lisp, on
prfre appeler le cycle Read-Eval-Print. Cette terminologie a un autre avantage,
elle prend dnitivement le point de vue de Maple. Maple apparat comme un chef
d'orchestre avec trois excutants :
1. Le Lecteur : c'est la composante de la machine Maple charge de lire le
texte entr par l'utilisateur, autrement dit l'Input. Le paradoxe usuel, si
coriace pour les super-dbutants, est toujours l ; l'utilisateur a l'impression
au contraire d'crire, mais son point de vue ne nous intresse pas ; on ne veut
considrer que le point de vue de Maple, qui doit bel et bien lire un objet
Maple, appel Input, savoir l'objet crit par l'utilisateur. Le Lecteur est
l'excutant consacr cette tche.
2. L'valuateur : c'est vraiment le cur de Maple ; l'valuateur doit valuer
l'objet Maple que le Lecteur vient de lire. Ce peut tre un travail quasiinstantan ; inversement il peut l'occasion ncessiter plusieurs jours de
calcul ; peu importe, c'est une valuation et c'est l'valuateur qui en est
l'excutant.
3. L'Imprimante qu'il est plus raisonnable dans le contexte d'aujourd'hui
d'appeler l'Acheur : une fois que l'valuateur a termin son travail, l'Acheur doit faire le ncessaire pour acher le rsultat de l'valuation l'cran,
rsultat obtenu par l'valuateur. C'est un travail assez technique, peu important en thorie, trs dlicat en pratique, mais absolument indispensable sans
quoi le travail de l'valuateur serait perdu. L'Acheur est ddi cette troisime phase.
On a dj utilis sans explication une terminologie qu'il est temps d'claircir. L'valuateur travaille en fonction de l'expression (Input) qu'il doit valuer.
Quand il a termin son travail, on dit qu'il retourne le rsultat, c'est l'Output
que l'acheur doit maintenant acher. Cette terminologie est devenue usuelle en
informatique, mais l'exprience montre qu'elle trouble encore beaucoup de mathmaticiens, et non des moindres. . . Pour la justier, il faut penser que l'valuateur
est un correspondant qui reoit, disons par la Poste, une lettre lui commandant tel
ou tel travail ; quand le travail est excut, l'valuateur en retourne le rsultat au
demandeur, en fait par l'intermdiaire de l'acheur. En particulier il ne s'agit pas
d'un refus retour l'expditeur ! La commande est en gnral honore et ce qui est
retourn est au contraire, au moins les bons jours, ce qui est souhait !
Maple se contente de faire travailler les trois excutants Lecteur, Evaluateur
et Acheur tour de rle. Compte tenu de cette organisation en cycles ReadEval-Print, l'utilisateur de Maple doit organiser son travail sous forme d'une suite
d'valuations d'objets dnir en fonction du problme rsoudre. Le travail de
comprhension de Maple se partage donc paralllement en trois parties.
1. On doit savoir comment travaille le Lecteur de Maple ; bien entendu la
connaissance de la structure interne du lecteur ne nous intresse pas ; par
contre nous devons connatre les mcanismes permettant de dcrire l'objet
44

Maple dont on va demander l'valuation. Cet objet a une structure interne


qui peut tre assez riche, et il va falloir comprendre comment il est possible de
dcrire cet objet plus ou moins complexe l'aide d'une chane de caractres
ordinaires, l'Input transmis au lecteur.
2. On doit savoir transformer notre problme mathmatique rsoudre en une
ou plusieurs valuations. Ceci ncessite bien sr une connaissance parfaite du
travail de l'valuateur. La nature rcursive de l'valuateur joue de ce point
de vue un rle essentiel.
3. Un minimum de technique sera aussi ncessaire pour que l'achage du rsultat de l'valuation corresponde raisonnablement au but qui est recherch.

2.2.3 Rcursivit des types de donnes.


Un autre ingrdient facilite sensiblement la couverture de ces sujets. On expliquera en temps utile ce qu'il faut comprendre par nature rcursive de l'valuateur.
Avant de penser valuation, il faut considrer quels sont les objets valuables,
autrement dit quels sont les dirents objets sur lesquels on peut faire travailler
l'valuateur. C'est une question de structure de donnes, l'un des sujets cls de
l'informatique moderne. Il se trouve que la dnition des objets Maple, plus prcisment de leur structure possible, est elle aussi rcursive. Ceci veut dire qu'un
nombre relativement petit de structures lmentaires va tre susant pour dcrire,
grce la rcursivit du mcanisme, tout objet Maple. Par exemple l'objet :
int((1+x)/(1+x2+x4), x=1..infinity)

est un objet function2 . Un tel objet est toujours de la forme (externe) :


obj0(obj1, obj2, ..., objn)

Peu importe ce que sont les objets composants obj0, . . ., objn, notre objet compos est un objet function propos duquel des rgles universelles de construction,
d'valuation et d'achage sont applicables. Les dirents composants sont des objets quelconques ; ils peuvent tre leur tour, pourquoi pas, des objets function,
ou bien des objets d'autres types qu'on tudiera le moment venu, il y en a une
grande varit. Dans notre exemple, le composant obj0 est l'objet symbol3 int,
le composant obj1 est l'objet *4 (1+x)/(1+x2+x4), enn le dernier composant obj2 est l'objet equation x=1..infinity. Autrement dit tout type de donne
va donner lieu la description des objets de ce type comme constitus d'objets
composants, en gnral quelconques, assembls selon des rgles ne dpendant que
2 Les

questions de types sont importantes ; on utilise pour le souligner une police un peu
sophistique pour les noms de types ; choisis par les concepteurs de Maple, ce sont des noms
anglais.
3 Ainsi symbole quivaut objet symbol.
4 de rares exceptions prs, Maple code de faon interne les quotients A/B comme le produit
(A1)*(B(-1)), de sorte que pour Maple ces objets qui extrieurement paraissent tre des
quotients sont en fait des produits, de type *.

45

du type de donne en question. Certains types sont terminaux, on les appelle atomiques : ce sont des objets irrductibles en plus petits objets. Les symboles sont
de cette nature.
Ce mcanisme est trs bnque. Il va donc s'agir en dnitive de bien connatre
les types de donnes disponibles, qu'on peut considrer comme des constructeurs
lmentaires, capables de construire partir d'autres objets, simples ou complexes,
peu importe, un nouvel objet certainement plus complexe. Pour chaque type de
donne, il va falloir connatre sa structure interne ; mais un modle thorique pour
cette structure interne, plus commode, sura ; il va falloir aussi connatre sa forme
externe, autrement dit comment on peut prparer un tel objet comme une chane
de caractres qu'on donnera en Input au lecteur Maple pour qu'il construise eectivement l'objet souhait, en vue de son valuation . Le plus souvent on retrouvera
la mme forme externe l'achage, si un objet de ce type est un rsultat d'valuation ; cependant, pour le dernier point, un achage plus proche des habitudes des
mathmaticiens est souvent prfr. Considrons par exemple l'intgrale prpare
pour le Lecteur plus haut ; il pourrait se faire que cette intgrale (non value) soit
au contraire le rsultat d'une valuation, auquel cas elle serait alors ache :
..................................................................................................................................
Z

1+x
dx
1
+
x2 + x4
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

mais ces dirences entre forme externe lire et forme externe ache sont assez
secondaires.
Faisons cette petite exprience. Soit l'instruction :
..................................................................................................................................

> 'int((1+x)/(1+x^2+x^4), x=1..infinity)' ;


Z
1+x
dx
2
4
1 1+x +x

..................................................................................................................................

On a entr nouveau notre intgrale ftiche, ceci prs qu'elle est maintenant
quote : le premier et le dernier caractre sont maintenant des quotes, c'est--dire
des apostrophes ou, si on prfre, des accents aigus isols. L'anglicisme quote est
laid, mais sa smantique est si particulire qu'on prfre l'utiliser. Il s'agissait ici
d'empcher l'valuation de l'intgrale et, comme on l'observe l'cran, l'intgrale
est retourne telle quelle, sauf qu'elle apparat sous la forme typographique usuelle
des manuels de mathmatiques. Notre exprience consiste nous dmontrer que
la forme interne est bien la mme. Pour ce faire on amne la souris sur le rsultat
qui vient d'tre obtenu, et on slectionne ce rsultat par la manuvre usuelle de
balayage : la belle intgrale est maintenant dessine en jaune dans un rectangle
noir ; Maple fait plus, il ache dans une mini-fentre de la barre contextuelle, la
forme dite Maple-Notation de la mme intgrale ; on l'a souligne par une che
rouge dans la reproduction ci-dessous :

46

On voit que cette forme Maple-Notation n'est autre que notre Input, ceci
prs que les quotes d'encadrement ont disparu. On dtaillera ce point un peu plus
loin5 . On demande un copi de cette intgrale, par exemple par Ctrl-Insert. On
positionne ensuite le curseur au prompt en attente et on demande cette fois un coll,
par exemple par <-Insert>. On voit alors apparatre l'intgrale sous la forme ncessaire pour un Input, une chane de caractres rouges int((1+x)/...infinity),
celle qu'on a dj vue plusieurs fois :

La dirence d'achage entre ce que vous voyez l o le copi a t fait, d'une


part, et l o le coll a t fait, d'autre part, est due au contexte qui n'est pas
le mme ; Maple en a tenu compte pour acher sa guise le mme objet interne
5 Rgle

Eval-10

47

sous deux formes externes assez direntes en apparence, quivalentes sur le fond.
L'opration copi aurait aussi bien pu tre eectue dans la fentre contextuelle.
On peut mettre en vidence la sparation du travail entre Lecteur et Evaluateur d'une part, Evaluateur et Acheur d'autre part, comme suit. Considrons
l'expression absurde suivante, dont prudemment on empche d'abord l'valuation
(quotes) :
..................................................................................................................................

> 'int(sin(x), [1,2,3])' ;

Z
sin(x)d[1, 2, 3]

> % ;
Error, (in int) wrong number (or type) of arguments

..................................................................................................................................

L'intgrale est une expression qui, sans convention pralable, n'a pas de sens.
Mais c'est un objet Maple lgal, que le Lecteur de Maple sait lire, que l'Acheur
sait acher. L'instruction suivante demande l'valuation de cet objet ; l'valuateur
ne peut traiter cette intgrale et retourne donc un message d'erreur.

2.3 Notion d'environnement.


2.3.1 Un peu d'histoire.
Quand une session Maple est en repos, en attente de la prochaine commande,
l'tat interne de la session est dcrit par ce qu'on appelle un environnement. C'est
nouveau une question de modle : l'tat interne en question n'est autre que
la longue chane de bits en attente dans la mmoire de Maple, plus prcisment
dans les pages mmoire rserves Maple par le systme d'exploitation. Cette liste
plutt indigeste de 0's et de 1's va pourtant vous permettre des calculs peut-tre
de la plus haute importance. Pour la matriser, il est ncessaire de la modliser ;
le concept moderne d'environnement est l'outil cl.
Turing a invent sa fameuse machine thorique au milieu des annes 30 [3]. La
mmoire de sa machine tait aussi une suite de 0's et de 1's dont l'tat voluait
pendant le calcul ; la n du calcul, on y lisait le rsultat. Quand Von Neumann
a ralis la premire machine concrte en s'inspirant du modle de Turing, il y a
ajout une amlioration : le mcanisme d'adressage de la mmoire : chaque unit
mmoire est repre par un numro, son adresse ; les instructions machines citent
souvent de telles adresses pour utiliser d'une faon ou d'une autre le contenu de
l'unit mmoire correspondante, ou encore pour y copier une chane de bits
utiliser plus tard. Le modle thorique correspondant est la machine RAM [1].
Pour des programmes complexes, la gestion des adresses numriques devient
vite insupportable ; divers mcanismes de reprsentations symboliques des adresses
ont t imagins pour dcharger le programmeur. Les langages assembleurs, mme
les plus primitifs, disposent d'un tel mcanisme ; les langages volus a fortiori.
Dans un programme C, une dclaration int n ; demande au compilateur la rservation d'un mot mmoire o un entier peut tre install ; son adresse relle
48

restera inconnue de l'utilisateur, mais elle pourra tre cite indirectement l'aide
du symbole n. Si la dclaration est locale une procdure appele dynamiquement,
l'adresse relle machine est en gnral variable d'une invocation l'autre de la procdure, mais le mcanisme d'adressage symbolique dispense justement l'utilisateur
des technicits sous-jacentes : elles sont gres par le systme.
Ce mcanisme d'adressage symbolique s'est son tour montr insusant. Les
mthodes d'indirections dynamiques utilises en langages machines et assembleurs
depuis longtemps taient inaccessibles aux utilisateurs de langages dits volus
comme Fortran6 . Pour y remdier, on a imagin un nouveau type de donne, celui
de pointeur : un symbole de type pointeur reprsente une case mmoire contenant
l'adresse d'une autre case mmoire. Les mcanismes satellites d'allocation mmoire
avec mise jour d'un pointeur vers l'adresse de la zone mmoire alloue permettent
de nouvelles techniques de programmation trs puissantes, traitements de listes et
d'arbres notamment. Les langages PL/I puis Pascal ont t les premiers langages
populaires ayant parfaitement intgr ce type de donnes.
Les langages plus modernes, Lisp notamment7 , sont alls plus loin. Par une
organisation soigneuse des types de donnes disponibles, la notion de pointeur y a
t en apparence compltement supprime, alors qu'en fait les pointeurs y sont plus
prsents qu'ils ne l'ont jamais t ! C'est un point trs intressant de l'volution
des langages informatiques. L'ide cl est la suivante : compte tenu de l'importance
des pointeurs, au lieu de laisser l'utilisateur la libert de dcider quand un objet
est de type pointeur ou non, on organise le langage comme si tout objet tait
un pointeur potentiel ; c'est le systme sous-jacent qui prendra en dnitive les
dcisions ce propos. Typiquement, si un symbole n repre un entier, le systme
doit de toute faon rserver un mot mmoire pour n ; si la valeur de n est un
entier court, le systme peut dcider d'installer cet entier directement dans la
case rserve pour n ; si au contraire c'est un entier long ou trs long, le systme
dcide alors d'installer dans la case n l'adresse d'une liste contenant l'ensemble
de tous les ingrdients ncessaires pour dnir l'entier long en question ; quelques
bits systme sont rservs dans la case n pour indiquer quelle est la solution
utilise un instant donn. Ce type de mcanisme est devenu standard dans les
langages trs volus. L'utilisateur n'est d'ailleurs pas directement concern par
les techniques d'implmentation ; pour lui tout se passe comme si un symbole tait
toujours un pointeur.
C'est l'organisation adopte dans Maple. Un symbole est un pointeur vers un
objet de type quelconque, quelques variantes prs qu'on verra en temps utile.
Le couple [symbole objet point] est un chanage. L'ensemble de tous les
chanages en mmoire un moment donn est l'environnement en cours, et c'est
cet objet assez sophistiqu qu'il s'agit d'tudier dans cette section.
6 Les

versions rcentes de Fortran, depuis Fortran 90, disposent aussi du type pointeur ; la
notion de classe est prvue pour 2020 et la programmation fonctionnelle pour 2050.
7 Lisp est en fait un langage trs ancien, qui est n au dbut des annes 60, mais il n'est
devenu utilisable pour les grands projets qu'assez rcemment, depuis la dnition de la norme
ANSI Common Lisp.

49

2.3.2 Chanages.
Vocabulaire.
De bons petits exemples valent mieux que des tonnes de thorie. Considrons
cette micro-session Maple :
..................................................................................................................................

> x := 34 ;

x := 34
..................................................................................................................................

Quand vous commencez une session Maple, l'environnement en cours est


l'environnement initial. Ci-dessus l'excution de l'instruction x := 34 modie
l'environnement initial. Un nouveau chanage [x 34] y est ajout, alors qu'auparavant aucun chanage de source x n'y tait prsent. Si un chanage de source
x est prsent dans l'environnement, par abus de langage, on dit que le symbole x
est prsent dans l'environnement, ou plus brivement qu'il est prsent. L'environnement initial n'est autre que l'ensemble de tous les chanages prinstalls quand
une session Maple est commence. Un chanage est un couple [symbol object]
de source un symbole et de but un objet Maple quelconque ; on dira simplement
un objet.
Un environnement est donc un ensemble de chanages dcrivant quels sont ce
moment les symboles aects. Chaque symbole aect est la source d'un chanage,
dont le but est un objet quelconque. Un symbole est source au plus d'un chanage.
Un symbole qui n'est pas aect est un symbole libre ; ces symboles libres vont
jouer un rle essentiel en calcul symbolique, un type de calcul qui est la principale
raison d'tre de Maple.
Il est trs tentant ici d'appeler valeur d'un symbole aect le but du chanage
correspondant, mais, dans un premier temps, il ne faut surtout pas le faire. On
verra que dans un environnement donn, la valeur d'un symbole, presque toujours
bien dnie, n'est pas en gnral le but du chanage de source ce symbole. On
donne un exemple un peu plus loin. Il faut dire, si [symbol object] est un
chanage, que le symbole symbol pointe vers l'objet object.

Voir un chanage.
Le lecteur souhaite probablement voir un chanage de l'environnement initial. Pour voir le chanage ventuel de source le symbole symb, il faut excuter
eval(symb, 1). Par exemple la mise en vidence du chanage [x 34] install
ci-dessus peut tre obtenue par :
..................................................................................................................................

> eval(x, 1) ;

34
..................................................................................................................................

Si, au dbut d'une session Maple vous voulez voir par exemple le chanage de
source le symbole sin, procdez de mme.

50

..................................................................................................................................

> eval(sin, 1) ;

readlib('sin')

..................................................................................................................................

La procdure sin sait calculer le sinus de nombres rels ou complexes. L'environnement initial contient ce qu'il faut pour faire savoir Maple, le cas chant,
que la procdure sin peut tre obtenue par chargement partir de la bibliothque
standard. Vous tes peut-tre tent par un exemple plus simple, consistant voir
par exemple la valeur de dans l'environnement initial, mais vous allez tre du :
..................................................................................................................................

> eval(Pi, 1) ;

..................................................................................................................................

Quand un symbole, d'aprs eval(..., 1), pointe vers lui-mme, c'est qu'en fait
ce symbole est absent de l'environnement, et c'est le cas du symbole Pi si important
pour les mathmaticiens ; noter au passage qu'on trouve ici aussi une situation o
l'unique objet interne, le symbole de nom Pi, a une forme externe input Pi assez
dirente de la forme externe output choisie par l'Acheur : . Mais o donc par
exemple est localise l'information que est peu dirent de 3.14 ? On l'obtient
par la procdure evalf :
..................................................................................................................................

> evalf(Pi, 4) ;

3.142
..................................................................................................................................

C'est donc le symbole evalf et non pas le symbole Pi qui est prsent dans l'environnement initial de telle faon que l'information 3.142 soit accessible ; le
deuxime argument 4 de evalf demandait une approximation quatre chires dcimaux. Bien noter que le fait que Pi soit absent de l'environnement ne signie pas
qu'il n'y soit pas rfrenc. C'est un point de terminologie important : un symbole
est prsent dans un environnement si et seulement s'il est la source d'un chanage.
On peut par exemple modier le chanage de source x par :
..................................................................................................................................

> x := Pi ;

x :=
..................................................................................................................................

de telle sorte que x pointe vers le symbole Pi ; le symbole Pi est donc dsormais
rfrenc, mais il reste absent de l'environnement. Le symbole Pi est libre, ce qui
est un peu trange par rapport son statut mathmatique ; ce sont les procdures
utilisatrices de Pi qui sont au parfum et sauront faire les calculs quelquefois
diciles que vous attendez. Vous pouvez aussi tre tent par :
..................................................................................................................................

> Pi := 355/113 ;

Error, attempting to assign to `Pi` which is protected

..................................................................................................................................

On voit que Pi est un symbole mieux que libre, il est protg ; en particulier vous
ne pouvez pas le rendre prsent dans l'environnement8 .
8

moins de lever la protection (unprotect), mais, sauf cas trs spcial, c'est franchement
dconseill !

51

Un symbole qui ne pointe pas vers sa valeur.


Examinons maintenant une situation o la valeur d'un symbole n'est pas l'objet
point par ce symbole.
..................................................................................................................................

> a := b ;

a := b

> b := c ;
b := c
..................................................................................................................................

Deux chanages [a b] et [b c] sont maintenant installs. Regardons l'objet


point par a, puis la valeur de a :
..................................................................................................................................

> eval(a, 1) ;

> a ;
c
..................................................................................................................................

On voit que la valeur c du symbole a, autrement dit le rsultat de l'valuation du


symbole a n'est pas l'objet point par a. Le fonctionnement de l'valuateur Maple
est vritablement la pice matresse du logiciel ; les rgles de fonctionnement de
l'valuateur seront runies dans des paragraphes spciaux intituls Eval.

Eval 7  La valeur d'un symbole9 est dnie comme suit :


1. Si le symbole est libre, c'est le symbole lui-mme (valuation triviale) ;
2. Si le symbole est prsent dans l'environnement, le but du chanage correspondant est valu et le rsultat de cette valuation sera la valeur du symbole
dans cet environnement (post-valuation).
Voir cependant l'exception Eval-16.
C'est la premire fois que la nature rcursive de l'valuateur est observe : si le
symbole est prsent, sa valeur est. . . la valeur de l'objet point. En consquence,
un objet point par un symbole peut ne pas tre la valeur ce ce symbole ; il en sera
ainsi si l'objet point est valuation non triviale. C'tait le cas pour le symbole a
plus haut : l'objet point b avait une valeur non triviale c. Si on ajoute maintenant :
..................................................................................................................................

> c := d ;

c := d

> a ;
d
..................................................................................................................................

et ainsi de suite.

Warning 8  Si la valeur du symbole symb est l'objet obj dirent de symb, ceci
n'implique pas que le symbole symb pointe vers l'objet obj. La seule conclusion
correcte est la suivante : la valeur de l'objet obj2 point par symb est obj.
9 On

verra Chapitre 6 qu'il y a une rgle d'valuation particulire pour les paramtres de
procdures et leurs symboles locaux.

52

Et si on introduit un cycle dans l'ensemble des chanages ? Le cycle le plus


simple serait celui d'un symbole pointant vers lui-mme, mais ceci est impossible.
Si on demande qu'un symbole pointe vers lui-mme, Maple comprend qu'on veut
en fait le librer ! Dans ces jeux ( ?) de chanage, il peut tre important de revenir
l'environnement initial, ce qui est obtenu par la commande :
..................................................................................................................................

> restart ;

..................................................................................................................................

Ceci restaure l'environnement initial et en particulier dtruit les chanages prcdemment installs par l'utilisateur. Ne pas s'tonner de l'absence apparente d'output ; il y en a bien un mais c'est l'objet vide, dont l'achage est aussi vide ! Ce
point sera dtaill plus tard. Si vous demandez maintenant :
..................................................................................................................................

> a := a ;

a := a
..................................................................................................................................

l'environnement n'est pas modi ; c'est une convention : demander qu'un symbole pointe sur lui-mme, c'est demander conventionnellement de le librer10 . S'il
tait dj libre, l'environnement n'est donc pas modi. Prenons maintenant au
contraire le cas o le symbole a serait prsent :
..................................................................................................................................

> a := b ;

a := b
..................................................................................................................................

Comment librer a ? Ceci ne fonctionne pas :


..................................................................................................................................

> a := a ;

a := b

> a ;
b
..................................................................................................................................

Vous avez ici la surprise de voir qu'aprs avoir demand (input) que a pointe
vers a, Maple dcide de le faire pointer. . . vers b, comme le montre l'output ! Que
comprendre ? Il y a ici un autre point de rcursivit trs important.

Eval 9  Une instruction d' aectation symb := obj est excute en deux

temps :

1. L'objet obj est valu et, si cette valuation termine, elle retourne un objet
obj2 ;
2. Un chanage [symb obj2] est install dans l'environnement. Si le symbole
symb tait dj prsent dans l'environnement, le chanage antrieur est retir.
C'est pourquoi, dans la commande qui semblait si innocente a := a, Maple
a d'abord valu le second membre a et l'valuateur a retourn b ; Maple dcide
donc d'aecter b a comme le montre ce qui est indiqu par l'acheur ; en dnitive la situation reste inchange : l'ancien chanage est dtruit, mais le mme est
10 Voir

aussi les procdures unassign et assigned expliques Section 2.6.

53

aussitt rinstall ! D'une faon gnrale, une instruction symb := symb modie
l'environnement comme suit : le chanage de source symb est redni pour pointer
vers la valeur actuelle de symb. L'exprience ad hoc est la suivante.
..................................................................................................................................

> restart ;
a := b ; b := c ; c:= d ;

a := b
b := c
c := d

> eval(a,1) ;
a ;
b
d

> a := a ;
a := d

> eval(a,1);
a ;
d
d
..................................................................................................................................

Bien, mais comment alors aecter a a, autrement dit comment retirer de


l'environnement le chanage de source a ? Il faut quoter le membre de droite de
l'instruction d'aectation, pour empcher son valuation.

Eval 10 L'valuation d'une expression quote 'expr' retourne l'objet expr non
valu, quotes retirs.

..................................................................................................................................

> a := 'a' ;

a := a

> a ;
a
..................................................................................................................................

Il est donc, malgr les apparences, impossible d'installer un chanage [a a].


Mais peut-on installer deux chanages [a b] et [b a] ? Oui, mais pas comme
a :
..................................................................................................................................

> a := b ; b := a ;

a := b
b := b
..................................................................................................................................

Car ds que a pointe vers b, l'valuation de b := a demande en fait de faire


pointer b vers la valeur de a, savoir b, et en dnitive b reste libre. Il faut donc
faire :
..................................................................................................................................

> restart ;
> a := b ; b := 'a' ;

a := b
b := a
..................................................................................................................................

54

Et cette fois on a bien install un cycle d'ordre 2 dans les chanages. On peut
dans ces conditions, compte tenu de la rcursivit de l'valuation des symboles (cf.
Eval-7), tre assez perplexe sur le rsultat de l'valuation de a (ou b). Maple aussi :
..................................................................................................................................

> a ;

Error, too many levels of recursion

..................................................................................................................................

C'est notre premier exemple d'une valuation qui ne termine pas. Les deux chanages rciproques [a b] et [b a] provoquent une rcursivit sans terminaison de l'valuateur. Le rsultat obtenu dpend du systme sous-jacent ; le
message d'erreur ach ici est obtenu sous Windows ; sur certains systmes Unix,
aucun message d'erreur n'est ach ; de plus l'valuation indnie ne peut mme
pas tre interrompue de l'intrieur de Maple par le bouton stop ; la seule solution
est l'interruption extrieure, par exemple par la commande Unix kill mise par
un autre process ; mais la session Maple est perdue !

Les valuations ne permutent pas toujours.


Une autre consquence des rgles d'valuation Eval-7 et Eval-9 est la dissymtrie surprenante pour les non-initis entre les deux squences d'instruction suivantes.
..................................................................................................................................

> restart ; a := b ; b := c ; b := d ;
a, eval(a, 1) ;
a := b
b := c
b := d
d, b
> restart ; b := c ; a := b ; b := d ;
a, eval(a, 1) ;
b := c
a := c
b := d
c, c

..................................................................................................................................

On voit que l'ordre des aectations est important. Dans le premier cas, b est aect
a avant que c soit aect b ; compte tenu de l'aectation de d b, il en rsulte
que la valeur de a est d, dirente de l'objet point par a. Dans le second cas,
les deux premires aectations sont changes ; l'aectation demande a := b
aecte donc la valeur de b, soit c, a ; le nouveau chanage install pour b ne
modie donc pas la valeur de a.
Le lecteur est normalement troubl par les virgules sparant a de eval(a, 1),
alors qu'on devrait sparer par un point-virgule les deux instructions demandant,
la premire, l'valuation de a, la seconde, l'valuation de eval(a, 1). On verra
par la suite qu'en fait le texte a, eval(a, 1) est la forme externe d'un unique
objet Maple deux composants ; en Maple, la virgule n'est pas un sparateur,
c'est un oprateur constructeur de suites. Ces notions seront dtailles plus loin
55

Chapitre 4. Pour le moment, vous pouvez considrer qu'est ainsi disponible une
mthode permettant d'acher deux objets Maple ou plus sur une seule ligne. Par
contre vous ne pouvez faire de mme avec deux instructions d'aectation, car ces
instructions ne sont pas des objets Maple.
..................................................................................................................................

> a := 1 , a :=
| 2 ;
`:=` unexpected

..................................................................................................................................

2.3.3 Bugs possibles.


Les mcanismes d'valuation de Maple sont puissants, mais provoquent souvent
des bugs diciles pour les novices. Compte tenu de ce qui vient d'tre expliqu sur
l'valuation des symboles, on prfre anticiper un peu et expliquer immdiatement
deux bugs frquents directement lis ces questions. Ils proviennent de symboles
que l'utilisateur croit libres et qui en fait ne le sont pas.

Variables prtendues libres.


On a dj vu, on donnera les dtails plus tard, que les intgrations raisonnables
peuvent tre tentes l'aide de la procdure int. Par exemple :
..................................................................................................................................

> int(exp(-x^2)/(1+x^2), x=-infinity..infinity) ;


e e erf(1)
> evalf(%) ;
1.343293422

..................................................................................................................................

Il faut en particulier utiliser une variable libre, ici x, pour faire savoir Maple
par rapport quelle variable l'intgration doit tre eectue, et aussi, s'il s'agit
d'une intgrale dnie, quel est l'intervalle d'intgration. Pour Maple, cette variable libre est en fait un symbole, mais par abus de langage, tenant compte aussi
du contexte mathmatique, on parle souvent de variable libre. Toujours est-il
que ce symbole doit tre eectivement libre, sous peine d'erreur assez souvent rebelle. Le scenario est habituellement le suivant ; on fait pendant un moment de
petits calculs et il est alors tentant, quand on souhaite conserver pour un temps
une valeur numrique un peu complique de l'aecter un symbole quelconque,
pourquoi pas x. Par exemple la valeur numrique de la fonction en 1/3 pourrait
tre utilise de faon un peu rptitive et pour viter de devoir retaper chaque
fois evalf(GAMMA(1/3)), vous pouvez choisir de demander :
..................................................................................................................................

> x := evalf(GAMMA(1/3)) ;

2.678938537
..................................................................................................................................

Le choix du symbole x n'est pas merveilleux ; il faut toujours mieux utiliser un


symbole avec un minimum de lisibilit, peut-tre ici g3, mais comme justement on
sait que dans dix minutes, ce point sera sans objet, en mal d'inspiration on choisit
souvent un symbole trs pauvre, x par exemple.
56

Bien ! Eectivement la session Maple volue, la question faisant intervenir ponctuellement la quantit (1/3) est traite, on passe la suite du plan de travail ; les
divers sujets se succdent et quelquefois beaucoup plus tard, mais dans la mme
session, on doit valuer l'intgrale eulrienne indique plus haut.
..................................................................................................................................

> int(exp(-x^2)/(1+x^2), x=-infinity..infinity) ;


Error, (in int) wrong number (or type) of arguments

..................................................................................................................................

On est pourtant absolument certain d'avoir dj trait ce type d'intgrale comme


on le voit ici, sans avoir rencontr de problme signicatif. Aurait-on oubli quelque
chose au sujet de la syntaxe dj un peu complexe ? On examine patiemment la
page d'aide de la procdure int ; elle contient beaucoup d'exemples, certains assez
impressionnants, mais rien ne permet d'y dcouvrir une faute quelconque dans
notre utilisation. Alors quoi ?

Conseil 11  Dans une instruction fautive rebelle, examinez soigneusement le


statut des symboles utiliss, notamment de ceux qui devraient tre libres.
Une erreur peut en eet provenir d'un symbole qui normalement devrait tre
libre, mais qui en fait est prsent dans l'environnement en cours. Les rgles d'valuation impliquent le plus souvent que les occurences de ce symbole sont remplaces
par sa valeur, et ceci peut tre l'origine d'une erreur. C'est ce qui se produisait
plus haut. L'instruction d'intgration ne peut tre russie que si le symbole x est
libre ; en fait ici x pointe vers (1/3) = 2.678938537, de sorte que le mcanisme
d'valuation pralable des arguments de int demande en fait l'valuation de :
..................................................................................................................................

> int(exp(-2.678938537^2)/(1+2.678938537^2), 2.678938537=-infinity..infinity);

..................................................................................................................................

La variable x a disparu, remplace par sa valeur. La fonction intgrer est devenue


une constante, l'intgrale est maintenant divergente ! L'expression symb = ...
expliquant par rapport quelle variable il faut intgrer est devenue non sens et
provoque l'erreur de type.

Variable pilote value trop tt.


Une variante frquente de l'erreur montre dans la section prcdente est la suivante. Un oprateur commode qu'on examinera en dtail plus loin, l'oprateur $,
permet de construire facilement des suites plus ou moins compliques ; par exemple
pour construire la liste des carrs des entiers de 10 20, on peut demander :
..................................................................................................................................

> SquareList := [i^2 $ i=10..20] ;


SquareList := [100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400]

..................................................................................................................................

Une lecture correcte de l'objet valu va comme suit : la liste des i2 pour ($ =
pour) i variant de 10 20. La liste en question est eectivement retourne.
Comme tout langage impratif, Maple propose des instructions itratives. Par
exemple pour acher les valeurs de l'intgrale de 1/(1+x3 ) entre 0 et les premires
puissances de 10, on pourrait demander :
57

..................................................................................................................................

> for i from 1 to 5 do


evalf(int(1/(1+x^3), x = 0..10^i))
od ;
1.204201575
1.209149577
1.209199076
1.209199571
1.209199574

..................................................................................................................................

Mais si, ceci fait, vous demandez maintenant la construction de SquareList comme
ceci avait pourtant t russi auparavant :
..................................................................................................................................

> SquareList := [i^2 $ i=10..20] ;

Error, wrong number (or type) of parameters in function $

..................................................................................................................................

vous obtenez une erreur trange. C'est le moment de penser Conseil-11 ; le seul
symbole suspect est i, et il faut donc l'examiner :
..................................................................................................................................

> i

6
..................................................................................................................................

On voit que le symbole i a la valeur 6 ! En eet l'instruction itrative for a


demand de faire varier i de 1 5 ; le processus a t interrompu quand i avait
atteint la valeur 6, mais le chanage [i 6] est rest prsent11 dans l'environnement. Donc, compte tenu du mcanisme d'valuation, l'instruction d'aectation
demande quivaut :
..................................................................................................................................

> SquareList := [6^2 $ 6=10..20] ;

Error, wrong number (or type) of parameters in function $

..................................................................................................................................

qui est incohrente, car ce qu'on appellera plus tard la variable pilote pour la
procdure $ est ici l'entier 6, mais un entier n'est pas une variable ! Si on empche
(quotes) l'valuation de i :
..................................................................................................................................

> SquareList := [i^2 $ 'i'=10..20] ;


SquareList := [36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36]

..................................................................................................................................

cette fois la procdure $ peut travailler, mais l'valuation prmature du premier
terme i^2 ne donne pas le rsultat escompt ! Pour obtenir le bon rsultat, il faut
aussi quoter le premier i :
..................................................................................................................................

> SquareList := ['i'^2 $ 'i'=10..20] ;


SquareList := [100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400]

..................................................................................................................................

Conseil 12  En prsence d'une erreur rebelle, rchir si une valuation imprvue n'a pas impliqu l'invocation d'une procdure avec des arguments incorrects.
11 Contrairement

Lisp.

ce qui est maintenant standard, par exemple dans les langages C, Java et

58

2.4 valuateur rcursif.


Si on a lu soigneusement la section prcdente, en rptant patiemment les
exemples prvus sur son poste de travail, on commence avoir une ide intuitive du
fonctionnement de l'valuateur Maple. Deux principes gnraux sont applicables.

2.4.1 Post-valuation.
Eval 13  Quand un rsultat d'valuation est obtenu, Maple examine si ce rsul-

tat est son tour non trivialement valuable. Si la rponse est ngative, le processus d'valuation est termin. Si au contraire la rponse est positive, le rsultat de
l'valuation sera en dnitive le rsultat de l'valuation du rsultat prcdemment
obtenu.
Il est clair que dans la deuxime hypothse aucune garantie ne peut tre obtenue sur la terminaison du processus d'valuation. L'exemple des deux chanages
rciproques [a b] et [b a] a montr qu'il peut eectivement arriver que
l'valuation ne termine pas. Pour illustrer la porte plus gnrale de Eval-13,
considrons la situation suivante. On fait pointer le symbole a vers la liste des
deux symboles b1 et c1 ;
..................................................................................................................................

> restart ;
> a := [b1, c1] ;

a := [b1, c1]

..................................................................................................................................

Ensuite on cre deux suites de chanages [b1 -> b2 -> b3] et [c1 -> c2 -> c3 ->
c4]. On verra page
les dtails concernant l'oprateur || (concatnation12 ) ;
les aectations rsultantes sont aches.
..................................................................................................................................

> for i from 1 to 2 do b||i := b||(i+1) od ;


b1 := b2
b2 := b3
> for i from 1 to 3 do c||i := c||(i+1) od ;
c1 := c2
c2 := c3
c3 := c4

..................................................................................................................................

Ceci tant fait, grce aux procdures trs particulires seq et eval, dtails plus
tard, on peut acher les phases intermdiaires du processus d'valuation. On
ache ensuite le rsultat de l'valuation banale de a :
12 Jusqu'

Maple 5, l'oprateur de concatnation tait l'oprateur dot, reprsent par un point


(`.') et non pas par la double barre (`||').

59

..................................................................................................................................

> seq(eval(a, i), i=1..5) ;


[b1, c1], [b2, c2], [b3, c3], [b3, c4], [b3, c4]
> a
[b3, c4]

..................................................................................................................................

Il a donc fallu quatre phases d'valuation pour aboutir au rsultat dnitif. Si on


ajoute un chanage [c4 c2], il est clair que l'valuation ne termine plus :
..................................................................................................................................

> c4 := 'c2' ;

c4 := c2

> a ;
Error, too many levels of recursion

..................................................................................................................................

2.4.2 Pr-valuation.
La rgle Eval-13 indique qu'une valuation a posteriori est toujours tente. La
rgle d'valuation suivante demande au contraire une pr-valuation.

Eval 14  Quand un objet function :


obj0(obj1, obj2, ..., objn)

doit tre valu, l'oprateur obj0 et les oprandes13 obj1, . . ., objn sont valus
squentiellement avant d'tre utiliss. L'valuation de obj0 est de type explicite14
alors que l'valuation des autres arguments est de type implicite.
La rgle Eval-14 a de trs nombreuses exceptions, et son interprtation prcise
est assez dlicate, surtout quand il s'agit du traitement de l'oprateur obj0. Si
la valeur procdure de obj0 est une procdure non standard, le traitement des
oprandes peut tre trs dirent.

Eval 15  Une procdure est standard si la rgle Eval-14 s'applique strictement


quand elle est invoque.

On se contentera sagement dans un premier temps d'illustrer l'esprit gnral


de la rgle Eval-14, ce qui sura pour commencer. Plus tard, au fur et mesure
qu'on avancera dans la connaissance de Maple, cette rgle sera plusieurs reprises
complte, quelquefois pour examiner son application dans certaines situations
exceptionnelles, d'autres fois pour en prciser l'interprtation propos de tel ou
tel dtail, d'autres fois encore ce qui advient quand une procdure est non standard.
Considrons les procdures mathmatiques suivantes. La procdure Psi calcule
la (n + 1)-ime drive logarithmique de la fonction : (n, x) = (n) (x) o
(x) = 0 (x)/(x) :
13 Appels

14 Voir

aussi arguments.
ce propos Eval-16.

60

..................................................................................................................................

> Psi(2, 3.4) ;

.1155897239
..................................................................................................................................

La procdure round arrondit un ottant l'entier le plus proche :


..................................................................................................................................

> round(3.8) ;

4
..................................................................................................................................

Considrons enn l'valuation de l'expression suivante :


..................................................................................................................................

> Psi(round(tan(2.5)), sin(5.1)) ;


2.639819868 3.141592654 I

..................................................................................................................................

Le rsultat est un complexe dont la partie imaginaire semble i.


La rgle Eval-14 explique que l'expression valuer tant un objet function, cet
objet est dstructur en sous-objets. Ici, trois composants numrots de 0 2. Le
composant obj0 est le symbole Psi ; le symbole Psi est d'abord valu, et Maple
trouve comme rsultat un objet procedure ; on peut le voir comme suit :
..................................................................................................................................

> eval(Psi) ;

proc ... end

..................................................................................................................................

Raisonnablement, Maple prfre n'acher que sous une forme trs simplie l'objet procedure valeur, vous faisant grce du texte source fort complexe. L'valuateur observe que cette procdure est standard 15 et qu'elle est invoque avec
deux arguments ; le premier, appel obj1 dans la rgle Eval-14 est l'expression
round(tan(2.5)), le second, obj2, est l'expression sin(5.1). La terminologie suivante sera systmatiquement utilise dans la suite, elle est particulirement commode pour dcrire le fonctionnement de la rgle Eval-14 dans un cas particulier.
L'expression round(tan(2.5)) est le premier argument provisoire ; de la mme faon, l'expression sin(5.1) est le deuxime et dernier argument provisoire. La rgle
Eval-14 explique que ces arguments doivent tre valus avant d'tre utiliss. Les
rsultats de ces valuations seront les arguments dnitifs , ceux avec lesquels la
procdure Psi va eectivement travailler.
C'est ce point que l'valuateur est rcursif. L'exemplaire de l'valuateur qui
tait en activit pour traiter l'valuation principale est mis provisoirement au repos. Un deuxime exemplaire de l'valuateur est invoqu pour eectuer l'valuation
ncessaire de notre argument provisoire round(tan(2.5)). Pour cette invocation,
de nouveaux ingrdients sont identis ; l'oprande obj0 est cette fois le symbole
round, l'unique argument obj1 est l'expression tan(2.5). Cet argument, provisoire,
doit aussi tre valu avant d'tre utilis, etc. Le schma complet de l'valuation
est donc le suivant :
Eval1(Psi(round(tan(2.5)), sin(5.1)))
obj0p = Psi
15 Dans

de nombreux cas qui seront examins plus tard, la procdure est non-standard et les
arguments ne sont pas traits de la mme faon.

61

Eval2(Psi)
Eval2 -> procedure(Psi)
objOd = procedure(Psi)
obj1p = round(tan(2.5))
Eval2(round(tan(2.5)))
obj0p = round
Eval3(round)
Eval3 -> procedure(round)
obj0d = procedure(round)
obj1p = tan(2.5)
Eval3(tan(2.5))
obj0p = tan
Eval4(tan)
Eval4 -> procedure(tan)
obj0d = procedure(tan)
obj1p = 2.5
Eval4(2.5)
Eval4 -> 2.5
obj1d = 2.5
procedure(tan) works with 2.5
Eval3 -> -.7470222972
obj1d = -.7470222972
procedure(round) works with -.7470222972
Eval2 -> -1
obj1d = -1
obj2p = sin(5.1)
Eval2(sin(5.1))
obj0p = sin
Eval3(sin)
Eval3 -> procedure(sin)
obj0d = procedure(sin)
obj1p = 5.1
Eval3(5.1)
Eval3 -> 5.1
obj1d = 5.1
procedure(sin) works with 5.1
Eval2 -> -.9258146823
obj2d = -.9258146823
procedure(Psi) works with -1 and -.9258146823
Eval1 -> 2.639819868+3.141592654*I

On a utilis quelques conventions assez videntes pour ne pas tre envahi par
l'achage de tout ce qui serait en principe ncessaire. Chaque invocation de l'valuateur correspond une squence :
Evaln(expr)
...
...
Evaln -> ...

o en entre gure l'expression valuer et en sortie l'objet retourn par l'valuation. Quand cette invocation est active, l'invocation prcdente est mise au repos.
Une indication comme obj1p = ... indique qu'un composant avant valuation
62

est identi, p pour provisoire ; symtriquement une indication obj1d = ...
indique le mme composant aprs valuation, d pour dnitif. Enn une indication comme procedure(sin) note de faon symbolique l'objet procedure associ
au symbole sin, en gnral trs complexe.
On voit que le mcanisme d'valuation rcursive d'un objet function suit une
chronologie trs prcise et relativement complexe. L'objet valuer est d'abord dstructur pour obtenir les dirents composants. Le plus souvent, ces composants
sont valus avant d'tre utiliss, auquel cas le mcanisme en cours de description
s'applique son tour, rcursivement, aux composants. Quand les versions dnitives des composants sont obtenues, la procdure valeur du composant obj0
travaille enn avec les arguments dnitifs.
Il peut se faire que la valeur de obj0 ne soit pas une procdure mais par exemple
un symbole. Le mcanisme sera exactement le mme, ceci prs que la dernire
tape travail de la procdure est omise.
..................................................................................................................................

> restart ;
> f:= g ; g := h ; f(round(tan(2.5)), sin(5.1)) ;
f := g
g := h
h(1, .9258146823)

..................................................................................................................................

Bref, en parlant simplement, Maple value ce qu'il peut.


Au fait, pour quelle raison l'valuation de notre expression (round(tan(2.5)),
sin(5.1)) retournait-elle un nombre complexe ? Comme l'a montr l'analyse de
l'valuation, il s'agissait en fait de (1, .9258146823) ; Maple devait donc considrer la drive d'ordre -1 de la drive de ln() ; la drive d'ordre -1 est logiquement la primitive, et le rsultat doit donc tre ln((.9258146823)) ; mais la
valeur de la fonction en ce point est ngative et la dtermination principale du
logarithme d'un nombre ngatif a, au moins pour Maple, i pour partie imaginaire.

2.4.3 Une premire exception.


Le lecteur perspicace a en principe t troubl dans la section prcdente
quand on montrait la valeur procdure du symbole Psi. Il tait indiqu d'valuer
eval(Psi) ; pourquoi pas seulement Psi ? Considrons ces trois possibilits :
..................................................................................................................................

> Psi

> eval(Psi) ;
> eval(Psi, 1) ;

Psi

proc ... end


proc ... end

..................................................................................................................................

On voit grce au dernier essai que le chanage du symbole Psi vers la procdure
prdnie associe est bien l, mais l'valuation banale de Psi semble ne pas tenir
63

compte de ce chanage.

Eval 16  Si un symbole pointe vers une procdure ou une table, l'valuation

implicite de ce symbole retourne seulement le symbole initial ; l'valuation explicite


retourne la procdure ou la table.

Par dfaut, l'valuation d'un symbole est implicite ; elle est explicite dans deux
circonstances :
1. L'valuation est demande par l'intermdiaire de la procdure eval ;
2. Le symbole est valu en position oprateur d'une expression fonction ou
objet index.
On verra plus tard le cas des objets indexs. L'exemple compltement articiel
suivant illustre le cas des objets function :
..................................................................................................................................

> f1 := proc (arg1)


RETURN(arg1)
end :
> f1(35) ;

35

> f2 := proc (arg2)


RETURN(2*arg2)
end :
> f2 ;
f2

> eval(f1) ;

proc(arg1) RETURN(arg1) end

> f1(f2) ;
f2

> % ;
f2

> %(exemple) ;
2 exemple
..................................................................................................................................

Les deux procdures aectes f1 et f2 sont analogues ; elles retournent respectivement l'unique argument pass ou son double. On voit que l'valuation de
f1(35) a bien fait intervenir la procdure, car le symbole f1 est en position oprateur. Par contre l'valuation de f2 seul est implicite et la procdure but n'est
pas retourne. Dans l'valuation de f1(f2), l'valuation de f1 est explicite, alors
que celle de f2 est implicite, d'o le rsultat. Le pseudo-symbole % (objet ditto)
chane toujours vers le dernier rsultat obtenu, mais l'valuation est implicite et
l'valuation s'arrte donc f2. Enn dans la dernire expression, puisque % est
en position oprateur, l'valuation est explicite et la procdure valeur de f2 va
travailler, d'o le rsultat.
Un tel exemple est compltement articiel et a pour seul intrt de mettre
en vidence le mcanisme de fonctionnement de la rgle Eval-16. Il illustre aussi
comment justement concevoir des exemples articiels trs simples permettant de
dvisser le fonctionnement de l'valuateur.
64

2.5 D'autres objets de type function.


Contrairement Lisp, Maple a sacri aux usages remontant aux langages
prhistoriques style Fortran, o on considre comme insupportable de demander
que toutes les expressions soient prxes. L'expression qu'on crit en Fortran,
Ada, C, Java ou Maple sous forme inxe : (a + b) * (c + d) s'crit en Lisp
sous forme prxe (* (+ a b) (+ c d)). Les diteurs modernes savent faire
clignoter la parenthse ouvrante correspondant la parenthse fermante o le
curseur est positionn ; ce n'est malheureusement pas le cas de l'diteur intgr
de Maple. Quand un diteur moderne est utilis, l'exprience montre que la
notation systmatiquement prxe est bien suprieure la notation traditionnelle
des mathmaticiens, celle qui semblait si commode aux programmeurs Fortran.
Mais ce n'est pas le sujet du jour.
Cette digression n'tait l que pour expliquer au lecteur que bien des objets
Maple qui ne semblent pas tre des objets function quand on les entre au clavier
de la faon usuelle en fait sont bel et bien des objets function. On peut savoir si
un objet est d'un type donn l'aide de la procdure type. Il faut prvoir deux
arguments, l'objet dont le type ext examin et le descripteur de type, un symbole
dans les cas les plus simples.
..................................................................................................................................

> type(3.4, realcons), type(3.4, integer) ;


true, false

..................................................................................................................................

Attention, la procdure type est standard et value donc ses arguments avant
de les utiliser ; si donc vous essayez :
..................................................................................................................................

> type(Psi(round(tan(2.5)), sin(5.1)), function) ;


false

..................................................................................................................................

pour voir si l'expression tudie dans la section prcdente est bien un objet
function, la rponse est ngative, car l'expression est d'abord value ; le rsultat
est un nombre complexe et un nombre complexe n'est pas un objet function. Il
faut comme toujours quoter pour empcher l'valuation.
..................................................................................................................................

> type('Psi(round(tan(2.5)), sin(5.1))', function) ;


true

..................................................................................................................................

Noter qu'un objet peut tre de plusieurs types dirents. Chaque type est un
ensemble d'objets Maple et en gnral ces ensembles ont des intersections non
triviales ; par exemple un entier (type integer) est aussi un rel (type realcons) :
..................................................................................................................................

> type(3, integer), type(3, realcons) ;


true, true

..................................................................................................................................

Il a t expliqu Section 2.3.3 comment construire une liste de carrs :

65

..................................................................................................................................

> SquareList := [i^2 $ i=10..20] ;


SquareList := [100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400]

..................................................................................................................................

Il est lgal de prsenter la mme expression sans les crochets ouvrant et fermant,
auquel cas on construit une suite :
..................................................................................................................................

> SquareSequence := i^2 $ i=10..20 ;


SquareSequence := 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400

..................................................................................................................................

Les dtails sur ces types itratifs trs importants seront tudis Chapitre 4. Il avait
t expliqu Section 2.3.3 pourquoi les mcanismes de prvaluation pouvaient
compliquer la vie si le symbole i tait prsent dans l'environnement. La similitude
avec ce qui est nonc dans la rgle Eval-14 suggre que l'expression ci-dessus
construite partir de l'oprateur binaire $ est aussi un objet function. C'est
bien le cas :
..................................................................................................................................

> type('i^2 $ i=10..20', function) ;

true

..................................................................................................................................

On peut d'ailleurs prsenter cette expression d'une faon plus fonctionnelle ; les
backquotes (accents graves) encadrant le $ initial sont indispensables :
..................................................................................................................................

> `$`(i^2, i=10..20) ;


100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400

..................................................................................................................................

La forme interne des deux objets prsents Maple, forme inxe ou forme prxe, est la mme. C'est le Lecteur de Maple qui fait le travail ncessaire pour
reconnatre l'une quelconque des deux formes et construire de toute faon sous
forme fonctionnelle l'objet dcrit. Pour en avoir le cur net, comparons les deux
objets :
..................................................................................................................................

> evalb('`$`(i^2, i=10..20)' = 'i^2 $ i=10..20') ;


true

..................................................................................................................................

La procdure evalb travaille sur un argument de type equation et en compare


les deux membres. Mais propos, pourquoi les backquotes, en franais les accents
graves16 , encadrant le caractre $ quand on prsente l'expression sous forme fonctionnelle ? D'une part on veut le symbole $ permettant d'atteindre la procdure
approprie ; d'autre part les symboles banals sont constitus de lettres, de chires
et de blancs souligns _, le symbole ne devant toutefois pas commencer par
un chire. Donc en principe l'unique caractre d'un symbole ne peut pas tre $.
Mais toute chane de caractres devient un symbole si elle est encadre par des
back quotes :
16 La

police tltype utilise par LATEX est assez dcevante de ce point de vue : il faut tre
trs attentif pour distinguer les accents aigus des accents graves, autrement dit les quotes des
backquotes.

66

..................................................................................................................................

> type(`This & is # really [ a @ symbol`, symbol) ;


true

..................................................................................................................................

Le symbole vide sert en particulier d'innombrables tours de passe-passe dans les


achages, car les backquotes ncessaires l'entre ne sont pas achs en sortie :
..................................................................................................................................

> type(``, symbol) ;

> `` := `I'm not visible` ;

true
:= I'm not visible

..................................................................................................................................

Il est tentant de faire l'exprience fonctionnelle avec une expression somme,


mais surprise :

..................................................................................................................................

> evalb('`+`(a, b)' = 'a + b') ;

false

..................................................................................................................................

Les deux possibilits existent, produisent presque toujours le mme rsultat, mais
les formes internes sont cette fois direntes ; l'oprateur Maple + inx est
trs particulier et en particulier l'objet correspondant n'est pas un objet function ;
comparer les deux rsultats :

..................................................................................................................................

> type('a + b', function) ;

> type('`+`(a, b)', function) ;

false
true

..................................................................................................................................

Ces considrations ne sont pas l du tout pour vous apprendre les dirences
ventuelles plutt subtiles, quand elles existent, entre les formes inxes et les
formes prxes ; il est rarissime que ces dtails soient de quelque utilit. Il s'agit
seulement d'explorer un peu notre espace de travail, de fouiner, comme c'est la
rgle dans tous les grands logiciels. Seul l'utilisateur connaissant un peu la nature
gnrale de son espace de travail peut esprer y devenir un jour raisonnablement
autonome. Il s'agit dans ce manuel de vous expliquer Maple, et surtout de vous
rendre capable de trouver vous-mme les informations qui peuvent tre indispensables dans tel ou tel cas.

2.6 Procdures assigned, assign et unassign.


Cette section peut tre omise en premire lecture. Trois outils de la mme famille y sont dcrits, qui permettent d'analyser et de modier l'environnement ; ils
peuvent donc tre utiliss pour traiter les chanages. Dans les usages lmentaires
de Maple, ils sont rarement de quelque utilit ; pour des usages un peu plus sophistiqus, ils deviennent vite utiles ou mme indispensables ; c'est notamment le cas
quand il s'agit d'utiliser les rsultats des dirents solvers, comme solve, dsolve,
rsolve, etc.
67

La procdure assigned permet de savoir si un symbole est prsent dans l'environnement.


..................................................................................................................................

> restart ; assigned(a) ;

false

> a := 1 ; assigned(a) ;
a := 1
true

> a := 'a' ; assigned(a) ;


a := a
false

..................................................................................................................................

La procdure assigned est non-standard, car elle n'value pas son argument avant
de l'utiliser. Quand l'entier 1 est aect au symbole a, le symbole devient prsent
et la procdure assigned permet de le vrier. On retire ici a de l'environnement
en utilisant la convention explique page 53, par auto-aectation du symbole ;
on vrie ensuite, encore avec la procdure assigned, que le symbole a est bien
retir de l'environnement.
Le caractre non-standard de la procdure assigned est mis en vidence par
l'exprience suivante.
..................................................................................................................................

> restart ; a := b ;

a := b

> assigned(a), assigned(b) ;

true, false

..................................................................................................................................

Aprs l'aectation a := b, le symbole a est prsent dans l'environnement mais non


rfrenc, le symbole b est rfrenc mais non prsent (voir page 51). On voit donc
que l'valuateur n'a pas valu l'argument a de assigned(a) avant de l'utiliser ;
sinon l'argument dnitif aurait t b qui lui est absent de l'environnement, de
sorte que la rponse aurait t ngative.
La procdure unassign demande la libration de son (ou ses) argument(s).
Cette fois au contraire, la procdure est standard, ce qui est mis en vidence par
l'exprience analogue.
..................................................................................................................................

> restart ; a := b ; b := 3 ;

a := b
b := 3

> unassign(a) ;
Error, (in assign) invalid arguments

..................................................................................................................................

Ce type d'erreur, assez frquente en mode interactif, est assez troublante pour
l'utilisateur non initi. La procdure unassign est standard et l'argument a est donc
valu avant d'tre utilis. Les deux chanages [a b] et [b 3] prsents dans
l'environnement impliquent que la valeur actuelle de a est l'entier 3, voir la rgle
Eval-7. Mais librer l'entier 3 n'a pas de sens, car la source d'un chanage ne peut
tre qu'un symbole, pas un entier. Par ailleurs le message d'erreur cite curieusement
68

la procdure assign et non unassign ! Mais la procdure unassign en fait appelle


son tour la procdure assign avec des arguments ad hoc pour demander la
libration souhaite, et c'est seulement pendant cette invocation souterraine que
l'erreur est dtecte.
Dans le contexte ci-dessus, si l'utilisateur souhaite la libration du symbole
point par a, pour empcher l'valuation de b vers 3, il peut donc demander :
..................................................................................................................................

> unassign('b') ;

..................................................................................................................................

Noter aussi que la procdure unassign semble sans valeur ; un nouveau prompt
apparat, mais aucun output n'est ach. Plus prcisment, on verra Chapitre 4
que l'output est la suite dite vide, un objet pas du tout vide, mais dont par
contre l'achage est bien vide !
Dans le cas prcdent on a utilis le fait qu'on savait que le symbole a pointait
vers b. supposer qu'on l'ait oubli, il faudrait valuer eval(a, 1) qui retournerait b, surtout pas a qui retournerait 3 ! Voir Section 50. Mais si unassign est
utilis au sein d'une squence de programmation, il faut savoir demander la libration du symbole point par a sans connatre d'avance le nom du symbole en
question. C'est justement le moment d'utiliser bon escient eval(..., 1), comme
illustr maintenant.
..................................................................................................................................

> restart ; a := hidden_b ; hidden_b := 333 ;


a := hidden_b
hidden_b := 333
> unassign(eval(a, 1)) ; a ; hidden_b ;
hidden_b
hidden_b

..................................................................................................................................

On voit que le symbole a est rest prsent, son chanage vers hidden_b n'a pas t
modi ; par contre le chanage de source hidden_b a t retir, ce qui peut aussi
tre vri comme suit.
..................................................................................................................................

> assigned(a) ; assigned(hidden_b) ;

true
f alse
..................................................................................................................................

Si enn on veut librer le symbole a, vous avez compris que ceci est inoprant :
..................................................................................................................................

> unassign(a) ; assigned(a) ;

true

..................................................................................................................................

car l'argument dnitif est hidden_b et c'est donc ce dernier qui est libr ; il tait
d'ailleurs dj libre. Pour librer le symbole a, il faut donc empcher l'valuation
de a comme argument de unassign :

69

..................................................................................................................................

> unassign('a') ; assigned(a) ; a ;

false
a

..................................................................................................................................

Maple dispose symtriquement d'une procdure assign permettant au contraire


de raliser une aectation :
..................................................................................................................................

> assign(s = a) ; assigned(s) ; assigned(a) ; s ;


true
false
a

..................................................................................................................................

Bien noter que l'unique argument de assign a t ici l'objet equation s = a, et
non pas l'instruction aectation s := a qui serait de toute faon illgale ; en
eet le texte s := a dnote une instruction et non un objet ; or un argument ne
peut tre qu'un objet. Au contraire le texte assign(s = a) est un objet et peut
par exemple tre aect un symbole :
..................................................................................................................................

> restart ; assign(s := a) ;


`:=` unexpected

> restart ; obj := 'assign(s = a)' ;


obj := assign(s = a)

..................................................................................................................................

Il a fallu bien sr quoter le texte en question pour empcher son valuation. La


vrication de l'aectation ne peut dans un tel cas tre faite qu'avec un appel de
eval(..., 1) :
..................................................................................................................................

> eval(obj, 1) ;

assign(s = a)

..................................................................................................................................

car si on demande l'valuation banale de obj :


..................................................................................................................................

> obj ;

..................................................................................................................................

Ne pas croire que puisque rien n'est ach, rien n'est fait ! Comme la procdure
unassign, la procdure assign retourne la suite vide ; mais comme la procdure
unassign, l'invocation de la procdure assign modie l'environnement, cette fois
en y modiant ou en y ajoutant un chanage. Or ici on a demand l'valuation de
obj qui pointe vers assign(s = a) ; l'application de la rgle Eval-7 implique donc
que l'objet assign(...) doit tre valu ; le chanage [s a] est donc install
et le rsultat de l'valuation de obj est le rsultat de l'valuation de assign(...),
donc la suite vide, invisible.
On ne voit pas bien a priori l'utilit de la procdure assign par rapport
l'aectation ordinaire s := a ; mais la procdure assign est standard et value
donc ses arguments, ce qui est source de possibilits varies. Dans une squence
de programmation, il peut arriver par exemple qu'un symbole s pointe vers un
autre symbole variable d'un moment l'autre pendant l'excution ; il peut arriver
70

qu'une aectation soit souhaite pour le symbole point par s, ce que ne permet
en aucune faon l'aectation ordinaire.
..................................................................................................................................

> s := a ; s := 3 ;

s := a
s := 3

> s, a ;
3, a
..................................................................................................................................

On voit que l'instruction d'aectation s := 3 a aect 3 au symbole s et non pas


au symbole a valeur de s comme il pourrait l'tre souhait. On aimerait quelque
chose comme :
..................................................................................................................................

> eval(s) := 3 ;

Error, invalid left hand side in assignment

..................................................................................................................................

mais on voit que cette instruction produit une erreur, car aucune valuation ne
peut intervenir au niveau suprieur dans le membre de gauche d'une instruction
d'aectation. Il faut, si on veut aecter au symbole valeur de s par exemple l'entier 3, utiliser la procdure assign :
..................................................................................................................................

> restart ; s := a ;

s := a

> assign(s = 3) ;
> eval(s, 1) ; eval(a, 1) ;
a
3

> assign(s = 33) ;


Error, (in assign) invalid arguments

..................................................................................................................................

On voit ainsi, et on ne peut le voir que de cette faon, que le chanage [s a]


n'a pas t modi, alors que le nouveau chanage [a 3] a t install. Quel
que soit le symbole point par s, le rsultat analogue aurait t obtenu par la
mme valuation, grce au mcanisme de pr-valuation des arguments, dont on
commence comprendre l'intrt. On voit en outre qu'une fois que le chanage de
a vers 3 est install, on ne peut plus valuer la mme instruction assign, car cette
fois la valeur de s est 3, par l'intermdiaire de a, et l'aectation de 33 3 n'a pas
de sens. Par contre on peut demander :
..................................................................................................................................

> assign(eval(s, 1) = 33) ;


> eval(s, 1) ; eval(a, 1) ;

a
33
..................................................................................................................................

On espre que le lecteur comprend quel point ces jongleries exigent une
lucidit parfaite sur les mcanismes d'valuation, sous peine d'anarchie complte !
Mais inversement ces mcanismes ne sont quand mme pas si compliqus, et si
vous faites l'investissement appropri en la matire, le bnce est immense pour
les travaux un peu signicatifs.
71

Une autre cirsonstance o la procdure assign est bien utile, c'est quand la
valeur d'un symbole est un objet equation, autrement dit une quation. Ceci se
produit assez frquemment quand on travaille avec les solvers. Il peut arriver par
exemple qu'aprs avoir rsolu une quation, vous obteniez un rsultat quivalent
au suivant :
..................................................................................................................................

> restart ; result := solution = exp(Pi^2/12) ;

1 2

result := solution = e 12

..................................................................................................................................

Autrement dit la valeur du symbole result est maintenant l'quation dont le premier membre est le symbole solution et le second membre est l'expression math2
matique e /12 . Cette situation o la valeur d'un symbole est une quation o le
premier membre est son tour un symbole est en eet trs frquente. Vrions ce
point.
..................................................................................................................................

> result ;

1 2

solution = e 12

..................................................................................................................................

Dans un tel contexte, on souhaite assez souvent en dnitive aecter au symbole


2
premier membre, ici solution, le second membre, ici e /12 . Le mcanisme de prvaluation des arguments devient donc de plus en plus intressant.
..................................................................................................................................

> assign(result) ;

..................................................................................................................................

Rien n'est ach et pourtant l'aectation souhaite est ralise :


..................................................................................................................................

> solution ;

1 2

e 12

..................................................................................................................................

Le fait que la procdure assign ne retourne rien est assez dsagrable, car
moins d'un supplment de votre part, vous ne pouvez pas vrier que l'aectation
souhaite est ralise ; or le cadre de travail o des mcanismes d'valuation assez
subtils risquent d'intervenir est assez dangereux.

Conseil 17  En mode interactif, aprs une instruction assign, vriez que l'affectation souhaite est bien ralise. Le mieux pour ce faire consiste demander
en plus l'excution d'une quation :
'symb' = eval(symb, 1) ;

Par exemple il aurait t meilleur de demander plus haut :


..................................................................................................................................

> assign(result) ; 'solution' = eval(solution, 1) ;


1 2

solution = e 12

..................................................................................................................................

L'utilisateur est ainsi certain que l'aectation souhaite est ralise.


72

Bien distinguer dans ces questions l'instruction d'aectation  := de l'oprateur quation =.
-o-o-o-o-o-o-o-

73

Chapitre 3
Les types de donnes numriques
3.1 Types, gnralits.
3.1.1 Les procdures type et whattype.
On a vu la n du dernier chapitre comment dterminer si un objet est d'un
type donn, l'aide de la procdure type.
..................................................................................................................................

> type(2., integer), type(2., float) ;


false, true

..................................................................................................................................

On voit que le ottant 2. n'est pas un entier pour Maple. La procdure type examine la nature du codage qui est utilis pour l'objet dsign ; sa nature arithmtique
au sens mathmatique du terme n'est pas considre. Il aurait t plus prcis de
dire que 2. est un objet float mais n'est pas un objet integer.
Considrons dans le mme registre les instructions suivantes :
..................................................................................................................................

> x := (sqrt(5)-1) * (sqrt(5) +1) ;

x := ( 5 1)( 5 + 1)
> type(x, integer) ;
false

..................................................................................................................................

La procdure type est standard et value donc ses arguments avant de travailler.
L'instruction ci-dessus, ne concerne donc pas le type du symbole x, mais le type
de sa valeur. Comparer avec :
..................................................................................................................................

> y := 2 ; type(y, integer), type('y', integer), type('y', symbol) ;


y := 2
true, f alse, true

..................................................................................................................................

o cette fois la valeur de 'y' est le symbole y.


Le lecteur lucide sait que la valeur de x est, pour le mathmaticien, un entier,
mais Maple ne le sait pas. Les expressions comprenant des radicaux peuvent tre
manipules par des mthodes si varies que Maple prfre par dfaut sagement
74

s'abstenir. De sorte que x pointe vers un objet non simpli, assez complexe, dont
il est lgitime de demander le type :
..................................................................................................................................

> whattype(x) ;

..................................................................................................................................

La procdure whattype ne retourne pas le type d'un objet, mais un type qu'elle
essaie de dterminer au mieux parmi les types possibles pour l'objet en question.
En eet un type n'est autre qu'un ensemble d'objets Maple, et ces ensembles ne
sont pas en gnral disjoints. L'ensemble vide est en particulier un type, c'est le
type nothing. Aucun objet n'est du type nothing, pas mme le symbole nothing :
..................................................................................................................................

> type(nothing, nothing) ;

false

..................................................................................................................................

Inversement tout objet est du type anything, en particulier le symbole nothing :


..................................................................................................................................

> type(nothing, anything) ;

true

..................................................................................................................................

La procdure whattype pourrait donc rpondre anything pour tout objet, mais son
utilit ne serait pas vidente. On ne peut pas lui demander non plus de retourner le plus petit type contenant l'objet, car il existe toujours un type contenant
seulement cet lment. Par exemple l'objet sqrt(2) est l'unique lment du type
identical(sqrt(2)) :
..................................................................................................................................

> type(sqrt(2), identical(sqrt(2))) ;


> type(sqrt(3), identical(sqrt(2))) ;

true
false

..................................................................................................................................

Mais que choisit whattype pour sqrt(2) ?


..................................................................................................................................

> whattype(sqrt(2)) ;

..................................................................................................................................

Il faut une bonne vue pour voir que le type choisi est dsign par le symbole accent
circonexe  ; si on veut en avoir le cur net :
..................................................................................................................................

> type(sqrt(2), `^`) ;

true

..................................................................................................................................

Le symbole dsignant le type est exotique et doit donc tre encadr par des backquotes (accents graves) pour tre entr comme tel, sinon :
..................................................................................................................................

> type(sqrt(2), |) ;


`` unexpected

..................................................................................................................................

Chaque fois qu'un objet est structur, son codage commence par indiquer un

75

oprateur
dominant, et la procdure whattype retourne cet oprateur1 . Par exemple

2 est cod comme `^`(2, 1/2) = 2^(1/2) = 21/2 et l'oprateur matre est
l'exponentiation, ce qui explique la rponse de whattype
. De

la mme faon, notre


nombre x est cod essentiellement comme `*`(( 51), ( 5+1)) et l'oprateur
matre est l'oprateur de multiplication *, d'o la rponse qui nous tait donne
pour le type de x par whattype.

3.1.2 Constructeurs de types.


L'oprateur Not construit le type complmentaire du type argument.
..................................................................................................................................

> type(2, Not(float)) ;

true
..................................................................................................................................

L'interprtation prcdente, strictement parlant, est incorrecte. Contrairement


not qui est rellement un oprateur, bien sr essentiellement logique, il n'existe
pas de procdure Not et une tentative d'utilisation en ce sens est inoprante :
..................................................................................................................................

> eval(Not) ;

> Not(anything) ;

Not
Not(anything)

..................................................................................................................................

alors que l'utilisateur naf attendrait plutt, compte tenu de ce qui a t expliqu page 75, que le dernier rsultat soit nothing. La mthode utilise par Maple
pour donner l'utilisateur la possibilit de manipuler les types est la suivante.
Des symboles (integer, boolean, symbol, . . .) sont rservs pour les types lmentaires (integer, boolean, symbol, . . .). D'autres types peuvent alors tre dcrits
l'aide d'expressions fonctionnelles citant un pseudo-constructeur et un ou plusieurs
types pseudo-arguments ; par exemple le descripteur Not(float) utilise le pseudoconstructeur Not et le pseudo-argument float. Le mcanisme est bien sr rcursif.
..................................................................................................................................

> type(exp(I*3.14159), And(complexcons, Not(realcons))) ;


true
> type(exp(I*Pi), And(complexcons, Not(realcons)))
f alse

..................................................................................................................................

Quelquefois le pseudo-constructeur peut tre utilis sans argument, mais un argument implicite anything est alors suppos.
..................................................................................................................................

> type([1,2,3.], list(float)) ;

f alse

> type([1,2,3.], list(integer)) ;


f alse
1 Les choses sont en fait un peu plus compliques, comme on peut le voir l'aide de la procdure

dismantle ; mais l'approximation donne ici sut pour ce qui nous concerne.

76

> type([1,2,3.], list) ;


true
..................................................................................................................................

Comme observ ci-dessus, un pseudo-constructeur comme Not ou list ne


construit rien, c'est seulement un descripteur. Ce sont les procdures telles que
type qui vont ensuite utiliser ces pseudo-constructeurs bon escient. La situation
entre Not et type est exactement la mme que celle qui avait t signale page
51 entre Pi et evalf : l'information que l'utilisateur croit voir dans Pi est en fait
dans evalf2 qui saura, le cas chant, traiter le symbole Pi comme il convient ; de
la mme faon l'information que l'utilisateur croit voir dans Not(...) est en fait
dans type qui sait interprter une telle expression.
Maple ore aussi l'utilisateur la possibilit de dnir de nouveaux types ; il
s'agit l cette fois d'une vraie construction de type. Par dnition mme de la
notion de type, il faut donc ajouter l'environnement la procdure fonction caractristique du nouveau type. Si dans votre cadre de travail l'ensemble des entiers
multiples de 3 joue un rle essentiel, vous pouvez construire le type correspondant
comme suit :

..................................................................................................................................

> `type/divby3` := proc(obj)


RETURN(type(obj, integer)
and
obj mod 3 = 0)
end :

..................................................................................................................................

La procdure examine d'abord si l'objet considr est un entier, puis s'il est divisible par 3. Ceci fait, la notion d'objet divby3 a maintenant un sens dans l'environnement.
..................................................................................................................................

> type(x, divby3), type(44, divby3), type(45, divby3) ;


f alse, f alse, true

..................................................................................................................................

Le lecteur mathmaticien aimerait savoir ici comment lucider si le nombre


dsign par x est, du point de vue arithmtique, un entier. C'est un point bien connu
de logique qu'il ne peut exister de mthode gnrale pour obtenir une rponse ;
c'est l'utilisateur de s'adapter chaque cas de gure ; pour une expression comme
la valeur de x page 74, il sut d'utiliser la procdure radnormal qui sait obtenir une
forme canonique pour les expressions pas trop compliques base de radicaux :
..................................................................................................................................

> radnormal(x) ;

4
..................................................................................................................................

et la rponse est claire.


Pour illustrer3 la dicult fondamentale lucider si un nombre rel est entier,
on va anticiper un peu sur la Section 3.4. Considrons les nombres rels dnis
par une suite de Cauchy. Dans le cadre de travail Maple, une suite de Cauchy
pourrait tre une procdure associant un entier n un rationnel xn de telle faon
2 Et

dans les procdures qui savent tirer parti de la nature mathmatique du nombre .

3 Les considrations qui suivent sont dconseilles aux lecteurs fragiles aux troubles existentiels.

77

que |xn+k xn | < 2n si k > 0. Le thorme de Cauchy 4 assureque la suite (xn ) est
convergente et dnit donc un unique rel, sa limite. Le rel 2 peut par exemple
tre dni par :
..................................................................................................................................

> sq2 := proc(n)


local i, rslt ;
rslt := 2 ;
for i from 1 to evalf(log[2](n+1)) do
rslt := rslt/2 + 1/rslt
od ;
RETURN(rslt)
end :
> sq2(100) ;
1572584048032918633353217
1111984844349868137938112
> evalf(sq2(100)) ;
1.414213562
> evalb(abs(sq2(100)-sq2(300)) < 2^(-100)) ;
true

..................................................................................................................................

Les logiciens savent alors dmontrer l'existence d'une procdure :


..................................................................................................................................

> RealOfTheThirdType := proc(n)


...
...
end ;

..................................................................................................................................

satisfaisant les conditions requises ci-dessus pour une suite de Cauchy ; le rel
ainsi dni est entier mais ce fait n'admet aucune dmonstration. La preuve
d'existence d'une telle procdure n'est pas, ne peut pas tre, constructive ; pire,
aucune procdure ne peut tre identie comme telle ! Mais on est physiquement
certain que de telles procdures existent ; aussi certain qu'on sait qu'aprs avoir
ajout deux billes un sac qui en contenait deux, le sac contient quatre billes.
C'est un avatar du thorme d'incompltude de Gdel [2].
Vous pouvez par exemple tomber un jour sur une procdure de ce type qui
vous retourne pour chaque entier n que vous essayez une approximation xn vriant
|3 xn | 2n ; observant ceci, vous suspectez alors que le nombre rel limite x
ainsi dsign est en fait l'entier 3 ; vous cherchez donc une dmonstration que, quel
que soit l'entier n, le rsultat xn vrie cette ingalit, ce qui prouverait que le rel
limite est bien l'entier 3. Mais vous ne trouvez pas de telle dmonstration. dfaut,
vous essayez un grand nombre de nouvelles valeurs de n esprant enn trouver
le contre-exemple qui pourrait exister ce que vous aviez cru dans un premier
temps ; mais non, pour toutes ces nouvelles valeurs de n, l'ingalit |3 xn |
2n est dsesprment satisfaite ; utilisant ce rsultat qui semble dcidment
conrmer que le rel dni est entier, vous remettez en chantier la recherche d'une
dmonstration, que vous ne trouvez pas, etc. etc.
Quand vous serez un peu fatigu de ce travail sans n, invitablement vous
4 On

peut si on prfre considrer que ceci est une dnition de la notion de nombre rel.

78

suspecterez que vous tes en face d'un rel du troisime type, mais vous ne pourrez jamais le dmontrer non plus. . . L'exemple du nombre de Ramanujan vient
l'esprit, mais en fait il n'est pas de cette nature.

3.1.3 Le nombre de Ramanujan.

Le nombre de Ramanujan, e 163 , est assez instructif des dicults qui peuvent
tre rencontres quand on veut savoir si un nombre est entier ou pas. Aectons-le
au symbole r :
..................................................................................................................................

> r := exp(Pi*sqrt(163)) ;

r := e 163

..................................................................................................................................

et calculons l'approximation ottante :


..................................................................................................................................

> evalf(r) ;

.2625374126 1018

..................................................................................................................................

Le nombre de Ramanujan a 18 chires avant la virgule et il nous faut donc


une prcision d'au moins 20 chires :
..................................................................................................................................

> evalf(r, 20)

.26253741264076874443 1018

..................................................................................................................................

Il est un peu fatigant de compter les chires pour voir o la virgule est insre ;
un achage plus sophistiqu base d'impression formatte s'impose : puisque
20 chires exacts sont prvus et que 18 doivent se trouver avant la virgule,
l'achage de type %21.2f est le bon :
..................................................................................................................................

> printf("%21.2f", evalf(r, 20)) ;


262537412640768744.43

..................................................................................................................................

Mais peut-on avoir conance dans la partie dcimale ? Poussons un peu la prcision.
..................................................................................................................................

> printf("%31.12f", evalf(r, 30))


262537412640768743.999999999999

..................................................................................................................................

La question semble dcidment plus dlicate que prvu ! Il n'est certainement pas
possible que les derniers chires des deux rsultats prcdents soient exacts en
mme temps. . . Augmentons encore la prcision :
..................................................................................................................................

> printf("%41.22f", evalf(r, 40)) ;


262537412640768743.9999999999992500725944
> printf("%51.32f", evalf(r, 50)) ;
262537412640768743.99999999999925007259719818568865

..................................................................................................................................

Il est clair maintenant que le nombre de Ramanujan n'est pas entier. On note au
passage que les deux derniers chires d'un rsultat ottant sont en gnral assez
douteux. Le thorme suivant permet de dterminer la nature arithmtique du
79

nombre de Ramanujan.

Thorme 18 (Schneider)  Si le nombre est algbrique dirent de 0 et 1,


et si le nombre est algbrique irrationnel, alors le nombre est transcendant.

Il en
rsulte que le nombre de Ramanujan r est transcendant. En eet le nombre
= i 163 est algbrique : il est racine de l'quation 2 +163 = 0, et de plus il n'est
pas rationnel ; si le nombre = r tait entier,
il serait en particulier algbrique ; il

i 163
est aussi dirent de 0 et 1 et donc = r
serait transcendant. Calculons ce
dernier avec Maple :
..................................................................................................................................

> r^(I*sqrt(163)) ;

(e 163 )

I 163

> simplify(%) ;
1
..................................................................................................................................

qui n'est pas un nombre transcendant ! le nombre de Ramanujan est donc transcendant. Ramanujan avait devin il y a bien longtemps, sans Maple et sans ordinateur,
que son nombre, malgr sa taille imposante, tait non entier mais trs proche d'un
entier.

3.2 Le type integer.


Un objet integer est un entier de taille (nombre de chires) arbitraire, la seule
limitation tant due la capacit mmoire. Les sous-types posint (entiers strictement positifs), negint (entiers strictement ngatifs), nonnegint (entiers positifs
ou nuls), nonposint (entiers ngatifs ou nuls), even (entiers pairs) et odd (entiers
impairs) sont disponibles ; noter la terminologie l'amricaine o positif signie
strictement positif et non ngatif signie positif ou nul. Il faut utiliser ces soustypes chaque fois que c'est possible pour prciser les arguments de procdures. La
programmation de la fonction factorielle peut tre ainsi ralise :
..................................................................................................................................

> fact := proc(n::nonnegint)


local i, result ;
result := 1 ;
for i from 1 to n do result := i*result od ;
RETURN(result)
end :
> fact(0) ;
1
> fact(-1) ;

Error, fact expects its 1st argument, n, to be of type nonnegint, but received -1

..................................................................................................................................

La syntaxe ::nonnegint pour un paramtre n indique que ce paramtre doit tre


de type nonnegint. Comme on le voit, la vrication est faite chaque invocation de
procdure, ce qui peut permettre de dtecter des incohrences. Aucun mcanisme
80

analogue n'est disponible pour les variables des procdures, qu'elles soient locales5
ou globales.
La programmation rcursive rituelle de la fonction factorielle choue sous Windows pour n 530 pour cause de rcursivit trop profonde.
On voit aussi qu'on peut refuser l'achage d'un output en remplaant le terminateur  ; (point-virgule) par  : (deux-points) ; l'instruction est excute, mais
l'achage de l'objet retourn par l'valuateur n'est pas fait. On utilisera systmatiquement cette faon de faire pour la construction des procdures, o l'output est
en gnral de peu d'intrt.

3.3 Le type rational.


Maple permet de manipuler banalement les rationnels.
..................................................................................................................................

> e_rational := proc(n::nonnegint)


RETURN(add(1/i!, i=0..n))
end :
> e30 := e_rational(30) ;
55464002213405654539818183437977
e30 :=
20404066139399312202792960000000
..................................................................................................................................

Numrateurs et dnominateurs sont certainement premiers entre eux ; la procdure


utiliser pour calculer le (P)GCD de deux entiers est igcd :
..................................................................................................................................

> igcd(numer(e30), denom(e30)) ;

1
..................................................................................................................................

Mais le dnominateur est-il 30! ?


..................................................................................................................................

> 30! / denom(e30) ;

13
..................................................................................................................................

Noter aussi que whattype ne rpondra pas rational pour le type d'un tel
nombre, mais seulement fraction :
..................................................................................................................................

> whattype(e30) ;

> type(e30, rational) ;

fraction
true

..................................................................................................................................

Curieusement les objets qui paraissent d'abord tre des fractions sont en fait
des produits :
5 Possible

sous Maple 6.

81

..................................................................................................................................

> type(A/B, fraction) ;


> type(A/B, `*`) ;

false
true

..................................................................................................................................

car le produit A/B est cod de faon interne (A1)*(B(-1)). La seule exception
notable cette remarque concerne le cas o A et B sont en fait des entiers, celui o
A/B est donc alors un objet rational.

3.4 Le type float.


Les entiers et rationnels permettent le calcul exact. Mais les quantits mathmatiques ne sont que rarement rationnelles et il faut donc souvent se contenter
d'approximations dites ottantes de nombres rels. On peut par exemple dans
certains contextes se contenter de l'approximation ottante 3.14159 de ; elle a
l'inconvnient d'tre un peu inexacte, mais l'avantage du style numrique dans son
expression.
La mthode usuelle est utilise par Maple ; un ottant est une expression a.10k
o a est un nombre dcimal avec un certain nombre de chires signicatifs et k est
un entier positif ou ngatif. Les usages de la plupart des langages de programmation
sont respects. C'est le point dcimal qui impose le caractre ottant du nombre.
..................................................................................................................................

> whattype(4) ; whattype(4.) ;

integer
oat

..................................................................................................................................

Maple prvoit par dfaut une prcision de dix chires signicatifs pour les objets
float. On force l'valuation vers un ottant, partout o elle est possible, par la
procdure evalf.
..................................................................................................................................

> evalf(20^20/30^30) ;
> evalb(4. = 4) ;
> is(4. = 4) ;

.5092866261 1018

false
true

..................................................................................................................................

On voit ici une subtilit qui peut l'occasion tre importante ; la procdure d'valuation boolenne evalb est hard et compare en particulier les types des objets ;
la comparaison de l'entier 4 et du ottant 4. est donc ngative. Au contraire la
procdure is, dans le cas numrique, compare numriquement. Voir aussi :
..................................................................................................................................

> x := (sqrt(5)-1) * (sqrt(5) + 1) ;

x := ( 5 1) ( 5 + 1)

82

> evalb(x = 4), is(x = 4) ;

false, true

..................................................................................................................................

La procdure is est trs peu documente ; le listing source est disponible, mais trs
complexe. Sauf cas assez simples, son usage n'est pas trs clair et cette procdure
doit donc tre utilise avec beaucoup de prudence.
Pour obtenir un listing source, il faut d'abord modier un paramtre de l'interface appel verboseproc :
..................................................................................................................................

> interface(verboseproc = 2) ;

..................................................................................................................................

puis acher la procdure en tenant compte de la rgle Eval-16, donc en demandant


une valuation explicite :
..................................................................................................................................

> eval(is) ;
proc(obj, prop )

local . . .

..................................................................................................................................

Vous obtenez alors le listing source de la procdure is ; on vous souhaite bon


courage pour la dcrypter. Une procdure du noyau Maple est dclare builtin :
..................................................................................................................................

> eval(evalb) ;

proc () option builtin ; 99 end

..................................................................................................................................

Seuls les super-gurus de Waterloo en connaissent alors la nature.

3.4.1 Combien de chires signicatifs ?


La prcision des calculs ottants peut tre explicitement demande par le
deuxime argument de evalf pour un calcul ponctuel :
..................................................................................................................................

> evalf(exp(1), 20) ;

2.7182818284590452354
..................................................................................................................................

Par dfaut, Maple prvoit des calculs avec 10 chires exacts, information qu'on
trouve dans la variable Digits :
..................................................................................................................................

> Digits ;

10
..................................................................................................................................

Rien n'empche d'en changer la valeur :


..................................................................................................................................

> Digits := 30 ;

Digits := 30
..................................................................................................................................

et dsormais tous les calculs ottants vont tre eectus avec la prcision demande.

83

..................................................................................................................................

> evalf(sqrt(3)) ;

1.73205080756887729352744634151
..................................................................................................................................

Une autre faon de demander qu'une valuation ottante soit eectue, consiste
prvoir des arguments ottants. Si Maple voit qu'une fonction a un argument
ottant, Maple en dduit logiquement que le contexte est calcul numrique et
continue dans le mme esprit, on dit qu'il y a contagion du type float. Comparer :
..................................................................................................................................

> Digits := 10 :
sin(1), sin(1.), sin(3/2), sin(1.5) ;
3
sin(1), .8414709848, sin( ), .9974949866
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Les utilisateurs sont souvent surpris sinon agacs quand Maple laisse une expression comme sin(1) sans valuation. Mais Maple prfre toujours garder la possibilit de mener ultrieurement des calculs exacts. Comparer les deux cas suivants :
..................................................................................................................................

> is(sin(1+1/3) = sin(1)*cos(1/3)+sin(1/3)*cos(1)) ;


true
> is(sin(1+1./3) = sin(1)*cos(1/3)+sin(1/3)*cos(1)) ;
f alse

..................................................................................................................................

Dans le premier cas les arguments sont gards exacts et Maple connat assez de
trigonomtrie pour conclure l'galit. Dans le second cas l'unique point dcimal
ajout a, par contagion, transform l'argument du premier sinus en une approximation ottante inexacte, d'o le rsultat. Plus simplement :
..................................................................................................................................

> is(sin(1/3) = sin(1./3)) ;

f alse

> is(1/3 = 1./3) ;


true
..................................................................................................................................

La cohrence de l'ensemble de ces rsultats n'est pas vidente ; tout provient de


la faon dont la contagion ottante est propage. Comme aucune rgle logique
complte ne peut tre dnie en la matire, quelles que soient les dcisions prises,
il y aura toujours une zone frontire avec des incohrences apparentes qui peuvent
nanmoins srieusement perturber les programmes rdigs par les utilisateurs trop
crdules.
Comparer encore :
..................................................................................................................................

> sin(10000 * Pi), sin(10000 * evalf(Pi)) ;


0, .4102067615105

..................................................................................................................................

Le deuxime rsultat est banalement inexact, compte tenu de l'approximation


ottante utilise pour ; le premier est remarquablement exact : c'est en examinant
soigneusement la nature arithmtique multiple de de l'argument du sinus que
Maple peut conclure la nullit, rsultat parfait.

Conseil 19  Dans des calculs d'envergure, il est important d'avoir les ides
84

claires sur leur nature, numrique vs exacte.


1. Dans certains contextes, il est important de conserver les expressions exactes
des rsultats, mme s'ils sont achs d'une faon un peu encombrante ou
complique.
2. Si au contraire le contexte est purement numrique, l'exactitude de rsultats
intermdiaires peut considrablement alourdir le calcul ou mme le mettre en
chec.
L'exemple dtaill Section 3.9 montre dans un cas concret comment l'utilisateur
peut tre men changer plusieurs fois de stratgie ce propos en cours d'un calcul.

3.5 Le type realcons.


Le type real n'existe pas en Maple :
..................................................................................................................................

> type(3.4, real) ;

Error, type `real` does not exist

..................................................................................................................................

ce qui surprend un peu le mathmaticien, mais le type realcons est prvu avec une
smantique un peu plus prcise : on dit en mme temps que l'objet vis est une
constante.
..................................................................................................................................

> type(3, realcons), type(4/5, realcons),


type(6.7, realcons), type(Pi, realcons) ;
true, true, true, true
> a := Pi * cos(5) / GAMMA(sqrt(2)) ;
cos(5)

a :=
( 2)
> type(a, realcons) ;
true
> evalf(a) ;
1.005154190

..................................................................................................................................

La documentation explique qu'un objet est de type realcons si la procdure


evalf peut le prendre en argument et retourner un ottant rel. Il en est bien
ainsi pour la valeur du symbole a ci-dessus, mais avec des exemples un peu plus
compliqus, l'explication donne est prise en dfaut.
..................................................................................................................................

> b := int(exp(x^2)/(1+x), x=2..3) ; Z


b :=
> type(b, realcons) ;

ex
dx
1+x

f alse

> evalf(b) ;
374.9536307
..................................................................................................................................

L'utilisateur doit donc rester assez prudent pour l'utilisation de ce type


realcons.
85

Noter aussi que la procdure whattype ne retournera jamais la rponse realcons,


car elle ne considre, par principe, que le type de codage de l'objet dsign ; au
contraire la question type(xxx, realcons) est une interrogation arithmtique sur la
valeur de xxx. Dans le mme esprit on aimerait un type integercons mais on a dj
mentionn page 77 les problmes logiques insurmontables poss par un tel type.
L'incohrence releve ci-dessus pour le symbole b illustre prcisment comment
ce type de problme logique intervient vite, mme dans un contexte relativement
banal, ds qu'une procdure prtend pouvoir donner une rponse une question
arithmtique.

3.6 Alias.
Un alias est un symbole dclar synonyme d'un objet Maple. Le premier rexe la lecture de cette dnition consiste penser la notion de chanage, voir
Section 2.3.2 ; un chanage est en eet aussi un lien, install dans l'environnement,
entre un symbole et un objet Maple ; de sorte qu'une bonne lucidit va tre ncessaire pour bien comprendre la dirence entre les deux notions. Sans un eort
signicatif en ce sens, attendez-vous des dicults srieuses dans les situations
complexes.
Le sujet aurait mieux sa place comme satellite de ce qui avait t dit au sujet
de l'environnement, mais, strictement parlant, les alias ne sont pas indispensables,
de sorte qu'il est meilleur d'attendre qu'ils deviennent franchement utiles. C'est
le cas dans les deux sections suivantes, consacres aux nombres complexes et aux
nombres algbriques, et le sujet est donc maintenant l'ordre du jour.
Considrons donc qu'un alias est, comme un chanage, un lien entre symbole et
objet6 . Il est install par l'intermdiaire de la procdure alias. C'est une procdure
o chaque argument est un objet equation, autrement dit deux objets spars par
le signe = ; ces objets sont valus, et aprs valuation, le membre de gauche doit
tre un symbole, la source de l'alias dnir, le membre de droite est un objet
quelconque, le but de l'alias. Autant d'alias que d'quations seront construits. Dand
l'exemple qui suit, les deux membres de l'quation sont valuation triviale, et le
symbole source est donc alias_symbol, l'objet but est l'expression 1+x.
..................................................................................................................................

> alias(alias_symbol = 1+x) ;

I, alias_symbol

..................................................................................................................................

Quand un nouvel alias est install, Maple retourne la suite des symboles aliass, y
compris le dernier ; dans l'environnement initial, seul le symbole I est alias. Il s'agit
maintenant de bien analyser la dirence fondamentale entre alias et chanage.
..................................................................................................................................

> bounded_symbol := 1+y ;

bounded_symbol := 1 + y

..................................................................................................................................

6 En

fait un alias peut admettre une source de type quelconque ; pour les usages les plus
frquents, la source est un symbole et, pour simplier, nous considrons seulement ce cas.

86

Ces exemples sont parfaitement articiels et ne gurent ici que dans un but
didactique. Le point cl est le suivant. On a expliqu Section 2.2.2 le modle ReadEval-Print de Maple. On a compris l'essentiel de la dirence entre chanage
et alias quand on a bien vu comment et pourquoi un chanage n'intervient que
pendant la phase Eval alors qu'un alias n'intervient que dans les phases Read et
Print.
Pendant la phase Read, Maple lit caractre par caractre le texte de l'instruction que vous lui proposez, et construit l'objet Maple, plus gnralement (cas
d'instructions d'aectation, conditionnelle, itrative. . .) l'instruction Maple que
vous voulez faire valuer. Si un symbole alias gure dans votre texte, ce symbole va tre systmatiquement remplac par l'objet correspondant. Pour mettre en
vidence ce fait, comparez soigneusement ce qui suit.
..................................................................................................................................

> has('alias_symbol', x) ;

true

> has('bounded_symbol', y) ;
f alse
..................................................................................................................................

L'analyse est la suivante. Le lecteur Maple a construit dans le premier cas l'objet
has('1+x', x), car il a vu la prsence du symbole alias_symbol et l'a remplac par
l'objet 1+x. Puis l'objet construit par le lecteur est pass l'valuateur. La procdure has est standard et les arguments sont valus avant d'tre utiliss, de sorte
que le premier argument dnitif est la somme 1+x : les quotes sont retirs par
l'valuation, voir Eval-10. Enn la procdure has travaille et voit qu'eectivement
le second argument x gure dans le premier 1+x, elle retourne donc true. Dans le
second cas, le symbole bounded_symbol n'est pas alias et le lecteur va donc passer l'valuateur l'objet has('bounded_symbol', y) ; rappelons que le lecteur n'est
pas concern par l'environnement. Quand l'valuateur travaille, le premier argument provisoire 'bounded_symbol' devient l'argument dnitif bounded_symbol o
ne gure pas le symbole y et la rponse est donc ngative.
Montrons maintenant que le mcanisme alias ne travaille pas pendant une
valuation. Il est assez compliqu de mettre ce fait en vidence, car il faut arriver
faire valuer le symbole alias sans le montrer parce qu'il serait aussitt remplac
par le lecteur par le but de l'alias ! Une faon d'y arriver consiste obtenir le
symbole par rsultat d'une procdure de construction. L'oprateur de construction
d'un symbole par concatnation, oprateur ., convient pour ce faire.
..................................................................................................................................

> i := 1 : sample.i ;

sample1
..................................................................................................................................

D'o la comparaison :
..................................................................................................................................

> has(alias_sym.bol, x) ;

f alse

> has(bounded_sym.bol, y) ;
true
..................................................................................................................................

87

Cette fois les objets passs l'valuateur sont exactement ceux que vous voyez,
car le symbole alias_symbol ne gure pas dans le texte entr. Le premier argument dnitif, construit par l'oprateur ., est le symbole alias_symbol, car ce
symbole n'est pas prsent dans l'environnement, et l'objet retourn par l'oprateur de concatnation est donc l'argument dnitif. Au contraire bounded_symbol
est prsent, de sorte que le premier argument dnitif dans ce cas est la valeur de
ce symbole, savoir 1+y. C'est une illustration du mcanisme de post-valuation,
cf. Eval-13 : le symbole retourn par l'oprateur de concatnation est son tour
valu. D'o les rponses respectivement ngative et positive.
On note ici que toute tentative de comprhension la va-vite du style avec
alias a value plus (ou moins) qu'avec l'aectation est en chec. Dans le premier
cas, c'tait le mcanisme alias qui valuait plus, dans le second cas c'tait le
contraire, mais de toute faon cette terminologie pifomtrique est impropre et doit
tre proscrite. Le bon point de vue consiste avoir les ides claires sur la phase de
travail de Maple o le lien symbole-objet est utilis.
Enn le mcanisme alias reprend du service dans la phase Print. Le plus
simple pour le mettre en vidence est ceci :
..................................................................................................................................

> 1 + x, 1 + y ;

alias_symbol, 1 + y

..................................................................................................................................

Maple recherche en eet systmatiquement dans les objets achs des composantes aliases, et le cas chant remplace ces occurenses par l'alias. Ici Maple a
vu la prsence de l'objet 1+x et l'a donc remplac dans l'achage par le symbole
alias_symbol. On voit donc que, contrairement aux chanages de l'environnement,
le lien alias est bidirectionnel alors que le lien chanage est orient. Ce point est
mis en vidence par :
..................................................................................................................................

> alias_symbol, bounded_symbol ;


alias_symbol, 1 + y

..................................................................................................................................

o les deux valuations sont parfaitement direntes. Ici, le lecteur passe


l'valuateur l'objet 1+x, bounded_symbol ; l'valuation retourne l'objet 1+x,
1+y, mais cet objet est ach alias_symbol, 1 + y  alors qu'en fait le symbole x
est bien dans cet objet :
..................................................................................................................................

> has([%], x) ;

true
..................................................................................................................................

Ici, il faut encadrer le rsultat suite entre crochets pour en faire une liste, sinon
.
les arguments passs has seraient incorrects ; voir
Rien n'interdit d'avoir la fois le mme lien entre symbole et objet, simultanment sous forme alias et chanage environnement. Compte tenu de la pr-valuation
des arguments de la procdure alias, ceci peut tre fait comme suit.
..................................................................................................................................

> symb := 1+x ;

symb := 1 + x

88

> alias('symb' = symb)

I, alias_symb, symb

..................................................................................................................................

Selon les exemples donns prcdemment, on vrie la prsence simultane souhaite chanage et alias, par les instructions sotriques :
..................................................................................................................................

> has(sy.mb, x) , 1+x ;

true, symb
..................................................................................................................................

Ce n'est pas un exercice de style sans motivation ; on verra que les calculs dans
les groupes de Galois, Chapitre
, sont grandement facilits par cette technique.

3.7 Le type complexcons.


Maple n'a pas de type real, mais il a un type complex ; de plus le type
complexcons est aussi dni, et la cohrence de l'ensemble est donc pour le moins
assez obscure. On conseille de n'utiliser en fait que le type complexcons avec la
smantique que l'on devine. Le type complex est considrer comme un archasme
survivant de versions antrieures.
Les nombres complexes simples sont cods par l'intermdiaire de la constante I qui est en fait un alias pour l'expression sqrt(-1). Bien noter que le I
doit tre majuscule, cause constante de lapsus clavier ; le plus souvent le symbole
i minuscule est ddi aux entiers indices ou pilotes d'itration, mais ce n'est qu'un
usage. Les rles ainsi disjoints de I et i se rvlent la longue trs commodes.
Donc I est une abrviation externe, utilisable en entre, systmatiquement
utilise par Maple en sortie, pour l'objet que
les mathmaticiens, surtout ceux du
XVIII et XIX-imes sicles, dsignaient 1 ; sans cet alias, on devrait utiliser
sqrt(-1), ce qui serait un peu lourd. On peut y jouer un moment en supprimant
l'alias I.
..................................................................................................................................

> x := 3+4*I ;

3 + 4I

> alias(I = I) ;
> x ;

3 + 4 1

> alias(I = sqrt(-1))


I

> x ;
3 + 4I
..................................................................................................................................

Comme pour un symbole qu'on veut librer, la suppression d'un alias est conventionnellement demande par l'quation symb = symb si symb est le symbole source
dont on veut supprimer l'alias. Noter en particulier que les alias ne sont pas utiliss
pendant l'valuation des arguments de la procdure alias, sans quoi il serait trs
dicile le plus souvent d'atteindre le symbole dont on veut supprimer ou modier
l'alias ! Ceci a comme consquence un inconvnient quelquefois assez pervers :
89

Warning 20  On ne peut pas utiliser un alias pour en dnir un autre.


C'est un point qu'il est capital de ne pas oublier quand on travaille par exemple
avec des extensions successives de corps, car il est alors bien tentant de dnir
l'alias pour le gnrateur de la deuxime extension en utilisant l'alias qui a servi
aliaser le gnrateur de la premire. On discutera ce point en dtail en temps
utile.
Maple est organis pour traiter de faon cohrente les expressions o gurent
des radicaux avec un radicande ngatif.
..................................................................................................................................

> sqrt(-5) ;

..................................................................................................................................

On a expliqu plus haut que la procdure whattype ne retourne jamais la rponse


realcons, de nature arithmtique ; pour la mme raison elle ne retournera pas
complexcons. Comme toujours pour un objet structur, la procdure whattype retourne l'oprateur dominant.
..................................................................................................................................

> whattype(3+4*I) ;

+
..................................................................................................................................

L'oprateur dominant est en eet l'addition et whattype n'a pas de raison d'examiner les oprandes qui peuvent tre trs. . . complexes. Le type indiqu pour I
lui-mme est ;
..................................................................................................................................

> whattype(I) ;

..................................................................................................................................

car I est en fait cod comme


nentiation.

1 = (1)1/2 ; l'oprateur matre est donc l'expo-

Comme souvent, il est plus appropri de chercher si tel objet est de tel type :
..................................................................................................................................

> type(I, complexcons) ;

true

> type(3+4*I, complexcons) ;


true
> restart ; type(a+b*I, complexcons) ;
f alse
..................................................................................................................................

Un objet est de type complexcons s'il est une constante complexe, donc sans symbole libre. Les rels sont en particulier des complexes :
..................................................................................................................................

> type(3, complexcons) ;

true
..................................................................................................................................

Les considrations de la section prcdente au sujet du critre utilisant evalf


pour caractriser un objet realcons s'appliquent aussi bien au type complexcons.
D'une faon gnrale, tout calcul ayant un sens dans le contexte complexe, qu'il
90

soit numrique ou symbolique, peut tre tent.


..................................................................................................................................

> int(1/(1+I*x+x^2), x=0..infinity)

1
2
1
5 I arctanh
5
5
5
5
5
> evalf(%) ;
1.404962947 .4304089412 I

..................................................................................................................................

Il arrive mme assez souvent que les utilisateurs soient surpris par le degr de
gnralit suppos par Maple ; en particulier Maple ne suppose pas par dfaut que
vos symboles sont valeurs relles. D'o l'aventure qui survient inexorablement
aux novices quand ils essaient de sparer parties relle et imaginaire d'un complexe.
L'examen de la documentation mne aux procdures Re et Im qui travaillent comme
on pense :
..................................................................................................................................

> Re(exp(I*Pi/10)), Im(exp(I*Pi/10)) ;


q
1
1
1
2 5 + 5,
5
4
4
4
..................................................................................................................................

C'est le premier essai possible ; mais quelquefois celui qui vient l'esprit est le
suivant ; on cre un complexe abstrait
..................................................................................................................................

> z := x+I*y ;

z := x + Iy;
..................................................................................................................................

et on vrie que les procdures Re et Im travaillent comme on croit avoir compris :


..................................................................................................................................

> Re(z), Im(z) ;

R(x + Iy), I(x + Iy)


..................................................................................................................................

et on a la surprise de voir nos procdures refuser de travailler ! L'explication est


simple : il n'a jamais t dit que les symboles x et y sont considrer comme
valeurs relles, hypothse ncessaire pour la sparation souhaite. On a expliqu
plus haut que le type real n'existe pas dans Maple, mais la procdure assume vous
permet de demander Maple de prendre en compte l'hypothse qu'un symbole est
valeur relle, mme et surtout si votre symbole est libre :
..................................................................................................................................

> assume(x, real) ;


> Re(z), Im(z) ;

> assume(y, real) ;


> Re(z), Im(z) ;

 I(y), R(y)
x ,y

 

..................................................................................................................................

Les variables propos desquelles une ou des hypothses ont t faites sont signales
par un tilde suivant leur nom. Ce n'est pas le sujet de cette section, mais le contexte
est favorable pour signaler dans le mme registre :

91

..................................................................................................................................

> restart ;
> sqrt(x^2) ;

> simplify(%) ;

x2

csgn(x) x

..................................................................................................................................

Dans un contexte numrique o son argument est complexe, la procdure sqrt


retourne la racine carre de
partie relle positive. Il est ds lors impossible de
valider une simplication x2 = x sans information complmentaire
sur x. En

particulier si x est ngatif, la bonne simplication est x2 = x. La procdure


csgn donne le signe de la partie relle. Si on donne Maple une information
complmentaire, il peut aner la simplication.
..................................................................................................................................

> assume(x, negative) ;


> simplify(sqrt(x^2)) ;

..................................................................................................................................

La procdure evalc tente de prsenter son argument sous une forme xexpr +
I*yexpr.
..................................................................................................................................

> exp(I*Pi/10) ;

> evalc(%) ;
> evalc(exp(I*Pi/11)) ;

1
I
10
e
q

1
2
4

5+

5+I

1
1
5
4
4

1
1
) + I sin( )
11
11
..................................................................................................................................
cos(

Quand un objet est valu sous evalc, les symboles libres gurant dans l'objet
sont supposs rels et l'valuateur tient compte de cette hypothse momentane
pour sparer si c'est possible partie relle et imaginaire. Ceci permet assez souvent de se passer de la procdure assume quand les questions de sparations sont
trs localises. Exemples typiques aprs un restart ncessaire pour supprimer les
hypothses prcdemment installes par assume :
..................................................................................................................................

> restart ;
> Re(x+I*y) ; evalc(Re(x+I*y)) ;

<(x + Iy)
x
> Re(exp(x+I*y)) ; evalc(Re(exp(x+I*y))) ;
<(ex + Iy )
ex cos(y)

..................................................................................................................................

92

3.8 Nombres algbriques.


Le corps des complexes C, sujet de la section prcdente, n'est autre que le corps
de dcomposition du polynme X 2 +1, un polynme R-irrductible. Ce mcanisme
a une porte thorique trs gnrale et il est particulirement intressant dans le cas
du corps Q des rationnels, pour les polynmes coecients rationnels irrductibles.
Pour les considrations lmentaires sur les extensions algbriques de corps, voir
par exemple [6, 4].
Maple contient de ce point de vue un ensemble d'outils puissants, permettant
l'utilisateur de construire des extensions algbriques et d'y calculer aussi facilement
qu'avec les entiers, rationnels, ottants et complexes, au moins tant que l'obstacle
temps de calcul ou espace mmoire n'est pas rencontr.
Le sujet est vaste et on se contentera ici d'une introduction partir d'un
exemple. On va construire le corps de dcomposition du polynme X 3 + X + 1,
puis calculer un peu dans ce corps. On vrie d'abord que ce polynme est bien
Q-irrductible.
..................................................................................................................................

> P3 := X^3 + X + 1 ;

P 3 := X 3 + X + 1

> irreduc(P3) ;
true
..................................................................................................................................

Le corps K2 = Q[X]/(P 3), extension du corps K1 = Q, est donc mathmatiquement dni. Pour pouvoir y travailler commodment on procde dans l'espace de
travail Maple exactement comme dans l'espace de travail mathmatique. On crit
volontiers en mathmatiques que K2 = Q[] o est un nouveau nombre vriant 3 + + 1 = 0. Autrement dit K2 est obtenu partir de K1 par adjonction
d'un nouvel objet. Les lments de Q[] sont les polynmes a2 + b + c avec
a, b et c rationnels ; chaque tel polynme est considrer comme le reprsentant
canonique d'une classe d'quivalence de Q-polynmes modulo P 3 ; l'irrductibilit
de P 3 assure que K2 est bien un corps. En particulier est racine du polynme
P 3 ; le corps K2 contient donc au moins une racine de P 3 mais pour le moment
on ne sait pas s'il en contient d'autres.
Pour ajouter notre espace de travail Maple, on cre un alias.
..................................................................................................................................

> alias(alpha = RootOf(P3)) ;

I,
..................................................................................................................................

et dsormais est un objet comme un autre, un nombre algbrique, qui, strictement parlant, n'est rien d'autre que la classe d'quivalence de X dans le quotient
Q[X]/(P 3). Un calcul hors contexte ne donne rien de nouveau par rapport ce
qui tait prcdemment disponible :
..................................................................................................................................

> (1 + alpha)^6 ;

(1 + )6

93

> expand(%) ;

1 + 6 + 152 + 203 + 154 + 65 + 6

..................................................................................................................................

et on voit que Maple semble avoir oubli la relation 3 = 1. On demande


Maple d'en tenir compte systmatiquement en demandant le calcul dans le contexte
algbrique. De mme que la procdure evalf demande de privilgier le contexte
ottant, la procdure evala demande l'excution d'un travail dans le contexte
algbrique.
..................................................................................................................................

> evala((1 + alpha)^6) ;

52 12 21

..................................................................................................................................

Ici le rsultat est simple, mais dans ce contexte les rsultats euves sont frquents
et il peut tre important pour la lisibilit d'crire le polynme rsultat ordonn :
..................................................................................................................................

> sort(%, alpha)

52 21 12

..................................................................................................................................

Pour voir que le mcanisme d'alias est seulement auxiliaire :


..................................................................................................................................

> evala(RootOf(X^3+2*X+1)^3) ;
1 2 RootOf(_Z 3 + 2 _Z + 1)
> evala(RootOf(X^3+X+1)^3) ;
1

..................................................................................................................................

On voit que dans le deuxime cas, mme si on n'utilise pas l'alias disponible en
entre, Maple l'utilise si possible en sortie.
Une autre faon de voir que le polynme initial P 3 est irrductible, consiste
tenter de le factoriser.
..................................................................................................................................

> factor(P3) ;

X3 + X + 1

..................................................................................................................................

Dans le corps K1 = Q, le polynme P 3 n'a pas de racine. Par contre il a une racine
dans K2 = Q[], ce qui est mis en vidence comme suit :
..................................................................................................................................

> factor(P3, alpha) ;

(X 2 + X + 1 + 2 ) (X )

..................................................................................................................................

On voit qu'on dispose dans la procdure factor d'un argument optionnel complmentaire indiquant que la factorisation doit tre ralise dans une extension de Q,
dnie par l'intermdiaire d'un objet RootOf, adjoint Q.
..................................................................................................................................

> type(alpha, RootOf) ;

true
..................................................................................................................................

Le corps K2 contient comme il se doit la racine du polynme P 3, mais


pas d'autre. Le corps de dcomposition de P 3 n'est pas encore construit. Il faut
construire une extension K3 de degr 2 de K2 en ajoutant une racine du facteur
94

de degr 2 de P 3. Extrayons ce polynme. Il s'agit de diviser P 3 par (X ) ;


nouveau le contexte evala est indispensable.
..................................................................................................................................

> P2 := evala(P3/(X-alpha)) ;

P 2 := X 2 + X + 1 + 2

..................................................................................................................................

On ajoute notre environnement une racine de P 27 .


..................................................................................................................................

> alias(beta = RootOf(P2)) ;

I, ,
..................................................................................................................................

Ceci va nous permettre de travailler maintenant dans le corps K3 = K2 [] =


Q[, ]. Notre nouvel lment est bien racine du polynme initial :
..................................................................................................................................

> evala(subs(X = beta, P3)) ;

0
..................................................................................................................................

On peut d'ailleurs demander la factorisation de P 3 dans K3 :


..................................................................................................................................

factor(P3, {alpha, beta}) ;

(X ) (X + + ) (X )
..................................................................................................................................

Le corps K3 est donc le corps de dcomposition de P 3. C'est une extension


de degr 6 de Q dont un exercice classique consiste trouver un lment primitif.
C'est la porte de Maple.
..................................................................................................................................

> evala(Primfield({alpha, beta})) ;


[[RootOf(9 _Z 2 + 31 + 6 _Z 4 + _Z 6 ) = 2 + ],
2 1
5
[ = + RootOf(9 _Z 2 + 31 + 6 _Z 4 + _Z 6 ) +
RootOf(9 _Z 2 + 31 + 6 _Z 4 + _Z 6 )2
9 2
18
1
+ RootOf(9 _Z 2 + 31 + 6 _Z 4 + _Z 6 )4 ,
18
4 5
1
= RootOf(9 _Z 2 + 31 + 6 _Z 4 + _Z 6 )2 RootOf(9 _Z 2 + 31 + 6 _Z 4 + _Z 6 )4 ]]
. . . . . . . . .9
. . . . . .9
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

L'achage est assez encombrant, mais on repre immdiatement l'occurence rpte d'un nouveau RootOf pour lequel on va aussi crer un alias ; on voit que
notre RootOf est en particulier le premier membre de l'quation qui est le premier
(unique) lment de la premire liste du rsultat ; notre alias peut donc tre cr
comme suit8 :
..................................................................................................................................

> alias(gamma = op([1,1,1], %)) ;

I, , ,
..................................................................................................................................

moyennant quoi on peut rcrire le rsultat antrieur :


7 Attention,

ne pas crire ici :


> alias(beta = RootOf(X2 + alpha*X + 1+alpha2))
car un alias ne peut pas tre dni par une expression o gure explicitement un autre alias.
8 Voir Section 4.3 pourquoi la procdure op peut tre ainsi utilise.

95

..................................................................................................................................

> %% ;

[[ = 2 + ], [ =

1
5
1
4 5
1
+ + 2 + 4 , = 2 4 ]]

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .9. . . . . .2. . . . . . . .18


. . . . . . . . . . 18
. . . . . . . . . . . . . . . . .9
. . . . . .9
. . . . . . . . . .9. . . . . . . . . . . . . . . . . . . . . . . . . .

qui est maintenant bien lisible. Que faut-il lire ? Que l'lment primitif choisi
par Maple est la combinaison = 2 + , et que les deux gnrateurs et
s'expriment comme polynmes simples l'aide de . Le polynme minimal de
est trs particulier ; c'est un polynme de degr 6 et pourtant son corps de dcomposition est aussi de degr 6, alors qu'un polynme de degr 6 choisi au hasard a
en gnral un corps de dcomposition de degr 720 sur Q. Extrayons ce polynme ;
la variable systme _Z est laide et on la remplace par X :
..................................................................................................................................

> P6 := subs(_Z=X, op(gamma)) ;


P 6 := 9X 2 + 31 + 6X 4 + X 6

..................................................................................................................................

Ce polynme est certainement irrductible :


..................................................................................................................................

> irreduc(P6) ;

true
..................................................................................................................................

Mais il est entirement dcompos dans le corps Q() :


..................................................................................................................................

factor(P6, gamma)
1

(6X + 4 + 3 + 5 2 + 4 ) (6X + 4 3 + 5 2 + 4 ) (6X + 4 3 + 5 2 + 4 )


1296
(6X + 4 + 3 + 5 2 + 4 ) (X + ) (X + )

..................................................................................................................................

On est tout prs de la thorie de Galois qu'on rexaminera plus tard dans ce
manuel ; disons seulement que le degr du corps de dcomposition d'un polynme
de degr infrieur 8 est directement accessible sous Maple comme suit :
..................................................................................................................................

> galois(P6)[4] ;

6
..................................................................................................................................

comparer au groupe de Galois du premier polynme de degr 6 choisi au hasard


par Maple ; l'option terms=7 sert forcer la prsence d'un terme constant.
..................................................................................................................................

> galois(randpoly(X, degree=6, terms=7))[4]


720

..................................................................................................................................

3.9 Un exemple float vs Not(float).


Cette section peut tre omise en premire lecture ; de nombreuses procdures
non encore tudies y sont utilises. Ceci dit, une imitation dle dans une session
Maple de ce qui est montr ici ne devrait poser aucun problme, mme pour un
lecteur novice ; et elle peut tre instructive.
Considrons le problme suivant : on veut construire le polynme d'interpola96

tion P (z) de degr 7 vriant les relations :

P (e2ik/8 ) = k ; 0 k 7.
Puisqu'il s'agit d'un problme trs classique d'interpolation polynmiale, une
procdure Maple est peut-tre toute prte pour un tel travail ? La recherche
Topic Search mne rapidement la procdure interp, trs simple d'utilisation.
L'exemple suivant sut pour en comprendre le fonctionnement.
..................................................................................................................................

> P := interp([1,2,3,4], [81,70,97,63], X) ;


33
499
P := X 3 + 118 X 2
X + 229
2
2
> seq(subs(X=k, P), k=1..4) ;
81, 70, 97, 63

..................................................................................................................................

On dtermine dans l'exemple ci-dessus le polynme de degr 3 vriant P (1) = 81,


. . ., P (4) = 63. Puis le rsultat obtenu est contrl : l'appel de la procdure seq
demande l'achage, pour 1 k 4, de la valeur de P (k) obtenue par substitution
X 7 k dans l'expression de P .
Un essai dans le mme sens avec les racines 8-imes de l'unit mrite d'tre
tent. Les donnes sont un peu plus. . .complexes, et il est meilleur de les prparer
d'abord.
..................................................................................................................................

> xdata := [seq(exp(2*I*k*Pi/8), k=0..7)] ;


1
1
1
1
1
1
1
1
xdata := [1,
2 + I 2, I,
2 + I 2, 1,
2 I 2, I,
2 I 2]
2
2
2
2
2
2
2
2
> ydata := [seq(k, k=0..7)] ;
ydata := [0, 1, 2, 3, 4, 5, 6, 7]

..................................................................................................................................

Maple sait exprimer lmentairement les racines 8-imes de l'unit. Il ne reste plus
qu' utiliser ces donnes :
..................................................................................................................................

> interp(xdata, ydata, Z) ;


X

+ 12 . . .
1
1
1
1
1
1 1
1
((
2 + I 2 1)(
2 + I 2 I)(I
2 I 2)(
2 + I 2 1))
2
2
2
2
2
2
2
2

..................................................................................................................................

Le temps de calcul est trs bref, 1 seconde sur un PC moyen, mais le rsultat9 , dont
on n'a montr ici que le dbut de la premire ligne, est euve : l'auteur a compt
patiemment 379 crans de formules base de radicaux. Les tentatives rituelles
base de simplify et radnormal pour tenter de rduire le rsultat ne donnent rien,
de sorte que le rsultat est pratiquement inexploitable. On trouve ici une situation
typique o un calcul exact choue cause de sa trop grande complexit. Si le but du
calcul est le trac graphique obtenu page 102, des donnes ottantes sont toujours
susantes, et il est donc lgitime de se rabattre sur un calcul de type ottant. On
convertit donc nos racines de l'unit sous forme ottante et on applique le mme
calcul de polynme d'interpolation.
9 L'exprience

montre que l'ordre des termes achs est arbitraire d'une session l'autre.

97

..................................................................................................................................

> xdataf := evalf(xdata) ;


xdataf := [1., .7071067810 + .7071067810 I, 1. I, .7071067810 + .7071067810 I,
1., .7071067810 .7071067810 I, 1. I, .7071067810 .7071067810 I]
> Pf := interp(xdataf, ydata, Z) ;
P f := .2 108 I .500000001Z .499999999Z 3 + 1.207106778IZ .499999997Z 2
+.500000001IZ 2 + .207106785IZ 3 .207106783IZ 5 .500000000IZ 6
1.207106783IZ 7 .500000004Z 4 .499999999Z 5 .5000000003Z 6
+3.500000000 .4999999997Z 7

..................................................................................................................................

Le polynme d'interpolation est cette fois visible d'un coup d'il ; de plus
les coecients sont remarquablement simples et laissent subodorer des proprits
arithmtiques souterraines dans le calcul d'interpolation en cours. Les coecients
du style 1.207106778 sont moins clairs, mais leur quasi rptition nous incite
lucider ce qui peut expliquer ces phnomnes. Une ide naturelle consiste alors
isoler le coecient de Z dans P ; on sait qu'il est gant et on ne l'ache pas.
..................................................................................................................................

> a1 := coeff(P, Z, 1) :

..................................................................................................................................

puis on normalise par rapport aux radicaux ce coecient isol. Cette fois la normalisation va rapidement au bout et donne :
..................................................................................................................................

> a1rn := radnormal(a1) ;

1
1
1
I + I 2
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2. . . . . . .2
. . . . . . . . . . . .2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
a1rn :=

Le rsultat est si simple qu'il mrite d'tre compar au coecient correspondant


du polynme d'interpolation coecients ottants.
..................................................................................................................................

> evalf(a1rn - coeff(Pf, Z, 1)) ;


.10 108 + .30 108 I

..................................................................................................................................

Aux erreurs d'arrondi prs, les coecients sont bien les mmes. On peut faire le
mme travail pour les autres coecients, un par un, ce qui peut d'ailleurs tre
automatis : on a expliqu plus haut que les tentatives usuelles de simplication
chouent, mais il est maintenant clair qu'en traitant les coecients un par un, on
doit aboutir. On oriente normalement le calcul en ce sens comme suit, mais ne le
faites pas !
..................................................................................................................................

> P2 := collect(P, X) ;

..................................................................................................................................

Il semble en eet qu'un bug10 Maple soit ici : Maple reste sans rponse, les indicateurs Time et Bytes en bas de l'cran restent inactifs, et l'utilisateur ne peut
reprendre la main. Seule solution : abattre sa session de l'extrieur.
Ceci est assez troublant, et au lieu d'utiliser la procdure collect, on peut
chercher traiter soi-mme la gestion coecient par coecient.
10 Sous

versions 5 et 5.1, sous Windows ou sous Unix.

98

..................................................................................................................................

> P2 := add(radnormal(coeff(P, X, i))*X^i, i=0..7)) ;


7
1
1
1
1 1
1
1
1
1
P 2 := + ( I 2 + I ) X + ( + I) X 2 + ( I 2 I ) X 3 X 4
2
2
2
2
2 2
2
2
2
2
1
1 1
1 1
1 1
1
5
6
+ ( I 2 + I) X + ( I) X + ( I 2 I) X 7
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2. . . . . . . . . . . . .2. . . . . .2. . . . . . . . . . . . . . . . . 2
......2
. . . . . . . . . . . . . . . . . .2
. . . . . .2
. . . . . . . . . . . . .2
..........

Le but est-il atteint ? Si on en juge d'aprs le rsultat obtenu, oui ; ceci dit
le dernier calcul demande une quarantaine de secondes11 et compte tenu de la
simplicit du rsultat obtenu, il est trs tentant de chercher une mthode plus
simple permettant de court-circuiter les objets euves intermdiaires.
C'est le moment de penser que la solution rpute nave pour le problme
d'interpolation passe par une matrice de Vandermonde. Il s'agit en eet de trouver
des coecients i vriant les huit quations linaires :
7
X

j xjk = k avec xk = e2ik/8 , 0 k 7.

j=0

La matrice des coecients de ce systme linaire est la matrice de Vandermonde


par rapport aux racines 8-imes de l'unit ; elle a des proprits bien particulires.
Pour montrer commodment la matrice en question, crons un alias pour la racine
gnratrice, qu'on a intrt exprimer sous forme abstraite 12 , comme racine d'un
polynme irrductible :
..................................................................................................................................

> alias(alpha = RootOf(Z^4+1)) ;

I,
..................................................................................................................................

Rexprimons notre liste de racines :


..................................................................................................................................

> xdata := [seq(alpha^k, k=0..7)] ;


xdata := [1, , 2 , 3 , 4 , 5 , 6 , 7 ]

..................................................................................................................................

Maple ne semble pas savoir que 4 = 1, mais on peut lui souer d'exploiter ce
type de relation par application de la procdure evala explique page 94.
..................................................................................................................................

> xdata := evala(xdata) ;


xdata := [1, , 2 , 3 , 1, , 2 , 3 ]

..................................................................................................................................

On va utiliser les procdures spciques de calcul matriciel, qui ncessitent le


chargement pralable du package linalg,
..................................................................................................................................

> with(linalg) :

..................................................................................................................................

puis on construit la matrice de Vandermonde engendre par nos racines :


11 Sur

un PC moyen, on ne le prcisera plus.


prcisment est la classe du monme Z dans le corps Q[Z]/(Z 4 + 1) ; c'est un corps
cyclotomique et le polynme y est donc entirement dcompos.
12 Plus

99

..................................................................................................................................

> vdm := vandermonde(xdata) ;

1
1

1 2

1 3

vdm :=
1 1

1 2

10

12

12

15

18

10

12

14

21

14

12

15

18

21

..................................................................................................................................

On sait comment tenir compte de 4 = 1 ; une valuation explicite du symbole vdm est ici ncessaire pour atteindre la matrice pointe par le symbole
vdm : l'exception signale pour les valeurs procdures en Eval-16 intervient aussi
pour les valeurs matricielles ; voir Eval. D'o l'appel trange mais invitable
evala(eval(.... On cache le rsultat, vident mais encombrant.
..................................................................................................................................

> vdm := evala(eval(vdm)) :

..................................................................................................................................

L'inverse de cette matrice, cl du processus naf d'interpolation, est calcul


par la procdure inverse du package linalg.
..................................................................................................................................

> ivdm := inverse(vdm) ;


ivdm :=

1
1
8
8
1
1
1

8
4 (1 + 4 )

1
8
1 1
8 2

1
8
1

4 1 + 4

1
8
1

1
8
1 1

8 2

1 1
8 2
1

4 1 + 4

1
8
1 1
8 2

1
8
1
8

1 1
8 2
1

4 1 + 4

1
8
1
8

1
8
1
1
4 (1 + 4 )

1
8
1 1
8 2

1
8
1

4 1 + 4

1
1
1

8
8
8
1
1
1
1 1

8
4 (1 + 4 )
8 2

1
8
1
8

1 1
8 2
1

4 1 + 4

1
8
1 1

8 2

1 1
8 2
1
1
4 (1 + 4 )

1
8
1

1
1 1
1

8
8 2
8
1 1
1
1
1

8 2
4 (1 + 4 )
8

1
8
1
1
4 (1 + 4 )

1 1
8 2
1

4 1 + 4

1
8
1 1
8 2

1
8

4 1 + 4

1 1
8 2
1
1
4 (1 + 4 )

1
8
1

4 1 + 4

1 1
8 2
1
1

4 (1 + 4 )

..................................................................................................................................

Un appel de evala va nous simplier considrablement cette matrice.

100

..................................................................................................................................

> ivdm := evala(eval(ivdm)) ;


1
1
8
8

1
1
3

8 8

1
1

8
8

1
1

8 8
ivdm :=
1
1

8
8

1
1 3

8
8

1
1 2

8
8

1
1

8
8

1
8
1 2

8
1

8
1 2

8
1
8
1 2

8
1

8
1 2

1
8
1

8
1 2

8
1
3
8
1

8
1

8
1
2
8
1 3

1
8
1

8
1
8
1

8
1
8
1

8
1
8
1

1
8

1
8

1 3

8
1
2
8
1

8
1

8
1 3

8
1 2

8
1

8

1 2

8
1

8
1
2
8
1
8
1 2

8
1

8
1
2
8

1
8
1

8
1 2

8
1 3

8
1

8
1

8
1
2
8
1
3
8

..................................................................................................................................

Si on a l'il, on observe que l'inverse de notre matrice de Vandermonde est assez


extraordinaire ; c'est l'un des rares cas o l'inversion du cancre russit (presque),
celle qui consiste prendre comme inverse de la matrice la matrice des inverses !
L'inverse du cancre peut tre obtenu comme suit :
..................................................................................................................................

> dunce_ivdm := map(item -> 1/item, vdm) :


iszero(evala(evalm(8 - dunce_ivdm &* vdm))) ;
true

..................................................................................................................................

aprs quoi on vrie que le produit de notre candidat inverse par la matrice inverser est 8 fois la matrice identit ; la procdure evalm value l'expression matricielle
et l'appel de evala demande de tenir compte de 4 = 1 ; enn la procdure
iszero examine si la matrice obtenue est nulle.
L'inversion si facile est due aux proprits particulires de l'ensemble des racines de l'unit : on a retrouv les proprits les plus simples de la transformation
de Fourier discrte, voir par exemple [5]. Un autre point de vue peut aussi tre
considr ; examinons le conditionnement de la matrice inverser. Comparer :
..................................................................................................................................

> evalf(cond(vdm)) , evalf(cond(vandermonde(ydata))) ;


8.000000000, .9206599111 108

..................................................................................................................................

C'est pourquoi l'interpolation polynmiale par rapport une suite d'entiers 0, . . .,


n est si instable (phnomne de Runge par exemple), alors que, sur un groupe de
racines de l'unit, les mmes instabilits ne sont pas observes.
Le polynme qu'on avait obtenu trs facilement en calcul ottant mais sans
comprendre sa nature peut maintenant tre obtenu en calcul exact : on multiplie
matriciellement le vecteur des valeurs ydata par l'inverse ivdm ; on obtient ainsi la
liste des coecients du polynme d'interpolation cherch qu'on construit ensuite
par un mcanisme d'addition itrative. On vrie numriquement que c'est bien,
101

aux erreurs d'arrondi prs, le polynme ottant dj obtenu ; l'appel intermdiaire


de la procdure collect sert regrouper les coecients des mmes puissances de Z,
ncessaire, compte tenu de l'interfrence avec le gnrateur complexe I.
..................................................................................................................................

> coefficients := evala(evalm(ivdm &* ydata)) ;


coefficients

:= [ 27 , 12 + 12 3 + 12 2 + 21 , 12 + 12 2 , 12 + 21 12 2 + 21 3 , 12 ,
21 12 3 + 12 2 21 , 12 12 2 , 12 12 21 2 21 3 ]

> exactP := add(coefficients[i]*Z^(i-1), i=1..8) ;


exactP := 72 + ( 12 + 12 3 + 12 2 + 12 )Z + ( 12 + 12 2 )Z 2 + ( 12 + 12 12 2 + 12 3 )Z 3
21 Z 4 + ( 12 12 3 + 12 2 12 )Z 5 + ( 12 21 2 )Z 6
+( 12 12 12 2 12 3 )Z 7

> evalf(collect(Pf - subs(alpha = exp(2*I*Pi/8), exactP), Z));


.44 108 IZ 7 + (.18 108 .12 108 I)Z 6 + (.18 108 + .20 108 I)Z 5
+ (.20 108 + .1 108 I)Z 4 + (.18 108 .20 108 I)Z 3 + (.40 108 + .12 108 I)Z 2
+ (.28 108 + .44 108 I)Z + .1 108 .1 108 I

..................................................................................................................................

Notre polynme d'interpolation est cette fois obtenu par un calcul qui n'a pos
aucune dicult particulire : aucun rsultat intermdiaire ingrable l'cran,
1.3 seconde de temps CPU.
On voulait obtenir une courbe ferme du plan complexe joignant les huit points
rels de ydata. Il sut de tracer l'image du cercle unit par le polynme exactP.
Il faut mieux utiliser la procdure complexplot du package plots :
..................................................................................................................................

> with(plots, complexplot) :

..................................................................................................................................

On remplace notre racine abstraite par exp(2*I*Pi/8) = e2i/8 , on remplace


aussi X par exp(I*t) = eit et on se contente des approximations ottantes :
..................................................................................................................................

> fourierP := evalf(subs({alpha = exp(2*I*Pi/8), X = exp(I*t)}, exactP)) ;


f ourierP := 3.500000000 + (.4999999998 + 1.207106781 I) e(1. I t)
2
3
+(.5000000000 + .4999999998 I) (e(1. I t) ) + (.4999999998 + .2071067810 I) (e(1. I t) )
4
5
.5000000000 (e(1. I t) ) + (.5000000002 .2071067810 I) (e(1. I t) )
6
7
+(.5000000000 .4999999998 I) (e(1. I t) ) + (.5000000002 1.207106781 I) (e(1. I t) )

..................................................................................................................................

Le trac est alors obtenu par la procdure complexplot ; l'argument supplmentaire


scaling = constrained force Maple utiliser la mme chelle horizontalement
et verticalement.

102

..................................................................................................................................

> complexplot(fourierP, t=0..2*Pi, scaling = constrained) ;

..................................................................................................................................

Une proprit du graphique obtenu est inattendue ; la courbe d'interpolation


passe 6 fois au point 3.5. On est ici dans une situation typique o on constate
exprimentalement une proprit pas du tout vidente a priori. Peut-on obtenir
une conrmation autre que visuelle ? Dterminons la suite des points o notre
polynme d'interpolation vaut 3.5 :
..................................................................................................................................

> solve(Pf = 3.5) ;


.9963394407 0.08548518823 I, .6440712188 + .7649655315 I, .5009167252 .8654954829 I,
.1414213565 108 + .5857864416 109 I, .2577961103 + .9661993401 I,
.4381080388 .8989223241 I, .9454232373 + .3258449052 I

..................................................................................................................................

puis considrons les modules des racines obtenues :


..................................................................................................................................

> map(abs, [%]) ;


[.9999999993, .9999999996, .9999999983, .1530733733 108 ,
.9999999996, .9999999992, .9999999999]

..................................................................................................................................

On voit ainsi la racine 0, conrme aussi par la forme exacte du polynme d'interpolation, et les six autres racines manifestement de module 1. Pour conrmer
ce point de vue, on peut commencer par pousser la prcision ; le calcul avec 30
chires signicatifs ne prend pratiquement pas plus de temps et conrme notre
conjecture. Si au lieu de prendre huit points sur le cercle unit du plan complexe, on
en prend un nombre pair quelconque, le mme rsultat est observ ; et un rsultat
analogue est aussi constat dans le cas impair. Il reste obtenir une dmonstration
mathmatique gnrale de ce fait, mais c'est une autre histoire13
13 Indications.

Considrons d'abord le cas o n est pair et k un entier 0 k < n/2. On va


s'intresser aux racines de l'unit ` = e(2`(n1))i/n pour 0 ` < n. Il y a n telles racines, mais
disposes par paires, symtriquement par rapport l'axe rel. On considre alors le polynme
d'interpolation Pn,k vriant P (k ) = P (nk1 ) = k et P (` ) = 0 pour les autres ` . Ce

103

C'est un exemple lmentaire mais typique de Mathmatiques exprimentales :


des concidences troublantes observes sur des rsultats numriques ou graphiques permettent d'noncer et de dmontrer des proprits qu'il aurait t autrement dicile de trouver.
-o-o-o-o-o-o-o-

polynme est coecients rels ; il a la racine 0 et les autres racines sont les ` 6= k , nk1 ; on
en dduit sa forme Pn,k = XQn,k o le polynme Qn,k est coecients symtriques ; de plus le
polynme Qn,k est strictement positif sur l'axe rel. Donc toute combinaison coecients positifs
des polynmes Pn,k (n x) va avoir les mmes proprits : une racine 0 et les autres racines
sur le cercle unit du plan complexe. Or le polynme du texte se dduit d'une telle combinaison
par une manipulation simple. Une tude analogue aboutit dans le cas n impair. La symtrie
assez rudimentaire l'origine de notre phnomne est ainsi lucide ; par exemple le polynme
d'interpolation o les valeurs successives sur les 10 racines 10-imes de l'unit sont 2, 4, 1, 3, 5,
-5, -3, -1, -4 et -2 va prsenter la mme proprit : la courbe image du cercle unit va passer huit
fois par l'origine :

104

Chapitre 4
Listes, ensembles, suites et tables.
4.1 Introduction.
Ce chapitre est consacr des objets Maple qui, selon le contexte, pourraient
tre appels composs, ou itratifs, bien qu'aucun de ces qualicatifs ne soit sufsant pour dnir notre sujet. En langage C++, une paire d'accolades {. . ., . . .}
regroupe plusieurs instructions pour en produire une seule, qu'on appelle alors
instruction compose. Dans le mme esprit, si obj1, obj2, . . ., objn sont des objets
Maple, alors :
[obj1, obj2, ..., objn]

dsigne un objet compos, appel liste, ou encore objet list. Mais d'autres objets
comme par exemple l'objet function :
operator(operand1, ..., operandn)

est aussi en un sens un objet compos, mais qui n'est pourtant ni une liste, ni
un ensemble, ni une suite, ni une table. On verra toutefois que la suite des
oprandes operand1, ..., operandn est bien une suite au sens prcis donn par
Maple cette notion, et de telles suites d'oprandes (ou d'arguments) seront donc
considres dans ce chapitre, notamment Section 4.4.
Un autre point de vue est considrer ; l'instruction C++ :
..................................................................................................................................

for {int i = 0 ; i < 10 ; ++i}


cout << i^3 << endl ;

..................................................................................................................................

excute 10 fois la mme instruction, ceci prs que l'environnement est dirent
chaque itration : la valeur de i est modie. Dans le mme esprit l'instruction
Maple :
..................................................................................................................................

> [seq(i^3, i=0..9)] ;

[0, 1, 8, 27, 64, 125, 216, 343, 512, 729]

105

..................................................................................................................................

construit une liste o les lments sont tous de mme nature, un cube d'entier,
mais l'entier en question est variable d'un entier l'autre. Un tel objet peut donc
tre appel naturellement un objet itratif, mais d'autres listes ont au contraire
des lments trs dirents deux deux et ne peuvent pas raisonnablement entrer
dans cette catgorie.
Dcidons d'appeler listes, ensembles, suites et tables des objets multiples, pourquoi pas. Les objets multiples Maple sont donc de type list, set, exprseq ou table.
Le type table admet le sous-type array, lequel admet son tour les sous-types
matrix et vector ; les deux derniers types sont bien entendus ddis d'abord au
calcul matriciel.
Le type exprseq est vraiment l'un des ingrdients essentiels de Maple. Les lispeurs reconnatront dans les objets de type exprseq, absolument partout dans
Maple, la version adapte des listes de Lisp ; rappelons que Lisp est une contraction de List Processing. De mme que les cellules cons sont les particules lmentaires des objets Lisp, l'ingrdient de base pour la construction des listes Lisp, la
structure de type exprseq est le noyau de la structuration des objets Maple. C'est
peu dire que la comprhension des objets de ce type est la cl indispensable pour
entrer dans la confrrie des initis Maple.

Warning 21  Les quatre types exprseq (suite), list (liste), set (ensemble) et

table (table) sont disjoints deux deux. Une suite ne peut pas tre ni une liste,
ni un ensemble, ni une table. De mme pour toutes les autres combinaisons deux
deux.
Rien n'empche un lment de suite d'tre une liste, un ensemble ou une table ;
de mme pour les lments des listes, ensembles et tables. Par contre un lment
de suite, liste ou ensemble ne peut jamais tre une suite. Un lment de table peut
lui tre absolument de tout type ; il peut en particulier tre une suite.
Les relations d'appartenance possibles sont runies dans ce tableau.

exprseq
list
set
table

exprseq
Non
Oui
Oui
Oui

list
Non
Oui
Oui
Oui

set
Non
Oui
Oui
Oui

table
Oui
Oui
Oui
Oui

Ce warning est incomprhensible ce point ; il n'est nonc que pour dnir un


but qui doit tre atteint : n'esprez pas utiliser Maple pour des applications non
triviales si vous n'avez pas compris ce warning. Il s'agit dans les sections suivantes
de dcrypter ces assertions, pour le moment sotriques. Ces questions ne sont
pas capitales en elles-mmes, mais elles constituent un excellent thme didactique
permettant de vrier que ces structures sont bien comprises.

106

4.2 Premier examen des types multiples.


On construit une suite, une liste, un ensemble et une table, tous trs simples.
..................................................................................................................................

> seq4 := a, b, c, d ;
list4 := [a, b, c, d] ;
set4 := {a, b, c, d} ;
table4 := table([1=a, 2=b, 3=c, 4=d]) ;
seq4 := a, b, c, d
list4 := [a, b, c, d]
set4 := {a, b, c, d}
table4 := table([
1=a
2=b
3=c
4=d
])

..................................................................................................................................

Nos objets multiples ont tous quatre lments. Pour construire une suite, les
lments constituants sont spars par virgule. De mme pour liste et ensemble,
ceci prs que pour une liste il faut prvoir en plus crochets ouvrant et fermant, et
pour un ensemble, accolades ouvrante et fermante. Pour une table, on peut utiliser
le constructeur table avec comme argument une liste d'quations cl = objet.
On voit qu'une liste (resp. ensemble) n'est rien d'autre, typographiquement,
qu'une suite encadre de crochets (resp. accolades). Ceci n'est pas une convention
pour les reprsentations externes ; il en est essentiellement de mme en mmoire.
Avant de dtailler ce point, il faut d'abord expliquer que la virgule ne doit pas
tre comprise comme un procd syntaxique ; c'est vritablement l'oprateur inx
n-aire permettant de construire une suite. Comparer dans ce registre les deux
instructions :
..................................................................................................................................

> a + b + c ;
a , b , c ;

a+b+c
a, b, c
..................................................................................................................................

o l'analogie est parfaite, et ce n'est pas une analogie, c'est une ralit. L'auteur
suit le plus souvent en entre l'usage typographique : pas de blanc avant la virgule,
un blanc aprs ; mais ceci n'est qu'un usage, sans aucune importance pour le lecteur
Maple.
Donc une expression avec n oprandes spars par n 1 virgules est lue comme
une suite de n lments. Ceci n'a de sens que si n 2. En particulier la notion de
suite un lment n'a pas de sens ! Par contre la suite vide existe et est accessible
en particulier par l'intermdiaire du symbole NULL, protg, qui pointe vers cette
suite, invisible, comme on le voit ci-dessous.

107

..................................................................................................................................

> whattype(seq4) ;

exprseq

> wrong_seq1 := a ;

wrong_seq1 := a

> whattype(wrong_seq1) ;
symbol

> right_seq0 := NULL ;

right_seq0 :=

> whattype(right_seq0)

exprseq

..................................................................................................................................

On a expliqu qu'une liste (resp. ensemble ) n'est autre qu'une suite encadre
par crochets (resp. accolades). C'est si vrai que les liste et ensemble points par
list4 et set4 auraient pu aussi bien tre construits comme suit :
..................................................................................................................................

> list4 := [seq4] ; set4 := {seq4} ;


list4 := [a, b, c, d]
set4 := {a, b, c, d}

..................................................................................................................................

et en mmoire il en est de mme ; un objet list est une entte indiquant qu'il s'agit
d'une liste et un unique pointeur vers un objet exprseq, moins que la liste ait un
seul lment, auquel cas le pointeur pointe directement vers cet lment, car une
suite un lment n'a pas de sens1 .
Donc listes et ensembles ne sont en quelque sorte que des objets satellites de
suites. Une liste n'est autre qu'une suite avec un chapeau indiquant qu'il s'agit en
fait d'une liste, de mme pour un ensemble. Il y a pourtant une dirence entre les
constructeurs de listes et d'ensembles ; une liste n'est vraiment rien d'autre qu'une
suite avec un chapeau, un ensemble aussi, mais le constructeur d'ensemble va
en plus vrier que les objets constituants sont dirents deux deux. Le cas
chant, les objets doublons sont carts. De plus l'ordre des objets achs est
sans importance pour un ensemble alors qu'il l'est pour une liste. En fait Maple
trie pour un ensemble selon les adresses machine. Comparer :
..................................................................................................................................

> seq6 := a, z, e, r, a, z ;
> list6 := [seq6] ;

seq6 := a, z, e, r, a, z
list6 := [a, z, e, r, a, z]

> set4 := {seq6} ;

set4 := {a, r, z, e}

..................................................................................................................................

Avant de poursuivre notre examen des types multiples, donnons-nous les


moyens d'analyse d'objets oerts par Maple.
1 Les passionns d'implmentation machine peuvent examiner ces questions avec les procdures

addressof, pointto et disassemble.

108

4.3 Les procdures op et nops.


Les objets Maple sont constitus d'objets lmentaires assembls selon des procdures varies riches en possibilits, mais en dnitive assez simples. On a dj
expliqu Section 2.2.3 que les types de donnes taient rcursifs ; ceci permet, avec
des procds de construction assez rudimentaires, de construire des objets fort
complexes. Inversement il faut tre capable d'analyser indniment comment est
structur un objet quelconque, analyse qui n'est termine que quand les composantes irrductibles sont identies, ainsi que leur mode d'assemblage. Les principaux outils d'analyse sont les procdures op et nops.
L'usage de ces analyseurs est trs facile, sauf pour les suites. On a expliqu
Section 2.4.2 que les objets function ont un oprateur et des oprandes ; dans des
cas particuliers, il peut y avoir seulement un oprande, ou mme pas d'oprande du
tout. Le nombre d'oprandes est obtenu par la procdure nops, chaque oprande est
obtenu par la procdure op, l'oprateur aussi. Pour faire comprendre le mcanisme,
considrons l'objet function point par le symbole function3 :
..................................................................................................................................

> function3 := abc(bcd1, bcd2, bcd3) ;


function3 := abc(bcd1, bcd2, bcd3)
> whattype(function3) ;
function

..................................................................................................................................

L'objet function est construit puis aect au symbole function3 ; quand on demande le type de la valeur de ce symbole, la procdure whattype rpond justement
function. On obtient le nombre d'oprandes de la valeur du symbole function3
l'aide de la procdure nops :
..................................................................................................................................

> nops(function3) ;

3
..................................................................................................................................

Moyennant quoi on sait que la valeur de function3 est un objet avec trois
oprandes. On peut demander par exemple le deuxime oprande :
..................................................................................................................................

> op(2, function3) ;

bcd2

..................................................................................................................................

Par extension, le 0-ime oprande est l'oprateur :


..................................................................................................................................

> op(0, function3) ;

abc

..................................................................................................................................

On a ainsi un procd trs gnral et trs simple pour analyser tout objet.
Considrons par exemple cet objet appel une intgrale inerte ; c'est une intgrale o le choix de l'oprateur Int commenant par une majuscule, au lieu de
l'oprateur d'intgration usuel int commenant par une minuscule, demande explicitement Maple de ne pas valuer l'intgrale et donc de la garder telle quelle.
On verra plus tard de nombreuses circonstances o de tels objets inertes sont
utiles, voire indispensables.
109

..................................................................................................................................

> II := Int(x^3, x=1..2) ;

II :=

x3 dx

1
..................................................................................................................................

La valeur de II semble un peu exotique pour le dbutant, mais il ne doit pas


se laisser intimider par l'apparence extrieure de cette intgrale non value ; les
procdures nops et op vont lui permettre d'analyser la structure de cet objet.
..................................................................................................................................

> nops(II) ;

> op(0, II) ;


> op(1, II) ;

Int
x3

> op(2, II) ;


x = 1..2
..................................................................................................................................

On voit qu'en fait le format interne correspond exactement ce qui avait t entr
pour la cration de l'objet.
Le choix d'une intgrale inerte pour cette illustration n'est pas innocent ; l'intgrale inerte, par principe, n'est pas value. Comparer le mme exercice avec la
procdure int ordinaire, celle qui cherche eectuer l'intgration :
..................................................................................................................................

> nops(int(x^3, x=1..2)) ;

> op(0, int(x^3, x=1..2)) ;

fraction

> op(1, int(x^3, x=1..2)) ;


15

> op(2, int(x^3, x=1..2)) ;


4
..................................................................................................................................

Car l'intgrale est value et retourne 15/4 :


..................................................................................................................................

> int(x^3, x=1..2) ;

15
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Il faut rester toujours vigilant ce propos ; malgr leur parfum systme, les procdures nops et op sont standard et valuent leurs arguments avant de les utiliser,
source permanente de piges dans les debuggings vreux.
Les procdures nops et op fonctionnent en particulier pour les listes. Considrons cette liste biscornue :

110

..................................................................................................................................

> list4 := [27, x^2+y^2, Pi, Int(x^3, x=1..2)] ;

Z 2
list4 := 27, x2 + y 2 , ,
x3 dx
1

> nops(list4) ;
4

..................................................................................................................................

Notre liste, dans la terminologie Maple, est donc un objet quatre oprandes,
correspondant ce qui est appel d'habitude les lments de la liste. On peut
demander l'oprande 4 :
..................................................................................................................................

> op(4, list4) ;

x3 dx

1
..................................................................................................................................

et l'oprande 0 :
..................................................................................................................................

> op(0, list4) ;

list

..................................................................................................................................

On peut demander l'oprande 2 de l'oprande 4 :


..................................................................................................................................

> op(2, op(4, list4)) ;

x = 1..2
..................................................................................................................................

ou si on prfre :
..................................................................................................................................

> op([4, 2], list4) ;

x = 1..2
..................................................................................................................................

Noter que les indices successifs sont alors lire de gauche droite et doivent tre
les constituants d'une liste. Et ainsi de suite :
..................................................................................................................................

> op([4,2,1], list4) ;

x
..................................................................................................................................

On voit qu'on dispose bien ainsi du scanner permettant d'identier chaque


composante d'un objet, quelque profondeur que ce soit. Si on va trop loin, une
erreur intervient.
..................................................................................................................................

> op([4,2,1,2], list4) ;

Error, improper op or subscript selector

..................................................................................................................................

L'oprande 0 peut tre aussi structur.

111

..................................................................................................................................

> op(0, f(g)(h)) ;

f(g)

> op([0,1], f(g)(h)) ;


g

> op([0,0], f(g)(h)) ;


f

> op([1,0], f(g(h))) ;


g
..................................................................................................................................

On pratique aussi assez souvent l'analyse niveau par niveau, en descendant


un tage chaque fois par rapport au rsultat prcdent atteint par le symbole
systme ditto, savoir % :
..................................................................................................................................

> op(4, list4) ;

x3 dx

> op(1, %) ;

x3

> op(0, %) ;

..................................................................................................................................

Si un numro d'oprande est ngatif dans l'analyse l'aide de la procdure op, la


numrotation commence par la n. Une autre faon de retrouver notre intgrale
inerte est donc :
..................................................................................................................................

> op(-1, list4) ;

x3 dx

> op([-1,2,-2], list4) ;

x
..................................................................................................................................

On peut encore appeler la procdure op avec un seul argument, l'objet analyser ; dfaut de prcision sur l'oprande souhait, la procdure retourne alors la
suite des oprandes, oprateur exclu.
..................................................................................................................................

> op(list4) ;

Z
2

27, x + y , ,

x3 dx

1
..................................................................................................................................

Autrement dit on a ralis la conversion objet list objet exprseq, et ceci est
la seule faon d'y parvenir. Cette conversion est souvent indispensable et l'exemple
qui prcde doit donc tre bien compris. Un exemple typique d'application consiste
chercher l'lment maximum d'une liste ; la procdure max est disponible et tout
le monde espre d'abord pouvoir l'utiliser ainsi :
..................................................................................................................................

> list5 := [13, 26, 46, 10, 45] ;


list5 := [13, 26, 46, 10, 45]
> max(list5) ;
Error, (in simpl/max) arguments must be of type algebraic

..................................................................................................................................

112

Il faut en eet ncessairement retirer les crochets, c'est--dire convertir liste vers
suite.
..................................................................................................................................

> max(op(list5)) ;

46
..................................................................................................................................

Plus explicitement :
..................................................................................................................................

> max([13, 26, 46, 10, 45]) ;

Error, (in simpl/max) arguments must be of type algebraic

> max(13, 26, 46, 10, 45) ;

46
..................................................................................................................................

On peut aussi passer comme premier argument la procdure op un objet


range indiquant qu'on veut comme rsultat la suite des oprandes couverts par le
range :
..................................................................................................................................

> op(2..3, list4) ;

x2 + y 2 ,

> op(3..2, list4) ;


> op(-3..3,list4) ;

x2 + y 2 ,

> op(0..nops(list4), list4) ;

list, 27, x2 + y 2 , ,

x3 dx

1
..................................................................................................................................

La procdure subsop est logiquement de la mme famille que les procdures op


et nops, car il s'agit de traitement assez n d'oprandes. Nous prfrons toutefois
reporter son tude Section 4.5.3 dans un autre contexte, quand il s'agit de modier
composante par composante un objet dj existant.

4.4 Suites d'arguments.


Les suites sont aussi trs utilises dans les appels de procdures, le plus souvent
sans que l'utilisateur en ait mme conscience. La syntaxe d'un appel de procdure
est en eet proc(arg1, ..., argn) o proc est un objet dont la valeur est une
procdure, celle qu'on veut invoquer ; les arguments (provisoires) arg1, ..., argn
sont spars par virgule et constituent bien une suite, qui est en fait l'unique argu.
ment vraiment pass la procdure. On rexaminera cette question Chapitre
Disons tout de suite que ceci permet des appels sophistiqus, o on prpare patiemment la suite d'arguments ncessaires. Un point ce propos est important :
l'oprateur virgule opre non seulement sur les objets quelconques, mais aussi sur
les suites :

113

..................................................................................................................................

> seq12 := 1, 2 ; seq456 := 4, 5, 6 ;


seq12 := 1, 2
seq456 := 4, 5, 6
> seq16 := seq12, 3, seq456 ;
seq16 := 1, 2, 3, 4, 5, 6

..................................................................................................................................

On voit que chaque symbole pointant vers une suite a t remplac par la suite en
question ; autrement dit l'oprateur virgule est en fait un oprateur de concatnation entre suites, o, cas le plus frquent, tout oprande qui n'est pas une suite
est remplac par la suite constitue de cet unique lment. Ceci semble contredire
le warning expliquant qu'un lment de suite ne peut pas tre une suite, mais justement, l'valuateur tient compte de notre warning et en quelque sorte enlve
les parenthses implicites que vous croyez peut-tre voir ; les concepteurs de Maple
auraient aussi bien pu dcider ici que la valeur du symbole seq16 est une suite
trois lments o le premier et le troisime auraient t des suites, mais ce n'est
pas le choix qui a t fait ; ils ont dcid que si un argument de l'oprateur virgule
est une suite, alors la suite argument est concatne aux suites adjacentes. C'est
souvent commode, mais ncessite d'tre bien compris. Aucun parenthsage, mme
intensif, ne changera ceci :
..................................................................................................................................

> seq16bis := (((seq12), 3), (((seq456)))) ;


seq16bis := 1, 2, 3, 4, 5, 6

..................................................................................................................................

comparer avec :
..................................................................................................................................

> result := (((1 + 2) + 3) + (((4 + 5 + 6)))) ;


result := 21

..................................................................................................................................

o le parenthsage intensif n'a videmment pas empch l'addition de travailler.


C'est une consquence d'Eval-13 ; quand une expression est parenthse, elle
est value sparment, puis devient un composant de suite ; de sorte que si ce
composant est lui-mme une suite, la suite en question s'allonge, ou encore se
raccourcit si notre composant suite est la suite vide ! Ci-dessus l'valuation de
(seq12) retourne la mme valeur que celle de seq12 et le parenthsage pour tenter
d'isoler la suite rsultat est inoprant.
Considrons maintenant cet exemple :
..................................................................................................................................

> max(2, 4, 3) ;

4
..................................................................................................................................

La procdure max travaille sur un nombre quelconque d'arguments, et retourne


dans le cas rel ce qu'on pense. D'o :
..................................................................................................................................

> max(seq12, 3, seq456) ;

6
..................................................................................................................................

ce qui dans certains contextes peut tre assez commode. Cette technique est par
114

exemple bien utile quand vous avez dcid une fois pour toutes d'utiliser les procdures de trac graphique avec les options couleur, paisseur du trac et type de
trac ci-dessous :
..................................................................................................................................

> plot(sin(x), x=-Pi..+Pi, color=blue, thickness=2, linestyle=4) :

..................................................................................................................................

On ne montre pas ce trac, hors sujet ici. Mais l'usage rpt des mmes options
peut tre abrg par la dnition de la suite de trois quations aecte au symbole
my_options :
..................................................................................................................................

my_options := color=blue, thickness=2, linestyle=4 ;


my_options := color = blue, thickness = 2, linestyle = 4

..................................................................................................................................

Moyennant quoi vous pouvez entrer maintenant plus simplement :


..................................................................................................................................

> plot(sin(x), x=-Pi..+Pi, my_options) :

..................................................................................................................................

Ce qui semble tre l'unique argument my_options est dvelopp en trois arguments, chacun d'eux tant un objet equation.
On est maintenant enn capable de comprendre ce qu'on tait bien en peine
d'expliquer page 19. Reprenons l'expression qui tait value :
..................................................................................................................................

> int((1+x/(1+x^2+x^4), x=1..infinity)) ;

..................................................................................................................................

L'analyse du lecteur Maple est la suivante : il s'agit d'valuer un objet function


un seul oprande ; l'oprateur est le symbole int, et, cause du parenthsage,
l'unique oprande, est la suite (1+x/(1+x2+x4), x=1..infinity) ; en eet le
parenthsage oblige le lecteur considrer tout ce texte comme un unique objet,
ce qui est possible, l'objet en question tant une suite deux lments.
Ces prparatifs tant faits par le lecteur, l'valuateur est appel. La procdure
int est standard et l'unique argument provisoire suite est valu ; son valuation
est triviale et on est donc dans une situation o l'unique argument initial est
remplacer par deux arguments dnitifs. La procdure int est donc nalement
invoque comme suit :
..................................................................................................................................

> int(1+x/(1+x^2+x^4), x=1..infinity)

..................................................................................................................................

Autrement dit les parenthses redondantes, fautives pour un profane, ici sont parfaitement lgales et n'ont provoqu aucune erreur. Mais la fonction intgrer,
compte tenu de la priorit suprieure de la division sur l'addition, est la fonction :

1+

x
1 + x2 + x4

et l'intgrale est donc divergente ; alors que l'utilisateur souhaitait en fait intgrer :

1+x
1 + x2 + x4
115

La premire parenthse fermante trop droite a impliqu l'erreur de fonction, sans


provoquer d'erreur de Maple.

4.4.1 Avantages et inconvnients.


Rien n'est bien compliqu dans les explications qui prcdent, l'ensemble est
cohrent et facile utiliser. Il y a cependant quelques consquences assez cocasses
qu'il faut connatre.

Warning 22  Les procdures d'analyse op, nops et type ne peuvent tre utilises
pour analyser les suites.

Reprenons par exemple notre suite seq456, et tentons d'en dterminer le nombre
d'oprandes :
..................................................................................................................................

> seq456 ;

4, 5, 6

> nops(seq456) ;
Error, wrong number (or type) of parameters in function nops

..................................................................................................................................

alors que le profane attend videmment le rsultat 3. Mais rchissez aux consquences de ce qui a t expliqu plus haut ; ce que l'utilisateur croit voir comme
un unique argument est transform par le mcanisme de prvaluation Eval-14 en
une suite trois lments 4, 5 et 6. De sorte que notre appel quivaut :
..................................................................................................................................

> nops(4, 5, 6) ;

Error, wrong number (or type) of parameters in function nops

..................................................................................................................................

qui provoque l'erreur constate, puisque la procdure nops ne doit tre appele
qu'avec un seul argument. On aurait prfr ici que notre argument volue en un
unique argument suite qui aurait donc pu tre trait de faon cohrente par la
procdure nops, mais on perdrait alors la possibilit montre plus haut de runir
en un seul argument my_options les trois arguments de la procdure plot qu'on
ne souhaite pas rpter chaque appel. Comme toujours, l'essentiel est de savoir
lucider le cas chant comment le moteur Maple va en dnitive fonctionner dans
tel ou tel cas.
Le mme phnomne va engendrer des anomalies invitables avec les procdures
op et type.
..................................................................................................................................

> op(seq456) ;

Error, wrong number (or type) of parameters in function op

..................................................................................................................................

Plus vicieux :
..................................................................................................................................

> op(seq12) ;

2
..................................................................................................................................

car :
116

..................................................................................................................................

> op(0..1, 2) ;

integer, 2

..................................................................................................................................

Il est clair maintenant que la procdure type va tre srieusement en dicult


avec les suites :
..................................................................................................................................

> type(seq456, integer) ;

Error, wrong number (or type) of parameters in function type

..................................................................................................................................

car ceci quivaut type(4, 5, 6, integer), or la procdure type ne travaille


qu'avec deux arguments. Encore plus cocasse :
..................................................................................................................................

> whattype(seq456) ;

exprseq

> type(1, exprseq) ;


Error, type `exprseq` does not exist

..................................................................................................................................

La procdure whattype examine en eet d'abord le nombre d'arguments passs.


S'il est dirent de 1, elle en dduit qu'aprs tout la suite d'arguments peut tre
considre comme. . . une suite. Sinon, elle examine le type de l'unique objet argument. Dans le mme esprit, la procdure type aurait d retourner true si l'appel
a un nombre d'arguments dirent de 2 et si le type demand est exprseq. Au lieu
de quoi, la procdure type retourne une erreur dans un tel cas ; le dfaut de cohrence est vident, le plus tonnant consistant mentir insolemment en dclarant
que le type exprseq n'existe pas, alors qu'il est d'une certaine faon le constituant
essentiel de Maple !

4.5 Listes et ensembles, n.


Le rle assez particulier des suites est maintenant couvert. Listes et ensembles
ne posent ds lors plus de problme. Ne pas se laisser impressionner par l'apparence
exotique des oprateurs liste : [. . .] et ensemble : {. . .} ; ce sont des oprateurs la
fois pr-et-post-xs, c'est tout ; les procdures correspondantes sont standard et
valuent leurs arguments avant de les utiliser :
..................................................................................................................................

> a := b ; c := d ; list2 := [{a, c}, [a, c]] ;


a := b
c := d
list2 := [{b, d}, [b, d]]

..................................................................................................................................

On voit en particulier qu'une liste ou un ensemble peut tre un lment de liste.


Supposons qu'on veuille convertir la liste list2 en un ensemble avec les mmes
lments ; la mthode style ingnieur systme consiste retirer les crochets,
autrement dit extraire les oprandes l'aide de la procdure op, puis ajouter
les accolades ncessaires pour construire l'ensmble souhait.

117

..................................................................................................................................

> set2 := {op(list2)} ;

set2 := {{b, d}, [b, d]}

..................................................................................................................................

L'application simple de ce qui a t expliqu prcdemment montre que le rsultat


doit tre atteint et c'est ce qu'on observe. Ceci dit il est sensiblement plus lisible
d'utiliser la procdure convert, capable de beaucoup de conversions, en particulier
de liste vers ensemble.
..................................................................................................................................

> set2bis := convert(list2, set) ;


set2bis := {{b, d}, [b, d]}

..................................................................................................................................

La conversion inverse peut aussi tre obtenue de l'une ou l'autre faon. Par contre
la procdure convert ne sait pas raliser les conversions vers une suite ou d'une
suite. Le second cas est logique puisqu'on buterait nouveau sur le problme
de l'argument suite dvelopp le plus souvent en plus d'un argument. On peut
supposer que pour respecter une symtrie tentante, les concepteurs Maple n'ont
pas souhait proposer la conversion inverse, qui ne poserait en fait aucun problme.
..................................................................................................................................

> convert(list2, exprseq) ;


Error, unable to convert

> convert(op(list2), list) ;


Error, wrong number (or type) of parameters in function convert

..................................................................................................................................

La deuxime conversion est dlicate grer en raison du nombre d'arguments


variable en fonction de la suite convertir ; par contre la premire est facilement
ralisable et peut tre ajoute votre environnement comme suit :
..................................................................................................................................

> `convert/exprseq` := proc(obj)


RETURN(op(obj))
end :
> convert(list2, exprseq) ;

{b, d}, [b, d]


..................................................................................................................................

car une procdure peut parfaitement retourner une suite, ce qui est souvent commode. Il est frquent que des procdures Maple de porte assez gnrale peuvent
tre tendues par l'utilisateur pour couvrir tel ou tel cas non prvu par les concepteurs Maple. On avait dj vu cette technique pour la procdure type page 77.
Le cas de la procdure convert ici est analogue. L'utilisateur peut alors dnir
une procdure `mapleproc/othercase` o mapleproc est une procdure Maple prdnie, et othercase est un symbole expliquant que si tel argument d'un appel
de mapleproc est othercase, alors l'appel doit tre trait comme expliqu dans
le corps de la procdure introduite. Pour le cas ajout exprseq de convert, on a
simplement expliqu qu'il fallait appliquer l'objet convertir la procdure op.
Noter que la prsence du slash / dans le nom de la procdure impose les backquotes encadrant le symbole, sous peine d'erreur. Il faut comprendre que le nom
de la nouvelle procdure est un peu exotique pour dissuader l'utilisateur d'utiliser
directement cette procdure ; c'est en fait faisable, mais sans intrt :

118

..................................................................................................................................

> `convert/exprseq`(list2) ;

{b, d}, [b, d]


..................................................................................................................................

On comprend maintenant pourquoi un lment de suite, liste ou ensemble ne


peut pas tre une suite ; l'exemple qui suit est une variante de ce qui a t fait plus
haut et illustre ce point :
..................................................................................................................................

> list_seq12_3_seq456 := [seq12, 3, seq456] ;


list_seq12_3_seq456 := [1, 2, 3, 4, 5, 6]

..................................................................................................................................

On a tent de construire une liste trois lments o le premier et le dernier


seraient des suites ; mais l'oprateur virgule concatne les suites, de sorte que le
rsultat est en fait une liste dont le corps est une suite six lments. C'est ce
qu'exprime entre autres le Warning-21 : un lment de suite ne peut pas tre une
suite ; puisque le corps d'une liste ou un ensemble est justement une suite, il en
est de mme aussi pour les listes et ensembles.

4.5.1 Lecture indexe des lments de suites, listes et ensembles.


Reprenons notre premire liste exercice list4.
..................................................................................................................................

> list4 := [a, b, c, d] ;

list4 := [a, b, c, d]

..................................................................................................................................

On a vu Section 4.3 comment utiliser les procdures op et nops, pour extraire un


ou plusieurs lments de listes ou ensembles.
..................................................................................................................................

> op(2, list4) ;

> op(2..3, list4) ;


b, c
..................................................................................................................................

Le mme rsultat est obtenu l'aide d'une notation indexe, sensiblement plus
lisible :
..................................................................................................................................

> list4[2] ;

> list4[2..3] ;
[b, c]

> op(2..3, list4) ;


b, c
..................................................................................................................................

On note toutefois une dirence : si l'indice est un range, l'expression indexe


retourne une sous-liste alors que l'expression utilisant la procdure op retourne une
suite, comme il se doit compte tenu de la porte trs gnrale de cette procdure.
Les indices ngatifs peuvent aussi tre utiliss, la numrotation commenant alors
119

par la n ;
..................................................................................................................................

> list4[-3] ;

> list4[-3..3] ;
[b, c]
..................................................................................................................................

Ce qui est illustr ici sur les listes s'applique exactement de la mme faon pour
les ensembles. Mais, et ceci est important, contrairement la procdure op qui est
inutilisable pour les suites, l'extraction indexe d'lments de suite travaille comme
on le souhaite.
..................................................................................................................................

> seq4 := a, b, c, d ;

seq4 := a, b, c, d

> seq4[2] ;
b

> seq4[-3..3] ;
b, c
..................................................................................................................................

4.5.2 Ecriture indexe dans une liste.


Dans le mme esprit que dans la section prcdente, on peut modier un lment de liste par une instruction d'aectation citant la rfrence de l'lment
modier.
..................................................................................................................................

> list4[2] := bb ;

> list4[-2] := cc ;
> list4 ;

list42 := bb
list42 := cc
[a, bb, cc, d]

..................................................................................................................................

Ceci n'est utilisable que pour les listes, ne fonctionne donc pas pour les ensembles
et les suites. Ne pas essayer non plus la modication de sous-liste.
..................................................................................................................................

> list4[2..3] := [bbb, ccc] ;

Error, invalid subscript on left hand side of assignment

..................................................................................................................................

Il faut toutefois tre assez mant dans ces instructions de modication de liste.
Compte tenu de ce qui vient d'tre expliqu, le pige suivant fonctionne presque
coup sr :
..................................................................................................................................

> list32 := [[a,aa], [b, bb], [c, cc]] ;


list32 := [[a, aa], [b, bb], [c, cc]]

..................................................................................................................................

Il peut se faire qu'au cours d'une session, on ait prouv la ncessit d'isoler le
deuxime lment, qui est aussi une liste (cf. Warning-21) :

120

..................................................................................................................................

> pair2 := list32[2] ;

pair2 := [b, bb]

..................................................................................................................................

puis on peut avoir une raison de modier par exemple le second lment de cette
liste :
..................................................................................................................................

> pair2[2] := bbb ;


> pair2 ;

pair22 := bbb
[b, bbb]

..................................................................................................................................

On a pris soin de vrier, par examen de la valeur de pair2 que la modication a


bien t ralise ; oui, mais :
..................................................................................................................................

> list32 ;

[[a, aa], [b, bb], [c, cc]]

..................................................................................................................................

et on voit que la valeur de list32, elle, est inchange ! Dans un exercice d'tudiant
comme ici, cette tranget est identiable, mais si un tel vnement se produit
pendant la mise au point d'un programme complexe, le bug rsultant peut tre
extrmement dicile expliquer ! Une analyse soigneuse mais dlicate coups de
procdures systme addressof, pointto et disassemble, montre que la modication
de l'lment pair2[2] modie aussi la valeur, plus prcisment l'adresse de la valeur
de pair2 ; une nouvelle liste est cre, avec les pointeurs ad hoc, mais comme au
contraire rien n'est chang pour la valeur de list32, la liste valeur de ce dernier
symbole est inchange !
Comparer avec :
..................................................................................................................................

> list32 := [[a, aa], [b, bb], [c, cc]] ;


list32 := [[a, aa], [b, bb], [c, cc]]
> pair2 := list32[2] ;
pair2 := [b, bb]
> list32[2,2] := bbb ;
list322,2 := bbb
> list32, pair2 ;
[[a, aa], [b, bbb], [c, cc]], [b, bb]

..................................................................................................................................

Cette fois c'est la sous-liste repre par pair2 qui n'est pas modie.

Warning 23  La modication d'un terme de liste ne modie que la liste explicitement indique comme devant tre modie ; les listes apparemment partages
ne sont pas modies.
Noter aussi que les deux instructions suivantes sont parfaitement quivalentes,
pour la lecture de l'lment de liste comme pour sa modication :

121

..................................................................................................................................

> list32[2, 2], list32[2][2] ;

bbb, bbb

..................................................................................................................................

Dans le registre surprises associes aux modications de listes, il faut aussi


signaler ce qui suit. Construisons une liste de 100 entiers quelconques et une autre
de 101 ; on cache le rsultat, de peu d'intrt.
..................................................................................................................................

> list100 := [0 $ 100] :


> list101 := [0 $ 101] :

..................................................................................................................................

Modions dans l'une et l'autre le premier lment :


..................................................................................................................................

> list100[1] := 1 ; list101[1] := 1 ;


list1001 := 1
Error, assigning to a long list, please use arrays

..................................................................................................................................

La modication est accepte pour la premire liste, refuse pour la deuxime. On


dduit qu'une liste est rpute longue si elle a plus de 100 lments. Ceci est a
priori surprenant, car les circonstances sont nombreuses, en simulation notamment, o on peut souhaiter faire voluer une liste, longue ou pas, pendant une
session. Il a t expliqu un peu plus haut pourquoi ces modications sont en fait
trs coteuses, vu l'implmentation adopte : chaque modication d'un lment
de liste demande la reconstruction d'une liste entire de toutes les adresses d'lments de listes ! Cette mthode trs primitive par rapport ce qui est usuel en
traitement de liste fait craindre aux concepteurs de Maple que des usages rpts
intempestifs de cette possibilit saturent rapidement la mmoire alloue Maple ;
les dits concepteurs ont donc prudemment dcid que ceci ne serait autoris que
pour les listes raisonnablement courtes ; cette dernire notion est heuristique, et
la barre a t place 100, pourquoi pas. Voir page 160 un exemple frappant pour
la comparaison de ce point de vue entre les techhniques liste et vecteur.

Warning 24  Les modications de listes Maple sont trs coteuses en mmoire ;

elles sont dconseilles ds qu'elles sont frquentes ou concernent des listes relativement longues ; elles sont de toute faon exclues si la longueur de liste est > 100.
Le cas chant, il faut prfrer, selon les circonstances, un type de donne vector
ou table.
Si la liste volutive est de longueur constante, la solution vecteur est la plus
ecace :
..................................................................................................................................

> vect100 := vector(100, [0 $ 100]) :

..................................................................................................................................

Si la liste est de longueur variable mais avec longueur maximale connue d'avance,
la mme solution est utilisable, avec des conventions appropries pour marquer les
cases en fait vides :

122

..................................................................................................................................

> vect10 := vector(10, [seq(i^2, i=1..5), nil $ 5]) ;


vect10 := [1, 4, 9, 16, 25, nil, nil, nil, nil, nil]
> for i from 6 to 8 do
vect10[i] := i^3
od :
> vect10 ; eval(vect10) ;
vect10
[1, 4, 9, 16, 25, 216, 343, 512, nil, nil]

..................................................................................................................................

etc. Voir Section 4.9.1 pour les dtails, en particulier pour comprendre pourquoi
le vecteur est ach comme une liste, mais n'est pourtant en aucune faon une
liste. Pour des situations beaucoup plus imprvisibles, il faut utiliser des tables,
voir Section 4.7.

4.5.3 La procdure subsop.


Puisque la section prcdente nous a fait toucher du doigt les dicults potentielles des problmes de modication, le moment est appropri d'tudier la procdure subsop qui, d'un certain point de vue, est un peu de la mme famille, mais
d'un autre est assez dirente. L'exemple lmentaire suivant explique le principe
de base.
..................................................................................................................................

> expr := a^2 + b^2 + c^2 ;


> op(expr) ;
> subsop(2 = bb^3, expr) ;

expr := a2 + b2 + c2
a2 , b2 , c2
a2 + bb3 + c2

..................................................................................................................................

La procdure subsop utilise deux arguments ; le premier est une quation o le


membre de gauche est un numro d'oprande modier, et le membre de droite
est le (ou les) nouvel(eaux) oprande(s) qu'on veut voir gurer en place de l'oprande dsign par son numro ; enn le second argument de subs est l'objet o
la substitution est souhaite. Ici, on a remplac le deuxime oprande (donc la
sous-expression b2) par l'expression bb3. Bien noter que ceci dcrit un procd
de construction d'un nouvel objet, mais que l'ancien est inchang :
..................................................................................................................................

> expr ;

a2 + b2 + c2

..................................................................................................................................

Dans une telle substitution, le nombre d'oprandes peut tre augment :


..................................................................................................................................

> subsop(2 = bb^2 + bbb^2, expr) ;


a2 + bb2 + bbb2 + c2

..................................................................................................................................

Une certaine cohrence peut tre ncessaire dans la substitution, sous peine d'erreur :
123

..................................................................................................................................

> subsop(2 = (bb^2, bbb^2), expr) ;


Error, invalid types in sum

..................................................................................................................................

puisqu'un terme d'une somme ne peut pas tre une suite ; ici le parenthsage de
la suite membre de droite de l'quation premier argument vitait toute confusion
sur la nature des arguments ; comparer avec :
..................................................................................................................................

> subsop(2 = bb^2, bbb^2, expr) ;

Error, wrong number (or type) of parameters in function subsop

..................................................................................................................................

puisque le non-parenthsage implique cette fois trois arguments pour l'appel de


subsop ; ceci n'est pas illgal en soi, voir la documentation pour diverses variantes
de subsop, mais ici le second argument est incorrect ; il devrait tre de la forme
integer = . . .
Par contre un terme de somme peut trs bien tre une liste :
..................................................................................................................................

> subsop(2 = [bb^2, bbb^2], expr) ;


a2 + [bb2 , bbb2 ] + c2

..................................................................................................................................

Dans certains contextes, ceci pourrait avoir un sens, par exemple dans un contexte
vectoriel.
Revenons au sujet principal de cette section, savoir les listes et ensembles. La
procdure subsop peut tre utilise pour des manipulations conduisant intercaler
ou supprimer un terme de liste ou d'ensemble, car cette fois, l'objet substituer
peut tre une suite avec un nombre quelconque d'lments.
..................................................................................................................................

> list4 := [a, b, c, d] ;

list4 := [a, b, c, d]
> subsop(2 = (b, bb, bbb), list4) ;
[a, b, bb, bbb, c, d]
> subsop(2 = NULL, list4) ;
[a, c, d]
..................................................................................................................................

On verra, voir Section


, que la procdure subs permet elle aussi de nombreuses constructions de mme nature, par description de l'objet construire
partir d'un objet dj existant modulo quelques changements.

4.6 Les constructeurs seq et $.


Cette section est assez dlicate et pour viter toute interfrence fcheuse avec
ce qui prcde, il est prfrable de remettre les compteurs zro.
..................................................................................................................................

> restart ;

..................................................................................................................................

L'importance des suites dans la structure des objets Maple commence s'imposer.
Il est donc important de disposer de constructeurs commodes pour crer des objets o les suites sont des constituants essentiels ; l'oprateur virgule permet de
124

construire les suites lment par lment, mais il serait fort pnible de construire
ainsi par exemple la suite des entiers de 1 1000. La procdure seq est idale pour
ce faire. Elle utilise une variable pilote, un symbole2 . La procdure seq ncessite
deux arguments ; le premier est un terme gnrique, un objet Maple quelconque o
gure le plus souvent la variable pilote ; le second argument est un objet equation
dont le membre de gauche doit tre la variable pilote, et le membre de droite est le
plus souvent un range, c'est--dire deux expressions qui seront values, spares
par l'oprateur ... Par exemple pour construire la suite des cubes des entiers de
10 20 on peut procder comme suit :
..................................................................................................................................

> CubeSeq := seq(i^3, i=10..20) ;


CubeSeq := 1000, 1331, 1728, 2197, 2744, 3375, 4096, 4913, 5832, 6859, 8000

..................................................................................................................................

Dans cet appel de la procdure seq, la variable pilote est le symbole i ; le terme
gnrique est l'objet Maple i3 ; le range dcrivant le domaine de variation de la
variable pilote est l'objet 10..20. Si le deuxime membre de l'quation deuxime
argument n'est pas un objet range, il est interprt d'une faon un peu dirente ;
dans un tel cas, la variable pilote va parcourir la suite des oprandes de ce second
membre. Exemple typique :
..................................................................................................................................

> seq(item^3, item = a^2 + b^2 + c^2) ;


a6 , b6 , c6

..................................................................................................................................

Considrons maintenant l'oprateur $. Il a l'air ts semblable la procdure


seq ; par exemple notre construction de suite de cubes peut tre obtenue l'aide
de l'oprateur $ comme suit :
..................................................................................................................................

> CubeSeq2 := i^3 $ i=10..20 ;


CubeSeq2 := 1000, 1331, 1728, 2197, 2744, 3375, 4096, 4913, 5832, 6859, 8000

..................................................................................................................................

On voit que les deux appels sont analogues ceci prs que pour la procdure seq,
le nom de procdure est prxe, prcdant les deux arguments parenthss, alors
que pour la procdure $, l'oprateur est inx, c'est--dire insr entre les deux
oprandes. C'est vrai, mais il y a une autre dirence beaucoup plus importante,
invisible sur notre exemple simple : le mcanisme d'valuation des arguments est
compltement dirent.

Eval 25  L'valuation d'une expression  expr1 $ expr2 procde comme suit.

L'argument expr1 est d'abord valu ; soit expr11 l'objet rsultat de l'valuation ;
l'argument expr2 est ensuite valu et le rsultat de cette valuation doit tre une
quation symb = n1..n2 o symb est un symbole, n1 et n2 sont deux entiers. Alors
l'expression expr11 est rvalue dans un contexte o le symbole symb pointe successivement vers les entiers n1, n1+1, . . ., n2. Les (n2-n1+1) rsultats successifs
sont les composants de la suite rsultat.
Construisons une procdure espion pour mettre en vidence les direntes
2 Ou

plus gnralement un nom ; autrement dit une variable indice peut aussi tre utilise,
mais ceci n'est que trs rarement utilis.

125

tapes d'une valuation.


..................................................................................................................................

> spy := proc(arg)


printf("Evaluating spy(%a)\n", arg) ;
RETURN(arg)
end :

..................................................................................................................................

La procdure spy, quand elle est appele, ache un message signalant l'appel,
permettant aussi de voir quel est l'argument dnitif 3 qui est pass ; de plus la
procdure retourne seulement cet argument.
..................................................................................................................................

> spy('message') ;

Evaluating spy(message)

message

..................................................................................................................................

Notre procdure permet donc de tracer certaines tapes du fonctionnement de


l'valuateur ; considrons par exemple :
..................................................................................................................................

> spy('spy(i^2)') $ spy(i)=spy(2)..spy(3) ;


Evaluating
Evaluating
Evaluating
Evaluating
Evaluating
Evaluating

spy(spy(i^2))
spy(i)
spy(2)
spy(3)
spy(4)
spy(9)

4, 9
..................................................................................................................................

On voit que l'valuateur a bien travaill ! Le premier spy('spy(i2)') est d'abord


valu et retourne spy(i2) ; les trois valuations suivantes construisent le second
argument de l'expression $ qui va donc tre i = 2..3. On voit ensuite que
spy(i2) est valu deux fois, la premire fois dans un environnement o [i 2],
la seconde dans un environnement o [i 3], de sorte que les arguments dnitifs
de spy sont respectivement 4 et 9. D'o le rsultat nal. La procdure $ ne
dispose pas de la mme possibilit qui avait t signale pour la procdure seq,
permettant de faire dcrire la variable pilote les oprandes d'un objet :
..................................................................................................................................

> i^2 $ i = a^2+b^2+c^2 ;

Error, wrong number (or type) of parameters in function

..................................................................................................................................

Espionnons maintenant la variante seq de l'appel sophistiqu ci-dessus de la


procdure $ :
..................................................................................................................................

> seq(spy('spy(i^2)'), spy(i) = spy(2)..spy(3)) ;


Evaluating spy(2)
Evaluating spy(3)
Error, unable to execute seq

..................................................................................................................................

On voit que Maple procde d'une faon compltement dirente. La procdure


seq n'value pas d'abord son premier argument et ce n'est donc pas une procdure
3 Voir

page 61.

126

standard : elle ne respecte pas Eval-14. On verra page


comment l'utilisateur
peut lui aussi prparer des procdures non standard. La procdure seq commence
par vrier que le deuxime argument est une quation, sans quoi elle arrte immdiatement.
..................................................................................................................................

> seq(spy(a), spy(b)) ;

Error, wrong number (or type) of parameters in function seq

..................................................................................................................................

Si par contre le second argument est une quation, la procdure seq value d'abord
son second membre, puis vrie que le premier est un symbole4 , sinon erreur :
..................................................................................................................................

> seq(spy(a), spy(b) = spy(c)) ;


Evaluating spy(c)
Error, unable to execute seq

..................................................................................................................................

C'est ce qui avait provoqu l'erreur dans l'exemple initial, car :


..................................................................................................................................

> type('spy(i)', name) ;

false

..................................................................................................................................

Noter la ncessit de quoter le premier argument car la procdure type au contraire


est standard et value donc ses arguments avant de les utiliser :
..................................................................................................................................

> type(spy(i), name) ;


Evaluating spy(i)

true

..................................................................................................................................

Comme spy(i) est valu, l'argument dnitif est cette fois le symbole i qui est
bien un objet name ! L'exprience suivante ne peut tre que :
..................................................................................................................................

> seq(spy('spy(i^2)'), i = spy(2)..spy(3)) ;


Evaluating
Evaluating
Evaluating
Evaluating

spy(2)
spy(3)
spy(spy(i^2))
spy(spy(i^2))

spy(i2 ), spy(i2 )

..................................................................................................................................

Encore une surprise, mais facile expliquer. Une fois que le second argument de seq
est valu, le premier est donc maintenant, et maintenant seulement, valu deux
fois, une fois dans un environnement o [i 2], une autre fois avec [i 3].
Mais puisque l'unique occurence du symbole i est entre quotes, ces valeurs de i
sont inutilises. L'argument dnitif de spy est l'expression spy(i2), qui ne sera
plus rvalue, d'o le rsultat sous forme de deux exemplaires de cette expression,
un pour chaque valeur de i demande. La dernire exprience est donc :
4 Plus

gnralement un objet name.

127

..................................................................................................................................

> seq(spy(i^2), i = spy(2..3)) ;


Evaluating spy(2..3)
Evaluating spy(4)
Evaluating spy(9)

4, 9
..................................................................................................................................

qui nous donne la chronologie parfaite des valuations ralises.

Eval 26  Un appel seq(expr1, symb=expr2) est valu comme suit. L'objet

expr2 est d'abord valu, soit expr22 l'objet retourn par l'valuateur ; le domaine
que doit parcourir la variable pilote symb est la suite des oprandes de expr22,

moins que cet objet soit un objet range auquel cas le domaine sera l'ensemble
des entiers dcrit par ce range. Ensuite l'objet expr1 est valu autant de fois que
ncessaire dans un environnement o le symbole symb pointe successivement vers
les dirents lments du domaine dduit de expr22. Le rsultat de l'valuation
sera la suite des rsultats d'valuation obtenus.

Conseil 27  D'une faon gnrale, la procdure seq est sensiblement plus adapte la construction des suites que l'oprateur  $.

Pour illustrer ce conseil, considrons l'exemple prototype suivant. Soit


construire une suite de 10 entiers alatoires du range 1..100. Pour construire un
tel entier, on peut appeler la procdure rand :
..................................................................................................................................

> rand(1..100)() ;

82
..................................................................................................................................

L'appel rand(1..100) construit un gnrateur d'entiers alatoires, sans argument,


qu'on appelle donc par rand(1..100)().
Puisqu'on s'apprte appeler de faon rptitive la procdure construite par
rand(1..100), il est bien prfrable de la crer une fois pour toutes et de l'aecter
un symbole appropri. Pour des exercices d'tudiants comme ici, ce point est relativement secondaire, mais si vous comptez un jour faire de vrais calculs avec Maple,
notamment de vraies simulations avec de vastes gnrations de nombres alatoires,
cette prcaution peut tre capitale et il n'est jamais trop tt pour acqurir le bon
rexe. On refait donc l'exemple prcdent comme suit :
..................................................................................................................................

> rnd100 := rand(1..100) ;


rnd100 := proc()
local t; global _seed;
_seed := irem(427419669081 _seed, 999999999989);
t := _seed;
irem(t, 100) + 1
> rnd100() ;

end

71
..................................................................................................................................

Pour une fois, on a montr le rsultat procdure5 pour mettre en vidence que la
5 Habituellement

ach sur une ligne dans une fentre 17.

128

procdure rand retourne eectivement une procdure.


Si donc on veut rpter dix fois cet appel pour obtenir une suite de dix entiers
alatoires, avec l'oprateur $, on procde a priori comme suit :
..................................................................................................................................

> rnd100() $ i=1..10 ;

64, 64, 64, 64, 64, 64, 64, 64, 64, 64


..................................................................................................................................

Ce n'est pas du tout le rsultat souhait ! On voit ici que le luxe de dtails prcdemment donns dans cette section est loin d'tre superu. L'expression rnd100()
est d'abord value, choisit donc un nombre alatoire, ici 64 ; c'est l'objet not
expr11 dans Eval-25. Puis le deuxime oprande de l'expression $ est trait. Le
rsultat de la premire valuation, donc l'entier 64, est alors valu autant de fois
que ncessaire, donc 10 fois, dans un environnement o le symbole i pointe vers
1, puis vers 2, etc. Mais quel que soit l'environnement, le rsultat de l'valuation
de 64 est 64, d'o notre rsultat. Comparer avec ce qui est obtenu naturellement
avec la procdure seq :
..................................................................................................................................

> seq(rnd100(), i=1..10) ;

77, 39, 86, 69, 22, 10, 56, 64, 58, 61


..................................................................................................................................

Car cette fois le terme gnrique n'est valu qu'une fois pour chacune des valeurs
de i souhaites, valeurs qui ne jouent d'ailleurs aucun rle en elles-mmes. On
obtiendrait un rsultat analogue avec l'oprateur $ en interdisant la premire
valuation :
..................................................................................................................................

> 'rand(1..100)()' $ 'i'=1..10 ;


75, 86, 17, 62, 8, 50, 87, 99, 67, 10

..................................................................................................................................

mais cette technique est ranger dans les dirty tricks.


Les seuls cas o l'oprateur $ est franchement commode sont les suivants.
Pour la rptition simple d'un objet, on n'est pas en fait tenu de prvoir une
variable pilote :
..................................................................................................................................

> a $ 5 ;

a, a, a, a, a
..................................................................................................................................

On aurait donc pu crer notre suite d'entiers alatoires comme suit :


..................................................................................................................................

> 'rnd100()' $ 10 ;

74, 82, 75, 67, 74, 43, 92, 94, 1, 12


..................................................................................................................................

Puisque chaque valuation de rnd100() retourne un nouvel entier alatoire, la suite


obtenue dans ce cas n'est pas constante, mais c'est justement ce qui est souhait !
Un autre cas, plus rare, est aussi intressant :
..................................................................................................................................

> $ 5..10 ;

5, 6, 7, 8, 9, 10
..................................................................................................................................

129

Noter aussi la dicult dj signale page 58 ; comparer :


..................................................................................................................................

> for i from 1 to 3 do print(i) od ;

1
2
3

> i^2 $ i = 1..10 ;


Error, wrong number (or type) of parameters in function \boxtt{\$}

> seq(i^2, i=1..10) ;

1, 4, 9, 16, 25, 36, 49, 64, 81, 100


..................................................................................................................................

On avait expliqu page 58 que l'instruction itrative for laisse le symbole i pointant
vers 4, d'o l'erreur dans l'instruction $ car la variable pilote y est value, alors
qu'au contraire l'appel de seq produit le rsultat escompt, car la variable pilote
n'y est jamais value. Ceci fonctionne :
..................................................................................................................................

> 'i^2' $ 'i' = 1..10 ;

1, 4, 9, 16, 25, 36, 49, 64, 81, 100


..................................................................................................................................

mais c'est dtestable et propice bien des erreurs dans des situations plus complexes.

4.7 Tables.
La structure d'une table est assez dirente de ce qui a t expliqu pour les
suites, listes et ensembles. Dans le cas le plus gnral il s'agit en langage informatique d'un chier accs direct ; les articles sont des objets Maple quelconques, et
chaque article est accessible par une cl, un autre objet Maple lui aussi quelconque.
D'habitude, on appelle plutt indice ce qui est de fait une cl d'accs. Exemple
articiel :
..................................................................................................................................

> table4 := table([1=a, 2=b, 3=c, 4=d]) ;


table4 := table([
1=a
2=b
3=c
4=d
])

..................................................................................................................................

Cette table a quatre articles (entries en jargon Maple), savoir les symboles a, b,
c et d. Chacun est accessible par sa cl (indice ), respectivement 1, 2, 3 et 4. Noter
que, contrairement ce qui est frquemment prvu dans les systmes de traitement
de chiers, la cl n'est pas une partie de l'article : les objets correspondants, article
et cl, sont disjoints, conceptuellement et aussi en machine.
Pour voir l'intgralit par exemple d'une liste qui serait pointe par le symbole
list3, il sut d'valuer le symbole list3 :
130

..................................................................................................................................

> list3 := [aa, bb, cc] ;


> list3 ;

list3 := [aa, bb, cc]


[aa, bb, cc]

..................................................................................................................................

On ne peut demander de la mme faon le contenu d'une table pointe par un


symbole ; par exemple si on tente de voir le contenu de notre table repre par le
symbole table4 :
..................................................................................................................................

> table4 ;

table4

..................................................................................................................................

L'explication vient de la rgle Eval-16 : un chanage [symbol table] n'est utilis


que dans une valuation explicite, donc seulement si le symbole est en position
oprateur, ou encore si on demande explicitement l'valuation par l'intermdiaire
de la procdure eval :
..................................................................................................................................

> eval(table4) ;
table([
1=a
2=b
3=c
4=d
])

..................................................................................................................................

Les oprations fondamentales de traitements de chiers sont :


1. Lecture d'un article, tant donn sa cl ;
2. Modication, on dit plutt mise--jour, d'un article, tant donn sa cl et le
nouvel article installer la place de l'ancien ;
3. Suppression d'un article, tant donn sa cl ;
4. Ajout d'un article tant donn le nouvel article installer, et la cl qui
permettra d'y accder ; la terminologie standard traitement de chier appelle
ceci une criture.
Il va donc falloir nous intresser aux mthodes, en fait assez simples, qui permettent de raliser ces quatre oprations.

4.7.1 Lecture d'un article.


On lit un article de table en indexant la table par la cl de l'article cherch.
..................................................................................................................................

> table4[2] ;

b
..................................................................................................................................

Il est lgal de citer une cl inexistante, auquel cas l'objet retourn est aussi un
objet index, type indexed :

131

..................................................................................................................................

> table4[55] ;

> type(%, indexed) ;

table455
true

..................................................................................................................................

Ceci fonctionne mme si l'oprateur n'value pas vers une table. Exemple articiel
pour expliquer le mcanisme :
..................................................................................................................................

> a := b ;

a := b

> a[a+4] ;
bb+4

> eval(b) ;
b
..................................................................................................................................

On voit que dans la deuxime instruction, l'oprateur a et l'indice a+4 ont t


valus. Le rsultat est l'objet de type indexed b[b+4] (en notation input). Cet
objet retourn n'implique pas la cration d'une table repre par b comme le
dmontre la dernire instruction.
Une table peut donc tre considre comme une extension de l'environnement.
Ainsi la table repre par le symbole table4 peut tre vue comme un ensemble
de quatre chanages [table4[1] a], [table4[2] b], etc. De ce point de
vue, si un indice comme 55 est absent de la table, on peut penser que le nom
table4[55] est absent de l'environnement, auquel cas le mcanisme d'valuation
triviale expliqu Eval-7 s'applique, le nom est retourn tel quel.
Comparer avec :
..................................................................................................................................

> list4 := [a, b, c, d] ;

[a, b, c, d]

> list4[55] ;
Error, invalid subscript selector

..................................................................................................................................

On verra cependant que pour les tableaux, et donc en particulier pour les matrices
et les vecteurs, il est ncessaire de choisir la cration du tableau l'ensemble
des indices valides ; si un indice non valide est ensuite utilis, il entrane alors
logiquement une erreur. Ce point sera rediscut Section
.

4.7.2 Modication ou ajout d'un article.


Ces deux oprations sont traites de la mme faon, par une instruction d'affectation, citant la rfrence modier ou ajouter. Par exemple on peut modier
l'article associ la cl 3 :

132

..................................................................................................................................

> table4[3] := cc ;

table43 := cc

> eval(table4) ;
table([
1=a
2=b
3 = cc
4=d
])
..................................................................................................................................

L'achage des tables entires est un peu envahissant, et on prfrera dsormais


examiner plutt le ou les seuls lments qui nous intressent, justement par une
opration de lecture :
..................................................................................................................................

> table4[3] ;

cc

..................................................................................................................................

crivons, c'est--dire ajoutons, un lment de cl 5 :


..................................................................................................................................

> table4[5] := `fifth element` ;


table45 := fth element

..................................................................................................................................

Le symbole pointant notre table n'a pas chang, mais notre table a maintenant
5 lments ; l'article ajout est un symbole exotique, cause du caractre espace y gurant, et a ncessit les backquotes d'encadrement. Les nouvelles cls
ajoutes peuvent tre des objets Maple quelconques, idem pour les articles ajouts.
..................................................................................................................................

> table4[55] := 5 &+ 11 ;

table455 := 5 &+ 11
..................................................................................................................................

Ici l'article ajout est une expression utilisant un oprateur inx non prdni ;
voir ce sujet la page de documentation intitule neutral.
Rien n'empche un article d'tre une suite :
..................................................................................................................................

> table4[x^2+y^2] := 1, 2, 3 ;

table4 2
:= 1, 2, 3
x + y2
..................................................................................................................................

Une cl peut aussi tre une suite :


..................................................................................................................................

> table4[1, 2, 3] := {4, 5, 6, 7} ;


table41,2,3 := {4, 5, 6, 7}

..................................................................................................................................

Notre table est maintenant un objet auquel on serait bien en peine de donner
un sens raisonnable, mais ceci est sans importance pour Maple.

133

..................................................................................................................................

> eval(table4) ;
table([
x2 + y 2 = (1, 2, 3)
1=a
2=b
3 = cc
4=d
5 = fth element
55 = 5 &+ 11
(1, 2, 3) = {4, 5, 6, 7}
])
> table4[table4[y^2+x^2]] ;

{4, 5, 6, 7}
..................................................................................................................................

Bref, on voit que cls et articles peuvent tre des objets absolument quelconques,
et que les oprations usuelles de comparaison sont utilises pour identication ; en
particulier la rfrence de cl x2+y2 est synonyme de y2+x2.

4.7.3 Suppression d'un article.


La suppression d'un article d'une table est apparente au retrait d'un symbole
de l'environnement ; elle est eectue exactement de la mme faon. Deux mthodes
sont donc possibles ; la premire consiste demander une auto-aectation :
..................................................................................................................................

> table4[3] := 'table4[3]' ;

table43 := table43

> assigned(table4[3]) ;
f alse
..................................................................................................................................

La deuxime mthode, sensiblement plus lisible, consiste utiliser la procdure


unassign ; il faut cependant faire attention l'valuation de son argument ; presque
toujours il doit tre quot justement pour empcher cette valuation.
..................................................................................................................................

> unassign('table4[1]') ; assigned(table4[1]) ;


f alse

..................................................................................................................................

4.7.4 Questions subtiles d'valuation autour des objets indexs.


Repartons de zro et crons une petite table en vue de quelques expriences.

134

..................................................................................................................................

> restart ; a := table([11, 22, 33, 44, 55]) ;


a := table([
1 = 11
2 = 22
3 = 33
4 = 44
5 = 55
])

..................................................................................................................................

On observe au passage que si on ne prsente pas l'argument de la procdure table


sous forme d'une liste d'quations, la procdure considre alors que la liste ne
contient que les lments (entries) de la table, et elle aecte d'oce des indices
entiers en partant de 1. On vous laisse exprimenter ce qui advient si la liste
contient des quations et d'autres objets qui ne sont pas des quations.
Il peut arriver alors qu'une variable disons n ait pour valeur un entier indice
de notre table et qu'on veuille modier l'lment ayant cet indice. Observons trs
attentivement l'aectation suivante :
..................................................................................................................................

> n := 3 ; a[n] := n^2 ;

n := 3
a3 := 9

..................................................................................................................................

On voit que le comportement de l'valuateur est ici assez n : quand il traite


l'objet qu'il s'agit d'aecter, il constate que c'est un objet index ; il dcide alors
d'valuer l'indice, transformant ici n en 3, et l'lment de table aecter est donc
en dnitive a[3] ; bien noter qu'au contraire il n'value pas a[3] qui produirait
33, mais une aectation 33, un entier, n'aurait pas de sens. Dans le mme esprit :
..................................................................................................................................

> a[n^2-n-2] := 444 ; a[4] ;

a4 := 444
444

> a[a[n+1]/111] := 555 ;


a4 := 555
..................................................................................................................................

Autrement dit, comme il l'avait dj t observ page 71, il n'y a pas d'valuation
au niveau suprieur dans le membre de gauche d'une instruction d'aectation, par
contre toute valuation un niveau infrieur, typiquement d'un indice, est eectue
pour dterminer quel est l'objet source du chanage installer ou modier.
Moyennant quoi vous pouvez comprendre l'exemple articiel suivant.

135

..................................................................................................................................

> b[1] := 11 ; n := 1 ; b[n] := 111 ; b['n'] := nn ; eval(b) ;


b1 := 11
n := 1
b1 := 111
bn := nn
table([
1 = 111
n = nn
])

..................................................................................................................................

Il a fallu en eet quoter le symbole n en indice pour empcher son valuation an
de crer un lment d'indice n.
Dans le mme registre la libration d'un lment de table indice calcul va
poser problme. Supposons qu'on veuille librer l'lment de la table a dont l'indice
est la valeur de n. Ceci ne fonctionne pas :
..................................................................................................................................

> a[n] := a[n] ;

a1 := 11
..................................................................................................................................

En eet le terme de gauche de l'instruction d'aectation devient comme on le


souhaite a[1], car n est valu ; mais le terme de droite est lui entirement valu
produisant la valeur de a[1], savoir 11 et notre aectation ne sert rien, elle ne
fait que rpter la situation dj existante !
Ceci ne fonctionne pas non plus :
..................................................................................................................................

> a[n] := 'a[n]' ;

a1 := an

> a[1] ;
Error, too many levels of recursion

> eval(a[1], 1) ;

an
..................................................................................................................................

car on voit qu'on a cette fois trop empch l'valuation du terme de droite de
l'aectation ; ce n'est donc pas une auto-aectation qui est demande, de sorte
que Maple installe un chanage de a[1] vers a[n]. Provoquant ainsi quand on demande la valeur de a[1] une erreur amusante, consquence curieuse du mcanisme
de post-valuation, voir la rgle Eval-13 : la valeur de a[1] est a[n], oui, mais
n a pour valeur 1, donc l'valuateur obtient a[1], oui, mais a[1] a pour valeur
a[n], etc. Comme toujours, eval(..., 1) permet de demander une seule phase
d'valuation.
Et on voit qu'on est en panne pour demander l'auto-aectation souhaite !
Il faut en fait utiliser ici unassign ; on semble pourtant buter a priori sur les
mmes dicults. En particulier unassign(a[n]) va provoquer la mme erreur de
rcursisivit indnie :

136

..................................................................................................................................

> unassign(a[n]) ;

Error, too many levels of recursion

..................................................................................................................................

Et le lecteur lucide pense probablement ici que unassign('a[n]') ne fonctionne


pas non plus car on demande semble-t-il ainsi la libration de a[n] et c'est en
fait celle de a[1] qui est voulue. Oui, mais ici la procdure unassign nous aide
bigrement car elle dispose d'un traitement trs sophistiqu des objets indics6 ; si
l'argument dnitif est un objet indic, la procdure value encore l'indice donn
avant de raliser la libration. Preuve :
..................................................................................................................................

> eval(a[1], 1) ;

an

> unassign('a[n]') ;
> assigned(a[1]) ;

false

..................................................................................................................................

4.7.5 Indices et lments d'une table.


On peut obtenir la suite des cls (resp. articles) actuels d'une table par appel
de la procdure indices (resp. entries) :
..................................................................................................................................

> restart ; a := table([b, c, d]) ;


a := table([
1=b
2=c
3=d
])
> indices(a) ; entries(a) ;

[1], [2], [3]


[b], [c], [d]
..................................................................................................................................

On voit que chaque cl, chaque article, est encadr entre crochets. Cette notation
assez lourde pour le rsultat est ncessaire pour lever l'ambigut qui pourrait
rsulter du Warning-21 : un lement de table, contrairement ce qui a t expliqu
pour les suites, listes et ensembles, peut tre une suite. Un indice de table peut aussi
tre une suite, auquel cas il devient essentiellement un multi-indice. Procdons aux
expriences rituelles pour examiner ces points.
6 Par

l'intermdiaire de la procdure souterraine unassign/indexed

137

..................................................................................................................................

> a[1,2,3] := e ;

> a[f] := 4, 5, 6 ;

a1, 2, 3 := e
af := 4, 5, 6

> indices(a) ; entries(a) ;


[1, 2, 3], [1], [2], [3], [f ]
[e], [b], [c], [d], [4, 5, 6]
..................................................................................................................................

On voit que sans les crochets dlimitant les multi-indices ou les lments suites,
on serait incapable d'interprter correctement les rsultats.
Dans le mme ordre d'ides, si on initialise une table avec des quations index
= entry, quand un indice est multiple, il doit tre parenths, pour lever le mme
genre d'ambigut.
..................................................................................................................................

> restart ; a := table([1, 2 = 3, 4]) ;


a := table([
1=1
2 = (2 = 3)
3=4
])

..................................................................................................................................

Ici la liste a trois arguments dont deux ne sont pas des quations ; Maple dcide
donc l'aectation automatique des cls ; en particulier l'lment de cl 2 est l'quation 2 = 3 ; la concidence cl et premier membre de l'article est considrer
comme fortuite. Comparer avec les trois autres cas complmentaires.
..................................................................................................................................

> restart ; a := table([(1, 2) = 3, 4]) ;


a := table([
1 = ((1, 2) = 3)
2=4
])
> restart ; a := table([1, 2 = (3, 4)]) ;
a := table([
1=1
2 = (2 = (3, 4))
])
> restart ; a := table([(1, 2) = (3, 4)]) ;
a := table([
(1, 2) = (3, 4)
])
> a[1,2] ;
3, 4

..................................................................................................................................

Rien n'empche dans une table que certains indices soient multiples et d'autres
non, comme il l'avait dj t constat plus haut quand on examinait les rsultats
de la procdure indices.

138

Le lecteur peut aussi tre troubl s'il compare les valuations :


..................................................................................................................................

> 1, 2 = 3, 4, 5 ;

1, 2 = 3, 4, 5

> 1, 2 = (3, 4), 5 ;


1, 2 = (3, 4), 5

> 1, 2 = 3, (4, 5) ;
1, 2 = 3, 4, 5

> nops([%%]), nops([%]) ;


3, 4
..................................................................................................................................

Si on est imprcis, on peut ne pas comprendre pourquoi l'valuateur garde bien


la suite (3, 4) dans le deuxime cas, et qu'au contraire il ne garde pas la suite
(4, 5) dans le troisime. Il faut ici penser au travail du lecteur Maple. Dans
le deuxime cas, quand le lecteur entame la lecture du deuxime lment de liste,
il lit successivement l'entier 2, le signe = et l'objet est donc une quation, car
l'oprateur-sic = est en fait un constructeur, qui construit une quation qui
restera certainement telle, et enn la lecture du second membre commence par
une parenthse ; Maple sait qu'il n'aura termin le traitement du second membre
que quand il aura trouv la parenthse fermante correspondante ; en dnitive le
second lment de liste est donc une quation dont le second membre est une liste,
et le traitement du deuxime argument est ainsi dnitivement termin.
Dans le dernier cas, ce qui semble tre le troisime argument est dvelopp en
une suite qui est donc concatne par la deuxime virgule aux deux arguments
prcdents, produisant ainsi une suite de quatre arguments ; la liste construite est
donc de longueur 4. Noter qu'on ne peut pas demander directement la longueur
d'une suite, d'o la ncessit des crochets encadrant les symboles %% et % pour
dterminer la longueur des deux derniers rsultats.

4.8 Tableaux.
Les tableaux sont des tables particulires. Elles ont deux particularits :
1. L'ensemble des indices possibles pour leurs lments est dni une fois pour
toutes la cration du tableau ;
2. L'ensemble des indices possibles doit tre un produit cartsien d'intervalles
d'entiers :
[i1 . .j1 ] . . . [id . .jd ].
L'entier d est la dimension du tableau ; c'est un entier strictement positif.
Chaque indice est donc une suite d'entiers k1, ..., kd qu'on considre habituellement plutt comme un multi-indice ; mais en plusieurs circonstances, le seul
point de vue qui, strictement parlant, soit correct est selui-ci : l'unique indice est
une suite de d entiers.
Soit par exemple crer un tableau o la suite d'indices possible est le produit
[0. .4] [0. .4]. La procdure array peut tre utilise comme suit, et le tableau
139

rsultat est aect au symbole m5.


..................................................................................................................................

> m5 := array(0..4, 0..4) ;

m5 := array(0..4, 0..4, [ ])

..................................................................................................................................

Le tableau tant ainsi cr, ses lments peuvent maintenant tre aects, modis
ou supprims comme pour les tables, la condition expresse de ne citer qu'un indice
autoris, donc ici une suite de deux entiers du domaine 0..4. On peut par exemple
souhaiter installer dans m5[i,j] le produit modulo 5 des deux indices i et j, pour
obtenir la table de multiplication des entiers modulo 5 :
..................................................................................................................................

> for i from 0 to 4 do


for j from 0 to 4 do
m5[i, j] := (i * j) mod 5
od
od ;

..................................................................................................................................

Aucun achage n'apparat l'cran ; ceci est d au fait que deux instructions for
sont embotes, et Maple juge que la profondeur de travail est alors trop importante
pour justier un achage qui risquerait d'tre un peu envahissant7 . La table m5
peut maintenant tre utilise pour obtenir un produit modulo 5 particulier.
..................................................................................................................................

> m5[2,4] ;

3
..................................................................................................................................

Quand un lment de tableau n'est pas dni, le mcanisme d'valuation triviale


s'applique comme toujours. Supposons qu'on construise une table analogue la
prcdente modulo 6, mais qu'on oublie de corriger les domaines de variation de i
et j :
..................................................................................................................................

> m6 := array(0..5, 0..5) ;

m6 := array(0..5, 0..5, [ ])
> for i from 0 to 4 do
for j from 0 to 4 do
m6[i, j] := (i * j) mod 6
od
od ;

..................................................................................................................................

L'utilisation de notre table pour retrouver le produit modulo 6 de 3 et 5 donne


alors le rsultat suivant :
..................................................................................................................................

> m6[3,4], m6[3,5] ;

0, m63,5
..................................................................................................................................

Mais toute tentative de citer un indice illgal sera sanctionne par un message
d'erreur assez clair.
7 Ce

point peut tre modi par l'utilisateur l'aide de la variable printlevel, voir la page
de documentation correspondante.

140

..................................................................................................................................

> m6[3, 6] ;

Error, 2nd index, 6, larger than upper array bound 5

..................................................................................................................................

La notion d'indice illgal peut d'ailleurs tre assez subtile ; examinez ceci :
..................................................................................................................................

> expr := m6[3,t] ;

m63,t

> t := 4 : expr ;
0

> t := 6 : expr ;
Error, 2nd index, 6, larger than upper array bound 5

..................................................................................................................................

Le bon point de vue est le suivant : l'indice t peut tre ou non lgal selon
sa valeur, et dans le doute, Maple accepte l'indice. Si par la suite, on aecte au
symbole t la valeur 4 (lgale) ou 6 (illgale), l'valuation de expr est correcte ou
non.

4.8.1 Cration-Initialisation.
On peut initialiser directement tout ou partie des lments d'un tableau la
cration en prvoyant en plus une liste d'initialisation. Soit crer un tableau des
cubes des entiers compris entre 10 et 20 :
..................................................................................................................................

> cubes := array(10..20, [seq(i^3, i=10..20)]) :


> cubes[15] ;
3375

..................................................................................................................................

On voit ici que le mcanisme permettant de crer facilement, l'aide de la procdure seq, une suite d'lments itrative permet une initialisation confortable et
lisible. On peut critiquer le choix du symbole pluriel cubes, l'origine de l'appel
cubes[15], incohrent, puisqu'on ne demande qu'un seul cube ! mais si on choisit le
singulier, c'est la dsignation de la table elle-mme avec un singulier qui est alors
critiquable. Le perfectionniste en choix de symboles peut demander :
..................................................................................................................................

> cube := cubes ;

cube := cubes

> cube[16] ;
4096
..................................................................................................................................

Le profane peut penser ici que l'aectation du symbole cubes au symbole cube a
transmis aussi de faon souterraine la table sous-jacente valeur de cubes, comme
semble l'indiquer l'valuation qui suit. Cette interprtation est incorrecte ; quand
Maple lit l'expression valuer, il trouve une expression indexe, o, avant de faire
travailler le mcanisme de lecture de table, il value l'expression racine, ici cube ;
il trouve le symbole cubes et c'est donc partir de ce symbole qu'il cherchera
l'lment de table demand. D'une certaine faon, l'expression cube[16] est une
expression deux arguments, le premier le symbole cube, le second l'entier 16 ;
141

l'valuation implicite de cube produit cubes et puisqu'il s'agit d'une expression


indexe, Maple va examiner si la valeur du symbole cubes est une table, d'o le
rsultat. Voir aussi :
..................................................................................................................................

> cubes := cubes ;

cubes := cubes

> cube[16] ;

cubes16
..................................................................................................................................

C'est ici un cas trs curieux qui semble contredire ce qui avait t expliqu page 53.
Dans l'instruction d'aectation cubes := cubes, l'valuation du second membre
est implicite et la valeur du symbole cubes tant une table, c'est seulement le symbole cubes qui est retourn, cause de la rgle Eval-16. Ensuite, l'aectation de
ce symbole lui-mme est interprte par Maple comme une demande de libration du symbole, voir page 53. Donc ici le symbole cubes est libr. Comme cube
chane toujours vers cubes, l'valuation de cube[16] provoque l'valuation de cube
vers cubes, mais puisque cette fois le symbole est libre, le mcanisme d'valuation
triviale s'applique et l'expression cubes[16] est en dnitive retourne.
On rediscutera ces questions quand on examinera les problmes assez subtils lis
aux changes de valeurs entre procdures et monde extrieur. Notez ds prsent
que des bugs subtils et trs coriaces lucider en sont souvent la consquence si
on ne procde pas de faon prcise en la matire.
Pour en terminer avec l'initialisation des tableaux, il faut aussi signaler que si
un tableau a une dimension multiple, il faut l'initialiser avec une liste de listes de
listes. . . avec la profondeur ad hoc.
..................................................................................................................................

> sample := array(0..1, 0..2, [[4, 5, 6], [7, 8, 9]]) :


> sample[0, 2], sample[1, 1] ;
6, 8

..................................................................................................................................

4.9 Vecteurs et matrices.


Les vecteurs et matrices sont des tableaux particuliers, et puisque les tableaux
sont des tables particulires, les vecteurs et les matrices sont donc aussi des tables
particulires. Les subtilits base d'valuations implicites et explicites vont dont
tre rencontres ; elles demandent la plus grande prcision, sous peine de bugs assez
diciles.

4.9.1 Vecteurs.
Un vecteur est un tableau de dimension 1 o l'ensemble des indices est un range
1..n pour un entier positif n :

142

..................................................................................................................................

> A := array(0..2, [4,5,6]) ; V := array(1..3, [4,5,6]) ;


A := array(0 .. 2[
(0) = 4
(1) = 5
(2) = 6
])
V := [4, 5, 6]

..................................................................................................................................

Les formes internes des deux objets construits sont pratiquement les mmes ; pour
A, l'indice varie de 0 2, alors que pour V il varie de 1 3. Mais ceci sut faire
de la valeur de V un vecteur, alors que la valeur de A n'est pas un vecteur :
..................................................................................................................................

> type(A, vector), type(V, vector) ;


f alse, true

..................................................................................................................................

Le lecteur (trs-trs) attentif doit ici tre surpris qu'on n'ait pas prfr :
..................................................................................................................................

> type(eval(A), vector), type(eval(V), vector) ;


f alse, true

..................................................................................................................................

car en principe une valuation explicite est ncessaire pour atteindre les valeurs
tableaux ; oui, mais la procdure type applique elle-mme l'valuation explicite au
premier argument si le type dsign au second demande une telle valuation pour
atteindre l'un de ses lments, ce qui nous dispense dans ce cas, et dans ce cas
seulement, de l'application de la procdure eval. Comparer avec :
..................................................................................................................................

> type(A, symbol), type(V, symbol) ;


true, true

..................................................................................................................................

o cette fois, puisque le type propos est symbol, seule une valuation implicite
est eectue !
Un vecteur est ach comme une liste mais n'est en aucune faon une liste :
..................................................................................................................................

> L := [4,5,6] ;

[4, 5, 6]
> type(L, list), type(L, symbol), type(L, vector),
type(V, list), type(eval(V), list) ;
true, f alse, f alse, f alse, f alse
..................................................................................................................................

Cette fois, pour une liste, mme l'valuation implicite du symbole L a retourn
la liste, et c'est pourquoi type(L, symbol) rpond ngativement ; l'valuation implicite ou explicite de V ne donne pas une liste, elle retourne respectivement un
symbole ou un vecteur.

143

4.9.2 Matrices.
La situation est trs analogue pour les matrices. Une matrice est un tableau de
dimension 2 dont les domaines de variation des indices commencent par 1.
..................................................................................................................................

> T1 := array(0..4, 1..6) ;


M := array(1..4, 1..6) ;
T2 := array(1..4, 2..6) ;

T1 := array(0..4, 1..6, [])


M := array(1..4, 1..6, [])
T2 := array(1..4, 2..6, [])

..................................................................................................................................

De ces trois tableaux du mme style, seul le deuxime est une matrice.
..................................................................................................................................

> type(T1, matrix), type(M, matrix), type(T2, matrix) ;


false, true, false

..................................................................................................................................

De nombreuses mthodes8 adaptes aux nombreux cas de gure de dnitions


de matrices sont disponibles pour initialiser les matrices. On les examinera plus
tard dans ce texte au gr des besoins pour nos nombreux exemples de calculs
matriciels. Juste pour donner une petite ide de ce qui est possible, soit construire
la matrice 33 dont la premire ligne est 1, 2, 3, la seconde 4, 5, 6, et la dernire 7,
8, 9. Le plus commode pour un tel cas consiste initialiser la matrice construire
l'aide d'une seule liste, constitu des lments de matrice lus l'occidentale, de
gauche droite puis de haut en bas.
..................................................................................................................................

> M := matrix(3,3, [seq(i, i=1..9)]) ;

1 2
M := 4 5
7 8

3
6
9

..................................................................................................................................

L aussi, Maple vous facilite la vie en choisissant un achage beaucoup plus


clair, celui gnralement utilis par les mathmaticiens pour les matrices. Comparer
les deux tableaux :
..................................................................................................................................

> T1 := array(0..1, 1..2, [[1, 2], [3, 4]]) ;


T2 := array(1..2, 1..2, [[1, 2], [3, 4]]) ;
T1 := table([
(0, 1) = 1
(0, 2) = 2
(1, 1) = 3
(1, 2) = 4
])

1 2
T2 :=
3 4

..................................................................................................................................

T2 est une matrice et est ache comme telle, alors que le domaine de variation
du premier indice de T1 exclut que T1 soit une matrice ; l'achage de T1 est donc
8 Voir

notamment matrix, entermatrix et randmatrix.

144

l'achage trs gnral, moins confortable, des tables.


Un package assez vaste appel linalg (linear algebra) donne l'utilisateur les
moyens les plus vidents de calcul matriciel. Chargeons-le dans notre environnement.
..................................................................................................................................

> with(linalg)

Warning, new definition for norm


Warning, new definition for trace

[BlockDiagonal, GramSchmidt, . . .
... ... ...
vecpotent, vectdim, vector, wronskian]

..................................................................................................................................

On n'a pas montr ici la liste complte des 114 procdures constituant ce
package. Tous les grands sujets classiques du calcul matriciel y sont traits. Par
exemple le dterminant de notre matrice M est nul :
..................................................................................................................................

> det(M) ;

0
..................................................................................................................................

Cette matrice est donc singulire, mais quel est son rang ?
..................................................................................................................................

> rank(M) ;

2
..................................................................................................................................

Le noyau de cette matrice est donc de dimension 1 ; comment en avoir un gnrateur ?


..................................................................................................................................

> K := kernel(M) ;

K := {[1, 2, 1])}
..................................................................................................................................

Sceptique ? Il faut alors valuer le produit de la matrice M par le vecteur qui vient
d'tre montr ; pour extraire ce vecteur de l'ensemble de vecteurs constituant la
base du noyau, ici rduite un lment, on peut utiliser l'indexation [1] ; un calcul
matriciel doit tre eectu sous evalm et l'oprateur de multiplication matricielle
est &*.
..................................................................................................................................

> evalm(M &* K[1]) ;

[0, 0, 0]
..................................................................................................................................

Ce calcul trs simple montre qu'on peut travailler interactivement avec des donnes matricielles quelconques. On en verra de nombreux exemples, voir notamment
. On avait dj vu un exemple relativement sophistiqu page 99 et
les chapitres
suivantes propos de problmes d'interpolation et de matrices de Vandermonde.
-o-o-o-o-o-o-

145

Chapitre 5
Programmation.
5.1 Introduction.
Maple n'est pas seulement un systme de calcul formel ; c'est aussi un langage
de programmation. Il est de ce point de vue thoriquement quivalent tous les
autres langages, bien que, comme chacun sait, selon le contexte, tel langage est
commode ou au contraire dlicat utiliser.
Le point de vue vident ce propos des concepteurs de Maple tait, et reste,
le suivant. Le contexte calcul symbolique est relativement dlicat, et pour viter
toute surcharge de complexit, un langage de programmation qu'on peut qualier
de rustique a t adopt.
Il a en particulier l'avantage d'tre facile apprendre, car conceptuellement
simple tout en tant logiquement bien quilibr. Sa faiblesse rapidement perue
comme la plus vidente est dans le typage des objets en gnral, des variables en
particulier. Avec une situation manifestement un peu dsquilibre de ce point de
vue : d'une part, d'innombrables types prdnis sont disponibles, et l'utilisateur a
de grandes facilits pour en crer de nouveaux sa guise. Mais il n'est pas possible
de dclarer les variables locales1 de procdures, ou mme les variables globales.
Ceci donne un style de programmation gnralement assez sauvage, proche de la
programmation en Lisp des premiers temps, o il arrive souvent de voir par erreur
une variable prvue pour localiser une matrice recevoir une. . . intgrale comme
valeur sans que Maple signale quoi que ce soit ! La procdure ASSERT permet de
mettre en uvre quelques prcautions dans ce registre, mais le plus souvent assez
rudimentaires.

5.2 Instructions conditionnelles.


Les canons de la programmation dite structure rduisent tout algorithme un
assemblage plus ou moins complexe d'instructions conditionnelles et d'instructions
1 Ceci

est maintenant possible dans Maple 6.

146

itratives. La forme la plus gnrale d'une instruction Maple conditionnelle est :

if

condition 1

then

elif

instruction 1,1 ;
... ... ;
instruction 1,n1

condition 2

then

elif
elif

instruction 2,1 ;
... ... ;
instruction 2,n2
... ...
... ...

condition k

then

else

;

instruction k,1 ;
... ... ;
instruction k,nk
instruction k+1,1 ;
... ... ;
instruction k+1,nk+1

Il est rare et surtout franchement dconseill d'utiliser le maximum de gnralit ach ici ! Presque toujours, un minimum de rexion sur le sujet trait permet
de se dispenser des instructions conditionnelles multiples branches, de plus en
gnral assez peu lisibles. Ceci dit, qui peut le plus peut le moins et inversement
toute limitation sur le degr de gnralit montr ici, commun presque tous les
langages de programmation, serait malcommode dans tel ou tel cas particulier.
Seule relative originalit de Maple : la possibilit automatique d'insrer dans
chaque branche un nombre arbitraire d'instructions. Avec un inconvnient : cette
possibilit ncessite un indicateur de fermeture, fi en n d'instruction, ou bien un
sparateur, elif ou else indiquant le passage la branche suivante. Mais ceci a
dispens les concepteurs de Maple de prvoir un format d'instruction compose,
comparable au {. . . . . .} de C. Il rsulte de ceci que la faute d'criture consistant
oublier le fi terminal est trs frquente, et surtout n'est pas dtectable en place,
puisque le point-virgule suivant indique que la branche de then ou else continue.
Si ceci se produit dans le texte d'une procdure, la faute n'est le plus souvent dtectable qu'au end terminal, situation qui laisse l'utilisateur dans le vide chercher
147

si c'est une parenthse, ou un crochet, ou une accolade, ou un if, ou encore un do


qui n'est pas referm. Seule solution : soigneusement indenter son texte pour en
vrier facilement la structure, comme il l'est toujours montr dans nos exemples.
On ne peut que regretter amrement le caractre franchement primitif de l'diteur Maple de ce point de cue ; il devrait, par un jeu quelconque d'dition, indiquer
dans le texte du groupe d'excution en cours quelle est l'entit la plus profonde
qui est la premire refermer. tant donn la sophistication d'autres lments de
cet diteur, on reste un peu surpris que ceci ne soit pas encore propos.
Passons en revue les cas d'utilisation les plus courants d'instructions conditionnelles.

5.2.1 if  then  .
C'est le cas le plus simple. Il intervient trs frquemment en dbut de procdure
pour traiter un ou plusieurs cas particuliers, permettant de dvier la procdure sur
un autre cas. Considrons par exemple l'exercice d'tudiant consistant mettre en
place une procdure de calcul numrique du logarithme de base 10, celle fournie
par le systme tant suppose en panne.
Un algorithme trs commode et de plus assez ecace pour ce faire consiste
n'utiliser que les quatre oprations classiques. Comme c'est souvent le cas, on a
intrt tre un peu plus gnral et installer un algorithme capable de calculer
(, , ) = + log(), pour > 0, le cas du logarithme seul tant le cas
particulier = 0 et = 1. Cette organisation permet en eet de reporter par
oprations lmentaires le logarithme vers jusqu' ce que la prcision souhaite
soit atteinte ; cette prcision est dnie par un paramtre , par exemple donn
comme = 1010 . On procde de faon itrative alors comme suit :
1. Si = 1, alors + log() = ;
2. Si < 1, alors + log() = log(1/) ;
3. Si 10, alors + log() = + + log(/10) ;
4. Si les conditions prcdentes ne sont pas satisfaites, c'est que 1 < < 10 et
donc 0 < log() < 1 ; dans ces conditions, si est non nul et si |/| < ,
l'exigence sur la prcision relative est satisfaite en se contentant de ;
5. Sinon on utilise + log() = + (/2) log( 2 ).
Il est facile de voir que l'volution de cet algorithme fait tendre / vers 0,
et la quatrime condition termine donc l'algorithme. La traduction en Maple, uniquement coups de if  then   s'crit alors :

148

..................................................................................................................................

> phi := proc(alpha::realcons, beta::realcons, gamma::positive)


global epsilon ;
if gamma=1. then RETURN(alpha) fi ;
if gamma<1. then RETURN(phi(alpha, -beta, 1/gamma)) fi ;
if gamma>=10. then RETURN(phi(alpha+beta, beta, gamma/10.)) fi ;
if alpha<>0. and abs(beta/alpha)<epsilon then RETURN(alpha) fi ;
RETURN(phi(alpha, beta/2., gamma^2))
end :

..................................................................................................................................

La procdure phi est le moteur de la procdure cherche :


..................................................................................................................................

> mylog10 := proc(x::positive)


global epsilon ;
epsilon := 1e-10 ;
RETURN(phi(0., 1., convert(x,float)))
end :

..................................................................................................................................

Noter la dclaration globale de epsilon dans les deux procdures, indispensable


pour la communication ce propos, sinon il faudrait prcoir un quatrime argument pour la procdure phi, ce qui alourdirait son fonctionnement rcursif. Ceci
dit cette mthode est dangereuse, cause des risques d'interfrence avec un autre
usage global d'epsilon ailleurs. On verra dans le prochain chapitre comment mieux
.
solutionner ce problme, voir page
La conversion en ottant dans mylog10 est ncessaire pour viter le clash surprenant :
..................................................................................................................................

> if 1 = 1. then equal else `not equal` fi ;


not equal

..................................................................................................................................

car contrairement ce que croient les mathmaticiens, en informatique, l'entier 1


et le ottant 1. ne sont pas gaux ! Ce qui oblige choisir entre 1 et 1. pour le cas
exceptionnel du logarithme trivial. Ces prparatifs tant faits, notre logarithme
est maintenant oprationnel :
..................................................................................................................................

> mylog10(2) ;

.3010299956
..................................................................................................................................

qu'on peut comparer au logarithme ociel soudainement redevenu disponible :


..................................................................................................................................

> log[10](2.);

.3010299957
..................................................................................................................................

Des tests faciles mener  utiliser la procdure time  permettent de constater que notre procdure est aussi ecace que la procdure Maple d'origine. Mais
la procdure Maple traite aussi le cas du logarithme complexe, non couvert par la
ntre. Cette dernire peut facilement tre adapte pour traiter d'autres bases de
logarithmes, et pour atteindre des prcisions suprieures, en jouant sur les variables
epsilon et Digits.

149

5.2.2 if  then  else  .


Un exemple tait montr ci-dessus, pour tester l'galit potentielle de l'entier
1 et du ottant 1.. La procdure evalb est appele implicitement pour la
comparaison :
..................................................................................................................................

> evalb(1 = 1.) ;

false

..................................................................................................................................

Comparer avec la procdure is :


..................................................................................................................................

> is(1 = 1.) ;

true

..................................................................................................................................

On avait signal la dicult provoque par la comparaison du paramtre avec


1 (ou 1.) pour traiter le cas, indispensable sous peine d'erreur occasionnelle, du
logarithme trivial dans la procdure phi ; cette dicult avait t surmonte par la
conversion en ottant de l'argument x l'appel de phi dans la procdure mylog10.
Ce qui est observ ici donne une autre solution : remplacer le dbut d'instruction
conditionnelle if gamma=1. ... par if is(gamma = 1.) .... On observe que
ces questions mathmatiquement lmentaires demandent une grande lucidit pour
tre traites ici correctement. Ainsi :
..................................................................................................................................

> if is(1 = 1.) then equal else `not equal` fi ;


equal

..................................................................................................................................

Comme usage un tout petit peu moins trivial de if  then  else  , observons que la procdure mylog10 aurait pu tre termine d'une faon que beaucoup
prfrent :
..................................................................................................................................

if alpha<>0. and abs(beta/alpha)<epsilon


then RETURN(alpha)
else(RETURN(phi(alpha, beta/2., gamma^2)))
end :

..................................................................................................................................

bien que les deux mthodes soient ici parfaitement quivalentes. Cette quivalence
est due un phnomne particulier qu'il faut bien avoir identi : ici la prsence
d'une instruction RETURN dans une branche implique que de toute faon la procdure
est interrompue, que la condition teste  comparaison avec  soit satisfaite
ou non.
Pour montrer une situation dirente considrons le problme n/2 ou 3n + 1.
Soit n un entier positif quelconque. On applique de faon itrative le processus
suivant : si n est pair, on le divise par 2, sinon on le remplace par 3n + 1. On veut
une procdure qui retourne le nombre d'tapes ncessaires pour atteindre 1. Il est
conjectur que ce nombre est toujours dni, autrement dit que le processus dcrit
nit par atteindre 1, mais cette conjecture, trs ancienne, reste non dmontre
quand ces lignes sont crites. Version utilisant if  then  else   :

150

..................................................................................................................................

> nsteps := proc(n::posint)


local nsteps, nn ;
nsteps := 0 ; nn := n ;
while nn <> 1 do
nsteps := nsteps+1 ;
if nn mod 2 = 0
then nn := nn/2
else nn := 3*nn+1
fi ;
od ;
RETURN(nsteps)
end :
> nsteps(10^67-1);

2076
..................................................................................................................................

La procdure nsteps est vraiment programme comme on pense. Seule coquetterie, l'usage du mme nom pour la procdure et pour la variable locale compteur ;
certains n'aiment pas ce style, d'autres trouvent au contraire commode de dsigner ainsi implicitement quelle est la variable cl de la procdure. Noter aussi
la ncessit d'une variable locale nn initialise l'argument n, car il n'est pas possible sous Maple de modier cet argument, moins d'utiliser une technique qu'on
examinera en temps utile, page
, mais en fait ici inapproprie.
Comparer la version suivante o on a jou utiliser seulement la version
if  then   de l'instruction conditionnelle :
..................................................................................................................................

> nsteps := proc(n::posint)


local nsteps, nn ;
nsteps := 0 ;
nn := n ;
while nn <> 1 do
nsteps := nsteps+1 ;
if nn mod 2 = 0 then nn := nn/2 fi ;
if nn mod 2 = 1 then nn := 3*nn+1 fi
od ;
RETURN(nsteps)
end :

..................................................................................................................................

La traduction dans ce nouveau style semble vidente. Vraiment ? Essayez le rsultat


et vous aurez une surprise ! C'est un excellent exercice de debugging d'identier
l'origine de cette surprise ; plusieurs solutions sont possibles pour la surmonter, bien
sr en respectant notre rgle : la clause else reste interdite ! La solution ci-dessous
n'est pas sans intrt, car elle montre une solution d'un style assez dirent, o
cette fois chaque clause then comporte deux instructions spares par un pointvirgule ; noter dans ce registre que les mots-cls elif, then et else sont du point
de vue syntaxique des sparateurs et qu'il est donc inutile, bien que tolr, de faire
prcder elif, else et  d'un point-virgule, autre sparateur plus profond dans la
hirarchie.

151

..................................................................................................................................

> nsteps := proc(n::posint)


local nsteps, nn ;
nsteps := 0 ; nn := n ;
while nn <> 1 do
if nn mod 2 = 1 then nn := 3*nn+1 ; nsteps := nsteps+1 fi ;
if nn mod 2 = 0 then nn := nn/2 ; nsteps := nsteps+1 fi
od ;
RETURN(nsteps)
end :

..................................................................................................................................

5.2.3 if  elif . . .
La procdure phi qui nous a servi pour le calcul du logarithme de base 10 est
le plus souvent crite par les programmeurs :
..................................................................................................................................

> phi := proc(alpha::realcons, beta::realcons, gamma::positive)


global epsilon ;
if gamma = 1. then RETURN(alpha)
elif gamma<1. then RETURN(phi(alpha, -beta, 1/gamma))
elif gamma>=10. then RETURN(phi(alpha+beta, beta, gamma/10.))
elif alpha<>0. and abs(beta/alpha)<epsilon
then RETURN(alpha)
else RETURN(phi(alpha, beta/2., gamma^2))
fi
end :

..................................................................................................................................

On voit en particulier que la lisiblit est excellente.

5.3 Instructions itratives.


De nombreux exemples ont t dj montrs, qui nous permettront de consacrer
ce paragraphe plutt des complments techniques par rapport aux usages les plus
simples dj vus, et aussi des considrations de style.

5.3.1 do.
Encore appel do forever, car utilise directement sans prambule, cette instruction est indniment rpte ; elle ne peut alors tre interrompue que par une
instruction break ou RETURN, ou encore, plus piteusement, par un click sur le bouton
. Pour montrer un usage plausible de ce do, transformons nos procdures
stop :
mylog10 et phi (cf. pages 149 et 152) de la forme rcursive prcdemment utilise vers une forme itrative, un peu plus technique, mais indispensable en haute
prcision. Une seule procdure va maintenant sure.

152

..................................................................................................................................

> mylog10 := proc(x::positive)


local alpha, beta, gamma, epsilon ;
epsilon := 1e-10 ;
alpha, beta, gamma := 0., 1., convert(x, float) ;
do
if gamma = 1. then RETURN(alpha)
elif gamma<1. then beta, gamma := -beta, 1/gamma
elif gamma>=10. then alpha, gamma := alpha+beta, gamma/10.
elif alpha<>0. and abs(beta/alpha)<epsilon
then RETURN(alpha)
else beta, gamma := beta/2., gamma^2
fi
od
end :
> mylog10(2) ;
.3010299956

..................................................................................................................................

La nouvelle procdure est vritablement une traduction en style itratif des


deux prcdentes. Noter l'usage intensif des aectations simultanes, trs commodes et trs lisibles. L'aectation simultane n'est pas seulement un raccourci
d'criture ; le fait que les aectations demandes soient eectues en parallle
permet des raccourcis ecaces et bien lisibles. L'exemple prototype est l'change
entre deux valeurs de variables. Sans aectation simultane, une variable auxiliaire est ncessaire :
..................................................................................................................................

> a := 2 ; b := 3 ;

a := 2
b := 3

> tmp := a ; a := b ; b := tmp ;

tmp := 2
a := 3
b := 2

..................................................................................................................................

alors que par aectation simultane :


..................................................................................................................................

> a, b := b, a ; a, b ;

a, b := 2, 3
2, 3
..................................................................................................................................

Dans le cours Maple de niveau perfectionnement, on cherche dmontrer que cette


aectation prtendue parallle ne l'est pas tant que a.
..................................................................................................................................

> a, b := 2, 3 ;

a, b := 2, 3
> a, b := [b, assign('a' = b)][1], a ;
a, b := 3, 3
..................................................................................................................................

Cette exprience assez sotrique dmontre que la premire composante a en fait


bien t value avant la seconde ; le paralllisme classiquement prtendu est donc
153

tout relatif ! En fait les expressions du second membre de l'aectation simultane


sont calcules squentiellement, mais chaque aectation demande n'est eectue
qu'aprs valuation complte de toutes ces expressions.

5.3.2 for et while.


Il est souvent commode de grer l'initialisation et la terminaison d'une itration
l'aide de clauses for et/ou while. L'usage en est si classique qu'il y a peu dire.
Considrons l'exercice consistant dterminer la premire puissance d'un rel a
vriant a > 1 qui est plus grande qu'un autre rel b. Le logarithme permet une
rponse simple, mais il est nouveau en panne. . . Avec do seul, on peut programmer
la procdure :
..................................................................................................................................

> FirstPower := proc(a::Range(1,infinity), b::realcons)


local FP, power ;
FP := 0 ; power := 1. ;
do
if power >= b
then RETURN(FP)
else FP := FP+1 ; power := power*a
fi
od
end :
> FirstPower(1.1, 10) ;
25

..................................................................................................................................

C'est en fait trs lisible, mais la progression rgulire du compteur suggre


plutt d'utiliser une clause for :
..................................................................................................................................

> FirstPower := proc(a::Range(1,infinity), b::realcons)


local FP, power ;
power := 1. ;
for FP from 0 do
if power >= b
then RETURN(FP)
else power := power*a
fi
od
end :
> FirstPower(1.1, 10) ;
25

..................................................................................................................................

En eet le compteur est incrment par dfaut d'une unit chaque tour  il
faut dire chaque itration  de sorte que la clause for gre automatiquement
la progression de la variable FP que la plupart des programmeurs appelleraient
simplement i. Si pour une raison qui nous chappe, le cahier des charges demande
la premire puissance paire satisfaisant la mme condition, il sut d'utiliser la
sous-clause by :

154

..................................................................................................................................

> FirstEvenPower := proc(a::Range(1,infinity), b::realcons)


local FP, power ;
power := 1. ;
for FP from 0 by 2 do
if power >= b
then RETURN(FP)
else power := power*a^2
fi
od
end :
> FirstEvenPower(1.1, 10) ;
26

..................................................................................................................................

Il serait bien sr plus rentable, dans le cas o chaque micro-seconde serait prcieuse,
de calculer une fois pour toutes le carr de a. Mais la terminaison elle-mme peut
tre simultanment gre par une clause while, ce qui donne un style beaucoup
plus compact.
..................................................................................................................................

> FirstEvenPower := proc(a::Range(1,infinity), b::realcons)


local sqa, FP, power ;
sqa := a^2 ; power := 1. ;
for FP from 0 by 2 while power < b do
power := power*sqa
od ;
RETURN(FP)
end :
> FirstEvenPower(1.1, 10) ;
26

..................................................................................................................................

Il se pourrait aussi qu'on craigne un temps de calcul trop long si a tait trop
proche de 1 et b trop grand ; on voudrait donc limiter tout prix 1000 le nombre
d'itrations.
..................................................................................................................................

> FirstEvenPower := proc(a::Range(1,infinity), b::realcons)


local sqa, FP, power ;
sqa := a^2 ; power := 1. ;
for FP from 0 by 2 to 1998 while power < b do
power := power*sqa
od ;
if FP = 2000
then ERROR(`Temps calcul trop long, excution arrte.`)
else RETURN(FP)
fi
end :
> FirstEvenPower(1.1, 10) ;
26
> FirstEvenPower(1.001, 1e20) ;
Error, (in FirstEvenPower) Temps calcul trop long, excution arrte.

..................................................................................................................................

Reprenons la procdure nsteps de la page 151 ; on peut ainsi la librer de


l'initialisation et de l'entretien de la variable nsteps l'aide de la clause for :
155

..................................................................................................................................

> nsteps := proc(n::posint)


local nsteps, nn ;
nn := n ;
for nsteps from 0 while nn <> 1 do
if nn mod 2 = 0 then nn := nn/2
else nn := 3*nn+1
fi ;
od ;
RETURN(nsteps)
end :

..................................................................................................................................

Il arrive aussi qu'une clause while suse elle seule. Par exemple si, dans notre
procdure FirstPower, on est intress seulement par la valeur de la puissance et
non par l'exposant, on peut l'crire :
..................................................................................................................................

> FirstPower := proc(a::Range(1,infinity), b::realcons)


local power ; power := 1. ;
while power < b do power := power * a od ;
RETURN(power)
end :
> FirstPower(1.1, 10) ;
10.83470595

..................................................................................................................................

5.3.3 next et break.


Deux mots-cls sont quelquefois utiles dans un contexte itratif. L'instruction
next demande l'interruption de l'itration en cours et le passage immdiat l'itration suivante, alors que l'instruction break demande l'interruption complte de
l'itration. Exemple articiel :
..................................................................................................................................

> for i from 0 do


if i mod 3 = 0 then next fi ;
if i = 5 then break fi ;
print(i)
od ;

1
2
4
..................................................................................................................................

Il n'est pas dicile de dmontrer qu'on peut toujours se passer de ces instructions,
ceci dit il est frquent que leur usage facilite l'criture et amliore la lisibilit des
programmes itratifs un peu compliqus.

5.4 Tris.
La mthode standard pour vrier que l'essentiel est compris en programmation
conditionnelle et itrative consiste programmer les algorithmes lmentaires de
156

tri ; ils ncessitent en eet du programmeur une gymnastique instructive. Considrons par exemple l'un des tris les plus simples, le tri par insertion. On range les
objets trier les uns aprs les autres, insrant chaque objet la bonne place, qu'il
faut donc dterminer par rapport aux objets dj rangs. La liste des objets tris
augmente donc rgulirement, et les objets au-del de l'objet insrer doivent tre
dplacs pour laisser une place au nouveau venu. Plusieurs solutions techniques
sont possibles qu'il est intressant de comparer.
Mais avant de trier, il faut un objet raisonnable trier. Dans les exercices de
tri, ce sont classiquement des listes d'entiers. Soit donc construire une liste de 20
entiers alatoires compris entre 1 et 1000. On construit d'abord une procdure
de gnration, qu'on essaie par exemple cinq fois.
..................................................................................................................................

> rnd1000 := rand(1..1000) :


> seq(rnd1000(), i=1..5) ;

82, 271, 698, 564, 977


..................................................................................................................................

Moyennant quoi notre liste exercice peut tre construite :


..................................................................................................................................

> list1 := [seq(rnd1000(), i=1..20)] ;


list1 := [539, 86, 769, 922, 410, 656, 164, 458, 161, 675, 86, 917, 462, 308, 350, 87, 199, 467, 710, 974]

..................................................................................................................................

Pour avoir les ides plus claires, on va commencer par trier en crant un nouvel
objet, une liste qu'il faut initialiser la bonne longueur, en la remplissant par
exemple par des zros, comme suit.
..................................................................................................................................

> list2 := [0 $ 20] ;


list2 := [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

..................................................................................................................................

On va prendre ensuite le premier lment, 539, le ranger dans la premire case,


puis le second, 86 ; son insertion demande de pousser 539 la deuxime case, etc.
On voit assez rapidement qu'on a intrt descendre dans la liste rsultat pour
chercher la bonne place du nouvel lment, tout en dcalant les lments lus pour
prparer la place du nouveau venu. D'o cette programmation :
..................................................................................................................................

> insertion1 := proc(list1::list(integer))


local list2, i, j ;
list2 := [0 $ nops(list1)] ;
# initialisation liste rsultat
for i from 1 to nops(list1) do
# pour chaque lment liste entre
for j from i-1 to 1 by -1 do
# pour chaque lment dj tri
if list1[i] < list2[j]
# comparaison
then list2[j+1] := list2[j] # si < dcaler
else break
# si >= stopper l'itration intrieure
fi
od ;
list2[j+1] := list1[i]
# insrer
od ;
RETURN(list2)
end :

157

> insertion1(list1) ;
[86, 86, 87, 161, 164, 199, 308, 350, 410, 458, 462, 467, 539, 656, 675, 710, 769, 917, 922, 974]
..................................................................................................................................

Les textes aprs # sur chaque ligne sont des commentaires.


Cette solution n'est dj pas si facile obtenir. On peut par exemple oublier la
sous-clause by -1 dans l'itration interne, car le fait que la valeur initiale de j
soit plus grande que la valeur nale peut faire croire que Maple devinera qu'il
faut faire dcrotre j ; il n'en est rien ; comparer :
..................................................................................................................................

> for j from 2 to 1 do print(coucou) od ;


> for j from 2 to 1 by -1 do print(coucou) od ;
coucou
coucou

..................................................................................................................................

Si on oublie by -1 dans la programmation de insertion1, le rsultat est cocasse,


essayez et cherchez comprendre la nature du message d'erreur. Autre subtilit,
il est plus instinctif dans le if de faire l'insertion avant le break quand la rponse
est ngative ; mais ceci interdit toute insertion si la rponse est toujours positive,
ce qui arrive quand l'lment insrer est plus petit que tous ceux dj tris. On
voit que si l'insertion est ralise l'extrieur aprs terminaison de l'itration la
plus intrieure, alors elle fonctionne toujours correctement. C'est d'ailleurs un cas,
peu frquent, o la persistance de la valeur de j aprs l'itration est bigrement
utile : la concidence de correction de l'insertion, qu'il y ait eu break ou non, est
assez frappante, indice de bonne programmation.
Ceci dit ce programme a encore beaucoup de dfauts. On voit d'abord qu'une
clause while aurait permis un code plus compact, sensiblement plus lgant. Pourtant la correction de clauses simultanes for et while n'est jamais facile tester,
et il est souvent plus sr de commencer sagement par un code plus rustre. Certains s'imposent dans ce registre de commencer la programmation d'une itration
do ... od sans clause for ou while, en prvoyant banalement aprs le do initial la
progression ventuelle d'une variable pilote et/ou le test d'arrt. Une fois que le
programme dans ce style est au point, ils rchissent alors seulement ce moment
s'ils pourraient astucieusement utiliser une clause for ou while, ou mme les deux,
pour prxer le do.
..................................................................................................................................

> insertion2 := proc(list1::list(integer))


local list2, i, j ;
list2 := [0 $ nops(list1)] ;
# initialisation liste rsultat
for i from 1 to nops(list1) do
# pour chaque lment liste entre
for j from i-1 to 1 by -1
# pour chaque lment dj tri
while list1[i] < list2[j] do # tant que trop petit
list2[j+1] := list2[j]
# dcaler
od ;
list2[j+1] := list1[i]
# insrer
od ;
RETURN(list2)
end :

..................................................................................................................................

158

Un dfaut d'une autre nature est assez important. Ici, pour un exercice d'tudiant, il est secondaire, mais pour un vrai tri sur de grands ensembles, il aurait de
srieux inconvnients. On observe que list1[i] est utilis pour chaque comparaison, lecture dans une liste bien plus coteuse que le laisse penser le texte list1[i],
si court. Alors que cet objet aurait pu tre lu une seule fois et rutilis ensuite ; il
faut pour ce faire une nouvelle variable qu'on appelle fllw (following).
..................................................................................................................................

> insertion3 := proc(list1::list(integer))


local list2, i, j, fllw ;
list2 := [0 $ nops(list1)] ;
# initialisation liste rsultat
for i from 1 to nops(list1) do
# pour chaque lment liste entre
fllw := list1[i] ;
# lment suivant insrer
for j from i-1 to 1 by -1
# pour chaque lment dj tri
while fllw < list2[j] do
# tant que fllw trop petit
list2[j+1] := list2[j]
# dcaler
od ;
list2[j+1] := fllw
# insrer
od ;
RETURN(list2)
end :

..................................................................................................................................

Comparons insertion2 et insertion3 pour une liste de 100 lments. La procdure time, utilise sans argument, retourne le temps machine en secondes depuis
le dbut de la session ; elle permet donc de chronomtrer une excution. On rpte
chaque tri 100 fois pour une comparaison signicative.
..................................................................................................................................

> list11 := [seq(rnd1000(), i=1..100)] :


> st := time() :
for i from 1 to 100 do insertion2(list11) od :
time() - st ;
8.940
> st := time() :
for i from 1 to 100 do insertion3(list11) od :
time() - st ;
8.680

..................................................................................................................................

Le gain est rel mais peu important pour des listes de si petite taille, sans aucune
comparaison avec ce qui est fait usuellement sur machine. On ne peut faire plus
ici pour une autre raison, qu'il est encore bien plus important de comprendre.
Essayons d'utiliser notre tri pour une liste de 200 lments.
..................................................................................................................................

> list11 := [seq(rnd1000(), i=1..200)] :


> insertion3(list11) ;

Error, (in insertion3) assigning to a long list, please use arrays

..................................................................................................................................

Ici, on avait oubli ce qui tait expliqu page 122 : on ne peut pas modier une
liste de plus de 100 lments ! Pour les tris consquents, les seuls dignes d'intrt,
il faut donc obligatoirement utiliser une technique tableau (array), autrement dit
vecteur (vector) dans le cas d'un seul indice.

159

..................................................................................................................................

> insertion4 := proc(list1::list(integer))


local vct2, i, j, fllw ;
vct2 := vector(nops(list1)) ;
# initialisation vecteur rsultat
for i from 1 to nops(list1) do
# pour chaque lment liste entre
fllw := list1[i] ;
# lment suivant insrer
for j from i-1 to 1 by -1
# pour chaque lment dj tri
while fllw < vct2[j] do
# tant que fllw trop petit
vct2[j+1] := vct2[j]
# dcaler
od ;
vct2[j+1] := fllw
# insrer
od ;
RETURN(convert(vct2, list))
end :

..................................................................................................................................

On voit que le vecteur sert d'outil annexe, et que, en supposant que le cahier des
charges demande le rsultat sous forme de liste, on convertit le vecteur en liste en
n d'excution. Refaisons le mme test temps :
..................................................................................................................................

> st := time() :
for i from 1 to 100 do insertion4(list11) od :
time() - st ;
3.490

..................................................................................................................................

Le gain est trs consquent et on comprend bien maintenant pourquoi Maple vous
interdit de modier des listes longues : ces modications sont vritablement calamiteuses en optimisation temps et espace mmoire, et pour viter des dfauts
de rendement aux programmeurs inexpriments, Maple interdit purement et simplement de telles modications sauf pour de petites listes. Mme pour celles-ci
l'exemple vu ici montre que ce peut tre trs coteux si le mme phnomne est
rpt intensivement.
Rien n'empche maintenant de trier de longues listes. Une mthode nave
comme la ntre a un cot temps de tri grossirement proportionnel au carr du
nombre d'lments trier.
..................................................................................................................................

> list11 := [seq(rnd1000(), i=1..1000)] :


> time(insertion4(list11)) ;
4.754
> list11 := [seq(rnd1000(), i=1..10000)] :
> time(insertion4(list11)) ;
520.791

..................................................................................................................................

de sorte que les temps de tri deviennent vite importants. Les mthodes plus ruses
base d'arborescence sont beaucoup plus ecaces. Voir par exemple, pour un beau
traitement didactique du sujet, le chapitre 2 du livre de Wirth [7]. Comparer aussi
ce qui vient d'tre fait avec la procdure de tri propose par Maple lui-mme :
..................................................................................................................................

> time(sort(list11)) ;

0.45
..................................................................................................................................

160

Le temps de calcul est donc divis par 10000 ! On ne saurait mieux montrer que
Maple n'est pas vraiment fait pour la programmation de base. La programmation
interne de sort est en eet crite en C, avec une ecacit sans commune mesure,
d'une part parce que la technique de tri est autrement sophistique, d'autre part
parce que C est beaucoup plus proche du langage machine : notre programmation
est en eet interprte et l'ecacit par rapport ce qui est en fait disponible sur
machine est drisoire.
-o-o-o-o-o-o-

161

Chapitre 6
Procdures.
6.1 Introduction.
On a vu dans le chapitre prcdent un type de programmation itrative consistant rpter un certain nombre de fois une squence de programmation dans un
environnement lgrement variable d'une fois l'autre. La squence en question
doit alors tre encapsule dans une instruction do ... od. Le prsent chapitre
est consacr une autre forme de programmation itrative, en un sens trs dirent, consistant construire un objet procedure, appel plus simplement procdure,
puis l'utiliser de temps autre, quelquefois un grand nombre de fois, avec l
aussi un environnement un peu dirent d'une fois l'autre.
La principale dirence entre les deux cas est la suivante. Une suite d'instructions encapsule dans un do ... od est excute de faon rptitive un certain
nombre de fois puis dnitivement abandonne ; les guillemets de la qualication
dnitive sont ncessaires, parce que, pour d'autres raisons, cette itration peut en
fait tre nouveau excute ; cette instruction do peut tre par exemple son tour
encapsule dans un autre do ... od comme on l'a vu dans le chapitre prcdent
pour notre programmation du tri-insertion, voir Section 5.4. Une instruction do
peut aussi gurer dans une procdure, on a vu de nombreux exemples, de sorte
que la rexcution de la procdure impliquera en particulier une nouvelle excution
de l'instruction do.
Le caractre itratif d'une procdure est dirent. Il s'agit d'un ensemble d'instructions qu'on veut pouvoir excuter au besoin, n'importe quel moment.
Une terminologie bien dnie doit tre utilise en la matire, terminologie qu'on
prsente dans cette introduction, dont la signication sera dtaille dans ce chapitre. Quand une procdure est construite, elle ne sera utilisable que si elle est
installe dans l'environnement, accessible le plus souvent par l'intermdiare d'un
symbole appel alors, mais c'est un abus de langage, le nom de la procdure. Le
cas des procdures anonymes est aussi important : une telle procdure est alors
une composante d'un objet plus ou moins complexe, de nature quelconque, suite,
liste, ensemble, matrice, etc. Le cas d'une procdure gurant comme lment d'une
suite d'arguments d'un appel d'une autre procdure est frquent.
162

Quand une procdure est disponible, elle peut tre appele de diverses faons.
On dit alors qu'une invocation de la procdure est active. Cette invocation peut
tre active un temps trs court, moins d'une micro-seconde, ou un temps trs long,
plusieurs jours, avec bien sr tous les intermdiaires possibles. Trs important :
plusieurs invocations de la mme procdure peuvent tre actives au mme moment, mais au plus une est en cours d'excution ; les autres, bien qu'actives, sont
provisoirement au repos, en attente de la suite de leur excution ; c'est le point
cl de la programmation rcursive dont un exemple typique est la programmation de la procdure phi page 149. Quand une invocation de procdure termine,
cette invocation retourne toujours une valeur, quel que soit le cas de gure. Les
appels de procdures qui semblent ne rien retourner retournent en fait la suite
vide, celle qui est repre par le symbole NULL, et ceci doit alors presque toujours
tre explicitement prvu dans la dnition de la procdure. Une procdure peut
aussi retourner plusieurs objets, en fait une suite d'objets de longueur arbitraire.
Le mcanisme d'aectation multiple est alors souvent utilis pour dispatcher les
composantes du rsultat vers divers symboles.
Des symboles dits locaux sont souvent ajouts l'environnement lors de l'activation d'une procdure. Les autres symboles utiliss dans la procdure sont globaux. Par ailleurs des symboles locaux trs particuliers appels paramtres servent
particulariser le travail d'une invocation particulire de la procdure. Quand la
procdure est appele, des arguments sont passs la procdure, et les paramtres
de la procdure sont initialiss en fonction de ces arguments ; on verra que cette
description simplie est en fait assez incorrecte, mais chaque chose en son temps.
On a dj discut pour une autre raison la dirence entre ce que nous avons
appel argument provisoire et argument dnitif, voir la rgle Eval-14.
La partie locale de l'environnement peut son tour contenir des procdures
dont les rgles de visibilit sont alors particulires au contexte. Un tel objet, en
premire approximation local une procdure, peut nanmoins tre retourn
l'extrieur de la procdure, tout en gardant ses rgles de visibilit. Ces objets trs
tranges mnent la programmation fonctionnelle, inaccessible aux utilisateurs des
langages ordinaires, Pascal, C, C++ ou Java. C'est un outil trs puissant, ouvrant
un monde de programmation compltement nouveau, auquel le chapitre
sera
entirement consacr.

6.2 Exemple lmentaire.


p
Un utilisateur doit utiliser de faon frquente une expression x2 + y 2 pour des
objets varis. Plutt que de taper chaque fois sqrt( ? ? ?2 + ? ? ?2), il prfre
construire une procdure approprie, qu'il aecte au symbole rho.
..................................................................................................................................

> rho := proc(x, y)


RETURN(sqrt(x^2 + y^2))
end :

..................................................................................................................................

Notre utilisateur peut dsormais appeler sa procdure, elle lui retournera le


163

rsultat souhait.
..................................................................................................................................

> rho(20,21) ;

29

> rho(a, b+c) ;

a2 + (b + c)2

..................................................................................................................................

Exploitons cette procdure, simple mais dj utile, pour expliquer les notions
les plus lmentaires.

6.2.1 Une procdure est un objet.


Une procdure Maple est un objet Maple comme un autre, de type procedure. Le
plus souvent cet objet est accessible par l'intermdiaire d'un symbole, dans notre
exemple par le symbole rho. Ici le symbole rho est prsent dans l'environnement,
et sa valeur est l'objet procdure qui nous intresse. L'analogie est parfaite entre
notre rho et le sigma ci-dessous.
..................................................................................................................................

> sigma := 123.456 ;

123.456

> eval(sigma, 1) ; eval(rho, 1) ;


123.456
proc(x, y) RETURN(sqrt(x2 + y 2)) end

..................................................................................................................................

Le symbole sigma est aussi prsent dans l'environnement et sa valeur est l'objet
float 123.456.
La forme output d'une procdure est un texte utilisant diverses polices et indentations pour tenter d'en faciliter la lecture. Notre procdure valeur de rho n'est
accessible que par valuation explicite, voir ce sujet la rgle Eval-16.
..................................................................................................................................

> rho ;

> eval(rho) ;

proc(x, y) RETURN(sqrt(x2 + y 2)) end

> whattype(rho), whattype(eval(rho)) ;


symbol, procedure

..................................................................................................................................

Un objet compos, comme une liste, une table, une matrice peut parfaitement
avoir comme composante une procdure. Ne pas croire qu'une telle situation est
articielle, elle ouvre des possibilits de programmation fonctionnelle trs intressantes qu'on examinera plus tard, largissant considrablement le domaine de la
programmation. Par exemple notre procdure repre par le symbole rho peut tre
un lment de liste :
..................................................................................................................................

> lst := [a, eval(rho), b] ;


lst := [a, proc(x, y) RETURN(sqrt(x2 + y 2)) end, b]

..................................................................................................................................

La procdure installe ainsi bizarrement en deuxime position de la liste lst est


164

nanmoins utilisable telle quelle.


..................................................................................................................................

> lst[2](20, 21) ;

29
..................................................................................................................................

Dans le mme registre, considrer l'instruction :


..................................................................................................................................

> proc(x,y) RETURN(sqrt(x^2+y^2)) end (20,21) ;


29

..................................................................................................................................

L'expression encadre par les mots-cls proc et end, considrer comme parenthses ouvrante et fermante, est un constructeur de procdure pouvant gurer en
toute place o, aprs valuation, un objet procdure peut gurer. Une fois cette
procdure construite, Maple observe qu'elle doit tre applique la paire d'arguments 20 et 21, et le fait. Le rsultat est donc une nouvelle fois notre hypotnuse 29.

6.2.2 Nom d'une procdure.


Dans l'environnement en cours, la valeur du symbole rho est un objet procedure,
celui qui sait calculer les hypotnuses. Dans une telle situation, par abus de langage,
on dit que le nom de la procdure est rho ; de faon encore plus expditive, et
strictement parlant c'est encore plus incorrect, on dit la procdure rho. Ceci dit,
ces raccourcis sont commodes, rarement vraiment gnants, et ils ont t dj trs
souvent utiliss dans ce texte. Ces approximations supposent implicitement que
chaque objet procdure est repr exactement par un symbole, mais il est facile de
mettre en dfaut cette assertion. Par exemple on peut aecter la mme procdure
aux dix symboles psi1, . . ., psi10 :
..................................................................................................................................

> psi.(1..10) := seq(eval(rho), i=1..10) :


> eval(psi3) ;
proc(x, y) RETURN(sqrt(x2 + y 2)) end
> psi6(20,21) ;
29

..................................................................................................................................

On a donc maintenant dans notre environnement onze symboles ayant pour valeur
le mme objet procdure, et il n'est donc pas correct de dire que son nom est l'un
ou l'autre de ces symboles. On mditera en particulier les comparaisons suivantes :
..................................................................................................................................

> evalb(psi3 = psi6) ;

> evalb(eval(psi3) = eval(psi6)) ;

false
true

..................................................................................................................................

Inversement une procdure peut tre anonyme, autrement dit sans nom. On
verra plus tard que l'instruction suivante cre 100 procdures cres l'une aprs
l'autre par la procdure prdnie unapply, chacune levant son argument une
certaine puissance :

165

..................................................................................................................................

> ProcedureList := [seq(unapply(x^i, x), i=1..100)] :

..................................................................................................................................

On montre la 99-ime, puis on essaie la dixime sur 2 et la vingtime sur 3 :


..................................................................................................................................

> ProcedureList[99] ;

(x x)99

> ProcedureList[10](2) ;
1024

> ProcedureList[20](3) ;
3486784401
..................................................................................................................................

Notre environnement contient donc maintenant cent procdures supplmentaires,


toutes anonymes. Elles sont nanmoins accessibles par l'intermdiaire du symbole
ProcedureList, qui pointe sur la liste de ces procdures. On peut faire travailler
tel lment de la liste sur tel entier comme montr sur les exemples, o 210 et 320
sont calculs.

6.2.3 Appel d'une procdure.


Un appel d'une procdure est une expression :
obj0(obj1, obj2, ..., objn)

De faon plus prcise la prsence contigu d'un objet et d'une parenthse ouvrante, sans sparateur, note un objet de type function, mme si aucune procdure
n'est en piste :
..................................................................................................................................

> whattype(truc(chose, machin)), whattype(truc()), whattype(truc) ;


function, function, symbol

..................................................................................................................................

Les objets gurant entre parenthses sont les arguments (provisoires) ; il peut ne
pas y en avoir, mais les parenthses restent indispensables pour mriter le titre
function ; comparer ci-dessus les types de truc(), avec parenthses, et de truc, sans
parenthses.
De la mme faon, et c'est relativement frquent, une procdure peut tre sans
paramtre ; quand elle sera appele, il ne faudra donc donner aucun argument, mais
les parenthses doivent nanmoins gurer dans l'appel. Un exemple de procdure
sans argument est celle qui est retourne par la procdure rand, qu'on a dj utilise
plusieurs fois, voir par exemple page 40 pour initialiser une matrice alatoire.
Supposons que le contexte ncessite frquemment le tirage au sort d'un entier
entre -5 et +5. La procdure rand est disponible pour construire et retourner
une procdure capable d'eectuer ces tirages ; une telle procdure est appele un
gnrateur alatoire. Le plus simple consiste alors aecter la procdure ainsi
construite un symbole, par exemple rnd5 :

166

..................................................................................................................................

> rnd5 := rand(-5..+5) ;


rnd5 := proc ()
local t; global _seed;
_seed := irem(427419669081 _seed, 999999999989);
t := _seed;
irem(t, 11) 5

end

..................................................................................................................................

On a encadr sur le listing ci-dessus, les parenthses ouvrante et fermante qui se


succdent sans paramtre intermdiaire dans la forme externe de l'objet procedure
construit et retourn par rand. La procdure de nom rnd5 est donc une procdure
sans paramtre qu'on peut, ou plutt qu'on doit, appeler comme suit :

..................................................................................................................................

> rnd5() ;

4
..................................................................................................................................

comparer avec :
..................................................................................................................................

> rnd5 ; eval(rnd5) ;

rnd5
rnd5 := proc()
local t; global _seed;
_seed := irem(427419669081 _seed, 999999999989);
t := _seed;
irem(t, 11) 5

end

..................................................................................................................................

o l'absence de parenthse ouvrante derrire rnd5 exclut un appel de la procdure


repre par ce symbole, alors qu'au contraire la procdure eval a travaill.

6.3 Invocations multiples et programmation rcursive.


L'exemple prototype de la programmation rcursive est la programmation de
la fonction factorielle
..................................................................................................................................

> fact := proc(n::nonnegint)


if n = 0 then RETURN(1)
else RETURN(n*fact(n-1))
fi
end :
> fact(4) ;

24
..................................................................................................................................

Ici, l'valuateur appelle la procdure fact en lui passant l'argument 4 ; puisque cet
argument n'est pas nul, c'est la branche ngative de l'instruction if qui est excute, savoir RETURN(n*fact(n-1)) ; l'excution de cette instruction ncessite en
particulier l'valuation de fact(3) et l'valuateur va donc r -appeler la procdure
fact, cette fois avec l'argument 3 ; l'invocation initiale de fact est mise au repos,
167

et une nouvelle invocation est active, mais o cette fois l'argument pass est 3.
Le processus continue de la sorte jusqu' ce que cinq invocations soient actives,
appeles respectivement avec les arguments 4, 3, 2, 1 et 0. Pour cette dernire invocation c'est au contraire la branche positive de l'instruction if qui va tre excute
et l'instruction RETURN(1) est donc excute. Cette excution met n la dernire
invocation de fact, invocation qui retourne 1. La branche ngative de l'invocation
prcdente, essentiellement RETURN(1*fact(0)) peut alors tre termine ; l'appel
fact(0) a retourn 1 et cette avant-dernire invocation de fact va donc aussi
retourner 1. La troisime invocation est ractive, qui tait arrte par l'instruction
RETURN(2*fact(1)) ; la quatrime invocation de fact vient justement de retourner
1, et la troisime va donc elle aussi terminer son excution et retourner 2. Selon le
mme processus, la seconde invocation de fact va retourner 6 et enn la premire
va retourner 24.
On peut mettre en vidence ce dispositif  tiroirs en demandant d'excuter
la procdure fact en mode debug.
..................................................................................................................................

> debug(fact) ;

> fact(4)
{--> enter fact, args
{--> enter fact, args
{--> enter fact, args
{--> enter fact, args
{--> enter fact, args
<-- exit fact (now in
<-- exit fact (now in
<-- exit fact (now in
<-- exit fact (now in
<-- exit fact (now at

fact

= 4
= 3
= 2
= 1
= 0
fact) = 1}
fact) = 1}
fact) = 2}
fact) = 4}
top level) = 24}
24

..................................................................................................................................

Si une procdure est en mode debug, chaque invocation de cette procdure


va tre signale, et les arguments passs sont achs. Inversement, quand une
invocation termine, l'objet retourn par cette invocation est aussi ach, et le
debugger vous indique de plus quelle est la procdure qui reprend son activit, ou
le top level si aucune procdure n'est plus active.
La variante suivante, articielle, montre le cas de procdures mutuellement
rcursives.
..................................................................................................................................

> evenfact := proc(n::And(nonnegint, even))


if n = 0 then RETURN(1)
else RETURN(n*oddfact(n-1))
fi
end :
oddfact := proc(n::And(posint, odd))
RETURN(n*evenfact(n-1))
end :
debug(evenfact, oddfact) ;
evenfact, oddfact

168

> evenfact(4)
{--> enter evenfact, args = 4
{--> enter oddfact, args = 3
{--> enter evenfact, args = 2
{--> enter oddfact, args = 1
{--> enter evenfact, args = 0
<-- exit evenfact (now in oddfact) =
<-- exit oddfact (now in evenfact) =
<-- exit evenfact (now in oddfact) =
<-- exit oddfact (now in evenfact) =
<-- exit evenfact (now at top level)

1}
1}
2}
6}
= 24}
24

..................................................................................................................................

Il est presque toujours ncessaire, quand les expriences souhaites sont termines, de dsactiver le mode debug d'une procdure. Il faut alors utiliser la procdure
undebug en donnant comme argument(s) le(s) nom(s) de procdure(s) en question.
..................................................................................................................................

> undebug(fact)

fact

> fact(5) ;
120
..................................................................................................................................

La programmation rcursive d'une procdure est souvent commode, mais on


dmontre qu'elle n'est jamais indispensable : une version purement itrative est
toujours possible. Ainsi la fonction factorielle peut aussi tre programme :
..................................................................................................................................

> itfact := proc(n::nonnegint)


local i, result ;
result := 1 ;
for i from 1 to n do
result := i*result
od ;
RETURN(result)
end :
> seq(itfact(i), i=0..10) ;
1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800

..................................................................................................................................

En particulier, et c'est un lment prendre souvent en compte, une procdure


programme rcursivement peut ncessiter des invocations si nombreuses qu'elles
peuvent nir par mettre en chec les ressources du systme. Comparer.
..................................................................................................................................

> floor(log[10](fact(600))) + 1 ;

Error, (in fact) too many levels of recursion

> floor(log[10](itfact(600))) + 1 ;

1409
..................................................................................................................................

On compare nos deux programmations senses de la fonction factorielle, l'aide


de la procdure fact, mthode rcursive, ou de la procdure itfact, mthode
itrative. Pour mener bien cette comparaison, on essaie le calcul de 600!. C'est
un nombre un peu encombrant : 1409 chires dcimaux, et le rsultat suppos
obtenu, on ajoute ce qu'il faut pour ne faire apparatre justement que ce nombre
169

de chires. D'une faon gnrale, le nombre de chires c avant la virgule d'un


nombre dcimal x est obtenu par la formule mathmatique c = E(log10 (x)) + 1 o
E est la fonction partie entire, floor en langage Maple :
..................................................................................................................................

> floor(log[10](100.000)) + 1 ;

> floor(log[10](99.999)) + 1 ;
2

> floor(log[10](0.00123)) + 1 ;
2
..................................................................................................................................

On voit ainsi que la programmation rcursive de la fonction factorielle choue. Ne


pas croire inversement que le style rcursif est toujours dconseill. Il est trs frquent que la programmation rcursive d'une procdure est particulirement commode et/ou lisible. Ainsi ci-dessus, il faut dj un peu de lucidit pour comprendre
que l'itration dans le calcul de result doit imprativement commencer 1. Voir
aussi la programmation rcursive de la procdure phi page 149, commode, alors
que sa programmation itrative est plus dicile et moins lisible, voir page 152.
Bien que ce ne soit jamais indispensable, les programmeurs expriments savent
qu'il faut toujours mieux penser d'abord, quand on programme rcursivement,
au(x) cas qui va (vont) terminer la rcursivit, c'est--dire celui (ceux) qui commence(nt) la dnition rcursive de la fonction programmer. C'est le style qui a
t systmatiquement adopt ici.

6.4 Paramtres et arguments.


C'est l'une des questions les plus diciles de la programmation. Les solutions
adoptes par les dirents langages sont en gnral trs direntes. S'il est le
plus souvent facile de passer d'un langage de programmation un autre pour ce
qui concerne les programmations itratives et conditionnelles, il n'en est pas de
mme pour la programmation procdurale ; les styles sont en eet en la matire
si dirents que des bugs apparemment incomprhensibles sanctionnent trs vite
ceux qui se contentent d'une tude supercelle de la question quand ils changent
de langage.
Ceci est d ce que beaucoup de solutions sont possibles pour tablir la correspondance entre paramtres et arguments ; l'espace de travail est si vaste qu'il
est impossible d'inclure dans un langage toutes les solutions possibles ; en inclure beaucoup rend d'ailleurs le langage techniquement dicile, de sorte que les
concepteurs, toujours angoisss l'ide que leur langage soit jug rbarbatif et
donc peu utilis, hsitent travailler en ce sens.
Maple est assez particulier de ce point de vue et un minimum de travail doit
tre prvu pour qu'un programmeur Maple domine susamment le sujet pour
un usage disons professionnel. Trois points mritent en eet d'tre soigneusement
considrs.

170

1. Le passage des arguments s'eectue normalement par valeur, notion qu'il


faut donc avoir comprise, mais la transmission de la valeur elle-mme se fait
par substitution et non par. . . valeur ; le lecteur est sans doute perplexe
la lecture de ces technicits, mais quand il aura compris, il saura identier
certains bugs pas si rares et franchement diciles lucider.
2. La rgle Eval-14 implique l'valuation pralable des arguments, voir Section 2.4.2. Ceci dit, ceci est modiable par l'utilisateur, et il peut tre utile
de connatre cette possibilit. C'est par ce biais que Maple permet le passage
ventuel par rfrence.
3. Maple permet aussi des appels de procdure avec un nombre variable d'arguments. La technique en est assez primitive, mais peut nanmoins tre considre pour permettre des appels de procdures  gomtrie variable.

6.4.1 Le passage standard d'argument.


Si un paramtre de procdure est dclar sans type, ou bien avec un type ordinaire, le mcanisme de passage d'argument est le suivant. L'argument provisoire
correspondant est valu et le rsultat de l'valuation est appel l'argument dnitif. Quand la procdure est invoque, un travail pralable de substitution est
eectu : toute occurence du paramtre dans le texte de la procdure est remplace
par l'argument dnitif.
L'illustration la plus simple va comme suit :
..................................................................................................................................

> rho := proc(x, y)


RETURN(sqrt(x^2 + y^2))
end :
> a, b, c := 3, 4, 5 ;

a, b, c := 3, 4, 5

> rho(a, b+c) ;

3 10

..................................................................................................................................

Ici, x et y sont des paramtres sans spcication de type, et le passage d'argument par valeur et substitution va donc s'appliquer. Quand la procdure rho est
appele, deux arguments provisoires sont prvus, le symbole a et l'expression b+c.
L'valuateur de Maple est donc mis d'abord deux fois au travail pour produire les
arguments dnitifs, donc dans ce cas, vu les aectations pralables aux symboles
a, b et c, les arguments dnitifs vont tre 3 et 9.
Cette phase pralable tant ralise, avant d'appeler la procdure rho, Maple
fait encore un autre travail : il substitue dans le texte de la procdure toute occurence de x par 3 et toute occurence de y par 9. Le texte de la procdure pour la
nouvelle invocation devient donc :
..................................................................................................................................

RETURN(sqrt(3^2 + 9^2))

..................................................................................................................................

Ce texte-l est alors


invoqu, et la procdure retourne donc l'objet 3*sqrt(10)
ach en output 3 10.
171

Il est important ici de comprendre qu'il y a bien eu un mcanisme de substitution de l'argument au paramtre, et non pas de mise--jour de l'environnement
l'aide des arguments, comme il est si tentant de le croire. Beaucoup de langages,
C et Lisp notamment, modient l'environnement visible de l'intrieur de la procdure pour y ajouter dans un tel cas de gure de nouveaux chanages [x 3] et
[y 9], cachant ventuellement des chanages externes de mme source. Maple
est de ce point de vue trs dirent. Pour s'en convaincre, il faut faire deux expriences.
La premire est l'origine des plus mmorables crises de nerfs des utilisateurs
de Maple. Les calculs trs lmentaires suivants peuvent tre eectus hors procdure :
..................................................................................................................................

> a := 5 ; a := a+a ;

a := 5
a := 10

> a := b ; a := a + a ;
a := b
a := 2b
..................................................................................................................................

Ces calculs sont si lmentaires que le lecteur s'interroge probablement sur leur
intrt ; mais considrez la version suivante des mmes calculs l'intrieur d'une
procdure.
..................................................................................................................................

> restart :
exp1 := proc(a)
a := a + a ;
RETURN(a)
end :
> exp1(5) ;

Error, (in exp1) illegal use of a formal parameter

> exp1(b) ;

> b ;
Error, too many levels of recursion

..................................................................................................................................

Si vous n'avez pas d'explication, vous aurez probablement les plus grandes
peines comprendre ces rsultats. Celui qui croit un passage par valeur et
aectation une variable a interne la procdure est bien incapable d'expliquer
ces phnomnes si tranges. Il faut absolument interdire cette interprtation, et
revenir la seule valide, le mcanisme de substitution. Quand la procdure exp1 a
t appele avec l'argument 5, le texte de la procdure est devenu :
..................................................................................................................................

5 := 5 + 5 ;
RETURN(5)

..................................................................................................................................

de sorte que l'instruction d'aectation est devenue errone : le calcul de 5 + 5 ne


pose pas de problme, par contre l'aectation l'entier 5 n'a pas de sens, ce qui
explique le premier message d'erreur. Noter que Maple sait vous indiquer que l'erreur provient de l'usage de ce qui est appel dans la documentation Maple formal
172

parameter, que nous appelons simplement paramtre. Cet usage n'est pourtant pas
si illgal que a, comme on va le voir immdiatement.
Quand exp1(b) est appel, comme b est alors un symbole libre, l'argument
dnitif est aussi le symbole b, de sorte que le texte de la procdure invoque
devient :
..................................................................................................................................

b := b + b ;
RETURN(b)

..................................................................................................................................

Cette fois l'instruction d'aectation est tout--fait lgale et est vritablement


excute comme prvu ; en particulier un chanage [b 2*b] est install dans
l'environnement. On s'attend donc ce que RETURN(b) retourne 2*b ? Non, c'est
seulement b qui est retourn ! Ici s'intercale une autre rgle de fonctionnement dans
les procdures : les rsultats de substitution installs l'invocation de la procdure
ne sont pas rvalus l'excution. C'est pourquoi c'est b qui est brutalement
retourn et non pas 2*b comme s'y attend le profane. De toute faon il avait tort,
car l'valuation ultrieure de b hors procdure a provoqu une erreur de rcursion :
en eet la valeur de b est 2*b qui est rvaluable, voir la rgle Eval-7, donnant 4*b,
donnant 8*b, . . ., nissant par donner une erreur de rcursion non terminable.

Conseil 28  Bien que ce ne soit pas toujours erron, au sens strict du terme,
ne cherchez pas modier la valeur d'un paramtre par une instruction d'aectation, notion qui est en fait non sens. Si vous avez vraiment besoin de faire varier
cette pseudo-valeur, doublez ce paramtre d'une variable locale et commencez par
initialiser cette variable comme il se doit.

Soit construire une procdure permettant d'changer les valeurs de deux


symboles. On avait vu page 5.3.1 que, hors procdure, la mthode la plus simple
consiste utiliser une aectation multiple.
..................................................................................................................................

> a, b := 2, 3 ;

a, b := 2, 3

> a, b := b, a ;
a, b := 3, 2

> a, b ;
3, 2
..................................................................................................................................

crire une procdure swap ralisant la mme chose d'une faon sensiblement
plus lisible est une ide naturelle.
..................................................................................................................................

> a, b := 2, 3 ;

a, b := 2, 3

> swap(a, b) ;
> a, b ;
3, 2
..................................................................................................................................

Reste crire la procdure swap. L'application directe de la mthode hors


procdure choue pour la raison explique.
173

..................................................................................................................................

> swap := proc(x, y)


x, y := y, x ;
RETURN(NULL)
end :
> a, b := 2, 3 ;

a, b := 2, 3

> swap(a,b) ;
Error, (in swap) illegal use of a formal parameter

..................................................................................................................................

Notre conseil suivi sans rchir ne donne pas la solution.


..................................................................................................................................

> swap := proc(x, y)


local xx, yy ;
xx, yy := x, y ;
xx, yy := yy, xx ;
RETURN(NULL)
end :
> swap(a,b) ;
> a, b ;

2, 3
..................................................................................................................................

Cette fois l'erreur est vite, mais la procdure est sans eet sur les aectations
de a et b ; seules les aectations internes la procdure ont t modies. Il faut
donc ncessairement s'organiser pour passer les symboles eux-mmes et non pas
leur valeur. C'est un peu audacieux, car le conseil ci-dessus n'est plus respect. De
plus l'appel de swap doit citer les symboles quots, car leur valuation doit tout
prix tre empche. D'o cette (tentative de) solution.
..................................................................................................................................

> swap := proc(x::symbol, y::symbol)


x, y := y, x ;
RETURN(NULL)
end :
> swap(a, b) ;

Error, swap expects its 1st argument, a, to be of type symbol, but received 2

> swap('a', 'b') ;


> a, b ;

Error, too many levels of recursion

..................................................................................................................................

Il est judicieux ici de dclarer les paramtres symbol1 de faon intercepter


l'erreur de l'utilisateur qui oublie de quoter les symboles dans l'appel de la procdure swap, comme montr dans le premier appel de cette nouvelle forme de la
procdure. Dans le deuxime appel les quotes ne sont pas oublis, et l'appel apparemment russit, mais la vrication engendre une nouvelle erreur, parce que,
compte tenu du fait que les arguments substitus ne sont pas rvalus, on a en
dnitive install les chanages [a b] et [b a] dans l'environnement qui
provoquent l'erreur de rcursion dj observe page 2.3.2 :
..................................................................................................................................

> eval([a,b], 1) ;

[b, a]
1 Une

dclaration name est plus logique et a une porte plus gnrale.

174

..................................................................................................................................

Une bonne ( ?) solution est donc la suivante :


..................................................................................................................................

> a, b := 2, 3 ;

a, b := 2, 3
> swap := proc(x::symbol, y::symbol)
x, y := eval(y), eval(x) ;
RETURN(NULL)
end :
> swap('a', 'b') ;
> a, b ;
3, 2
..................................................................................................................................

Mais cette solution est peu lgante : les quotes toujours ncessaires dans
l'appel sont franchement pnibles. C'est prcisment dans une telle situation qu'il
faut songer l'autre mthode disponible de passages d'arguments, qu'on examinera
un peu plus loin.

6.4.2 Pige base de mots rservs.


On examine dans cette section un type de bug assez pervers d au problme,
prsent dans tous les langages, des mots rservs, mais qui induit sous Maple,
cause du mcanisme de substitution paramtre-argument, des bugs trs tranges.
Typiquement, le symbole list est rserv, toute tentative d'aectation ce symbole est refuse :
..................................................................................................................................

> list := [1,2,3,4] ;

Error, attempting to assign to `list` which is protected

..................................................................................................................................

ce qui oblige l'utilisateur en panne d'inspiration de choisir des variantes comme


list_ (le blanc soulign est lgal), lst, etc. C'est un tout petit peu dsagrable, de
sorte que quand on dcouvre qu'au contraire, pour les paramtres ou les symboles
locaux de procdures, ces symboles redeviennent possibles, on est ravi de cette
libert retrouve.
..................................................................................................................................

> list_list := proc(list)


RETURN([op(list), op(list)])
end :
> list_list([1,2,3]) ;

[1, 2, 3, 1, 2, 3]
..................................................................................................................................

Cette procdure exercice met bout bout deux exemplaires de la liste argument. En mal d'inspiration pour le nom du paramtre, pourquoi ne pas choisir
simplement list ? Or ceci est tout--fait lgal pour un nom de paramtre, comme
on peut le voir. Les utilisateurs prennent ainsi rapidement l'habitude d'appeler set
l'unique paramtre ensemble, matrix l'unique paramtre matrice, etc. Mais considrons le petit exercice suivant. Soit crire une procdure liminant les doublons
d'une liste d'entiers, et triant la liste d'entiers rsultante.
175

..................................................................................................................................

> clean := proc(list)


RETURN(sort(convert(convert(list, set), list)))
end :

..................................................................................................................................

La conversion en ensemble (set) limine automatiquement les ventuels doublons, voir page 108 ; ceci fait, on reconvertit l'ensemble obtenu en liste, qu'enn
on trie. Essai :
..................................................................................................................................

> clean([2,1,2,3]) ;

Error, (in clean) wrong number (or type) of parameters in function convert

..................................................................................................................................

La procdure convert est en dlicatesse. Un examen soigneux montre immdiatement la confusion : le deuxime argument list du convert externe est valu
avant d'tre utilis, car convert est une procdure standard. L'erreur est facile
corriger : pour empcher cette valuation intempestive, il sut de quoter cette
occurence-l du symbole list :
..................................................................................................................................

> clean := proc(list)


RETURN(sort(convert(convert(list, set), 'list')))
end :
> clean([2,1,2,3]) ;

Error, (in clean) wrong number (or type) of parameters in function convert

..................................................................................................................................

et on a la mauvaise surprise de constater que l'erreur est exactement la mme,


de quoi rester perplexe ! C'est le moment o jamais de penser un moyen de
debugging franchement rustique, mais qu'il ne faut jamais oublier, consistant
excuter soi-mme, hors procdure, une une, les instructions fautives ; mais
ici c'est impossible, car il n'est pas lgal, hors procdure, d'aecter une valeur au
symbole list ; moins de lever la protection sur le symbole list, ce qui donne
l'essai suivant.
..................................................................................................................................

> list := [2,1,2,3] ;

Error, attempting to assign to `list` which is protected

> unprotect(list) ;
> list := [2,1,2,3] ;

list := [2, 1, 2, 3]
> sort(convert(convert(list, set), 'list')) ;
[1, 2, 3]
..................................................................................................................................

et on constate que cette fois l'erreur ne se produit pas. Nous sommes l dcidment
dans un cas de debugging plus que svre ! Mais que peut bien expliquer tout cela ?
L'erreur commise ici rsulte d'une incomprhension fondamentale du mcanisme de transmission argument vers paramtre. Il est erron de penser que le
paramtre est un symbole ayant, lors d'une valuation, telle valeur dduite de l'argument dnitif. Ce n'est pas le bon point de vue, et c'est cette erreur de point
de vue qui engendre ces birarreries en srie. En fait le paramtre est une composante de texte, et l'argument est substitu cette composante de texte paramtre
l'invocation de la procdure. Pour provoquer hors procdure la mme erreur, il
176

faut procder comme suit :


..................................................................................................................................

> eval(subs('list'=list,
'sort(convert(convert(list, set), 'list'))')) ;
Error, wrong number (or type) of parameters in function convert

..................................................................................................................................

ou, en style plus dcompos :


..................................................................................................................................

> subs('list'=list,
'sort(convert(convert(list, set), 'list'))') ;
sort(convert(convert([2, 1, 2, 3], set),0 [2, 1, 2, 3]0 ))
> eval(%) ;
Error, wrong number (or type) of parameters in function convert

..................................................................................................................................

et on observe l une proprit logique mais franchement perverse du mcanisme


de substitution : la substitution est applique mme dans les expressions quotes,
ce qui simule vaguement une valuation tout prix, mme sous les quotes !
Ci-dessus la substitution a remplac 'list' par '[2, 1, 2, 3]', donnant l'impression que list a t valu.
Pour mettre en vidence ce phnomne sous procdure, considrons l'exemple
articiel mais dcisif :
..................................................................................................................................

> test := proc(parameter)


local var ;
var := 'parameter' ;
RETURN('parameter')
end :
> debug(test) ;

test

> test(argument) ;
{--> enter test, args = argument

var := argument

<-- exit test (now at top level) = argument}

argument
..................................................................................................................................

On voit ici que les quotes n'ont pas empch la substitution de parameter par
argument.
Revenons notre exemple initial. La seule faon de le debugger si on veut
garder le mme style de programmation consiste ne pas utiliser le symbole list
comme paramtre. On commence d'abord par remettre le symbole list dans son
tat normal, sans valeur et protg.
..................................................................................................................................

> unassign('list') ; protect(list) ;


> clean := proc(lst)
RETURN(sort(convert(convert(lst, set), list)))
end :
> clean([2,1,2,3]) ;
[1, 2, 3]

..................................................................................................................................

Autre mthode bien amusante, mais qu'on ne peut pas dcemment conseiller :
177

..................................................................................................................................

> clean := proc(list)


RETURN(sort(convert(convert(list, set), li.st)))
end :
> clean([2,1,2,3]) ;
[1, 2, 3]

..................................................................................................................................

On a russi ainsi cacher le symbole list par l'intermdiaire de l'expression li.st ;


Maple ne voit pas l en eet dans le texte de la procdure une occurence du symbole
list, mais une expression de concatnation sur les deux symboles li et st ; quand,
plus tard, cette expression est value, Maple a oubli la liaison de list vers
[2,1,2,3], car cette liaison, plus prcisment la substitution paramtre-argument,
n'est utilise qu' l'invocation de la procdure ; elle n'est plus utilise ensuite.
Ces considrations semblent sans doute exagrment minutieuses, mais elles
sont invitables dans un langage o les symboles jouent un rle double : d'une
part, comme dans les langages ordinaires, reprer telle ou telle expression valeur
de ce symbole, d'autre part servir d'tiquette pour donner telle ou telle indication,
notamment une indication de variable formelle sans valeur, ou encore une indication de type. Vouloir faire jouer simultanment les deux rles au symbole list
est donc assez casse-cou, et c'est ce coup d'audace qui est l'origine de ces bugs
assez diciles.

6.4.3 Exclure l'valuation d'un argument.


Le langage Pascal prvoit la possibilit, option var, de passer une procdure
la rfrence d'une variable et non pas sa valeur ; ceci permet de modier, de l'intrieur de la procdure, la valeur 2 de la variable passe. Par le jeu des pointeurs
et rfrences, les langages C et Java orent des possibilits encore plus larges. Le
langage Lisp spare soigneusement les appels de fonctions des appels de macros,
avec une structure beaucoup plus tudie, beaucoup plus puissante aussi, mais
ncessitant souvent quelque syntaxe sotrique dans l'criture des fonctions et macros, sans parler des macros gnratrices de macros, notion hors de porte des
autres langages. Maple est aussi plus ou moins de cette nature, en fait impose par
la nature dynamique des symboles : un symbole en Maple, comme en Matlab,
comme en Lisp, reste vivant l'excution, sa valeur n'tant accessible que par
un mcanisme d'valuation, modlisant en fait une indirection pointeur.
C'est par l'intermdiaire d'un contrle soigneux du mcanisme d'valuation
que l'utilisateur Maple pourra manipuler dans une procdure des chanages varis
passs en argument par l'intermdiaire de leur source. Le principe de base est assez
simple : si un paramtre est dclar uneval, l'argument correspondant l'appel
de la procdure ne sera pas valu. La procdure disposera donc de la source
potentielle d'un chanage et pourra le modier sa guise. L'exemple prototype est
bien sr celui de la procdure swap dont la version prsente maintenant est idale.
2 En

fait le contenu de la zone mmoire rserve pour cette variable.

178

..................................................................................................................................

> restart :
> swap := proc(x::uneval, y::uneval)
x, y := eval(y), eval(x) ;
RETURN(NULL)
end :
> a, b := 2, 3 ;
a, b := 2, 3
> swap(a,b) ;
> a, b ;
3, 2

..................................................................................................................................

L'appel de la procdure swap est maintenant confortable : il n'est plus ncessaire


de quoter les arguments, compte tenu de la dclaration uneval pour les paramtres
de la procdure. Noter toutefois qu'un utilisateur appliquant le rituel principe de
prcaution, autrement dit quotant  tout hasard les arguments, a maintenant
une erreur.
..................................................................................................................................

> swap('a', 'b') ;

Error, (in swap) illegal use of a formal parameter

..................................................................................................................................

car le mcanisme de substitution, combin avec les dclarations uneval, engendre


l'instrution suivante :
..................................................................................................................................

> 'a', 'b' := eval('a'), eval('b') ;

..................................................................................................................................

qui est videmment errone. L'exercice suivant pour le perfectionniste consiste


donc cocooner l'utilisateur de la procdure swap de telle faon que si jamais
il quote tort la variable changer, alors l'erreur est dtecte et corrige de
l'intrieur de la procdure. Comment obtenir un tel rsultat ? Il faut alors savoir
reconnatre si l'argument est quot ou non. L'objet quot est de type uneval :
..................................................................................................................................

> whattype(''expr'') ;

uneval

..................................................................................................................................

Noter qu'il a t indispensable de quoter deux fois pour qu'il reste une expression
quote aprs valuation de l'argument, car whattype est une procdure standard ;
comparer avec :
..................................................................................................................................

> whattype('expr') ;

symbol
..................................................................................................................................

La nouvelle procdure swap est assez technique, typique de ce type de manipulation de chanage, et va aussi mettre en vidence un caractre particulier aux
symboles locaux.

179

..................................................................................................................................

> swap := proc(x::uneval, y::uneval)


local xx, yy, xval, yval ;
xx , yy := x, y ;
if type(xx, uneval) then xx := op(1, xx) fi
if type(yy, uneval) then yy := op(1, yy) fi
if not type(xx, name) then ERROR(`%a should
if not type(yy, name) then ERROR(`%a should
xval, yval := eval(xx), eval(yy) ;
print('arg1' = x, 'arg2' = y,
'xx' = xx, 'yy' = yy,
'xval' = xval, 'yval' = yval) ;
assign(xx = yval, yy = xval) ;
RETURN(NULL)
end :

;
;
be a name`, xx) fi ;
be a name`, yy) fi ;

..................................................................................................................................

Pour bien faire comprendre le fonctionnement de cette nouvelle mouture de


notre procdure, on a ajout, juste avant que l'change se ralise (instruction
assign), un achage de toutes les variables et paramtres en jeu. Exemples typiques de fonctionnement :
..................................................................................................................................

> a, b := 2, 3 ;

a, b := 2, 3
> swap(a, b) ; a, b ;
arg1 = a, arg2 = b, xx = a, yy = b, xval = 2, yval = 3
3, 2
> swap('a', 'b') ; a, b ;
arg1 = 0a0 , arg2 = 0b0 , xx = a, yy = b, xval = 3, yval = 2
2, 3
> swap(a, a+b) ;
Error, (in swap) a+b should be a name.

> lst := [[1,2], [3,4]] ;

lst := [[1, 2], [3, 4]]


> swap(lst[1,1], lst[2,2]) ; lst ;
arg1 = lst[1, 1], arg2 = lst[2, 2], xx = lst[1, 1], yy = lst[2, 2], xval = 1, yval = 4
[[4, 2], [3, 1]]
..................................................................................................................................

D'abord il a fallu utiliser des variables locales xx et yy pour pouvoir manipuler les arguments, surtout supprimer les quotes ventuels : ils sont reprs par
type(..., uneval) et le cas chant, ils sont supprims par xx := op(1, xx), qui
extrait l'unique oprande, donc l'objet entre quotes. Demander xx := xx est insufsant, parce que pour un symbole local, un seul niveau d'valuation est eectu,
de sorte que la valeur de xx resterait en fait inchange.

Eval 29  Un symbole local une procdure ne suit pas la rgle Eval-7 ; quand il
est valu, le rsultat est seulement le but du chanage correspondant ; en particulier
ce but n'est pas rvalu.
Considrez l'exemple suivant, trs exotique, pour mettre en vidence cette particularit des symboles locaux par rapport l'valuateur.
180

..................................................................................................................................

> restart ;
> c := d ;

c := d

> test := proc(x::uneval)


global a ;
local b ;
a := b ;
b := x ;
print(a, b, eval(b))
end :
> test(c) ;
d, c, d
..................................................................................................................................

Plusieurs chanages de dirents types sont installs. D'abord un chanage banal


entre symboles externes [c d]. Puis le symbole a est dclar global et a donc le
statut d'un symbole externe mais visible de l'intrieur de la procdure, alors que
le symbole b est local la procdure ; les guillemets sont l pour prparer le
lecteur une nouveaut : on va nanmoins russir faire survivre ce symbole
l'extrieur de la procdure ! Dans la procdure, des chanages [a b] et [b c]
sont installs, car l'appel de test(c), le texte x est remplac par le symbole c.
Puis on regarde par curiosit les valeurs de a, b et eval(b). On a la stupfaction
d'observer que dans le traitement des chanages successifs de a vers b puis c puis
d, si on part de a on va jusqu' d, alors que si on part de b on s'arrte c ! On
voit nanmoins que eval(b) atteint d.
Pourquoi ? Dans la procdure, b est local et son valuation arrte donc au but
du chanage correspondant ; c'est une consquence de la rgle Eval-29. Au contraire
a est global et c'est la rgle Eval-7 qui est applique : son valuation va donc aussi
loin que possible. Tout se passe comme si ce n'tait pas le mme valuateur qui
travaillait pour les symboles globaux et les symboles locaux ! Considrez encore
ces tests ultrieurs, encore plus exotiques :
..................................................................................................................................

> a ;

> eval(a,1), eval(a,2), eval(a,3) ;


b, c, d
> evalb(b = b), evalb(b = eval(a,1)) ;
true, false
> {b, eval(a, 1)} ;
{b, b}
> addressof(%[1]), addressof(%[2]) ;
8857168, 8857184
..................................................................................................................................

Le symbole a avait t dclar global et continue vivre en dehors de la procdure, valeur conserve. Les eval(a,-) permettent de suivre la chane de. . . chanages partant de a. En particulier le symbole b, en principe local la procdure
test, reste accessible de l'extrieur, par l'intermdiaire de a, alors que l'invocation
de la procdure qui avait cr ce symbole est acheve ! Si on compare ce symbole b
l un symbole b banal, on constate qu'ils sont dirents ! Notre environnement
181

a maintenant deux symboles de mme nom, dont l'un est accessible seulement par
l'intermdiaire de a. On constate d'ailleurs que l'ensemble constitu de ces deux
symboles a bien deux lments : pas d'limination de doublon puisqu'il n'y a pas
de doublon ! On vrie enn que les adresses machines de ces symboles sont bien
direntes.
Ces questions ne sont en aucune faon articielle. Frquemment quand une
procdure retourne par exemple une matrice, on cite seulement le symbole reprant
cette matrice, et en raison de la rgle Eval-16, le symbole seul est retourn.
nouveau, des crises de nerfs sont proches si on compare ces deux exemples.
..................................................................................................................................

> testm := proc()


local A ;
A := matrix([[1,2],[3,4]]) ;
RETURN(A)
end :
> testm() ;

> evalm(A) ;
A
..................................................................................................................................

Dans ce premier essai, l'utilisation de evalm ne permet pas d'atteindre la matrice qui avait t aecte A. Le point, c'est que le symbole retourn, local, est
dirent du symbole A argument de evalm ! Comparez avec cet autre essai :
..................................................................................................................................

> B := testm() ;

B := A

> evalm(B) ;

1 2
3 4

..................................................................................................................................

Cette fois la valeur de B est le bon symbole A, de sorte que evalm atteint le but
recherch. Avez-vous bien compris toutes ces choses ? Si oui, vous ne rsisterez pas
tenter ceci :
..................................................................................................................................

> A := testm() ;

A := A

> eval(A,1) ;
A

> eval(A,2) ;

1 2
3 4

..................................................................................................................................

o on joue atteindre la matrice en partant du A global, en passant par le A local.

6.4.4 Nombre variable d'arguments.


Comme dj expliqu, le mcanisme est rustique mais rend l'utilisateur absolument libre pour toute organisation. Pour expliquer rapidement ce dont il s'agit,
rappelons-nous, voir page 112, que la procdure prdnie Maple max admet comme
182

argument une suite de rels ; l'utilisateur a l'impression, pas compltement justie, que cette procdure admet un nombre quelconque d'arguments . Programmons
nous-mme cette procdure pour montrer le principe.
..................................................................................................................................

> my_max := proc()


local i, result ;
print(nargs) ;
print(args) ;
result := -infinity ;
for i from 1 to nargs do
if args[i] > result then result := args[i] fi
od ;
RETURN(result)
end :
> my_max() ;
0

> my_max(4,6,5) ;
3
4, 6, 5
6

..................................................................................................................................

Le principe est fort simple. Deux variables locales sont disponibles dans toute
procdure, nargs et args. Elles sont automatiquement initialises par Maple
chaque invocation de la procdure. La premire, nargs, a pour valeur le nombre
d'arguments passs l'appel de cette invocation, ou plus prcisment la longueur
de la suite qui est en fait l'unique argument vritable, voir ce qui a dj t expliqu
propos des suites d'arguments Section 4.4.
Bien comprendre que ce mcanisme est disjoint de l'utilisation standard des
arguments, l'aide de la liste de paramtres proc(prm1, prm2, ...). Ici, dans
la procdure my_max, on n'a mme prvu aucun paramtre, la liste d'arguments
tant entirement gre par l'intermdiaire des variables nargs et args. Noter la
programmation complte conssistant considrer comme lgal un appel de la procdure my_max sans argument, ce qui est d'ailleurs trait de la mme faon par la
procdure ocielle max, essayez.
Pour rendre plus visible ce mcanisme, la programmation donne ici de my_max
ache au dvut de l'activation de la procdure les valeurs des variables nargs et
args.
Rien n'empche de combiner le mcanisme banal base de symboles paramtres
et les informations disponibles par l'intermdiaire des variables implicites nargs et
args.
Commenons par un exemple articiel mais didactique.

183

..................................................................................................................................

> test := proc(prm1, prm2)


local i ;
printf("Cet appel de la procdure test a %a arguments.\n", nargs) ;
printf("Arg1 = %a.\n", prm1) ;
printf("Arg2 = %a.\n", prm2) ;
for i from 3 to nargs do
printf("Arg%a = %a.\n", i, args[i])
od ;
printf("The end.")
end :
> test(foo1, foo2, foo3, foo4) ;
Cet appel de la procdure test a 4 arguments.
Arg1 = foo1.
Arg2 = foo2.
Arg3 = foo3.
Arg4 = foo4.
The end.

..................................................................................................................................

On a pass quatre arguments la procdure, dont deux ont t lus par l'intermdiaire des paramtres prm1 et prm2, et les autres par celui de la variable args ;
leur nombre a t dduit de nargs.
Comme application signicative de ce mcanisme, reprenons le problme de
la programmation rcursive de la procdure mylog10 de la page 149. On avait
not le danger, trs rel, d'une variable globale epsilon dnie par la procdure
matresse mylog10, puis utilise par la procdure moteur phi : si l'utilisateur a
pour d'autres raisons une variable dj baptise epsilon, l'ancienne valeur de cette
variable serait perdue ! Le nom de procdure phi n'est pas non plus bien fantastique
et risque d'interfrer avec un autre symbole. On pourrait utiliser ici pour mettre en
vidence la dpendance de la seconde procdure un nom plus explicite ce propos
comme `mylog10/phi` ; Maple utilise souvent lui-mme cette technique pour ses
propres procdures. Autre problme : la prcision associe la variable epsilon
n'est pas modiable, alors qu'il serait bien plus intressant de laisser l'utilisateur
la possibilit ventuelle de prfrer une autre prcision.
On va solutionner l'ensemble de ces problmes comme suit :
..................................................................................................................................

> mylog10 := proc(x::positive)


local phi, epsilon ;

phi := proc(alpha::realcons, beta::realcons, gamma::positive)


if gamma=1. then RETURN(alpha) fi ;
if gamma<1. then RETURN(phi(alpha, -beta, 1/gamma)) fi ;
if gamma>=10. then RETURN(phi(alpha+beta, beta, gamma/10.)) fi ;
if alpha<>0. and abs(beta/alpha)<epsilon then RETURN(alpha) fi ;
RETURN(phi(alpha, beta/2., gamma^2))
end :

184

>
>
>
>

if nargs = 2 then epsilon := args[2]


else epsilon := 1e-10
fi ;
RETURN(phi(0., 1., convert(x,float)))
end :
mylog10(2) ;
.3010299956
mylog10(2, 1e-5) ;
.3010292053
Digits := 20 :
mylog10(2, 1e-20) ;
.30102999566398119522

..................................................................................................................................

L'utilisateur a maintenant la possibilit de donner un deuxime argument pour


refuser la valeur par dfaut de epsilon. La prsence de l'argument optionnel est
dtecte par examen de nargs. Par ailleurs le fait d'avoir dni la procdure phi
l'intrieur de la procdure mylog10 la rend invisible de l'extrieur ; la variable
epsilon est maintenant locale mais nanmoins visible de la procdure phi ; tout
usage global de phi et epsilon peut maintenant coexister sans interfrence avec
les usages internes mylog10 de ces symboles.
..................................................................................................................................

> Digits := 10 :
> phi, epsilon := 56, 0.01 ; mylog10(3) ; phi, epsilon ;
, := 56, .01
.4771212547
56, .01

..................................................................................................................................

6.4.5 Arguments mots-cls.


La variable args permet en particulier d'utiliser un mcanisme d'arguments
mots-cls, trs utilis par Maple lui-mme dans ses propres procdures. Typiquement, quand vous utilisez la procdure plot pour tracer une courbe, la couleur
par dfaut de la courbe est rouge, mais vous pouvez modier cette couleur par un
argument mot-cl color. Exemple de trac sans couleur indique :
..................................................................................................................................

> plot(sin, 0..2*Pi) ;

..................................................................................................................................

Pour une raison ou une autre, cette couleur peut tre juge non satisfaisante ;
Maple vous donne la possibilit d'un troisime argument, optionnel, permettant
de demander une autre couleur.

185

..................................................................................................................................

> plot(sin, 0..2*Pi, color=blue) ;

..................................................................................................................................

On a utilis ici l'argument mot-cl color. Noter que l'unique argument supplmentaire est l'objet de type equation color=blue, donc un seul objet oprateur
`=', et oprandes color et blue. C'est la procdure plot qui analyse cet argument, en dduit notamment qu'il s'agit de modier la couleur par dfaut, et fait
le ncessaire pour tenir compte de l'indication blue qui est donne.
Un grand nombre d'arguments mot-cl sont disponibles pour les procdures
graphiques, donnant beaucoup de possibilits l'utilisateur pour obtenir telle ou
telle particularit dans le rsultat. Par exemple on peut en plus souhaiter un trac
plus pais (argument mot-cl thickness) et en trait non continu (argument
mot-cl linestyle).
..................................................................................................................................

> plot(sin, 0..2*Pi, thickness=5, color=coral, linestyle=3) ;

..................................................................................................................................

Voir la page de documentation plot,options pour avoir une ide des diverses
possibilits proposes, assez vastes. Ce qui est trs commode dans ces arguments
mot-cl, c'est le fait qu'ils sont utilisables en nombre arbitraire et dans un ordre
arbitraire. Comparer le trac prcdent avec le suivant.
..................................................................................................................................

> plot(sin, 0..2*Pi, linestyle=3, color=coral, thickness=5) ;

..................................................................................................................................

Il serait en eet franchement dsagrable de contraindre l'utilisateur prciser tous les arguments optionnels et avec un ordre impos ; on prfre dnir
ces arguments par dfaut, et laisser l'utilisateur la possibilit d'en modier un
nombre quelconque en gnral assez modeste. Comment obtenir un tel rsultat
dans l'criture d'une procdure ?
186

Prenons par exemple le cas d'une procdure de traitement de liste assez souvent
utile retournant la position de tel lment, premier argument, dans telle liste,
deuxime argument. La programmation la plus simple peut-tre la suivante.
..................................................................................................................................

> position := proc(element::anything, list::list)


local i ;
for i from 1 to nops(list) do
if element = list[i] then RETURN(i) fi
od ;
RETURN('not_found')
end :
> position(4, [3,6,4,7,9,4]) ;
3
> position(44, [3,6,4,7,9,4]) ;
not_found

..................................................................................................................................

Ceci dit un certain nombre d'options donnes l'utilisateur pourraient augmenter sensiblement la porte de cette procdure. En particulier on peut donner
la possibilit de prciser une fonction de comparaison dirente de l'galit usuelle
pour la comparaison entre l'lment  chercher et les lments de liste examiner. On pourrait donc comme dj fait utiliser un troisime argument optionnel ; si
l'argument ne gure pas, on utilise la comparaison standard, sinon la comparaison
propose.
..................................................................................................................................

> position2 := proc(element::anything, list::list)


local i, comp_func ;
if nargs = 2 then comp_func := `=`
else comp_func := args[3]
fi ;
for i from 1 to nops(list) do
if comp_func(element, list[i]) then RETURN(i) fi
od ;
RETURN('not_found')
end :
> position2(4, [3,6,4,7,9,4]) ;
3
> position2(4, [3,6,4,7,9,4],
proc(x,y) (y-x) mod 2 = 0 end) ;
2

..................................................................................................................................

Mais d'autres options sont tentantes pour le dveloppeur. Par exemple on peut
aussi demander de ne considrer qu'une sous-liste de la liste argument, considrant
que le reste de la liste n'est pas concern par la recherche de position. On peut
aussi considrer plus intressant dans certains cas de commencer par la n. On
voit que les combinaisons d'options peuvent tre trs varies et c'est justement le
cas o il faut penser arguments mots-cls.
On va ici prvoir quatre arguments mot-cl :
 cmpr : pour une fonction de comparaison dirente de la comparaison standard.
187

 strt : pour commencer l'examen partir d'une position dirente de 1.


 endd : pour nir l'examen avant la n de la liste ; end est rserv et il faut un
autre mot-cl.
 rvrs : pour prciser qu'il faut commencer l'examen par la n.
Comment grer cette varit de cas ? Une procdure auxiliaire de recherche de
valeur ventuelle d'argument mot-cl va nous aider. C'est une procdure trois
arguments, le mot-cl, la liste o la recherche est faite et la valeur par dfaut si
l'argument n'est pas trouv.
..................................................................................................................................

> kw_arg := proc(keyword::symbol, list::list, default::anything)


local i ;
for i from 1 to nops(list) do
if type(list[i], equation) and keyword = lhs(list[i])
then RETURN(rhs(list[i]))
fi
od ;
RETURN(default)
end :
> kw_arg(strt, [endd=34, rvrs=true], 1) ;
1
> kw_arg(strt, [strt=3, endd=34, rvrs=true], 1) ;
3

..................................................................................................................................

Pour chaque lment de la liste examiner, on regarde si cet lment est un


objet equation et, si oui, si le membre de gauche (lhs = lefthand side) est le bon
mot-cl. Le cas chant, le membre de droite de l'quation est retourn. Sinon,
si la liste est puise sans succs, on retourne la valeur par dfaut indique en
argument.
Maintenant la programmation de la procdure position est divise en deux
tapes : d'une part le traitement des options, d'autre part la programmation proprement dite. Une programmation professionnelle devrait prvoir tous les cas plausibles d'erreurs d'arguments, ce qui n'est pas notre sujet et n'a pas t fait ici. Noter
d'ailleurs que le perfectionnisme en la matire est souvent dangereux dans un langage la structure aussi oue que celui de Maple, le statut vritable des symboles
chappant presque toujours l'utilisateur ordinaire.

188

..................................................................................................................................

> position3 := proc(element::anything, list::list)


local i, opts, lcmpr, lstrt, lendd, lrvrs, step ;
opts := [args[3..-1]] ;
lcmpr := kw_arg('cmpr', opts, `=`) ;
lstrt := kw_arg('strt', opts, 1) ;
lendd := kw_arg('endd', opts, nops(list)) ;
lrvrs := kw_arg('rvrs', opts, false) ;
step := +1 ;
if lrvrs then lstrt, lendd, step := lendd, lstrt, -1 fi ;
for i from lstrt to lendd by step do
if lcmpr(element, list[i]) then RETURN(i) fi
od ;
RETURN(`not_found`)
end :
> position3(4, [3,6,4,7,9,4]) ;
3
> position3(4, [3,6,4,7,9,4],
cmpr = ((x,y) -> (x-y) mod 2 = 0)) ;
2
> position3(4, [3,6,4,7,9,4], strt=4) ;
6
> position3(4, [3,6,4,7,9,4], strt=7) ;
not_found
> position3(4, [3,6,4,7,9,4], strt=4, endd=5) ;
not_found
> position3(4, [3,6,4,7,9,4], rvrs=true) ;
6
> position3(4, [3,6,4,7,9,4], endd=5, rvrs=true) ;
3
> strt := 7 ;
strt := 7
> position3(4, [3,6,4,7,9,4], strt=7) ;
3
> position3(4, [3,6,4,7,9,4], 'strt'=7) ;
not_found

..................................................................................................................................

On note l'inuence dsastreuse d'une ventuelle valeur pour un symbole motcl ; si, par mgarde, le mot-cl strt a une valeur, ici 7, alors l'argument mot-cl
est inoprant ; c'est une source permanente de bugs quelquefois assez pervers sous
Maple, qu'on retrouve ici sous une forme un peu dirente. Comparer avec :
..................................................................................................................................

> color := 56 ;

color := 56

> plot(sin, 0..2*Pi, color=blue) ;


Error, (in plot) invalid arguments

..................................................................................................................................

Le point de vue de Maple est en eet un peu dirent ; il considre que tous les
arguments partir du troisime sont des arguments mot-cl, mais il ne reconnat
pas dans l'entier 56, valeur du symbole color, un mot-cl lgal enregistr et
189

signale une erreur de cohrence. Maple signale qu'on peut viter ce type d'erreur
en empchant l'valuation du symbole color ; c'est exact mais reste assez lourd3 .
..................................................................................................................................

> plot(sin, 0..2*Pi, 'color'=blue) ;

..................................................................................................................................

-o-o-o-o-o-o-

3 Les

langages plus volus commme Common Lisp ont un espace particulier de symbolesmots-cls, notion trop dlicate techniquement pour le grand public Maple. . .

190

Chapitre 7
Graphiques.
7.1 Introduction.
Comme (presque) tout logiciel mathmatique grand public, Maple permet
la ralisation assez commode de graphiques mathmatiques de toutes sortes. Le
mcanisme sous-jacent est astucieux et lgant et donne des moyens assez puissants
aux dveloppeurs. Le principe est le suivant ; les procdures graphiques Maple
produisent des objets (pseudo-) fonctions particuliers dont l'oprateur matre est
le symbole PLOT. Ceci fait, si jamais l'utilisateur Maple, inconsciemment (cas
le plus frquent) ou consciemment, demande l'impression de l'objet en question,
Maple ache le graphique probablement souhait par l'utilisateur.
Pour mettre en vidence cette tehnique, le truc consiste aecter un symbole exprience la valeur d'une instruction graphique ; en premire approximation,
cette instruction apparat comme telle, mais en fait il s'agit d'une procdure banale
retournant un objet de type function o l'oprateur matre est le symbole PLOT.
Reprenons le trac ftiche de la fonction sinus de 0 2 :
..................................................................................................................................

> plot(sin, 0..2*Pi) ;

..................................................................................................................................

L'utilisateur a ici l'impression d'utiliser la procdure graphique plot ; mais


organisons-nous d'une faon un peu dirente :

191

..................................................................................................................................

> result := plot(sin, 0..2*Pi) ;


result := PLOT(CURVES([[0, 0], [.1369555585245651, .1365278179668514],
[.2561198576993970, .2533288954318780], [.3901325751264872, .3803110317172750],
[.5250336158355156, .5012420929778901], [.6592934954461389, .6125585658925692],
... ...
[6.146664884637999, .1360967435821896], [6.283185294620000, .1255958650482642e7]],
COLOUR(RGB, 1.0, 0, 0)), AXESLABELS(, ), VIEW(0..6.283185308, DEFAULT))

..................................................................................................................................

On voit ainsi que l'objet retourn par la procdure plot est un objet function
dont l'oprateur est le symbole PLOT, le premier argument est son tour un objet
function dont l'oprateur est cette fois le symbole CURVES (on a renonc ici le
montrer compltement), etc. On voit ainsi la structure interne de l'objet retourn
par la procdure plot o, strictement parlant, aucun nouveau type de donne
est impliqu. C'est seulement la composante print (voir Section 2.2.2) du cycle
read-eval-print qui reconnat un traitement particulier : si jamais l'objet function
acher en sortie a l'oprateur PLOT, c'est qu'il s'agit d'un objet reprsentant
selon un codage pas si compliqu un graphique, de sorte que l'achage graphique
appropri de cet objet est donn l'cran. Pour mettre ce dernier point en vidence,
demandons l'achage de la valeur du symbole result :
..................................................................................................................................

> result ;

..................................................................................................................................

Par comparaison avec le cas de l'instruction prcdente, on voit que cet achage graphique n'est obtenu que si l'unique objet acher est de ce type, sinon
l'achage banal est prfr. Voir par exemple l'achage de la suite deux lments
o le second est encore la valeur du symbole result :
..................................................................................................................................

> 1, result ;
1, PLOT(CURVES([[0, 0], [.1369555585245651, .1365278179668514],
... ...

..................................................................................................................................

De la sorte, les objets graphiques peuvent tre manipuls comme tout objet
Maple. Comme exemple simple, transformons titre d'exercice notre courbe rouge
en courbe bleue ; il sut pour ce faire de modier l'oprande COLOUR de notre objet
graphique ; ceci est obtenu par substitution, et ici on ache immdiatement l'objet
transform :

192

..................................................................................................................................

> subs(COLOUR(RGB,1.0,0,0) = COLOUR(RGB,0,0,1.), result) ;

..................................................................................................................................

Le mode RGB pour la couleur de l'objet graphique est un triplet de rels compris
entre 0 et 1 donnant un indice pour chacune des trois couleurs fondamentales,
rouge, vert (green) et bleu. Par dfaut, un seul objet graphique est le plus souvent
ach en rouge pur, donc indices RGB = (1, 0, 0) ; on comprend ainsi comment
le rsultat aprs substitution est au contraire ach en bleu.
Comme autre exercice, on va manipuler la liste des points de notre courbe
sinusodale comme suit : on va changer la premire et la deuxime coordonne,
ralisant donc une symtrie par rapport la premire bissectrice des deux axes,
puis on augmente la premire coordonne obtenue d'une unit. Ceci peut tre
obtenu par la suite de manipulations lmentaires suivantes dont on cache les
rsultats. D'abord on extrait la composante CURVES, dont on extrait ensuite la liste
des points. Un coup de map permet de faire facilement la transformation souhaite,
optenant la liste appele points2. On construit par substitution un nouvel objet
CURVES, puis un nouvel objet PLOT qu'enn on ache :
..................................................................................................................................

>
>
>
>
>
>

curve := op(1, result) :


points := op(1, curve) :
points2 := map(item -> [item[2]+1,item[1]], points) :
curve2 := subsop(1=points2, curve) :
result2 := subsop(1=curve2, result) :
result2 ;

..................................................................................................................................

193

Bibliographie
[1] Alfred V. Aho, John E. Hopcroft, Jerey D. Ullman. The design and analysis
of computer algorithms. Addison-Wesley, 1974.
[2] Patrick Dehornoy, Complexit et dcidabilit. Springer, 1993.
[3] Andrew Hodges. Alan Turing : the enigma of intelligence. Burnett Books
Limited, 1983.
[4] Serge Lang. Algebra. Addison-Wesley, 1965.
[5] Patrice Naudin et Claude Quitt. Algorithmique Algbrique. Masson, 1992.
[6] Lionel Schwartz. Mathmatiques pour la Liccence, Algbre. Dunod, 1998.
[7] Niklaus Wirth. Algorothms + Data Structures = Programs. Prentice Hall,
1976.

194

Vous aimerez peut-être aussi