Résolution numérique de systèmes linéaires

Cours ENPC — Pratique du calcul scientifique

Objectif

But de ce chapitre

Étudier les méthodes numériques pour l’équation linéaire \[ \mathsf A \mathbf{\boldsymbol{x}} = \mathbf{\boldsymbol{b}}, \]\(\mathsf A \in \mathbf R^{n \times n}\) et \(b \in \mathbf R^n.\)

Deux classes de méthodes :

  • Méthodes directes :

    • Décomposition LU (pour les matrices inversibles générales) ;

    • Décomposition de Cholesky (pour les matrices symétriques définies positives)

  • Méthodes itératives :

    • Méthodes itératives de base par décomposition ;

    • Gradient conjugué ;

    • Et bien d’autres : GMRES, BiCGStab, etc.

Avant de présenter ces méthodes, nous introduisons la notion de conditionnement.

Conditionnement des systèmes linéaires

  • Supposons que nous voulions calculer numériquement la solution \((1, -1)^T\) de \[ \mathsf A \mathbf{\boldsymbol{x}} := \begin{pmatrix} 1 & 1 \\ 1 & 1 - 10^{-12} \end{pmatrix} \begin{pmatrix} x_1 \\ x_2 \end{pmatrix} = \begin{pmatrix} 0 \\ 10^{-12} \end{pmatrix} =: \mathbf{\boldsymbol{b}}. \]
  • En Julia, on peut calculer la solution avec l’opérateur \

    A = [1 1; 1 (1-1e-12)]
    b = [0; 1e-12]
    x = A\b
    2-element Vector{Float64}:
      1.0000221222095027
     -1.0000221222095027

    Pourquoi l’erreur relative est-elle bien plus grande que l’epsilon machine ?

  • Julia ne résout pas \(\mathsf A \mathbf{\boldsymbol{x}} = \mathbf{\boldsymbol{b}}\) mais \[(\mathsf A + \Delta \mathsf A) (\mathbf{\boldsymbol{x}} + \Delta \mathbf{\boldsymbol{x}}) = (\mathbf{\boldsymbol{b}} + \Delta \mathbf{\boldsymbol{b}})\]\(\Delta \mathsf A\) et \(\Delta \mathbf{\boldsymbol{b}}\) sont les erreurs d’arrondi, et \(\Delta \mathbf{\boldsymbol{x}}\) est la perturbation résultante de la solution.

Question : Peut-on estimer \(\frac{{\lVert {\Delta \mathbf{\boldsymbol{x}}} \rVert}}{{\lVert {\mathbf{\boldsymbol{x}}} \rVert}}\) en fonction de \(\frac{{\lVert {\Delta \mathsf A} \rVert}}{{\lVert {\mathsf A} \rVert}}\) et \(\frac{{\lVert {\Delta \mathbf{\boldsymbol{b}}} \rVert}}{{\lVert {\mathbf{\boldsymbol{b}}} \rVert}}\) ?

Rappels : normes vectorielles et matricielles (1/3)

Pour \(p \in [1, \infty]\), la \(p\)-norme d’un vecteur \(\mathbf{\boldsymbol{x}} \in \mathbf R^n\) est définie par : \[ {\lVert {\mathbf{\boldsymbol{x}}} \rVert}_p := \begin{cases} \left( \sum_{i=1}^{n} {\lvert {x_i} \rvert}^p \right)^{\frac{1}{p}} & \text{si $p < \infty$}, \\ \max \Bigl\{ {\lvert {x_1} \rvert}, \dotsc, {\lvert {x_n} \rvert} \Bigr\} & \text{si $p = \infty$}. \end{cases} \] En Julia, calculer \({\lVert {\mathbf{\boldsymbol{x}}} \rVert}_p\) avec norm(x, p).

Code
Plots.plot(aspect_ratio=:equal, xlims=(-1.1,1.1), ylims=(-1.1, 1.1))
Plots.plot!(framestyle=:origin, grid=true, legend=:outertopright)
Plots.plot!(title="Cercle unité dans différentes normes")
Plots.plot!([0, 1, 0, -1, 0], [-1, 0, 1, 0, -1], label=L"$p = 1$ (norme taxicab)")
Plots.plot!(t -> cos(t), t -> sin(t), 0, 2π, label=L"$p = 2$ (norme euclidienne)")
Plots.plot!([1, 1, -1, -1, 1], [1, -1, -1, 1, 1], label=L"p = \infty")

Rappels : normes vectorielles et matricielles (2/3)

La norme d’opérateur sur les matrices induite par la \(p\)-norme vectorielle est donnée par \[ {\lVert {\mathsf A} \rVert}_{p} := \sup_{{\lVert {\mathbf{\boldsymbol{x}}} \rVert}_{p} \leqslant 1} {\lVert {\mathsf A \mathbf{\boldsymbol{x}}} \rVert}_{p} \] Il découle de la définition que \({\lVert {\mathsf A \mathsf B} \rVert}_p \leqslant{\lVert {\mathsf A} \rVert}_p {\lVert {\mathsf B} \rVert}_p\). En Julia, calculer \({\lVert {\mathsf A} \rVert}_p\) avec opnorm(A, p).

Exercices

Montrer que

  • La 2-norme matricielle est donnée par \(\sqrt{\lambda_{\rm max}(\mathsf A^* \mathsf A)}\).

  • La 1-norme matricielle est le maximum des sommes absolues des colonnes :

    \[{\lVert {\mathsf A} \rVert}_1 = \max_{1 \leqslant j \leqslant n} \sum_{i=1}^{n} {\lvert {a_{ij}} \rvert}.\]

  • La \(\infty\)-norme matricielle est le maximum des sommes absolues des lignes :

    \[{\lVert {\mathsf A} \rVert}_{\infty} = \max_{1 \leqslant i \leqslant n} \sum_{j=1}^{n} {\lvert {a_{ij}} \rvert}.\]

