Tuteur pour le langage MAPLE

novalid      

Texte du Tuteur écrit par Gilles HUNAULT

Une liste des autres tuteurs (langages, logiciels, systèmes d'exploitations...) est accessible par Mosaic...


Maple est un langage dit "fonctionnel" et mathématique, comme Mathematica.

Une discussion sur cette notion, une comparaison avec Apl et Lisp est accessible en cliquant sur cette ligne.

Table des matières

1. Présentation générale de Maple

   1.1. Syntaxe de Maple
   1.2. Principes de programmation
        - Actions élémentaires
        - Syntaxe des Tests et Boucles
   1.3. Exemples de structure d'un package
   1.4. Exemples de fonctions

2. Programmation en Maple

   2.1. Les fonctions en Maple
   2.2. Structure d'une fonction
   2.3. Paramètres et filtrage
   2.4 Quelques exemples
       - Une fonction qui calcule les points sur un intervalle
       - Une fonction avec "list-ability"

3. Maple : Une session commentée

4. Maple : Quelques "trucs"

   4.1 Chargement des programmes
   4.2 Affichages simples
   4.3 Entrées clavier
   4.4 Affichages cadrés
   4.5 Lecture sur fichier

5. Maple et les mathématiques formelles

   5.1 Factorisation de polynomes
   5.2 Résolution d'équations de récurrences
   5.3 Equations matricielles
   5.4 Equations sur densité de probabilité


1. Présentation générale de Maple

Maple est à la fois :

   - un ensemble de primitives de calculs
   - un outil de calcul numérique et de calcul formel
   - un langage de programmation
   - un outil de visualisation graphique

1.1. Objets et Syntaxe sous Maple :

Les objets manipulés sont :

   - des nombres comme 1./3 et 2^92
   - des valeurs formelles comme 1/3 et (x+y)^3
   - des listes comme [1,17,5,1], des ensembles comme {1,2,a}
   - des vecteurs comme [1,17,5,1], des matrices comme [ [a,b],[c,d] ]
   - des énumérations comme 1,2,3,4,5 ou comme x = 1, y = 2...

Les fonctions agissent sur ces objets :

   - sin(x) et sin(arccos(x)) sont des appels de fonctions.
   - BesselJ(x,y) est une fonction élémentaire,
   - plot3d et charpoly(M,v) aussi .

Pour apprendre Maple, on travaille en deux temps, comme pour tout
langage  interprété : d'abord on apprend les fonctions, les emboitements
d'instructions ; ensuite on programme. L'utilisation interactive ne pose
aucune difficulté, il faut seulement ne pas oublier de mettre un
point-virgule en fin d'instruction (même au bout de plusieurs lignes
physiques sur l'écran) - voir un peu plus loin la session commentée.

Il faut toutefois un certain temps avant de bien connaitre les centaines
de fonctions Maple. Ainsi, la résolution d'équations se fait par solve,
isolve, msolve, dsolve... et les résultats peuvent être contraints par
assume, utilisés par assign...

Un tour rapide de Maple est effectué par un survol des fonctions

 sum         pour calculer des sommes
 ifactor     pour factoriser en produit d'entiers
 solve       pour résoudre une ou plusieurs équations
 diff        pour dériver, différencier
 dsolve      pour résoudre des équations différentielles
 plot        pour tracer des courbes ou des solutions d'ED
 fsolve      pour résoudre numériquement les équations
 rsolve      pour résoudre des équations de récurrence
 int         pour intégrer des fonctions
 matrix      pour définir une matrice
 eigenvals   pour calculer des valeurs propres
 series      pour calculer la série de Taylor
 limit       pour évaleur une limite

 Comme pour d'autres langages (notamment 
 Mathématica), la représentation interne
 des expressions oblige parfois à développer, réduire, ordonner, simplifier, etc.
 Les fonctions associées sont expand,simplify,normal...

1.2. Principes de programmation :


Actions élémentaires

   - un commentaire est repéré par #
     un point-virgule termine une instruction
   - le symbole : termine une instruction
     (aucun affichage, contrairement au symbole ;)
   - le symbole := réalise l'affectation
   - readstat et readline effectuent une entrée
   - print, printf et lprint effectuent les sorties
   - args et nargs gèrent les paramètres passés

