"""Compute operations for matrices. This module provides public functions for matrix multiplication, transposition, matrix rotation, and generating 2D and 3D rotation matrices as well as projections. """ from __future__ import annotations import math from typing import List def matmul( matrix_a: List[List[float]], matrix_b: List[List[float]] ) -> List[List[float]]: """Multiply two 2D matrices. Both matrices are expected to be non‑empty and to have consistent row lengths. The number of columns in ``matrix_a`` must equal the number of rows in ``matrix_b``. Args: matrix_a: A matrix of shape (m, n) represented as a list of m rows. matrix_b: A matrix of shape (n, p) represented as a list of n rows. Returns: A new matrix of shape (m, p) containing the product ``matrix_a @ matrix_b``. Raises: ValueError: If either matrix is empty or dimensions do not match. """ if not matrix_a or not matrix_b: raise ValueError("Input matrices must not be empty.") n_cols_a = len(matrix_a[0]) if any(len(row) != n_cols_a for row in matrix_a): raise ValueError("All rows of matrix_a must have the same number of columns.") n_rows_b = len(matrix_b) if n_cols_a != n_rows_b: raise ValueError( f"Matrix dimension mismatch: matrix_a columns {n_cols_a} != matrix_b rows {n_rows_b}" ) n_cols_b = len(matrix_b[0]) if any(len(row) != n_cols_b for row in matrix_b): raise ValueError("All rows of matrix_b must have the same number of columns.") result: List[List[float]] = [] for i in range(len(matrix_a)): row: List[float] = [] for j in range(n_cols_b): elem = sum(matrix_a[i][k] * matrix_b[k][j] for k in range(n_cols_a)) row.append(elem) result.append(row) return result def transpose(matrix: List[List[float]]) -> List[List[float]]: """Return the transpose of a 2D matrix.""" if not matrix: raise ValueError("Cannot transpose an empty matrix.") n_rows = len(matrix) n_cols = len(matrix[0]) if any(len(row) != n_cols for row in matrix): raise ValueError("All rows of the matrix must have the same number of columns.") return [[matrix[i][j] for i in range(n_rows)] for j in range(n_cols)] def rotate_clockwise(matrix: List[List[float]]) -> List[List[float]]: """Rotate a square matrix 90 degrees clockwise.""" if not matrix: raise ValueError("Cannot rotate an empty matrix.") n_cols = len(matrix[0]) if any(len(row) != n_cols for row in matrix): raise ValueError("All rows of the matrix must have the same number of columns.") transposed = transpose(matrix) return [row[::-1] for row in transposed] def rot_2D(theta: float) -> List[List[float]]: """Return the 2D rotation matrix for a given angle in degrees.""" rad = math.radians(theta) c = math.cos(rad) s = math.sin(rad) return [[c, -s], [s, c]] def rot_3D(angle: float, axis: str) -> list[list[float]]: """Erzeugt eine 3D-Rotationsmatrix um die angegebene Achse ('x', 'y' oder 'z').""" rad = math.radians(angle) c, s = math.cos(rad), math.sin(rad) axis = axis.lower() if axis == 'x': return [ [1.0, 0.0, 0.0], [0.0, c, -s], [0.0, s, c] ] elif axis == 'y': return [ [c, 0.0, s], [0.0, 1.0, 0.0], [-s, 0.0, c] ] elif axis == 'z': return [ [c, -s, 0.0], [s, c, 0.0], [0.0, 0.0, 1.0] ] else: raise ValueError("Achse muss 'x', 'y' oder 'z' sein.") def project_ortho(point: tuple[float, float, float], scale: float = 1.0) -> tuple[float, float]: """Projiziert einen 3D-Punkt orthogonal auf eine 2D-Ebene und skaliert ihn.""" x, y, z = point return (x * scale, y * scale) def project_perspective(point: tuple[float, float, float], distance: float = 200.0, scale: float = 1.0) -> tuple[float, float]: """Projiziert einen 3D-Punkt perspektivisch auf eine 2D-Fläche.""" x, y, z = point # Verhindert Division durch 0, falls z genau bei -distance liegt factor = distance / (distance + z) if (distance + z) != 0 else 1.0 return (x * factor * scale, y * factor * scale) if __name__ == "__main__": a = [[1, 2, 3], [4, 5, 6]] b = [[7, 8], [9, 10], [11, 12]] print("matmul(a, b):", matmul(a, b)) print("transpose(a):", transpose(a)) # Teste deine Tests mit: python -m pytest