From 80f2e9e0aa2562ef4efed59c9034615ad2175836 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 12 Mar 2021 15:59:04 +0100 Subject: Link to OFF file format in example section --- src/python/doc/alpha_complex_user.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/python/doc/alpha_complex_user.rst') diff --git a/src/python/doc/alpha_complex_user.rst b/src/python/doc/alpha_complex_user.rst index fffcb3db..b116944c 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -178,7 +178,7 @@ In the following example, a threshold of :math:`\alpha^2 = 32.0` is used. Example from OFF file ^^^^^^^^^^^^^^^^^^^^^ -This example builds the alpha complex from 300 random points on a 2-torus. +This example builds the alpha complex from 300 random points on a 2-torus, given by an `OFF file `_. Then, it computes the persistence diagram and displays it: -- cgit v1.2.3 From af98f16e12ec9d1af7d925ecdc53b4daefea6ebe Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 18 Mar 2021 16:16:48 +0100 Subject: Add weight support --- src/python/doc/alpha_complex_user.rst | 104 ++++++++++++++++++++++----- src/python/gudhi/alpha_complex.pyx | 48 ++++++++----- src/python/include/Alpha_complex_factory.h | 65 +++++++++++++++-- src/python/include/Alpha_complex_interface.h | 28 +++++--- 4 files changed, 194 insertions(+), 51 deletions(-) (limited to 'src/python/doc/alpha_complex_user.rst') diff --git a/src/python/doc/alpha_complex_user.rst b/src/python/doc/alpha_complex_user.rst index b116944c..6f35cc15 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -44,16 +44,15 @@ This example builds the alpha-complex from the given points: .. testcode:: - import gudhi - alpha_complex = gudhi.AlphaComplex(points=[[1, 1], [7, 0], [4, 6], [9, 6], [0, 14], [2, 19], [9, 17]]) - - 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) + from gudhi import AlphaComplex + ac = AlphaComplex(points=[[1, 1], [7, 0], [4, 6], [9, 6], [0, 14], [2, 19], [9, 17]]) + + stree = ac.create_simplex_tree() + print('Alpha complex is of dimension ', stree.dimension(), ' - ', + stree.num_simplices(), ' simplices - ', stree.num_vertices(), ' vertices.') + fmt = '%s -> %.2f' - for filtered_value in simplex_tree.get_filtration(): + for filtered_value in stree.get_filtration(): print(fmt % tuple(filtered_value)) The output is: @@ -174,6 +173,78 @@ of speed-up, since we always first build the full filtered complex, so it is rec :paramref:`~gudhi.AlphaComplex.create_simplex_tree.max_alpha_square`. In the following example, a threshold of :math:`\alpha^2 = 32.0` is used. +Weighted specific version +^^^^^^^^^^^^^^^^^^^^^^^^^ + +:Requires: `Eigen `_ :math:`\geq` 3.1.0 and `CGAL `_ :math:`\geq` 5.1.0. + +A weighted version for Alpha complex is available. It is like a usual Alpha complex, but based on a +`CGAL regular triangulation `_ +of Delaunay. + +This example builds the CGAL weighted alpha shapes from a small molecule, and initializes the alpha complex with +it. This example is taken from +`CGAL 3d weighted alpha shapes `_. + +Then, it is asked to display information about the alpha complex. + +.. testcode:: + + from gudhi import AlphaComplex + wgt_ac = AlphaComplex(weighted_points=[[[ 1., -1., -1.], 4.], + [[-1., 1., -1.], 4.], + [[-1., -1., 1.], 4.], + [[ 1., 1., 1.], 4.], + [[ 2., 2., 2.], 1.]]) + # equivalent to: + # wgt_ac = AlphaComplex(points=[[ 1., -1., -1.], + # [-1., 1., -1.], + # [-1., -1., 1.], + # [ 1., 1., 1.], + # [ 2., 2., 2.]], + # weights = [4., 4., 4., 4., 1.]) + + stree = wgt_ac.create_simplex_tree() + print('Weighted alpha complex is of dimension ', stree.dimension(), ' - ', + stree.num_simplices(), ' simplices - ', stree.num_vertices(), ' vertices.') + fmt = '%s -> %.2f' + for filtered_value in stree.get_filtration(): + print(fmt % tuple(filtered_value)) + +The output is: + +.. testoutput:: + + Weighted alpha complex is of dimension 3 - 29 simplices - 5 vertices. + [ 0 ] -> [-4] + [ 1 ] -> [-4] + [ 2 ] -> [-4] + [ 3 ] -> [-4] + [ 1, 0 ] -> [-2] + [ 2, 0 ] -> [-2] + [ 2, 1 ] -> [-2] + [ 3, 0 ] -> [-2] + [ 3, 1 ] -> [-2] + [ 3, 2 ] -> [-2] + [ 2, 1, 0 ] -> [-1.33333] + [ 3, 1, 0 ] -> [-1.33333] + [ 3, 2, 0 ] -> [-1.33333] + [ 3, 2, 1 ] -> [-1.33333] + [ 3, 2, 1, 0 ] -> [-1] + [ 4 ] -> [-1] + [ 4, 2 ] -> [-1] + [ 4, 0 ] -> [23] + [ 4, 1 ] -> [23] + [ 4, 2, 0 ] -> [23] + [ 4, 2, 1 ] -> [23] + [ 4, 3 ] -> [23] + [ 4, 3, 2 ] -> [23] + [ 4, 1, 0 ] -> [95] + [ 4, 2, 1, 0 ] -> [95] + [ 4, 3, 0 ] -> [95] + [ 4, 3, 1 ] -> [95] + [ 4, 3, 2, 0 ] -> [95] + [ 4, 3, 2, 1 ] -> [95] Example from OFF file ^^^^^^^^^^^^^^^^^^^^^ @@ -186,14 +257,9 @@ Then, it computes the persistence diagram and displays it: :include-source: import matplotlib.pyplot as plt - import gudhi - alpha_complex = gudhi.AlphaComplex(off_file=gudhi.__root_source_dir__ + \ - '/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) - diag = simplex_tree.persistence() - gudhi.plot_persistence_diagram(diag) + import gudhi as gd + ac = gd.AlphaComplex(off_file=gd.__root_source_dir__ + '/data/points/tore3D_300.off') + stree = ac.create_simplex_tree() + dgm = stree.persistence() + gd.plot_persistence_diagram(dgm, legend = True) plt.show() diff --git a/src/python/gudhi/alpha_complex.pyx b/src/python/gudhi/alpha_complex.pyx index b7c20f74..681faebe 100644 --- a/src/python/gudhi/alpha_complex.pyx +++ b/src/python/gudhi/alpha_complex.pyx @@ -29,7 +29,7 @@ __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, bool exact_version) nogil except + + Alpha_complex_interface(vector[vector[double]] points, vector[double] weights, 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 default_filtration_value) nogil except + @@ -56,26 +56,35 @@ cdef class AlphaComplex: cdef Alpha_complex_interface * this_ptr # Fake constructor that does nothing but documenting the constructor - def __init__(self, points=[], off_file='', weights=[], weight_file='', precision='safe'): + def __init__(self, points=[], off_file='', weights=[], weight_file='', weighted_points=[], + precision='safe'): """AlphaComplex constructor. :param points: A list of points in d-Dimension. - :type points: list of list of double + :type points: Iterable[Iterable[float]] - :param off_file: An `OFF file style `_ name. `points` are - read and overwritten by the points in the `off_file`. + :param off_file: An `OFF file style `_ name. + If an `off_file` is given with `points` or `weighted_points`, only points from the + file are taken into account. :type off_file: string :param weights: A list of weights. If set, the number of weights must correspond to the number of points. - :type weights: list of double + :type weights: Iterable[float] :param weight_file: A file containing a list of weights (one per line). - `weights` are read and overwritten by the weights in the `weight_file`. - If set, the number of weights must correspond to the number of points. + If a `weight_file` is given with `weights` or `weighted_points`, only weights from the + file are taken into account. + :type weight_file: string - :param precision: Alpha complex precision can be 'fast', 'safe' or 'exact'. Default is 'safe'. + :param weighted_points: A list of points in d-Dimension and its weight. + If `weighted_points` are given with `weights` or `points`, these last ones will + not be taken into account. + :type weighted_points: Iterable[Iterable[float], float] + + :param precision: Alpha complex precision can be 'fast', 'safe' or 'exact'. Default is + 'safe'. :type precision: string :raises FileNotFoundError: If `off_file` and/or `weight_file` is set but not found. @@ -83,11 +92,16 @@ cdef class AlphaComplex: """ # The real cython constructor - def __cinit__(self, points = [], off_file = '', weights=[], weight_file='', precision = 'safe'): + def __cinit__(self, points = [], off_file = '', weights=[], weight_file='', weighted_points=[], + precision = 'safe'): assert precision in ['fast', 'safe', 'exact'], "Alpha complex precision can only be 'fast', 'safe' or 'exact'" cdef bool fast = precision == 'fast' cdef bool exact = precision == 'exact' + if len(weighted_points) > 0: + points = [wpt[0] for wpt in weighted_points] + weights = [wpt[1] for wpt in weighted_points] + if off_file: if os.path.isfile(off_file): points = read_points_from_off_file(off_file = off_file) @@ -100,20 +114,18 @@ cdef class AlphaComplex: else: raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), weight_file) + # weights are set but is inconsistent with the number of points + if len(weights) != 0 and len(weights) != len(points): + raise ValueError("Inconsistency between the number of points and weights") + # need to copy the points to use them without the gil cdef vector[vector[double]] pts cdef vector[double] wgts pts = points + wgts = weights if len(weights) == 0: with nogil: - self.this_ptr = new Alpha_complex_interface(pts, fast, exact) - else: - if len(weights) == len(points): - wgts = weights - with nogil: - self.this_ptr = new Alpha_complex_interface(pts, fast, exact) - else: - raise ValueError("Inconsistency between the number of points and weights") + self.this_ptr = new Alpha_complex_interface(pts, wgts, fast, exact) def __dealloc__(self): if self.this_ptr != NULL: diff --git a/src/python/include/Alpha_complex_factory.h b/src/python/include/Alpha_complex_factory.h index 3405fdd6..36e98615 100644 --- a/src/python/include/Alpha_complex_factory.h +++ b/src/python/include/Alpha_complex_factory.h @@ -55,13 +55,13 @@ class Abstract_alpha_complex { virtual ~Abstract_alpha_complex() = default; }; -class Exact_Alphacomplex_dD final : public Abstract_alpha_complex { +class Exact_alpha_complex_dD final : public Abstract_alpha_complex { private: using Kernel = CGAL::Epeck_d; using Point = typename Kernel::Point_d; public: - Exact_Alphacomplex_dD(const std::vector>& points, bool exact_version) + Exact_alpha_complex_dD(const std::vector>& points, bool exact_version) : exact_version_(exact_version), alpha_complex_(boost::adaptors::transform(points, pt_cython_to_cgal)) { } @@ -81,13 +81,13 @@ class Exact_Alphacomplex_dD final : public Abstract_alpha_complex { Alpha_complex alpha_complex_; }; -class Inexact_Alphacomplex_dD final : public Abstract_alpha_complex { +class Inexact_alpha_complex_dD final : public Abstract_alpha_complex { private: using Kernel = CGAL::Epick_d; using Point = typename Kernel::Point_d; public: - Inexact_Alphacomplex_dD(const std::vector>& points, bool exact_version) + Inexact_alpha_complex_dD(const std::vector>& points, bool exact_version) : exact_version_(exact_version), alpha_complex_(boost::adaptors::transform(points, pt_cython_to_cgal)) { } @@ -106,8 +106,61 @@ class Inexact_Alphacomplex_dD final : public Abstract_alpha_complex { Alpha_complex alpha_complex_; }; +class Exact_weighted_alpha_complex_dD final : public Abstract_alpha_complex { + private: + using Kernel = CGAL::Epeck_d; + using Point = typename Kernel::Point_d; + + public: + Exact_weighted_alpha_complex_dD(const std::vector>& points, + const std::vector& weights, bool exact_version) + : exact_version_(exact_version), + alpha_complex_(boost::adaptors::transform(points, pt_cython_to_cgal), weights) { + } + + virtual std::vector get_point(int vh) override { + Point const& point = alpha_complex_.get_point(vh).point(); + return pt_cgal_to_cython(point); + } + + virtual bool create_simplex_tree(Simplex_tree_interface<>* simplex_tree, double max_alpha_square, + bool default_filtration_value) override { + return alpha_complex_.create_complex(*simplex_tree, max_alpha_square, exact_version_, default_filtration_value); + } + + private: + bool exact_version_; + Alpha_complex alpha_complex_; +}; + +class Inexact_weighted_alpha_complex_dD final : public Abstract_alpha_complex { + private: + using Kernel = CGAL::Epick_d; + using Point = typename Kernel::Point_d; + + public: + Inexact_weighted_alpha_complex_dD(const std::vector>& points, + const std::vector& weights, bool exact_version) + : exact_version_(exact_version), + alpha_complex_(boost::adaptors::transform(points, pt_cython_to_cgal), weights) { + } + + virtual std::vector get_point(int vh) override { + Point const& point = alpha_complex_.get_point(vh).point(); + return pt_cgal_to_cython(point); + } + virtual bool create_simplex_tree(Simplex_tree_interface<>* simplex_tree, double max_alpha_square, + bool default_filtration_value) override { + return alpha_complex_.create_complex(*simplex_tree, max_alpha_square, exact_version_, default_filtration_value); + } + + private: + bool exact_version_; + Alpha_complex alpha_complex_; +}; + template -class Alphacomplex_3D final : public Abstract_alpha_complex { +class Alpha_complex_3D final : public Abstract_alpha_complex { private: using Point = typename Alpha_complex_3d::Bare_point_3; @@ -116,7 +169,7 @@ class Alphacomplex_3D final : public Abstract_alpha_complex { } public: - Alphacomplex_3D(const std::vector>& points) + Alpha_complex_3D(const std::vector>& points) : alpha_complex_(boost::adaptors::transform(points, pt_cython_to_cgal_3)) { } diff --git a/src/python/include/Alpha_complex_interface.h b/src/python/include/Alpha_complex_interface.h index 23be194d..43c96b2f 100644 --- a/src/python/include/Alpha_complex_interface.h +++ b/src/python/include/Alpha_complex_interface.h @@ -27,8 +27,11 @@ namespace alpha_complex { class Alpha_complex_interface { public: - Alpha_complex_interface(const std::vector>& points, bool fast_version, bool exact_version) + Alpha_complex_interface(const std::vector>& points, + const std::vector& weights, + bool fast_version, bool exact_version) : points_(points), + weights_(weights), fast_version_(fast_version), exact_version_(exact_version) { } @@ -41,13 +44,13 @@ class Alpha_complex_interface { bool default_filtration_value) { if (points_.size() > 0) { std::size_t dimension = points_[0].size(); - if (dimension == 3 && !default_filtration_value) { + if (dimension == 3 && weights_.size() == 0 && !default_filtration_value) { if (fast_version_) - alpha_ptr_ = std::make_unique>(points_); + alpha_ptr_ = std::make_unique>(points_); else if (exact_version_) - alpha_ptr_ = std::make_unique>(points_); + alpha_ptr_ = std::make_unique>(points_); else - alpha_ptr_ = std::make_unique>(points_); + alpha_ptr_ = std::make_unique>(points_); if (!alpha_ptr_->create_simplex_tree(simplex_tree, max_alpha_square, default_filtration_value)) { // create_simplex_tree will fail if all points are on a plane - Retry with dD by setting dimension to 2 dimension--; @@ -55,11 +58,19 @@ class Alpha_complex_interface { } } // Not ** else ** because we have to take into account if 3d fails - if (dimension != 3 || default_filtration_value) { + if (dimension != 3 || weights_.size() != 0 || default_filtration_value) { if (fast_version_) { - alpha_ptr_ = std::make_unique(points_, exact_version_); + if (weights_.size() == 0) { + alpha_ptr_ = std::make_unique(points_, exact_version_); + } else { + alpha_ptr_ = std::make_unique(points_, weights_, exact_version_); + } } else { - alpha_ptr_ = std::make_unique(points_, exact_version_); + if (weights_.size() == 0) { + alpha_ptr_ = std::make_unique(points_, exact_version_); + } else { + alpha_ptr_ = std::make_unique(points_, weights_, exact_version_); + } } alpha_ptr_->create_simplex_tree(simplex_tree, max_alpha_square, default_filtration_value); } @@ -69,6 +80,7 @@ class Alpha_complex_interface { private: std::unique_ptr alpha_ptr_; std::vector> points_; + std::vector weights_; bool fast_version_; bool exact_version_; }; -- cgit v1.2.3 From 0fc53e3b820130169a6a9ad2866cff6f1b4a64c6 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 22 Mar 2021 16:25:58 +0100 Subject: Fix sphinx issues --- src/python/doc/alpha_complex_user.rst | 62 +++++++++++++++++------------------ src/python/gudhi/alpha_complex.pyx | 5 ++- 2 files changed, 33 insertions(+), 34 deletions(-) (limited to 'src/python/doc/alpha_complex_user.rst') diff --git a/src/python/doc/alpha_complex_user.rst b/src/python/doc/alpha_complex_user.rst index 6f35cc15..5e028cdc 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -59,7 +59,7 @@ The output is: .. testoutput:: - Alpha complex is of dimension 2 - 25 simplices - 7 vertices. + Alpha complex is of dimension 2 - 25 simplices - 7 vertices. [0] -> 0.00 [1] -> 0.00 [2] -> 0.00 @@ -215,36 +215,36 @@ The output is: .. testoutput:: - Weighted alpha complex is of dimension 3 - 29 simplices - 5 vertices. - [ 0 ] -> [-4] - [ 1 ] -> [-4] - [ 2 ] -> [-4] - [ 3 ] -> [-4] - [ 1, 0 ] -> [-2] - [ 2, 0 ] -> [-2] - [ 2, 1 ] -> [-2] - [ 3, 0 ] -> [-2] - [ 3, 1 ] -> [-2] - [ 3, 2 ] -> [-2] - [ 2, 1, 0 ] -> [-1.33333] - [ 3, 1, 0 ] -> [-1.33333] - [ 3, 2, 0 ] -> [-1.33333] - [ 3, 2, 1 ] -> [-1.33333] - [ 3, 2, 1, 0 ] -> [-1] - [ 4 ] -> [-1] - [ 4, 2 ] -> [-1] - [ 4, 0 ] -> [23] - [ 4, 1 ] -> [23] - [ 4, 2, 0 ] -> [23] - [ 4, 2, 1 ] -> [23] - [ 4, 3 ] -> [23] - [ 4, 3, 2 ] -> [23] - [ 4, 1, 0 ] -> [95] - [ 4, 2, 1, 0 ] -> [95] - [ 4, 3, 0 ] -> [95] - [ 4, 3, 1 ] -> [95] - [ 4, 3, 2, 0 ] -> [95] - [ 4, 3, 2, 1 ] -> [95] + Weighted alpha complex is of dimension 3 - 29 simplices - 5 vertices. + [0] -> -4.00 + [1] -> -4.00 + [2] -> -4.00 + [3] -> -4.00 + [0, 1] -> -2.00 + [0, 2] -> -2.00 + [1, 2] -> -2.00 + [0, 3] -> -2.00 + [1, 3] -> -2.00 + [2, 3] -> -2.00 + [0, 2, 3] -> -1.33 + [1, 2, 3] -> -1.33 + [0, 1, 2] -> -1.33 + [0, 1, 3] -> -1.33 + [0, 1, 2, 3] -> -1.00 + [4] -> -1.00 + [3, 4] -> -1.00 + [0, 4] -> 23.00 + [1, 4] -> 23.00 + [2, 4] -> 23.00 + [0, 3, 4] -> 23.00 + [1, 3, 4] -> 23.00 + [2, 3, 4] -> 23.00 + [0, 1, 4] -> 95.00 + [0, 2, 4] -> 95.00 + [1, 2, 4] -> 95.00 + [0, 1, 3, 4] -> 95.00 + [0, 2, 3, 4] -> 95.00 + [1, 2, 3, 4] -> 95.00 Example from OFF file ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/python/gudhi/alpha_complex.pyx b/src/python/gudhi/alpha_complex.pyx index 681faebe..d4c4ba20 100644 --- a/src/python/gudhi/alpha_complex.pyx +++ b/src/python/gudhi/alpha_complex.pyx @@ -123,9 +123,8 @@ cdef class AlphaComplex: cdef vector[double] wgts pts = points wgts = weights - if len(weights) == 0: - with nogil: - self.this_ptr = new Alpha_complex_interface(pts, wgts, fast, exact) + with nogil: + self.this_ptr = new Alpha_complex_interface(pts, wgts, fast, exact) def __dealloc__(self): if self.this_ptr != NULL: -- cgit v1.2.3 From dcb90cc644f91265c9bd3011a89b5f0b0e9f3869 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Tue, 23 Mar 2021 16:21:00 +0100 Subject: Remove weighted_points, as it is overdesigned --- src/python/doc/alpha_complex_user.rst | 18 ++++++------------ src/python/gudhi/alpha_complex.pyx | 22 ++++++---------------- 2 files changed, 12 insertions(+), 28 deletions(-) (limited to 'src/python/doc/alpha_complex_user.rst') diff --git a/src/python/doc/alpha_complex_user.rst b/src/python/doc/alpha_complex_user.rst index 5e028cdc..f59f69e7 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -191,18 +191,12 @@ Then, it is asked to display information about the alpha complex. .. testcode:: from gudhi import AlphaComplex - wgt_ac = AlphaComplex(weighted_points=[[[ 1., -1., -1.], 4.], - [[-1., 1., -1.], 4.], - [[-1., -1., 1.], 4.], - [[ 1., 1., 1.], 4.], - [[ 2., 2., 2.], 1.]]) - # equivalent to: - # wgt_ac = AlphaComplex(points=[[ 1., -1., -1.], - # [-1., 1., -1.], - # [-1., -1., 1.], - # [ 1., 1., 1.], - # [ 2., 2., 2.]], - # weights = [4., 4., 4., 4., 1.]) + wgt_ac = AlphaComplex(points=[[ 1., -1., -1.], + [-1., 1., -1.], + [-1., -1., 1.], + [ 1., 1., 1.], + [ 2., 2., 2.]], + weights = [4., 4., 4., 4., 1.]) stree = wgt_ac.create_simplex_tree() print('Weighted alpha complex is of dimension ', stree.dimension(), ' - ', diff --git a/src/python/gudhi/alpha_complex.pyx b/src/python/gudhi/alpha_complex.pyx index d4c4ba20..9c364b76 100644 --- a/src/python/gudhi/alpha_complex.pyx +++ b/src/python/gudhi/alpha_complex.pyx @@ -56,15 +56,14 @@ cdef class AlphaComplex: cdef Alpha_complex_interface * this_ptr # Fake constructor that does nothing but documenting the constructor - def __init__(self, points=[], off_file='', weights=[], weight_file='', weighted_points=[], - precision='safe'): + def __init__(self, points=[], off_file='', weights=[], weight_file='', precision='safe'): """AlphaComplex constructor. :param points: A list of points in d-Dimension. :type points: Iterable[Iterable[float]] :param off_file: An `OFF file style `_ name. - If an `off_file` is given with `points` or `weighted_points`, only points from the + If an `off_file` is given with `points` as arguments, only points from the file are taken into account. :type off_file: string @@ -73,16 +72,11 @@ cdef class AlphaComplex: :type weights: Iterable[float] :param weight_file: A file containing a list of weights (one per line). - If a `weight_file` is given with `weights` or `weighted_points`, only weights from the + If a `weight_file` is given with `weights` as arguments, only weights from the file are taken into account. :type weight_file: string - :param weighted_points: A list of points in d-Dimension and its weight. - If `weighted_points` are given with `weights` or `points`, these last ones will - not be taken into account. - :type weighted_points: Iterable[Iterable[float], float] - :param precision: Alpha complex precision can be 'fast', 'safe' or 'exact'. Default is 'safe'. :type precision: string @@ -92,16 +86,12 @@ cdef class AlphaComplex: """ # The real cython constructor - def __cinit__(self, points = [], off_file = '', weights=[], weight_file='', weighted_points=[], - precision = 'safe'): - assert precision in ['fast', 'safe', 'exact'], "Alpha complex precision can only be 'fast', 'safe' or 'exact'" + def __cinit__(self, points = [], off_file = '', weights=[], weight_file='', precision = 'safe'): + assert precision in ['fast', 'safe', 'exact'], \ + "Alpha complex precision can only be 'fast', 'safe' or 'exact'" cdef bool fast = precision == 'fast' cdef bool exact = precision == 'exact' - if len(weighted_points) > 0: - points = [wpt[0] for wpt in weighted_points] - weights = [wpt[1] for wpt in weighted_points] - if off_file: if os.path.isfile(off_file): points = read_points_from_off_file(off_file = off_file) -- cgit v1.2.3 From 77e577eb28ca7622553cd0527db76d46b473c445 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 24 Mar 2021 15:27:11 +0100 Subject: Remove read_weights and depreciate off_file --- src/python/doc/alpha_complex_user.rst | 8 +- ...ex_diagram_persistence_from_off_file_example.py | 55 ++++------ .../alpha_rips_persistence_bottleneck_distance.py | 110 +++++++++---------- src/python/example/plot_alpha_complex.py | 5 +- src/python/gudhi/alpha_complex.pyx | 30 ++---- src/python/gudhi/reader_utils.pyx | 16 --- src/python/test/test_alpha_complex.py | 116 +++++++-------------- src/python/test/test_reader_utils.py | 16 --- 8 files changed, 128 insertions(+), 228 deletions(-) (limited to 'src/python/doc/alpha_complex_user.rst') diff --git a/src/python/doc/alpha_complex_user.rst b/src/python/doc/alpha_complex_user.rst index f59f69e7..2b4b75cf 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -243,7 +243,8 @@ The output is: Example from OFF file ^^^^^^^^^^^^^^^^^^^^^ -This example builds the alpha complex from 300 random points on a 2-torus, given by an `OFF file `_. +This example builds the alpha complex from 300 random points on a 2-torus, given by an +`OFF file `_. Then, it computes the persistence diagram and displays it: @@ -252,8 +253,9 @@ Then, it computes the persistence diagram and displays it: import matplotlib.pyplot as plt import gudhi as gd - ac = gd.AlphaComplex(off_file=gd.__root_source_dir__ + '/data/points/tore3D_300.off') - stree = ac.create_simplex_tree() + off_file = gd.__root_source_dir__ + '/data/points/tore3D_300.off' + points = gd.read_points_from_off_file(off_file = off_file) + stree = gd.AlphaComplex(points = points).create_simplex_tree() dgm = stree.persistence() gd.plot_persistence_diagram(dgm, legend = True) plt.show() diff --git a/src/python/example/alpha_complex_diagram_persistence_from_off_file_example.py b/src/python/example/alpha_complex_diagram_persistence_from_off_file_example.py index fe03be31..c96121a6 100755 --- a/src/python/example/alpha_complex_diagram_persistence_from_off_file_example.py +++ b/src/python/example/alpha_complex_diagram_persistence_from_off_file_example.py @@ -1,9 +1,7 @@ #!/usr/bin/env python import argparse -import errno -import os -import gudhi +import gudhi as gd """ This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. @@ -41,33 +39,24 @@ parser.add_argument( args = parser.parse_args() -with open(args.file, "r") as f: - first_line = f.readline() - if (first_line == "OFF\n") or (first_line == "nOFF\n"): - print("##############################################################") - print("AlphaComplex creation from points read in a OFF file") - - alpha_complex = gudhi.AlphaComplex(off_file=args.file) - if args.max_alpha_square is not None: - print("with max_edge_length=", args.max_alpha_square) - simplex_tree = alpha_complex.create_simplex_tree( - max_alpha_square=args.max_alpha_square - ) - else: - simplex_tree = alpha_complex.create_simplex_tree() - - print("Number of simplices=", simplex_tree.num_simplices()) - - diag = simplex_tree.persistence() - - print("betti_numbers()=", simplex_tree.betti_numbers()) - - if args.no_diagram == False: - import matplotlib.pyplot as plot - gudhi.plot_persistence_diagram(diag, band=args.band) - plot.show() - else: - raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), - args.file) - - f.close() +print("##############################################################") +print("AlphaComplex creation from points read in a OFF file") + +points = gd.read_points_from_off_file(off_file = args.file) +alpha_complex = gd.AlphaComplex(points = points) +if args.max_alpha_square is not None: + print("with max_edge_length=", args.max_alpha_square) + simplex_tree = alpha_complex.create_simplex_tree( + max_alpha_square=args.max_alpha_square + ) +else: + simplex_tree = alpha_complex.create_simplex_tree() + +print("Number of simplices=", simplex_tree.num_simplices()) + +diag = simplex_tree.persistence() +print("betti_numbers()=", simplex_tree.betti_numbers()) +if args.no_diagram == False: + import matplotlib.pyplot as plot + gd.plot_persistence_diagram(diag, band=args.band) + plot.show() diff --git a/src/python/example/alpha_rips_persistence_bottleneck_distance.py b/src/python/example/alpha_rips_persistence_bottleneck_distance.py index 3e12b0d5..6b97fb3b 100755 --- a/src/python/example/alpha_rips_persistence_bottleneck_distance.py +++ b/src/python/example/alpha_rips_persistence_bottleneck_distance.py @@ -1,10 +1,8 @@ #!/usr/bin/env python -import gudhi +import gudhi as gd import argparse import math -import errno -import os import numpy as np """ This file is part of the Gudhi Library - https://gudhi.inria.fr/ - @@ -37,70 +35,60 @@ parser.add_argument("-t", "--threshold", type=float, default=0.5) parser.add_argument("-d", "--max_dimension", type=int, default=1) args = parser.parse_args() -with open(args.file, "r") as f: - first_line = f.readline() - if (first_line == "OFF\n") or (first_line == "nOFF\n"): - point_cloud = gudhi.read_points_from_off_file(off_file=args.file) - print("##############################################################") - print("RipsComplex creation from points read in a OFF file") +point_cloud = gd.read_points_from_off_file(off_file=args.file) +print("##############################################################") +print("RipsComplex creation from points read in a OFF file") - message = "RipsComplex with max_edge_length=" + repr(args.threshold) - print(message) +message = "RipsComplex with max_edge_length=" + repr(args.threshold) +print(message) - rips_complex = gudhi.RipsComplex( - points=point_cloud, max_edge_length=args.threshold - ) - - rips_stree = rips_complex.create_simplex_tree( - max_dimension=args.max_dimension) - - message = "Number of simplices=" + repr(rips_stree.num_simplices()) - print(message) - - rips_stree.compute_persistence() - - print("##############################################################") - print("AlphaComplex creation from points read in a OFF file") - - message = "AlphaComplex with max_edge_length=" + repr(args.threshold) - print(message) - - alpha_complex = gudhi.AlphaComplex(points=point_cloud) - alpha_stree = alpha_complex.create_simplex_tree( - max_alpha_square=(args.threshold * args.threshold) - ) - - message = "Number of simplices=" + repr(alpha_stree.num_simplices()) - print(message) +rips_complex = gd.RipsComplex( + points=point_cloud, max_edge_length=args.threshold +) - alpha_stree.compute_persistence() +rips_stree = rips_complex.create_simplex_tree( + max_dimension=args.max_dimension) - max_b_distance = 0.0 - for dim in range(args.max_dimension): - # Alpha persistence values needs to be transform because filtration - # values are alpha square values - alpha_intervals = np.sqrt(alpha_stree.persistence_intervals_in_dimension(dim)) +message = "Number of simplices=" + repr(rips_stree.num_simplices()) +print(message) - rips_intervals = rips_stree.persistence_intervals_in_dimension(dim) - bottleneck_distance = gudhi.bottleneck_distance( - rips_intervals, alpha_intervals - ) - message = ( - "In dimension " - + repr(dim) - + ", bottleneck distance = " - + repr(bottleneck_distance) - ) - print(message) - max_b_distance = max(bottleneck_distance, max_b_distance) +rips_stree.compute_persistence() - print("==============================================================") - message = "Bottleneck distance is " + repr(max_b_distance) - print(message) +print("##############################################################") +print("AlphaComplex creation from points read in a OFF file") - else: - raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), - args.file) +message = "AlphaComplex with max_edge_length=" + repr(args.threshold) +print(message) +alpha_complex = gd.AlphaComplex(points=point_cloud) +alpha_stree = alpha_complex.create_simplex_tree( + max_alpha_square=(args.threshold * args.threshold) +) - f.close() +message = "Number of simplices=" + repr(alpha_stree.num_simplices()) +print(message) + +alpha_stree.compute_persistence() + +max_b_distance = 0.0 +for dim in range(args.max_dimension): + # Alpha persistence values needs to be transform because filtration + # values are alpha square values + alpha_intervals = np.sqrt(alpha_stree.persistence_intervals_in_dimension(dim)) + + rips_intervals = rips_stree.persistence_intervals_in_dimension(dim) + bottleneck_distance = gd.bottleneck_distance( + rips_intervals, alpha_intervals + ) + message = ( + "In dimension " + + repr(dim) + + ", bottleneck distance = " + + repr(bottleneck_distance) + ) + print(message) + max_b_distance = max(bottleneck_distance, max_b_distance) + +print("==============================================================") +message = "Bottleneck distance is " + repr(max_b_distance) +print(message) diff --git a/src/python/example/plot_alpha_complex.py b/src/python/example/plot_alpha_complex.py index 99c18a7c..0924619b 100755 --- a/src/python/example/plot_alpha_complex.py +++ b/src/python/example/plot_alpha_complex.py @@ -1,8 +1,9 @@ #!/usr/bin/env python import numpy as np -import gudhi -ac = gudhi.AlphaComplex(off_file='../../data/points/tore3D_1307.off') +import gudhi as gd +points = gd.read_points_from_off_file(off_file = '../../data/points/tore3D_1307.off') +ac = gd.AlphaComplex(points = points) st = ac.create_simplex_tree() points = np.array([ac.get_point(i) for i in range(st.num_vertices())]) # We want to plot the alpha-complex with alpha=0.1. diff --git a/src/python/gudhi/alpha_complex.pyx b/src/python/gudhi/alpha_complex.pyx index 9c364b76..5d181391 100644 --- a/src/python/gudhi/alpha_complex.pyx +++ b/src/python/gudhi/alpha_complex.pyx @@ -18,10 +18,11 @@ from libcpp cimport bool from libc.stdint cimport intptr_t import errno import os +import warnings from gudhi.simplex_tree cimport * from gudhi.simplex_tree import SimplexTree -from gudhi import read_points_from_off_file, read_weights +from gudhi import read_points_from_off_file __author__ = "Vincent Rouvreau" __copyright__ = "Copyright (C) 2016 Inria" @@ -56,54 +57,45 @@ cdef class AlphaComplex: cdef Alpha_complex_interface * this_ptr # Fake constructor that does nothing but documenting the constructor - def __init__(self, points=[], off_file='', weights=[], weight_file='', precision='safe'): + def __init__(self, points=[], off_file='', weights=[], precision='safe'): """AlphaComplex constructor. :param points: A list of points in d-Dimension. :type points: Iterable[Iterable[float]] - :param off_file: An `OFF file style `_ name. - If an `off_file` is given with `points` as arguments, only points from the - file are taken into account. + :param off_file: **[deprecated]** An `OFF file style `_ + name. + If an `off_file` is given with `points` as arguments, only points from the file are + taken into account. :type off_file: string :param weights: A list of weights. If set, the number of weights must correspond to the number of points. :type weights: Iterable[float] - :param weight_file: A file containing a list of weights (one per line). - If a `weight_file` is given with `weights` as arguments, only weights from the - file are taken into account. - - :type weight_file: string - :param precision: Alpha complex precision can be 'fast', 'safe' or 'exact'. Default is 'safe'. :type precision: string - :raises FileNotFoundError: If `off_file` and/or `weight_file` is set but not found. + :raises FileNotFoundError: **[deprecated]** If `off_file` is set but not found. :raises ValueError: In case of inconsistency between the number of points and weights. """ # The real cython constructor - def __cinit__(self, points = [], off_file = '', weights=[], weight_file='', precision = 'safe'): + def __cinit__(self, points = [], off_file = '', weights=[], precision = 'safe'): assert precision in ['fast', 'safe', 'exact'], \ "Alpha complex precision can only be 'fast', 'safe' or 'exact'" cdef bool fast = precision == 'fast' cdef bool exact = precision == 'exact' if off_file: + warnings.warn("off_file is a deprecated parameter, please consider using gudhi.read_points_from_off_file", + DeprecationWarning) if os.path.isfile(off_file): points = read_points_from_off_file(off_file = off_file) else: raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), off_file) - if weight_file: - if os.path.isfile(weight_file): - weights = read_weights(weight_file = weight_file) - else: - raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), weight_file) - # weights are set but is inconsistent with the number of points if len(weights) != 0 and len(weights) != len(points): raise ValueError("Inconsistency between the number of points and weights") diff --git a/src/python/gudhi/reader_utils.pyx b/src/python/gudhi/reader_utils.pyx index f997ad3e..fe1c3a2e 100644 --- a/src/python/gudhi/reader_utils.pyx +++ b/src/python/gudhi/reader_utils.pyx @@ -84,19 +84,3 @@ def read_persistence_intervals_in_dimension(persistence_file='', only_this_dim=- 'utf-8'), only_this_dim)) print("file " + persistence_file + " not set or not found.") return [] - -def read_weights(weight_file=''): - """Reads a file containing weights. Only one float value per line is read and stored. - The return value is a `list(weight)`. - - :param weight_file: A weight file style name (one weight per line). - :type weight_file: string - - :returns: A list of weights. - :rtype: List[float] - """ - weights=[] - with open(weight_file, 'r') as wfile: - weights = [float(wline) for wline in wfile if wline.strip()] - return weights - diff --git a/src/python/test/test_alpha_complex.py b/src/python/test/test_alpha_complex.py index a0de46c3..e0f2b5df 100755 --- a/src/python/test/test_alpha_complex.py +++ b/src/python/test/test_alpha_complex.py @@ -12,6 +12,8 @@ import gudhi as gd import math import numpy as np import pytest +import warnings + try: # python3 from itertools import zip_longest @@ -203,7 +205,13 @@ def test_delaunay_complex(): _delaunay_complex(precision) def _3d_points_on_a_plane(precision, default_filtration_value): - alpha = gd.AlphaComplex(off_file='alphacomplexdoc.off', precision = precision) + alpha = gd.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], + [0.0, 14.0, 0.0], + [2.0, 19.0, 0.0], + [9.0, 17.0, 0.0]], precision = precision) simplex_tree = alpha.create_simplex_tree(default_filtration_value = default_filtration_value) assert simplex_tree.dimension() == 2 @@ -211,28 +219,16 @@ def _3d_points_on_a_plane(precision, default_filtration_value): assert simplex_tree.num_simplices() == 25 def test_3d_points_on_a_plane(): - off_file = open("alphacomplexdoc.off", "w") - off_file.write("OFF \n" \ - "7 0 0 \n" \ - "1.0 1.0 0.0\n" \ - "7.0 0.0 0.0\n" \ - "4.0 6.0 0.0\n" \ - "9.0 6.0 0.0\n" \ - "0.0 14.0 0.0\n" \ - "2.0 19.0 0.0\n" \ - "9.0 17.0 0.0\n" ) - off_file.close() - for default_filtration_value in [True, False]: for precision in ['fast', 'safe', 'exact']: _3d_points_on_a_plane(precision, default_filtration_value) def _3d_tetrahedrons(precision): points = 10*np.random.rand(10, 3) - alpha = gd.AlphaComplex(points=points, precision = precision) + alpha = gd.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 = gd.AlphaComplex(points = points, precision = precision) st_delaunay = delaunay.create_simplex_tree(default_filtration_value = True) delaunay_tetra = [] @@ -262,11 +258,7 @@ def test_3d_tetrahedrons(): for precision in ['fast', 'safe', 'exact']: _3d_tetrahedrons(precision) -def test_non_existing_off_file(): - with pytest.raises(FileNotFoundError): - alpha = gd.AlphaComplex(off_file="pouetpouettralala.toubiloubabdou") - -def test_non_existing_weight_file(): +def test_off_file_deprecation_warning(): off_file = open("alphacomplexdoc.off", "w") off_file.write("OFF \n" \ "7 0 0 \n" \ @@ -279,67 +271,32 @@ def test_non_existing_weight_file(): "9.0 17.0 0.0\n" ) off_file.close() - with pytest.raises(FileNotFoundError): - alpha = gd.AlphaComplex(off_file="alphacomplexdoc.off", - weight_file="pouetpouettralala.toubiloubabdou") + with pytest.warns(DeprecationWarning): + alpha = gd.AlphaComplex(off_file="alphacomplexdoc.off") +def test_non_existing_off_file(): + with pytest.raises(FileNotFoundError): + alpha = gd.AlphaComplex(off_file="pouetpouettralala.toubiloubabdou") -def test_inconsistency_off_weight_file(): - off_file = open("alphacomplexdoc.off", "w") - off_file.write("OFF \n" \ - "7 0 0 \n" \ - "1.0 1.0 0.0\n" \ - "7.0 0.0 0.0\n" \ - "4.0 6.0 0.0\n" \ - "9.0 6.0 0.0\n" \ - "0.0 14.0 0.0\n" \ - "2.0 19.0 0.0\n" \ - "9.0 17.0 0.0\n" ) - off_file.close() - # 7 points, 8 weights, on purpose - weight_file = open("alphacomplexdoc.wgt", "w") - weight_file.write("5.0\n" \ - "2.0\n" \ - "7.0\n" \ - "4.0\n" \ - "9.0\n" \ - "0.0\n" \ - "2.0\n" \ - "9.0\n" ) - weight_file.close() - +def test_inconsistency_points_and_weights(): + 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]] with pytest.raises(ValueError): - alpha = gd.AlphaComplex(off_file="alphacomplexdoc.off", - weight_file="alphacomplexdoc.wgt") + # 7 points, 8 weights, on purpose + alpha = gd.AlphaComplex(points = points, + weights = [1., 2., 3., 4., 5., 6., 7., 8.]) - # 7 points, 6 weights, on purpose with pytest.raises(ValueError): - alpha = gd.AlphaComplex(off_file="alphacomplexdoc.off", - weights=[1., 2., 3., 4., 5., 6.]) - -def _with_or_without_weight_file(precision): - off_file = open("weightalphacomplex.off", "w") - off_file.write("OFF \n" \ - "5 0 0 \n" \ - "1. -1. -1. \n" \ - "-1. 1. -1. \n" \ - "-1. -1. 1. \n" \ - "1. 1. 1. \n" \ - "2. 2. 2.") - off_file.close() - - weight_file = open("weightalphacomplex.wgt", "w") - weight_file.write("4.0\n" \ - "4.0\n" \ - "4.0\n" \ - "4.0\n" \ - "1.0\n" ) - weight_file.close() - - stree_from_files = gd.AlphaComplex(off_file="weightalphacomplex.off", - weight_file="weightalphacomplex.wgt", - precision = precision).create_simplex_tree() + # 7 points, 6 weights, on purpose + alpha = gd.AlphaComplex(points = points, + weights = [1., 2., 3., 4., 5., 6.]) +def _doc_example(precision): stree_from_values = gd.AlphaComplex(points=[[ 1., -1., -1.], [-1., 1., -1.], [-1., -1., 1.], @@ -348,8 +305,11 @@ def _with_or_without_weight_file(precision): weights = [4., 4., 4., 4., 1.], precision = precision).create_simplex_tree() - assert stree_from_files == stree_from_values + 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.) -def test_with_or_without_weight_file(): +def test_doc_example(): for precision in ['fast', 'safe', 'exact']: - _with_or_without_weight_file(precision) + _doc_example(precision) diff --git a/src/python/test/test_reader_utils.py b/src/python/test/test_reader_utils.py index 91de9ba0..4fc7c00f 100755 --- a/src/python/test/test_reader_utils.py +++ b/src/python/test/test_reader_utils.py @@ -125,19 +125,3 @@ def test_read_persistence_intervals_with_dimension(): 1: [(9.6, 14.0), (3.0, float("Inf"))], 3: [(34.2, 34.974)], } - - -def test_non_existing_weights_file(): - with raises(FileNotFoundError): - # Try to open a non existing file - persistence = gd.read_weights(weight_file="pouetpouettralala.toubiloubabdou") - -def test_read_weights(): - # Create test file - test_file = open("test_read_weights.wgt", "w") - test_file.write( - "2.7\n 9.6 \n\t34.2\n3.\t\n\n" - ) - test_file.close() - weights = gd.read_weights(weight_file = "test_read_weights.wgt") - assert weights == [2.7, 9.6, 34.2, 3.] -- cgit v1.2.3 From 10b04732e032f0b45542c6d08d4d774bce7ddc23 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 8 Apr 2021 08:56:35 +0200 Subject: Some documentation for alpha complex 3d specific version --- src/python/doc/alpha_complex_ref.rst | 7 ++++++- src/python/doc/alpha_complex_sum.inc | 24 ++++++++++++------------ src/python/doc/alpha_complex_user.rst | 12 +++++++++--- 3 files changed, 27 insertions(+), 16 deletions(-) (limited to 'src/python/doc/alpha_complex_user.rst') diff --git a/src/python/doc/alpha_complex_ref.rst b/src/python/doc/alpha_complex_ref.rst index 7da79543..49321368 100644 --- a/src/python/doc/alpha_complex_ref.rst +++ b/src/python/doc/alpha_complex_ref.rst @@ -9,6 +9,11 @@ Alpha complex reference manual .. autoclass:: gudhi.AlphaComplex :members: :undoc-members: - :show-inheritance: .. automethod:: gudhi.AlphaComplex.__init__ + +.. autoclass:: gudhi.AlphaComplex3D + :members: + :undoc-members: + + .. automethod:: gudhi.AlphaComplex3D.__init__ diff --git a/src/python/doc/alpha_complex_sum.inc b/src/python/doc/alpha_complex_sum.inc index aeab493f..5c76fd54 100644 --- a/src/python/doc/alpha_complex_sum.inc +++ b/src/python/doc/alpha_complex_sum.inc @@ -1,15 +1,15 @@ .. table:: :widths: 30 40 30 - +----------------------------------------------------------------+-------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------+ - | .. figure:: | Alpha complex is a simplicial complex constructed from the finite | :Author: Vincent Rouvreau | - | ../../doc/Alpha_complex/alpha_complex_representation.png | cells of a Delaunay Triangulation. It has the same persistent homology | | - | :alt: Alpha complex representation | as the Čech complex and is significantly smaller. | :Since: GUDHI 2.0.0 | - | :figclass: align-center | | | - | | | :License: MIT (`GPL v3 `_) | - | | | | - | | | :Requires: `Eigen `_ :math:`\geq` 3.1.0 and `CGAL `_ :math:`\geq` 4.11.0 | - | | | | - +----------------------------------------------------------------+-------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------+ - | * :doc:`alpha_complex_user` | * :doc:`alpha_complex_ref` | - +----------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +----------------------------------------------------------------+-------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+ + | .. figure:: | Alpha complex is a simplicial complex constructed from the finite | :Author: Vincent Rouvreau | + | ../../doc/Alpha_complex/alpha_complex_representation.png | cells of a Delaunay Triangulation. It has the same persistent homology | | + | :alt: Alpha complex representation | as the Čech complex and is significantly smaller. | :Since: GUDHI 2.0.0 | + | :figclass: align-center | | | + | | | :License: MIT (`GPL v3 `_) | + | | | | + | | | :Requires: `Eigen `_ :math:`\geq` 3.1.0 and `CGAL `_ :math:`\geq` 5.1 | + | | | | + +----------------------------------------------------------------+-------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+ + | * :doc:`alpha_complex_user` | * :doc:`alpha_complex_ref` | + +----------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/src/python/doc/alpha_complex_user.rst b/src/python/doc/alpha_complex_user.rst index 2b4b75cf..13187f1f 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -9,7 +9,7 @@ Definition .. include:: alpha_complex_sum.inc -:doc:`AlphaComplex ` is constructing a :doc:`SimplexTree ` using +:class:`~gudhi.AlphaComplex` is constructing a :doc:`SimplexTree ` using `Delaunay Triangulation `_ :cite:`cgal:hdj-t-19b` from the `Computational Geometry Algorithms Library `_ :cite:`cgal:eb-19b`. @@ -176,8 +176,6 @@ In the following example, a threshold of :math:`\alpha^2 = 32.0` is used. Weighted specific version ^^^^^^^^^^^^^^^^^^^^^^^^^ -:Requires: `Eigen `_ :math:`\geq` 3.1.0 and `CGAL `_ :math:`\geq` 5.1.0. - A weighted version for Alpha complex is available. It is like a usual Alpha complex, but based on a `CGAL regular triangulation `_ of Delaunay. @@ -259,3 +257,11 @@ Then, it computes the persistence diagram and displays it: dgm = stree.persistence() gd.plot_persistence_diagram(dgm, legend = True) plt.show() + +3d specific version +^^^^^^^^^^^^^^^^^^^ + +:Requires: `Eigen `_ :math:`\geq` 3.1.0 and `CGAL `_ :math:`\geq` 4.11.0. + +A specific module for Alpha complex is available in 3d (cf. :class:`~gudhi.AlphaComplex3D`) and +allows to construct standard and weighted versions of alpha complexes. \ No newline at end of file -- cgit v1.2.3 From cfed19a5dc9c7c0aabf91248a25a6fb82be6900b Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 22 Apr 2021 10:28:12 +0200 Subject: Workaround doc issue on OSx --- src/python/doc/alpha_complex_user.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/python/doc/alpha_complex_user.rst') diff --git a/src/python/doc/alpha_complex_user.rst b/src/python/doc/alpha_complex_user.rst index 13187f1f..1c2fb8e7 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -205,7 +205,10 @@ Then, it is asked to display information about the alpha complex. The output is: -.. testoutput:: +.. + the line below should be a '.. testoutput::' but order fails in the output on OSx + +.. code-block:: text Weighted alpha complex is of dimension 3 - 29 simplices - 5 vertices. [0] -> -4.00 -- cgit v1.2.3 From 620e23bef5e209d2596d1d99a7284fda77f420c0 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 22 Apr 2021 12:15:35 +0200 Subject: On azure, got 'expected nothing, got ...' error. Let's try another approach --- src/python/doc/alpha_complex_user.rst | 55 +++++++++++++++++------------------ 1 file changed, 26 insertions(+), 29 deletions(-) (limited to 'src/python/doc/alpha_complex_user.rst') diff --git a/src/python/doc/alpha_complex_user.rst b/src/python/doc/alpha_complex_user.rst index 1c2fb8e7..d15af56a 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -200,46 +200,43 @@ Then, it is asked to display information about the alpha complex. print('Weighted alpha complex is of dimension ', stree.dimension(), ' - ', stree.num_simplices(), ' simplices - ', stree.num_vertices(), ' vertices.') fmt = '%s -> %.2f' - for filtered_value in stree.get_filtration(): - print(fmt % tuple(filtered_value)) + for simplex in stree.get_simplices(): + print(fmt % tuple(simplex)) The output is: -.. - the line below should be a '.. testoutput::' but order fails in the output on OSx - -.. code-block:: text +.. testoutput:: Weighted alpha complex is of dimension 3 - 29 simplices - 5 vertices. - [0] -> -4.00 - [1] -> -4.00 - [2] -> -4.00 - [3] -> -4.00 + [0, 1, 2, 3] -> -1.00 + [0, 1, 2] -> -1.33 + [0, 1, 3, 4] -> 95.00 + [0, 1, 3] -> -1.33 + [0, 1, 4] -> 95.00 [0, 1] -> -2.00 + [0, 2, 3, 4] -> 95.00 + [0, 2, 3] -> -1.33 + [0, 2, 4] -> 95.00 [0, 2] -> -2.00 - [1, 2] -> -2.00 + [0, 3, 4] -> 23.00 [0, 3] -> -2.00 - [1, 3] -> -2.00 - [2, 3] -> -2.00 - [0, 2, 3] -> -1.33 - [1, 2, 3] -> -1.33 - [0, 1, 2] -> -1.33 - [0, 1, 3] -> -1.33 - [0, 1, 2, 3] -> -1.00 - [4] -> -1.00 - [3, 4] -> -1.00 [0, 4] -> 23.00 - [1, 4] -> 23.00 - [2, 4] -> 23.00 - [0, 3, 4] -> 23.00 + [0] -> -4.00 + [1, 2, 3, 4] -> 95.00 + [1, 2, 3] -> -1.33 + [1, 2, 4] -> 95.00 + [1, 2] -> -2.00 [1, 3, 4] -> 23.00 + [1, 3] -> -2.00 + [1, 4] -> 23.00 + [1] -> -4.00 [2, 3, 4] -> 23.00 - [0, 1, 4] -> 95.00 - [0, 2, 4] -> 95.00 - [1, 2, 4] -> 95.00 - [0, 1, 3, 4] -> 95.00 - [0, 2, 3, 4] -> 95.00 - [1, 2, 3, 4] -> 95.00 + [2, 3] -> -2.00 + [2, 4] -> 23.00 + [2] -> -4.00 + [3, 4] -> -1.00 + [3] -> -4.00 + [4] -> -1.00 Example from OFF file ^^^^^^^^^^^^^^^^^^^^^ -- cgit v1.2.3 From 05aff3cba18e1e14549747f3b0673edd6d704d47 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 9 Jun 2021 08:22:52 +0200 Subject: doc review: remove 'specific' --- src/python/doc/alpha_complex_user.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/python/doc/alpha_complex_user.rst') diff --git a/src/python/doc/alpha_complex_user.rst b/src/python/doc/alpha_complex_user.rst index d15af56a..985ee962 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -173,8 +173,8 @@ of speed-up, since we always first build the full filtered complex, so it is rec :paramref:`~gudhi.AlphaComplex.create_simplex_tree.max_alpha_square`. In the following example, a threshold of :math:`\alpha^2 = 32.0` is used. -Weighted specific version -^^^^^^^^^^^^^^^^^^^^^^^^^ +Weighted version +^^^^^^^^^^^^^^^^ A weighted version for Alpha complex is available. It is like a usual Alpha complex, but based on a `CGAL regular triangulation `_ -- cgit v1.2.3 From f1effb5b5bf30275a692b51528ec068f7cef84ab Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 9 Jun 2021 11:47:34 +0200 Subject: doc review: use 120 characters per line and warning about the numbering of vertices for 3d version --- src/python/doc/alpha_complex_user.rst | 10 +++++++--- src/python/gudhi/alpha_complex.pyx | 33 ++++++++++++--------------------- src/python/gudhi/alpha_complex_3d.pyx | 31 +++++++++++++++---------------- 3 files changed, 34 insertions(+), 40 deletions(-) (limited to 'src/python/doc/alpha_complex_user.rst') diff --git a/src/python/doc/alpha_complex_user.rst b/src/python/doc/alpha_complex_user.rst index 985ee962..e615d0be 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -34,8 +34,6 @@ 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 ------------------- @@ -264,4 +262,10 @@ Then, it computes the persistence diagram and displays it: :Requires: `Eigen `_ :math:`\geq` 3.1.0 and `CGAL `_ :math:`\geq` 4.11.0. A specific module for Alpha complex is available in 3d (cf. :class:`~gudhi.AlphaComplex3D`) and -allows to construct standard and weighted versions of alpha complexes. \ No newline at end of file +allows to construct standard and weighted versions of alpha complexes. + +Remark +"""""" + +* Contrary to the dD version, with the 3d version, the vertices in the output simplex tree are not guaranteed to match + the order of the input points. One can use :func:`~gudhi.AlphaComplex3D.get_point` to get the initial point back. diff --git a/src/python/gudhi/alpha_complex.pyx b/src/python/gudhi/alpha_complex.pyx index caebfab0..2cf4738b 100644 --- a/src/python/gudhi/alpha_complex.pyx +++ b/src/python/gudhi/alpha_complex.pyx @@ -36,22 +36,18 @@ cdef extern from "Alpha_complex_interface.h" namespace "Gudhi": # AlphaComplex python interface cdef class AlphaComplex: - """AlphaComplex is a simplicial complex constructed from the finite cells - of a Delaunay Triangulation. + """AlphaComplex is a simplicial complex constructed from the finite cells of a Delaunay Triangulation. - The filtration value of each simplex is computed as the square of the - circumradius of the simplex if the circumsphere is empty (the simplex is - then said to be Gabriel), and as the minimum of the filtration values of - the codimension 1 cofaces that make it not Gabriel otherwise. + The filtration value of each simplex is computed as the square of the circumradius of the simplex if the + circumsphere is empty (the simplex is then said to be Gabriel), and as the minimum of the filtration values of the + codimension 1 cofaces that make it not Gabriel otherwise. - All simplices that have a filtration value strictly greater than a given - alpha squared value are not inserted into the complex. + All simplices that have a filtration value strictly greater than a given alpha squared value are not inserted into + the complex. .. note:: - When Alpha_complex is constructed with an infinite value of alpha, the - complex is a Delaunay complex. - + When Alpha_complex is constructed with an infinite value of alpha, the complex is a Delaunay complex. """ cdef Alpha_complex_interface * this_ptr @@ -63,18 +59,14 @@ cdef class AlphaComplex: :param points: A list of points in d-Dimension. :type points: Iterable[Iterable[float]] - :param off_file: **[deprecated]** An `OFF file style `_ - name. - If an `off_file` is given with `points` as arguments, only points from the file are - taken into account. + :param off_file: **[deprecated]** An `OFF file style `_ name. + If an `off_file` is given with `points` as arguments, only points from the file are taken into account. :type off_file: string - :param weights: A list of weights. If set, the number of weights must correspond to the - number of points. + :param weights: A list of weights. If set, the number of weights must correspond to the number of points. :type weights: Iterable[float] - :param precision: Alpha complex precision can be 'fast', 'safe' or 'exact'. Default is - 'safe'. + :param precision: Alpha complex precision can be 'fast', 'safe' or 'exact'. Default is 'safe'. :type precision: string :raises FileNotFoundError: **[deprecated]** If `off_file` is set but not found. @@ -83,8 +75,7 @@ cdef class AlphaComplex: # The real cython constructor def __cinit__(self, points = [], off_file = '', weights=None, precision = 'safe'): - assert precision in ['fast', 'safe', 'exact'], \ - "Alpha complex precision can only be 'fast', 'safe' or 'exact'" + assert precision in ['fast', 'safe', 'exact'], "Alpha complex precision can only be 'fast', 'safe' or 'exact'" cdef bool fast = precision == 'fast' cdef bool exact = precision == 'exact' diff --git a/src/python/gudhi/alpha_complex_3d.pyx b/src/python/gudhi/alpha_complex_3d.pyx index 3959004a..4d3fe59c 100644 --- a/src/python/gudhi/alpha_complex_3d.pyx +++ b/src/python/gudhi/alpha_complex_3d.pyx @@ -36,22 +36,24 @@ cdef extern from "Alpha_complex_interface_3d.h" namespace "Gudhi": # AlphaComplex3D python interface cdef class AlphaComplex3D: - """AlphaComplex3D is a simplicial complex constructed from the finite cells - of a Delaunay Triangulation. + """AlphaComplex3D is a simplicial complex constructed from the finite cells of a Delaunay Triangulation. - The filtration value of each simplex is computed as the square of the - circumradius of the simplex if the circumsphere is empty (the simplex is - then said to be Gabriel), and as the minimum of the filtration values of - the codimension 1 cofaces that make it not Gabriel otherwise. + The filtration value of each simplex is computed as the square of the circumradius of the simplex if the + circumsphere is empty (the simplex is then said to be Gabriel), and as the minimum of the filtration values of the + codimension 1 cofaces that make it not Gabriel otherwise. - All simplices that have a filtration value strictly greater than a given - alpha squared value are not inserted into the complex. + All simplices that have a filtration value strictly greater than a given alpha squared value are not inserted into + the complex. .. note:: - When AlphaComplex3D is constructed with an infinite value of alpha, the - complex is a Delaunay complex. + When AlphaComplex3D is constructed with an infinite value of alpha, the complex is a Delaunay complex. + .. warning:: + + Contrary to the dD version, with the 3d version, the vertices in the output simplex tree are not guaranteed to + match the order of the input points. One can use :func:`~gudhi.AlphaComplex3D.get_point` to get the initial + point back. """ cdef Alpha_complex_interface_3d * this_ptr @@ -63,12 +65,10 @@ cdef class AlphaComplex3D: :param points: A list of points in d-Dimension. :type points: Iterable[Iterable[float]] - :param weights: A list of weights. If set, the number of weights must correspond to the - number of points. + :param weights: A list of weights. If set, the number of weights must correspond to the number of points. :type weights: Iterable[float] - :param precision: Alpha complex precision can be 'fast', 'safe' or 'exact'. Default is - 'safe'. + :param precision: Alpha complex precision can be 'fast', 'safe' or 'exact'. Default is 'safe'. :type precision: string :raises ValueError: In case of inconsistency between the number of points and weights. @@ -76,8 +76,7 @@ cdef class AlphaComplex3D: # The real cython constructor def __cinit__(self, points = [], weights=[], precision = 'safe'): - assert precision in ['fast', 'safe', 'exact'], \ - "Alpha complex precision can only be 'fast', 'safe' or 'exact'" + assert precision in ['fast', 'safe', 'exact'], "Alpha complex precision can only be 'fast', 'safe' or 'exact'" cdef bool fast = precision == 'fast' cdef bool exact = precision == 'exact' -- cgit v1.2.3 From 35d82325366afa1131c12d9e38599ff9e5ecdd84 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 21 Jun 2021 14:53:54 +0200 Subject: Remove advice to use CGAL > 5.0 for performances reason as CGAL 5.1 is required for weighted version --- src/python/doc/alpha_complex_user.rst | 1 - 1 file changed, 1 deletion(-) (limited to 'src/python/doc/alpha_complex_user.rst') diff --git a/src/python/doc/alpha_complex_user.rst b/src/python/doc/alpha_complex_user.rst index e615d0be..d7b09246 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -33,7 +33,6 @@ Remarks 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. Example from points ------------------- -- cgit v1.2.3 From f70e6f26f329428184fc5cf935ad4dfc20648bfb Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 1 Jul 2021 17:30:38 +0200 Subject: Revert AlphaComplex3D. To be done with periodic --- .../example/Alpha_complex_3d_from_points.cpp | 29 ++-- .../Weighted_alpha_complex_3d_from_points.cpp | 29 ++-- src/Alpha_complex/include/gudhi/Alpha_complex_3d.h | 19 +-- .../test/Alpha_complex_3d_unit_test.cpp | 30 ---- .../test/Weighted_alpha_complex_unit_test.cpp | 2 +- src/python/CMakeLists.txt | 2 - src/python/doc/alpha_complex_ref.rst | 6 - src/python/doc/alpha_complex_user.rst | 14 -- src/python/gudhi/alpha_complex_3d.pyx | 135 ----------------- src/python/include/Alpha_complex_factory.h | 35 ----- src/python/test/test_alpha_complex_3d.py | 159 --------------------- 11 files changed, 42 insertions(+), 418 deletions(-) delete mode 100644 src/python/gudhi/alpha_complex_3d.pyx delete mode 100755 src/python/test/test_alpha_complex_3d.py (limited to 'src/python/doc/alpha_complex_user.rst') diff --git a/src/Alpha_complex/example/Alpha_complex_3d_from_points.cpp b/src/Alpha_complex/example/Alpha_complex_3d_from_points.cpp index dd3c0225..a2c85138 100644 --- a/src/Alpha_complex/example/Alpha_complex_3d_from_points.cpp +++ b/src/Alpha_complex/example/Alpha_complex_3d_from_points.cpp @@ -34,22 +34,23 @@ int main(int argc, char **argv) { Alpha_complex_3d alpha_complex_from_points(points); Gudhi::Simplex_tree<> simplex; - alpha_complex_from_points.create_complex(simplex); - // ---------------------------------------------------------------------------- - // Display information about the alpha complex - // ---------------------------------------------------------------------------- - std::clog << "Alpha complex is of dimension " << simplex.dimension() << " - " << simplex.num_simplices() - << " simplices - " << simplex.num_vertices() << " vertices." << std::endl; + if (alpha_complex_from_points.create_complex(simplex)) { + // ---------------------------------------------------------------------------- + // Display information about the alpha complex + // ---------------------------------------------------------------------------- + std::clog << "Alpha complex is of dimension " << simplex.dimension() << " - " << simplex.num_simplices() + << " simplices - " << simplex.num_vertices() << " vertices." << std::endl; - std::clog << "Iterator on alpha complex simplices in the filtration order, with [filtration value]:" << std::endl; - for (auto f_simplex : simplex.filtration_simplex_range()) { - std::clog << " ( "; - for (auto vertex : simplex.simplex_vertex_range(f_simplex)) { - std::clog << vertex << " "; + std::clog << "Iterator on alpha complex simplices in the filtration order, with [filtration value]:" << std::endl; + for (auto f_simplex : simplex.filtration_simplex_range()) { + std::clog << " ( "; + for (auto vertex : simplex.simplex_vertex_range(f_simplex)) { + std::clog << vertex << " "; + } + std::clog << ") -> " + << "[" << simplex.filtration(f_simplex) << "] "; + std::clog << std::endl; } - std::clog << ") -> " - << "[" << simplex.filtration(f_simplex) << "] "; - std::clog << std::endl; } return 0; } diff --git a/src/Alpha_complex/example/Weighted_alpha_complex_3d_from_points.cpp b/src/Alpha_complex/example/Weighted_alpha_complex_3d_from_points.cpp index 507d6413..ee12d418 100644 --- a/src/Alpha_complex/example/Weighted_alpha_complex_3d_from_points.cpp +++ b/src/Alpha_complex/example/Weighted_alpha_complex_3d_from_points.cpp @@ -30,22 +30,23 @@ int main(int argc, char **argv) { Weighted_alpha_complex_3d alpha_complex_from_points(weighted_points); Gudhi::Simplex_tree<> simplex; - alpha_complex_from_points.create_complex(simplex); - // ---------------------------------------------------------------------------- - // Display information about the alpha complex - // ---------------------------------------------------------------------------- - std::clog << "Weighted alpha complex is of dimension " << simplex.dimension() << " - " << simplex.num_simplices() - << " simplices - " << simplex.num_vertices() << " vertices." << std::endl; + if (alpha_complex_from_points.create_complex(simplex)) { + // ---------------------------------------------------------------------------- + // Display information about the alpha complex + // ---------------------------------------------------------------------------- + std::clog << "Weighted alpha complex is of dimension " << simplex.dimension() << " - " << simplex.num_simplices() + << " simplices - " << simplex.num_vertices() << " vertices." << std::endl; - std::clog << "Iterator on weighted alpha complex simplices in the filtration order, with [filtration value]:" << std::endl; - for (auto f_simplex : simplex.filtration_simplex_range()) { - std::clog << " ( "; - for (auto vertex : simplex.simplex_vertex_range(f_simplex)) { - std::clog << vertex << " "; + std::clog << "Iterator on weighted alpha complex simplices in the filtration order, with [filtration value]:" << std::endl; + for (auto f_simplex : simplex.filtration_simplex_range()) { + std::clog << " ( "; + for (auto vertex : simplex.simplex_vertex_range(f_simplex)) { + std::clog << vertex << " "; + } + std::clog << ") -> " + << "[" << simplex.filtration(f_simplex) << "] "; + std::clog << std::endl; } - std::clog << ") -> " - << "[" << simplex.filtration(f_simplex) << "] "; - std::clog << std::endl; } return 0; } diff --git a/src/Alpha_complex/include/gudhi/Alpha_complex_3d.h b/src/Alpha_complex/include/gudhi/Alpha_complex_3d.h index 73f9dd41..4e5fc933 100644 --- a/src/Alpha_complex/include/gudhi/Alpha_complex_3d.h +++ b/src/Alpha_complex/include/gudhi/Alpha_complex_3d.h @@ -48,7 +48,6 @@ #include // for std::unique_ptr #include // for std::conditional and std::enable_if #include // for numeric_limits<> -#include // 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 @@ -429,18 +428,19 @@ 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. * - * @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. + * @return true if creation succeeds, false otherwise. * * @pre The simplicial complex must be empty (no vertices). * */ template - void create_complex(SimplicialComplexForAlpha3d& complex, + bool create_complex(SimplicialComplexForAlpha3d& complex, Filtration_value max_alpha_square = std::numeric_limits::infinity()) { - GUDHI_CHECK(complex.num_vertices() == 0, - std::invalid_argument("Alpha_complex_3d create_complex - The complex given as argument is not empty")); + if (complex.num_vertices() > 0) { + std::cerr << "Alpha_complex_3d create_complex - complex is not empty\n"; + return false; // ----- >> + } using Complex_vertex_handle = typename SimplicialComplexForAlpha3d::Vertex_handle; using Simplex_tree_vector_vertex = std::vector; @@ -461,8 +461,10 @@ 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) - throw std::domain_error("Alpha_complex_3d create_complex - no triangulation as points are on a 2d plane"); + if (objects.size() == 0) { + std::cerr << "Alpha_complex_3d create_complex - no triangulation as points are on a 2d plane\n"; + return false; // ----- >> + } using Alpha_value_iterator = typename std::vector::const_iterator; Alpha_value_iterator alpha_value_iterator = alpha_values.begin(); @@ -557,6 +559,7 @@ 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 94021954..a4ecb6ad 100644 --- a/src/Alpha_complex/test/Alpha_complex_3d_unit_test.cpp +++ b/src/Alpha_complex/test/Alpha_complex_3d_unit_test.cpp @@ -11,7 +11,6 @@ #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MODULE "alpha_complex_3d" #include -#include #include // float comparison #include @@ -37,7 +36,6 @@ using Safe_alpha_complex_3d = using Exact_alpha_complex_3d = Gudhi::alpha_complex::Alpha_complex_3d; - template std::vector get_points() { std::vector points; @@ -199,31 +197,3 @@ BOOST_AUTO_TEST_CASE(Alpha_complex_3d_from_points) { ++safe_sh; } } - -typedef boost::mpl::list list_of_alpha_variants; - -BOOST_AUTO_TEST_CASE_TEMPLATE(Alpha_complex_3d_exceptions_points_on_plane, Alpha, list_of_alpha_variants) { - std::vector 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()); - 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 4e1a38df..875704ee 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; - alpha_complex_3D_from_weighted_points.create_complex(w_simplex_3); + BOOST_CHECK(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/CMakeLists.txt b/src/python/CMakeLists.txt index 669239b8..bfa78131 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -62,7 +62,6 @@ if(PYTHONINTERP_FOUND) set(GUDHI_PYTHON_MODULES "${GUDHI_PYTHON_MODULES}'subsampling', ") set(GUDHI_PYTHON_MODULES "${GUDHI_PYTHON_MODULES}'tangential_complex', ") set(GUDHI_PYTHON_MODULES "${GUDHI_PYTHON_MODULES}'alpha_complex', ") - set(GUDHI_PYTHON_MODULES "${GUDHI_PYTHON_MODULES}'alpha_complex_3d', ") set(GUDHI_PYTHON_MODULES "${GUDHI_PYTHON_MODULES}'euclidean_witness_complex', ") set(GUDHI_PYTHON_MODULES "${GUDHI_PYTHON_MODULES}'euclidean_strong_witness_complex', ") # Modules that should not be auto-imported in __init__.py @@ -158,7 +157,6 @@ if(PYTHONINTERP_FOUND) set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'nerve_gic', ") endif () if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0) - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'alpha_complex_3d', ") set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'subsampling', ") set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'tangential_complex', ") set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'euclidean_witness_complex', ") diff --git a/src/python/doc/alpha_complex_ref.rst b/src/python/doc/alpha_complex_ref.rst index 49321368..eaa72551 100644 --- a/src/python/doc/alpha_complex_ref.rst +++ b/src/python/doc/alpha_complex_ref.rst @@ -11,9 +11,3 @@ Alpha complex reference manual :undoc-members: .. automethod:: gudhi.AlphaComplex.__init__ - -.. autoclass:: gudhi.AlphaComplex3D - :members: - :undoc-members: - - .. automethod:: gudhi.AlphaComplex3D.__init__ diff --git a/src/python/doc/alpha_complex_user.rst b/src/python/doc/alpha_complex_user.rst index d7b09246..db0ccdc9 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -254,17 +254,3 @@ Then, it computes the persistence diagram and displays it: dgm = stree.persistence() gd.plot_persistence_diagram(dgm, legend = True) plt.show() - -3d specific version -^^^^^^^^^^^^^^^^^^^ - -:Requires: `Eigen `_ :math:`\geq` 3.1.0 and `CGAL `_ :math:`\geq` 4.11.0. - -A specific module for Alpha complex is available in 3d (cf. :class:`~gudhi.AlphaComplex3D`) and -allows to construct standard and weighted versions of alpha complexes. - -Remark -"""""" - -* Contrary to the dD version, with the 3d version, the vertices in the output simplex tree are not guaranteed to match - the order of the input points. One can use :func:`~gudhi.AlphaComplex3D.get_point` to get the initial point back. diff --git a/src/python/gudhi/alpha_complex_3d.pyx b/src/python/gudhi/alpha_complex_3d.pyx deleted file mode 100644 index 578011a7..00000000 --- a/src/python/gudhi/alpha_complex_3d.pyx +++ /dev/null @@ -1,135 +0,0 @@ -# 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 __future__ import print_function -from cython cimport numeric -from libcpp.vector cimport vector -from libcpp.utility cimport pair -from libcpp.string cimport string -from libcpp cimport bool -from libc.stdint cimport intptr_t -import errno -import os -import warnings - -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) 2021 Inria" -__license__ = "GPL v3" - -cdef extern from "Alpha_complex_interface_3d.h" namespace "Gudhi": - cdef cppclass Alpha_complex_interface_3d "Gudhi::alpha_complex::Alpha_complex_interface_3d": - Alpha_complex_interface_3d(vector[vector[double]] points, vector[double] weights, 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) nogil except + - -# AlphaComplex3D python interface -cdef class AlphaComplex3D: - """AlphaComplex3D is a simplicial complex constructed from the finite cells of a Delaunay Triangulation. - - The filtration value of each simplex is computed as the square of the circumradius of the simplex if the - circumsphere is empty (the simplex is then said to be Gabriel), and as the minimum of the filtration values of the - codimension 1 cofaces that make it not Gabriel otherwise. - - All simplices that have a filtration value strictly greater than a given alpha squared value are not inserted into - the complex. - - .. note:: - - When AlphaComplex3D is constructed with an infinite value of alpha, the complex is a Delaunay complex. - - .. warning:: - - Contrary to the dD version, with the 3d version, the vertices in the output simplex tree are not guaranteed to - match the order of the input points. One can use :func:`~gudhi.AlphaComplex3D.get_point` to get the initial - point back. - """ - - cdef Alpha_complex_interface_3d * this_ptr - - # Fake constructor that does nothing but documenting the constructor - def __init__(self, points=[], weights=[], precision='safe'): - """AlphaComplex3D constructor. - - :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. - :type weights: Iterable[float] - - :param precision: Alpha complex precision can be 'fast', 'safe' or 'exact'. Default is 'safe'. - :type precision: string - - :raises ValueError: If the given points are not in 3d. - :raises ValueError: In case of inconsistency between the number of points and weights. - """ - - # The real cython constructor - def __cinit__(self, points = [], weights=[], precision = 'safe'): - assert precision in ['fast', 'safe', 'exact'], "Alpha complex precision can only be 'fast', 'safe' or 'exact'" - cdef bool fast = precision == 'fast' - cdef bool exact = precision == 'exact' - - if len(points) > 0: - if len(points[0]) != 3: - raise ValueError("AlphaComplex3D only accepts 3d points as an input") - - # weights are set but is inconsistent with the number of points - if len(weights) != 0 and len(weights) != len(points): - raise ValueError("Inconsistency between the number of points and weights") - - # need to copy the points to use them without the gil - cdef vector[vector[double]] pts - cdef vector[double] wgts - pts = points - wgts = weights - with nogil: - self.this_ptr = new Alpha_complex_interface_3d(pts, wgts, fast, exact) - - def __dealloc__(self): - if self.this_ptr != NULL: - del self.this_ptr - - def __is_defined(self): - """Returns true if AlphaComplex3D pointer is not NULL. - """ - return self.this_ptr != NULL - - def get_point(self, vertex): - """This function returns the point corresponding to a given vertex from the :class:`~gudhi.SimplexTree`. - - :param vertex: The vertex. - :type vertex: int - :rtype: list of float - :returns: the point. - """ - return self.this_ptr.get_point(vertex) - - def create_simplex_tree(self, max_alpha_square = float('inf')): - """ - :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 - :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 - cdef intptr_t stree_int_ptr=stree.thisptr - with nogil: - self.this_ptr.create_simplex_tree(stree_int_ptr, - mas) - return stree diff --git a/src/python/include/Alpha_complex_factory.h b/src/python/include/Alpha_complex_factory.h index fbbf8896..298469fe 100644 --- a/src/python/include/Alpha_complex_factory.h +++ b/src/python/include/Alpha_complex_factory.h @@ -147,41 +147,6 @@ class Inexact_alpha_complex_dD final : public Abstract_alpha_complex { Alpha_complex alpha_complex_; }; -template -class Alpha_complex_3D final : public Abstract_alpha_complex { - private: - using Bare_point = typename Alpha_complex_3d::Bare_point_3; - using Point = typename Alpha_complex_3d::Point_3; - - static Bare_point pt_cython_to_cgal_3(std::vector const& vec) { - return Bare_point(vec[0], vec[1], vec[2]); - } - - public: - Alpha_complex_3D(const std::vector>& points) - : alpha_complex_(boost::adaptors::transform(points, pt_cython_to_cgal_3)) { - } - - Alpha_complex_3D(const std::vector>& points, const std::vector& weights) - : alpha_complex_(boost::adaptors::transform(points, pt_cython_to_cgal_3), weights) { - } - - virtual std::vector get_point(int vh) override { - // Can be a Weighted or a Bare point in function of Weighted - return Point_cgal_to_cython()(alpha_complex_.get_point(vh)); - } - - virtual bool create_simplex_tree(Simplex_tree_interface<>* simplex_tree, double max_alpha_square, - bool default_filtration_value) override { - alpha_complex_.create_complex(*simplex_tree, max_alpha_square); - return true; - } - - private: - Alpha_complex_3d alpha_complex_; -}; - - } // namespace alpha_complex } // namespace Gudhi diff --git a/src/python/test/test_alpha_complex_3d.py b/src/python/test/test_alpha_complex_3d.py deleted file mode 100755 index a5d9373b..00000000 --- a/src/python/test/test_alpha_complex_3d.py +++ /dev/null @@ -1,159 +0,0 @@ -""" 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 -import numpy as np - -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) - -def test_points_not_in_3d(): - with pytest.raises(ValueError): - alpha = AlphaComplex3D(points = np.random.rand(6,2)) - with pytest.raises(ValueError): - alpha = AlphaComplex3D(points = np.random.rand(6,4)) - - alpha = AlphaComplex3D(points = np.random.rand(6,3)) - assert alpha.__is_defined() == True \ No newline at end of file -- cgit v1.2.3 From 63aadb9a9eca849e1d7557fdced3bc6874426eb1 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Mon, 8 Nov 2021 09:17:17 +0100 Subject: doc review: regular triangulation is not 'of Delaunay' --- src/python/doc/alpha_complex_user.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/python/doc/alpha_complex_user.rst') diff --git a/src/python/doc/alpha_complex_user.rst b/src/python/doc/alpha_complex_user.rst index db0ccdc9..84932c18 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -174,8 +174,7 @@ Weighted version ^^^^^^^^^^^^^^^^ A weighted version for Alpha complex is available. It is like a usual Alpha complex, but based on a -`CGAL regular triangulation `_ -of Delaunay. +`CGAL regular triangulation `_. This example builds the CGAL weighted alpha shapes from a small molecule, and initializes the alpha complex with it. This example is taken from -- cgit v1.2.3 From 1f9b9d2e751332c944d98be366d39d8a69556187 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Wed, 19 Jan 2022 08:14:07 +0100 Subject: Doc review: reword confusing sentence --- src/python/doc/alpha_complex_user.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/python/doc/alpha_complex_user.rst') diff --git a/src/python/doc/alpha_complex_user.rst b/src/python/doc/alpha_complex_user.rst index 94c54053..cfd22742 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -179,8 +179,8 @@ Weighted version A weighted version for Alpha complex is available. It is like a usual Alpha complex, but based on a `CGAL regular triangulation `_. -This example builds the CGAL weighted alpha shapes from a small molecule, and initializes the alpha complex with -it. This example is taken from +This example builds the weighted alpha-complex of a small molecule, where atoms have different sizes. +It is taken from `CGAL 3d weighted alpha shapes `_. Then, it is asked to display information about the alpha complex. -- cgit v1.2.3