Lineare Gleichungssysteme

Der Prozessor eines Computers kann bekanntlich nicht mit Sinus, Logarithmus, Differential, Integral oder gar mit Differenzialgleichungen umgehen, er kann im Prinzip nur Bitmuster manipulieren und stellt damit die Grundrechnungsarten dar. Alles andere über Grundrechnungsarten Hinausgehende, wie Höhere Mathematik, rechnerischer Crash-Test eines Automobils, Statik einer Brücke, rechnerische Wettervorhersagen, Strömung um Flugzeug, Strömungen in einem Verbrennungsmotor, Geschehen im Weltraum usw., usw. muss über mathematische Modelle nachgebildet werden und dabei spielen neben den mathematischen Reihenentwicklungen lineare Gleichungen, korrekter lineare Gleichungssysteme, die entscheidende Rolle.

Lineare Gleichungen können mit den Grundrechnungsarten des Computers gelöst werden. Dabei wird ein sehr rationelles Verfahren eingesetzt, das im Grundsatz auf Carl Friedrich Gauß (1799 bis 1855, Braunschweig, Göttingen)zurückführt. Beim halbjährlichen Wettstreit der 500 schnellsten Computer der Welt werden riesige lineare Gleichungssysteme mit einem geringfügig modifizierten Gauß-Verfahren bezüglich der Rechenzeit getestet, siehe https://www.top500.org

Frage an die KI: Zu linearen Gleichungssystemen: Wie groß war in etwa das Gleichungssystem, das ein Großrechner um das Jahr 1980 lösen konnte?
Antwort der KI: Ein Großrechner konnte um das Jahr 1980 typischerweise lineare Gleichungssysteme mit etwa 10.000 bis 100.000 Unbekannten lösen.

Ein Gleichungssystem mit 10.000 Unbekannten schafft im Jahre 2025 jedes Smartphone! Siehe nachstehendes Testprogramm.

Interessierte können den nachstehenden Python-Code auf den Rechner übertragen, ab etwa Zeile 150 (+/-) folgen Hinweise zur (kostenlosen) Installation des Python-Systems. Viel Erfolg!


 
import numpy as np           # Dr. Karl Haller (Kürzel kha).  Letzte Änderung vom 26.10.2025
import time                  # Von der KI geliefert nach kha-Aufgabenstellung vom 13.04.2025 
import os                    # in der Textdatei "Lineare Gleichungssysteme - V1.txt".
import platform              # Python-Code später von kha nur minimal kosmetisiert, reichlich
                             # kommentiert und die Formatierung der Rechenfehler zugefügt.
                             # Siehe ausführlichen Kommentarblock am Ende des effektiven Codes.
                             
