"""Mathematische Hilfsfunktionen für Matrixoperationen.""" import math def matmul(matrix_a: list[list[float]], matrix_b: list[list[float]]) -> list[list[float]]: """Berechnet das Matrixprodukt zweier Matrizen (matrix_a @ matrix_b). :param matrix_a: Die linke Matrix. :param matrix_b: Die rechte Matrix. :return: Die Ergebnismatrix der Multiplikation. :raises ValueError: Wenn eine Matrix leer ist, Zeilen ungleich lang sind oder die Spaltenanzahl von matrix_a nicht der Zeilenanzahl von matrix_b entspricht. """ if not matrix_a or not matrix_b or not matrix_a[0] or not matrix_b[0]: raise ValueError("Beide Matrizen müssen nicht-leer sein.") rows_a, cols_a = len(matrix_a), len(matrix_a[0]) rows_b, cols_b = len(matrix_b), len(matrix_b[0]) if any(len(row) != cols_a for row in matrix_a) or any(len(row) != cols_b for row in matrix_b): raise ValueError("Alle Zeilen einer Matrix müssen dieselbe Länge besitzen.") if cols_a != rows_b: raise ValueError("Matrixdimensionen stimmen für die Multiplikation nicht überein.") result: list[list[float]] = [] for i in range(rows_a): result_row: list[float] = [] for j in range(cols_b): dot_product = sum(matrix_a[i][k] * matrix_b[k][j] for k in range(cols_a)) result_row.append(dot_product) result.append(result_row) return result def transpose(matrix: list[list[float]]) -> list[list[float]]: """Transponiert eine Matrix, sodass alle Zeilen zu Spalten und Spalten zu Zeilen werden. :param matrix: Die zu transponierende Matrix. :return: Die transponierte Matrix. :raises ValueError: Wenn die Matrix leer ist oder die Zeilen ungleichmäßig viele Spalten besitzen. """ if not matrix or not matrix[0]: raise ValueError("Die Matrix darf nicht leer sein.") num_cols = len(matrix[0]) if any(len(row) != num_cols for row in matrix): raise ValueError("Alle Zeilen müssen dieselbe Länge besitzen.") num_rows = len(matrix) return [ [matrix[row_idx][col_idx] for row_idx in range(num_rows)] for col_idx in range(num_cols) ] def rot_2d(angle: float) -> list[list[float]]: """Berechnet die 2D-Rotationsmatrix für einen gegebenen Drehwinkel. Die Rotationsmatrix R(theta) lautet: [[cos(theta), -sin(theta)], [sin(theta), cos(theta)]] :param angle: Der Rotationswinkel im Bogenmaß (Radiant). :return: Die 2x2-Rotationsmatrix als verschachtelte Liste. """ cos_theta = math.cos(angle) sin_theta = math.sin(angle) return [ [cos_theta, -sin_theta], [sin_theta, cos_theta], ] if __name__ == "__main__": a1 = [ [3, 4, -1, 4], [-2, 2, 5, 1], ] b1 = [ [1, 3, -2], [2, 5, 1], [-1, 4, -4], [2, 3, 6], ] expected_c1 = [ [20, 37, 26], [-1, 27, -8], ] c1 = matmul(a1, b1) assert c1 == expected_c1, f"Fehler in Beispiel 1: Erwartet {expected_c1}, erhalten {c1}" print("Test 1 (Skript-Beispiel) erfolgreich bestanden!") a2 = [ [1, 2], [3, 4], ] identity = [ [1, 0], [0, 1], ] c2 = matmul(a2, identity) assert c2 == a2, f"Fehler in Beispiel 2: Erwartet {a2}, erhalten {c2}" print("Test 2 (Einheitsmatrix) erfolgreich bestanden!") incompatible_b = [ [1, 2], [3, 4], ] try: matmul(a1, incompatible_b) raise AssertionError("Fehlerfall wurde nicht abgefangen!") except ValueError: print("Test 3 (Fehlerfall inkompatible Dimensionen) erfolgreich abgefangen!") # Tests für Transpose example_matrix = [ [1, 2, 3], [4, 5, 6], ] expected_transposed = [ [1, 4], [2, 5], [3, 6], ] assert transpose(example_matrix) == expected_transposed, ( f"Erwartet: {expected_transposed}, Erhalten: {transpose(example_matrix)}" ) print("Test 4 (transpose) erfolgreich bestanden!") # Test transpose: Leere Matrix try: transpose([]) raise AssertionError("Leere Matrix wurde nicht abgefangen!") except ValueError: print("Test 5 (transpose leere Matrix) erfolgreich abgefangen!") # Test transpose: Ungleichmäßige Zeilenlänge uneven_matrix = [ [1, 2, 3], [4, 5], ] try: transpose(uneven_matrix) raise AssertionError("Ungleichmäßige Matrix wurde nicht abgefangen!") except ValueError: print("Test 6 (transpose ungleichmäßige Matrix) erfolgreich abgefangen!") # Test 7: Rotation um 0 Radianten (entspricht der Einheitsmatrix) rot_0 = rot_2d(0.0) assert math.isclose(rot_0[0][0], 1.0, abs_tol=1e-9) assert math.isclose(rot_0[0][1], 0.0, abs_tol=1e-9) assert math.isclose(rot_0[1][0], 0.0, abs_tol=1e-9) assert math.isclose(rot_0[1][1], 1.0, abs_tol=1e-9) print("Test rot_2D (0 Radiant) erfolgreich bestanden!") # Test 8: Rotation um 90 Grad (pi / 2) -> [[0, -1], [1, 0]] rot_90 = rot_2d(math.pi / 2) assert math.isclose(rot_90[0][0], 0.0, abs_tol=1e-9) assert math.isclose(rot_90[0][1], -1.0, abs_tol=1e-9) assert math.isclose(rot_90[1][0], 1.0, abs_tol=1e-9) assert math.isclose(rot_90[1][1], 0.0, abs_tol=1e-9) print("Test rot_2D (pi / 2 Radiant) erfolgreich bestanden!") # Test 9: Drehung des Vektors (1, 0) um 90 Grad ergibt (0, 1) via matmul point = [[1.0], [0.0]] rotated_point = matmul(rot_90, point) assert math.isclose(rotated_point[0][0], 0.0, abs_tol=1e-9) assert math.isclose(rotated_point[1][0], 1.0, abs_tol=1e-9) print("Test rot_2D (Vektordrehung mit matmul) erfolgreich bestanden!") # Test-Änderung