Rappels : normes vectorielles et matricielles (3/3)

À partir des normes matricielles, on définit le nombre de conditionnement d’une matrice par \[ \kappa_p(\mathsf A) = {\lVert {\mathsf A} \rVert}_p {\lVert {\mathsf A^{-1}} \rVert}_p \]

Propriétés :

  • \(\kappa_p(\mathsf I) = 1\)

  • \(\kappa_p(\mathsf A) \geqslant 1\)

  • \(\kappa_p(\alpha \mathsf A) = \kappa_p(\mathsf A)\)

En Julia, calculer le nombre de conditionnement avec cond(A, p).

Conditionnement des systèmes linéaires

Proposition

Soit \(\mathbf{\boldsymbol{x}} + \Delta \mathbf{\boldsymbol{x}}\) la solution de \[ \mathsf A (\mathbf{\boldsymbol{x}} + \Delta \mathbf{\boldsymbol{x}}) = \mathbf{\boldsymbol{b}} + \Delta \mathbf{\boldsymbol{b}} \] L’inégalité suivante est vérifiée : \[ \frac{{\lVert {\Delta \mathbf{\boldsymbol{x}}} \rVert}}{{\lVert {\mathbf{\boldsymbol{x}}} \rVert}} \leqslant\kappa(\mathsf A) \frac{{\lVert {\Delta \mathbf{\boldsymbol{b}}} \rVert}}{{\lVert {\mathbf{\boldsymbol{b}}} \rVert}} \]

Preuve

Par définition de \(\Delta \mathbf{\boldsymbol{x}}\), on a \(\mathsf A \Delta \mathbf{\boldsymbol{x}} = \Delta \mathbf{\boldsymbol{b}}\). Donc \[ \begin{aligned} {\lVert {\Delta \mathbf{\boldsymbol{x}}} \rVert} &= {\lVert {\mathsf A^{-1} \Delta \mathbf{\boldsymbol{b}}} \rVert} \leqslant{\lVert {\mathsf A^{-1}} \rVert} {\lVert {\Delta \mathbf{\boldsymbol{b}}} \rVert} \\ &= \frac{{\lVert {\mathsf A \mathbf{\boldsymbol{x}}} \rVert}}{{\lVert {\mathbf{\boldsymbol{b}}} \rVert}} {\lVert {\mathsf A^{-1}} \rVert} {\lVert {\Delta \mathbf{\boldsymbol{b}}} \rVert} \leqslant\frac{{\lVert {\mathsf A} \rVert} {\lVert {\mathbf{\boldsymbol{x}}} \rVert}}{{\lVert {\mathbf{\boldsymbol{b}}} \rVert}} {\lVert {\mathsf A^{-1}} \rVert} {\lVert {\Delta \mathbf{\boldsymbol{b}}} \rVert}. \end{aligned} \] En réarrangeant, on obtient l’énoncé.

Proposition

Soit \(\mathbf{\boldsymbol{x}} + \Delta \mathbf{\boldsymbol{x}}\) la solution de \[ (\mathsf A + \Delta \mathsf A) (\mathbf{\boldsymbol{x}} + \Delta \mathbf{\boldsymbol{x}}) = \mathbf{\boldsymbol{b}} \] Si \(\mathsf A\) est inversible et \({\lVert {\Delta \mathsf A} \rVert} < \frac{1}{2} {\lVert {\mathsf A^{-1}} \rVert}^{-1}\), alors \[ \frac{{\lVert {\Delta \mathbf{\boldsymbol{x}}} \rVert}}{{\lVert {\mathbf{\boldsymbol{x}}} \rVert}} \leqslant 2\kappa(\mathsf A) \frac{{\lVert {\Delta \mathsf A} \rVert}}{{\lVert {\mathsf A} \rVert}} \]

Conclusion : \(\kappa(\mathsf A)\) mesure la sensibilité aux perturbations :

  • utile pour estimer l’impact des erreurs d’arrondi ;

  • influence la vitesse de convergence des méthodes (voir plus loin).

  • Lorsque \(\kappa_p(\mathsf A) \gg 1\), le système est dit mal conditionné.

Illustration numérique

Considérons le système linéaire \[ \mathsf A(α) \mathbf x := \begin{pmatrix} 1 & 1 \\ 1 & 1 - α \end{pmatrix} \begin{pmatrix} x_1 \\ x_2 \end{pmatrix} = \begin{pmatrix} π \\ π - πα \end{pmatrix} =: \mathbf b(α). \]

On trace sur le même graphe les fonctions qui à \(\alpha\) associent …

  • … la quantité \(\kappa_2\bigl(\mathsf A(α)\bigr) \times ε\), où \(ε\) est l’epsilon machine pour le format Float64.

  • … l’erreur relative en norme euclidienne, obtenue en résolvant le système linéaire avec l’opérateur \.

Af(α) = [1. 1.; 1. (1-α)]
bf(α) = [π; π - π*α]

# Solution exacte
x_exact = [0.; π]

# Plage de α
αs = 10. .^ (-15:.1:-2)
rel_err(α) = norm(Af(α)\bf(α) - x_exact)/norm(x_exact)
Plots.plot(αs, cond.(Af.(αs)) * eps(), label=L"κ_2(A) \times ε")
Plots.plot!(αs, rel_err.(αs), label=L"erreur $ℓ^2$")
Plots.plot!(xscale=:log10, yscale=:log10, xlabel=L"α", bottom_margin=5Plots.mm)