Syntaxe des Tests et Boucles

   - If condition then instructions [else instructions] fi ;
     effectue un test
   - For var from ...  to ... do instructions od ;
     est une boucle de taille fixe
   - While test do instructions od  ;
     est une itération conditionnelle

De nombreuses primitives et constructions évitent ces structures.
En particulier les fonctions peuvent agir sur des listes en
s'exécutant pour chaque élément de la liste, les opérations
classiques peuvent aussi travailler sur des listes, les ensembles,
les matrices, les fonctions en mode terme à terme automatique.

De plus, un opérateur comme $ génère dynamiquement une énumération
convertible en liste, ensemble, vecteur...

Ainsi la table de multiplication de n peut se faire soit en
programmant une boucle explicite

Algorithme   { n est connu, on néglige le cadrage }
             pour i de 1a 10
               écrire i," fois ", n , " = " , i*n
             finpour


Maple  For i from 1 to 10 do ;
                lprint(i,` fois `, n , ` = ` , i*n ) ;
       od ; # fin de boucle


soit en utilisant les fonctions sur listes :


   map(x->lprint(x,` fois `,n,` = `,x*n),{$1..10}) ;



Ainsi, pour trouver les Nombres de Mersenne qui sont
de la forme (2^p)-1 où p est premier qui sont eux-mêmes
premiers, pour p entre 1 et z, on peut utiliser l'expression

map(p->if isprime(p)and isprime(2^p-1)then p; fi ,[$1..z]);

Pour z = 150, il y en a 12, donnés pour p dans :
   {2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127}

Autre exemple : si on prend 10 nombres pseudo-aléatoires
entre 0 et 100, pour savoir combien (et lesquels) sont
supérieurs à 50, on écrit

   y := map(rand(100),[$1..10] ) ;
   convert(map(x -> if x > 50 then 1 ; fi ,y  ),`+`) ;

Leur position dans la liste est donnée par :

     map(x -> if x>50 then pos(x,y) ; fi , y) ;    

où pos est la fonction définie en 1.4


1.3. Exemples de structure d'un package


Un package permet de regrouper des fonctions et variables,
des textes d'aides et d'explications liées à un
même problème. Il est conseillé de suivre
la structure suivante :

#  commentaires de présentation :
#    - auteurs
#    - références mathématiques etc.

package[fonction_1] := ...

package[fonction_2] := ...

package[fonction_3] := ...

# aides contextuelles
help/text/packages := TEXT(
,
CALLING SEQUENCE:,
 (args),
 package[](args),
,
SYNOPSIS:
,
- explications diverses
- liste des fonctions...
) :


1.4. Exemples de fonctions

pos := proc(x,y)

local z ; # donne la position de x dans la structure y ou (vide) # par exemple pos( 3 , [1,3,4,8] ) renvoie 2 car 3 est le 2ème élément. for z from 1 to nops(y) do ; if op(z,y) = x then RETURN(z) ; fi ; od ; RETURN() ; end ;

Ls2Mat := proc()

# convertit une structure de système L en matrice local regprod,nbprod,varis,nbvar,matrice,lig,col,optsys ; # rappel de la syntaxe if nargs=0 then lprint(`Fonction Ls2Mat`) ; lprint(` Syntaxe : Ls2Mat(systemL) `) ; lprint(` Exemple : matfibo := Ls2Mat(fibo) ;`) ; RETURN() else # conversion paramètres/variables regprod := args[1][2] ; # règles de production nbprod := nops(regprod) ; # nombre de règles varis := sort(convert(indets(map(indets,regprod)),list),lexorder) ; nbvar := nops(varis) ; # nombre de variables matrice := array(1..nbvar,1..nbvar); # remplissage de la matrice for col from 1 to nbvar do for lig from 1 to nbvar do matrice[lig,col] := degree(regprod[lig][2],varis[col]) ; od : od : # définition des options "système" if nargs > 1 then optsys := args[2] ; else optsys := {} ; fi ; # affichage éventuel if member(BAV,optsys) then lprint(` On dispose de `,nbprod,`règles, à savoir `) ; for lig from 1 to nbprod do lprint(` `,regprod[lig][1],` -> `,regprod[lig][2]) ; od ; lprint(` et de `,nbvar,` variables qui sont `) ; map(x->lprint(` `,x),varis) ; lprint(` Matrice renvoyée :`) ; print(evalm(matrice)) ; fi ; RETURN( evalm(matrice) ) ; fi end : # fin de Ls2Mat

