164 lines
4.6 KiB
Python
164 lines
4.6 KiB
Python
"""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))
|