From d49bccdd7a90c7463c28c18833190116f3478ba9 Mon Sep 17 00:00:00 2001 From: Yona Date: Mon, 19 Oct 2026 17:42:28 +0200 Subject: [PATCH] Version 0 --- Compute.py | 234 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 Compute.py diff --git a/Compute.py b/Compute.py new file mode 100644 index 0000000..1be1103 --- /dev/null +++ b/Compute.py @@ -0,0 +1,234 @@ +"""Rechen-Hilfen für Matrizen. + +Dieses Modul stellt vier Funktionen bereit: + +* :func:`matmul` – multipliziert zwei (auch nicht-quadratische) + Matrizen. +* :func:`transpose` – transponiert eine Matrix. +* :func:`rotate` – rotiert eine Matrix um 90 Grad im Uhrzeigersinn. +* :func:`rot_2D` – erzeugt die 2x2-Rotationsmatrix für einen Winkel. + +Die Implementierung validiert alle Eingaben: + +* Alle Zeilen einer Matrix müssen gleich lang sein. +* Bei :func:`matmul` muss die Spaltenzahl der ersten Matrix der + Zeilenzahl der zweiten Matrix entsprechen – die klassische Regel + der Matrixmultiplikation. +* Alle Elemente müssen ``int`` oder ``float`` sein – andernfalls wird + ein :class:`TypeError` ausgelöst. + +Nicht kompatible Matrizen führen zu einem :class:`ValueError`. +Unter ``__main__`` befindet sich ein kleiner Testrahmen zum schnellen +manuellen Ausprobieren. + +Für dieses Rechenmodul werden keine externen Abhängigkeiten benötigt. +""" + +from __future__ import annotations + +import math + +__all__ = ["matmul", "transpose", "rotate", "rot_2D"] + + +def _validate(matrix: list[list[float]], name: str) -> tuple[int, int]: + """Prüfe eine Matrix und gib ihre Form ``(Zeilen, Spalten)`` zurück. + + Akzeptiert auch die leere Matrix ``[]`` (Form ``(0, 0)``). Alle + Zeilen müssen gleich lang und alle Elemente müssen ``int`` oder + ``float`` sein. + + Raises + ------ + ValueError + Wenn die Zeilen ungleich lang sind. + TypeError + Wenn ein Element keine Zahl ist. + """ + if not matrix: + return (0, 0) + n_rows = len(matrix) + n_cols = len(matrix[0]) + for row in matrix: + if len(row) != n_cols: + raise ValueError( + f"Alle Zeilen von {name} müssen gleich lang sein " + f"(erwartet {n_cols}, erhalten {len(row)})" + ) + for x in row: + if not isinstance(x, (int, float)): + raise TypeError( + f"Elemente von {name} müssen Zahlen sein, " + f"aber {x!r} ist {type(x).__name__}" + ) + return (n_rows, n_cols) + + +# ================= Matrixmultiplikation ================= + +def matmul( + a: list[list[float]], b: list[list[float]] +) -> list[list[float]]: + """Berechne das Produkt ``a @ b`` zweier Matrizen. + + Die Matrizen dürfen auch rechteckig sein. Beide Eingaben werden + nicht verändert. + + Parameters + ---------- + a, b : list[list[float]] + Zweidimensionale Listen mit Zahlen. Die Spaltenzahl von + ``a`` muss der Zeilenzahl von ``b`` entsprechen. Die leere + Matrix (``[]``) ist als Operand nicht erlaubt. + + Returns + ------- + list[list[float]] + Das Matrixprodukt ``a @ b``. + + Raises + ------ + ValueError + Wenn eine der Matrizen leer ist, Zeilen ungleich lang sind oder + die Dimensionen nicht zusammenpassen. + TypeError + Wenn ein Element keine Zahl ist. + """ + rows_a, cols_a = _validate(a, "'a'") + rows_b, cols_b = _validate(b, "'b'") + + if rows_a == 0 or rows_b == 0: + raise ValueError( + "Leere Matrizen sind als Operanden der Multiplikation " + "nicht erlaubt" + ) + if cols_a != rows_b: + raise ValueError( + f"Spaltenzahl von 'a' ({cols_a}) und Zeilenzahl von 'b' " + f"({rows_b}) müssen übereinstimmen" + ) + + # Initialisiere die Ergebnismatrix (rows_a x cols_b) mit Nullen. + result: list[list[float]] = [[0] * cols_b for _ in range(rows_a)] + + # Zeilenweise durchlaufen (i), dann das gemeinsame Element (k): + # ikj-Reihenfolge ist cache-freundlicher als das klassische ijk. + for i in range(rows_a): + row_result = result[i] + for k in range(cols_a): + aik = a[i][k] + if aik == 0: + continue + b_row = b[k] + for j in range(cols_b): + row_result[j] += aik * b_row[j] + return result + + +# ================= Transposition ================= + +def transpose(matrix: list[list[float]]) -> list[list[float]]: + """Gib die Transponierte einer Matrix zurück. + + Parameters + ---------- + matrix : list[list[float]] + Zweidimensionale Liste mit Zahlen. Die leere Matrix ``[]`` + wird als ``[]`` zurückgegeben. + + Returns + ------- + list[list[float]] + Die transponierte Matrix. + + Raises + ------ + ValueError + Wenn die Zeilen ungleich lang sind. + TypeError + Wenn ein Element keine Zahl ist. + """ + n_rows, n_cols = _validate(matrix, "matrix") + return [[matrix[i][j] for i in range(n_rows)] for j in range(n_cols)] + + +# ================= Rotation um 90 Grad ================= + +def rotate(matrix: list[list[float]]) -> list[list[float]]: + """Rotiere eine Matrix um 90 Grad im Uhrzeigersinn. + + Die erste Zeile wird zur letzten Spalte, die letzte Zeile zur + ersten Spalte. Die Eingabe wird nicht verändert. + + Parameters + ---------- + matrix : list[list[float]] + Zweidimensionale Liste mit Zahlen. Die leere Matrix ``[]`` + wird als ``[]`` zurückgegeben. + + Returns + ------- + list[list[float]] + Die um 90 Grad im Uhrzeigersinn rotierte Matrix. + + Raises + ------ + ValueError + Wenn die Zeilen ungleich lang sind. + TypeError + Wenn ein Element keine Zahl ist. + """ + return [row[::-1] for row in transpose(matrix)] + + +# ================= 2D-Rotationsmatrix ================= + +def rot_2D(theta: float) -> list[list[float]]: + """Erzeuge die Rotationsmatrix für eine Drehung um ``theta``. + + Die Matrix dreht einen Punkt in der Ebene um den Winkel ``theta`` + um den Ursprung: + + .. math:: + + \\begin{pmatrix} \\cos\\theta & -\\sin\\theta \\\\ + \\sin\\theta & \\cos\\theta \\end{pmatrix} + + Parameters + ---------- + theta : float + Drehwinkel im Bogenmaß (Radiant). + + Returns + ------- + list[list[float]] + Die 2x2-Rotationsmatrix. + """ + cos_t = math.cos(theta) + sin_t = math.sin(theta) + return [[cos_t, -sin_t], [sin_t, cos_t]] + + +# ================= Testrahmen ================= +if __name__ == "__main__": + # matmul mit rechteckigen Matrizen + matrix_a = [ + [3, 4, -1, 4], + [-2, 2, 5, 1], + ] + matrix_b = [ + [1, 3, -2], + [2, 5, 1], + [-1, 4, -4], + [2, 3, 6], + ] + matrix_c = matmul(matrix_a, matrix_b) + print("Ergebnis C = A * B:") + for row in matrix_c: + print(row) + + # rot_2D: Drehung um 90 Grad gegen den Uhrzeigersinn + rotation = rot_2D(math.pi / 2) + point = [[1.0], [0.0]] + print("rot_2D-Ergebnis:", matmul(rotation, point)) +