def linearesGleichungssystem():
    if platform.system() == "Windows":      # Von kha später zugefügt,
        os.system("cls")                    # da Bildschirm löschen
    else:                                   # bei Android/Linux leider anders
        os.system("clear")                  # als bei Windows.
    # --------------------
    zMax = 9       # Für Zufallszahlen aus 
    zMin = -zMax   # diesem Bereich -9 ... +9
    
    # 1. Benutzereingabe: Größe des Gleichungssystems
    try:
        n_input = input("Gebe die Größe des 'Linearen Gleichungssystems' n ein (1 ... 14000 ... ): ")
        n = int(n_input)
        if n <= 0:
            c = input("Ungültige Eingabe: Die Zahl muss größer als 0 sein. Abbruch nach Enter ")
            return
    except ValueError:
        c = input("Ungültige Eingabe: Nur ganze Zahlen zulässig. Abbruch nach Enter ")
        return

    # 2. Matrixgenerierung, Initialisierung des Lösungsvektors und Berechnung von b
    try:
        print(f"\nEs werden {n}*{(n+1)} Daten für Matrix 'A' (Zufallsdaten zwischen {zMin} und {zMax})")
        print("und für Vektor 'b' (für x = 1) generiert. Dann werden die Lösungen 'x'")
        print("für 'A*x = b' neu berechnet. Vor allem bei größeren Werten von n stellen")
        print("sich unvermeidbare kleine Binäreffekt-Fehler ein. Bitte warten ...")
        
        start_time_matrix = time.perf_counter()
        
        # 3. Erzeuge die n x n Matrix A mit zufälligen Werten im Bereich -9 bis +9
        A = np.random.randint(zMin, zMax+1, size = (n, n))
        
        # 4. Initialisiere den Lösungsvektor x (alle Elemente x = 1)
        x_alt = np.ones(n)  # Von der KI so vorgeschlagen: Erspart etwas Tipp-Arbeit
        
        # 5. Berechne den Vektor b = A * x_alt (Matrix-Vektor-Multiplikation)
        b = A @ x_alt       # Von der KI so vorgeschlagen, super.
                            # Die kha-Lösung nach Pascal-Manier wäre um einiges länger gewesen   
        
        end_time_matrix = time.perf_counter()
        matrix_time     = end_time_matrix - start_time_matrix
    except MemoryError:
        c = input("Nicht genügend Speicher zur Generierung der Matrix. Abbruch nach Enter ")
        return

    # 6. Löse das Gleichungssystem A*x = b
    try: 
        start_time_solution = time.perf_counter()
        
        x_neu = np.linalg.solve(A, b)
        
        end_time_solution = time.perf_counter()
        solution_time     = end_time_solution - start_time_solution
    except MemoryError:
        c = input("Nicht genügend Speicher zum Lösen des Gleichungssystems. Abbruch nach Enter ")
        return
    except np.linalg.LinAlgError as e:
        print(e)
        c = input("NumPy-Fehler beim Lösen des Gleichungssystems. Abbruch nach Enter ")
        return

    # 7. Fehleranalyse: Berechne die Differenz zum ursprünglichen Vektor (x_true = 1)
    errors = x_neu - x_alt
    
    # 8. Ermittle größten Positiv-Fehler und größten Negativ-Fehler samt Index
    max_pos_error = np.max(errors); index_max_pos = np.argmax(errors)
    max_neg_error = np.min(errors); index_max_neg = np.argmin(errors)
    
    L1 = len(str(index_max_pos + 1))   # Formatierung der Fehlerberechnung 
    L2 = len(str(index_max_neg + 1))   # von kha zugefügt, nur Kosmetik
    if L1 > L2:
        dL2 = "".ljust(L1 - L2); dL1 = ""
    else:
        dL1 = "".ljust(L2 - L1); dL2 = ""

    print("\nBerechnungen fertig:")
 
    # 9. Ausgabe in tabellarischer Form mit 16 Nachkommastellen
    print("\nIndex\tLösungen x           Fehler")
    print("-----------------------------------------------")
    
    for i, (x_val, err) in enumerate(zip(x_neu, errors)):
        if i == 100:
            c = input(f"Sollen wirklich alle {n} Lösungen ausgegeben werden (j/n)?")
            if (c == "n") or (c == "N"):   # Alle anderen Zeichen für "j = ja" deuten
                break;
        print(f"{i+1:<6d} {x_val: .16f}  {err: .16f}")
        
    print("--------------------------")
    print("Soll:   1.0000000000000000\n")
    
    # 8. Ausgabe der Rechenzeiten, mit 11 Schreibstellen, davon 6 Nachkommastellen:
    print(f"Das ist die Python-Lösung eines linearen Gleichungssystems (mit {n} Gleichungen")
    print(f"und {n*n+1} generierten Daten) mit der NumPy-Funktion 'np.linalg.solve(A, b)'.")
    print()
    print("Größter Plus-Fehler  in Zeile " + dL1 + "{0}, Fehler = {1: .16f}".format(index_max_pos+1, max_pos_error))
    print("Größter Minus-Fehler in Zeile " + dL2 + "{0}, Fehler = {1: .16f}".format(index_max_neg+1, max_neg_error))
    print()
    print(f"Rechenzeit für Generierung Matrix A und Berechnung Vektor b:     {matrix_time:11.6f} sec")
    print(f"Rechenzeit für Neuberechnung des Lösungsvektors x, ohne Ausgabe: {solution_time:11.6f} sec")
    print(f"Gesamte Rechenzeit, ohne Ausgabe:                                {(matrix_time + solution_time):11.6f} sec")
   
