135 lines
3.8 KiB
Python
135 lines
3.8 KiB
Python
"""Computational utilities for matrix operations and 2D transformations.
|
||
|
||
Functions:
|
||
matmul(A, B)
|
||
Multiply two matrices represented as list of lists.
|
||
transpose(matrix)
|
||
Return the transpose of a matrix.
|
||
rot_2D(theta)
|
||
Return the 2D rotation matrix for a given angle theta.
|
||
"""
|
||
|
||
# Teständerung
|
||
|
||
from __future__ import annotations
|
||
|
||
import math
|
||
|
||
from tabulate import tabulate
|
||
|
||
Matrix = list[list[float]]
|
||
|
||
def transpose(matrix: Matrix) -> Matrix:
|
||
"""Return the transpose of *matrix*.
|
||
|
||
The matrix must be non‑empty and rectangular; this is validated
|
||
by the existing ``_check_matrix`` helper.
|
||
"""
|
||
_check_matrix(matrix)
|
||
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) -> Matrix:
|
||
"""Return the 2D rotation matrix for a given angle theta (in radians).
|
||
|
||
Parameters
|
||
----------
|
||
theta : float
|
||
Rotation angle in radians.
|
||
|
||
Returns
|
||
-------
|
||
Matrix
|
||
A 2x2 rotation matrix [[cos(theta), -sin(theta)], [sin(theta), cos(theta)]].
|
||
"""
|
||
c = math.cos(theta)
|
||
s = math.sin(theta)
|
||
return [
|
||
[c, -s],
|
||
[s, c]
|
||
]
|
||
|
||
def _check_matrix(matrix: Matrix) -> None:
|
||
"""Ensure all rows in *matrix* are lists of floats and of equal length.
|
||
|
||
Raises:
|
||
ValueError: If *matrix* is empty, contains non‑list rows,
|
||
non‑float elements, or uneven row lengths.
|
||
"""
|
||
if not matrix:
|
||
raise ValueError("Matrix must not be empty")
|
||
row_len = None
|
||
for row_idx, row in enumerate(matrix):
|
||
if not isinstance(row, list):
|
||
raise ValueError(f"Row {row_idx} is not a list")
|
||
if row_len is None:
|
||
row_len = len(row)
|
||
if row_len == 0:
|
||
raise ValueError("Rows must contain at least one element")
|
||
elif len(row) != row_len:
|
||
raise ValueError(
|
||
f"Row {row_idx} length {len(row)} differs from expected {row_len}"
|
||
)
|
||
for col_idx, item in enumerate(row):
|
||
if not isinstance(item, (int, float)):
|
||
raise ValueError(
|
||
f"Element at ({row_idx},{col_idx}) is not a number"
|
||
)
|
||
|
||
|
||
def matmul(A: Matrix, B: Matrix) -> Matrix:
|
||
"""Return the matrix product of *A* and *B*.
|
||
|
||
The matrices must be compatible for multiplication, i.e. the
|
||
number of columns in *A* must equal the number of rows in *B*.
|
||
|
||
Parameters
|
||
----------
|
||
A, B : Matrix
|
||
Two‑dimensional lists of numeric values.
|
||
|
||
Returns
|
||
-------
|
||
Matrix
|
||
Resulting matrix of dimensions ``len(A) x len(B[0])``.
|
||
|
||
Raises
|
||
------
|
||
ValueError
|
||
If either input is malformed (non‑uniform rows, empty,
|
||
non‑numeric entries) or if the dimensions are incompatible.
|
||
"""
|
||
_check_matrix(A)
|
||
_check_matrix(B)
|
||
|
||
a_rows, a_cols = len(A), len(A[0])
|
||
b_rows, b_cols = len(B), len(B[0])
|
||
|
||
if a_cols != b_rows:
|
||
raise ValueError(
|
||
f"Cannot multiply: {a_rows}x{a_cols} matrix A with {b_rows}x{b_cols} matrix B"
|
||
)
|
||
|
||
result: Matrix = []
|
||
for i in range(a_rows):
|
||
row: list[float] = []
|
||
for j in range(b_cols):
|
||
s = 0.0
|
||
for k in range(a_cols):
|
||
s += A[i][k] * B[k][j]
|
||
row.append(s)
|
||
result.append(row)
|
||
|
||
return result
|
||
|
||
if __name__ == "__main__":
|
||
# Test für rot_2D (z. B. Rotation um 90 Grad = pi / 2)
|
||
theta = math.pi / 2
|
||
R = rot_2D(theta)
|
||
print("Rotationsmatrix für 90 Grad:", R)
|
||
|
||
# Einen Punkt (Vektor) als 2x1 Matrix rotieren: [ [x], [y] ]
|
||
point = [[1.0], [0.0]] # Punkt auf der x-Achse bei x=1, y=0
|
||
rotated_point = matmul(R, point)
|
||
print("Gedrehter Punkt (erwartet y=1, x=0):", rotated_point)
|
||
print(tabulate(rot_2D(1.0))) |