import pytest
import numpy as np
import scirs2
class TestDistanceFunctions:
def test_euclidean_basic(self):
u = np.array([0.0, 0.0])
v = np.array([3.0, 4.0])
result = scirs2.euclidean_py(u, v)
assert abs(result - 5.0) < 1e-10
def test_euclidean_zero_distance(self):
u = np.array([1.0, 2.0, 3.0])
result = scirs2.euclidean_py(u, u)
assert abs(result) < 1e-10
def test_euclidean_3d(self):
u = np.array([0.0, 0.0, 0.0])
v = np.array([1.0, 2.0, 2.0])
result = scirs2.euclidean_py(u, v)
assert abs(result - 3.0) < 1e-10
def test_cityblock_basic(self):
u = np.array([0.0, 0.0])
v = np.array([3.0, 4.0])
result = scirs2.cityblock_py(u, v)
assert abs(result - 7.0) < 1e-10
def test_cityblock_3d(self):
u = np.array([1.0, 2.0, 3.0])
v = np.array([4.0, 6.0, 8.0])
result = scirs2.cityblock_py(u, v)
assert abs(result - 12.0) < 1e-10
def test_chebyshev_basic(self):
u = np.array([0.0, 0.0])
v = np.array([3.0, 4.0])
result = scirs2.chebyshev_py(u, v)
assert abs(result - 4.0) < 1e-10
def test_chebyshev_3d(self):
u = np.array([0.0, 0.0, 0.0])
v = np.array([1.0, 5.0, 3.0])
result = scirs2.chebyshev_py(u, v)
assert abs(result - 5.0) < 1e-10
def test_minkowski_p1(self):
u = np.array([0.0, 0.0])
v = np.array([3.0, 4.0])
result = scirs2.minkowski_py(u, v, 1.0)
cityblock = scirs2.cityblock_py(u, v)
assert abs(result - cityblock) < 1e-10
def test_minkowski_p2(self):
u = np.array([0.0, 0.0])
v = np.array([3.0, 4.0])
result = scirs2.minkowski_py(u, v, 2.0)
euclidean = scirs2.euclidean_py(u, v)
assert abs(result - euclidean) < 1e-10
def test_minkowski_p3(self):
u = np.array([0.0, 0.0])
v = np.array([1.0, 1.0])
result = scirs2.minkowski_py(u, v, 3.0)
expected = 2.0 ** (1/3)
assert abs(result - expected) < 1e-10
def test_cosine_orthogonal(self):
u = np.array([1.0, 0.0])
v = np.array([0.0, 1.0])
result = scirs2.cosine_py(u, v)
assert abs(result - 1.0) < 1e-10
def test_cosine_same_direction(self):
u = np.array([1.0, 2.0, 3.0])
v = np.array([2.0, 4.0, 6.0])
result = scirs2.cosine_py(u, v)
assert abs(result) < 1e-10
def test_cosine_opposite(self):
u = np.array([1.0, 0.0])
v = np.array([-1.0, 0.0])
result = scirs2.cosine_py(u, v)
assert abs(result - 2.0) < 1e-10
class TestPdist:
def test_pdist_basic(self):
x = np.array([
[0.0, 0.0],
[1.0, 0.0],
[0.0, 1.0]
])
result = scirs2.pdist_py(x, metric="euclidean")
assert len(result) == 3
assert abs(result[0] - 1.0) < 1e-10 assert abs(result[1] - 1.0) < 1e-10 assert abs(result[2] - np.sqrt(2)) < 1e-10
def test_pdist_cityblock(self):
x = np.array([
[0.0, 0.0],
[1.0, 1.0],
[2.0, 2.0]
])
result = scirs2.pdist_py(x, metric="cityblock")
assert len(result) == 3
assert abs(result[0] - 2.0) < 1e-10 assert abs(result[1] - 4.0) < 1e-10 assert abs(result[2] - 2.0) < 1e-10
def test_pdist_chebyshev(self):
x = np.array([
[0.0, 0.0],
[1.0, 2.0],
[3.0, 1.0]
])
result = scirs2.pdist_py(x, metric="chebyshev")
assert len(result) == 3
assert abs(result[0] - 2.0) < 1e-10 assert abs(result[1] - 3.0) < 1e-10 assert abs(result[2] - 2.0) < 1e-10
def test_pdist_single_point(self):
x = np.array([
[0.0, 0.0],
[3.0, 4.0]
])
result = scirs2.pdist_py(x)
assert len(result) == 1
assert abs(result[0] - 5.0) < 1e-10
class TestCdist:
def test_cdist_basic(self):
xa = np.array([
[0.0, 0.0],
[1.0, 0.0]
])
xb = np.array([
[0.0, 1.0],
[1.0, 1.0],
[2.0, 0.0]
])
result = scirs2.cdist_py(xa, xb)
assert result.shape == (2, 3)
assert abs(result[0, 0] - 1.0) < 1e-10 assert abs(result[0, 1] - np.sqrt(2)) < 1e-10 assert abs(result[1, 2] - 1.0) < 1e-10
def test_cdist_cityblock(self):
xa = np.array([[0.0, 0.0]])
xb = np.array([
[1.0, 2.0],
[3.0, 4.0]
])
result = scirs2.cdist_py(xa, xb, metric="cityblock")
assert result.shape == (1, 2)
assert abs(result[0, 0] - 3.0) < 1e-10
assert abs(result[0, 1] - 7.0) < 1e-10
def test_cdist_square(self):
x = np.array([
[0.0, 0.0],
[1.0, 0.0],
[0.0, 1.0]
])
result = scirs2.cdist_py(x, x)
assert abs(result[0, 0]) < 1e-10
assert abs(result[1, 1]) < 1e-10
assert abs(result[2, 2]) < 1e-10
assert abs(result[0, 1] - result[1, 0]) < 1e-10
assert abs(result[0, 2] - result[2, 0]) < 1e-10
class TestSquareform:
def test_squareform_basic(self):
condensed = np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
result = scirs2.squareform_py(condensed)
assert result.shape == (4, 4)
for i in range(4):
assert abs(result[i, i]) < 1e-10
for i in range(4):
for j in range(4):
assert abs(result[i, j] - result[j, i]) < 1e-10
def test_squareform_values(self):
condensed = np.array([1.0, 2.0, 3.0])
result = scirs2.squareform_py(condensed)
assert abs(result[0, 1] - 1.0) < 1e-10
assert abs(result[0, 2] - 2.0) < 1e-10
assert abs(result[1, 2] - 3.0) < 1e-10
def test_squareform_two_points(self):
condensed = np.array([5.0])
result = scirs2.squareform_py(condensed)
assert result.shape == (2, 2)
assert abs(result[0, 1] - 5.0) < 1e-10
assert abs(result[1, 0] - 5.0) < 1e-10
class TestEdgeCases:
def test_high_dimensional(self):
u = np.ones(100)
v = np.zeros(100)
result = scirs2.euclidean_py(u, v)
assert abs(result - 10.0) < 1e-10
def test_pdist_many_points(self):
n = 50
x = np.random.randn(n, 3)
result = scirs2.pdist_py(x)
expected_len = n * (n - 1) // 2
assert len(result) == expected_len
assert all(d >= 0 for d in result)
def test_cdist_different_sizes(self):
xa = np.random.randn(10, 5)
xb = np.random.randn(20, 5)
result = scirs2.cdist_py(xa, xb)
assert result.shape == (10, 20)
def test_unit_vectors(self):
u = np.array([1.0, 0.0, 0.0])
v = np.array([0.0, 1.0, 0.0])
result = scirs2.cosine_py(u, v)
assert abs(result - 1.0) < 1e-10
class TestKDTree:
def test_kdtree_basic(self):
points = np.array([
[0.0, 0.0],
[1.0, 0.0],
[0.0, 1.0],
[1.0, 1.0]
])
tree = scirs2.KDTree(points)
result = tree.query(np.array([0.1, 0.1]), k=1)
assert "indices" in result
assert "distances" in result
assert len(result["indices"]) == 1
assert result["indices"][0] == 0
def test_kdtree_knn(self):
points = np.array([
[0.0, 0.0],
[1.0, 0.0],
[0.0, 1.0],
[1.0, 1.0],
[0.5, 0.5]
])
tree = scirs2.KDTree(points)
result = tree.query(np.array([0.5, 0.5]), k=3)
assert len(result["indices"]) == 3
assert 4 in result["indices"]
def test_kdtree_radius_query(self):
points = np.array([
[0.0, 0.0],
[1.0, 0.0],
[0.0, 1.0],
[1.0, 1.0]
])
tree = scirs2.KDTree(points)
result = tree.query_radius(np.array([0.0, 0.0]), r=1.5)
assert "indices" in result
assert len(result["indices"]) >= 3
def test_kdtree_3d(self):
points = np.array([
[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0]
])
tree = scirs2.KDTree(points)
result = tree.query(np.array([0.1, 0.1, 0.1]), k=1)
assert len(result["indices"]) == 1
assert result["indices"][0] == 0
def test_kdtree_many_points(self):
np.random.seed(42)
points = np.random.randn(100, 3)
tree = scirs2.KDTree(points)
result = tree.query(np.array([0.0, 0.0, 0.0]), k=5)
assert len(result["indices"]) == 5
assert len(result["distances"]) == 5
for i in range(len(result["distances"]) - 1):
assert result["distances"][i] <= result["distances"][i + 1]
class TestConvexHull:
def test_convex_hull_triangle(self):
points = np.array([
[0.0, 0.0],
[1.0, 0.0],
[0.5, 1.0]
])
result = scirs2.convex_hull_py(points)
assert "vertices" in result
assert "simplices" in result
assert "area" in result
assert len(result["vertices"]) == 3
def test_convex_hull_square(self):
points = np.array([
[0.0, 0.0],
[1.0, 0.0],
[1.0, 1.0],
[0.0, 1.0]
])
result = scirs2.convex_hull_py(points)
assert len(result["vertices"]) == 4
assert result["area"] > 0
def test_convex_hull_with_interior(self):
points = np.array([
[0.0, 0.0],
[1.0, 0.0],
[1.0, 1.0],
[0.0, 1.0],
[0.5, 0.5] ])
result = scirs2.convex_hull_py(points)
assert len(result["vertices"]) == 4
def test_convex_hull_3d(self):
points = np.array([
[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0]
])
result = scirs2.convex_hull_py(points)
assert "vertices" in result
assert "volume" in result
assert len(result["vertices"]) == 4
assert abs(result["volume"] - (1.0 / 6.0)) < 0.01
def test_convex_hull_class(self):
points = np.array([
[0.0, 0.0],
[1.0, 0.0],
[0.5, 1.0]
])
hull = scirs2.ConvexHullPy(points)
vertices = hull.vertices()
simplices = hull.simplices()
area = hull.area()
assert len(vertices) == 3
assert len(simplices) > 0
assert area > 0
def test_convex_hull_contains(self):
points = np.array([
[0.0, 0.0],
[2.0, 0.0],
[2.0, 2.0],
[0.0, 2.0]
])
hull = scirs2.ConvexHullPy(points)
assert hull.contains(np.array([1.0, 1.0]))
assert hull.contains(np.array([0.0, 0.0]))
def test_convex_hull_many_points(self):
np.random.seed(42)
theta = np.linspace(0, 2*np.pi, 21)[:-1] points = np.column_stack([np.cos(theta), np.sin(theta)])
result = scirs2.convex_hull_py(points)
assert len(result["vertices"]) == 20