From de176746115e8686d745575a1c959eaa3069bb20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kowalczyk?= Date: Tue, 31 Mar 2026 22:52:18 +0200 Subject: [PATCH 1/4] implemented gaussian elimination without pivoting and added test function --- matrix_calculus/matrix_processor.py | 29 +++++++++++++++++++++++++++++ tests/gaussian_elimination_test.py | 22 ++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 matrix_calculus/matrix_processor.py create mode 100644 tests/gaussian_elimination_test.py diff --git a/matrix_calculus/matrix_processor.py b/matrix_calculus/matrix_processor.py new file mode 100644 index 0000000..d759d23 --- /dev/null +++ b/matrix_calculus/matrix_processor.py @@ -0,0 +1,29 @@ +from __future__ import annotations + + +class MatrixProcessor: + @staticmethod + def gaussian_elimination( + matrix: list[list[float]], + enable_pivoting: bool = False, + ) -> list[list[float]]: + M = [row[:] for row in matrix] + + n = len(M) + + for diagonal_element in range(n): + + diagonal_element_value = M[diagonal_element][diagonal_element] + + if diagonal_element_value == 0: + raise ValueError("Either matrix is singular or pivoting is required!") + + for col in range(diagonal_element, n): + M[diagonal_element][col] /= diagonal_element_value + + for row in range(diagonal_element + 1, n): + factor = M[row][diagonal_element] + for col in range(diagonal_element, n): + M[row][col] -= factor * M[diagonal_element][col] + + return M diff --git a/tests/gaussian_elimination_test.py b/tests/gaussian_elimination_test.py new file mode 100644 index 0000000..d226664 --- /dev/null +++ b/tests/gaussian_elimination_test.py @@ -0,0 +1,22 @@ +from __future__ import annotations + +import pytest # noqa: F401 + +from matrix_calculus.matrix_processor import MatrixProcessor + + +def test_gaussian_elimination(): + # Test 1x1 matrix + matrix = [[2]] + res = MatrixProcessor.gaussian_elimination(matrix) + assert res == [[1.0]] + + # Test 2x2 matrix + matrix = [[2, 4], [1, 3]] + res = MatrixProcessor.gaussian_elimination(matrix) + assert res == [[1.0, 2.0], [0.0, 1.0]] + + # Test 3x3 singular matrix + with pytest.raises(ValueError): + matrix = [[2, 4, 6], [1, 3, 5], [0, 2, 4]] + MatrixProcessor.gaussian_elimination(matrix) From dfe7fec0d1891ccaf533bc8108274e737d7343e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kowalczyk?= Date: Tue, 31 Mar 2026 23:26:35 +0200 Subject: [PATCH 2/4] fixed gaussian elimination - added row swap when no other option --- matrix_calculus/matrix_processor.py | 17 ++++++++++++++--- tests/gaussian_elimination_test.py | 5 +++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/matrix_calculus/matrix_processor.py b/matrix_calculus/matrix_processor.py index d759d23..9f96fc7 100644 --- a/matrix_calculus/matrix_processor.py +++ b/matrix_calculus/matrix_processor.py @@ -8,15 +8,26 @@ def gaussian_elimination( enable_pivoting: bool = False, ) -> list[list[float]]: M = [row[:] for row in matrix] - n = len(M) + eps = 1e-12 + + def swap_rows(row1, row2): + for col in range(n): + M[row1][col], M[row2][col] = M[row2][col], M[row1][col] for diagonal_element in range(n): diagonal_element_value = M[diagonal_element][diagonal_element] - if diagonal_element_value == 0: - raise ValueError("Either matrix is singular or pivoting is required!") + if abs(diagonal_element_value) < eps: + for row in range(diagonal_element + 1, n): + if abs(M[row][diagonal_element]) > eps: + diagonal_element_value = M[row][diagonal_element] + + swap_rows(diagonal_element, row) + + if abs(diagonal_element_value) < eps: + raise ValueError("Matrix is singular") for col in range(diagonal_element, n): M[diagonal_element][col] /= diagonal_element_value diff --git a/tests/gaussian_elimination_test.py b/tests/gaussian_elimination_test.py index d226664..673b1e4 100644 --- a/tests/gaussian_elimination_test.py +++ b/tests/gaussian_elimination_test.py @@ -20,3 +20,8 @@ def test_gaussian_elimination(): with pytest.raises(ValueError): matrix = [[2, 4, 6], [1, 3, 5], [0, 2, 4]] MatrixProcessor.gaussian_elimination(matrix) + + # Test 3x3 matrix + matrix = [[2, 4, 6], [1, 2, 5], [0, 2, 4]] + res = MatrixProcessor.gaussian_elimination(matrix) + assert res == [[1.0, 2.0, 3.0], [0.0, 1.0, 2.0], [0.0, 0.0, 1.0]] \ No newline at end of file From 9dafc8977df929e004032c586a2885f225a38f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kowalczyk?= Date: Tue, 31 Mar 2026 23:49:58 +0200 Subject: [PATCH 3/4] implemented gaussian elimination with pivoting --- matrix_calculus/matrix_processor.py | 38 ++++++++++++++++++++++++++--- tests/gaussian_elimination_test.py | 23 ++++++++++++++++- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/matrix_calculus/matrix_processor.py b/matrix_calculus/matrix_processor.py index 9f96fc7..8e57096 100644 --- a/matrix_calculus/matrix_processor.py +++ b/matrix_calculus/matrix_processor.py @@ -3,10 +3,7 @@ class MatrixProcessor: @staticmethod - def gaussian_elimination( - matrix: list[list[float]], - enable_pivoting: bool = False, - ) -> list[list[float]]: + def gaussian_elimination(matrix: list[list[float]]) -> list[list[float]]: M = [row[:] for row in matrix] n = len(M) eps = 1e-12 @@ -38,3 +35,36 @@ def swap_rows(row1, row2): M[row][col] -= factor * M[diagonal_element][col] return M + + @staticmethod + def gaussian_elimination_pivoting(matrix: list[list[float]]) -> list[list[float]]: + M = [row[:] for row in matrix] + n = len(M) + eps = 1e-12 + + def swap_rows(row1, row2): + for col in range(n): + M[row1][col], M[row2][col] = M[row2][col], M[row1][col] + + for diagonal_element in range(n): + + max_pivot_value = abs(M[diagonal_element][diagonal_element]) + highest_pivot_row = diagonal_element + for row in range(diagonal_element + 1, n): + if abs(M[row][diagonal_element]) > max_pivot_value: + max_pivot_value = abs(M[row][diagonal_element]) + highest_pivot_row = row + + if highest_pivot_row != diagonal_element: + swap_rows(diagonal_element, highest_pivot_row) + + pivot_value = M[diagonal_element][diagonal_element] + if abs(pivot_value) < eps: + raise ValueError("Matrix is singular") + + for row in range(diagonal_element + 1, n): + factor = M[row][diagonal_element] / pivot_value + for col in range(diagonal_element, n): + M[row][col] -= factor * M[diagonal_element][col] + + return M diff --git a/tests/gaussian_elimination_test.py b/tests/gaussian_elimination_test.py index 673b1e4..bc59bd9 100644 --- a/tests/gaussian_elimination_test.py +++ b/tests/gaussian_elimination_test.py @@ -24,4 +24,25 @@ def test_gaussian_elimination(): # Test 3x3 matrix matrix = [[2, 4, 6], [1, 2, 5], [0, 2, 4]] res = MatrixProcessor.gaussian_elimination(matrix) - assert res == [[1.0, 2.0, 3.0], [0.0, 1.0, 2.0], [0.0, 0.0, 1.0]] \ No newline at end of file + assert res == [[1.0, 2.0, 3.0], [0.0, 1.0, 2.0], [0.0, 0.0, 1.0]] + +def test_gaussian_elimination_pivoting(): + # Test 1x1 matrix + matrix = [[2]] + res = MatrixProcessor.gaussian_elimination_pivoting(matrix) + assert res == [[2.0]] + + # Test 2x2 matrix + matrix = [[2, 4], [1, 3]] + res = MatrixProcessor.gaussian_elimination_pivoting(matrix) + assert res == [[2.0, 4.0], [0.0, 1.0]] + + # Test 3x3 singular matrix + with pytest.raises(ValueError): + matrix = [[2, 4, 6], [1, 3, 5], [0, 2, 4]] + MatrixProcessor.gaussian_elimination_pivoting(matrix) + + # Test 3x3 matrix + matrix = [[2, 4, 6], [1, 2, 5], [0, 2, 4]] + res = MatrixProcessor.gaussian_elimination_pivoting(matrix) + assert res == [[2, 4, 6], [0, 2, 4], [0, 0, 2]] \ No newline at end of file From 799d3085e138b26faf13971caf27156715c3ff90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kowalczyk?= Date: Thu, 16 Apr 2026 18:58:55 +0200 Subject: [PATCH 4/4] fixed git hooks errors --- matrix_calculus/matrix_processor.py | 8 +-- tests/gaussian_elimination_test.py | 97 +++++++++++++++-------------- 2 files changed, 53 insertions(+), 52 deletions(-) diff --git a/matrix_calculus/matrix_processor.py b/matrix_calculus/matrix_processor.py index 8e57096..b3f9652 100644 --- a/matrix_calculus/matrix_processor.py +++ b/matrix_calculus/matrix_processor.py @@ -22,7 +22,7 @@ def swap_rows(row1, row2): diagonal_element_value = M[row][diagonal_element] swap_rows(diagonal_element, row) - + if abs(diagonal_element_value) < eps: raise ValueError("Matrix is singular") @@ -35,7 +35,7 @@ def swap_rows(row1, row2): M[row][col] -= factor * M[diagonal_element][col] return M - + @staticmethod def gaussian_elimination_pivoting(matrix: list[list[float]]) -> list[list[float]]: M = [row[:] for row in matrix] @@ -47,14 +47,14 @@ def swap_rows(row1, row2): M[row1][col], M[row2][col] = M[row2][col], M[row1][col] for diagonal_element in range(n): - + max_pivot_value = abs(M[diagonal_element][diagonal_element]) highest_pivot_row = diagonal_element for row in range(diagonal_element + 1, n): if abs(M[row][diagonal_element]) > max_pivot_value: max_pivot_value = abs(M[row][diagonal_element]) highest_pivot_row = row - + if highest_pivot_row != diagonal_element: swap_rows(diagonal_element, highest_pivot_row) diff --git a/tests/gaussian_elimination_test.py b/tests/gaussian_elimination_test.py index bc59bd9..c78e090 100644 --- a/tests/gaussian_elimination_test.py +++ b/tests/gaussian_elimination_test.py @@ -1,48 +1,49 @@ -from __future__ import annotations - -import pytest # noqa: F401 - -from matrix_calculus.matrix_processor import MatrixProcessor - - -def test_gaussian_elimination(): - # Test 1x1 matrix - matrix = [[2]] - res = MatrixProcessor.gaussian_elimination(matrix) - assert res == [[1.0]] - - # Test 2x2 matrix - matrix = [[2, 4], [1, 3]] - res = MatrixProcessor.gaussian_elimination(matrix) - assert res == [[1.0, 2.0], [0.0, 1.0]] - - # Test 3x3 singular matrix - with pytest.raises(ValueError): - matrix = [[2, 4, 6], [1, 3, 5], [0, 2, 4]] - MatrixProcessor.gaussian_elimination(matrix) - - # Test 3x3 matrix - matrix = [[2, 4, 6], [1, 2, 5], [0, 2, 4]] - res = MatrixProcessor.gaussian_elimination(matrix) - assert res == [[1.0, 2.0, 3.0], [0.0, 1.0, 2.0], [0.0, 0.0, 1.0]] - -def test_gaussian_elimination_pivoting(): - # Test 1x1 matrix - matrix = [[2]] - res = MatrixProcessor.gaussian_elimination_pivoting(matrix) - assert res == [[2.0]] - - # Test 2x2 matrix - matrix = [[2, 4], [1, 3]] - res = MatrixProcessor.gaussian_elimination_pivoting(matrix) - assert res == [[2.0, 4.0], [0.0, 1.0]] - - # Test 3x3 singular matrix - with pytest.raises(ValueError): - matrix = [[2, 4, 6], [1, 3, 5], [0, 2, 4]] - MatrixProcessor.gaussian_elimination_pivoting(matrix) - - # Test 3x3 matrix - matrix = [[2, 4, 6], [1, 2, 5], [0, 2, 4]] - res = MatrixProcessor.gaussian_elimination_pivoting(matrix) - assert res == [[2, 4, 6], [0, 2, 4], [0, 0, 2]] \ No newline at end of file +from __future__ import annotations + +import pytest # noqa: F401 + +from matrix_calculus.matrix_processor import MatrixProcessor + + +def test_gaussian_elimination(): + # Test 1x1 matrix + matrix = [[2]] + res = MatrixProcessor.gaussian_elimination(matrix) + assert res == [[1.0]] + + # Test 2x2 matrix + matrix = [[2, 4], [1, 3]] + res = MatrixProcessor.gaussian_elimination(matrix) + assert res == [[1.0, 2.0], [0.0, 1.0]] + + # Test 3x3 singular matrix + with pytest.raises(ValueError): + matrix = [[2, 4, 6], [1, 3, 5], [0, 2, 4]] + MatrixProcessor.gaussian_elimination(matrix) + + # Test 3x3 matrix + matrix = [[2, 4, 6], [1, 2, 5], [0, 2, 4]] + res = MatrixProcessor.gaussian_elimination(matrix) + assert res == [[1.0, 2.0, 3.0], [0.0, 1.0, 2.0], [0.0, 0.0, 1.0]] + + +def test_gaussian_elimination_pivoting(): + # Test 1x1 matrix + matrix = [[2]] + res = MatrixProcessor.gaussian_elimination_pivoting(matrix) + assert res == [[2.0]] + + # Test 2x2 matrix + matrix = [[2, 4], [1, 3]] + res = MatrixProcessor.gaussian_elimination_pivoting(matrix) + assert res == [[2.0, 4.0], [0.0, 1.0]] + + # Test 3x3 singular matrix + with pytest.raises(ValueError): + matrix = [[2, 4, 6], [1, 3, 5], [0, 2, 4]] + MatrixProcessor.gaussian_elimination_pivoting(matrix) + + # Test 3x3 matrix + matrix = [[2, 4, 6], [1, 2, 5], [0, 2, 4]] + res = MatrixProcessor.gaussian_elimination_pivoting(matrix) + assert res == [[2, 4, 6], [0, 2, 4], [0, 0, 2]]