Méthodes directes

  • On calcule d’abord la décomposition \(\mathsf L \mathsf U\) de \(\mathsf A\) avec

    • \(\mathsf U\) matrice triangulaire supérieure ;

    • \(\mathsf L\) matrice triangulaire inférieure unitaire.

  • Puis on résout \(\mathsf L \mathbf{\boldsymbol{y}} = \mathbf{\boldsymbol{b}}\) par substitution avant.

    y = copy(b)
    for i in 2:n
        for j in 1:i-1
            y[i] -= L[i, j] * y[j]
        end
    end
  • Enfin, on résout \(\mathsf U \mathbf{\boldsymbol{x}} = \mathbf{\boldsymbol{y}}\) par substitution arrière.

Remarque : La décomposition LU peut ne pas exister

En pratique, on utilise la décomposition \(\mathsf P \mathsf A = \mathsf L \mathsf U\), avec \(\mathsf P\) une matrice de permutation.

  • Garantie d’existence si \(\mathsf A\) est inversible ;

  • Plus stable numériquement.

Décomposition LU par élimination de Gauss

\[ \begin{pmatrix} 2 & 1 & -1 \\ -3 & -1 & 2 \\ -2 & 1 & 2 \end{pmatrix} =: \mathsf A \]

\[ \underbrace{ \begin{pmatrix} 1 & 0 & 0 \\ {\color{red}\frac{3}{2}} & 1 & 0 \\ {\color{red}{1}} & 0 & 1 \end{pmatrix} }_{=: \, \mathsf M_1}~ \underbrace{ \begin{pmatrix} 2 & 1 & -1 \\ -3 & -1 & 2 \\ -2 & 1 & 2 \end{pmatrix} }_{\mathsf A} = \begin{pmatrix} 2 & 1 & -1 \\ {\color{red} 0} & \frac{1}{2} & \frac{1}{2} \\ {\color{red} 0} & 2 & 1 \end{pmatrix} \]