2. Programmation en Maple

2.1. Les fonctions en Maple

Contrairement aux langages classiques et à l'algorithmique traditionnelle qui utilise des modules (procédures et fonctions), Maple ne travaille que par fonction. Les fonctions sont donc tour à tour des programmes ou des sous-programmes, suivant qu'ils sont appelés directement ou par d'autres fonctions. Par exemple, si on a défini une fonction f et une fonction g, alors f(x) est un "programme" de paramètre x, et f( g(x) ) est un "programme" où g est un sous-programme alors que g( f(x) ) est un "programme" oùf est un sous-programme.

2.2. Structure d'une fonction


Une fonction consiste en un ensemble de définitions,
qui peut regrouper :

   - une aide à l'utilisation de la fonction
   - les cas particuliers de valeurs
   - la déclaration et la vérification  des paramètres
   - le détail des instructions du programme

Le  squelette  "classique"  d'une  fonction  (nommée  pour   l'exemple Fm) est :

  # Commentaires pour le programmeur
  # on conseille de mettre ici les références mathématiques
  # et bibliographiques importantes
  Fm() := proc() ;
     if nargs = 0 then
     # la phrase suivante sera affichée si on tape Fm()
       print ` Fm(n) calcule 2^n -1 pour n entier`
     # on traite le cas particulier (elif est mis pour else if)
     elif args[1] = 0 then RETURN(1)
     # et le cas général *)
     else RETURN(2^args[1] - 1)
     fi ;
  end : # surtout ne pas mettre ; car sinon,
        # la valeur renvoyée est affichée

2.3. Paramètres et filtrage

Comme le montre l'exemple précédent, il est possible de tester le nombre et la valeurs des arguments. On peut de plus tester le type des arguments. Ainsi if not type([args],[name,integer]) then... permet de vérifier que l'utilisateur a bien fourni comme paramètre un nom et un entier (dans cet ordre).

2.4 Quelques exemples

2.4.1. Une fonction qui calcule les points sur un intervalle

Interv := proc() local a,b,n,h ; if nargs = 0 then print(`Interv(a,b,n) renvoie points dont le premier est a`) ; print(` et le dernier est b`) ; print(` n est facultatif ; par défaut : n=10`) ; else if nargs < 2 then ERROR(` il vous faut au moins deux paramètres numériques`) ; else a := args[1] ; b := args[2] ; if nargs <= 2 then n := 10 ; else n := args[3] ; fi ; h := (b-a)/(n-1) ; RETURN(evalm([a$n] + h*[$0..(n-1)])) ; fi ; fi ; end :

2.4.2. Une fonction avec "list-ability"

La fonction SC calcule le carré du successeur d'un nombre ; la fonction CSC calcule pour chaque élément d'une liste son SC et enfin la fonction GSC effectue ces deux actions, suivant le type du paramètre...

SC := proc(x) RETURN((x+1)^2) : end: CSC := proc(x) RETURN(map(a->(a+1)^2,[op(x)])) : end: GSC := proc(x) if nops([x]) = 1 then RETURN((x+1)^2) : else RETURN(map(a->(a+1)^2,[op(x)])) : fi ; end :

3. Maple : Une session commentée

