Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Wir werfen einen kurzen Blick auf das numerische Lösen nichtlinearer Gleichungssysteme

F(x)=0,F=(f1,,fd):DRd,F(x)=0,\quad F=(f_1,\ldots,f_d):D\to\bbR^d,

wobei DRdD\subseteq\bbR^d der Definitionsbereich der vektorwertigen Funktion FF ist. Beschränken uns auf den Fall, dass die Anzahl der Unbekannten mit der Anzahl der Gleichungen übereinstimmt.

Gelegentlich treten nichtlineare Gleichungssysteme mit nur kleinem dd auf. Meist entstehen die Systeme jedoch als endlich Näherung kontinuierlicher Probleme (Strömungsmechanik usw.) und weisen dann sehr viele Unbekannte auf.

Ziel dieses Kapitels ist nicht die detaillierte behandlung konkreter Verfahren, sondern das Aufzeigen von zusätzlichen Fragen und Problemen, die im eindimensionalen Fall nicht auftraten.

5.1Bisektion vs. Dimension

Prinzipiell lässt sich das Bisektionsverfahren auf höhere Dimensionen übertragen, allerdings nicht so einfach wie es zunächst erscheinen mag; siehe z.B. A rapid Generalized Method of Bisection for solving Systems of Non-linear Equations. Hauptproblem ist die mit der Dimension dd exponentiell wachsende Anzahl zu untersuchender Punkte. Während im eindimensionalen Fall der Suchbereich durch zwei Punkte begrenzt ist, werden in dd Dimensionen 2d2^d Punkte benötigt. Dies entspricht gerade der Anzahl der Ecken eines dd-dimensionalen Quaders.

Beispiel: Für ein nichtlineares Gleichungssystem mit nur d=30d=30 Unbekannten und Gleichungen wäre das Suchgebiet durch ca. 1 Milliarde Punkte begrenzt!

5.2Newton-Verfahren

Das Newton-Verfahren lässt sich leicht auf Gleichungssysteme übertragen. Das Newton-Verfahren und daraus abgeleitete Verfahren (siehe unten) sind das wichtigsten Verfahren für das Lösen auch großer nichtlinearer Gleichungssysteme.

5.2.1Verfahren

Wie bei d=1d=1 lösen wir eine linearisierte Version des nichtlinearen Gleichungsystems, wobei wir die Linearisierungspunkte sukzessive ausgehend von einem Startpunkt x0x_0 als Lösung des vorhergehenden linearisierten Systems berechnen.

Für gegebenen Punkt xk1x_{k-1} liefert der Satz von Taylor bei zweimal stetig differenzierbarem FF die Näherung

F(x)F(xk1)+JF(xk1)(xxk1),F(x)\approx F(x_{k-1})+J_F(x_{k-1})\,(x-x_{k-1}),

wobei

JF(xk1):=[f1x1(xk1)f1xd(xk1)fdx1(xk1)fdxd(xk1)]J_F(x_{k-1}):=\begin{bmatrix} \frac{\partial f_1}{\partial x_1}(x_{k-1})&\cdots&\frac{\partial f_1}{\partial x_d}(x_{k-1})\\ \vdots&&\vdots\\ \frac{\partial f_d}{\partial x_1}(x_{k-1})&\cdots&\frac{\partial f_d}{\partial x_d}(x_{k-1}) \end{bmatrix}

die Matrix der ersten partiellen Ableitungen der Komponenten f1,,fdf_1,\ldots,f_d von FF ist (“Jacobi-Matrix”). Das nichtlineare Gleichungssystem F(x)=0F(x)=0 wird also in einer (kleinen) Umgebung von xk1x_{k-1} näherungsweise durch das lineare Gleichungssystem

JF(xk1)x=JF(xk1)xk1F(xk1)J_F(x_{k-1})\,x=J_F(x_{k-1})\,x_{k-1}-F(x_{k-1})

