• Aucun résultat trouvé

Opérations globales sur les listes

Dans le document Calcul mathématique avec Sage (Page 87-93)

structures de données

4.3 Listes et structures composées

4.3.2 Opérations globales sur les listes

L’opérateur d’addition «+» effectue la concaténation de deux listes, et l’opérateur de multiplication «*» associé à un entier itère cette concaténa-tion :

sage: L = [1, 2, 3] ; L + [10, 20, 30]

[1, 2, 3, 10, 20, 30]

sage: 4 * [1, 2, 3]

[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]

La concaténation de ces deux sous-listes d’indice limitekreconstruit la liste initiale :

L=L[:k]+L[k:]= (`0, `1, `2,· · ·, `n−1)

= (`0, `1, `2,· · · , `k−1) + (`k, `k+1, `k+2,· · · , `n−1).

L’exemple suivant illustre cette propriété :

sage: L = 5*[10, 20, 30] ; L[:3]+L[3:] == L True

L’opérateur composé de deux points «..» automatise la construction des listes d’entiers sans énumérer explicitement tous leurs éléments. L’exemple suivant construit une liste faite d’énumérations d’entiers et d’éléments isolés :

sage: [1..3, 7, 10..13]

[1, 2, 3, 7, 10, 11, 12, 13]

La suite de ce paragraphe décrit comment construire par compréhension l’image d’une liste par une application et une sous-liste d’une liste. Les fonctions associées sontmapetfilter, et la construction[..for..x..in..].

Les mathématiques font souvent intervenir des listes constituées des images par une applicationf de ses éléments :

(a0, a1, a2,· · · , an−1)7→(f(a0), f(a1),· · · , f(an−1)).

La commande map construit cette image ; l’exemple suivant applique la fonction trigonométrique cos à une liste d’angles usuels :

sage: map (cos, [0, pi/6, pi/4, pi/3, pi/2]) [1, 1/2*sqrt(3), 1/2*sqrt(2), 1/2, 0]

Il est aussi possible d’utiliser une fonction de l’utilisateur définie pardef, ou de déclarer directement une fonction par lambda; la commande ci-dessous est équivalente à la précédente et applique la fonction définie part7→cost:

BR

OUILLON

sage: map (lambda t: cos(t), [0, pi/6, pi/4, pi/3, pi/2]) [1, 1/2*sqrt(3), 1/2*sqrt(2), 1/2, 0]

La commande lambdaest suivie de la déclaration du ou des paramètres séparés par des virgules, et ne peut comporter après le deux-point qu’une et une seule expression qui est le résultat de la fonction sans utiliser l’instruction return.

Cette fonctionlambdapeut aussi comporter un test, les codes suivants sont équivalents :

fctTest1 = lambda x: res1 if cond else res2 def fctTest2 (x):

if cond: return res1 else: return res2

Les trois commandes mapsuivantes sont équivalentes, la composition des applicationsN◦cos étant effectuée d’une façon ou d’une autre :

sage: map (lambda t: N(cos(t)), [0, pi/6, pi/4, pi/3, pi/2]) [1.00000000000000, 0.866025403784439, 0.707106781186548, 0.500000000000000, 0.000000000000000]

sage: def ncos (t): return (N(cos(t))) ...

sage: map (ncos, [0, pi/6, pi/4, pi/3, pi/2])

[1.00000000000000, 0.866025403784439, 0.707106781186548, 0.500000000000000, 0.000000000000000]

sage: map (N, map (cos, [0, pi/6, pi/4, pi/3, pi/2])) [1.00000000000000, 0.866025403784439, 0.707106781186548, 0.500000000000000, 0.000000000000000]

La commande filterconstruit une sous-liste des éléments vérifiant une condition, l’exemple suivant applique le test de primalité is_prime aux entiers jusqu’à 55 :

sage: filter (is_prime, [1..55])

[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53]