\[ \underbrace{ \begin{pmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & {\color{blue} -4} & 1 \end{pmatrix} }_{=: \, \mathsf M_2}~ \underbrace{ \begin{pmatrix} 1 & 0 & 0 \\ {\color{red}\frac{3}{2}} & 1 & 0 \\ {\color{red}{1}} & 0 & 1 \end{pmatrix} }_{=: \, \mathsf M_1}~ \underbrace{ \begin{pmatrix} 2 & 1 & -1 \\ -3 & -1 & 2 \\ -2 & 1 & 2 \end{pmatrix} }_{\mathsf A} = \underbrace{ \begin{pmatrix} 2 & 1 & -1 \\ {\color{red} 0} & \frac{1}{2} & \frac{1}{2} \\ {\color{red} 0} & {\color{blue} 0} & -1 \end{pmatrix} }_{=: \, \mathsf U} \]

Les transformations de Gauss \(\mathsf M_1\), \(\mathsf M_2\) sont simples à inverser et à multiplier. En particulier \[ \mathsf A = \mathsf M_1^{-1} \mathsf M_2^{-1} \mathsf U = \underbrace{ \begin{pmatrix} 1 & 0 & 0 \\ {\color{red}-\frac{3}{2}} & 1 & 0 \\ {\color{red}{-1}} & 0 & 1 \end{pmatrix} }_{=: \, \mathsf M_1^{-1}}~ \underbrace{ \begin{pmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & {\color{blue} 4} & 1 \end{pmatrix} }_{=: \, \mathsf M_2^{-1}}~ \mathsf U = \underbrace{ \begin{pmatrix} 1 & 0 & 0 \\ {\color{red}-\frac{3}{2}} & 1 & 0 \\ {\color{red}{-1}} & {\color{blue} 4} & 1 \end{pmatrix} }_{\mathsf M_1^{-1} \mathsf M_2^{-1} =: \, \mathsf L}~ \mathsf U \]

Décomposition LU : coût de calcul

# A est une matrice inversible de taille n x n
L = [r == c ? 1.0 : 0.0 for r in 1:n, c in 1:n]
U = copy(A)
for c in 1:n-1, r in c+1:n
   U[c, c] == 0 && error("L'entrée pivot est nulle !")
   L[r, c] = U[r, c] / U[c, c]
   U[r, c:end] -= U[c, c:end] * L[r, c]
end
# L est triangulaire inférieure unitaire et U est triangulaire supérieure

\(~\)

  • Coût de calcul : \(\frac{2}{3} n^3 + \mathcal O(n^2)\) opérations en virgule flottante (flops) ;

  • Par comparaison, le coût de calcul de la substitution avant/arrière est en \(\mathcal O(n^2)\) ;

  • La décomposition LU peut être réutilisée pour différents membres de droite ;

  • Si \(\mathsf A\) est une matrice bande, \(\mathsf L\) et \(\mathsf U\) le sont aussi, avec la même largeur de bande ;

  • \(\mathsf L\) et \(\mathsf U\) ne sont pas nécessairement creuses lorsque \(\mathsf A\) est creuse.

Comparaison avec d’autres approches directes

Alternative 1 : Calculer \(\mathsf A^{-1}\) en appliquant des opérations sur les lignes de la matrice étendue \([\mathsf A | \mathsf I]\), puis poser \(\mathbf x = \mathsf A^{-1} \mathbf b\)

  • Revient à résoudre \(\mathsf A \mathbf{\boldsymbol{x}}_i = \mathbf{\boldsymbol{e}}_i\) pour tout \(i\), puis à combiner linéairement les solutions ;

  • ❌ Moins stable numériquement (plus d’erreurs d’arrondi) ;

  • ❌ Coût de calcul également en \(\mathcal O(n^3)\), mais avec un préfacteur plus grand.

Alternative 2 : Calculer \(\mathbf{\boldsymbol{x}}\) par élimination de Gauss sur la matrice étendue \([\mathsf A | \mathbf{\boldsymbol{b}}]\)

  • ✔️ Coût de calcul à peu près identique à la factorisation \(\mathsf L \mathsf U\) ;

  • ❌ Pas idéal lorsqu’on résout plusieurs systèmes \(\mathsf A \mathbf{\boldsymbol{x}}_i = \mathbf{\boldsymbol{b}}_i\) avec la même matrice.

using LinearAlgebra
A = [1 1 1; 1 2 3; 1 4 9]
A = factorize(A)
@show A  # Remarque : A peut encore être utilisée comme matrice par la suite !
A = LU{Float64, Matrix{Float64}, Vector{Int64}}([1.0 1.0 1.0; 1.0 3.0 8.0; 1.0 0.3333333333333333 -0.6666666666666665], [1, 3, 3], 0)
LU{Float64, Matrix{Float64}, Vector{Int64}}
L factor:
3×3 Matrix{Float64}:
 1.0  0.0       0.0
 1.0  1.0       0.0
 1.0  0.333333  1.0
U factor:
3×3 Matrix{Float64}:
 1.0  1.0   1.0
 0.0  3.0   8.0
 0.0  0.0  -0.666667

Méthode directe pour \(\mathsf A\) symétrique définie positive

  • Il est plus efficace de calculer la factorisation de Cholesky \(\mathsf A = \mathsf C \mathsf C^*\) avec \(\mathsf C\) triangulaire inférieure à éléments diagonaux positifs.
  • Détermination de \(\mathsf C\) par identification colonne par colonne, d’abord le terme diagonal puis les autres termes : \[a_{ij}=\sum_{k=1}^{\min{(i,j)}}c_{ik}\overline{c_{jk}} \quad ⇒\quad ∀j=1\ldots n\quad c_{jj}=\sqrt{a_{jj}-\sum_{k=1}^{j-1}\lvert c_{jk}\rvert^2} \quad\textrm{ et }\quad ∀i=j+1\ldots n \quad c_{ij}=\frac{a_{ij}-\sum_{k=1}^{j-1}c_{ik}\overline{c_{jk}}}{c_{jj}}\]
function cholesky(A)
    n = size(A, 1)
    C = copy(LowerTriangular(A))
    for j  1:n
        Cⱼₖ = C[j, 1:j-1]
        C[j,j] -= Cⱼₖ'Cⱼₖ
        C[j,j] = √C[j,j]
        for i  j+1:n
            C[i,j] -= Cⱼₖ'C[i, 1:j-1]
            C[i,j] = C[i,j]/C[j,j]
        end
    end
    return C
end
Code
using Polynomials, Statistics
generate_defpos_matrix(n) = begin A = rand(n,n); A'A + I end
generate_defpos_matrix(1000) |> cholesky # Pour forcer la compilation

nb_samples = 10
Plots.plot(xaxis=:log10, yaxis=:log10, xlabel="n", ylabel="Temps CPU", legend=:topleft, size=(900,400),
           bottom_margin=5Plots.mm, left_margin=5Plots.mm, top_margin=5Plots.mm)
tf, tb = Float64[], Float64[]
tn = 2 .^(6:9)
for n in tn
    A = generate_defpos_matrix(n)
    push!(tf, mean(@elapsed cholesky(A) for _ in 1:nb_samples))
end

Pf = fit(log10.(tn), log10.(tf), 1) ; af = round(coeffs(Pf)[2]; digits=2)
Plots.plot!(tn, tf, marker=:o, label=L"Matrice dense $n^{%$af}$")
Plots.xticks!(tn, [L"2^{%$p}" for p in 6:9])

Cholesky pour les matrices bandes

  • \(\mathsf A\) est une matrice bande, c.-à-d. qu’il existe \(b\in{\mathbb{{N}}}\) tel que \(a_{ij}=0\) si \(|i-j|>b\).
  • Il s’ensuit que \(\mathsf C\) est aussi une matrice bande de même largeur de bande.

\[∀j=1\ldots n\quad c_{jj}=\sqrt{a_{jj}-\sum_{k=\max{(1,j-b)}}^{j-1}\lvert c_{jk}\rvert^2} \quad\textrm{ et }\quad ∀i=j+1\ldots \min{(n,j+b)} \quad c_{ij}=\frac{a_{ij}-\sum_{k=\max{(1,j-b)}}^{j-1}c_{ik}\overline{c_{jk}}}{c_{jj}}\]

function cholesky_banded(A, b)
    n = size(A, 1)
    C = copy(LowerTriangular(A))
    for j  1:n
        m, M = max(1,j-b), min(n,j+b)
        Cⱼₖ = C[j, m:j-1]
        C[j,j] -= Cⱼₖ'Cⱼₖ
        C[j,j] = √C[j,j]
        for i  j+1:M
            C[i,j] -= Cⱼₖ'C[i, m:j-1]
            C[i,j] = C[i,j]/C[j,j]
        end
    end
    return C
end
Code
function generate_banded_matrix(n, b)
    C = [jij+b ? rand() : 0.0 for i in 1:n, j in 1:n]
    return C*C'+I
end

b = 4; A = generate_banded_matrix(10, b)
cholesky_banded(A, b) # Pour forcer la compilation

Plots.plot(xaxis=:log10, yaxis=:log10, xlabel="n", ylabel="Temps CPU", legend=:topleft, size=(900,400),
           bottom_margin=5Plots.mm, left_margin=5Plots.mm, top_margin=5Plots.mm)
tf, tb = Float64[], Float64[]
tn = 2 .^(6:9)
for n in tn
    A = generate_banded_matrix(n, b)
    push!(tf, mean(@elapsed cholesky(A) for _ in 1:nb_samples))
    push!(tb, mean(@elapsed cholesky_banded(A,b) for _ in 1:nb_samples))
end

Pf = fit(log10.(tn), log10.(tf), 1) ; af = round(coeffs(Pf)[2]; digits=2)
Plots.plot!(tn, tf, marker=:o, label=L"Matrice dense $n^{%$af}$")

ntn = 2 .^(10:12)
for n in ntn
    A = generate_banded_matrix(n, b)
    push!(tb, mean(@elapsed cholesky_banded(A,b) for _ in 1:nb_samples))
end
append!(tn,ntn)
Pb = fit(log10.(tn),log10.(tb),1) ; ab = round(coeffs(Pb)[2]; digits=2)
Plots.plot!(tn, tb, marker=:diamond, label="Matrice bande "*latexstring("n^{$(ab)}"))
Plots.xticks!(ntn, [L"2^{%$p}" for p in 6:12])

Méthodes itératives

Motivation : Les méthodes directes d’usage général sont

  • exactes à des erreurs d’arrondi près

  • mais coûteuses en calcul : \(\mathcal O(n^3)\) flops pour les matrices pleines…

  • De plus, elles requièrent le stockage de \(\mathsf L\) et \(\mathsf U\).

\(~\)

En revanche, les méthodes itératives

  • sont en général approchées (mais il existe des exceptions) ;

  • ont en général un coût par itération en \(\mathcal O(n^2)\) au plus ;

    \(\rightarrow\) souvent plus économiques en calcul

  • peuvent être arrêtées à tout moment lorsque le résidu \(\mathsf A \mathbf{\boldsymbol{x}} - \mathbf{\boldsymbol{b}}\) est suffisamment petit ;

\(~\)

Par souci de simplicité, on se restreint désormais au cas où \(\mathsf A \in \mathbf R^{n \times n}\) est symétrique définie positive.

Une première méthode itérative

Méthode de Richardson

\[\begin{align*} \mathbf{\boldsymbol{x}}^{(k + 1)} = \mathbf{\boldsymbol{x}}^{(k)} + \omega (\mathbf{\boldsymbol{b}} - \mathsf A \mathbf{\boldsymbol{x}}^{(k)}) \end{align*}\]

Proposition

Supposons \(\omega \neq 0\). Si \((\mathbf{\boldsymbol{x}}^{(k)})\) converge dans l’itération ci-dessus, alors elle converge vers la solution de \[\begin{align*} \mathsf A \mathbf{\boldsymbol{x}} = \mathbf{\boldsymbol{b}}. \end{align*}\]

Questions :

  • Cette méthode converge-t-elle et à quelle vitesse ?

  • Quel est un bon critère d’arrêt ?

Rayon spectral

Définition

Le rayon spectral de \(\mathsf A \in \mathbf R^{n \times n}\) est donné par \[ \rho(\mathsf A) := \max_{\lambda \in \mathop{\mathrm{spectrum}}A} {\lvert {\lambda} \rvert} \]

Remarques :

  • \(\rho(A)\) n’est pas une norme ;

  • \(\rho(A) \leqslant{\lVert {\mathsf A} \rVert}\) pour toute norme matricielle induite.

  • 🔎 Formule de Gelfand : Pour tout \(\mathsf A \in \mathbf R^{n \times n}\) et toute norme matricielle \({\lVert {\cdot} \rVert}\), \[ \lim_{k \to \infty} {\lVert {\mathsf A^k} \rVert}^{1/k} = \rho(\mathsf A). \]

Analyse de la méthode de Richardson (1/2)

\[\begin{align*} \mathbf{\boldsymbol{x}}^{(k + 1)} = \mathbf{\boldsymbol{x}}^{(k)} + \omega (\mathbf{\boldsymbol{b}} - \mathsf A \mathbf{\boldsymbol{x}}^{(k)}) \end{align*}\]

Proposition

L’itération de Richardson converge vers la solution exacte pour tout choix de \(\mathbf{\boldsymbol{x}}^{(0)}\) si et seulement si \[\begin{align*} \lambda := \rho(\mathsf I - \omega \mathsf A) = \max_{\lambda \in \mathop{\mathrm{spectrum}}A} {\lvert {1 - \omega \lambda} \rvert} < 1. \end{align*}\] De plus \(\| \mathbf{\boldsymbol{x}}^{(k)} - \mathbf{\boldsymbol{x}}_* \|_2 \leqslant\lambda^k \| \mathbf{\boldsymbol{x}}^{(0)} - \mathbf{\boldsymbol{x}}_* \|_2\) pour tout \(k \in \mathbb N\).

Preuve

On remarque que \[ \mathbf{\boldsymbol{x}}^{(k+1)} - \mathbf{\boldsymbol{x}}_* = \mathbf{\boldsymbol{x}}^{(k)} - \mathbf{\boldsymbol{x}}_* + \omega (\mathsf A \mathbf{\boldsymbol{x}}_* - \mathsf A \mathbf{\boldsymbol{x}}^{(k)}) = (\mathsf I - \omega \mathsf A) \left( \mathbf{\boldsymbol{x}}^{(k)} - \mathbf{\boldsymbol{x}}_* \right). \] Donc \[ \mathbf{\boldsymbol{x}}^{(k)} - \mathbf{\boldsymbol{x}}_* = (\mathsf I - \omega \mathsf A)^k \left( \mathbf{\boldsymbol{x}}^{(0)} - \mathbf{\boldsymbol{x}}_* \right) \] L’énoncé découle de la diagonalisation de la matrice \(\mathsf I - \omega \mathsf A\).

Corollaire : Il est nécessaire pour la convergence que toutes les valeurs propres aient des parties réelles non nulles de même signe.

Lien avec l’optimisation

Exercice : trouver le \(\omega\) qui minimise \(\rho(\mathsf I - \omega \mathsf A)\)

Des calculs simples donnent \[ \omega_* = \frac{2}{\lambda_{\min}(\mathsf A) + \lambda_{\max}(\mathsf A)}, \qquad \rho(\mathsf I - \omega_* \mathsf A) = \frac{\kappa_2(\mathsf A) - 1}{\kappa_2(\mathsf A) + 1} \]

\(~\)

Analyse de la méthode de Richardson (2/2)

Puisque \(\mathsf A\) est supposée symétrique définie positive, la solution de \(\mathsf A \mathbf{\boldsymbol{x}} = \mathbf{\boldsymbol{b}}\) est le minimiseur de \[ f(\mathbf{\boldsymbol{x}}) = \frac{1}{2} \mathbf{\boldsymbol{x}}^T\mathsf A \mathbf{\boldsymbol{x}} - \mathbf{\boldsymbol{b}}^T\mathbf{\boldsymbol{x}}. \] Dans ce cas, l’itération de Richardson peut s’écrire \[ \mathbf{\boldsymbol{x}}^{(k+1)} = \mathbf{\boldsymbol{x}}^{(k)} - \omega \nabla f(\mathbf{\boldsymbol{x}}^{(k)}). \]

Illustration de la méthode de Richardson

Considérons le système linéaire \[ \begin{pmatrix} 2 & 1 \\ 1 & 2 \end{pmatrix} \begin{pmatrix} x_1 \\ x_2 \end{pmatrix} = \begin{pmatrix} 7 \\ 8 \end{pmatrix} \]

  • La solution exacte est \((2, 3)^T\) ;

  • Les valeurs propres de \(\mathsf A\) sont 1 et 3 ;

  • Le nombre de conditionnement \(\kappa_2(\mathsf A)\) vaut 3 ;

  • Le \(\omega\) optimal est \(\frac{1}{2}\).

Courbes de niveau de \[f(\mathbf{\boldsymbol{x}}) = \frac{1}{2} \mathbf{\boldsymbol{x}}^T\mathsf A \mathbf{\boldsymbol{x}} - \mathbf{\boldsymbol{b}}^T\mathbf{\boldsymbol{x}}.\]

Illustration de la méthode de Richardson : \(\omega = .2\)

Illustration de la méthode de Richardson : \(\omega = .6\)

Illustration de la méthode de Richardson : \(\omega\) optimal \(= .5\)

🔎 Méthodes itératives de base plus générales

Considérons la décomposition \[ \mathsf A = {\color{green}\mathsf M} - {\color{blue} \mathsf N} \]\(\mathsf M\) est inversible et facile à inverser. Alors \[ \mathsf A \mathbf{\boldsymbol{x}}_* = \mathbf{\boldsymbol{b}} \quad \Leftrightarrow \quad {\color{green}\mathsf M} \mathbf{\boldsymbol{x}}_* = {\color{blue} \mathsf N} \mathbf{\boldsymbol{x}}_* + \mathbf{\boldsymbol{b}} \] ce qui suggère la méthode itérative \[ {\color{green}\mathsf M} \mathbf{\boldsymbol{x}}^{(k+1)} = {\color{blue} \mathsf N} \mathbf{\boldsymbol{x}}^{(k)} + \mathbf{\boldsymbol{b}} \]

Méthodes itératives de base standard (\(\mathsf A = \mathsf L + \mathsf D + \mathsf U\))

  • La méthode de Richardson correspond à \[ \mathsf A = \underbrace{{\color{green}\frac{1}{\omega} \mathsf I }}_{\mathsf M} - \underbrace{\left({\color{blue} \frac{1}{\omega} \mathsf I - \mathsf A}\right)}_{\mathsf N} \]

  • Itération de Jacobi : \(\mathsf A = {\color{green}\mathsf D} - ({\color{blue}-\mathsf L - \mathsf U})\).

  • Itération de Gauss-Seidel : \(\mathsf A = ({\color{green}\mathsf D + \mathsf L}) - ({\color{blue}- \mathsf U})\)

Proposition : convergence de la méthode par décomposition

  • L’itération \[ {\color{green}\mathsf M} \mathbf{\boldsymbol{x}}^{(k+1)} = {\color{blue} \mathsf N} \mathbf{\boldsymbol{x}}^{(k)} + \mathbf{\boldsymbol{b}} \] converge pour tout \(\mathbf{\boldsymbol{x}}^{(0)}\) initial si et seulement si \(\rho({\color{green}\mathsf M}^{-1} {\color{blue} \mathsf N}) < 1\).

  • De plus, pour tout \(\varepsilon > 0\) il existe \(K > 0\) tel que \[ \forall k \geqslant K, \qquad {\lVert {\mathbf{\boldsymbol{x}}^{(k)} - \mathbf{\boldsymbol{x}}_*} \rVert} \leqslant\bigl(\rho({\color{green}\mathsf M}^{-1} {\color{blue} \mathsf N}) + \varepsilon\bigr)^k {\lVert {\mathbf{\boldsymbol{x}}^{(0)} - \mathbf{\boldsymbol{x}}_*} \rVert}. \]

    Exercice : prouver ce résultat en utilisant la formule de Gelfand.

🔎 Convergence de la méthode itérative de base générale : solution

Preuve

En soustrayant les équations \[ \begin{aligned} {\color{green}\mathsf M} \mathbf{\boldsymbol{x}}^{(k+1)} &= {\color{blue} \mathsf N} \mathbf{\boldsymbol{x}}^{(k)} + \mathbf{\boldsymbol{b}} \\ {\color{green}\mathsf M} \mathbf{\boldsymbol{x}}_* &= {\color{blue} \mathsf N} \mathbf{\boldsymbol{x}}_* + \mathbf{\boldsymbol{b}} \end{aligned} \] et en réarrangeant, on obtient \[ \mathbf{\boldsymbol{x}}^{(k+1)} - \mathbf{\boldsymbol{x}}_* = {\color{green}\mathsf M}^{-1} {\color{blue} \mathsf N} (\mathbf{\boldsymbol{x}}^{(k)} - \mathbf{\boldsymbol{x}}_*) = \dots = ({\color{green}\mathsf M}^{-1} {\color{blue} \mathsf N})^{k+1} (\mathbf{\boldsymbol{x}}^{(0)} - \mathbf{\boldsymbol{x}}_*). \] La partie « seulement si » du premier point est simple. Les autres assertions découlent de la formule de Gelfand : \[ \forall \mathsf B \in \mathbf R^{n \times n}, \qquad \lim_{k \to \infty} {\lVert {\mathsf B^k} \rVert}^{1/k} = \rho(\mathsf B). \]

🔎 Garanties de convergence concrètes

Les situations où \(\rho(\mathsf M^{-1} \mathsf N) < 1\) sont identifiées au cas par cas :

  • Itération de Richardson, condition suffisante : \(\mathsf A\) symétrique définie positive ;

  • Itération de Jacobi, condition suffisante : \(\mathsf A\) strictement à diagonale dominante par lignes ou par colonnes :

\[ \lvert a_{ii} \rvert > \sum_{j \neq i} \lvert a_{ij} \rvert \quad \forall i \qquad \text{ ou } \qquad \lvert a_{jj} \rvert > \sum_{i \neq j} \lvert a_{ij} \rvert \quad \forall j. \]

  • Itération de Gauss-Seidel, condition suffisante : \(\mathsf A\) strictement à diagonale dominante par lignes ou par colonnes ;

  • Méthode de relaxation, condition suffisante : \(\mathsf A\) symétrique définie positive et \(\omega \in (0, 2)\) ;

  • Méthode de relaxation, condition nécessaire : \(\omega \in (0, 2)\) ;

Améliorer la méthode de Richardson

Rappel : jusqu’à la fin de ce cours, la matrice \(\mathsf A\) est supposée symétrique définie positive

On rappelle l’itération de Richardson : \[\begin{align*} \mathbf{\boldsymbol{x}}^{(k + 1)} = \mathbf{\boldsymbol{x}}^{(k)} - \omega \nabla f(\mathbf{\boldsymbol{x}}^{(k)}), \qquad f(\mathbf{\boldsymbol{x}}) := \frac{1}{2} \mathbf{\boldsymbol{x}}^T\mathsf A \mathbf{\boldsymbol{x}} - \mathbf{\boldsymbol{b}}^T\mathbf{\boldsymbol{x}}. \end{align*}\]

Proposition

Pour tout \(\mathbf{\boldsymbol{d}} \in \mathbf R^n\), on a \[ \mathop{\mathrm{arg\,min}}_{\omega \in \mathbf R} f \left(\mathbf{\boldsymbol{x}} - \omega \mathbf{\boldsymbol{d}} \right) = \frac{\mathbf{\boldsymbol{d}}^T\mathbf{\boldsymbol{r}}}{\mathbf{\boldsymbol{d}}^T\mathsf A \mathbf{\boldsymbol{d}}}, \qquad \mathbf{\boldsymbol{r}} = \mathsf A \mathbf{\boldsymbol{x}} - \mathbf{\boldsymbol{b}}. \]

On peut améliorer la méthode de Richardson en prenant \[ \mathbf{\boldsymbol{x}}^{(k + 1)} = \mathbf{\boldsymbol{x}}^{(k)} - \omega_{\color{red}k} \nabla f(\mathbf{\boldsymbol{x}}^{(k)}), \qquad \omega_{\color{red}k} := \frac{\mathbf{\boldsymbol{d}}_k^T\mathbf{\boldsymbol{d}}_k}{\mathbf{\boldsymbol{d}}_k^T\mathsf A \mathbf{\boldsymbol{d}}_k}, \qquad \mathbf{\boldsymbol{d}}_k := \mathsf A \mathbf{\boldsymbol{x}}^{(k)} - \mathbf{\boldsymbol{b}}. \]

C’est la méthode de descente de gradient avec pas optimal.

Illustration de la descente de gradient

Amélioration supplémentaire : la méthode des directions conjuguées

\[ f(\mathbf{\boldsymbol{x}}) := \frac{1}{2} \mathbf{\boldsymbol{x}}^T\mathsf A \mathbf{\boldsymbol{x}} - \mathbf{\boldsymbol{b}}^T\mathbf{\boldsymbol{x}} = \frac{1}{2} {\lVert {\mathbf{\boldsymbol{x}} - \mathbf{\boldsymbol{x}}_*} \rVert}_{\mathsf A}^2 + \text{constante}, \qquad {\lVert {\mathbf{\boldsymbol{y}}} \rVert}_{\mathsf A} := \sqrt{{\langle {\mathbf{\boldsymbol{y}}, \mathbf{\boldsymbol{y}}} \rangle}_{\mathsf A}}, \qquad {\langle {\mathbf{\boldsymbol{x}}, \mathbf{\boldsymbol{y}}} \rangle}_{\mathsf A} := \mathbf{\boldsymbol{x}}^T\mathsf A \mathbf{\boldsymbol{y}}. \] Étant donné \(n\) directions conjuguées \(\{\mathbf{\boldsymbol{d}}_0, \dotsc, \mathbf{\boldsymbol{d}}_{n-1}\}\) telles que \({\langle {\mathbf{\boldsymbol{d}}_i, \mathbf{\boldsymbol{d}}_j} \rangle}_{\mathsf A} = \delta_{ij}\), on a \[ \mathbf{\boldsymbol{x}}_* - \mathbf{\boldsymbol{x}}^{(0)} = \sum_{i=0}^{n-1} \mathbf{\boldsymbol{d}}_i \mathbf{\boldsymbol{d}}_i^T\mathsf A (\mathbf{\boldsymbol{x}}_* - \mathbf{\boldsymbol{x}}^{(0)}) = \sum_{i=0}^{n-1} \mathbf{\boldsymbol{d}}_i \mathbf{\boldsymbol{d}}_i^T({\color{green}\mathbf{\boldsymbol{b}}} - \mathsf A \mathbf{\boldsymbol{x}}^{(0)}) \]

\(\color{green}\rightarrow\) les projections \(\mathsf A\)-orthogonales de \(\mathbf{\boldsymbol{x}}_* - \mathbf{\boldsymbol{x}}^{(0)}\) peuvent être calculées même si \(\mathbf{\boldsymbol{x}}_*\) est inconnu !

# On suppose que `ds` est une liste de n directions conjuguées
x = zeros(n)
for k in 1:n
    d = ds[k]
    r = A*x - b
    ω = d'r / (d'A*d)  # Dénominateur = 1 si `d` est normalisé
    x -= ω * d
end

Propriété de minimisation (par construction)

  • \(\mathbf{\boldsymbol{x}}^{(k)} - \mathbf{\boldsymbol{x}}^{(0)}\) est la projection \(\mathsf A\)-orthogonale de \(\mathbf{\boldsymbol{x}}_* - \mathbf{\boldsymbol{x}}^{(0)}\) sur \(\mathop{\mathrm{Span}}\{\mathbf{\boldsymbol{d}}_0, \dotsc, \mathbf{\boldsymbol{d}}_{k-1}\}\).

  • Par conséquent, \(\mathbf{\boldsymbol{x}}^{(k)}\) minimise \(f(\mathbf{\boldsymbol{x}}^{(k)})\) sur le sous-espace affine complet \(\mathbf{\boldsymbol{x}}^{(0)} + \mathop{\mathrm{Span}}\{\mathbf{\boldsymbol{d}}_0, \dotsc, \mathbf{\boldsymbol{d}}_{k-1}\}\).

Directions conjuguées : exemple

  • Considérons à nouveau le système linéaire \[ \begin{pmatrix} 2 & 1 \\ 1 & 2 \end{pmatrix} \begin{pmatrix} x_1 \\ x_2 \end{pmatrix} = \begin{pmatrix} 7 \\ 8 \end{pmatrix} \]

  • Directions conjuguées (non normalisées) calculées par Gram-Schmidt : \[ \mathbf{\boldsymbol{d}}_0 = \begin{pmatrix} 1 \\ 0 \end{pmatrix}, \qquad \mathbf{\boldsymbol{d}}_1 = \begin{pmatrix} -1 \\ 2 \end{pmatrix}. \]

using LinearAlgebra
n = 2
A = [2.0 1.0; 1.0 2.0]
b = [7.0; 8.0]
x = zeros(n)
ds = [[1.0; 0.0], [-1.0; 2.0]]
for i in 1:n
    d = ds[i]
    r = A*x - b
    ω = d'r / (d'A*d)  # Dénominateur utile si `d` n'est pas normalisé
    x -= ω*d
    println("Résidu : $(norm(A*x - b))")
