mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-04-12 01:00:13 -04:00
319 lines
8.8 KiB
Markdown
319 lines
8.8 KiB
Markdown
---
|
|
id: 5e6decd8ec8d7db960950d1c
|
|
title: LU-Zerlegung
|
|
challengeType: 1
|
|
forumTopicId: 385280
|
|
dashedName: lu-decomposition
|
|
---
|
|
|
|
# --description--
|
|
|
|
Every square matrix $A$ can be decomposed into a product of a lower triangular matrix $L$ and a upper triangular matrix $U$. This is known as the LU decomposition.
|
|
|
|
$A = LU$
|
|
|
|
Es handelt sich um eine modifizierte Form der Gaußschen Elimination.
|
|
|
|
Während die Cholesky-Zerlegung nur für symmetrische, positiv definierte Matrizen funktioniert, funktioniert die allgemeinere LU-Zerlegung für jede quadratische Matrix.
|
|
|
|
Es gibt mehrere Algorithmen zur Berechnung von $L$ und $U$.
|
|
|
|
Um den *Crout'schen Algorithmus* für ein 3x3-Beispiel abzuleiten, müssen wir das folgende System lösen:
|
|
|
|
\\begin{align}A = \\begin{pmatrix} a\_{11} & a\_{12} & a\_{13}\\\\ a\_{21} & a\_{22} & a\_{23}\\\\ a\_{31} & a\_{32} & a\_{33}\\\\ \\end{pmatrix}= \\begin{pmatrix} l\_{11} & 0 & 0 \\\\ l\_{21} & l\_{22} & 0 \\\\ l\_{31} & l\_{32} & l\_{33}\\\\ \\end{pmatrix} \\begin{pmatrix} u\_{11} & u\_{12} & u\_{13} \\\\ 0 & u\_{22} & u\_{23} \\\\ 0 & 0 & u\_{33} \\end{pmatrix} = LU\\end{align}
|
|
|
|
Wir müssten nun 9 Gleichungen mit 12 Unbekannten lösen. Um das System eindeutig lösbar zu machen, werden normalerweise die Diagonalelemente von $L$ auf 1 gesetzt
|
|
|
|
$l\_{11}=1$
|
|
|
|
$l\_{22}=1$
|
|
|
|
$l\_{33}=1$
|
|
|
|
wir erhalten also ein lösbares System mit 9 Unbekannten und 9 Gleichungen.
|
|
|
|
\\begin{align}A = \\begin{pmatrix} a\_{11} & a\_{12} & a\_{13}\\\\ a\_{21} & a\_{22} & a\_{23}\\\\ a\_{31} & a\_{32} & a\_{33}\\\\ \\end{pmatrix} = \\begin{pmatrix} 1 & 0 & 0 \\\\ l\_{21} & 1 & 0 \\\\ l\_{31} & l\_{32} & 1\\\\ \\end{pmatrix} \\begin{pmatrix} u\_{11} & u\_{12} & u\_{13} \\\\ 0 & u\_{22} & u\_{23} \\\\ 0 & 0 & u\_{33} \\end{pmatrix} = \\begin{pmatrix} u\_{11} & u\_{12} & u\_{13} \\\\ u\_{11}l\_{21} & u\_{12}l\_{21}+u\_{22} & u\_{13}l\_{21}+u\_{23} \\\\ u\_{11}l\_{31} & u\_{12}l\_{31}+u\_{22}l\_{32} & u\_{13}l\_{31} + u\_{23}l\_{32}+u\_{33} \\end{pmatrix} = LU\\end{align}
|
|
|
|
Löst man die anderen $l$ und $u$, erhält man die folgenden Gleichungen:
|
|
|
|
$u\_{11}=a\_{11}$
|
|
|
|
$u\_{12}=a\_{12}$
|
|
|
|
$u\_{13}=a\_{13}$
|
|
|
|
$u\_{22}=a\_{22} - u\_{12}l\_{21}$
|
|
|
|
$u\_{23}=a\_{23} - u\_{13}l\_{21}$
|
|
|
|
$u\_{33}=a\_{33} - (u\_{13}l\_{31} + u\_{23}l\_{32})$
|
|
|
|
und für $l$:
|
|
|
|
$l\_{21}=\\frac{1}{u\_{11}} a\_{21}$
|
|
|
|
$l\_{31}=\\frac{1}{u\_{11}} a\_{31}$
|
|
|
|
$l\_{32}=\\frac{1}{u\_{22}} (a\_{32} - u\_{12}l\_{31})$
|
|
|
|
Wir sehen, dass es ein Berechnungsmuster gibt, das durch folgende Formeln ausgedrückt werden kann, zunächst für $U$
|
|
|
|
$u\_{ij} = a\_{ij} - \\sum\_{k=1}^{i-1} u\_{kj}l\_{ik}$
|
|
|
|
und dann für $L$
|
|
|
|
$l\_{ij} = \\frac{1}{u\_{jj}} (a\_{ij} - \\sum\_{k=1}^{j-1} u\_{kj}l\_{ik})$
|
|
|
|
In der zweiten Formel sehen wir, dass wir, um $l\_{ij}$ unterhalb der Diagonale zu erhalten, durch das Diagonalelement (Drehpunkt) $u\_{jj}$ dividieren müssen, so dass wir Probleme bekommen, wenn $u\_{jj}$ entweder 0 oder sehr klein ist, was zu numerischer Instabilität führt.
|
|
|
|
Die Lösung dieses Problems ist das *pivoting* von $A$, was bedeutet, dass die Zeilen von $A$ vor der $LU$-Zerlegung so umgeordnet werden, dass das größte Element jeder Spalte auf die Diagonale von $A$ gelangt. Das Umordnen der Zeilen bedeutet, dass man $A$ mit einer Permutationsmatrix $P$ multipliziert:
|
|
|
|
$PA \\Rightarrow A'$
|
|
|
|
Beispiel:
|
|
|
|
\\begin{align} \\begin{pmatrix} 0 & 1 \\\\ 1 & 0 \\end{pmatrix} \\begin{pmatrix} 1 & 4 \\\\ 2 & 3 \\end{pmatrix} \\Rightarrow \\begin{pmatrix} 2 & 3 \\\\ 1 & 4 \\end{pmatrix} \\end{align}
|
|
|
|
Der Zersetzungsalgorithmus wird dann auf die umgeordnete Matrix angewandt, so dass
|
|
|
|
$PA = LU$
|
|
|
|
# --instructions--
|
|
|
|
Die Aufgabe besteht darin, eine Routine zu implementieren, die aus einer quadratischen nxn-Matrix $A$ eine untere Dreiecksmatrix $L$, eine obere Dreiecksmatrix $U$ und eine Permutationsmatrix $P$ liefert, so dass die obige Gleichung erfüllt ist. Der zurückgegebene Wert sollte die Form `[L, U, P]` haben.
|
|
|
|
# --hints--
|
|
|
|
`luDecomposition` sollte eine Funktion sein.
|
|
|
|
```js
|
|
assert(typeof luDecomposition == 'function');
|
|
```
|
|
|
|
`luDecomposition([[1, 3, 5], [2, 4, 7], [1, 1, 0]])` sollte ein Array zurückgeben.
|
|
|
|
```js
|
|
assert(
|
|
Array.isArray(
|
|
luDecomposition([
|
|
[1, 3, 5],
|
|
[2, 4, 7],
|
|
[1, 1, 0]
|
|
])
|
|
)
|
|
);
|
|
```
|
|
|
|
`luDecomposition([[1, 3, 5], [2, 4, 7], [1, 1, 0]])` sollte `[[[1, 0, 0], [0.5, 1, 0], [0.5, -1, 1]], [[2, 4, 7], [0, 1, 1.5], [0, 0, -2]], [[0, 1, 0], [1, 0, 0], [0, 0, 1]]]` zurückgeben.
|
|
|
|
```js
|
|
assert.deepEqual(
|
|
luDecomposition([
|
|
[1, 3, 5],
|
|
[2, 4, 7],
|
|
[1, 1, 0]
|
|
]),
|
|
[
|
|
[
|
|
[1, 0, 0],
|
|
[0.5, 1, 0],
|
|
[0.5, -1, 1]
|
|
],
|
|
[
|
|
[2, 4, 7],
|
|
[0, 1, 1.5],
|
|
[0, 0, -2]
|
|
],
|
|
[
|
|
[0, 1, 0],
|
|
[1, 0, 0],
|
|
[0, 0, 1]
|
|
]
|
|
]
|
|
);
|
|
```
|
|
|
|
`luDecomposition([[11, 9, 24, 2], [1, 5, 2, 6], [3, 17, 18, 1], [2, 5, 7, 1]])` sollte `[[[1, 0, 0, 0], [0.2727272727272727, 1, 0, 0], [0.09090909090909091, 0.2875, 1, 0], [0.18181818181818182, 0.23124999999999996, 0.0035971223021580693, 1]], [[11, 9, 24, 2], [0, 14.545454545454547, 11.454545454545455, 0.4545454545454546], [0, 0, -3.4749999999999996, 5.6875], [0, 0, 0, 0.510791366906476]], [[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]]` zurückgeben.
|
|
|
|
```js
|
|
assert.deepEqual(
|
|
luDecomposition([
|
|
[11, 9, 24, 2],
|
|
[1, 5, 2, 6],
|
|
[3, 17, 18, 1],
|
|
[2, 5, 7, 1]
|
|
]),
|
|
[
|
|
[
|
|
[1, 0, 0, 0],
|
|
[0.2727272727272727, 1, 0, 0],
|
|
[0.09090909090909091, 0.2875, 1, 0],
|
|
[0.18181818181818182, 0.23124999999999996, 0.0035971223021580693, 1]
|
|
],
|
|
[
|
|
[11, 9, 24, 2],
|
|
[0, 14.545454545454547, 11.454545454545455, 0.4545454545454546],
|
|
[0, 0, -3.4749999999999996, 5.6875],
|
|
[0, 0, 0, 0.510791366906476]
|
|
],
|
|
[
|
|
[1, 0, 0, 0],
|
|
[0, 0, 1, 0],
|
|
[0, 1, 0, 0],
|
|
[0, 0, 0, 1]
|
|
]
|
|
]
|
|
);
|
|
```
|
|
|
|
`luDecomposition([[1, 1, 1], [4, 3, -1], [3, 5, 3]])` sollte `[[[1, 0, 0], [0.75, 1, 0], [0.25, 0.09090909090909091, 1]], [[4, 3, -1], [0, 2.75, 3.75], [0, 0, 0.9090909090909091]], [[0, 1, 0], [0, 0, 1], [1, 0, 0]]]` zurückgeben.
|
|
|
|
```js
|
|
assert.deepEqual(
|
|
luDecomposition([
|
|
[1, 1, 1],
|
|
[4, 3, -1],
|
|
[3, 5, 3]
|
|
]),
|
|
[
|
|
[
|
|
[1, 0, 0],
|
|
[0.75, 1, 0],
|
|
[0.25, 0.09090909090909091, 1]
|
|
],
|
|
[
|
|
[4, 3, -1],
|
|
[0, 2.75, 3.75],
|
|
[0, 0, 0.9090909090909091]
|
|
],
|
|
[
|
|
[0, 1, 0],
|
|
[0, 0, 1],
|
|
[1, 0, 0]
|
|
]
|
|
]
|
|
);
|
|
```
|
|
|
|
`luDecomposition([[1, -2, 3], [2, -5, 12], [0, 2, -10]])` sollte `[[[1, 0, 0], [0, 1, 0], [0.5, 0.25, 1]], [[2, -5, 12], [0, 2, -10], [0, 0, -0.5]], [[0, 1, 0], [0, 0, 1], [1, 0, 0]]]` zurückgeben.
|
|
|
|
```js
|
|
assert.deepEqual(
|
|
luDecomposition([
|
|
[1, -2, 3],
|
|
[2, -5, 12],
|
|
[0, 2, -10]
|
|
]),
|
|
[
|
|
[
|
|
[1, 0, 0],
|
|
[0, 1, 0],
|
|
[0.5, 0.25, 1]
|
|
],
|
|
[
|
|
[2, -5, 12],
|
|
[0, 2, -10],
|
|
[0, 0, -0.5]
|
|
],
|
|
[
|
|
[0, 1, 0],
|
|
[0, 0, 1],
|
|
[1, 0, 0]
|
|
]
|
|
]
|
|
);
|
|
```
|
|
|
|
# --seed--
|
|
|
|
## --seed-contents--
|
|
|
|
```js
|
|
function luDecomposition(A) {
|
|
|
|
}
|
|
```
|
|
|
|
# --solutions--
|
|
|
|
```js
|
|
function luDecomposition(A) {
|
|
|
|
function dotProduct(a, b) {
|
|
var sum = 0;
|
|
for (var i = 0; i < a.length; i++)
|
|
sum += a[i] * b[i]
|
|
return sum;
|
|
}
|
|
|
|
function matrixMul(A, B) {
|
|
var result = new Array(A.length);
|
|
for (var i = 0; i < A.length; i++)
|
|
result[i] = new Array(B[0].length)
|
|
var aux = new Array(B.length);
|
|
|
|
for (var j = 0; j < B[0].length; j++) {
|
|
|
|
for (var k = 0; k < B.length; k++)
|
|
aux[k] = B[k][j];
|
|
|
|
for (var i = 0; i < A.length; i++)
|
|
result[i][j] = dotProduct(A[i], aux);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function pivotize(m) {
|
|
var n = m.length;
|
|
var id = new Array(n);
|
|
for (var i = 0; i < n; i++) {
|
|
id[i] = new Array(n);
|
|
id[i].fill(0)
|
|
id[i][i] = 1;
|
|
}
|
|
|
|
for (var i = 0; i < n; i++) {
|
|
var maxm = m[i][i];
|
|
var row = i;
|
|
for (var j = i; j < n; j++)
|
|
if (m[j][i] > maxm) {
|
|
maxm = m[j][i];
|
|
row = j;
|
|
}
|
|
|
|
if (i != row) {
|
|
var tmp = id[i];
|
|
id[i] = id[row];
|
|
id[row] = tmp;
|
|
}
|
|
}
|
|
return id;
|
|
}
|
|
|
|
var n = A.length;
|
|
var L = new Array(n);
|
|
for (var i = 0; i < n; i++) { L[i] = new Array(n); L[i].fill(0) }
|
|
var U = new Array(n);
|
|
for (var i = 0; i < n; i++) { U[i] = new Array(n); U[i].fill(0) }
|
|
var P = pivotize(A);
|
|
var A2 = matrixMul(P, A);
|
|
|
|
for (var j = 0; j < n; j++) {
|
|
L[j][j] = 1;
|
|
for (var i = 0; i < j + 1; i++) {
|
|
var s1 = 0;
|
|
for (var k = 0; k < i; k++)
|
|
s1 += U[k][j] * L[i][k];
|
|
U[i][j] = A2[i][j] - s1;
|
|
}
|
|
for (var i = j; i < n; i++) {
|
|
var s2 = 0;
|
|
for (var k = 0; k < j; k++)
|
|
s2 += U[k][j] * L[i][k];
|
|
L[i][j] = (A2[i][j] - s2) / U[j][j];
|
|
}
|
|
}
|
|
return [L, U, P];
|
|
}
|
|
```
|