La fonction de test peut aussi être définie à l’intérieur de la commande filter. L’exemple ci-dessous, par des essais exhaustifs, détermine toutes les racines quatrièmes de 7 modulo le nombre premier 37 ; cette équation comporte quatre solutions 3, 18, 19 et 34 :

sage: p = 37 ; filter (lambda n: n^4 % p == 7, [0..p-1]) [3, 18, 19, 34]

Par ailleurs, la commande [..for..x..in..] construit par compréhen-sion une liste ; ces deux commandes énumèrent de façon équivalente les entiers impairs de 1 à 31 :

sage: map(lambda n:2*n+1, [0..15])

[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31]

sage: [2*n+1 for n in [0..15]]

[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31]

BR

OUILLON

Cette commande est indépendante de la commande de bouclefor. La condi-tionif associée à foraboutit à cette construction équivalente à la fonction filter:

sage: filter (is_prime, [1..55])

[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53]

sage: [p for p in [1..55] if is_prime(p)]

[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53]

Les deux exemples suivants combinent les tests ifetfilteravec forpour déterminer une liste des nombres premiers qui sont congrus à 1 modulo 4, puis une liste de carrés de nombres premiers :

sage: filter (is_prime, [4*n+1 for n in [0..20]]) [5, 13, 17, 29, 37, 41, 53, 61, 73]

sage: [n^2 for n in [1..20] if is_prime(n)]

[4, 9, 25, 49, 121, 169, 289, 361]

Dans le premier cas le testis_primeest effectué après le calcul 4n+ 1 alors que dans le second le test est effectué avant le calcul du carrén2.

La fonctionreduceopère par associativité de la gauche vers la droite sur les éléments d’une liste ; définissons ainsi la loi de composition interne ?:

x ? y= 10x+y, alors ((1?2)?3)?4 = (12?3)?4 = 1234.

Le premier argument est une fonction à deux paramètres, le deuxième est la liste des arguments, et l’éventuel troisième argument permet de valider le résultat sur une liste vide :

sage: reduce (lambda x, y: 10*x+y, [1, 2, 3, 4]) 1234

sage: reduce (lambda x, y: 10*x+y, [9, 8, 7, 6], 1) 19876

L’exemple ci-dessous calcule un produit d’entiers impairs, le troisième para-mètre correspond généralement à l’élément neutre de l’opération appliquée pour obtenir un résultat valide sur une liste vide :

sage: L = [2*n+1 for n in [0..9]]

sage: reduce (lambda x, y: x*y, L, 1) 654729075

Les fonctionssumetproddeSageappliquent directement l’opérateurreduce pour calculer des sommes et des produits ; le résultat est le même dans les trois exemples ci-dessous, et la commande sur une liste autorise en outre d’ajouter un second terme optionnel représentant l’élément neutre, l’élément unité du produit et élément nul pour la somme, par exemple une matrice unité pour un produit matriciel :

sage: prod ([2*n+1 for n in [0..9]], 1) # une liste avec for 654729075

sage: prod ( 2*n+1 for n in [0..9]) # sans liste 654729075

BR

OUILLON

sage: prod (n for n in [0..19] if n%2 == 1) 654729075

La fonction any associée à l’opérateur or et la fonction all à l’opérateur andsont de principe et de syntaxe équivalente. Cependant l’évaluation se termine dès que le résultatTrueouFalsed’un des termes impose ce résultat sans effectuer l’évaluation des termes suivants :

sage: def fct (x): return 4/x == 2 ...

sage: all (fct(x) for x in [2, 1, 0]) False

sage: any (fct(x) for x in [2, 1, 0]) True

En revanche la construction de la liste [fct(x) for x in [2, 1, 0]]et la commandeall([fct(x) for x in [2, 1, 0]])provoquent des erreurs car tous les termes sont évalués, y compris le dernier avec x= 0.

L’imbrication de plusieurs commandes for dans les listes permet de construire le produit cartésien de deux listes ou de définir des listes de listes.