end
Résidu : 4.5
Résidu : 0.0

Directions conjuguées : illustration

  • En général, convergence en au plus \(n\) itérations ;
  • Question : comment générer des directions conjuguées ?

    \({\color{green} \rightarrow}\) la méthode du gradient conjugué permet de générer des directions conjuguées à la volée.

Méthode du gradient conjugué

  • Idée : générer la direction conjuguée \(\mathbf{\boldsymbol{d}}_k\) en appliquant Gram-Schmidt à \(\mathbf{\boldsymbol{r}}^{(0)}, \mathbf{\boldsymbol{r}}^{(1)}, \dotsc, \mathbf{\boldsymbol{r}}^{(k)}\).
  • Le coût de calcul d’une nouvelle direction \(\mathbf{\boldsymbol{d}}_k\) semble être en \(\mathcal O(k)\), mais est en fait \(\color{green} \mathcal O(1)\).
  • Convergence : exacte en \(n\) itérations, et sinon plus rapide que la méthode de Richardson :

Théorème

Supposons que \(\mathsf A\) est symétrique définie positive. Alors \[ \forall k \geqslant 0, \qquad {\lVert {\mathbf{\boldsymbol{x}}^{(k)} - \mathbf{\boldsymbol{x}}_*} \rVert}_{\mathsf A} \leqslant 2 \left( \frac{{\color{red}\sqrt{\kappa_2(\mathsf A)}} - 1}{{\color{red}\sqrt{\kappa_2(\mathsf A)}} + 1} \right)^{k} {\lVert {\mathbf{\boldsymbol{x}}^{(0)} - \mathbf{\boldsymbol{x}}_*} \rVert}_{\mathsf A}, \]

Illustration de la méthode du gradient conjugué