linearesGleichungssystem()

c = input("\nEnde mit Tastendruck...") # -------------- EoF Python-Programm ------------

""" -----------------------------------------------------------------------------------
Anfang Python-Kommentarblock, markiert durch drei Anführungszeichen, Ende siehe unten
--- Ggf. Python-Download   via:  https://python.org
--- Ggf. Python-Thonny-IDE via:  https://thonny.org    Es gibt auch andere IDEs
--- Ggf. Python-Modul-NumPy erst installieren mit:     pip install numpy
--- Bei Android-Geräten mit "Pydroid 3": NumPy im Menü von "Pydroid 3" installieren

Es wird im Dialog N als Größe der Matrix A[n, n] abgefragt (bei Handrechnungen gilt
meist schon n = 3 als KO-Kriterium). Dann wird A gefüllt mit ganzzahligen Zufallswerten
zwischen MIN = -9 und MAX = 9. Danach wird der Vektor B[n] belegt mit den Summen der
jeweiligen Zeile des Vektors A. Wegen der Python-Zufallsfunktion ergeben sich bei jedem
Lauf andere Werte von A und B. Dennoch müsste bei dieser Vorgabe der Lösungsvektor x
der Gleichung A*x = B in allen Fällen gleich 1.000 sein. Durch Binäreffekte sind u.U.
bei sehr großen Matrizen geringfügige Abweichungen möglich.

Nebenbei: Die leistungsfähigsten Computer der Welt werden mit linearen Gleichungen
getestet, siehe "wwww.top500.org"
    
Die unten aufgeführten drei kha-Laptops (ACER, HP und der gebraucht gekaufte DELL) 
besitzen alle den Prozessor Intel i7, wenn auch beim HP schon sehr betagt, werden
aber alle mit Windows 11 betrieben. Der ACER und der HP besitzen 8 GB Hauptspeicher,
der DELL sagenhafte 32 GB.

Die Anzahl der generierten Daten und die Rechenzeiten in Sekunden für die kha-Geräte:   (DELL ab 09.2025)
Matrix N*N | Anzahl Daten = N*(N+1) |    ACER-PC | Tablet S6 | Handy S22 | alter HP-PC | DELL, 32 GB | 
-----------|------------------------|------------|-----------|-----------|-------------|-------------|
N =      1 |                      3 |    0,000 s |   0,000 s |   0,000 s |     0,000 s |    0.000 s  |
N =      2 |                      6 |    0,000 s |   0,000 s |   0,000 s |     0,000 s |    0.000 s  |
N =      3 |                     12 |    0,000 s |   0,000 s |   0,000 s |     0,000 s |    0.000 s  |
N =    100 |                 10.100 |    0,030 s |   0,024 s |   0,005 s |     0,046 s |    0,019 s  |
N = 10.000 |            100.010.000 |   11,670 s |  23,445 s |  17,570 s |    48,579 s |    5,968 s  |
N = 15.000 |            225.015.000 |   40,684 s |   Abbruch | 218,745 s |   168,459 s |   16,965 s  |
N = 25.000 |            625.025.000 |  379,230 s |    ./.    |   Abbruch |   992,786 s |   69,888 s  |
N = 30.000 |            900.030.000 | 1521,827 s |    ./.    |    ./.    |  4276,155 s |  114,282 s  |
N = 40.000 |          1.600.040.000 |    Abbruch |    ./.    |    ./.    |     Abbruch |  4,848 min  |
N = 50.000 |          2.500.050.000 |     ./.    |    ./.    |    ./.    |      ./.    | 17,104 min  |
N = 55.000 |          3.025.055.000 |     ./.    |    ./.    |    ./.    |      ./.    | 42,183 min  |
Anzahl Daten mit Ausgabevektor. Abbruch = Out of Memory.  
Bei N = 60.000 hat der DELL mit seinen  32 GB Fehler gezeigt. Kein Wunder, der Speicherbedarf alleine 
für die Daten zu je 8 Byte belegen über 28 GB.

Beispiel für n = 2:
1. Matrix A[n, n]:                    In mathematischer Schreibweise:
 [[ -9  6]                              -9*x1 + 6*x2  = -3
  [  6  4]]                              6*x1 + 4*x2  = 10
2. Vektor B[n]:                       Lösungen: x1 = 1, x2 = 1
  [-3 10]
3. Lösungsvektor x[n]: (sollte immer '1.' = 1.000 sein):
  [1. 1.]
4. Rechenzeit für n = 2 lineare Gleichungen mit 6 generierten Daten:
  0.000 sec
--------------------------------------------------------
Und so sähe der reine Gauß-Lösung ohne  Modul NumPy aus:
--------------------------------------------------------
def solve_linearesGleichungssystem(A, b):  # Aus KI
    n = len(A)
    for i in range(n):   # Gauss-Elimination 
        for j in range(i+1, n):
            factor = A[j][i] / A[i][i]
            for k in range(i, n):
                A[j][k] -= factor * A[i][k]
            b[j] -= factor * b[i]
    x = [0 for _ in range(n)]  # Rückwärtssubstitution
    for i in range(n-1, -1, -1):
        sum_ax = sum(A[i][j] * x[j] for j in range(i+1, n))
        x[i] = (b[i] - sum_ax) / A[i][i]
    return x

# Beispiel: Gleichungssystem Ax = b
A = [
      [ 2,  1, -1],
      [-3, -1,  2],
      [-2,  1,  2]
    ]
b = [8, -11, -3]

x = solve_linearesGleichungssystem(A, b)
print("Die Lösung:", x)
----------------------------------------------------------
... und so sähe eine komplette Lösung in der Programmiersprache Pascal aus:
... umständlicher, aber vielleicht etwas klarer
program GaussMitAusgabe;
uses
  CRT;

const
  n = 4;

var
  A:       array[1..n, 1..n] of Real;
  b, x:    array[1..n] of Real;
  i, j, k: Integer;
  Faktor:  Real;

begin
  // Initialisierung der Matrix A und des Vektors b
  A[1, 1] :=  2; A[1, 2] :=  3; A[1, 3] :=  1; A[1, 4] :=  2; b[1] :=  7;
  A[2, 1] := -1; A[2, 2] :=  1; A[2, 3] := -2; A[2, 4] :=  2; b[2] :=  0;
  A[3, 1] :=  4; A[3, 2] :=  3; A[3, 3] := -3; A[3, 4] :=  1; b[3] := -2;
  A[4, 1] :=  1; A[4, 2] :=  0; A[4, 3] := -1; A[4, 4] :=  2; b[4] :=  5;

  // Vorwaertselimination
  for i := 1 to n - 1 do
  begin
    for j := i + 1 to n do
    begin
      Faktor := A[j, i] / A[i, i];
      for k := i to n do
        A[j, k] := A[j, k] - Faktor * A[i, k];
      b[j] := b[j] - Faktor * b[i];
    end;
  end;

  // Rückwärtssubstitution
  for i := n downto 1 do
  begin
    x[i] := b[i];
    for j := i + 1 to n do
      x[i] := x[i] - A[i, j] * x[j];
    x[i] := x[i] / A[i, i];
  end;

  // Ausgabe der Loesung
  writeln('Loesung des Gleichungssystems:');
  for i := 1 to n do
    writeln('x[', i, '] = ', x[i]:2:4);
  // Lösungen:  1.000,  -1.000,  2.000,   3.000
  repeat until KeyPressed;
end.                                    

Ende Python-Kommentarblock, markiert mit drei Anführungszeichen --------------------- """