On trouvera en colonne 1 le texte tapé, à partir de la colonne 2 la réponse éventuelle de Maple et ensuite, bien décalés, les commentaires read `/users1/maple/tuteurs/demo.prm` ; Bienvenue on vient lire le fichier des exemples la machine répond Bienvenue car la dernière ligne du fichier contient print(Bienvenue) ; Bienvenue := 1 ; 1 on affecte à la variable Bienvenue la valeur 1 Bienvenue := 2 : on affecte à la variable Bienvenue la valeur 2 Maple ne répond pas car on utilise : au lieu de ; read `/users1/maple/tuteurs/demo.prm` ; 2 Maple vient relire le fichier des exemples ; puisque Bienvenue a une valeur, c'est cette valeur qui a retournée. a := Bienvenue ; a := 2 ; Bienvenue := 3 : a ; 2 L'association entre Bienvenue et a s'est faite au moment de l'affectation a := Bienvenue ; modifier Bienvenue ne modifie donc pas a. Fm() pour l'instant Maple ne répond rien car on n'a pas entré de point-virgule. ; Fm calcule... Maple exécute le texte de la fonction Fm qui correspond à nargs = 0 CSC() ; Error, (in CSC) CSC uses a 1st argument, x, which is missing ici, par contre, la fonction n'est pas programmée pour tester le nombre d'arguments. print(CSC) ; proc(x) RETURN(map(a -> (a+1)^2,[op(x)])) end l'affichage fourni n'est pas exactement celui entré... SC(a) ; 9 c'est correct, puisque a vaut 2 et que (2+1) = 3 et que 3*3 = 9 SC(b) ; (b+1)^2 SC([$1..3]) ; ([1,2,3]+1)^2 puisque Maple ne sait pas comprend traiter une puissance de liste, il laisse l'expression là où il est rendu (mais $1..3 a été interprété). CSC([$1..3]) ; [4,9,16] par contre, CSC sait effectuer une puissance de liste... Fm(Pi) ; 2^Pi -1 Certaines valeurs, comme Pi, ne sont pas évaluées numériquement evalf(") ; 7.824977830 le symbole " désigne le dernier calcul effectué evalf(2^1994) ; .1793954211 10^601 si maple calcule de grands nombres, il faut se méfier de la taille des nombres mis en jeu : 2^ " ; Error, (in evalf/power) argument too large Interv(1,5) ; 13 17 7 25 29 11 37 41 [ 1 -- -- - -- -- -- -- -- 5 ] 9 9 3 9 9 3 9 9 pour obtenir des valeurs numériques, il faut mettre un séparateur de décimales Interv(1,5.0) ; [ 1 1.44 1.8888889 2.333333 etc. interv(1,5) ; interv(1,5) mais Maple distingue majuscules et minuscules ; quand une fonction n'est pas définie, Maple renvoie l'expression telle quelle. Fm(1+I) ; 2^(1+I)-1 ; les nombres complexes peuvent garder une forme symbolique ou on peut les évaluer evalf(") ; .538478 + 1.277923 I

4. Maple : Quelques "trucs"

4.1 Chargement des programmes

Les programmes pour Maple sont écrits dans des fichiers "textes". Il est possible de les recharger automatiquement par une commande comme :

rtu := proc() read `/users/gh/#Rch/#Lf_Pls/tuteur.prm` end :

Maple permet aussi de cliquer sur des lignes, des portions de texte pour éviter de retaper des commandes... Il est conseillé de sauvegarder dans une "session" Maple de telles commandes.

4.2 Affichages simples

L'affichage est au choix exécuté par print et lprint ; print donne un "joli" affichage, surtour avec les formes inertes comme : int(x+1,x) = Int(x+1,x) qui renvoie un signe "intégrale".

print est souvent bien lisible, mais écrit au milieu de la ligne, ne cadre pas et print(a,b) laisse les virgules dans l'affichage. On peut utiliser print(a.b) sauf si a.b a un sens pour Maple. Par exemple print(` valeur `.a) est correct, mais print(a.1) renvoie l'élément nommé a.1

lprint (pour line print) est plus lourd mais aussi plus explicite. Les puissances sont notées avec ^, le retour charriot est bien géré, on peut mettre plusieurs expressions à la suite.

4.3 Entrées clavier

Une fonction comme

bonjour := proc()
 local pren ;
 printf(`Bonjour. Quel est votre prénom ? `) ;
 pren := readline(terminal) ;
 lprint(`au revoir,`,maju(pren),`.`) :
end:

