mcp-calculator/tests/test_linalg.py
2026-09-15 20:38:16 +02:00

74 lines
3 KiB
Python

from mcp_calculator.config import Limits
from mcp_calculator.ops.context import MathError, set_limits
from mcp_calculator.ops.linalg import matrix
from tests.support import MathTestCase
A = [[1, 2], [3, 4]]
class ExactMatrixTest(MathTestCase):
def test_determinant(self):
self.assertEqual(matrix("determinant", A)["result"], "-2")
def test_symbolic_determinant(self):
self.assertEqual(matrix("determinant", [["a", "b"], ["c", "d"]])["result"], "a*d - b*c")
def test_inverse_is_exact(self):
self.assertEqual(matrix("inverse", A)["result"], [["-2", "1"], ["3/2", "-1/2"]])
def test_singular_inverse(self):
with self.assertRaisesRegex(MathError, "singular"):
matrix("inverse", [[1, 2], [2, 4]])
def test_eigenvalues(self):
values = {e["value"] for e in matrix("eigenvalues", [[2, 1], [1, 2]])["result"]}
self.assertEqual(values, {"1", "3"})
def test_eigenvectors(self):
r = matrix("eigenvectors", [[2, 0], [0, 3]])["result"]
self.assertEqual({e["value"]: e["vectors"] for e in r}, {"2": [["1", "0"]], "3": [["0", "1"]]})
def test_solve_linear_system(self):
self.assertEqual(matrix("solve", [[1, 1], [1, -1]], [10, 2])["result"], [["6"], ["4"]])
def test_solve_inconsistent(self):
self.assertIsNone(matrix("solve", [[1, 1], [1, 1]], [1, 2])["result"])
def test_multiply_and_shapes(self):
self.assertEqual(matrix("multiply", A, [[1], [1]])["result"], [["3"], ["7"]])
with self.assertRaisesRegex(MathError, "not compatible"):
matrix("multiply", A, [[1, 2, 3]])
def test_power_rank_trace_transpose(self):
self.assertEqual(matrix("power", A, exponent=2)["result"], [["7", "10"], ["15", "22"]])
self.assertEqual(matrix("rank", [[1, 2], [2, 4]])["result"], 1)
self.assertEqual(matrix("trace", A)["result"], "5")
self.assertEqual(matrix("transpose", A)["result"], [["1", "3"], ["2", "4"]])
def test_vectors(self):
self.assertEqual(matrix("dot", [1, 2, 3], [4, 5, 6])["result"], "32")
self.assertEqual(matrix("cross", [1, 0, 0], [0, 1, 0])["result"], [["0"], ["0"], ["1"]])
def test_characteristic_polynomial(self):
self.assertEqual(matrix("characteristic_polynomial", A)["result"], "lambda**2 - 5*lambda - 2")
class NumericMatrixTest(MathTestCase):
def test_numeric_mode(self):
r = matrix("determinant", A, numeric_mode=True)
self.assertTrue(r["mode"].startswith("numeric"))
self.assertApprox(r["result"], -2)
def test_svd_is_numeric(self):
self.assertEqual(len(matrix("svd", A)["singular_values"]), 2)
class MatrixValidationTest(MathTestCase):
def test_size_limit(self):
set_limits(Limits(max_matrix_size=2))
with self.assertRaisesRegex(MathError, "larger than"):
matrix("determinant", [[1, 2, 3], [4, 5, 6], [7, 8, 9]])
def test_ragged_rows(self):
with self.assertRaisesRegex(MathError, "same length"):
matrix("determinant", [[1, 2], [3]])