Les résultats de ces exemples montrent que l’opérateurforest évalué de la gauche vers la droite et de l’intérieur vers l’extérieur des listes :

sage: [[x, y] for x in [1..2] for y in [6..9]]

[[1, 6], [1, 7], [1, 8], [1, 9], [2, 6], [2, 7], [2, 8], [2, 9]]

sage: [10*x+y for x in [1..3] for y in [6..9]]

[16, 17, 18, 19, 26, 27, 28, 29, 36, 37, 38, 39]

sage: [[10*x+y for x in [1..3]] for y in [6..9]]

[[16, 26, 36], [17, 27, 37], [18, 28, 38], [19, 29, 39]]

sage: [10*x+1 for x in [1..3, 6..9]]

[11, 21, 31, 61, 71, 81, 91]

sage: map (lambda x, y: [x, y], [1..3], [6..8]) [[1, 6], [2, 7], [3, 8]]

Cette dernière commandemapavec plusieurs listes arguments avance de façon synchronisée dans ces listes.

Enfin la commande flatten permet de concaténer des listes sur un ou plusieurs niveaux :

sage: L = [[1, 2, [3]], [4, [5, 6]], [7, [8, [9]]]]

sage: flatten (L, max_level = 1) [1, 2, [3], 4, [5, 6], 7, [8, [9]]]

sage: flatten (L, max_level = 2) [1, 2, 3, 4, 5, 6, 7, 8, [9]]

sage: flatten (L) # dans ce cas =flatten (L, max_level = 3) [1, 2, 3, 4, 5, 6, 7, 8, 9]

Ces manipulations élémentaires de listes interviennent de façon très utiles dans les autres branches de Sage; l’exemple suivant calcule les premières dérivées itérées de x ex; le premier argument de diff est l’expression à

BR

OUILLON

dériver, et le ou les suivants correspondent à la variable de dérivation, ces paramètres peuvent aussi être la liste des variables par rapport auxquelles ces dérivées sont effectuées :

sage: x = var('x')

sage: factor(diff(x*exp(x), [x, x])) (x + 2)*e^x

sage: map(lambda n: factor(diff(x*exp(x), n*[x])), [0..6]) [x*e^x, (x + 1)*e^x, (x + 2)*e^x, (x + 3)*e^x, (x + 4)*e^x, (x + 5)*e^x, (x + 6)*e^x]

sage: [factor (diff (x*exp(x), n*[x])) for n in [0..6]]

[x*e^x, (x + 1)*e^x, (x + 2)*e^x, (x + 3)*e^x, (x + 4)*e^x, (x + 5)*e^x, (x + 6)*e^x]

La commande diff possède plusieurs syntaxes. Les paramètres suivant la fonction f peuvent aussi bien être la liste des variables de dérivation que l’énumération de ces variables, ou l’ordre de la dérivée :

diff(f(x), x, x, x), diff(f(x), [x, x, x]), diff(f(x), x, 3).

On peut aussi employerdiff(f(x), 3)pour les fonctions à une seule variable.

Ces résultats se vérifient directement par la formule de Leibniz de dérivée itérée d’un produit de deux termes où les dérivées d’ordre 2 ou plus dex sont nulles :

(xex)(n)=

n

X

k=0

n k

!

x(k)(ex)(n−k)= (x+n)ex. 4.3.3 Principales méthodes sur les listes

La méthode reverse renverse l’ordre des éléments d’une liste, et la méthode sorttransforme la liste initiale en une liste triée :

sage: L = [1, 8, 5, 2, 9] ; L.reverse() ; L [9, 2, 5, 8, 1]

sage: L.sort() ; L [1, 2, 5, 8, 9]

sage: L.sort(reverse = True) ; L [9, 8, 5, 2, 1]

Ces deux méthodes opèrent à l’intérieur de la liste, et l’ancienne valeur de L est perdue.