montre comment effectuer des entrées clavier ; on récupère alors une variable texte. Par contre, pour lire des valeurs (ou même des expressions calculables) il faut utiliser readstat, abréviation de read statement, mais attention : il s'agit d'une instruction au sens Maple : le point-virgule est alors obligatoire.

4.4 Affichages cadrés

L'affichage cadré est réalisé avec printf avec la syntaxe du langage C. Par exemple, la table de multiplication est donnée (avec test de paramètre) par la fonction :

tabledemult := proc() local nb,iloop ; if nargs = 0 then lprint(` tabledemult : Table de Multiplication`) ; lprint() ; lprint(` syntaxe : tabledemult(exprEnt) `); lprint(` où exprEnt est un nombre entier`); lprint(` ou une expression à résultat entier`); lprint(` exemples : tabledemult(3) ;`); lprint(` : tabledemult(3^5); `); else nb := args[1] ; if not (type(nb,integer) or type(eval(nb),integer)) then print(`ERREUR`) ; print() ; lprint(`votre expression n'est pas un ENTIER`) ; ERROR(`Mauvais argument ! Taper tabledemult() ; pour plus d'info.`) ; else print(`Table de `.nb) ; lprint ; for iloop from 1 to 10 do printf(` %6d fois %2d = %8d `,nb,iloop,nb*iloop) ; lprint() ; od ; fi ; fi ; end :

4.5 Lecture sur fichier

L'instruction read la réalise. Ainsi le calcul de moyenne sur des notes lues dans le fichier classe.dat est exécuté par la fonction : (sscanf permet la conversion texte --> nombre)

classe := proc() local nomF,nblig,ligne,nomlu,noteslues,moynotes,lunom ; if nargs = 0 then lprint(` classe : moyenne d'un fichiers de notes`) ; lprint() ; lprint(` syntaxe : classe(nomF) `); lprint(` où nomF est un nom de fichier`); lprint(` exemple : tabledemult(``/users/gh/#Rch/#Lf_Pls/classe.dat``) ;`); lprint(` (/ est mis pour \\ à cause de Maple) `); RETURN() ; else nomF := args[1] ; print(`Lecture du fichier `.nomF) ; nblig := 0 ; ligne := traperror(readline(nomF)) ; if ligne=lasterror then ERROR(` Fichier `.nomF.` non vu`) ; else nomlu := substring(ligne,1..15) ; noteslues := sscanf(substring( ligne,16..length(ligne)),`%f %f %f`) ; # convert(liste,`+`) équivaut à +/liste d'APL moynotes := round(stats[average] (noteslues)*100)/100.0 ; # on notera ici l'appel de la fonction average # du package stats moynotes := convert(evalf(moynotes,4),string) ; while length(moynotes) < 5 do moynotes := ``.moynotes.`0` ; od ; nomnot := ` `.nomlu.moynotes ; notnom := ` `.moynotes.` `.nomlu ; lnomnot := [nomnot] ; lnotnom := [notnom] ; lprint(`Par ordre de lecture `) ; while type(ligne,string) do lprint(nomnot) ; ligne := readline(nomF) ; if type(ligne,string) then nomlu := substring(ligne,1..15) ; noteslues := sscanf(substring( ligne,16..length(ligne)),`%f %f %f`) ; moynotes := round(stats[average](noteslues)*100)/100.0 ; moynotes := convert(evalf(moynotes,4),string) ; while length(moynotes) < 5 do moynotes :=``.moynotes.`0` ;od ; nomnot := ` `.nomlu.moynotes ; notnom := ` `.moynotes.` `.nomlu ; lnomnot := [op(lnomnot) , nomnot ]; lnotnom := [op(lnotnom) , notnom ]; fi ; od : fi ; fi : lprint(`Par ordre alphabétique`) ; printlist(sort(lnomnot)) ; lprint(`Par ordre de mérite`) ; printlist(sort(lnotnom)) ; RETURN() : end : Nous avons au passage défini la fonction d'affichage : printlist := proc(lst) local il ; for il from 1 to nops(lst) do lprint(lst[il]) ; od ; end :

5. Maple et les mathématiques formelles

