145 lines
3.6 KiB
Python
145 lines
3.6 KiB
Python
"""
|
||
Matrix multiplication for nested list matrices.
|
||
|
||
This module contains the :func:`matmul` function, which multiplies two
|
||
matrices represented as nested Python lists. The matrices are
|
||
expected to be rectangular (each sub‑list has the same length). A
|
||
:class:`ValueError` is raised if the inner dimensions do not match.
|
||
|
||
Example
|
||
-------
|
||
>>> a = [[1, 2], [3, 4]]
|
||
>>> b = [[5, 6], [7, 8]]
|
||
>>> matmul(a, b)
|
||
[[19.0, 22.0], [43.0, 50.0]]
|
||
|
||
The function is intentionally simple and performs no type checking
|
||
of the inner elements; it simply forwards the arithmetic operations to
|
||
Python's built‑in integer and float handling.
|
||
"""
|
||
|
||
import math
|
||
|
||
from tabulate import tabulate
|
||
|
||
|
||
def rot_2D(theta: float) -> list[list[float]]:
|
||
"""Return the 2‑D rotation matrix for a given angle.
|
||
|
||
Parameters
|
||
----------
|
||
theta : float
|
||
Angle in radians to rotate counter‑clockwise around the origin.
|
||
|
||
Returns
|
||
-------
|
||
list[list[float]]
|
||
2x2 rotation matrix
|
||
|
||
Examples
|
||
--------
|
||
>>> rot_2D(0) # identity
|
||
[[1.0, -0.0], [0.0, 1.0]]
|
||
"""
|
||
c = math.cos(theta)
|
||
s = math.sin(theta)
|
||
return [[c, -s], [s, c]]
|
||
|
||
|
||
def matmul(a: list[list[float | int]], b: list[list[float | int]]) -> list[list[float]]:
|
||
"""Return the matrix product of *a* and *b*.
|
||
|
||
Parameters
|
||
----------
|
||
a : list[list[float | int]]
|
||
First matrix, shape ``(m, n)``.
|
||
b : list[list[float | int]]
|
||
Second matrix, shape ``(n, p)``.
|
||
|
||
Returns
|
||
-------
|
||
list[list[float]]
|
||
The result matrix of shape ``(m, p)``.
|
||
|
||
Raises
|
||
------
|
||
ValueError
|
||
If the number of columns of ``a`` does not equal the number of
|
||
rows of ``b``.
|
||
"""
|
||
n_cols_a = len(a[0]) if a else 0
|
||
n_rows_b = len(b)
|
||
if n_cols_a != n_rows_b:
|
||
raise ValueError(
|
||
f"inner dimensions must match: {n_cols_a} (a columns) != {n_rows_b} (b rows)"
|
||
)
|
||
|
||
m = len(a)
|
||
p = len(b[0]) if b else 0
|
||
# Pre‑allocate result matrix
|
||
result: list[list[float]] = [[0.0 for _ in range(p)] for _ in range(m)]
|
||
|
||
for i in range(m):
|
||
for k in range(n_cols_a): # using k as column index of a, row of b
|
||
a_val = a[i][k]
|
||
for j in range(p):
|
||
result[i][j] += a_val * b[k][j]
|
||
return result
|
||
|
||
|
||
def transpose(matrix: list[list[float | int]]) -> list[list[float | int]]:
|
||
"""Return the transpose of the given matrix.
|
||
|
||
Parameters
|
||
----------
|
||
matrix : list[list[float | int]]
|
||
Matrix to transpose. All rows must have the same length.
|
||
|
||
Returns
|
||
-------
|
||
list[list[float | int]]
|
||
Transposed matrix.
|
||
|
||
Raises
|
||
------
|
||
ValueError
|
||
If ``matrix`` is empty or rows have differing lengths.
|
||
|
||
Examples
|
||
--------
|
||
>>> mat = [[1, 2, 3], [4, 5, 6]]
|
||
>>> transpose(mat)
|
||
[[1, 4], [2, 5], [3, 6]]
|
||
"""
|
||
if not matrix:
|
||
raise ValueError("Matrix must not be empty")
|
||
row_length = len(matrix[0])
|
||
if any(len(row) != row_length for row in matrix):
|
||
raise ValueError("All rows must have the same number of columns")
|
||
return [list(col) for col in zip(*matrix)]
|
||
|
||
|
||
if __name__ == "__main__":
|
||
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 = [
|
||
[1, 2, 3],
|
||
[4, 5, 6],
|
||
]
|
||
|
||
print("Transposed Matrix:\n", transpose(matrix))
|
||
print("\nMatrix multiplication result:\n")
|
||
matrix_c = matmul(matrix_a, matrix_b)
|
||
for row in matrix_c:
|
||
print(row)
|
||
print("\nRotation matrix 90°:\n", rot_2D(math.pi / 2))
|
||
print(tabulate(rot_2D(1.0)))
|