beschrieben. Ist JF(xk1)J_F(x_{k-1}) invertierbar, so besitzt dieses die eindeutige Lösung

xk:=xk1JF(xk1)1F(xk1).x_k:=x_{k-1}-J_F(x_{k-1})^{-1}\,F(x_{k-1}).

Dies ist die Iterationsvorschrift für das mehrdimensionale Newton-Verfahren.

5.2.2Probleme

Analog zum eindimensionalen Fall (aber technisch aufwendiger) kann man zeigen, dass das mehrdimensionale Newton-Verfahren quadratisch konvergiert, also

xkxCxk1x2|x_k-x^\ast|\leq C\,|x_{k-1}-x^\ast|^2

gilt, sofern die Funktion FF gewisse, recht strenge Bedingungen erfüllt und x0x_0 nah genug an der Lösung xx^\ast liegt. Beachte, dass xx^\ast und alle xkx_k hier Vektoren aus Rd\bbR^d sind, in der Ungleichung nun also Längen von Vektoren verglichen werden.

Wie man x0x_0 in der Praxis wählen muss um quadratische Konvergenz oder überhaupt Konvergenz zu erhalten, ist nicht so klar. Der Satz von Kantorovich liefert hier praktisch verwertbare Anhaltspunkte. Letztlich wird es aber meist auf “Versuch und Irrtum” hinauslaufen.

Nebendem auch im eindimensionalen Fall vorhandenen Konvergenzproblem macht zusätzlich die Jacobi-Matrix JF(xk1)J_F(x_{k-1}) Probleme. Selbst wenn diese als auswertbare Formel vorliegt, müssen in jedem Interationsschritt die d2d^2 Einträge neu berechnet werden (eigentlich nur n(n+1)2\frac{n\,(n+1)}{2}, da symmetrisch). Oft ist FF so beschaffen, dass man JFJ_F gar nicht explizit in Formeln ausdrücken kann. Dann muss JF(xk1)J_F(x_{k-1}) numerisch bestimmt werden. Die Probleme um JFJ_F haben vielfältige Lösungen hervorgeracht, die zu unterschiedlichen, sogenannten Newton-ähnlichen Verfahren geführt haben.

5.3Newton-ähnliche Verfahren

Bezüglich der Jacobi-Matrix JFJ_F im mehrdimensionalen Newton-Verfahren sind zwei Probleme zu lösen:

Der zweite Punkt ist besonders schwierig, weil numerische Differentiation ein schlecht konditioniertes Problem ist (siehe Veranstaltung zum wissenschaftlichen Rechnen).

Lösungsansätze:

5.4Ausflug: Newton-Fraktal

Um die Konvergenz bzw. Nichtkonvergenz des Newton-Verfahrens in Abhängigkeit vom Startpunkt zu visualisieren betrachten wir verschiedene Beispiele mit d=2d=2.

Wir generieren ein regelmäßiges Rechteckgitter aus Startpunkten und führen das Newton-Verfahren mit jedem dieser Punkte als Startpunkt aus. Jeder Lösung der Gleichung F(x,y)=(0,0)F(x,y)=(0,0) wird eine Farbe zugeordnet. Die Startpunkte werden in der Farbe der Lösung gefärbt, zu der die Iteration führt. Je langsamer die Konvergenz (hohe Iterationsanzahl), desto dunkler die Farbe.

Startpunkte, die nicht zur Konvergenz führen, werden schwarz erscheinen. Zur leichteren Wahrnehmung dieser Punkte erstellen wir eine zweite Grafik, die diese Startpunkte in weiß auf schwarzem Grund darstellt. Grautöne entsprechen langsamer Konvergenz.

Source
import numpy as np
import matplotlib.pyplot as plt
import sympy

