From c7b82f49f01075519189f1fdb56cc485e4ad9f46 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 21 May 2020 11:08:25 +0200 Subject: Use unique_pointer and template alpha complex interface for python interface --- src/python/gudhi/alpha_complex.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/python/gudhi/alpha_complex.pyx') diff --git a/src/python/gudhi/alpha_complex.pyx b/src/python/gudhi/alpha_complex.pyx index d75e374a..2b7ce00d 100644 --- a/src/python/gudhi/alpha_complex.pyx +++ b/src/python/gudhi/alpha_complex.pyx @@ -26,7 +26,7 @@ __copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" cdef extern from "Alpha_complex_interface.h" namespace "Gudhi": - cdef cppclass Alpha_complex_interface "Gudhi::alpha_complex::Alpha_complex_interface": + cdef cppclass Alpha_complex_interface "Gudhi::alpha_complex::Alpha_complex_interface": Alpha_complex_interface(vector[vector[double]] points) nogil except + # bool from_file is a workaround for cython to find the correct signature Alpha_complex_interface(string off_file, bool from_file) nogil except + -- cgit v1.2.3 From 4826b8bf49aafb23c57eb6983c886235e8f7c0b2 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 22 May 2020 18:04:33 +0200 Subject: brute force version - complexity is read only --- src/python/gudhi/alpha_complex.pyx | 69 ++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 17 deletions(-) (limited to 'src/python/gudhi/alpha_complex.pyx') diff --git a/src/python/gudhi/alpha_complex.pyx b/src/python/gudhi/alpha_complex.pyx index 2b7ce00d..dc2fcb01 100644 --- a/src/python/gudhi/alpha_complex.pyx +++ b/src/python/gudhi/alpha_complex.pyx @@ -26,10 +26,18 @@ __copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" cdef extern from "Alpha_complex_interface.h" namespace "Gudhi": - cdef cppclass Alpha_complex_interface "Gudhi::alpha_complex::Alpha_complex_interface": - Alpha_complex_interface(vector[vector[double]] points) nogil except + + cdef cppclass Alpha_complex_exact_interface "Gudhi::alpha_complex::Alpha_complex_interface": + Alpha_complex_exact_interface(vector[vector[double]] points) nogil except + # bool from_file is a workaround for cython to find the correct signature - Alpha_complex_interface(string off_file, bool from_file) nogil except + + Alpha_complex_exact_interface(string off_file, bool from_file) nogil except + + vector[double] get_point(int vertex) nogil except + + void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square) nogil except + + +cdef extern from "Alpha_complex_interface.h" namespace "Gudhi": + cdef cppclass Alpha_complex_inexact_interface "Gudhi::alpha_complex::Alpha_complex_interface": + Alpha_complex_inexact_interface(vector[vector[double]] points) nogil except + + # bool from_file is a workaround for cython to find the correct signature + Alpha_complex_inexact_interface(string off_file, bool from_file) nogil except + vector[double] get_point(int vertex) nogil except + void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square) nogil except + @@ -53,10 +61,12 @@ cdef class AlphaComplex: """ - cdef Alpha_complex_interface * thisptr + cdef Alpha_complex_exact_interface * exact_ptr + cdef Alpha_complex_inexact_interface * inexact_ptr + complexity = 'safe' # Fake constructor that does nothing but documenting the constructor - def __init__(self, points=None, off_file=''): + def __init__(self, points=None, off_file='', complexity='safe'): """AlphaComplex constructor. :param points: A list of points in d-Dimension. @@ -66,15 +76,23 @@ cdef class AlphaComplex: :param off_file: An OFF file style name. :type off_file: string + + :param complexity: Alpha complex complexity can be 'fast', 'safe' or 'exact'. Default is 'safe'. + :type complexity: string """ # The real cython constructor - def __cinit__(self, points = None, off_file = ''): + def __cinit__(self, points = None, off_file = '', complexity = 'safe'): + assert complexity == 'fast' or complexity == 'safe' or complexity == 'exact', "Alpha complex complexity can be 'fast', 'safe' or 'exact'" + self.complexity = complexity + cdef vector[vector[double]] pts if off_file: if os.path.isfile(off_file): - self.thisptr = new Alpha_complex_interface( - off_file.encode('utf-8'), True) + if complexity == 'fast': + self.inexact_ptr = new Alpha_complex_inexact_interface(off_file.encode('utf-8'), True) + else: + self.exact_ptr = new Alpha_complex_exact_interface(off_file.encode('utf-8'), True) else: print("file " + off_file + " not found.") else: @@ -82,18 +100,28 @@ cdef class AlphaComplex: # Empty Alpha construction points=[] pts = points - with nogil: - self.thisptr = new Alpha_complex_interface(pts) - + if complexity == 'fast': + with nogil: + self.inexact_ptr = new Alpha_complex_inexact_interface(pts) + else: + with nogil: + self.exact_ptr = new Alpha_complex_exact_interface(pts) def __dealloc__(self): - if self.thisptr != NULL: - del self.thisptr + if self.complexity == 'fast': + if self.inexact_ptr != NULL: + del self.inexact_ptr + else: + if self.exact_ptr != NULL: + del self.exact_ptr def __is_defined(self): """Returns true if AlphaComplex pointer is not NULL. """ - return self.thisptr != NULL + if self.complexity == 'fast': + return self.inexact_ptr != NULL + else: + return self.exact_ptr != NULL def get_point(self, vertex): """This function returns the point corresponding to a given vertex. @@ -103,7 +131,10 @@ cdef class AlphaComplex: :rtype: list of float :returns: the point. """ - return self.thisptr.get_point(vertex) + if self.complexity == 'fast': + return self.inexact_ptr.get_point(vertex) + else: + return self.exact_ptr.get_point(vertex) def create_simplex_tree(self, max_alpha_square = float('inf')): """ @@ -118,6 +149,10 @@ cdef class AlphaComplex: stree = SimplexTree() cdef double mas = max_alpha_square cdef intptr_t stree_int_ptr=stree.thisptr - with nogil: - self.thisptr.create_simplex_tree(stree_int_ptr, mas) + if self.complexity == 'fast': + with nogil: + self.inexact_ptr.create_simplex_tree(stree_int_ptr, mas) + else: + with nogil: + self.exact_ptr.create_simplex_tree(stree_int_ptr, mas) return stree -- cgit v1.2.3 From 28a6889dc9865c75acc3d3be4edce01b3942e56f Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Sat, 23 May 2020 08:45:13 +0200 Subject: First working version --- src/python/gudhi/alpha_complex.pyx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'src/python/gudhi/alpha_complex.pyx') diff --git a/src/python/gudhi/alpha_complex.pyx b/src/python/gudhi/alpha_complex.pyx index dc2fcb01..e2d3db9c 100644 --- a/src/python/gudhi/alpha_complex.pyx +++ b/src/python/gudhi/alpha_complex.pyx @@ -63,7 +63,8 @@ cdef class AlphaComplex: cdef Alpha_complex_exact_interface * exact_ptr cdef Alpha_complex_inexact_interface * inexact_ptr - complexity = 'safe' + cdef bool fast + cdef bool exact # Fake constructor that does nothing but documenting the constructor def __init__(self, points=None, off_file='', complexity='safe'): @@ -84,12 +85,13 @@ cdef class AlphaComplex: # The real cython constructor def __cinit__(self, points = None, off_file = '', complexity = 'safe'): assert complexity == 'fast' or complexity == 'safe' or complexity == 'exact', "Alpha complex complexity can be 'fast', 'safe' or 'exact'" - self.complexity = complexity + self.fast = complexity == 'fast' + self.exact = complexity == 'safe' cdef vector[vector[double]] pts if off_file: if os.path.isfile(off_file): - if complexity == 'fast': + if self.fast: self.inexact_ptr = new Alpha_complex_inexact_interface(off_file.encode('utf-8'), True) else: self.exact_ptr = new Alpha_complex_exact_interface(off_file.encode('utf-8'), True) @@ -100,7 +102,7 @@ cdef class AlphaComplex: # Empty Alpha construction points=[] pts = points - if complexity == 'fast': + if self.fast: with nogil: self.inexact_ptr = new Alpha_complex_inexact_interface(pts) else: @@ -108,7 +110,7 @@ cdef class AlphaComplex: self.exact_ptr = new Alpha_complex_exact_interface(pts) def __dealloc__(self): - if self.complexity == 'fast': + if self.fast: if self.inexact_ptr != NULL: del self.inexact_ptr else: @@ -118,7 +120,7 @@ cdef class AlphaComplex: def __is_defined(self): """Returns true if AlphaComplex pointer is not NULL. """ - if self.complexity == 'fast': + if self.fast: return self.inexact_ptr != NULL else: return self.exact_ptr != NULL @@ -131,7 +133,7 @@ cdef class AlphaComplex: :rtype: list of float :returns: the point. """ - if self.complexity == 'fast': + if self.fast: return self.inexact_ptr.get_point(vertex) else: return self.exact_ptr.get_point(vertex) @@ -149,7 +151,7 @@ cdef class AlphaComplex: stree = SimplexTree() cdef double mas = max_alpha_square cdef intptr_t stree_int_ptr=stree.thisptr - if self.complexity == 'fast': + if self.fast: with nogil: self.inexact_ptr.create_simplex_tree(stree_int_ptr, mas) else: -- cgit v1.2.3 From 50b460f867b5801ce3459d60fb86b02051eb4a7d Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Sat, 23 May 2020 09:52:24 +0200 Subject: Delaunay complex and tests all possibilities --- src/python/gudhi/alpha_complex.pyx | 22 ++++---- src/python/include/Alpha_complex_interface.h | 5 +- src/python/test/test_alpha_complex.py | 75 ++++++++++++++++++++++++---- 3 files changed, 82 insertions(+), 20 deletions(-) (limited to 'src/python/gudhi/alpha_complex.pyx') diff --git a/src/python/gudhi/alpha_complex.pyx b/src/python/gudhi/alpha_complex.pyx index e2d3db9c..700fa738 100644 --- a/src/python/gudhi/alpha_complex.pyx +++ b/src/python/gudhi/alpha_complex.pyx @@ -31,7 +31,7 @@ cdef extern from "Alpha_complex_interface.h" namespace "Gudhi": # bool from_file is a workaround for cython to find the correct signature Alpha_complex_exact_interface(string off_file, bool from_file) nogil except + vector[double] get_point(int vertex) nogil except + - void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square) nogil except + + void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square, bool exact_version, bool default_filtration_value) nogil except + cdef extern from "Alpha_complex_interface.h" namespace "Gudhi": cdef cppclass Alpha_complex_inexact_interface "Gudhi::alpha_complex::Alpha_complex_interface": @@ -39,7 +39,7 @@ cdef extern from "Alpha_complex_interface.h" namespace "Gudhi": # bool from_file is a workaround for cython to find the correct signature Alpha_complex_inexact_interface(string off_file, bool from_file) nogil except + vector[double] get_point(int vertex) nogil except + - void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square) nogil except + + void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square, bool exact_version, bool default_filtration_value) nogil except + # AlphaComplex python interface cdef class AlphaComplex: @@ -138,23 +138,27 @@ cdef class AlphaComplex: else: return self.exact_ptr.get_point(vertex) - def create_simplex_tree(self, max_alpha_square = float('inf')): + def create_simplex_tree(self, max_alpha_square = float('inf'), default_filtration_value = False): """ - :param max_alpha_square: The maximum alpha square threshold the - simplices shall not exceed. Default is set to infinity, and - there is very little point using anything else since it does - not save time. + :param max_alpha_square: The maximum alpha square threshold the simplices shall not exceed. Default is set to + infinity, and there is very little point using anything else since it does not save time. :type max_alpha_square: float + :param default_filtration_value: Set this value to `True` if filtration values are not needed to be computed + (will be set to `NaN`). Default value is `False` (which means compute the filtration values). + :type default_filtration_value: bool :returns: A simplex tree created from the Delaunay Triangulation. :rtype: SimplexTree """ stree = SimplexTree() cdef double mas = max_alpha_square cdef intptr_t stree_int_ptr=stree.thisptr + cdef bool compute_filtration = default_filtration_value == True if self.fast: with nogil: - self.inexact_ptr.create_simplex_tree(stree_int_ptr, mas) + self.inexact_ptr.create_simplex_tree(stree_int_ptr, + mas, False, compute_filtration) else: with nogil: - self.exact_ptr.create_simplex_tree(stree_int_ptr, mas) + self.exact_ptr.create_simplex_tree(stree_int_ptr, + mas, self.exact, compute_filtration) return stree diff --git a/src/python/include/Alpha_complex_interface.h b/src/python/include/Alpha_complex_interface.h index 5fb694cd..3dd01345 100644 --- a/src/python/include/Alpha_complex_interface.h +++ b/src/python/include/Alpha_complex_interface.h @@ -56,8 +56,9 @@ class Alpha_complex_interface { return vd; } - void create_simplex_tree(Simplex_tree_interface<>* simplex_tree, double max_alpha_square) { - alpha_complex_->create_complex(*simplex_tree, max_alpha_square); + void create_simplex_tree(Simplex_tree_interface<>* simplex_tree, double max_alpha_square, + bool exact_version, bool default_filtration_value) { + alpha_complex_->create_complex(*simplex_tree, max_alpha_square, exact_version, default_filtration_value); } private: diff --git a/src/python/test/test_alpha_complex.py b/src/python/test/test_alpha_complex.py index 77121302..913397dd 100755 --- a/src/python/test/test_alpha_complex.py +++ b/src/python/test/test_alpha_complex.py @@ -24,14 +24,18 @@ __copyright__ = "Copyright (C) 2016 Inria" __license__ = "MIT" -def test_empty_alpha(): - alpha_complex = AlphaComplex(points=[[0, 0]]) +def _empty_alpha(complexity): + alpha_complex = AlphaComplex(points=[[0, 0]], complexity = complexity) assert alpha_complex.__is_defined() == True +def test_empty_alpha(): + _empty_alpha('fast') + _empty_alpha('safe') + _empty_alpha('exact') -def test_infinite_alpha(): +def _infinite_alpha(complexity): point_list = [[0, 0], [1, 0], [0, 1], [1, 1]] - alpha_complex = AlphaComplex(points=point_list) + alpha_complex = AlphaComplex(points=point_list, complexity = complexity) assert alpha_complex.__is_defined() == True simplex_tree = alpha_complex.create_simplex_tree() @@ -79,10 +83,14 @@ def test_infinite_alpha(): else: assert False +def test_infinite_alpha(): + _infinite_alpha('fast') + _infinite_alpha('safe') + _infinite_alpha('exact') -def test_filtered_alpha(): +def _filtered_alpha(complexity): point_list = [[0, 0], [1, 0], [0, 1], [1, 1]] - filtered_alpha = AlphaComplex(points=point_list) + filtered_alpha = AlphaComplex(points=point_list, complexity = complexity) simplex_tree = filtered_alpha.create_simplex_tree(max_alpha_square=0.25) @@ -119,7 +127,12 @@ def test_filtered_alpha(): assert simplex_tree.get_star([0]) == [([0], 0.0), ([0, 1], 0.25), ([0, 2], 0.25)] assert simplex_tree.get_cofaces([0], 1) == [([0, 1], 0.25), ([0, 2], 0.25)] -def test_safe_alpha_persistence_comparison(): +def test_filtered_alpha(): + _filtered_alpha('fast') + _filtered_alpha('safe') + _filtered_alpha('exact') + +def _safe_alpha_persistence_comparison(complexity): #generate periodic signal time = np.arange(0, 10, 1) signal = [math.sin(x) for x in time] @@ -131,10 +144,10 @@ def test_safe_alpha_persistence_comparison(): embedding2 = [[signal[i], delayed[i]] for i in range(len(time))] #build alpha complex and simplex tree - alpha_complex1 = AlphaComplex(points=embedding1) + alpha_complex1 = AlphaComplex(points=embedding1, complexity = complexity) simplex_tree1 = alpha_complex1.create_simplex_tree() - alpha_complex2 = AlphaComplex(points=embedding2) + alpha_complex2 = AlphaComplex(points=embedding2, complexity = complexity) simplex_tree2 = alpha_complex2.create_simplex_tree() diag1 = simplex_tree1.persistence() @@ -143,3 +156,47 @@ def test_safe_alpha_persistence_comparison(): for (first_p, second_p) in zip_longest(diag1, diag2): assert first_p[0] == pytest.approx(second_p[0]) assert first_p[1] == pytest.approx(second_p[1]) + + +def test_safe_alpha_persistence_comparison(): + # Won't work for 'fast' version + _safe_alpha_persistence_comparison('safe') + _safe_alpha_persistence_comparison('exact') + +def _delaunay_complex(complexity): + point_list = [[0, 0], [1, 0], [0, 1], [1, 1]] + filtered_alpha = AlphaComplex(points=point_list, complexity = complexity) + + simplex_tree = filtered_alpha.create_simplex_tree(default_filtration_value = True) + + assert simplex_tree.num_simplices() == 11 + assert simplex_tree.num_vertices() == 4 + + assert point_list[0] == filtered_alpha.get_point(0) + 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 + + for filtered_value in simplex_tree.get_filtration(): + assert math.isnan(filtered_value[1]) + for filtered_value in simplex_tree.get_star([0]): + assert math.isnan(filtered_value[1]) + for filtered_value in simplex_tree.get_cofaces([0], 1): + assert math.isnan(filtered_value[1]) + +def test_delaunay_complex(): + _delaunay_complex('fast') + _delaunay_complex('safe') + _delaunay_complex('exact') -- cgit v1.2.3 From 78fb7ccd413ca655bdbe4adc9b4b256f20e11fe5 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Sun, 24 May 2020 10:16:58 +0200 Subject: c++ version to trigger exact/inexact kernel --- src/python/gudhi/alpha_complex.pyx | 59 ++++++---------------- src/python/include/Alpha_complex_interface.h | 73 ++++++++++++++++++++-------- 2 files changed, 68 insertions(+), 64 deletions(-) (limited to 'src/python/gudhi/alpha_complex.pyx') diff --git a/src/python/gudhi/alpha_complex.pyx b/src/python/gudhi/alpha_complex.pyx index 700fa738..5bc9ebc4 100644 --- a/src/python/gudhi/alpha_complex.pyx +++ b/src/python/gudhi/alpha_complex.pyx @@ -26,18 +26,10 @@ __copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" cdef extern from "Alpha_complex_interface.h" namespace "Gudhi": - cdef cppclass Alpha_complex_exact_interface "Gudhi::alpha_complex::Alpha_complex_interface": - Alpha_complex_exact_interface(vector[vector[double]] points) nogil except + + cdef cppclass Alpha_complex_interface "Gudhi::alpha_complex::Alpha_complex_interface": + Alpha_complex_interface(vector[vector[double]] points, bool fast_version) nogil except + # bool from_file is a workaround for cython to find the correct signature - Alpha_complex_exact_interface(string off_file, bool from_file) nogil except + - vector[double] get_point(int vertex) nogil except + - void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square, bool exact_version, bool default_filtration_value) nogil except + - -cdef extern from "Alpha_complex_interface.h" namespace "Gudhi": - cdef cppclass Alpha_complex_inexact_interface "Gudhi::alpha_complex::Alpha_complex_interface": - Alpha_complex_inexact_interface(vector[vector[double]] points) nogil except + - # bool from_file is a workaround for cython to find the correct signature - Alpha_complex_inexact_interface(string off_file, bool from_file) nogil except + + Alpha_complex_interface(string off_file, bool fast_version, bool from_file) nogil except + vector[double] get_point(int vertex) nogil except + void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square, bool exact_version, bool default_filtration_value) nogil except + @@ -61,8 +53,7 @@ cdef class AlphaComplex: """ - cdef Alpha_complex_exact_interface * exact_ptr - cdef Alpha_complex_inexact_interface * inexact_ptr + cdef Alpha_complex_interface * this_ptr cdef bool fast cdef bool exact @@ -91,10 +82,7 @@ cdef class AlphaComplex: cdef vector[vector[double]] pts if off_file: if os.path.isfile(off_file): - if self.fast: - self.inexact_ptr = new Alpha_complex_inexact_interface(off_file.encode('utf-8'), True) - else: - self.exact_ptr = new Alpha_complex_exact_interface(off_file.encode('utf-8'), True) + self.this_ptr = new Alpha_complex_interface(off_file.encode('utf-8'), self.fast, True) else: print("file " + off_file + " not found.") else: @@ -102,28 +90,17 @@ cdef class AlphaComplex: # Empty Alpha construction points=[] pts = points - if self.fast: - with nogil: - self.inexact_ptr = new Alpha_complex_inexact_interface(pts) - else: - with nogil: - self.exact_ptr = new Alpha_complex_exact_interface(pts) + with nogil: + self.this_ptr = new Alpha_complex_interface(pts, self.fast) def __dealloc__(self): - if self.fast: - if self.inexact_ptr != NULL: - del self.inexact_ptr - else: - if self.exact_ptr != NULL: - del self.exact_ptr + if self.this_ptr != NULL: + del self.this_ptr def __is_defined(self): """Returns true if AlphaComplex pointer is not NULL. """ - if self.fast: - return self.inexact_ptr != NULL - else: - return self.exact_ptr != NULL + return self.this_ptr != NULL def get_point(self, vertex): """This function returns the point corresponding to a given vertex. @@ -133,10 +110,7 @@ cdef class AlphaComplex: :rtype: list of float :returns: the point. """ - if self.fast: - return self.inexact_ptr.get_point(vertex) - else: - return self.exact_ptr.get_point(vertex) + return self.this_ptr.get_point(vertex) def create_simplex_tree(self, max_alpha_square = float('inf'), default_filtration_value = False): """ @@ -153,12 +127,7 @@ cdef class AlphaComplex: cdef double mas = max_alpha_square cdef intptr_t stree_int_ptr=stree.thisptr cdef bool compute_filtration = default_filtration_value == True - if self.fast: - with nogil: - self.inexact_ptr.create_simplex_tree(stree_int_ptr, - mas, False, compute_filtration) - else: - with nogil: - self.exact_ptr.create_simplex_tree(stree_int_ptr, - mas, self.exact, compute_filtration) + with nogil: + self.this_ptr.create_simplex_tree(stree_int_ptr, + mas, self.exact, compute_filtration) return stree diff --git a/src/python/include/Alpha_complex_interface.h b/src/python/include/Alpha_complex_interface.h index 3dd01345..46f2ba03 100644 --- a/src/python/include/Alpha_complex_interface.h +++ b/src/python/include/Alpha_complex_interface.h @@ -29,40 +29,75 @@ namespace Gudhi { namespace alpha_complex { -using Exact_kernel = CGAL::Epeck_d< CGAL::Dynamic_dimension_tag >; -using Inexact_kernel = CGAL::Epick_d< CGAL::Dynamic_dimension_tag >; - -template class Alpha_complex_interface { - using Point_d = typename Kernel::Point_d; + private: + using Exact_kernel = CGAL::Epeck_d< CGAL::Dynamic_dimension_tag >; + using Inexact_kernel = CGAL::Epick_d< CGAL::Dynamic_dimension_tag >; + using Point_exact_kernel = typename Exact_kernel::Point_d; + using Point_inexact_kernel = typename Inexact_kernel::Point_d; + + template + std::vector pt_cgal_to_cython(CgalPointType& ph) { + std::vector vd; + for (auto coord = ph.cartesian_begin(); coord != ph.cartesian_end(); coord++) + vd.push_back(CGAL::to_double(*coord)); + return vd; + } + + template + CgalPointType pt_cython_to_cgal(std::vector const& vec) { + return CgalPointType(vec.size(), vec.begin(), vec.end()); + } public: - Alpha_complex_interface(const std::vector>& points) { - auto mkpt = [](std::vector const& vec){ - return Point_d(vec.size(), vec.begin(), vec.end()); - }; - alpha_complex_ = std::make_unique>(boost::adaptors::transform(points, mkpt)); + Alpha_complex_interface(const std::vector>& points, bool fast_version) + : fast_version_(fast_version) { + auto pt = pt_cython_to_cgal(points[0]); + if (fast_version_) { + auto mkpt = [](std::vector const& vec) { + return Point_inexact_kernel(vec.size(), vec.begin(), vec.end()); + }; + ac_inexact_ptr_ = std::make_unique>(boost::adaptors::transform(points, mkpt)); + //ac_inexact_ptr_ = std::make_unique>(boost::adaptors::transform(points, pt_cython_to_cgal)); + } else { + auto mkpt = [](std::vector const& vec) { + return Point_exact_kernel(vec.size(), vec.begin(), vec.end()); + }; + ac_exact_ptr_ = std::make_unique>(boost::adaptors::transform(points, mkpt)); + //ac_exact_ptr_ = std::make_unique>(boost::adaptors::transform(points, pt_cython_to_cgal)); + } } - Alpha_complex_interface(const std::string& off_file_name, bool from_file = true) { - alpha_complex_ = std::make_unique>(off_file_name); + Alpha_complex_interface(const std::string& off_file_name, bool fast_version, bool from_file = true) + : fast_version_(fast_version) { + if (fast_version_) + ac_inexact_ptr_ = std::make_unique>(off_file_name); + else + ac_exact_ptr_ = std::make_unique>(off_file_name); } std::vector get_point(int vh) { - std::vector vd; - Point_d const& ph = alpha_complex_->get_point(vh); - for (auto coord = ph.cartesian_begin(); coord != ph.cartesian_end(); coord++) - vd.push_back(CGAL::to_double(*coord)); - return vd; + if (fast_version_) { + Point_inexact_kernel const& ph = ac_inexact_ptr_->get_point(vh); + return pt_cgal_to_cython(ph); + } else { + Point_exact_kernel const& ph = ac_exact_ptr_->get_point(vh); + return pt_cgal_to_cython(ph); + } } void create_simplex_tree(Simplex_tree_interface<>* simplex_tree, double max_alpha_square, bool exact_version, bool default_filtration_value) { - alpha_complex_->create_complex(*simplex_tree, max_alpha_square, exact_version, default_filtration_value); + if (fast_version_) + ac_inexact_ptr_->create_complex(*simplex_tree, max_alpha_square, exact_version, default_filtration_value); + else + ac_exact_ptr_->create_complex(*simplex_tree, max_alpha_square, exact_version, default_filtration_value); } private: - std::unique_ptr> alpha_complex_; + bool fast_version_; + std::unique_ptr> ac_exact_ptr_; + std::unique_ptr> ac_inexact_ptr_; }; } // namespace alpha_complex -- cgit v1.2.3 From a4598f043824db493369d3e78048139988bde9aa Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau <10407034+VincentRouvreau@users.noreply.github.com> Date: Fri, 5 Jun 2020 17:59:37 +0200 Subject: Update src/python/gudhi/alpha_complex.pyx Co-authored-by: Marc Glisse --- src/python/gudhi/alpha_complex.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/python/gudhi/alpha_complex.pyx') diff --git a/src/python/gudhi/alpha_complex.pyx b/src/python/gudhi/alpha_complex.pyx index 5bc9ebc4..80e54da0 100644 --- a/src/python/gudhi/alpha_complex.pyx +++ b/src/python/gudhi/alpha_complex.pyx @@ -75,7 +75,7 @@ cdef class AlphaComplex: # The real cython constructor def __cinit__(self, points = None, off_file = '', complexity = 'safe'): - assert complexity == 'fast' or complexity == 'safe' or complexity == 'exact', "Alpha complex complexity can be 'fast', 'safe' or 'exact'" + assert complexity in ['fast', 'safe', 'exact'], "Alpha complex complexity can only be 'fast', 'safe' or 'exact'" self.fast = complexity == 'fast' self.exact = complexity == 'safe' -- cgit v1.2.3 From 58cb456a33b4eec8ecc926457668d7d77d6662c3 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 5 Jun 2020 18:23:02 +0200 Subject: Code review: 'fast' class attribute was not necessary and redundant with C++ class attribute --- src/python/gudhi/alpha_complex.pyx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/python/gudhi/alpha_complex.pyx') diff --git a/src/python/gudhi/alpha_complex.pyx b/src/python/gudhi/alpha_complex.pyx index 80e54da0..3855f1ac 100644 --- a/src/python/gudhi/alpha_complex.pyx +++ b/src/python/gudhi/alpha_complex.pyx @@ -54,7 +54,6 @@ cdef class AlphaComplex: """ cdef Alpha_complex_interface * this_ptr - cdef bool fast cdef bool exact # Fake constructor that does nothing but documenting the constructor @@ -76,13 +75,13 @@ cdef class AlphaComplex: # The real cython constructor def __cinit__(self, points = None, off_file = '', complexity = 'safe'): assert complexity in ['fast', 'safe', 'exact'], "Alpha complex complexity can only be 'fast', 'safe' or 'exact'" - self.fast = complexity == 'fast' + cdef bool fast = complexity == 'fast' self.exact = complexity == 'safe' cdef vector[vector[double]] pts if off_file: if os.path.isfile(off_file): - self.this_ptr = new Alpha_complex_interface(off_file.encode('utf-8'), self.fast, True) + self.this_ptr = new Alpha_complex_interface(off_file.encode('utf-8'), fast, True) else: print("file " + off_file + " not found.") else: @@ -91,7 +90,7 @@ cdef class AlphaComplex: points=[] pts = points with nogil: - self.this_ptr = new Alpha_complex_interface(pts, self.fast) + self.this_ptr = new Alpha_complex_interface(pts, fast) def __dealloc__(self): if self.this_ptr != NULL: -- cgit v1.2.3 From 4f02ba9c5a3233ff9d4554578fbe3ae456b9711f Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 5 Jun 2020 18:44:17 +0200 Subject: code review: rename complexity with precision --- src/python/doc/alpha_complex_user.rst | 8 ++++---- src/python/gudhi/alpha_complex.pyx | 14 +++++++------- src/python/test/test_alpha_complex.py | 22 +++++++++++----------- 3 files changed, 22 insertions(+), 22 deletions(-) (limited to 'src/python/gudhi/alpha_complex.pyx') diff --git a/src/python/doc/alpha_complex_user.rst b/src/python/doc/alpha_complex_user.rst index bc9fe513..e8b4f25e 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -23,14 +23,14 @@ Remarks equivalent to the `Čech complex `_ and much smaller if you do not bound the radii. `Čech complex `_ can still make sense in higher dimension precisely because you can bound the radii. -* Using the default :code:`complexity = 'safe'` makes the construction safe. - If you pass :code:`complexity = 'exact'` to :func:`~gudhi.AlphaComplex.__init__`, the filtration values are the exact +* Using the default :code:`precision = 'safe'` makes the construction safe. + If you pass :code:`precision = 'exact'` to :func:`~gudhi.AlphaComplex.__init__`, the filtration values are the exact ones converted to float. This can be very slow. - If you pass :code:`complexity = 'safe'` (the default), the filtration values are only + If you pass :code:`precision = 'safe'` (the default), the filtration values are only guaranteed to have a small multiplicative error compared to the exact value. A drawback, when computing persistence, is that an empty exact interval [10^12,10^12] may become a non-empty approximate interval [10^12,10^12+10^6]. - Using :code:`complexity = 'fast'` makes the computations slightly faster, and the combinatorics are still exact, but + Using :code:`precision = 'fast'` makes the computations slightly faster, and the combinatorics are still exact, but the computation of filtration values can exceptionally be arbitrarily bad. In all cases, we still guarantee that the output is a valid filtration (faces have a filtration value no larger than their cofaces). * For performances reasons, it is advised to use Alpha_complex with `CGAL `_ :math:`\geq` 5.0.0. diff --git a/src/python/gudhi/alpha_complex.pyx b/src/python/gudhi/alpha_complex.pyx index 3855f1ac..d9c2be81 100644 --- a/src/python/gudhi/alpha_complex.pyx +++ b/src/python/gudhi/alpha_complex.pyx @@ -57,7 +57,7 @@ cdef class AlphaComplex: cdef bool exact # Fake constructor that does nothing but documenting the constructor - def __init__(self, points=None, off_file='', complexity='safe'): + def __init__(self, points=None, off_file='', precision='safe'): """AlphaComplex constructor. :param points: A list of points in d-Dimension. @@ -68,15 +68,15 @@ cdef class AlphaComplex: :param off_file: An OFF file style name. :type off_file: string - :param complexity: Alpha complex complexity can be 'fast', 'safe' or 'exact'. Default is 'safe'. - :type complexity: string + :param precision: Alpha complex precision can be 'fast', 'safe' or 'exact'. Default is 'safe'. + :type precision: string """ # The real cython constructor - def __cinit__(self, points = None, off_file = '', complexity = 'safe'): - assert complexity in ['fast', 'safe', 'exact'], "Alpha complex complexity can only be 'fast', 'safe' or 'exact'" - cdef bool fast = complexity == 'fast' - self.exact = complexity == 'safe' + def __cinit__(self, points = None, off_file = '', precision = 'safe'): + assert precision in ['fast', 'safe', 'exact'], "Alpha complex precision can only be 'fast', 'safe' or 'exact'" + cdef bool fast = precision == 'fast' + self.exact = precision == 'safe' cdef vector[vector[double]] pts if off_file: diff --git a/src/python/test/test_alpha_complex.py b/src/python/test/test_alpha_complex.py index 913397dd..943ad2c4 100755 --- a/src/python/test/test_alpha_complex.py +++ b/src/python/test/test_alpha_complex.py @@ -24,8 +24,8 @@ __copyright__ = "Copyright (C) 2016 Inria" __license__ = "MIT" -def _empty_alpha(complexity): - alpha_complex = AlphaComplex(points=[[0, 0]], complexity = complexity) +def _empty_alpha(precision): + alpha_complex = AlphaComplex(points=[[0, 0]], precision = precision) assert alpha_complex.__is_defined() == True def test_empty_alpha(): @@ -33,9 +33,9 @@ def test_empty_alpha(): _empty_alpha('safe') _empty_alpha('exact') -def _infinite_alpha(complexity): +def _infinite_alpha(precision): point_list = [[0, 0], [1, 0], [0, 1], [1, 1]] - alpha_complex = AlphaComplex(points=point_list, complexity = complexity) + alpha_complex = AlphaComplex(points=point_list, precision = precision) assert alpha_complex.__is_defined() == True simplex_tree = alpha_complex.create_simplex_tree() @@ -88,9 +88,9 @@ def test_infinite_alpha(): _infinite_alpha('safe') _infinite_alpha('exact') -def _filtered_alpha(complexity): +def _filtered_alpha(precision): point_list = [[0, 0], [1, 0], [0, 1], [1, 1]] - filtered_alpha = AlphaComplex(points=point_list, complexity = complexity) + filtered_alpha = AlphaComplex(points=point_list, precision = precision) simplex_tree = filtered_alpha.create_simplex_tree(max_alpha_square=0.25) @@ -132,7 +132,7 @@ def test_filtered_alpha(): _filtered_alpha('safe') _filtered_alpha('exact') -def _safe_alpha_persistence_comparison(complexity): +def _safe_alpha_persistence_comparison(precision): #generate periodic signal time = np.arange(0, 10, 1) signal = [math.sin(x) for x in time] @@ -144,10 +144,10 @@ def _safe_alpha_persistence_comparison(complexity): embedding2 = [[signal[i], delayed[i]] for i in range(len(time))] #build alpha complex and simplex tree - alpha_complex1 = AlphaComplex(points=embedding1, complexity = complexity) + alpha_complex1 = AlphaComplex(points=embedding1, precision = precision) simplex_tree1 = alpha_complex1.create_simplex_tree() - alpha_complex2 = AlphaComplex(points=embedding2, complexity = complexity) + alpha_complex2 = AlphaComplex(points=embedding2, precision = precision) simplex_tree2 = alpha_complex2.create_simplex_tree() diag1 = simplex_tree1.persistence() @@ -163,9 +163,9 @@ def test_safe_alpha_persistence_comparison(): _safe_alpha_persistence_comparison('safe') _safe_alpha_persistence_comparison('exact') -def _delaunay_complex(complexity): +def _delaunay_complex(precision): point_list = [[0, 0], [1, 0], [0, 1], [1, 1]] - filtered_alpha = AlphaComplex(points=point_list, complexity = complexity) + filtered_alpha = AlphaComplex(points=point_list, precision = precision) simplex_tree = filtered_alpha.create_simplex_tree(default_filtration_value = True) -- cgit v1.2.3 From 19dc69e6edaac076da5138fe091be367a3652057 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 5 Jun 2020 22:28:03 +0200 Subject: code review: exact version was not correct --- src/python/gudhi/alpha_complex.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/python/gudhi/alpha_complex.pyx') diff --git a/src/python/gudhi/alpha_complex.pyx b/src/python/gudhi/alpha_complex.pyx index d9c2be81..a356384d 100644 --- a/src/python/gudhi/alpha_complex.pyx +++ b/src/python/gudhi/alpha_complex.pyx @@ -76,7 +76,7 @@ cdef class AlphaComplex: def __cinit__(self, points = None, off_file = '', precision = 'safe'): assert precision in ['fast', 'safe', 'exact'], "Alpha complex precision can only be 'fast', 'safe' or 'exact'" cdef bool fast = precision == 'fast' - self.exact = precision == 'safe' + self.exact = precision == 'exact' cdef vector[vector[double]] pts if off_file: -- cgit v1.2.3 From 10ca6a70ba7ffea5c65d9c045b624da3d4200a63 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 15 Jun 2020 07:52:15 +0200 Subject: Factory to build python alpha complex. 3d version of alpha complex. Needs change in doc as alphacomplexdoc.off is a fake 3d off data file --- src/python/doc/alpha_complex_user.rst | 47 ++------- src/python/gudhi/alpha_complex.pyx | 27 +++-- src/python/include/Alpha_complex_factory.h | 144 +++++++++++++++++++++++++++ src/python/include/Alpha_complex_interface.h | 74 ++++---------- 4 files changed, 185 insertions(+), 107 deletions(-) create mode 100644 src/python/include/Alpha_complex_factory.h (limited to 'src/python/gudhi/alpha_complex.pyx') diff --git a/src/python/doc/alpha_complex_user.rst b/src/python/doc/alpha_complex_user.rst index 097470c1..bcc2fc51 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -178,49 +178,22 @@ In the following example, a threshold of :math:`\alpha^2 = 32.0` is used. Example from OFF file ^^^^^^^^^^^^^^^^^^^^^ -This example builds the Delaunay triangulation from the points given by an OFF file, and initializes the alpha complex -with it. +This example builds the alpha complex from 300 random points on a 2-torus. +Then, it computes the persistence diagram and diplays it: -Then, it is asked to display information about the alpha complex: - -.. testcode:: +.. plot:: + :include-source: + import matplotlib.pyplot as plt import gudhi alpha_complex = gudhi.AlphaComplex(off_file=gudhi.__root_source_dir__ + \ - '/data/points/alphacomplexdoc.off') - simplex_tree = alpha_complex.create_simplex_tree(max_alpha_square=32.0) + '/data/points/tore3D_300.off') + simplex_tree = alpha_complex.create_simplex_tree() result_str = 'Alpha complex is of dimension ' + repr(simplex_tree.dimension()) + ' - ' + \ repr(simplex_tree.num_simplices()) + ' simplices - ' + \ repr(simplex_tree.num_vertices()) + ' vertices.' print(result_str) - fmt = '%s -> %.2f' - for filtered_value in simplex_tree.get_filtration(): - print(fmt % tuple(filtered_value)) - -the program output is: - -.. testoutput:: - - Alpha complex is of dimension 2 - 20 simplices - 7 vertices. - [0] -> 0.00 - [1] -> 0.00 - [2] -> 0.00 - [3] -> 0.00 - [4] -> 0.00 - [5] -> 0.00 - [6] -> 0.00 - [2, 3] -> 6.25 - [4, 5] -> 7.25 - [0, 2] -> 8.50 - [0, 1] -> 9.25 - [1, 3] -> 10.00 - [1, 2] -> 11.25 - [1, 2, 3] -> 12.50 - [0, 1, 2] -> 13.00 - [5, 6] -> 13.25 - [2, 4] -> 20.00 - [4, 6] -> 22.74 - [4, 5, 6] -> 22.74 - [3, 6] -> 30.25 - + diag = simplex_tree.persistence() + gudhi.plot_persistence_diagram(diag) + plt.show() diff --git a/src/python/gudhi/alpha_complex.pyx b/src/python/gudhi/alpha_complex.pyx index a356384d..ac44c61f 100644 --- a/src/python/gudhi/alpha_complex.pyx +++ b/src/python/gudhi/alpha_complex.pyx @@ -20,6 +20,7 @@ import os from gudhi.simplex_tree cimport * from gudhi.simplex_tree import SimplexTree +from gudhi import read_points_from_off_file __author__ = "Vincent Rouvreau" __copyright__ = "Copyright (C) 2016 Inria" @@ -27,11 +28,9 @@ __license__ = "GPL v3" cdef extern from "Alpha_complex_interface.h" namespace "Gudhi": cdef cppclass Alpha_complex_interface "Gudhi::alpha_complex::Alpha_complex_interface": - Alpha_complex_interface(vector[vector[double]] points, bool fast_version) nogil except + - # bool from_file is a workaround for cython to find the correct signature - Alpha_complex_interface(string off_file, bool fast_version, bool from_file) nogil except + + Alpha_complex_interface(vector[vector[double]] points, bool fast_version, bool exact_version) nogil except + vector[double] get_point(int vertex) nogil except + - void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square, bool exact_version, bool default_filtration_value) nogil except + + void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square, bool default_filtration_value) nogil except + # AlphaComplex python interface cdef class AlphaComplex: @@ -54,7 +53,6 @@ cdef class AlphaComplex: """ cdef Alpha_complex_interface * this_ptr - cdef bool exact # Fake constructor that does nothing but documenting the constructor def __init__(self, points=None, off_file='', precision='safe'): @@ -76,21 +74,20 @@ cdef class AlphaComplex: def __cinit__(self, points = None, off_file = '', precision = 'safe'): assert precision in ['fast', 'safe', 'exact'], "Alpha complex precision can only be 'fast', 'safe' or 'exact'" cdef bool fast = precision == 'fast' - self.exact = precision == 'exact' + cdef bool exact = precision == 'exact' cdef vector[vector[double]] pts if off_file: if os.path.isfile(off_file): - self.this_ptr = new Alpha_complex_interface(off_file.encode('utf-8'), fast, True) + points = read_points_from_off_file(off_file = off_file) else: print("file " + off_file + " not found.") - else: - if points is None: - # Empty Alpha construction - points=[] - pts = points - with nogil: - self.this_ptr = new Alpha_complex_interface(pts, fast) + if points is None: + # Empty Alpha construction + points=[] + pts = points + with nogil: + self.this_ptr = new Alpha_complex_interface(pts, fast, exact) def __dealloc__(self): if self.this_ptr != NULL: @@ -128,5 +125,5 @@ cdef class AlphaComplex: cdef bool compute_filtration = default_filtration_value == True with nogil: self.this_ptr.create_simplex_tree(stree_int_ptr, - mas, self.exact, compute_filtration) + mas, compute_filtration) return stree diff --git a/src/python/include/Alpha_complex_factory.h b/src/python/include/Alpha_complex_factory.h new file mode 100644 index 00000000..7cab73bd --- /dev/null +++ b/src/python/include/Alpha_complex_factory.h @@ -0,0 +1,144 @@ +/* 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) 2020 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +#ifndef INCLUDE_ALPHA_COMPLEX_FACTORY_H_ +#define INCLUDE_ALPHA_COMPLEX_FACTORY_H_ + +#include +#include +#include +#include +#include +#include + +#include + +#include "Simplex_tree_interface.h" + +#include +#include +#include +#include // for std::unique_ptr + +namespace Gudhi { + +namespace alpha_complex { + +template +std::vector pt_cgal_to_cython(CgalPointType& point) { + std::vector vd; + for (auto coord = point.cartesian_begin(); coord != point.cartesian_end(); coord++) + vd.push_back(CGAL::to_double(*coord)); + return vd; +} + +template +static CgalPointType pt_cython_to_cgal(std::vector const& vec) { + return CgalPointType(vec.size(), vec.begin(), vec.end()); +} + +class Abstract_alpha_complex { + public: + virtual std::vector get_point(int vh) = 0; + virtual void create_simplex_tree(Simplex_tree_interface<>* simplex_tree, double max_alpha_square, + bool default_filtration_value) = 0; +}; + +class Exact_Alphacomplex_dD : public Abstract_alpha_complex { + private: + using Exact_kernel = CGAL::Epeck_d; + using Point_exact_kernel = typename Exact_kernel::Point_d; + + public: + Exact_Alphacomplex_dD(const std::vector>& points, bool exact_version) + : exact_version_(exact_version) { + ac_exact_ptr_ = std::make_unique>( + boost::adaptors::transform(points, pt_cython_to_cgal)); + } + + std::vector get_point(int vh) { + Point_exact_kernel const& point = ac_exact_ptr_->get_point(vh); + return pt_cgal_to_cython(point); + } + + void create_simplex_tree(Simplex_tree_interface<>* simplex_tree, double max_alpha_square, + bool default_filtration_value){ + ac_exact_ptr_->create_complex(*simplex_tree, max_alpha_square, exact_version_, default_filtration_value); + } + + private: + bool exact_version_; + std::unique_ptr> ac_exact_ptr_; +}; + +class Inexact_Alphacomplex_dD : public Abstract_alpha_complex { + private: + using Inexact_kernel = CGAL::Epick_d; + using Point_inexact_kernel = typename Inexact_kernel::Point_d; + + public: + Inexact_Alphacomplex_dD(const std::vector>& points, bool exact_version) + : exact_version_(exact_version) { + ac_inexact_ptr_ = std::make_unique>( + boost::adaptors::transform(points, pt_cython_to_cgal)); + } + + std::vector get_point(int vh) { + Point_inexact_kernel const& point = ac_inexact_ptr_->get_point(vh); + return pt_cgal_to_cython(point); + } + void create_simplex_tree(Simplex_tree_interface<>* simplex_tree, double max_alpha_square, + bool default_filtration_value){ + ac_inexact_ptr_->create_complex(*simplex_tree, max_alpha_square, exact_version_, default_filtration_value); + } + + private: + bool exact_version_; + std::unique_ptr> ac_inexact_ptr_; +}; + +template +class Alphacomplex_3D : public Abstract_alpha_complex { + private: + using Point_3 = typename Alpha_complex_3d::Bare_point_3; + + static Point_3 pt_cython_to_cgal_3(std::vector const& vec) { + return Point_3(vec[0], vec[1], vec[2]); + } + + public: + Alphacomplex_3D(const std::vector>& points) { + alpha3d_ptr_ = std::make_unique>( + boost::adaptors::transform(points, pt_cython_to_cgal_3)); + } + + std::vector get_point(int vh) { + Point_3 const& point = alpha3d_ptr_->get_point(vh); + return pt_cgal_to_cython(point); + } + + void create_simplex_tree(Simplex_tree_interface<>* simplex_tree, double max_alpha_square, + bool default_filtration_value){ + alpha3d_ptr_->create_complex(*simplex_tree, max_alpha_square); + if (default_filtration_value) { + // TODO + } + } + + private: + std::unique_ptr> alpha3d_ptr_; +}; + + +} // namespace alpha_complex + +} // namespace Gudhi + +#endif // INCLUDE_ALPHA_COMPLEX_FACTORY_H_ diff --git a/src/python/include/Alpha_complex_interface.h b/src/python/include/Alpha_complex_interface.h index 3ac5db1f..c4b9df4b 100644 --- a/src/python/include/Alpha_complex_interface.h +++ b/src/python/include/Alpha_complex_interface.h @@ -11,12 +11,8 @@ #ifndef INCLUDE_ALPHA_COMPLEX_INTERFACE_H_ #define INCLUDE_ALPHA_COMPLEX_INTERFACE_H_ -#include -#include -#include -#include - -#include +#include "Alpha_complex_factory.h" +#include #include "Simplex_tree_interface.h" @@ -30,67 +26,35 @@ namespace Gudhi { namespace alpha_complex { class Alpha_complex_interface { - private: - using Exact_kernel = CGAL::Epeck_d; - using Inexact_kernel = CGAL::Epick_d; - using Point_exact_kernel = typename Exact_kernel::Point_d; - using Point_inexact_kernel = typename Inexact_kernel::Point_d; - - template - std::vector pt_cgal_to_cython(CgalPointType& point) { - std::vector vd; - for (auto coord = point.cartesian_begin(); coord != point.cartesian_end(); coord++) - vd.push_back(CGAL::to_double(*coord)); - return vd; - } - - template - static CgalPointType pt_cython_to_cgal(std::vector const& vec) { - return CgalPointType(vec.size(), vec.begin(), vec.end()); - } - public: - Alpha_complex_interface(const std::vector>& points, bool fast_version) - : fast_version_(fast_version) { - if (fast_version_) { - ac_inexact_ptr_ = std::make_unique>( - boost::adaptors::transform(points, pt_cython_to_cgal)); + Alpha_complex_interface(const std::vector>& points, bool fast_version, bool exact_version) { + if (points[0].size() == 3) { + if (fast_version) + alpha_ptr_ = std::make_unique>(points); + else if (exact_version) + alpha_ptr_ = std::make_unique>(points); + else + alpha_ptr_ = std::make_unique>(points); } else { - ac_exact_ptr_ = std::make_unique>( - boost::adaptors::transform(points, pt_cython_to_cgal)); + if (fast_version) { + alpha_ptr_ = std::make_unique(points, exact_version); + } else { + alpha_ptr_ = std::make_unique(points, exact_version); + } } } - Alpha_complex_interface(const std::string& off_file_name, bool fast_version, bool from_file = true) - : fast_version_(fast_version) { - if (fast_version_) - ac_inexact_ptr_ = std::make_unique>(off_file_name); - else - ac_exact_ptr_ = std::make_unique>(off_file_name); - } - std::vector get_point(int vh) { - if (fast_version_) { - Point_inexact_kernel const& point = ac_inexact_ptr_->get_point(vh); - return pt_cgal_to_cython(point); - } else { - Point_exact_kernel const& point = ac_exact_ptr_->get_point(vh); - return pt_cgal_to_cython(point); - } + return alpha_ptr_->get_point(vh); } - void create_simplex_tree(Simplex_tree_interface<>* simplex_tree, double max_alpha_square, bool exact_version, + void create_simplex_tree(Simplex_tree_interface<>* simplex_tree, double max_alpha_square, bool default_filtration_value) { - if (fast_version_) - ac_inexact_ptr_->create_complex(*simplex_tree, max_alpha_square, exact_version, default_filtration_value); - else - ac_exact_ptr_->create_complex(*simplex_tree, max_alpha_square, exact_version, default_filtration_value); + alpha_ptr_->create_simplex_tree(simplex_tree, max_alpha_square, default_filtration_value); } private: - bool fast_version_; - std::unique_ptr> ac_exact_ptr_; - std::unique_ptr> ac_inexact_ptr_; + std::unique_ptr alpha_ptr_; }; } // namespace alpha_complex -- cgit v1.2.3 From 7fb8f17638ee7245a1eb6c604c6629a484612179 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 1 Jul 2020 07:41:13 +0200 Subject: Doc review: add some details about get_point --- src/python/doc/alpha_complex_user.rst | 2 ++ src/python/gudhi/alpha_complex.pyx | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src/python/gudhi/alpha_complex.pyx') diff --git a/src/python/doc/alpha_complex_user.rst b/src/python/doc/alpha_complex_user.rst index 714c5343..fd4a2372 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -34,6 +34,8 @@ Remarks the computation of filtration values can exceptionally be arbitrarily bad. In all cases, we still guarantee that the output is a valid filtration (faces have a filtration value no larger than their cofaces). * For performances reasons, it is advised to use Alpha_complex with `CGAL `_ :math:`\geq` 5.0.0. +* The vertices in the output simplex tree are not guaranteed to match the order of the input points. One can use + :func:`~gudhi.AlphaComplex.get_point` to get the initial point back. Example from points ------------------- diff --git a/src/python/gudhi/alpha_complex.pyx b/src/python/gudhi/alpha_complex.pyx index ac44c61f..ea128743 100644 --- a/src/python/gudhi/alpha_complex.pyx +++ b/src/python/gudhi/alpha_complex.pyx @@ -99,7 +99,7 @@ cdef class AlphaComplex: return self.this_ptr != NULL def get_point(self, vertex): - """This function returns the point corresponding to a given vertex. + """This function returns the point corresponding to a given vertex from the :class:`~gudhi.SimplexTree`. :param vertex: The vertex. :type vertex: int -- cgit v1.2.3