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]])