def newton_fractal(f1, f2, x, y, roots):
    # f1, f2, x, y are SymPy objects; roots is a list of coordinates
    
    # canvas size
    xmin, xmax, nx = -2, 2, 1000
    ymin, ymax, ny = -2, 2, 1000

    # colors for zeros
    colors = np.array([[1, 0, 0], [0, 0, 1], [0, 1, 0], [1, 1, 0], [0, 1, 1], [1, 0, 1]])

    # Jacobian
    f1x = sympy.diff(f1, x)
    f1y = sympy.diff(f1, y)
    f2x = sympy.diff(f2, x)
    f2y = sympy.diff(f2, y)
    
    # Newton step
    x_next = x - 1 / (f1x * f2y - f2x * f1y) * (f2y * f1 - f1y * f2)
    y_next = y - 1 / (f1x * f2y - f2x * f1y) * (-f2x * f1 + f1x * f2)
    x_next = sympy.simplify(x_next)
    y_next = sympy.simplify(y_next)
    
    # make Python function from SymPy result
    newton_update = sympy.utilities.lambdify([x, y], (x_next, y_next))

    # grid of initial values for Newton iteration and arrays for storing iteration counts (color-coded)
    grid_x, grid_y = np.meshgrid(np.linspace(xmin, xmax, nx), np.linspace(ymin, ymax, ny))
    canvas = np.zeros((ny, nx, 3))
    iters = np.zeros((ny, nx), dtype=int)

    # Newton interation for each initial value
    delta = 1e-10
    max_iter = 100
    for i in range(ny):
        for j in range(nx):

            # Newton iteration
            x_old, y_old = grid_x[i, j], grid_y[i, j]
            for k in range(max_iter):
                x, y = newton_update(x_old, y_old)
                if (x - x_old) ** 2 + (y - y_old) ** 2 < delta ** 2:
                    iters[i, j] = k
                    break
                x_old, y_old = x, y
            else:
                iters[i, j] = max_iter

            # find closest root (for color selection)
            dists = [(x - root_x) ** 2 + (y - root_y) ** 2 for root_x, root_y in roots]
            idx_root = np.array(dists).argmin()

            # store color-coded iteration count (** 0.5 is for color-scaling)
            canvas[i, j, :] = 1 / iters[i, j] ** 0.5 * colors[idx_root, :]

    # show convergence to roots
    fig, ax = plt.subplots(figsize=(10,10))
    ax.imshow(canvas / canvas.max(), extent=(xmin, xmax, ymin, ymax))
    ax.plot(*zip(*roots), 'ow')
    ax.axis('equal')
    plt.show()

    # show fractal (initial values without convergence)
    fig, ax = plt.subplots(figsize=(10,10))
    ax.imshow(iters, extent=(xmin, xmax, ymin, ymax), cmap='gray')
    ax.plot(*zip(*roots), 'ow')
    ax.axis('equal')
    plt.show()

Schauen uns zunächst die Ergebnisse für die Funktion

F(x,y):=[x2y212xy]F(x,y):=\begin{bmatrix}x^2-y^2-1\\2\,x\,y\end{bmatrix}

an. Diese Funktion hat zwei Nullstellen bei (1,0)(-1,0) und (1,0)(1, 0) (weiße Punkte).

x, y = sympy.symbols('x y', real=True)

#z = x + y * sympy.I
#f = z ** 2 - 1
#f1 = sympy.re(f)
#f2 = sympy.im(f)

f1 = x ** 2 - y ** 2 - 1
f2 = 2 * x * y

roots = [[1, 0], [-1, 0]]

newton_fractal(f1, f2, x, y, roots)
<Figure size 1000x1000 with 1 Axes>
<Figure size 1000x1000 with 1 Axes>

Das Newton-Verfahren konvergiert für alle Startpunkte, die nicht auf der vertikalen Koordinatenachse liegen. Je näher der Startpunkt an einer Nullstelle liegt, desto schneller die Konvergenz.

Erhöhen wir den Polynomgrad auf 3, z.B.

F(x,y):=[x33xy213x2yy3],F(x,y):=\begin{bmatrix}x^3-3\,x\,y^2-1\\3\,x^2\,y-y^3\end{bmatrix},

