import numpy as np
import pytest
import scirs2
class TestPolyfitBasics:
def test_linear_fit(self):
x = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
y = np.array([2.0, 4.0, 6.0, 8.0, 10.0])
result = scirs2.polyfit_py(x, y, deg=1)
assert "coefficients" in result
assert "r_squared" in result
assert len(result["coefficients"]) == 2
assert abs(result["coefficients"][0] - 0.0) < 0.01 assert abs(result["coefficients"][1] - 2.0) < 0.01
assert result["r_squared"] > 0.99
def test_quadratic_fit(self):
x = np.array([0.0, 1.0, 2.0, 3.0, 4.0])
y = np.array([1.0, 3.0, 9.0, 19.0, 33.0])
result = scirs2.polyfit_py(x, y, deg=2)
assert len(result["coefficients"]) == 3
assert abs(result["coefficients"][0] - 1.0) < 0.01 assert abs(result["coefficients"][1] - 2.0) < 0.01 assert abs(result["coefficients"][2] - 1.0) < 0.01
assert result["r_squared"] > 0.99
def test_cubic_fit(self):
x = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0])
y = np.array([0.0, 1.0, 8.0, 27.0, 64.0, 125.0])
result = scirs2.polyfit_py(x, y, deg=3)
assert len(result["coefficients"]) == 4
assert abs(result["coefficients"][3] - 1.0) < 0.01
assert result["r_squared"] > 0.99
def test_constant_fit(self):
x = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
y = np.array([5.0, 5.0, 5.0, 5.0, 5.0])
result = scirs2.polyfit_py(x, y, deg=0)
assert len(result["coefficients"]) == 1
assert abs(result["coefficients"][0] - 5.0) < 0.01
class TestPolyfitOutputs:
def test_output_fields(self):
x = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
y = np.array([2.0, 4.0, 6.0, 8.0, 10.0])
result = scirs2.polyfit_py(x, y, deg=1)
required_fields = [
"coefficients",
"r_squared",
"adj_r_squared",
"residuals",
"fitted_values",
]
for field in required_fields:
assert field in result, f"Missing field: {field}"
def test_residuals(self):
x = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
y = np.array([2.1, 3.9, 6.1, 7.9, 10.1])
result = scirs2.polyfit_py(x, y, deg=1)
residuals = result["residuals"]
fitted_values = result["fitted_values"]
assert len(residuals) == len(y)
for i in range(len(y)):
expected_residual = y[i] - fitted_values[i]
assert abs(residuals[i] - expected_residual) < 0.01
def test_fitted_values(self):
x = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
y = np.array([2.0, 4.0, 6.0, 8.0, 10.0])
result = scirs2.polyfit_py(x, y, deg=1)
fitted_values = result["fitted_values"]
coefficients = result["coefficients"]
for i, xi in enumerate(x):
expected = coefficients[0] + coefficients[1] * xi
assert abs(fitted_values[i] - expected) < 0.01
def test_adjusted_r_squared(self):
x = np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
y = np.array([2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0])
result = scirs2.polyfit_py(x, y, deg=1)
assert "adj_r_squared" in result
assert result["adj_r_squared"] <= result["r_squared"]
assert result["adj_r_squared"] > 0.99
class TestPolyfitEdgeCases:
def test_perfect_fit(self):
x = np.array([0.0, 1.0, 2.0, 3.0])
y = 1.0 + 2.0 * x + 3.0 * x**2
result = scirs2.polyfit_py(x, y, deg=2)
assert result["r_squared"] > 0.9999
assert abs(result["coefficients"][0] - 1.0) < 0.0001
assert abs(result["coefficients"][1] - 2.0) < 0.0001
assert abs(result["coefficients"][2] - 3.0) < 0.0001
def test_noisy_data(self):
np.random.seed(42)
x = np.linspace(0, 10, 50)
y = 2.0 + 3.0 * x + 0.5 * x**2 + np.random.normal(0, 2.0, len(x))
result = scirs2.polyfit_py(x, y, deg=2)
assert result["r_squared"] > 0.8
assert abs(result["coefficients"][0] - 2.0) < 2.0
assert abs(result["coefficients"][1] - 3.0) < 2.0
assert abs(result["coefficients"][2] - 0.5) < 1.0
def test_minimum_data_points(self):
x = np.array([1.0, 2.0, 3.0])
y = np.array([1.0, 4.0, 9.0])
result = scirs2.polyfit_py(x, y, deg=2)
assert len(result["coefficients"]) == 3
assert result["r_squared"] >= 0.0
def test_large_degree(self):
x = np.linspace(0, 10, 20)
y = np.sin(x)
result = scirs2.polyfit_py(x, y, deg=10)
assert len(result["coefficients"]) == 11
assert result["r_squared"] >= 0.0
def test_negative_values(self):
x = np.array([-3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0])
y = x**2
result = scirs2.polyfit_py(x, y, deg=2)
assert abs(result["coefficients"][0]) < 0.01 assert abs(result["coefficients"][1]) < 0.01 assert abs(result["coefficients"][2] - 1.0) < 0.01
class TestPolyfitNumericalProperties:
def test_large_values(self):
x = np.array([100.0, 200.0, 300.0, 400.0, 500.0])
y = 2.0 * x + 100.0
result = scirs2.polyfit_py(x, y, deg=1)
assert result["r_squared"] > 0.99
assert abs(result["coefficients"][1] - 2.0) < 0.1
def test_small_values(self):
x = np.array([0.001, 0.002, 0.003, 0.004, 0.005])
y = 2000.0 * x + 0.5
result = scirs2.polyfit_py(x, y, deg=1)
assert result["r_squared"] > 0.99
def test_different_scales(self):
x = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
y = x * 1000.0
result = scirs2.polyfit_py(x, y, deg=1)
assert result["r_squared"] > 0.99
assert abs(result["coefficients"][1] - 1000.0) < 10.0
class TestPolyfitRealWorldScenarios:
def test_temperature_conversion(self):
celsius = np.array([0.0, 10.0, 20.0, 30.0, 40.0, 100.0])
fahrenheit = np.array([32.0, 50.0, 68.0, 86.0, 104.0, 212.0])
result = scirs2.polyfit_py(celsius, fahrenheit, deg=1)
assert abs(result["coefficients"][0] - 32.0) < 0.1 assert abs(result["coefficients"][1] - 1.8) < 0.1 assert result["r_squared"] > 0.9999
def test_population_growth(self):
years = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0])
population = 100.0 + 10.0 * years + 2.0 * years**2
result = scirs2.polyfit_py(years, population, deg=2)
assert result["r_squared"] > 0.99
assert abs(result["coefficients"][0] - 100.0) < 1.0
assert abs(result["coefficients"][1] - 10.0) < 1.0
assert abs(result["coefficients"][2] - 2.0) < 1.0
def test_trajectory_modeling(self):
t = np.array([0.0, 0.5, 1.0, 1.5, 2.0, 2.5])
h = 10.0 + 20.0 * t - 0.5 * 9.8 * t**2
result = scirs2.polyfit_py(t, h, deg=2)
assert result["r_squared"] > 0.9999
assert abs(result["coefficients"][0] - 10.0) < 0.01 assert abs(result["coefficients"][1] - 20.0) < 0.01 assert abs(result["coefficients"][2] - (-4.9)) < 0.01
def test_signal_approximation(self):
x = np.linspace(0, np.pi, 10)
y = np.sin(x)
result = scirs2.polyfit_py(x, y, deg=5)
assert result["r_squared"] > 0.9
def test_data_smoothing(self):
np.random.seed(42)
x = np.linspace(0, 10, 30)
y_true = 5.0 + 2.0 * x
y_noisy = y_true + np.random.normal(0, 1.0, len(x))
result = scirs2.polyfit_py(x, y_noisy, deg=1)
fitted = np.array(result["fitted_values"])
for i, xi in enumerate(x):
expected = 5.0 + 2.0 * xi
assert abs(fitted[i] - expected) < 2.0
if __name__ == "__main__":
pytest.main([__file__, "-v"])