diff --git a/README.md b/README.md new file mode 100644 index 0000000..a5a03ef --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# MatrixMania + +Dies ist eine Übungsbibliothek für Programmieren III. +Enthält Funktionen für Matrix-Operationen und 3D-Rotationen. \ No newline at end of file diff --git a/matrixmania/__init__.py b/matrixmania/__init__.py new file mode 100644 index 0000000..c812c86 --- /dev/null +++ b/matrixmania/__init__.py @@ -0,0 +1 @@ +from .compute import matmul, transpose, rot_2D, rot_3D \ No newline at end of file diff --git a/compute.py b/matrixmania/compute.py similarity index 68% rename from compute.py rename to matrixmania/compute.py index 59fc2d8..2297a31 100644 --- a/compute.py +++ b/matrixmania/compute.py @@ -1,4 +1,5 @@ -# hab ich alles selbst programmiert +# created by ChatGPT + from typing import List import math from tabulate import tabulate @@ -44,6 +45,38 @@ def rot_2D(angle_degrees: float) -> Matrix: ] return rotation_matrix + +def rot_3D(angle_degrees: float, axis: str) -> Matrix: + """ + Erzeugt eine 3x3 Rotationsmatrix für die angegebene Achse. + """ + rad = math.radians(angle_degrees) + cos_a = math.cos(rad) + sin_a = math.sin(rad) + + axis = axis.lower() + + if axis == "x": + return [ + [1.0, 0.0, 0.0], + [0.0, cos_a, -sin_a], + [0.0, sin_a, cos_a] + ] + elif axis == "y": + return [ + [cos_a, 0.0, sin_a], + [0.0, 1.0, 0.0], + [-sin_a, 0.0, cos_a] + ] + elif axis == "z": + return [ + [cos_a, -sin_a, 0.0], + [sin_a, cos_a, 0.0], + [0.0, 0.0, 1.0] + ] + else: + raise ValueError("Achse muss x, y oder z sein.") + if __name__ == "__main__": matrix = [[1,2,3], [2,3,4]] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..c683244 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,15 @@ +[project] +name = "MatrixMania_dimartinoma102424" +version = "0.2.0" +description = "MatrixMania Library for Prog3" +authors = [{ name="Marco", email="dimartinoma102424@th-nuernberg.de" }] +readme = "README.md" +requires-python = ">=3.12" +dependencies = ["tabulate"] + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["matrixmania"] \ No newline at end of file diff --git a/test/test_matmul.py b/test/test_matmul.py new file mode 100644 index 0000000..81ca0c6 --- /dev/null +++ b/test/test_matmul.py @@ -0,0 +1,39 @@ +import pytest +from matrixmania.compute import matmul, transpose + +# --- Tests für Transponieren --- +def test_transpose_regular(): + # Testet eine normale 2x3 Matrix + matrix = [ + [1, 2, 3], + [4, 5, 6] + ] + expected = [ + [1, 4], + [2, 5], + [3, 6] + ] + assert transpose(matrix) == expected + +def test_transpose_empty(): + # Testet, ob der ValueError bei leerer Matrix kommt + with pytest.raises(ValueError): + transpose([]) + +# --- Tests für Matrixmultiplikation (matmul) --- +def test_matmul_simple(): + # Einfache Multiplikation 2x2 * 2x1 + A = [[1, 2], [3, 4]] + B = [[5], [6]] + # Rechnung: + # 1*5 + 2*6 = 5 + 12 = 17 + # 3*5 + 4*6 = 15 + 24 = 39 + expected = [[17], [39]] + assert matmul(A, B) == expected + +def test_matmul_invalid_dimensions(): + # Testet, ob Fehler geworfen wird, wenn Dimensionen nicht passen + A = [[1, 2]] # 1x2 + B = [[1, 2]] # 1x2 -> Spalten A (2) != Zeilen B (1) + with pytest.raises(ValueError): + matmul(A, B) \ No newline at end of file diff --git a/test/test_rot.py b/test/test_rot.py new file mode 100644 index 0000000..ffb728f --- /dev/null +++ b/test/test_rot.py @@ -0,0 +1,48 @@ +import pytest +from matrixmania.compute import rot_2D, rot_3D + + +# --- Tests für Rotationen (2D & 3D) --- +def test_rot_2D(): + # 90 Grad Rotation in 2D: (1, 0) -> (0, 1) + # Matrix sollte [[0, -1], [1, 0]] sein (cos(90)=0, sin(90)=1) + result = rot_2D(90) + + # Wir nutzen pytest.approx für Float-Vergleiche, da 0.00000000001 != 0 ist + assert result[0][0] == pytest.approx(0.0) # cos + assert result[0][1] == pytest.approx(-1.0) # -sin + assert result[1][0] == pytest.approx(1.0) # sin + assert result[1][1] == pytest.approx(0.0) # cos + + +def test_rot_3D_x_axis(): + # 90 Grad um X-Achse + # Erwartet: + # 1 0 0 + # 0 0 -1 + # 0 1 0 + result = rot_3D(90, 'x') + + assert result[0] == [1.0, 0.0, 0.0] # X-Achse bleibt stabil + assert result[1][1] == pytest.approx(0.0) + assert result[1][2] == pytest.approx(-1.0) + assert result[2][1] == pytest.approx(1.0) + + +def test_rot_3D_z_axis(): + # 180 Grad um Z-Achse + # Erwartet: + # -1 0 0 + # 0 -1 0 + # 0 0 1 + result = rot_3D(180, 'z') + + assert result[0][0] == pytest.approx(-1.0) + assert result[1][1] == pytest.approx(-1.0) + assert result[2][2] == pytest.approx(1.0) + + +def test_rot_3D_invalid_input(): + # Testet, ob Fehler geworfen wird bei falscher Achse + with pytest.raises(ValueError): + rot_3D(90, 'q') # 'q' gibt es nicht \ No newline at end of file