"""Matrix operations module. This module provides utilities for basic matrix arithmetic: * :func:`matmul` – standard matrix multiplication * :func:`transpose` – matrix transposition * :func:`rot_2D` – 2‑D rotation matrix generator All functions validate inputs and raise ``ValueError`` where appropriate. Type hints use the built‑in ``list`` and ``int | float`` union. """ from __future__ import annotations import math # Public type alias for a matrix of numeric values. Matrix = list[list[int | float]] # --------------------------------------------------------------------------- # matmul # --------------------------------------------------------------------------- def matmul(a: Matrix, b: Matrix) -> Matrix: """Multiply two matrices. Parameters ---------- a: Matrix Left‑hand operand. Must be a non‑empty, rectangular matrix. b: Matrix Right‑hand operand. Must be a non‑empty, rectangular matrix whose column count equals ``a``'s row count. Returns ------- Matrix Result of the matrix product ``a @ b``. Raises ------ ValueError If either matrix is empty, not rectangular, or the inner dimensions do not agree. """ if not a or not a[0] or not b or not b[0]: raise ValueError("Both matrices must be non‑empty") a_rows, a_cols = len(a), len(a[0]) b_rows, b_cols = len(b), len(b[0]) if any(len(row) != a_cols for row in a): raise ValueError("Matrix 'a' is not rectangular") if any(len(row) != b_cols for row in b): raise ValueError("Matrix 'b' is not rectangular") if a_cols != b_rows: raise ValueError( f"Inner matrix dimensions must agree: a_cols={a_cols} != b_rows={b_rows}" ) result: Matrix = [[0 for _ in range(b_cols)] for _ in range(a_rows)] for i in range(a_rows): for j in range(b_cols): s = 0 for k in range(a_cols): s += a[i][k] * b[k][j] result[i][j] = s return result # --------------------------------------------------------------------------- # Transpose # --------------------------------------------------------------------------- def transpose(mat: Matrix) -> Matrix: """Return the transpose of a matrix. Parameters ---------- mat: Matrix Input matrix to transpose. Must be a non‑empty, rectangular matrix. Returns ------- Matrix Transposed matrix: columns become rows and vice versa. Raises ------ ValueError If ``mat`` is empty or the rows have differing lengths. """ if not mat or not mat[0]: raise ValueError("Matrix must be non‑empty") row_len = len(mat[0]) if any(len(row) != row_len for row in mat): raise ValueError("Matrix must be rectangular – rows have varying lengths") transposed: Matrix = [[mat[row][col] for row in range(len(mat))] for col in range(row_len)] return transposed # --------------------------------------------------------------------------- # Rotation matrix generator # --------------------------------------------------------------------------- def rot_2D(theta: float) -> Matrix: """Return a 2‑D rotation matrix for an angle ``theta``. The matrix corresponds to a rotation about the origin by ``theta`` radians (counter‑clockwise). For a vector ``(x, y)`` the rotated coordinates are obtained via ``matmul(rot_2D(theta), [x, y])``. Parameters ---------- theta: float Rotation angle in radians. Returns ------- Matrix 2×2 rotation matrix. Raises ------ ValueError Never raised – the function accepts any floating‑point value. """ c = math.cos(theta) s = math.sin(theta) return [[c, -s], [s, c]] # --------------------------------------------------------------------------- # Example usage / tests # --------------------------------------------------------------------------- if __name__ == "__main__": # Example multiply 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) # Example transpose matrix_d = [[1, 2, 3], [4, 5, 6]] print("Transpose of", matrix_d, "=", transpose(matrix_d)) # Demonstrate rot_2D angle = math.radians(45) rot = rot_2D(angle) vec = [[1], [0]] print("Rotation matrix for 45°:", rot) print("Rotated vec:", matmul(rot, vec))