Skip to content

Commit

Permalink
Place hypothesis tests in test_ripser and remove superseded tests the…
Browse files Browse the repository at this point in the history
…re. Add regression test for giotto-ai#465
  • Loading branch information
ulupo committed Sep 8, 2020
1 parent 701f6f9 commit 0565a38
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 143 deletions.
76 changes: 0 additions & 76 deletions gtda/externals/python/tests/test_collapser.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,12 @@
"""

import numpy as np
import pytest
from gtda.externals.modules.gtda_collapser import \
flag_complex_collapse_edges_dense, \
flag_complex_collapse_edges_sparse, \
flag_complex_collapse_edges_coo
from hypothesis import given
from hypothesis.extra.numpy import arrays
from hypothesis.strategies import floats, integers, composite
from numpy.testing import assert_almost_equal
from scipy.sparse import coo_matrix, csr_matrix

from gtda.externals import ripser

X = np.array([[0, 1, 1.],
[1, 2, 1.],
[2, 3, 1.],
Expand Down Expand Up @@ -55,72 +48,3 @@ def test_simple_dense_example():
coo_ = flag_complex_collapse_edges_dense(data)
coo = coo_matrix((coo_[2], (coo_[0], coo_[1])))
assert check_collapse(coo, [[1, 3, 2]])


@composite
def get_dense_distance_matrices(draw):
"""Generate 2d dense square arrays of floats, with zero along the
diagonal."""
shapes = draw(integers(min_value=2, max_value=30))
distance_matrix = draw(arrays(dtype=np.float,
elements=floats(allow_nan=False,
allow_infinity=True,
min_value=0),
shape=(shapes, shapes), unique=False))
np.fill_diagonal(distance_matrix, 0)
return distance_matrix


@composite
def get_sparse_distance_matrices(draw):
"""Generate 2d sparse matrices of floats, with zero along the diagonal."""
shapes = draw(integers(min_value=2, max_value=30))
distance_matrix = draw(arrays(dtype=np.float,
elements=floats(allow_nan=False,
allow_infinity=True,
min_value=0),
shape=(shapes, shapes), unique=False))
distance_matrix = np.triu(distance_matrix, k=1)
distance_matrix = coo_matrix(distance_matrix)
row, col, data = \
distance_matrix.row, distance_matrix.col, distance_matrix.data
not_inf_idx = data != np.inf
row = row[not_inf_idx]
col = col[not_inf_idx]
data = data[not_inf_idx]
shape = (np.max(row) + 1, np.max(col) + 1) if not_inf_idx.sum() else (0, 0)
distance_matrix = coo_matrix((data, (row, col)), shape=shape)
return distance_matrix


@pytest.mark.parametrize('thresh', [False, True])
@given(distance_matrix=get_dense_distance_matrices())
def test_collapse_consistent_with_no_collapse_dense(thresh, distance_matrix):
thresh = np.max(distance_matrix) / 2 if thresh else np.inf
maxdim = 3
pd_collapse = ripser(distance_matrix, thresh=thresh, maxdim=maxdim,
metric='precomputed', collapse_edges=True)['dgms']
pd_no_collapse = ripser(distance_matrix, thresh=thresh, maxdim=maxdim,
metric='precomputed', collapse_edges=False)['dgms']
for i in range(maxdim + 1):
pd_collapse[i] = np.sort(pd_collapse[i], axis=0)
pd_no_collapse[i] = np.sort(pd_no_collapse[i], axis=0)
assert_almost_equal(pd_collapse[i], pd_no_collapse[i])


@pytest.mark.parametrize('thresh', [False, True])
@given(distance_matrix=get_sparse_distance_matrices())
def test_collapse_consistent_with_no_collapse_sparse(thresh, distance_matrix):
if thresh and distance_matrix.nnz:
thresh = np.max(distance_matrix) / 2
else:
thresh = np.inf
maxdim = 3
pd_collapse = ripser(distance_matrix, thresh=thresh, maxdim=maxdim,
metric='precomputed', collapse_edges=True)['dgms']
pd_no_collapse = ripser(distance_matrix, thresh=thresh, maxdim=maxdim,
metric='precomputed', collapse_edges=False)['dgms']
for i in range(maxdim + 1):
pd_collapse[i] = np.sort(pd_collapse[i], axis=0)
pd_no_collapse[i] = np.sort(pd_no_collapse[i], axis=0)
assert_almost_equal(pd_collapse[i], pd_no_collapse[i])
152 changes: 85 additions & 67 deletions gtda/externals/python/tests/test_ripser.py
Original file line number Diff line number Diff line change
@@ -1,79 +1,97 @@
import numpy as np
import scipy as sp
from .. import ripser
import pytest
from hypothesis import given
from hypothesis.extra.numpy import arrays
from hypothesis.strategies import floats, integers, composite
from numpy.testing import assert_almost_equal
from scipy.sparse import coo_matrix

X = np.random.random((50, 50))
# Without this line, there might be different results because GUDHI
# assumes zeros in the diagonal
np.fill_diagonal(X, 0)
maxdim = 2
from gtda.externals import ripser


def test_with_collapser():
diags_collapsed = ripser(
X,
metric='precomputed',
maxdim=maxdim,
collapse_edges=True)['dgms']
diags_not_collapsed = ripser(
X,
metric='precomputed',
maxdim=maxdim,
collapse_edges=False)['dgms']
@composite
def get_dense_distance_matrices(draw):
"""Generate 2d dense square arrays of floats, with zero along the
diagonal."""
shapes = draw(integers(min_value=2, max_value=30))
distance_matrix = draw(arrays(dtype=np.float,
elements=floats(allow_nan=False,
allow_infinity=True,
min_value=0),
shape=(shapes, shapes), unique=False))
np.fill_diagonal(distance_matrix, 0)
return distance_matrix

for i in range(maxdim):
assert np.array_equal(diags_collapsed[i], diags_not_collapsed[i])

@composite
def get_sparse_distance_matrices(draw):
"""Generate 2d sparse matrices of floats, with zero along the diagonal."""
shapes = draw(integers(min_value=2, max_value=40))
distance_matrix = draw(arrays(dtype=np.float,
elements=floats(allow_nan=False,
allow_infinity=True,
min_value=0),
shape=(shapes, shapes), unique=False))
distance_matrix = np.triu(distance_matrix, k=1)
distance_matrix = coo_matrix(distance_matrix)
row, col, data = \
distance_matrix.row, distance_matrix.col, distance_matrix.data
not_inf_idx = data != np.inf
row = row[not_inf_idx]
col = col[not_inf_idx]
data = data[not_inf_idx]
shape = (np.max(row) + 1, np.max(col) + 1) if not_inf_idx.any() else (0, 0)
distance_matrix = coo_matrix((data, (row, col)), shape=shape)
return distance_matrix

def test_with_collapser_with_tresh():
thresh = 0.1
diags_collapsed_thresh = ripser(
X,
metric='precomputed',
maxdim=maxdim,
thresh=thresh,
collapse_edges=True)['dgms']
diags_not_collapsed_thresh = ripser(
X, metric='precomputed', maxdim=maxdim, thresh=thresh,
collapse_edges=False)['dgms']

for i in range(maxdim):
assert np.array_equal(diags_collapsed_thresh[i],
diags_not_collapsed_thresh[i])
@pytest.mark.parametrize('thresh', [False, True])
@given(distance_matrix=get_dense_distance_matrices())
def test_collapse_consistent_with_no_collapse_dense(thresh, distance_matrix):
thresh = np.max(distance_matrix) / 2 if thresh else np.inf
maxdim = 3
pd_collapse = ripser(distance_matrix, thresh=thresh, maxdim=maxdim,
metric='precomputed', collapse_edges=True)['dgms']
pd_no_collapse = ripser(distance_matrix, thresh=thresh, maxdim=maxdim,
metric='precomputed', collapse_edges=False)['dgms']
for i in range(maxdim + 1):
pd_collapse[i] = np.sort(pd_collapse[i], axis=0)
pd_no_collapse[i] = np.sort(pd_no_collapse[i], axis=0)
assert_almost_equal(pd_collapse[i], pd_no_collapse[i])


def test_with_collapser_coo():
X_tri = np.triu(X, 1)
diags_collapsed = ripser(
sp.sparse.coo_matrix(X_tri),
metric='precomputed',
maxdim=maxdim,
collapse_edges=True)['dgms']
diags_not_collapsed = ripser(
sp.sparse.coo_matrix(X_tri),
metric='precomputed',
maxdim=maxdim,
collapse_edges=False)['dgms']
@pytest.mark.parametrize('thresh', [False, True])
@given(distance_matrix=get_sparse_distance_matrices())
def test_collapse_consistent_with_no_collapse_coo(thresh, distance_matrix):
if thresh and distance_matrix.nnz:
thresh = np.max(distance_matrix) / 2
else:
thresh = np.inf
maxdim = 3
pd_collapse = ripser(distance_matrix, thresh=thresh, maxdim=maxdim,
metric='precomputed', collapse_edges=True)['dgms']
pd_no_collapse = ripser(distance_matrix, thresh=thresh, maxdim=maxdim,
metric='precomputed', collapse_edges=False)['dgms']
for i in range(maxdim + 1):
pd_collapse[i] = np.sort(pd_collapse[i], axis=0)
pd_no_collapse[i] = np.sort(pd_no_collapse[i], axis=0)
assert_almost_equal(pd_collapse[i], pd_no_collapse[i])

for i in range(maxdim):
assert np.array_equal(diags_collapsed[i], diags_not_collapsed[i])


def test_with_collapser_coo_thresh():
thresh = 0.1
X_tri = np.triu(X, 1)
diags_collapsed = ripser(
sp.sparse.coo_matrix(X_tri),
metric='precomputed',
maxdim=maxdim,
thresh=thresh,
collapse_edges=True)['dgms']
diags_not_collapsed = ripser(
sp.sparse.coo_matrix(X_tri),
metric='precomputed',
maxdim=maxdim,
thresh=thresh,
collapse_edges=False)['dgms']

for i in range(maxdim):
assert np.array_equal(diags_collapsed[i], diags_not_collapsed[i])
def test_coo_results_independent_of_order():
"""Regression test for PR #465"""
data = np.array([6., 8., 2., 4., 5., 9., 10., 3., 1., 1.])
row = np.array([0, 0, 0, 0, 1, 1, 1, 2, 2, 3])
col = np.array([4, 1, 3, 2, 4, 3, 2, 3, 4, 4])
dm = coo_matrix((data, (row, col)))
diagrams = ripser(dm, metric="precomputed")['dgms']
diagrams_csr = ripser(dm.tocsr(), metric="precomputed")['dgms']
expected = [np.array([[0., 1.],
[0., 1.],
[0., 2.],
[0., 5.],
[0., np.inf]]),
np.array([], shape=(0, 2), dtype=np.float64)]
for i in range(2):
assert np.array_equal(diagrams[i], expected[i])
assert np.array_equal(diagrams_csr[i], expected[i])

0 comments on commit 0565a38

Please sign in to comment.