restart ; interface(echo=4) ; # (gH) -- rapm.prm ; TimeStamp (unix) : le 24 Septembre 03 à 13:36 ################################################################################### # # # ceci est le fichier rapm.prm qui évite de retaper les expressions et # # instructions Maple présentées dans le cours # # # # "Rappels mathématiques pour la licence informatique". # # # # l'url de la page web de ce fichier est : # # # # http://www.info.univ-angers.fr/pub/gh/cours_gH/rapm.prm # # # # # # Références : Gilles HUNAULT, Université d'Angers. # # Email : gilles.hunault@univ-angers.fr # # Site web : http://www.info.univ-angers.fr/pub/gh/ # # # ################################################################################### # # # - en ligne de commande, il faut taper # # # # maple < rapm.prm # # # # pour éxécuter ce fichier. # # (avec peut-être le chemin d'accés au fichier à maple) # # # # - à l'intérieur d'une session il faut taper : # # # # interface(echo=4) ; # # read "rapm.prm" ; # # # # pour éxécuter ce fichier. # # (avec peut-être le chemin d'accés au fichier rapm.prm) # # # ################################################################################### # comme vous l'avez surement compris, un commentaire commence par le symbole dièse # et il peut être mis apres une instruction ; # Maple ignore donc ces lignes... # le symbole > est le prompt de Maple qui attend une ligne # (même une ligne vide) print( interface(version) ) ; # <-- ceci donne la version de Maple utilisée interface(errorbreak=0) ; # <-- s'il y a une erreur de fichier, on continue ################################################################################### # # # pot-pourri d'expressions pour une prise de contact avec Maple # # # ################################################################################### # une expression formelle : le développement de (1+x) au cube, # sans que x n'ait de valeur expand((1+x)^3) ; # utilisation du pont-virgule et du symbole deux-points # avec le point virgule on calcule et on affiche x:= 0 ; y := x + 1; # avec le deux-points on calcule mais on n'affiche pas x:= 0 : y := x + 1; # si on décommente la ligne suivante, on sort de Maple #quit ; # Maple utilise une très grande précision pour les calculs en nombres entiers 2^1996 ; # les fonctions ont en général des noms anglais 2^3, 3**2 ,(7 mod 5)=irem(17,8), iquo(35, 8), gcd(1250,500); # il y a plusieurs types de nombres ; # (décommenter pour avoir le détail) # help (number) ; # Maple interprète les expressions directement 1.23456^1.3 ; # on peut forcer le nombre de décimales avec evalf evalf(1.23456^1.3,20) ; # et l'affichage cadré avec printf printf(`%20.15f`,1.23456^1.3) ; # la variable Digits gère la précision par défaut 1/3.0 ; Digits := 40 ; 1/3.0 ; # la précision n'est pas infinie 1996^(1996^1996) ; # incorrect volontairement : cela déborde # a propos, qui est plus grand : a^(b^c) ou (a^b)^c ? # les affectations avec := sont (presque) classiques x := 2 ; y := x+2 ; x := 3 ; # mais la "transparence référentielle" complique un peu b := a ; a := 1 ; b ; a := 2 : b ; restart ; # <-- pour effacer toutes la session, y compris les variables a := 1 ; b := a ; b ; a := 2 : b ; # les structures de base sont les ensembles ("sets"), les listes, les vecteurs, # (décommenter pour avoir le détail) # ? set # ? list # ? vector # ? matrix # ? seq # voici la liste des constantes reconnues par Maple constants ; # quand Maple "ne sait pas", il ne dit rien # et se contente de "répéter betement" factor(x^4+1) ; # pour suivre en détail, il faut utiliser infolevel restart ; # <-- car Maple garde en mémoire ses essais de factorisation infolevel[factor] := 4 ; factor(x^4+1) ; # une séquence d'expressions, ce sont des expressions séparées par # des virgules, comme a , 1+2, 3=6, evalb(3=9), Int(t/2,t) = int(t/2,t) ; # avec des accolades, cela devient un ensemble et avec des crochets, une liste s := a , b , c ; whattype( { s } ) ; whattype( [ s ] ) ; # la fonction seq produit des suites de valeurs numérique ou formelles seq(i*i,i=1..3) ; seq(h(i),i=[a,b,c]) ; # pour convertir, il faut rajouter une structure à seq convert( seq(`i`,i=1..10) ,`+` ) ; # incorrect volontairement : manque les crochets convert( [seq(`i`,i=1..10)],`+` ) ; # essais calcul de la somme formelle des n premiers entiers n := 'n' ; i := 'i' ; convert(seq(i,i=1..n),`+`) ; # incorrect volontairement : pas de seq formel add(i,i=1..n) ; # incorrect volontairement : pas de add formel sum(i,i=1..n) ; # une forme factorisée, c'est "plus propre" factor( sum(i,i=1..n) ) ; # les formes inertes permettent d'écrire de jolies expressions Sum(i,i=1..n) = factor( sum(i,i=1..n) ) ; # quand on a plusieurs expressions qui donnent le même résultats, # on peut utiliser time pour comparer la vitesse d'exécution n := 200 : i:='i':deb:=time():sum(`i`,`i`=1..n):time()-deb ; convert([seq(`i`,`i`=1..n)],`+`):time() -deb; product(`i`,`i`=1..n) :time() -deb ; convert([seq(`i`,`i`=1..n)],`*`):time() -deb ; # exemples de boucles pour traditionnelles i :='i':deb := time() : for j from 1 to 200 do : sum(`i`,`i`=1..n) : od : time() -deb ; i := 'i' : deb := time() : for j from 1 to 200 do : product(`i`,`i`=1..n) : od : time() -deb ; i := 'i' : deb := time() : for j from 1 to 200 do : s:=0 : for i from 1 to n do : s := s + i : od : od : time() -deb ; i := 'i' : deb := time() : for j from 1 to 200 do : fact(n) : od : time() -deb ; # le nombre d'éléments d'une liste est donné par nops, # on accède aux éléments via l'indice entre crochets L:=[seq(i*i,i=1..10)] ; nops(L); L[2] ; # la notation [$a..b] génére la liste-intervalle de a à b L := [\$1..10] ;L := [\$1..10] ; # reverse retourne une liste mais on peut aussi faire n := nops(L) ; L := [seq(L[n+1-i],i=1..n)] ; # mais attention à length pour une liste length(L) ; # map applique une fonction à chacun des éléments de la liste map(x->x+1,[1,2,4]) ; map(x->x-1,\{1,2,4\}) ; # mais attention à la vitesse d'exécution deb := time() : for j from 1 to 300 do convert(map(i->i,{$1..500}),`+`):od: time() -deb ; # pour appliquer un opérateur binaire à une liste, on utilise foldl foldl( `and`, true, op(map(isprime,[$1..3]))) ; # les fonctions classiques connaissent les listes L := [$1..5] : S := map( x->x+1, L ) : A := L + S ; sommeListe := (x,y) -> x+ y : Z := sommeListe(L,S) ; # la même choe avec les vecteurs V := vector(5,[$1..5]) : W := vector(5,[ seq(V[i]+1,i=1..5) ]) : sommeVecteur := (x,y) -> vector(5,[ seq(x[i]+y[i],i=1..5) ]): U := sommeVecteur(V,W) ; # on peut calculer la longueur d'un vecteur par nops( convert(V,list) ) ; nops( [ entries(V) ] ) ; # mais le mieux est sans doute d'utiliser la fonction "ad hoc" de Maple linalg[vectdim](V) ; # on définit rapidement une fonction par la correspondance fonctionnelle # noté -> soit les touches "tiret" et "supérieur" f := x -> x**2 = 1 ; f(5) ; # le test avec si permet de gérer les différents cas # et elif signifie else if (en français sinon si) f := x ->if x<3 then x+1 elif x <5 then x-1 else x*x :fi: map(f,[$1..10]) ; # nombres aléatoires y := map(1+rand(100),[$1..1000]) : # un test élémentaire pour voir la qualité du générateur aléatoire z := map(x-> if x>50 then 1 : fi , y ) : convert(z,`+`) ; # ceci est sans doute mieux mais plus illisible convert( map(x-> if x>50 then 1 : fi , map(1+rand(100),[$1..1000]) ),`+`) ; # détail des expressions gérées par Maple comme des arbres f := x**2*exp(3/2)*sin(Pi/3-1/x) ; nops(f),[op(f) ],length(f),op(3,f) ; op(1,op(op(3,f))) ; # quand on sait ce qu'on fait, on peut modifier une # sous-expression avec subsop : subsop(3=cos(x),f) ; f ; # subs, quant à lui remplace dans l'expression g := 2*(x-1) + 3**(x**2+1); subs(x=a,g) ; # mais seulement au niveau le plus haut ; subs(n=2,1+n) ; subs(a+b=2,1+a+b) ; # pour descendre dans l'arbre, il faut utiliser simplify simplify(1+a+b,{a+b=2}) ; # la boucle while permet de sortir d'une boucle en fonction d'un test i:=2; s := 0 ; while (i*i-35<0) do i := i +1 ; s := s + cos(i)**2 ; od : print(s) ; # il vaut mieux écrire "proprement" i:=2; s := 0 ; while (i*i<35) do i := i +1 ; s := s + cos(i*1.0)**2 ; od : print(s) ; # select effectue une boucle implicite select(isprime,[$1..100]) ; # utilisé avec convert, c'est illisible mais puissant convert([seq(1/2^p,p=select(isprime,[$1..1000]))],`+`); # si on ne veut que la durée : deb := time() ; convert([seq(1/2^p,p=select(isprime,[$1..1000]))],`+`): time()-deb; # pour programmer les fonctions, nargs donne le nombre d'arguments # et on peut donner explicitement les paramètres ou uitliser args[...] # la fonction renvoie la dernière valeur calculée # sauf si on trouve return avant f := (x,y) -> x+2*y ; f(3,4) ; f := proc() ; args[1] + 2* args[2] ; end ; f(3,4) ; f := proc(x,y) ; return x+2*y ; end ; f(3,4) ; # voici un exemple typique de fonction 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 Fm() ; # un exemple plus complet : 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 : Interv(0,1) ; Interv(0,1,5) ; Interv(0,1.0,5) ; # les fonctions définies par l'utilisateur peuvent auss # être appliquées aux listes SC := proc(x) RETURN((x+1)^2) : end: CSC1 := proc(x) RETURN(map(a->(a+1)^2,[op(x)])) : end: CSC2 := proc(x) RETURN(map(SC,[op(x)])) : end: GSC := proc(x) if nops([x]) = 1 then RETURN((x+1)^2) : else RETURN(map(SC,[op(x)])) : fi ; end : SC( 3 ) ; CSC1( [1,5,10]) ; CSC2( [1,5,10]) ; GSC( [1,5,10]) ; ################################################################################### # # chapitre 1 : Ensembles et Fonctions # ################################################################################### # utilisation de nops pour trouver le nombre d'éléments de { x,y } restart ; nops({x,y}) ; # on doit trouver 2 y := x ; nops({x,y}) ; # on doit maintenant trouver 1 # nops permet de trouver le nombre de voyelles nops({A,E,I,O,U,Y}) ; # mais length aussi, avec les chaines de caractères length("AEIOUY") ; # length pour un nombre entier donne son nombre de chiffres length(2^16) ; # ce qui est plus lisible que 2^16 ; # on aurait aussi pu utiliser 2.0^16 ; # mais attention à length pour des nombres non entiers : length(20.6) ; # renvoie 7 ??? length(2/3) ; # renvoie 5 ??? # ED est l'ensemble des entiers de 0 à 10 # D est incorrect comme variable (lettre réservée à la dérivation) # EP : les nombres pairs de ED # EI : les nombres impairs de ED ED:={$0..10} ; D:={$0..10} ; # volontairement incorrect (symbole de dérivation) ES:={$1..10} ; EP:=select(x->type(x,even),ED) ; EI:=select(x->not type(x,even),ED) ; # pour tester si x est inclus dans y, on écrit estinclusdans := (x,y) -> evalb(x = x intersect y) ; # ce qui reinvente member : member(x,y) <==> estinclusdans(x,y) # pour passer en revue toutes les inclusions, on fait une matrice de tests L := vector(4) ; L[1] := ED ; L[2] := ES ; L[3] := EP ; L[4] := EI ; n := linalg[vectdim](L) ; inclusions := matrix(n,n, (i,j) -> estinclusdans( L[i],L[j] ) ) ; evalm(inclusions) ; # les parties d'un ensemble se calculent avec powerset du "package" combinat E := {a,b,c} ; combinat[powerset](E) ; # on aurait pu aussi écrire # # with(combinat) ; # powerset(E) ; # # mais cela charge toutes les fonctions de combinat. # décommenter l'instruction suivante pour voir 256 éléments : #combinat[powerset]( combinat[powerset](E) ) ; # exemple d'une union rendue disjointe A := { a,b,c,d,e } ; B := { d,e,f,g } ; C := B minus (B \intersect A) ; evalb( (A union B)=(A union C ) ) ; restart ; evalb( (A union B)=(A union ( B minus (B \intersect A)) ) ) ; # pour vérifier que {} est l'élémen neutre de union {} union X ; # pour voir les jolis symboles de Maple (X_i intersect Y_j) union Z_k ; # on veut tester la notion de partition restart ; # on invente les ensembles E, X1, X3, X6 et X8 E := { $1..10 } ; ensX := i -> { i, i+1, i+2 } ; # F est la famille des Xi # vérifions que les éléments de E sont ceux de F # c'est à dire que F recouvre E F := { ensX(1), ensX(3), ensX(6), ensX(8) } ; evalb( E = map( x -> op(x) , F ) ) ; # inventons le test a est disjoint de b # c'est à dire que l'intersection des deux ensembles est vide sontdisjoints := (a,b) -> evalb( {} = (a intersect b) ) ; n := nops(F) ; # tentons de tester si les éléments de F sont disjoints deux à deux lt := seq( seq( sontdisjoints ( op(i,F),op(j,F)), j=1..n), i=1..n) ; foldl( `and`, true, lt) ; # essayons avec une forme matricielle mh := matrix( n,n, (i,j) -> if i=j then true else sontdisjoints( op(i,F), op(j,F) ) fi ) : # et non pas ; mt := convert( convert( mh,vector), list ) ; foldl( `and`, true, op(mt) ) ; # faisons une fonction de tout cela estpartition := ( X , Y ) -> if evalb( Y = ( map( x -> op(x) , X ) ) ) and foldl( `and`, true, seq( seq( sontdisjoints ( op(i,X),op(j,X)), j=1..nops(X)), i=1..nops(X)) ) then print( X, "est bien une partition de ",Y ) else print( X, "n'est pas une partition de ",Y ) fi ; # fin de la fonction est espartition (mais la fonction est fausse à cause des (i,i) # structurons un peu mieux notre travail recouvre := ( X , Y ) -> evalb( Y = ( map( x -> op(x) , X ) ) ) ; sontdisjoints2a2 := proc( X ) local i,j,n,mh,mt ; n := nops(X) ; mh := matrix( n,n, (i,j) -> if i=j then true else sontdisjoints( op(i,X), op(j,X) ) fi ) ; mt := convert( convert( mh,vector), list ) ; return foldl( `and`, true, op(mt) ) ; end ; # du coup, estpartition est plus lisible estpartition := ( X , Y ) -> if recouvre( X, Y ) and sontdisjoints2a2( X ) then print( X, "est bien une partition de ",Y ) else print( X, "n'est pas une partition de ",Y ) fi ; # fin de la fonction est espartition # appliquons nos fonctions au problème posé E := { $1..10 } ; F := { ensX(1), ensX(3), ensX(6), ensX(8) } ; ens2 := ( ensX(3) union ensX(6) ) minus ( ensX(1) union ensX(8) ) ; G := { ensX(1), ens2 , ensX(8) } ; estpartition( F, E ) ; estpartition( G, E) ; sontdisjoints2a2( G ) ; # en cas de problème, on peut chercher les éléments incriminés detailleDisjonction := proc(X) local i,j,n,e1,e2; n := nops(X) ; print(n,X) ; i := 1 ; while i <= n do e1 := op(i,X) ; print(i,e1) ; j := 1 ; while j <= n do e2 := op(j,X) ; print(j,e2) ; if (not i=j) then if not sontdisjoints( e1, e2 ) then print("les ensembles",e1,"et",e2,"situés en position",i,"et",j,"ne sont pas disjoints ") ; j := n ; i := n ; return false ; fi : fi : j := j + 1 ; od : # fin tant que sur j i := i + 1 ; od : # fin tant que sur i return true ; end ; sontdisjoints2a2( G ) ; sontdisjoints2a2( F ) ; detailleDisjonction( F ) ; # attention aux paramètres recouvre(E,F) ; recouvre(F,E) ; # si on hésite, il faut que le prorgrammeur # ait prévu le rappel de la syntaxe recouvre := proc( X , Y ) ; if nargs=0 then print(" recouvre(X,Y) renvoie vrai si X recouvre Y ") ; else evalb( Y = ( map( x -> op(x) , X ) ) ) ; fi ; end ; recouvre() ; # un bon programmeur testera aussi le nombre de paramètres... # et le type des paramètres. recouvre := proc( X , Y ) ; if not (nargs=2) then print(" attention : recouvre utilise exactement 2 paramètres ") ; print(" or ici vous en avez fourni ",nargs) ; return ; fi : if not type(X,set) then print(" erreur : dans recouvre(X,Y) X doit être de type \"ensemble\"") ; print(" or ici, X qui vaut ",X," est de type ",whattype(X)) ; return ; fi ; end ; recouvre(1) ; recouvre(1,2) ; # même démarche pour le problème de la hiérarchie : # on invente inclusionHierarchique puis on l'utilise # en boucle F := [ {}, {a}, {b} , {c}, {a,b}, {a,c}, {a,b,c} ] ; inclusionHierarchique := (X,Y) -> member( (X intersect Y) , { {}, X , Y } ) ; esthierarchie := X -> foldl( `and`, true, seq( seq( inclusionHierarchique( op(i,X),op(j,X)) , j=1..nops(X)), i=1..nops(X)) ) ; esthierarchie(F) ; # on peut alors l'appliquer au problème posé F := { {}, {a}, {b} , {c}, {a,b}, {a,c}, {a,b,c} } ; G := F minus { {a,c} } ; esthierarchie(G) ; # et écrire une fonction pour détailler si ce n'est pas une hiérarchie detailleinclusionHierarchique := proc(X) local i,j,n,e1,e2; n := nops(X) ; print(n,X) ; i := 1 ; while i <= n do e1 := op(i,X) ; print(i,e1) ; j := 1 ; while j <= n do e2 := op(j,X) ; print(j,e2) ; if not inclusionHierarchique( e1, e2 ) then print("les ensembles",e1,"et",e2,"situés en position",i,"et",j,"ne sont pas en inclusion hiérarchique ") ; print(" car leur intersection est ",e1 intersect e2) ; j := n ; i := n ; return false ; fi : j := j + 1 ; od : # fin tant que sur j i := i + 1 ; od : # fin tant que sur i return true ; end ; # fin detailleinclusionHierarchique detailleinclusionHierarchique(F) ; # en produit cartésien un peu compliqué E := {a,b} ; n := nops(E) ; F := combinat[powserset](E) ; p := nops(F) ; matrix(n,p, (i,j) -> (op(i,E), op(j,F))) ; E := [a,b] ; n := nops(E) : F := combinat[powerset](E) ; p := nops(F) : M := [ seq( seq( [op(i,E), op(j,F)], j=1..p ),i=1..n) ] : map( x -> print(op(x)) , M ) : # un exemple de point fixe f := x -> 2*x -1/2 ; solve( f(x)=x) ; # un calcul de limite limit( (x-1)*(x+1)/(x^6-1),x=-1) ; # volontairement incorrect # pas de chance, on ne saura pas comment calculer la limite ! restart ; infolevel[limit] := 100 ; limit( (x-1)*(x+1)/(x^6-1),x=-1) ; ; # volontairement incorrect # un test de commutativité f := (x,y) -> x*y -(x+y) ; evalb( f(x,y) = f(y,x) ) ;