On trouvera ici quelques exemples (et surtout contre-exemples ) destinés à montrer tout le bien et le mal qu'on peut attendre de Maple.

5.1 Factorisation de polynomes

Maple sait factoriser les polynomes. Ainsi

   factor(x^2 + 4*x*y + 2*x + 4*y^2 + 4*y + 1)

donne (x+2y+1)2. Par contre, factor(x4+1) ne donne rien.
Mais factor(x^4+1,I) lance la factorisation complexe et on
obtient alors (x^2+I)(x^2-I). Pour obtenir la "vraie"
factorisation de x^4+1, il faut ruser :

   a := RootOf(x^2 -2) ; factor(x^4+1,a)

et on obtient : (x^2 - RootOf(_Z^2 -2) + 1) (x^2 - RootOf(_Z^2 -2) - 1)

La factorisation est donc possible, mais non trivialement...
Par exemple, essayez de trouver la factorisation de x^4+2...

5.2 Résolution d'équations de récurrences

Maple sait, dans une certaine mesure résoudre une équation comme un = un-1 + 2 un-2 avec, disons u0 = a et u1 = b : solve( { u(n) = u(n-1) + 2* u(n-2) , u(0) = a, u(1) = b} , u(k) ) ; par contre si Maple sait résoudre un = 3un-1 -3 un-2 + un-3, il fournit comme résultat uk = 2(k+1)( 1 + k/2) - k - 1 qui ne devient (k+1)2 qu'après un petit ménage. Il arrive que Maple envoie le message sybillin Error, (in gcdex,/gcdex) invalid argument to icontent. Pensez alors à vérifier si vos variables ne sont pas déjà utilisées (ici u,n,k).

5.3 Equations matricielles


La (ou les ?) matrice de taille (2x2) dont le déterminant
est 1 et dont la trace est 4 peut être calculée par

   m := array(1..2,1..2) ;
   solve( { linalg[det](m) = 1 , linalg[trace](m) = 4 ) ;

Il peut toutefois ê tre plus intéressant d'écrire

   m := array(1..2,1..2, [ [a,b] , [c,d] ] ) ;
   solve( { linalg[det](m) = 1 , linalg[trace](m) = 4 ) ;

car les solutions sont plus lisibles :

   { a = - d + 4, c = c , d = d , b = - (d2 - 4d + 1 ) / c },
   { d = RootOf(_Z2 - 4_Z + 1) , a = - RootOf(_Z2 - 4_Z + 1) + 4,
               b = b , c = 0 }

Attention à ne pas utiliser trace mais bien linalg[trace] :
trace sert à suivre le déroulement d'une fonction, afficher
les résultats intermédiaires... Si on veut taper seulement
trace, il charger le package linalg avec la commande
with(lingalg,trace) ; la commande with(linalg) ;
quand à elle, charge tout le package.

5.4 Equations sur densité de probabilité

Un exercice classique de Deug consiste à calculer 2 nombres a et b tels que la fonction f définie par f(x) = ax + b pour x dans [0,1] et 0 ailleurs avec f(1/2) = c soit une densité de probabilité. Pour Maple, la réponse à la suite des instructions f := x -> a*x + b ; solve( { int( f(x),x=0..1 ) = 1, f(1/4) = c }, { a,b } ) ; est : { b = -1 + 2 c, a = 4 - 4 c } Pour c = 1/4, on trouve donc : res := subst( c = 1/4 , " ) ; soit a = 3 et b = -1/2 ; et on peut visualiser le graphe de f par : plot( subs( res,f(x) ), x = 0..1 ) ; Par contre, on ne peut pas faire résoudre à Maple le système f := x -> a*x + b ; solve({ int( f(x),x=0..1 ) = 1, f(1/2) = c }, {a,b} ) ; Et s'il est possible de définir f par f := x -> if (x>0 and x<1) then a*x + b ; else 0 ;fi ; Le système suivant n'admet pas non plus de solution : solve( { int( f(x),x=-infinity,infinity ) = 1, f(1/4) = c }, { a,b } ) ; car Maple ne peut interpréter le test et effectuer l'intégration.