Initial MatrixMania layout
This commit is contained in:
commit
970b4beeb2
4 files changed
+182
No files matched your search
@@ -0,0 +1,3 @@
|
|||||||
|
.venv/
|
||||||
|
__pycache__/
|
||||||
|
.env
|
||||||
@@ -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`.
|
||||||
+171
@@ -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)))
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[project]
|
||||||
|
name = "matrixmania"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = ["tabulate", "ruff"]
|
||||||
Reference in new issue
Block a user