commit 970b4beeb288ef39e4178c085e425c347abc3746 Author: Lena Date: Thu Oct 22 00:45:17 2026 +0200 Initial MatrixMania layout diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d1eb6e8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.venv/ +__pycache__/ +.env \ No newline at end of file diff --git a/agends.md b/agends.md new file mode 100644 index 0000000..79a2eba --- /dev/null +++ b/agends.md @@ -0,0 +1,4 @@ +# Regeln für dieses Projekt +- Code nach PEP 8, Zeilenlänge maximal 88 Zeichen. +- Jede Funktion und Methode hat einen Docstring und Type Hints. +- Vor jedem Commit: `ruff check` und `ruff format`. \ No newline at end of file diff --git a/compute.py b/compute.py new file mode 100644 index 0000000..cecb251 --- /dev/null +++ b/compute.py @@ -0,0 +1,171 @@ + + +"""Utility functions for matrix operations. + +This module contains: +* ``matmul`` – standard matrix multiplication. +* ``transpose`` – row↔column swapping. +* ``rotate`` – 90‑degree clockwise rotations. + +All functions use type hints and raise informative errors where +dimensions are incompatible or matrices are non‑rectangular. +""" + +from __future__ import annotations + +from tabulate import tabulate + +Matrix = list[list[int | float]] + + +def matmul(a: Matrix, b: Matrix) -> Matrix: + """Return the matrix product a @ b. + + Parameters + ---------- + a : Matrix + Left‑hand matrix. + b : Matrix + Right‑hand matrix. + + Returns + ------- + Matrix + Product matrix. + + Raises + ------ + ValueError + If matrices are not rectangular or dimensions are incompatible. + """ + def _rect(mat: Matrix) -> bool: + return all(len(row) == len(mat[0]) for row in mat) + + if not a or not b: + raise ValueError("matrices may not be empty") + if not _rect(a) or not _rect(b): + raise ValueError("input matrices must be rectangular") + + r1, c1 = len(a), len(a[0]) + r2, c2 = len(b), len(b[0]) + if c1 != r2: + raise ValueError("first matrix columns must equal second matrix rows") + + result: Matrix = [[0 for _ in range(c2)] for _ in range(r1)] + for i in range(r1): + for j in range(c2): + s = 0 + for k in range(c1): + s += a[i][k] * b[k][j] + result[i][j] = s + return result + + +def transpose(matrix: Matrix) -> Matrix: + """Return the transpose of a 2‑D matrix. + + The transpose operation swaps rows and columns: each row in the + result is a column from the input matrix. + + Parameters + ---------- + matrix : Matrix + Two‑dimensional list of numbers. All rows must contain the + same number of columns. + + Returns + ------- + Matrix + Transposed matrix. + + Raises + ------ + ValueError + If *matrix* is empty or if the rows have differing lengths. + """ + if not matrix: + raise ValueError("transpose requires a non‑empty matrix") + if any(len(row) != len(matrix[0]) for row in matrix): + raise ValueError("matrix must be rectangular to transpose") + rows, cols = len(matrix), len(matrix[0]) + return [[matrix[i][j] for i in range(rows)] for j in range(cols)] + + +def rot_2D(theta: float) -> list[list[float]]: + """Return the 2‑D rotation matrix for angle *theta* in degrees. + + The matrix is + ``[[cos(θ), -sin(θ)], + [sin(θ), cos(θ)]]`` + where θ is interpreted as a clockwise rotation. + + Parameters + ---------- + theta : float + Rotation angle in degrees (clockwise). + + Returns + ------- + list[list[float]] + 2x2 rotation matrix. + """ + import math + rad = math.radians(theta) + cos_t = math.cos(rad) + sin_t = math.sin(rad) + return [[cos_t, -sin_t], [sin_t, cos_t]] + + +def rotate(matrix: Matrix, degrees: float) -> Matrix: + """Rotate the matrix clockwise by 0, 90, 180, or 270 degrees. + + Parameters + ---------- + matrix : Matrix + degrees : float + Must be one of 0, 90, 180, 270. + + Returns + ------- + Matrix + + Raises + ------ + ValueError + If *degrees* is unsupported. + """ + if degrees not in (0, 90, 180, 270): + raise ValueError("degrees must be one of 0, 90, 180, 270") + if not matrix: + return [] + n_rows, n_cols = len(matrix), len(matrix[0]) + if degrees == 0: + return [row[:] for row in matrix] + if degrees == 90: + return [[matrix[n_rows - 1 - j][i] for j in range(n_rows)] for i in range(n_cols)] + if degrees == 180: + return [[matrix[n_rows - 1 - i][n_cols - 1 - j] for j in range(n_cols)] for i in range(n_rows)] + # 270 + return [[matrix[j][n_cols - 1 - i] for j in range(n_rows)] for i in range(n_cols)] + +if __name__ == "__main__": + # matmul tests + a1 = [[1, 2], [3, 4]] + b1 = [[5, 6], [7, 8]] + assert matmul(a1, b1) == [[19, 22], [43, 50]], "matmul example 1 failed" + a2 = [[1], [2], [3]] + b2 = [[4, 5, 6]] + assert matmul(a2, b2) == [[4, 5, 6], [8, 10, 12], [12, 15, 18]], "matmul example 2 failed" + + # transpose test + mat = [[1, 2, 3], [4, 5, 6]] + assert transpose(mat) == [[1, 4], [2, 5], [3, 6]], "transpose failed" + + # rotation tests + mat3 = [[1, 2], [3, 4], [5, 6]] + assert rotate(mat3, 90) == [[5, 3, 1], [6, 4, 2]], "rotate 90 failed" + assert rotate(mat3, 180) == [[6, 5], [4, 3], [2, 1]], "rotate 180 failed" + assert rotate(mat3, 270) == [[2, 4, 6], [1, 3, 5]], "rotate 270 failed" + assert rotate(mat3, 0) == mat3, "rotate 0 failed" + + print(tabulate(rot_2D(1.0))) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..3a776b1 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,4 @@ +[project] +name = "matrixmania" +version = "0.1.0" +dependencies = ["tabulate", "ruff"] \ No newline at end of file