Maple est un langage dit "fonctionnel" et mathématique, comme Mathematica.
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.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"
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.1 Factorisation de polynomes 5.2 Résolution d'équations de récurrences 5.3 Equations matricielles 5.4 Equations sur densité de probabilité
- un ensemble de primitives de calculs - un outil de calcul numérique et de calcul formel - un langage de programmation - un outil de visualisation graphique1.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.41.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:,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.(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 Ls2Mat2. Programmation en Maple
2.1. Les fonctions en Maple
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ée2.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.