import pytest
import numpy as np
import scirs2
class TestInterp1d:
def test_linear_interpolation(self):
x = np.array([0.0, 1.0, 2.0, 3.0])
y = np.array([0.0, 1.0, 4.0, 9.0])
interp = scirs2.Interp1d(x, y, method="linear")
result = interp(np.array([0.0, 1.0, 2.0]))
np.testing.assert_allclose(result, [0.0, 1.0, 4.0], rtol=1e-10)
def test_linear_midpoints(self):
x = np.array([0.0, 1.0, 2.0])
y = np.array([0.0, 2.0, 4.0])
interp = scirs2.Interp1d(x, y, method="linear")
result = interp(np.array([0.5, 1.5]))
np.testing.assert_allclose(result, [1.0, 3.0], rtol=1e-10)
def test_nearest_interpolation(self):
x = np.array([0.0, 1.0, 2.0])
y = np.array([10.0, 20.0, 30.0])
interp = scirs2.Interp1d(x, y, method="nearest")
result = interp(np.array([0.3, 0.7, 1.5]))
assert len(result) == 3
def test_cubic_interpolation(self):
x = np.array([0.0, 1.0, 2.0, 3.0, 4.0])
y = np.sin(x)
interp = scirs2.Interp1d(x, y, method="cubic")
x_new = np.array([0.5, 1.5, 2.5, 3.5])
result = interp(x_new)
expected = np.sin(x_new)
np.testing.assert_allclose(result, expected, rtol=0.15)
def test_eval_single(self):
x = np.array([0.0, 1.0, 2.0])
y = np.array([0.0, 1.0, 4.0])
interp = scirs2.Interp1d(x, y)
result = interp.eval_single(0.5)
assert abs(result - 0.5) < 1e-10
def test_pchip_interpolation(self):
x = np.array([0.0, 1.0, 2.0, 3.0])
y = np.array([0.0, 1.0, 0.0, 1.0])
interp = scirs2.Interp1d(x, y, method="pchip")
result = interp(np.array([0.5, 1.5, 2.5]))
assert len(result) == 3
class TestInterpFunction:
def test_interp_basic(self):
xp = np.array([0.0, 1.0, 2.0])
fp = np.array([0.0, 10.0, 20.0])
x = np.array([0.5, 1.5])
result = scirs2.interp_py(x, xp, fp)
np.testing.assert_allclose(result, [5.0, 15.0], rtol=1e-10)
def test_interp_at_data_points(self):
xp = np.array([0.0, 1.0, 2.0, 3.0])
fp = np.array([1.0, 4.0, 9.0, 16.0])
x = xp.copy()
result = scirs2.interp_py(x, xp, fp)
np.testing.assert_allclose(result, fp, rtol=1e-10)
class TestInterpWithBounds:
def test_with_left_bound(self):
xp = np.array([1.0, 2.0, 3.0])
fp = np.array([10.0, 20.0, 30.0])
x = np.array([0.0, 1.5, 2.5, 4.0])
result = scirs2.interp_with_bounds_py(x, xp, fp, left=0.0, right=100.0)
assert result[0] == 0.0 assert abs(result[1] - 15.0) < 1e-10 assert abs(result[2] - 25.0) < 1e-10 assert result[3] == 100.0
def test_default_boundaries(self):
xp = np.array([1.0, 2.0, 3.0])
fp = np.array([10.0, 20.0, 30.0])
x = np.array([0.0, 4.0])
result = scirs2.interp_with_bounds_py(x, xp, fp)
assert abs(result[0] - 10.0) < 1e-10
assert abs(result[1] - 30.0) < 1e-10
class TestExtrapolation:
def test_nearest_extrapolation(self):
x = np.array([0.0, 1.0, 2.0])
y = np.array([0.0, 1.0, 4.0])
interp = scirs2.Interp1d(x, y, extrapolate="nearest")
result = interp(np.array([0.5, 1.5]))
assert len(result) == 2
class TestEdgeCases:
def test_two_points(self):
x = np.array([0.0, 1.0])
y = np.array([0.0, 10.0])
interp = scirs2.Interp1d(x, y)
result = interp(np.array([0.5]))
np.testing.assert_allclose(result, [5.0], rtol=1e-10)
def test_many_points(self):
x = np.linspace(0, 10, 1000)
y = np.sin(x)
interp = scirs2.Interp1d(x, y)
x_new = np.array([0.1, 5.0, 9.9])
result = interp(x_new)
np.testing.assert_allclose(result, np.sin(x_new), rtol=0.01)
def test_single_query_point(self):
x = np.array([0.0, 1.0, 2.0])
y = np.array([0.0, 1.0, 4.0])
interp = scirs2.Interp1d(x, y)
result = interp(np.array([0.5]))
assert len(result) == 1
def test_constant_function(self):
x = np.array([0.0, 1.0, 2.0, 3.0])
y = np.array([5.0, 5.0, 5.0, 5.0])
interp = scirs2.Interp1d(x, y)
result = interp(np.array([0.5, 1.5, 2.5]))
np.testing.assert_allclose(result, [5.0, 5.0, 5.0], rtol=1e-10)
class TestCubicSpline:
def test_basic_spline(self):
x = np.array([0.0, 1.0, 2.0, 3.0])
y = np.array([0.0, 1.0, 4.0, 9.0])
spline = scirs2.CubicSpline(x, y)
result = spline(np.array([0.0, 1.0, 2.0, 3.0]))
np.testing.assert_allclose(result, y, rtol=1e-10)
def test_spline_interpolation(self):
x = np.array([0.0, 1.0, 2.0, 3.0])
y = np.array([0.0, 1.0, 0.5, 0.0])
spline = scirs2.CubicSpline(x, y, bc_type="natural")
x_new = np.array([0.5, 1.5, 2.5])
result = spline(x_new)
assert len(result) == 3
assert all(not np.isnan(val) for val in result)
def test_spline_derivative(self):
x = np.array([0.0, 1.0, 2.0, 3.0, 4.0])
y = x ** 2
spline = scirs2.CubicSpline(x, y)
x_eval = np.array([2.0])
deriv = spline.derivative(x_eval, nu=1)
np.testing.assert_allclose(deriv, [4.0], rtol=0.1)
def test_spline_second_derivative(self):
x = np.array([0.0, 1.0, 2.0, 3.0, 4.0])
y = x ** 2
spline = scirs2.CubicSpline(x, y)
x_eval = np.array([1.0, 2.0, 3.0])
deriv2 = spline.derivative(x_eval, nu=2)
np.testing.assert_allclose(deriv2, [2.0, 2.0, 2.0], rtol=0.3)
def test_spline_integration(self):
x = np.array([0.0, 1.0, 2.0, 3.0])
y = np.array([1.0, 1.0, 1.0, 1.0])
spline = scirs2.CubicSpline(x, y)
integral = spline.integrate(0.0, 3.0)
np.testing.assert_allclose(integral, 3.0, rtol=1e-5)
def test_spline_integration_polynomial(self):
x = np.array([0.0, 1.0, 2.0, 3.0, 4.0])
y = x ** 2
spline = scirs2.CubicSpline(x, y)
integral = spline.integrate(0.0, 4.0)
expected = 64.0 / 3.0
np.testing.assert_allclose(integral, expected, rtol=0.05)
def test_spline_eval_single(self):
x = np.array([0.0, 1.0, 2.0, 3.0])
y = np.array([0.0, 1.0, 4.0, 9.0])
spline = scirs2.CubicSpline(x, y)
result = spline.eval_single(1.5)
assert not np.isnan(result)
def test_spline_sine_function(self):
x = np.linspace(0, 2*np.pi, 10)
y = np.sin(x)
spline = scirs2.CubicSpline(x, y)
x_new = np.linspace(0, 2*np.pi, 50)
result = spline(x_new)
expected = np.sin(x_new)
np.testing.assert_allclose(result, expected, rtol=0.1)
class TestInterp2d:
def test_interp2d_linear_basic(self):
x = np.array([0.0, 1.0, 2.0])
y = np.array([0.0, 1.0])
z = np.array([[0.0, 1.0, 2.0],
[1.0, 2.0, 3.0]])
interp = scirs2.Interp2d(x, y, z, kind="linear")
assert abs(interp(0.0, 0.0) - 0.0) < 1e-10
assert abs(interp(1.0, 0.0) - 1.0) < 1e-10
assert abs(interp(2.0, 1.0) - 3.0) < 1e-10
def test_interp2d_linear_interpolation(self):
x = np.array([0.0, 1.0, 2.0])
y = np.array([0.0, 1.0])
z = np.array([[0.0, 1.0, 2.0],
[1.0, 2.0, 3.0]])
interp = scirs2.Interp2d(x, y, z, kind="linear")
result = interp(0.5, 0.5)
np.testing.assert_allclose(result, 1.0, rtol=1e-10)
result = interp(1.5, 0.5)
np.testing.assert_allclose(result, 2.0, rtol=1e-10)
def test_interp2d_cubic(self):
x = np.array([0.0, 1.0, 2.0, 3.0])
y = np.array([0.0, 1.0, 2.0, 3.0])
z = np.zeros((4, 4))
for i in range(4):
for j in range(4):
z[i, j] = x[j]**2 + y[i]**2
interp = scirs2.Interp2d(x, y, z, kind="cubic")
assert abs(interp(1.0, 1.0) - 2.0) < 1e-10
result = interp(1.5, 1.5)
expected = 1.5**2 + 1.5**2 assert abs(result - expected) < 0.5
def test_interp2d_eval_array(self):
x = np.array([0.0, 1.0, 2.0])
y = np.array([0.0, 1.0])
z = np.array([[0.0, 1.0, 2.0],
[1.0, 2.0, 3.0]])
interp = scirs2.Interp2d(x, y, z, kind="linear")
x_new = np.array([0.5, 1.0, 1.5])
y_new = np.array([0.5, 0.5, 0.5])
result = interp.eval_array(x_new, y_new)
assert len(result) == 3
np.testing.assert_allclose(result[1], 1.5, rtol=1e-10)
def test_interp2d_eval_grid(self):
x = np.array([0.0, 1.0])
y = np.array([0.0, 1.0])
z = np.array([[0.0, 1.0],
[1.0, 2.0]])
interp = scirs2.Interp2d(x, y, z, kind="linear")
x_new = np.array([0.0, 0.5, 1.0])
y_new = np.array([0.0, 0.5, 1.0])
result = interp.eval_grid(x_new, y_new)
assert result.shape == (3, 3)
assert abs(result[0, 0] - 0.0) < 1e-10
assert abs(result[0, 2] - 1.0) < 1e-10
assert abs(result[2, 0] - 1.0) < 1e-10
assert abs(result[2, 2] - 2.0) < 1e-10
assert abs(result[1, 1] - 1.0) < 1e-10
def test_interp2d_product_function(self):
x = np.array([0.0, 1.0, 2.0, 3.0])
y = np.array([0.0, 1.0, 2.0, 3.0])
z = np.zeros((4, 4))
for i in range(4):
for j in range(4):
z[i, j] = x[j] * y[i]
interp = scirs2.Interp2d(x, y, z, kind="linear")
result = interp(1.5, 2.0)
np.testing.assert_allclose(result, 3.0, rtol=1e-10)
def test_interp2d_constant(self):
x = np.array([0.0, 1.0, 2.0])
y = np.array([0.0, 1.0, 2.0])
z = np.ones((3, 3)) * 5.0
interp = scirs2.Interp2d(x, y, z, kind="linear")
assert abs(interp(0.5, 0.5) - 5.0) < 1e-10
assert abs(interp(1.5, 1.5) - 5.0) < 1e-10