so wird das Konvergenzverhalten deutlich komplexer. Die Funktion hat 3 Nullstellen (weiße Punkte).

x, y = sympy.symbols('x y', real=True)

#z = x + y * sympy.I
#f = z ** 3 - 1
#f1 = sympy.re(f)
#f2 = sympy.im(f)

f1 = x ** 3 - 3 * x * y ** 2 - 1
f2 = 3 * x ** 2 * y - y ** 3

roots = [[1, 0], [-0.5, 0.5 * np.sqrt(3)], [-0.5, - 0.5 * np.sqrt(3)]]

newton_fractal(f1, f2, x, y, roots)
<Figure size 1000x1000 with 1 Axes>
<Figure size 1000x1000 with 1 Axes>

Bei Start in der Nähe einer Nullstelle konvergiert das Newton-Verfahren zu dieser Nullstellen. Liegt der Startpunkt jedoch etwa gleich weit entfernt von zwei Nullstellen, so führen schon sehr kleine Änderungen am Startwert zu einem Wechsel der angenäherten Nullstelle.

Die Menge der Startpunkte von denen aus das Newton-Verfahren nicht konvergiert heißt Newton-Fraktal. Diese Menge hat eine äußerst komplexe sich sowohl in der Ausdehnung als auch im Detail immer wieder wiederholende Struktur. Das Newton-Fraktal ist weder Linie, noch Fläche, sondern eine Menge mit gebrochener Dimension zwischen 1 und 2 bei ca. 1.42. Siehe z.B. Fractal Basins of Attraction Associated with a Damped Newton’s Method für Details.

Zur besseren Visualisierung des Newton-Fraktals (Zoom usw.) existieren verschiedene Computerprogramme, z.B. XaoS (open-source für alle gängigen Plattformen).

Polynom 6. Grades:

x, y = sympy.symbols('x y', real=True)

#z = x + y * sympy.I
#f = z ** 6 - 1
#f1 = sympy.re(f)
#f2 = sympy.im(f)

f1 = x ** 6 - 15 * x ** 4 * y ** 2 + 15 * x ** 2 * y ** 4 - y ** 6 - 1
f2 = 6 * x ** 5 * y - 20 * x ** 3 * y ** 3 + 6 * x * y ** 5

roots = [
    [1, 0], [-0.5, 0.5 * np.sqrt(3)], [-0.5, - 0.5 * np.sqrt(3)],
    [-1, 0], [0.5, 0.5 * np.sqrt(3)], [0.5, - 0.5 * np.sqrt(3)]
]

newton_fractal(f1, f2, x, y, roots)
<Figure size 1000x1000 with 1 Axes>
<Figure size 1000x1000 with 1 Axes>

Für manche Funktionen gibt es ganze Flächen an Startpunkten, bei denen das Newton-Verfahren nicht konvergiert. Beispiel:

F(x,y):=[x33xy22x+23x2yy32y].F(x,y):=\begin{bmatrix}x^3-3\,x\,y^2-2\,x+2\\3\,x^2\,y-y^3-2\,y\end{bmatrix}.
x, y = sympy.symbols('x y', real=True)

#z = x + y * sympy.I
#f = z ** 3 - 2 * z + 2
#f1 = sympy.re(f)
#f2 = sympy.im(f)

f1 = x ** 3 - 3 * x * y ** 2 - 2 * x + 2
f2 = 3 * x ** 2 * y - y ** 3 - 2 * y

roots = [[-1.7693, 0], [0.88465, -0.58974], [0.88465, 0.58974]]

newton_fractal(f1, f2, x, y, roots)
<Figure size 1000x1000 with 1 Axes>
<Figure size 1000x1000 with 1 Axes>
References
  1. Vrahatis, M. N., & Iordanidis, K. I. (1986). A rapid Generalized Method of Bisection for solving Systems of Non-linear Equations. Numerische Mathematik, 49(2–3), 123–138. 10.1007/bf01389620