Un premier argument optionnel à sort permet de choisir la relation d’ordre appliquée sous la forme d’une fonction Ordre(x, y)à deux para-mètres. Le résultat doit être du typeintdes entiers « directement manipulés par l’ordinateur » ; il est strictement négatif, nul ou positif, par exemple−1, 0 ou 1, selon quexy,x=youxy. La liste transformée (x0, x1,· · ·, xn−1) vérifie x0 x1 · · · xn−1.

BR

OUILLON

L’ordre lexicographique de deux listes de nombres de même longueur est similaire à l’ordre alphabétique et est défini par cette équivalence en ignorant les premiers termes lorsqu’ils sont égaux deux à deux :

P = (p0, p1,· · ·pn−1)≺lex Q= (q0, q1,· · ·qn−1)

⇐⇒ ∃r∈ {0,· · · , n−1} (p0, p1,· · · , pr−1) = (q0, q1,· · · , qr−1) etpr < qr.

La fonction suivante compare deux listes supposées de même longueur.

Malgré la boucle a priori sans fin while True, les commandes return sortent directement de cette boucle et terminent la fonction. Le résultat est

−1, 0 ou 1 selon que PlexQ,P =Qou P lexQ :

sage: def alpha (P, Q): # len(P) == len(Q) par hypothèse ... i = 0

La commande suivante trie cette liste de listes de même longueur en suivant l’ordre lexicographique. Cette fonction correspond par ailleurs à l’ordre implanté dansSage pour comparer deux listes ; la commandeL.sort()sans paramètre optionnel est équivalente :

sage: L = [[2, 2, 5], [2, 3, 4], [3, 2, 4], [3, 3, 3],\

... [1, 1, 2], [1, 2, 7]]

sage: L.sort (cmp = alpha) ; L

[[1, 1, 2], [1, 2, 7], [2, 2, 5], [2, 3, 4], [3, 2, 4], [3, 3, 3]]

La définition de l’ordre lexicographique homogène consiste d’abord à comparer les termes de même poids avant d’appliquer l’ordre lexicographique, où le poids est la somme des coefficients :

P = (p0, p1,· · ·pn−1)≺lexH Q= (q0, q1,· · ·qn−1)

Le code ci-dessous implante cet ordre homogène : sage: def homogLex (P, Q):

... sp = sum (P) ; sq = sum (Q) ... if sp < sq: return int(-1) ... elif sp > sq: return int(1) ... else: return alpha (P, Q) ...

BR

OUILLON

sage: homogLex ([2, 3, 4, 6, 4], [2, 3, 4, 5, 6]) -1

La fonction sortedde Sage est une fonction au sens mathématique du terme, elle prend une liste comme premier argument et, sans la modifier, renvoie comme résultat une liste triée, contrairement à la méthodesort qui modifie la liste en place.

Sagepropose d’autres méthodes sur les listes, insertion d’un élément en fin de liste, concaténation en fin de liste, et dénombrement du nombre de répétitions d’un élément :

L.append(x) est équivalent à L[len(L):] = [x]

L.extend(L1) est équivalent à L[len(L):] = L1 L.insert(i, x) est équivalent à L[i:i] = [x]

L.count(x) est équivalent à len (select (lambda t : t == x, L)) Les commandesL.pop(i)etL.pop() suppriment l’élément d’indiceiou le dernier d’une liste, et renvoient la valeur de cet élément ; ces deux fonctions décrivent leur fonctionnement :

def pop1 (L, i): def pop2 (L):

a = L[i] return pop1 (L, len(L)-1) L[i:i+1] = []

return a

Par ailleurs L.index(x) renvoie l’indice du premier terme égal à x, et L.remove(x) enlève le premier élément de valeur x de la liste. Ces com-mandes provoquent une erreur si x n’appartient pas à la liste. Enfin la commande del L[p:q]est équivalente àL[p:q] = [].

Contrairement à de nombreux autres langages informatiques, ces fonctions modifient la listeLsans créer de nouvelles listes.

Dans le document Calcul mathématique avec Sage (Page 87-93)