# CAMA : ma11 Conditionnement d'une matrice
# Cours du 27 / 04
Soit la matrice symétrique $A$ suivante :
```python=
A = np.array([[10, 7, 8, 7], [7, 5, 6, 5], [8, 6, 10, 9], [7, 5, 9, 10]])
```
```
array([[10, 7, 8, 7],
[ 7, 5, 6, 5],
[ 8, 6, 10, 9],
[ 7, 5, 9, 10]])
```
```python=
lin.det(A) # calcul son determinant
```
```
0.9999999999999869 # on peut arrondir a 1
```
Construisons $b$ tel que $A{\bf x} = b$ et $\bf x = [1,1,1,1]$
```python=
b = A.sum(axis=1)
```
```
[32 23 33 31]
```
```python=
x = lin.solve(A, b)
```
```
array([1., 1., 1., 1.])
```
:::warning
Perturbons $b$, comme s'il y avait une erreur de mesure ou d'arrondi.
:::
```python=
bp = [32.1, 22.9, 33.1, 30.9]
eb = lin.norm(b - bp) / lin.norm(b)
# une erreur se mesure par rapport à la valeur de la donnée
```
```
0.0033319453118976702
```
On a une erreur de l'ordre de $0,3\%$.
:::danger
On note l'erreur :
$$ \frac{||{\bf \delta b}||}{||{\bf b}||}$$
:::
Regardons la solution ${\bf x}$ de notre système matriciel perturbé:
```python=
xp = lin.solve(A, bp)
```
```
array([ 9.2, -12.6, 4.5, -1.1])
```
:::warning
La solution n'a rien n'a voir avec $[1,1,1,1]$
:::
```python=
ex = lin.norm(x - xp) / lin.norm(x) #mesure de l'erreur
```
```
8.19847546803699
```
L'erreur est de l'ordre de 8.
```python=
ex / eb
```
```
2460.567236431514
```
:::warning
C'est $2460$ fois plus que l'erreur sur $b$.
:::
## Pourquoi ?
$$
\begin{aligned}
A ({\bf x} + {\bf \delta x}) &= {\bf b} + {\bf \delta b} \quad \textrm{et donc} \\
A \, {\bf \delta x} &= {\bf \delta b} \; \textrm{ puisque } A {\bf x} = {\bf b} \quad \textrm{et finalement}\\
{\bf \delta x} &= A^{-1} \, {\bf \delta b}
\end{aligned}
$$
Comme $A$ et son inverse sont des applications linéaires :
$$
\begin{align}
& ||{\bf b}|| \le ||A|| \, ||{\bf x}||
\quad \textrm{et} \quad ||{\bf \delta x}|| \le ||A^{-1}|| \, ||{\bf \delta b}||
\end{align}
$$
donc :
$$
\begin{align}
\frac{||{\bf \delta x}||}{||{\bf x}||} \le ||A^{-1}|| \, \frac{||{\bf \delta b}||}{||{\bf x}||}
\le ||A^{-1}|| \, ||A|| \, \frac{||{\bf \delta b}||}{||{\bf b}||}
\end{align}
$$
```python=
lin.norm(lin.inv(A)) * lin.norm(A)
```
```
3009.5787080586942
```
:::danger
On appelle cela le conditionnement de $A$ :
$$cond(A) = ||A^{-1}|| \, ||A||$$
**Une matrice mal conditionnée va générer des erreurs de calcul lors de la résolution du système matriciel.**
:::
```python=
np.linalg.cond(A) # scipy n'a pas le conditionnement mais numpy l'a.
```
```
2984.0927016757555 # different de 3009
```
## Perturbons la matrice
```python=
np.random.seed(0)
dA = 2 * np.random.random(size = A.shape) - 1
```
```
array([[ 0.098, 0.43 , 0.206, 0.09 ],
[-0.153, 0.292, -0.125, 0.784],
[ 0.927, -0.233, 0.583, 0.058],
[ 0.136, 0.851, -0.858, -0.826]])
```
```python=
ea = lin.norm(dA) / lin.norm(A) # erreur relative sur A
```
```
0.06868857112100454
```
```python=
Ap = A + dA
```
```
array([[10.098, 7.43 , 8.206, 7.09 ],
[ 6.847, 5.292, 5.875, 5.784],
[ 8.927, 5.767, 10.583, 9.058],
[ 7.136, 5.851, 8.142, 9.174]])
```
```python=
xp = lin.solve(Ap, b)
```
```
array([-12.365, 15.574, 10.146, -5.94 ])
```
```python=
ex = lin.norm(xp - x) / lin.norm(x)
```
```
11.432687335993894
```
```python=
ex / ea # valeur de l'erreur
```
```
166.44235204505293
```
:::success
L'erreur est moins grande.
:::
:::warning
Une erreur peut fortement perturber $A$, le conditionnement et l'erreur sont tous les deux importants.
:::
Pour retrouver le conditionnement de $A$ dans ce cas :
$$
\begin{align}
& (A + \Delta A) \, ({\bf x} + {\bf \delta x}) = {\bf b} \quad \textrm{et donc} \\
& A \, {\bf \delta x} + \Delta A \, ({\bf x} + {\bf \delta x}) = 0 \; \textrm{ puisque } A {\bf x} = {\bf b} \quad \textrm{et finalement}\\
& {\bf \delta x} = -A^{-1} \,\Delta A \, ({\bf x} + {\bf \delta x}) \quad \textrm{et} \\
& ||{\bf \delta x}|| \le ||A^{-1}|| \, ||\Delta A|| \, ||{\bf x} + {\bf \delta x}||
\end{align}
$$
Donc
$$
\begin{align}
\frac{||{\bf \delta x}||}{||{\bf x} + {\bf \delta x}||}
\le ||A^{-1}|| \, ||\Delta A|| = ||A^{-1}|| \, ||A|| \, \frac{||\Delta A||}{||A||}
\end{align}
$$
et
$$
\begin{align}
\frac{||{\bf \delta x}||}{||{\bf x} + {\bf \delta x}||}
\le cond(A) \, \frac{||\Delta A||}{||A||}
\end{align}
$$
## Propriétés
* $cond(A) \ge 1$ car $Id = A\, A^{-1}$ et donc $1 \le ||A||\, ||A^{-1}||$
* $cond(A) = cond(A^{-1})$
* $\displaystyle cond_2(A) = \frac{\max_i |\lambda_i|}{\min_i |\lambda_i|}$ si la matrice est réelle
* 2 indique qu'on utilise la norme 2
* $\lambda_i$ sont les valeurs propres de A
```python=
vp = lin.eigvals(A)
vp.max() / vp.min()
```
* si A est unitaire ou orthogonale : $cond_2(A) = 1$
* le conditionnement n'est pas modifié par transformation unitaire
## Préconditionnement
:::info
Le conditionnement peut etre tranformé :
$$
\forall A, \exists B \; \textrm{appelée matrice de préconditionnement t.q.} \quad cond(B\, A) < cond(A)
$$
:::
:::warning
On résoud $B\, A {\bf x} = B\, {\bf b}$.
:::