"""Tests for DOF counting.""" import pytest from kindred_solver.dof import count_dof from kindred_solver.expr import Const, Var from kindred_solver.params import ParamTable class TestDOF: def test_unconstrained(self): """2 free params, no residuals → DOF = 2.""" pt = ParamTable() pt.add("x", 0.0) pt.add("y", 0.0) assert count_dof([], pt) == 2 def test_fully_constrained(self): """1 free param, 1 independent residual → DOF = 0.""" pt = ParamTable() x = pt.add("x", 1.0) residuals = [x - Const(3.0)] assert count_dof(residuals, pt) == 0 def test_under_constrained(self): """2 free params, 1 residual → DOF = 1.""" pt = ParamTable() x = pt.add("x", 1.0) y = pt.add("y", 1.0) residuals = [x + y - Const(5.0)] assert count_dof(residuals, pt) == 1 def test_redundant_constraints(self): """2 free params, 3 residuals (2 independent) → DOF = 0.""" pt = ParamTable() x = pt.add("x", 1.0) y = pt.add("y", 1.0) residuals = [ x - Const(3.0), y - Const(4.0), x + y - Const(7.0), # redundant (sum of first two) ] assert count_dof(residuals, pt) == 0 def test_no_free_params(self): """All fixed → DOF = 0.""" pt = ParamTable() pt.add("x", 1.0, fixed=True) residuals = [Const(0.0)] assert count_dof(residuals, pt) == 0