PYTHON — EXAMEN MNI
Préparation EXPRESS — 7 points en poche
Stratégie : mémoriser 4 templates, savoir les adapter, connaître ~15 fonctions numpy.
CLASSEMENT par probabilité d'apparition à l'examen
# Sujet (chapitre) Source TD Probabilité
1 Jacobi / Gauss-Seidel — SEL itératifs TP1 ★★★★★
2 Dichotomie (+ variante itérative) TP4 ★★★★★
3 Interpolation Lagrange / Newton (Polynomial) TP2 ★★★★
4 Moindres carrés (régression) + Descente de gradient TP3 ★★★★
5 Tests/vérifications + tracés matplotlib Tous TP ★★★
CE QUE TU DOIS ABSOLUMENT MAÎTRISER
■ Reconnaître 4 patterns : « SEL itératif » / « f(x)=0 » / « interpoler » / « régression-optimisation ».
■ Adapter 4 templates : Jacobi, Dichotomie, polynome_lagrange, regression.
■ Connaître ~15 fonctions numpy (page suivante).
■ Savoir vectoriser : utiliser .dot(), [Link](), [Link]().
■ Toujours tester avec un exemple donné (les énoncés fournissent les données numériques).
Fonctions ESSENTIELLES (à mémoriser) — Cheat Sheet
Toutes les fonctions ci-dessous reviennent dans les 4 TP. Connais-les par cœur.
Fonction Rôle / Quand l'utiliser Mini-exemple
import numpy as np Toujours en premier import numpy as np
import [Link] as pltSi tracé demandé import [Link] as plt
Interpolation / régression
from [Link] import Polynomial P = Polynomial([1,2,3])
[Link]([...]) Créer vecteur/matrice A = [Link]([[1,2],[3,4]])
[Link]((n,m)) Matrice nulle n×m M = [Link]((3,3))
[Link]((n,1)) Vecteur colonne de 1 X0 = [Link]((10,1))
[Link](n) Matrice identité n×n I = [Link](3)
[Link](a,b,n) n points entre a et b (tracés) x = [Link](0,1,100)
[Link](a,b) Entiers de a à b-1 for i in [Link](0,n):
[Link] / len(X) Dimensions / longueur n = len(X)
A.T ou [Link](A) Transposée At = A.T
[Link](B) ou A @ B Produit matriciel C = [Link](B)
[Link](A) Inverse de A Ainv = [Link](A)
[Link](A,b) Solution exacte de AX=b X = [Link](A,b)
[Link](v) Norme euclidienne ■v■■ e = [Link](X-X_exact)
[Link]([Link](A)) Matrice diag. de A (D) D = [Link]([Link](A))
[Link](A,-1) / [Link](A,1) Tri. inf./sup. STRICTE E = -[Link](A,-1)
[Link](x) / abs(x) Valeur absolue if abs(f(c))<eps:
lambda x: ... Définir f rapidement f = lambda x: [Link](x)-2*x-2
f(x) (eval polynôme) Évaluer Polynomial P(2) → 23
Fonctions math sur vecteurs
[Link] / [Link] / [Link] / [Link] y = [Link](x) - 3*x
.append(...) Ajouter à une liste [Link](x_new)
[Link](x,y) / [Link]() Tracer une courbe [Link](x, f(x)); [Link]()
■■ Pièges classiques avec numpy :
• [Link](B) ≠ A*B. * fait du élément par élément, .dot ou @ = produit matriciel.
• [Link]([1,2,3]) est un vecteur 1D (shape (3,)). Pour un vrai vecteur colonne : .reshape(-1,1) donne
shape (3,1).
• [Link](A) coûte cher : préférer [Link](A,b) quand possible.
• Y dans TP3 est Y[:,0] car vecteur colonne — bien extraire la colonne.
Pattern 1 — Systèmes linéaires itératifs (Jacobi /
Gauss-Seidel)
Comment reconnaître l'exercice
■ Mots-clés : « méthode itérative », « Jacobi », « Gauss-Seidel », « diagonale strictement dominante
», « AX = b », « X0 = … », « epsilon », « nombre d'itérations », « [Link] » pour comparer.
Structure générale (3 fonctions s'enchaînent)
1■■ tridiag(a1, a2, a3, n) → construit A et b.
2■■ matrice_diag_dominante(A) → vérifie DSD (retourne True/False).
3■■ jacobi(A, b, X0, epsilon) ou gauss_seidel(...) → résout.
Template 1.A — matrice tridiagonale + DSD
def tridiag(a1, a2, a3, n):
A = a1*[Link](n) + a2*[Link](n,k=1) + a3*[Link](n,k=-1)
b = 2*[Link]((n,1))
return A, b
def matrice_diag_dominante(A):
n = [Link][0]
for i in range(n):
somme = sum(abs(A[i,j]) for j in range(n) if j != i)
if abs(A[i,i]) <= somme:
return False
return True
■ Astuce : [Link](n, k=1) = matrice identité décalée d'une diagonale vers le haut (super-diagonale). k=-1
→ sous-diagonale.
Template 1.B — Méthode de JACOBI (le plus probable)
def jacobi(A, b, X0, epsilon):
if not matrice_diag_dominante(A):
return "A n'est pas à diagonale strictement dominante"
D = [Link]([Link](A)) # matrice diagonale
E = -[Link](A, -1) # tri. inf. STRICTE (signe -)
F = -[Link](A, 1) # tri. sup. STRICTE (signe -)
M = D
N = E + F
Minv = [Link](M)
k = 0
while [Link]([Link](X0) - b) > epsilon:
X0 = [Link](N).dot(X0) + [Link](b)
k += 1
return X0, k
Template 1.C — Méthode de GAUSS-SEIDEL
Même structure que Jacobi, seul M et N changent :
def gauss_seidel(A, b, X0, epsilon):
if not matrice_diag_dominante(A):
return "A n'est pas à diagonale strictement dominante"
D = [Link]([Link](A))
E = -[Link](A, -1)
F = -[Link](A, 1)
M = D - E # ← SEULE DIFFÉRENCE vs Jacobi
N = F # ← SEULE DIFFÉRENCE vs Jacobi
Minv = [Link](M)
k = 0
while [Link]([Link](X0) - b) > epsilon:
X0 = [Link](N).dot(X0) + [Link](b)
k += 1
return X0, k
Décomposition A = D − E − F (à graver dans le cerveau)
• D = diagonale de A ([Link]([Link](A)))
• E = −(tri. inf. STRICTE de A) → −[Link](A, -1)
• F = −(tri. sup. STRICTE de A) → −[Link](A, 1)
• Jacobi : M = D, N = E + F
• Gauss-Seidel : M = D − E, N = F
Test typique (à savoir taper à la main)
n = 10
A, b = tridiag(4, 1, 1, n)
X0 = [Link]((n, 1))
epsilon = 1e-6
X_jac, k_jac = jacobi(A, b, X0, epsilon)
X_exact = [Link](A, b)
erreur = [Link](X_jac - X_exact)
print("Itérations :", k_jac, " Erreur :", erreur)
Pièges classiques
✗ Oublier le signe − dans E et F (E = −[Link](A,-1) avec le moins !).
✗ Confondre [Link](A) et [Link](A,-1) : le -1 exclut la diagonale (E doit avoir 0 sur la diag.).
✗ Utiliser A*B au lieu de [Link](B) ou A @ B.
✗ Oublier de vérifier DSD avant de lancer la boucle.
✗ Sortir X0 sous une forme étrange : assure-toi qu'il est shape (n,1).
Pattern 2 — Équations non linéaires f(x) = 0
Comment reconnaître
■ Mots-clés : « dichotomie », « bisection », « f(x)=0 », « racine », « précision ε », « Nmax », « point fixe
». Souvent une fonction donnée par lambda.
Template 2.A — DICHOTOMIE (THE classique)
def dichotomie(f, a, b, epsilon, Nmax):
k = 0
if f(a)*f(b) > 0:
print("f(a) et f(b) sont de même signe")
return None
c = (a + b) / 2
while abs(a - b) > epsilon and k < Nmax:
if f(c) == 0:
return c, k
elif f(a)*f(c) < 0:
b = c
else:
a = c
c = (a + b) / 2
k += 1
return c, k
Explication ligne par ligne
• if f(a)*f(b) > 0: → vérif. que f change de signe (sinon pas de racine garantie).
• c = (a+b)/2 → milieu.
• abs(a-b) > epsilon → critère d'arrêt sur la longueur de l'intervalle.
• f(a)*f(c) < 0 → racine dans [a, c], on garde [a, c]. Sinon, racine dans [c, b].
Test typique
f = lambda x: [Link](1 + x**2) - [Link](x)
a, b = 1, 2
epsilon = 1e-5
Nmax = 20
x, k = dichotomie(f, a, b, epsilon, Nmax)
print("x* ≈", x, "en", k, "itérations")
Template 2.B — Méthode itérative GÉNÉRIQUE (corde / variante)
La 2ème méthode du TP4 utilise un schéma x■■■ = x■ − [(b−a)/(f(b)−f(a))] · f(x■). À adapter selon
l'énoncé (Newton, sécante, point fixe…) :
def iterativemethod2(a, b, x0, f, epsilon):
x = [x0]
y = [f(x0)]
c = (b - a) / (f(b) - f(a)) # coefficient FIXE (corde)
while abs(y[-1]) > epsilon:
x0 = x0 - c * f(x0) # ← ICI : modifier selon le schéma
[Link](x0)
[Link](f(x0))
return x, y
■ Comment adapter selon la méthode demandée :
Méthode Ligne 'x■■■ = …' à mettre dans la boucle
Corde (TP4) x0 = x0 - ((b-a)/(f(b)-f(a))) * f(x0)
Newton x0 = x0 - f(x0)/df(x0) # df = dérivée à fournir
Point fixe x0 = g(x0) # g(x) = x ⇔ f(x)=0
Sécante x_new = x1 - f(x1)*(x1-x0)/(f(x1)-f(x0))
Variantes utiles à connaître
Newton (avec dérivée fournie ou calculée par sympy) :
def newton(f, df, x0, epsilon, Nmax):
x = [x0]
k = 0
while abs(f(x[-1])) > epsilon and k < Nmax:
x_new = x[-1] - f(x[-1]) / df(x[-1])
[Link](x_new)
k += 1
return x[-1], k
Dérivation symbolique avec sympy (si on demande df) :
import sympy as sp
x = [Link]('x')
f_sym = [Link](x**2 + 1) - [Link](x)
df_sym = [Link](f_sym, x)
# Pour utiliser dans du calcul numérique :
df = [Link](x, df_sym, 'numpy')
Pièges classiques
✗ f(a)*f(b) > 0 au lieu de < 0 : tester le BON signe.
✗ Oublier d'incrémenter k dans la boucle → boucle infinie.
✗ abs() et non [Link]() sur un scalaire (les deux marchent, mais pas confondre).
✗ [Link](x[n] - …) puis utiliser x[n] alors que la nouvelle valeur est en x[-1].
Pattern 3 — Interpolation polynomiale (Lagrange / Newton)
Comment reconnaître
■ Mots-clés : « interpoler », « polynôme d'interpolation », « base de Lagrange », « Newton », «
différences divisées », données (x■, y■), classe Polynomial.
Outil clé : la classe Polynomial
from [Link] import Polynomial
P = Polynomial([1, 2, 0, 3]) # P(x) = 1 + 2x + 0·x² + 3x³
print(P) # affiche le polynôme
print(P(2)) # évalue en x = 2
Q = P * P # produit
R = P + P # somme
■■ Ordre des coefficients : croissant (a■, a■, a■, …). Pas comme en maths !
Template 3.A — LAGRANGE
Base de Lagrange : L■(x) = ∏■≠■ (x − x■)/(x■ − x■)
def base_lagrange(X, i):
n = len(X)
L = Polynomial([1]) # polynôme constant 1
for j in range(n):
if j != i:
# facteur (x - X[j]) / (X[i] - X[j])
L = L * Polynomial([-X[j], 1]) / (X[i] - X[j])
return L
def polynome_lagrange(X, Y):
n = len(X)
P = Polynomial([0]) # polynôme nul
for i in range(n):
P = P + Y[i] * base_lagrange(X, i)
return P
■ Astuce : Polynomial([-X[j], 1]) = polynôme (x − X[j]) (coefficients [-X[j], 1] = constante d'abord, puis x).
Test typique
X = [Link]([-1, 0, 1])
Y = [Link]([2, 1, -1])
P = polynome_lagrange(X, Y)
print(P) # affiche le polynôme
print(P(0.5)) # évalue
Template 3.B — NEWTON (différences divisées)
Cherche les coefficients β■, β■, …, β■ tels que :
P(x) = β■ + β■(x−x■) + β■(x−x■)(x−x■) + …
def differences_divisees(X, Y):
n = len(X)
F = [Link](Y).astype(float) # copie modifiable
for j in range(1, n):
for i in range(n-1, j-1, -1):
F[i] = (F[i] - F[i-1]) / (X[i] - X[i-j])
return F # F[i] = β_i
def base_Newton(X, i):
W = Polynomial([1])
for j in range(i):
W = W * Polynomial([-X[j], 1]) # (x - X[j])
return W
def polynome_Newton(X, Y):
beta = differences_divisees(X, Y)
n = len(X)
P = Polynomial([0])
for i in range(n):
P = P + beta[i] * base_Newton(X, i)
return P
Pièges classiques
✗ Polynomial([1, -X[j]]) au lieu de Polynomial([-X[j], 1]) (constante d'abord !).
✗ Oublier le .astype(float) sur Y → division entière qui casse les résultats.
✗ Confondre X[j] et X[i-j] dans les différences divisées.
✗ Faire boucler for j in range(n) sur base_Newton au lieu de for j in range(i).
Pattern 4 — Moindres carrés + Descente de gradient
Comment reconnaître
■ Mots-clés : « moindres carrés », « régression », « ajuster », « pente », « descente de gradient », «
learning rate η », « fonction coût J », données expérimentales (x■, y■).
Formule fondamentale : Λ = (A■A)■¹ A■Y
où A est la matrice de Vandermonde du modèle polynomial choisi :
A = [[1, x_0, x_0², ..., x_0^p],
[1, x_1, x_1², ..., x_1^p],
...
[1, x_n, x_n², ..., x_n^p]]
Template 4.A — Construire A
def matrice(X, p):
n = len(X)
A = [Link]((n, p+1))
for j in range(p+1):
A[:, j] = X[:, 0] ** j # X[:,0] car X est vecteur colonne
return A
Template 4.B — Régression (méthode analytique)
def regression(X, Y, p):
A = matrice(X, p)
At = A.T
Lambda = [Link]([Link](A)).dot(At).dot(Y[:, 0])
return Lambda
Test typique
X = [Link]([-1, 0, 1]).reshape(-1, 1) # vecteur colonne
Y = [Link]([2, 1, -1]).reshape(-1, 1)
p = 1 # degré 1 → droite
Lambda = regression(X, Y, p)
P = Polynomial(Lambda)
print(P) # x → 0.666 - 1.5 x
■■ .reshape(-1, 1) est crucial : sans ça, X est 1D et X[:,0] plante.
Template 4.C — DESCENTE DE GRADIENT
Schéma : Λ■■■¹■ = Λ■■■ − η · ∇J(Λ■■■), avec ∇J = 2A■(AΛ − Y).
def gradient_descent(X, Y, p, Lambda0, eta, epsilon, max_iter):
A = matrice(X, p)
Lambda = [Link]()
J_hist = []
Grad_hist = []
for k in range(max_iter):
gradient = 2 * [Link]([Link](Lambda) - Y[:, 0])
Grad_hist.append(gradient)
Lambda = Lambda - eta * gradient
J = [Link]([Link](Lambda) - Y[:, 0])**2
J_hist.append(J)
if [Link](gradient) < epsilon:
break
return Lambda, J_hist, Grad_hist
Test typique
Lambda0 = [Link](p + 1)
eta = 1e-3
epsilon = 1e-4
max_iter = 10**4
Lambda_app, J_hist, Grad_hist = gradient_descent(
X, Y, p, Lambda0, eta, epsilon, max_iter)
print(Polynomial(Lambda_app))
■ Choix du learning rate η :
• η trop grand (ex. 10■¹) → divergence ou oscillations.
• η trop petit (ex. 10■■) → convergence très lente.
• η ≈ 10■³ est souvent le bon compromis. Justifier ainsi en exam.
Pièges classiques
✗ Oublier .reshape(-1, 1) sur X et Y.
✗ Utiliser Y au lieu de Y[:, 0] dans le gradient (problème de shape).
✗ Oublier le facteur 2 dans le gradient (∇J = 2A■(AΛ−Y)).
✗ Oublier Lambda = [Link]() → modifie l'argument original.
✗ Inverser [Link](A) et [Link](A.T).
Fiche FINALE — Dernière heure avant l'examen
1. Tableau ÉCLAIR : type d'exercice → template
Ce que l'énoncé demande Template à utiliser
« Résoudre AX = b par Jacobi/Gauss-Seidel » jacobi(A,b,X0,eps) ou gauss_seidel(...)
« Vérifier la convergence » matrice_diag_dominante(A) → True/False
« Solution exacte pour comparer » [Link](A, b)
« Erreur en norme euclidienne » [Link](X_approx - X_exact)
« Approcher la racine de f(x)=0 » dichotomie(f, a, b, eps, Nmax)
« Schéma x■■■ = … donné » iterativemethod2 + adapter la ligne x0 = …
« Méthode de Newton » newton(f, df, x0, eps, Nmax)
« Polynôme interpolant (x■, y■) » polynome_lagrange(X, Y) ou polynome_Newton(X, Y)
« Coefficients différences divisées » differences_divisees(X, Y)
« Droite de régression / ajustement » Lambda = regression(X, Y, p) ; Polynomial(Lambda)
« Estimer Λ par descente de gradient » gradient_descent(X, Y, p, L0, eta, eps, Nmax)
« Tracer la courbe et les points » [Link](x, f(x)) ; [Link](X, Y)
2. Squelette UNIVERSEL d'une réponse d'exam Python
# 1) Imports — TOUJOURS en premier
import numpy as np
import [Link] as plt
from [Link] import Polynomial
# 2) Définir les fonctions/données de l'énoncé
f = lambda x: ... # f donnée par l'énoncé
A, b = ..., ... # matrice / vecteur si SEL
X, Y = ..., ... # points si interp./régression
# 3) Définir la/les fonctions demandées
def methode(...):
# ... corps de la fonction
return ...
# 4) APPLIQUER avec les paramètres demandés
resultat = methode(...)
print(resultat)
# 5) (Optionnel) Tracé
[Link](...); [Link](True); [Link]()
3. Erreurs FATALES à éviter (perte de points sûre)
■ Oublier import numpy as np au début.
■ Confondre * (élément par élément) et .dot() (produit matriciel).
■ Oublier le signe − dans E = −[Link](A,-1) et F = −[Link](A,1).
■ Oublier de retourner ce qui est demandé (la solution ET le nombre d'itérations).
■ Boucle infinie : oublier k += 1 ou la mise à jour de X0.
■ Polynomial : ordre des coeffs croissant (constante en premier).
■ Régression : oublier .reshape(-1, 1) sur X et Y.
■ Tester sa fonction sur l'exemple fourni par l'énoncé (souvent demandé après la définition).
4. Conseils stratégiques de timing (sur ~30 min Python)
• 5 min : lire l'énoncé, identifier le pattern (1, 2, 3 ou 4).
• 15 min : écrire le template adapté + tester sur l'exemple donné.
• 5 min : répondre aux sous-questions (erreur, itérations, comparaison).
• 5 min : relire, vérifier les return, les indentations, les :.
5. Mantra Python d'examen
1) Pattern → Template → Adapter.
2) Toujours import numpy as np en haut.
3) Toujours return ce qui est demandé.
4) Toujours tester sur l'exemple de l'énoncé.
5) Si tu hésites entre * et .dot → c'est .dot.
■ 7 points dans la poche. Bon courage !