Erster Stand
This commit is contained in:
commit
397ab45018
10 files changed
+315
No files matched your search
@@ -0,0 +1,3 @@
|
||||
.venv/
|
||||
__pycache__/
|
||||
.env
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
Generated
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.13 (matrixmania)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
Generated
+7
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.13 (matrixmania)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (matrixmania)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/matrixmania.iml" filepath="$PROJECT_DIR$/.idea/matrixmania.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -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`.
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
"""Provides matmul, transpose, and rotate functions for 2‑D numeric matrices."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from collections.abc import Iterable
|
||||
from typing import Literal
|
||||
|
||||
__all__ = ["matmul", "rot_2d", "rotate", "transpose"]
|
||||
|
||||
_NUMERIC_TYPES = (int, float)
|
||||
|
||||
|
||||
def _validate_matrix(
|
||||
matrix: Iterable[Iterable[object]], name: str
|
||||
) -> list[list[float]]:
|
||||
"""Validate that *matrix* is a rectangular list of lists of numeric values.
|
||||
|
||||
Returns the matrix converted to ``list[list[float]]`` if valid.
|
||||
Raises ``TypeError`` for non‑numeric values or if any element is a ``bool``.
|
||||
Raises ``ValueError`` for empty matrices, empty rows, or ragged matrices.
|
||||
"""
|
||||
try:
|
||||
rows = list(map(list, matrix))
|
||||
except TypeError as exc:
|
||||
raise TypeError(f"{name} must be a sequence of sequences") from exc
|
||||
|
||||
if not rows:
|
||||
raise ValueError(f"{name} must not be empty")
|
||||
|
||||
if not rows[0]:
|
||||
raise ValueError(f"{name} must not contain empty rows")
|
||||
|
||||
row_len = len(rows[0])
|
||||
for row in rows:
|
||||
if len(row) != row_len:
|
||||
raise ValueError(f"{name} must be rectangular (row lengths differ)")
|
||||
for value in row:
|
||||
if isinstance(value, bool):
|
||||
raise TypeError(f"{name} contains boolean value {value!r}")
|
||||
if not isinstance(value, _NUMERIC_TYPES):
|
||||
raise TypeError(f"{name} contains non‑numeric value {value!r}")
|
||||
return [[float(value) for value in row] for row in rows]
|
||||
|
||||
|
||||
def matmul(a: list[list[float]], b: list[list[float]]) -> list[list[float]]:
|
||||
"""Multiply two matrices ``a`` and ``b``.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
a: list[list[float]]
|
||||
Left operand matrix.
|
||||
b: list[list[float]]
|
||||
Right operand matrix.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list[list[float]]
|
||||
The product matrix.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If matrix dimensions are incompatible or if a matrix is ragged.
|
||||
TypeError
|
||||
If inputs are not sequences of numeric values.
|
||||
"""
|
||||
a_matrix = _validate_matrix(a, "a")
|
||||
b_matrix = _validate_matrix(b, "b")
|
||||
|
||||
num_rows_a = len(a_matrix)
|
||||
num_cols_a = len(a_matrix[0])
|
||||
num_rows_b = len(b_matrix)
|
||||
num_cols_b = len(b_matrix[0])
|
||||
|
||||
if num_cols_a != num_rows_b:
|
||||
raise ValueError(
|
||||
f"Incompatible dimensions: a has {num_cols_a} columns; "
|
||||
f"b has {num_rows_b} rows"
|
||||
)
|
||||
|
||||
result: list[list[float]] = [
|
||||
[0.0 for _ in range(num_cols_b)] for _ in range(num_rows_a)
|
||||
]
|
||||
|
||||
for i in range(num_rows_a):
|
||||
for j in range(num_cols_b):
|
||||
dot_product = 0.0
|
||||
for k in range(num_cols_a):
|
||||
dot_product += a_matrix[i][k] * b_matrix[k][j]
|
||||
result[i][j] = dot_product
|
||||
return result
|
||||
|
||||
|
||||
def transpose(matrix: list[list[float]]) -> list[list[float]]:
|
||||
"""Return the transpose of *matrix*.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
matrix: list[list[float]]
|
||||
Input matrix as a list of rows.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list[list[float]]
|
||||
Transposed matrix.
|
||||
|
||||
Raises
|
||||
------
|
||||
TypeError, ValueError
|
||||
Propagated from :func:`_validate_matrix` when the input is not a
|
||||
rectangular numeric matrix.
|
||||
"""
|
||||
m_matrix = _validate_matrix(matrix, "matrix")
|
||||
rows, cols = len(m_matrix), len(m_matrix[0])
|
||||
return [[m_matrix[i][j] for i in range(rows)] for j in range(cols)]
|
||||
|
||||
|
||||
def rotate(matrix: list[list[float]]) -> list[list[float]]:
|
||||
"""Return the matrix rotated 90° clockwise.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
matrix: list[list[float]]
|
||||
Input matrix as a list of rows.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list[list[float]]
|
||||
Rotated matrix.
|
||||
|
||||
Raises
|
||||
------
|
||||
TypeError, ValueError
|
||||
Propagated from :func:`_validate_matrix` when the input is not a
|
||||
rectangular numeric matrix.
|
||||
"""
|
||||
m_matrix = _validate_matrix(matrix, "matrix")
|
||||
return [list(row) for row in zip(*reversed(m_matrix))]
|
||||
|
||||
|
||||
def rot_2d(angle: float, unit: Literal["deg", "rad"] = "deg") -> list[list[float]]:
|
||||
"""Return a 2×2 rotation matrix for a given angle.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
angle : float
|
||||
Rotation angle.
|
||||
unit : {"deg", "rad"}, default "deg"
|
||||
Whether *angle* is given in degrees or radians.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list[list[float]]
|
||||
2×2 rotation matrix.
|
||||
"""
|
||||
theta = math.radians(angle) if unit == "deg" else angle
|
||||
c = math.cos(theta)
|
||||
s = math.sin(theta)
|
||||
return [[c, -s], [s, c]]
|
||||
|
||||
|
||||
def print_matrix(title: str, matrix: list[list[float]]) -> None:
|
||||
"""Print a title followed by each matrix row on its own line."""
|
||||
print(title)
|
||||
for row in matrix:
|
||||
print(" ", row)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Matrix multiplication tests
|
||||
a1 = [[1, 2, 3], [4, 5, 6]]
|
||||
b1 = [[7, 8], [9, 10], [11, 12]]
|
||||
print_matrix("Matrix A:", a1)
|
||||
print_matrix("Matrix B:", b1)
|
||||
product = matmul(a1, b1)
|
||||
print_matrix("A x B:", product)
|
||||
assert product == [[58, 64], [139, 154]], "matmul first test failed"
|
||||
print()
|
||||
|
||||
a2 = [[1, 2], [3, 4]]
|
||||
b2 = [[5, 6], [7, 8]]
|
||||
print_matrix("Matrix A:", a2)
|
||||
print_matrix("Matrix B:", b2)
|
||||
product = matmul(a2, b2)
|
||||
print_matrix("A x B:", product)
|
||||
assert product == [[19, 22], [43, 50]], "matmul second test failed"
|
||||
print()
|
||||
|
||||
identity = [[1, 0], [0, 1]]
|
||||
print_matrix("Matrix A:", a2)
|
||||
print_matrix("Identity matrix:", identity)
|
||||
product = matmul(a2, identity)
|
||||
print_matrix("A x Identity:", product)
|
||||
assert product == a2, "matmul identity test failed"
|
||||
print()
|
||||
|
||||
# Dimension mismatch must raise ValueError
|
||||
try:
|
||||
matmul([[1, 2]], [[1, 2]])
|
||||
except ValueError as error:
|
||||
print(f"Expected error for mismatched dimensions: {error}")
|
||||
else:
|
||||
raise AssertionError("matmul did not raise ValueError")
|
||||
print()
|
||||
|
||||
# Transpose tests
|
||||
print_matrix("Matrix:", a1)
|
||||
transposed = transpose(a1)
|
||||
print_matrix("Transposed:", transposed)
|
||||
assert transposed == [[1, 4], [2, 5], [3, 6]], "transpose first test failed"
|
||||
assert transpose(transposed) == a1, "double transpose failed"
|
||||
print()
|
||||
|
||||
column = [[1], [2], [3]]
|
||||
print_matrix("Matrix:", column)
|
||||
transposed = transpose(column)
|
||||
print_matrix("Transposed:", transposed)
|
||||
assert transposed == [[1, 2, 3]], "transpose column test failed"
|
||||
print()
|
||||
|
||||
# Rotation tests
|
||||
print_matrix("Matrix:", a1)
|
||||
rotated = rotate(a1)
|
||||
print_matrix("Rotated 90 degrees clockwise:", rotated)
|
||||
assert rotated == [[4, 1], [5, 2], [6, 3]], "rotate 2x3 test failed"
|
||||
print()
|
||||
|
||||
square = [[1, 2], [3, 4]]
|
||||
print_matrix("Matrix:", square)
|
||||
rotated = rotate(square)
|
||||
print_matrix("Rotated 90 degrees clockwise:", rotated)
|
||||
assert rotated == [[3, 1], [4, 2]], "rotate square test failed"
|
||||
print()
|
||||
|
||||
# Four rotations must return the original matrix
|
||||
rotated = square
|
||||
for _ in range(4):
|
||||
rotated = rotate(rotated)
|
||||
print_matrix("Square matrix rotated four times:", rotated)
|
||||
assert rotated == square, "four rotations did not return original"
|
||||
print()
|
||||
|
||||
# 2D rotation matrix tests
|
||||
rotation_0 = rot_2d(0)
|
||||
print_matrix("Rotation matrix for 0 degrees:", rotation_0)
|
||||
assert rotation_0 == [[1.0, -0.0], [0.0, 1.0]], "rot_2d 0 degrees failed"
|
||||
print()
|
||||
|
||||
rotation_90 = rot_2d(90)
|
||||
print_matrix("Rotation matrix for 90 degrees:", rotation_90)
|
||||
point = [[1], [0]]
|
||||
rotated_point = matmul(rotation_90, point)
|
||||
print_matrix("Point (1, 0) rotated by 90 degrees:", rotated_point)
|
||||
assert math.isclose(rotated_point[0][0], 0.0, abs_tol=1e-9), "rot_2d x failed"
|
||||
assert math.isclose(rotated_point[1][0], 1.0, abs_tol=1e-9), "rot_2d y failed"
|
||||
print()
|
||||
|
||||
print("All tests passed.")
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[project]
|
||||
name = "matrixmania"
|
||||
version = "0.1.0"
|
||||
Reference in new issue
Block a user