summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorROUVREAU Vincent <vincent.rouvreau@inria.fr>2021-06-22 17:34:27 +0200
committerROUVREAU Vincent <vincent.rouvreau@inria.fr>2021-06-22 17:34:27 +0200
commit6d7c79a352023dd380b7361057cb7db371c5d269 (patch)
tree7a5c5b53c651cf51b98c2481bec70b06d5d66ab2
parent7cce5bc6778053ba6c2c3cce2bd9442c4e063e0d (diff)
Fix #448. Add Alpha complex 3d python module unitary tests accordingly.
-rw-r--r--src/Alpha_complex/include/gudhi/Alpha_complex_3d.h19
-rw-r--r--src/Alpha_complex/test/Alpha_complex_3d_unit_test.cpp30
-rw-r--r--src/Alpha_complex/test/Weighted_alpha_complex_unit_test.cpp2
-rw-r--r--src/python/gudhi/alpha_complex_3d.pyx4
-rwxr-xr-xsrc/python/test/test_alpha_complex.py107
-rwxr-xr-xsrc/python/test/test_alpha_complex_3d.py149
6 files changed, 231 insertions, 80 deletions
diff --git a/src/Alpha_complex/include/gudhi/Alpha_complex_3d.h b/src/Alpha_complex/include/gudhi/Alpha_complex_3d.h
index 4e5fc933..73f9dd41 100644
--- a/src/Alpha_complex/include/gudhi/Alpha_complex_3d.h
+++ b/src/Alpha_complex/include/gudhi/Alpha_complex_3d.h
@@ -48,6 +48,7 @@
#include <memory> // for std::unique_ptr
#include <type_traits> // for std::conditional and std::enable_if
#include <limits> // for numeric_limits<>
+#include <exception> // for domain_error and invalid_argument
// Make compilation fail - required for external projects - https://github.com/GUDHI/gudhi-devel/issues/10
#if CGAL_VERSION_NR < 1041101000
@@ -428,19 +429,18 @@ Weighted_alpha_complex_3d::Weighted_point_3 wp0(Weighted_alpha_complex_3d::Bare_
* @param[in] max_alpha_square maximum for alpha square value. Default value is +\f$\infty\f$, and there is very
* little point using anything else since it does not save time.
*
- * @return true if creation succeeds, false otherwise.
+ * @exception invalid_argument In debug mode, if `complex` given as argument is not empty.
+ * @exception domain_error If `points` given in the constructor are on a 2d plane.
*
* @pre The simplicial complex must be empty (no vertices).
*
*/
template <typename SimplicialComplexForAlpha3d,
typename Filtration_value = typename SimplicialComplexForAlpha3d::Filtration_value>
- bool create_complex(SimplicialComplexForAlpha3d& complex,
+ void create_complex(SimplicialComplexForAlpha3d& complex,
Filtration_value max_alpha_square = std::numeric_limits<Filtration_value>::infinity()) {
- if (complex.num_vertices() > 0) {
- std::cerr << "Alpha_complex_3d create_complex - complex is not empty\n";
- return false; // ----- >>
- }
+ GUDHI_CHECK(complex.num_vertices() == 0,
+ std::invalid_argument("Alpha_complex_3d create_complex - The complex given as argument is not empty"));
using Complex_vertex_handle = typename SimplicialComplexForAlpha3d::Vertex_handle;
using Simplex_tree_vector_vertex = std::vector<Complex_vertex_handle>;
@@ -461,10 +461,8 @@ Weighted_alpha_complex_3d::Weighted_point_3 wp0(Weighted_alpha_complex_3d::Bare_
#ifdef DEBUG_TRACES
std::clog << "filtration_with_alpha_values returns : " << objects.size() << " objects" << std::endl;
#endif // DEBUG_TRACES
- if (objects.size() == 0) {
- std::cerr << "Alpha_complex_3d create_complex - no triangulation as points are on a 2d plane\n";
- return false; // ----- >>
- }
+ if (objects.size() == 0)
+ throw std::domain_error("Alpha_complex_3d create_complex - no triangulation as points are on a 2d plane");
using Alpha_value_iterator = typename std::vector<FT>::const_iterator;
Alpha_value_iterator alpha_value_iterator = alpha_values.begin();
@@ -559,7 +557,6 @@ Weighted_alpha_complex_3d::Weighted_point_3 wp0(Weighted_alpha_complex_3d::Bare_
// Remove all simplices that have a filtration value greater than max_alpha_square
complex.prune_above_filtration(max_alpha_square);
// --------------------------------------------------------------------------------------------
- return true;
}
/** \brief get_point returns the point corresponding to the vertex given as parameter.
diff --git a/src/Alpha_complex/test/Alpha_complex_3d_unit_test.cpp b/src/Alpha_complex/test/Alpha_complex_3d_unit_test.cpp
index a4ecb6ad..94021954 100644
--- a/src/Alpha_complex/test/Alpha_complex_3d_unit_test.cpp
+++ b/src/Alpha_complex/test/Alpha_complex_3d_unit_test.cpp
@@ -11,6 +11,7 @@
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE "alpha_complex_3d"
#include <boost/test/unit_test.hpp>
+#include <boost/mpl/list.hpp>
#include <cmath> // float comparison
#include <limits>
@@ -36,6 +37,7 @@ using Safe_alpha_complex_3d =
using Exact_alpha_complex_3d =
Gudhi::alpha_complex::Alpha_complex_3d<Gudhi::alpha_complex::complexity::EXACT, false, false>;
+
template <typename Point>
std::vector<Point> get_points() {
std::vector<Point> points;
@@ -197,3 +199,31 @@ BOOST_AUTO_TEST_CASE(Alpha_complex_3d_from_points) {
++safe_sh;
}
}
+
+typedef boost::mpl::list<Fast_alpha_complex_3d, Safe_alpha_complex_3d, Exact_alpha_complex_3d> list_of_alpha_variants;
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(Alpha_complex_3d_exceptions_points_on_plane, Alpha, list_of_alpha_variants) {
+ std::vector<typename Alpha::Bare_point_3> points_on_plane;
+ points_on_plane.emplace_back(1.0, 1.0 , 0.0);
+ points_on_plane.emplace_back(7.0, 0.0 , 0.0);
+ points_on_plane.emplace_back(4.0, 6.0 , 0.0);
+ points_on_plane.emplace_back(9.0, 6.0 , 0.0);
+ points_on_plane.emplace_back(0.0, 14.0, 0.0);
+ points_on_plane.emplace_back(2.0, 19.0, 0.0);
+ points_on_plane.emplace_back(9.0, 17.0, 0.0);
+
+ Alpha alpha_complex(points_on_plane);
+ Gudhi::Simplex_tree<> stree;
+
+ BOOST_CHECK_THROW(alpha_complex.create_complex(stree), std::domain_error);
+}
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(Alpha_complex_3d_exceptions_non_empty_simplex_tree, Alpha, list_of_alpha_variants) {
+ Alpha alpha_complex(get_points<typename Alpha::Bare_point_3>());
+ Gudhi::Simplex_tree<> stree;
+ stree.insert_simplex_and_subfaces({2,1,0}, 3.0);
+
+#ifdef GUDHI_DEBUG
+ BOOST_CHECK_THROW(alpha_complex.create_complex(stree), std::invalid_argument);
+#endif // GUDHI_DEBUG
+} \ No newline at end of file
diff --git a/src/Alpha_complex/test/Weighted_alpha_complex_unit_test.cpp b/src/Alpha_complex/test/Weighted_alpha_complex_unit_test.cpp
index 875704ee..4e1a38df 100644
--- a/src/Alpha_complex/test/Weighted_alpha_complex_unit_test.cpp
+++ b/src/Alpha_complex/test/Weighted_alpha_complex_unit_test.cpp
@@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(Weighted_alpha_complex_3d_comparison) {
// Weighted alpha complex for 3D version
Exact_weighted_alpha_complex_3d alpha_complex_3D_from_weighted_points(w_points_3);
Gudhi::Simplex_tree<> w_simplex_3;
- BOOST_CHECK(alpha_complex_3D_from_weighted_points.create_complex(w_simplex_3));
+ alpha_complex_3D_from_weighted_points.create_complex(w_simplex_3);
std::clog << "Iterator on weighted alpha complex 3D simplices in the filtration order, with [filtration value]:"
<< std::endl;
diff --git a/src/python/gudhi/alpha_complex_3d.pyx b/src/python/gudhi/alpha_complex_3d.pyx
index 4d3fe59c..40f1b43a 100644
--- a/src/python/gudhi/alpha_complex_3d.pyx
+++ b/src/python/gudhi/alpha_complex_3d.pyx
@@ -62,7 +62,7 @@ cdef class AlphaComplex3D:
def __init__(self, points=[], weights=[], precision='safe'):
"""AlphaComplex3D constructor.
- :param points: A list of points in d-Dimension.
+ :param points: A list of points in 3d.
:type points: Iterable[Iterable[float]]
:param weights: A list of weights. If set, the number of weights must correspond to the number of points.
@@ -118,6 +118,8 @@ cdef class AlphaComplex3D:
:type max_alpha_square: float
:returns: A simplex tree created from the Delaunay Triangulation.
:rtype: SimplexTree
+
+ :raises ValueError: If the points given at construction time are on a plane.
"""
stree = SimplexTree()
cdef double mas = max_alpha_square
diff --git a/src/python/test/test_alpha_complex.py b/src/python/test/test_alpha_complex.py
index b0f219e1..f15284f3 100755
--- a/src/python/test/test_alpha_complex.py
+++ b/src/python/test/test_alpha_complex.py
@@ -8,7 +8,7 @@
- YYYY/MM Author: Description of the modification
"""
-import gudhi as gd
+from gudhi import AlphaComplex
import math
import numpy as np
import pytest
@@ -21,17 +21,14 @@ except ImportError:
# python2
from itertools import izip_longest as zip_longest
-__author__ = "Vincent Rouvreau"
-__copyright__ = "Copyright (C) 2016 Inria"
-__license__ = "MIT"
def _empty_alpha(precision):
- alpha_complex = gd.AlphaComplex(precision = precision)
+ alpha_complex = AlphaComplex(precision = precision)
assert alpha_complex.__is_defined() == True
def _one_2d_point_alpha(precision):
- alpha_complex = gd.AlphaComplex(points=[[0, 0]], precision = precision)
+ alpha_complex = AlphaComplex(points=[[0, 0]], precision = precision)
assert alpha_complex.__is_defined() == True
def test_empty_alpha():
@@ -41,7 +38,7 @@ def test_empty_alpha():
def _infinite_alpha(precision):
point_list = [[0, 0], [1, 0], [0, 1], [1, 1]]
- alpha_complex = gd.AlphaComplex(points=point_list, precision = precision)
+ alpha_complex = AlphaComplex(points=point_list, precision = precision)
assert alpha_complex.__is_defined() == True
simplex_tree = alpha_complex.create_simplex_tree()
@@ -76,18 +73,9 @@ def _infinite_alpha(precision):
assert point_list[1] == alpha_complex.get_point(1)
assert point_list[2] == alpha_complex.get_point(2)
assert point_list[3] == alpha_complex.get_point(3)
- try:
- alpha_complex.get_point(4) == []
- except IndexError:
- pass
- else:
- assert False
- try:
- alpha_complex.get_point(125) == []
- except IndexError:
- pass
- else:
- assert False
+
+ with pytest.raises(IndexError):
+ alpha_complex.get_point(len(point_list))
def test_infinite_alpha():
for precision in ['fast', 'safe', 'exact']:
@@ -95,7 +83,7 @@ def test_infinite_alpha():
def _filtered_alpha(precision):
point_list = [[0, 0], [1, 0], [0, 1], [1, 1]]
- filtered_alpha = gd.AlphaComplex(points=point_list, precision = precision)
+ filtered_alpha = AlphaComplex(points=point_list, precision = precision)
simplex_tree = filtered_alpha.create_simplex_tree(max_alpha_square=0.25)
@@ -106,18 +94,9 @@ def _filtered_alpha(precision):
assert point_list[1] == filtered_alpha.get_point(1)
assert point_list[2] == filtered_alpha.get_point(2)
assert point_list[3] == filtered_alpha.get_point(3)
- try:
- filtered_alpha.get_point(4) == []
- except IndexError:
- pass
- else:
- assert False
- try:
- filtered_alpha.get_point(125) == []
- except IndexError:
- pass
- else:
- assert False
+
+ with pytest.raises(IndexError):
+ filtered_alpha.get_point(len(point_list))
assert list(simplex_tree.get_filtration()) == [
([0], 0.0),
@@ -148,10 +127,10 @@ def _safe_alpha_persistence_comparison(precision):
embedding2 = [[signal[i], delayed[i]] for i in range(len(time))]
#build alpha complex and simplex tree
- alpha_complex1 = gd.AlphaComplex(points=embedding1, precision = precision)
+ alpha_complex1 = AlphaComplex(points=embedding1, precision = precision)
simplex_tree1 = alpha_complex1.create_simplex_tree()
- alpha_complex2 = gd.AlphaComplex(points=embedding2, precision = precision)
+ alpha_complex2 = AlphaComplex(points=embedding2, precision = precision)
simplex_tree2 = alpha_complex2.create_simplex_tree()
diag1 = simplex_tree1.persistence()
@@ -169,7 +148,7 @@ def test_safe_alpha_persistence_comparison():
def _delaunay_complex(precision):
point_list = [[0, 0], [1, 0], [0, 1], [1, 1]]
- filtered_alpha = gd.AlphaComplex(points=point_list, precision = precision)
+ filtered_alpha = AlphaComplex(points=point_list, precision = precision)
simplex_tree = filtered_alpha.create_simplex_tree(default_filtration_value = True)
@@ -180,18 +159,11 @@ def _delaunay_complex(precision):
assert point_list[1] == filtered_alpha.get_point(1)
assert point_list[2] == filtered_alpha.get_point(2)
assert point_list[3] == filtered_alpha.get_point(3)
- try:
- filtered_alpha.get_point(4) == []
- except IndexError:
- pass
- else:
- assert False
- try:
- filtered_alpha.get_point(125) == []
- except IndexError:
- pass
- else:
- assert False
+
+ with pytest.raises(IndexError):
+ filtered_alpha.get_point(4)
+ with pytest.raises(IndexError):
+ filtered_alpha.get_point(125)
for filtered_value in simplex_tree.get_filtration():
assert math.isnan(filtered_value[1])
@@ -205,7 +177,7 @@ def test_delaunay_complex():
_delaunay_complex(precision)
def _3d_points_on_a_plane(precision, default_filtration_value):
- alpha = gd.AlphaComplex(points = [[1.0, 1.0 , 0.0],
+ alpha = AlphaComplex(points = [[1.0, 1.0 , 0.0],
[7.0, 0.0 , 0.0],
[4.0, 6.0 , 0.0],
[9.0, 6.0 , 0.0],
@@ -225,10 +197,10 @@ def test_3d_points_on_a_plane():
def _3d_tetrahedrons(precision):
points = 10*np.random.rand(10, 3)
- alpha = gd.AlphaComplex(points = points, precision = precision)
+ alpha = AlphaComplex(points = points, precision = precision)
st_alpha = alpha.create_simplex_tree(default_filtration_value = False)
# New AlphaComplex for get_point to work
- delaunay = gd.AlphaComplex(points = points, precision = precision)
+ delaunay = AlphaComplex(points = points, precision = precision)
st_delaunay = delaunay.create_simplex_tree(default_filtration_value = True)
delaunay_tetra = []
@@ -272,11 +244,12 @@ def test_off_file_deprecation_warning():
off_file.close()
with pytest.warns(DeprecationWarning):
- alpha = gd.AlphaComplex(off_file="alphacomplexdoc.off")
+ alpha = AlphaComplex(off_file="alphacomplexdoc.off")
def test_non_existing_off_file():
- with pytest.raises(FileNotFoundError):
- alpha = gd.AlphaComplex(off_file="pouetpouettralala.toubiloubabdou")
+ with pytest.warns(DeprecationWarning):
+ with pytest.raises(FileNotFoundError):
+ alpha = AlphaComplex(off_file="pouetpouettralala.toubiloubabdou")
def test_inconsistency_points_and_weights():
points = [[1.0, 1.0 , 0.0],
@@ -288,27 +261,27 @@ def test_inconsistency_points_and_weights():
[9.0, 17.0, 0.0]]
with pytest.raises(ValueError):
# 7 points, 8 weights, on purpose
- alpha = gd.AlphaComplex(points = points,
+ alpha = AlphaComplex(points = points,
weights = [1., 2., 3., 4., 5., 6., 7., 8.])
with pytest.raises(ValueError):
# 7 points, 6 weights, on purpose
- alpha = gd.AlphaComplex(points = points,
+ alpha = AlphaComplex(points = points,
weights = [1., 2., 3., 4., 5., 6.])
def _weighted_doc_example(precision):
- stree_from_values = gd.AlphaComplex(points=[[ 1., -1., -1.],
- [-1., 1., -1.],
- [-1., -1., 1.],
- [ 1., 1., 1.],
- [ 2., 2., 2.]],
- weights = [4., 4., 4., 4., 1.],
- precision = precision).create_simplex_tree()
-
- assert stree_from_values.filtration([0, 1, 2, 3]) == pytest.approx(-1.)
- assert stree_from_values.filtration([0, 1, 3, 4]) == pytest.approx(95.)
- assert stree_from_values.filtration([0, 2, 3, 4]) == pytest.approx(95.)
- assert stree_from_values.filtration([1, 2, 3, 4]) == pytest.approx(95.)
+ stree = AlphaComplex(points=[[ 1., -1., -1.],
+ [-1., 1., -1.],
+ [-1., -1., 1.],
+ [ 1., 1., 1.],
+ [ 2., 2., 2.]],
+ weights = [4., 4., 4., 4., 1.],
+ precision = precision).create_simplex_tree()
+
+ assert stree.filtration([0, 1, 2, 3]) == pytest.approx(-1.)
+ assert stree.filtration([0, 1, 3, 4]) == pytest.approx(95.)
+ assert stree.filtration([0, 2, 3, 4]) == pytest.approx(95.)
+ assert stree.filtration([1, 2, 3, 4]) == pytest.approx(95.)
def test_weighted_doc_example():
for precision in ['fast', 'safe', 'exact']:
diff --git a/src/python/test/test_alpha_complex_3d.py b/src/python/test/test_alpha_complex_3d.py
new file mode 100755
index 00000000..f7bd4fda
--- /dev/null
+++ b/src/python/test/test_alpha_complex_3d.py
@@ -0,0 +1,149 @@
+""" This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ Author(s): Vincent Rouvreau
+
+ Copyright (C) 2021 Inria
+
+ Modification(s):
+ - YYYY/MM Author: Description of the modification
+"""
+
+from gudhi import AlphaComplex3D
+import pytest
+
+try:
+ # python3
+ from itertools import zip_longest
+except ImportError:
+ # python2
+ from itertools import izip_longest as zip_longest
+
+
+
+def _empty_alpha(precision):
+ alpha_complex = AlphaComplex3D(precision = precision)
+ assert alpha_complex.__is_defined() == True
+
+def _one_3d_point_alpha(precision):
+ alpha_complex = AlphaComplex3D(points=[[0, 0, 0]], precision = precision)
+ assert alpha_complex.__is_defined() == True
+
+def test_empty_alpha():
+ for precision in ['fast', 'safe', 'exact']:
+ _empty_alpha(precision)
+ _one_3d_point_alpha(precision)
+
+def _infinite_alpha(precision):
+ point_list = [[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0], [0, 0, 1], [1, 0, 1], [0, 1, 1], [1, 1, 1]]
+ alpha_complex = AlphaComplex3D(points=point_list, precision = precision)
+ assert alpha_complex.__is_defined() == True
+
+ stree = alpha_complex.create_simplex_tree()
+ assert stree.__is_persistence_defined() == False
+
+ assert stree.num_simplices() == 51
+ assert stree.num_vertices() == len(point_list)
+
+ for filtration in stree.get_filtration():
+ if len(filtration[0]) == 1:
+ assert filtration[1] == 0.
+ if len(filtration[0]) == 4:
+ assert filtration[1] == 0.75
+
+ for idx in range(len(point_list)):
+ pt_idx = point_list.index(alpha_complex.get_point(idx))
+ assert pt_idx >= 0
+ assert pt_idx < len(point_list)
+
+ with pytest.raises(IndexError):
+ alpha_complex.get_point(len(point_list))
+
+def test_infinite_alpha():
+ for precision in ['fast', 'safe', 'exact']:
+ _infinite_alpha(precision)
+
+def _filtered_alpha(precision):
+ point_list = [[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0], [0, 0, 1], [1, 0, 1], [0, 1, 1], [1, 1, 1]]
+ filtered_alpha = AlphaComplex3D(points=point_list, precision = precision)
+
+ stree = filtered_alpha.create_simplex_tree(max_alpha_square=0.25)
+
+ assert stree.num_simplices() == 20
+ assert stree.num_vertices() == len(point_list)
+
+ for filtration in stree.get_filtration():
+ if len(filtration[0]) == 1:
+ assert filtration[1] == 0.
+ elif len(filtration[0]) == 2:
+ assert filtration[1] == 0.25
+ else:
+ assert False
+
+ for idx in range(len(point_list)):
+ pt_idx = point_list.index(filtered_alpha.get_point(idx))
+ assert pt_idx >= 0
+ assert pt_idx < len(point_list)
+
+ with pytest.raises(IndexError):
+ filtered_alpha.get_point(len(point_list))
+
+def test_filtered_alpha():
+ for precision in ['fast', 'safe', 'exact']:
+ _filtered_alpha(precision)
+
+def _3d_points_on_a_plane(precision):
+ alpha = AlphaComplex3D(points = [[1.0, 1.0 , 0.0],
+ [7.0, 0.0 , 0.0],
+ [4.0, 6.0 , 0.0],
+ [9.0, 6.0 , 0.0],
+ [0.0, 14.0, 0.0],
+ [2.0, 19.0, 0.0],
+ [9.0, 17.0, 0.0]], precision = precision)
+
+ with pytest.raises(ValueError):
+ stree = alpha.create_simplex_tree()
+
+def test_3d_points_on_a_plane():
+ for precision in ['fast', 'safe', 'exact']:
+ _3d_points_on_a_plane(precision)
+
+def test_inconsistency_points_and_weights():
+ points = [[1.0, 1.0 , 1.0],
+ [7.0, 0.0 , 2.0],
+ [4.0, 6.0 , 0.0],
+ [9.0, 6.0 , 1.0],
+ [0.0, 14.0, 2.0],
+ [2.0, 19.0, 0.0],
+ [9.0, 17.0, 1.0]]
+ with pytest.raises(ValueError):
+ # 7 points, 8 weights, on purpose
+ alpha = AlphaComplex3D(points = points,
+ weights = [1., 2., 3., 4., 5., 6., 7., 8.])
+
+ with pytest.raises(ValueError):
+ # 7 points, 6 weights, on purpose
+ alpha = AlphaComplex3D(points = points,
+ weights = [1., 2., 3., 4., 5., 6.])
+
+def _weighted_doc_example(precision):
+ pts = [[ 1., -1., -1.],
+ [-1., 1., -1.],
+ [-1., -1., 1.],
+ [ 1., 1., 1.],
+ [ 2., 2., 2.]]
+ wgts = [4., 4., 4., 4., 1.]
+ alpha = AlphaComplex3D(points = pts, weights = wgts, precision = precision)
+ stree = alpha.create_simplex_tree()
+
+ # Needs to retrieve points as points are shuffled
+ get_idx = lambda idx: pts.index(alpha.get_point(idx))
+ indices = [get_idx(x) for x in range(len(pts))]
+
+ assert stree.filtration([indices[x] for x in [0, 1, 2, 3]]) == pytest.approx(-1.)
+ assert stree.filtration([indices[x] for x in [0, 1, 3, 4]]) == pytest.approx(95.)
+ assert stree.filtration([indices[x] for x in [0, 2, 3, 4]]) == pytest.approx(95.)
+ assert stree.filtration([indices[x] for x in [1, 2, 3, 4]]) == pytest.approx(95.)
+
+def test_weighted_doc_example():
+ for precision in ['fast', 'safe', 'exact']:
+ _weighted_doc_example(precision)