From a7decae3cdf47441cbd72c31e794176dbd3739c4 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 25 May 2020 08:21:47 +0200 Subject: C++ version and documentation --- src/python/doc/alpha_complex_user.rst | 21 +++++++++++++++++++-- 1 file changed, 19 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 d49f45b4..c1ed0eaa 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -16,8 +16,25 @@ Definition Remarks ^^^^^^^ -When an :math:`\alpha`-complex is constructed with an infinite value of :math:`\alpha^2`, -the complex is a Delaunay complex (with special filtration values). +* When an :math:`\alpha`-complex is constructed with an infinite value of :math:`\alpha^2`, the complex is a Delaunay + complex (with special filtration values). The Delaunay complex without filtration values is also available by + passing :code:`default_filtration_value = True` to :func:`~gudhi.AlphaComplex.create_simplex_tree`. +* For people only interested in the topology of the Alpha complex (for instance persistence), Alpha complex is + 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 + ones converted to the filtration value type of the simplicial complex. This can be very slow. + If you pass :code:`complexity = 'safe'` (the default) or :code:`complexity = 'fast'`, the filtration values are only + guaranteed to have a small multiplicative error compared to the exact value, see + `CGAL::Lazy_exact_nt::set_relative_precision_of_to_double `_ + for details. 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 + 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 14ee986e2d1802b7b40e3319bea787b5d1624b06 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 29 May 2020 21:35:02 +0200 Subject: Rewrite some summaries --- src/python/doc/alpha_complex_sum.inc | 14 ++++++-------- src/python/doc/alpha_complex_user.rst | 4 +++- src/python/doc/cubical_complex_sum.inc | 6 +++--- src/python/doc/index.rst | 4 ++-- src/python/doc/persistent_cohomology_sum.inc | 4 +--- src/python/doc/rips_complex_sum.inc | 18 +++++------------- src/python/doc/tangential_complex_sum.inc | 8 ++++---- 7 files changed, 24 insertions(+), 34 deletions(-) (limited to 'src/python/doc/alpha_complex_user.rst') diff --git a/src/python/doc/alpha_complex_sum.inc b/src/python/doc/alpha_complex_sum.inc index 3aba0d71..aeab493f 100644 --- a/src/python/doc/alpha_complex_sum.inc +++ b/src/python/doc/alpha_complex_sum.inc @@ -3,15 +3,13 @@ +----------------------------------------------------------------+-------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------+ | .. 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. | | - | :alt: Alpha complex representation | | :Since: GUDHI 2.0.0 | - | :figclass: align-center | The filtration value of each simplex is computed as the **square** of | | - | | the circumradius of the simplex if the circumsphere is empty (the | :License: MIT (`GPL v3 `_) | - | | simplex is then said to be Gabriel), and as the minimum of the | | - | | filtration values of the codimension 1 cofaces that make it not | :Requires: `Eigen `_ :math:`\geq` 3.1.0 and `CGAL `_ :math:`\geq` 4.11.0 | - | | Gabriel otherwise. | | + | ../../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 | | | | | - | | For performances reasons, it is advised to use CGAL :math:`\geq` 5.0.0. | | +----------------------------------------------------------------+-------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------+ | * :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 d49f45b4..e31194a7 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 -`AlphaComplex` is constructing a :doc:`SimplexTree ` using +:doc:`AlphaComplex ` is constructing a :doc:`SimplexTree ` using `Delaunay Triangulation `_ :cite:`cgal:hdj-t-19b` from the `Computational Geometry Algorithms Library `_ :cite:`cgal:eb-19b`. @@ -19,6 +19,8 @@ Remarks When an :math:`\alpha`-complex is constructed with an infinite value of :math:`\alpha^2`, the complex is a Delaunay complex (with special filtration values). +For performances reasons, it is advised to use CGAL :math:`\geq` 5.0.0. + Example from points ------------------- diff --git a/src/python/doc/cubical_complex_sum.inc b/src/python/doc/cubical_complex_sum.inc index 28bf8e94..87db184d 100644 --- a/src/python/doc/cubical_complex_sum.inc +++ b/src/python/doc/cubical_complex_sum.inc @@ -2,9 +2,9 @@ :widths: 30 40 30 +--------------------------------------------------------------------------+----------------------------------------------------------------------+-----------------------------+ - | .. figure:: | The cubical complex is an example of a structured complex useful in | :Author: Pawel Dlotko | - | ../../doc/Bitmap_cubical_complex/Cubical_complex_representation.png | computational mathematics (specially rigorous numerics) and image | | - | :alt: Cubical complex representation | analysis. | :Since: GUDHI 2.0.0 | + | .. figure:: | The cubical complex represents a grid as a cell complex with | :Author: Pawel Dlotko | + | ../../doc/Bitmap_cubical_complex/Cubical_complex_representation.png | cells of all dimensions. | | + | :alt: Cubical complex representation | | :Since: GUDHI 2.0.0 | | :figclass: align-center | | | | | | :License: MIT | | | | | diff --git a/src/python/doc/index.rst b/src/python/doc/index.rst index 13e51047..05bc18b4 100644 --- a/src/python/doc/index.rst +++ b/src/python/doc/index.rst @@ -53,8 +53,8 @@ Tangential complex Topological descriptors computation *********************************** -Persistence cohomology -====================== +Persistent cohomology +===================== .. include:: persistent_cohomology_sum.inc diff --git a/src/python/doc/persistent_cohomology_sum.inc b/src/python/doc/persistent_cohomology_sum.inc index a1ff2eee..58e44b8a 100644 --- a/src/python/doc/persistent_cohomology_sum.inc +++ b/src/python/doc/persistent_cohomology_sum.inc @@ -6,9 +6,7 @@ | ../../doc/Persistent_cohomology/3DTorus_poch.png | a sequence of (homology) groups, capturing global topological | | | :figclass: align-center | features like connected components, holes, cavities, etc. Persistent | :Since: GUDHI 2.0.0 | | | homology studies the evolution -- birth, life and death -- of these | | - | Rips Persistent Cohomology on a 3D | features when the topological space is changing. Consequently, the | :License: MIT | - | Torus | theory is essentially composed of three elements: topological spaces, | | - | | their homology groups and an evolution scheme. | | + | Rips Persistent Cohomology on a 3D Torus | features when the topological space is changing. | :License: MIT | | | | | | | Computation of persistent cohomology using the algorithm of | | | | :cite:`DBLP:journals/dcg/SilvaMV11` and | | diff --git a/src/python/doc/rips_complex_sum.inc b/src/python/doc/rips_complex_sum.inc index 9cd8074b..c123ea2a 100644 --- a/src/python/doc/rips_complex_sum.inc +++ b/src/python/doc/rips_complex_sum.inc @@ -2,21 +2,13 @@ :widths: 30 40 30 +----------------------------------------------------------------+------------------------------------------------------------------------+----------------------------------------------------------------------+ - | .. figure:: | Rips complex is a simplicial complex constructed from a one skeleton | :Authors: Clément Maria, Pawel Dlotko, Vincent Rouvreau, Marc Glisse | - | ../../doc/Rips_complex/rips_complex_representation.png | graph. | | + | .. figure:: | The Vietoris-Rips complex is a simplicial complex built as the | :Authors: Clément Maria, Pawel Dlotko, Vincent Rouvreau, Marc Glisse | + | ../../doc/Rips_complex/rips_complex_representation.png | clique-complex of a proximity graph. | | | :figclass: align-center | | :Since: GUDHI 2.0.0 | - | | The filtration value of each edge is computed from a user-given | | - | | distance function and is inserted until a user-given threshold | :License: MIT | - | | value. | | + | | We also provide sparse approximations, to speed-up the computation | | + | | of persistent homology, and weighted versions, which are more robust | :License: MIT | + | | to outliers. | | | | | | - | | This complex can be built from a point cloud and a distance function, | | - | | or from a distance matrix. | | - | | | | - | | Weighted Rips complex constructs a simplicial complex from a distance | | - | | matrix and weights on vertices. | | - | | | | - | | DTM Rips complex builds a simplicial complex from a point set or | | - | | a distance matrix. | | +----------------------------------------------------------------+------------------------------------------------------------------------+----------------------------------------------------------------------+ | * :doc:`rips_complex_user` | * :doc:`rips_complex_ref` | +----------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/src/python/doc/tangential_complex_sum.inc b/src/python/doc/tangential_complex_sum.inc index 22314a2d..2f330a07 100644 --- a/src/python/doc/tangential_complex_sum.inc +++ b/src/python/doc/tangential_complex_sum.inc @@ -3,10 +3,10 @@ +----------------------------------------------------------------+------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------+ | .. figure:: | A Tangential Delaunay complex is a simplicial complex designed to | :Author: Clément Jamin | - | ../../doc/Tangential_complex/tc_examples.png | reconstruct a :math:`k`-dimensional manifold embedded in :math:`d`- | | - | :figclass: align-center | dimensional Euclidean space. The input is a point sample coming from | :Since: GUDHI 2.0.0 | - | | an unknown manifold. The running time depends only linearly on the | | - | | extrinsic dimension :math:`d` and exponentially on the intrinsic | :License: MIT (`GPL v3 `_) | + | ../../doc/Tangential_complex/tc_examples.png | reconstruct a :math:`k`-dimensional manifold embedded in | | + | :figclass: align-center | :math:`d`-dimensional Euclidean space. The input is a point sample | :Since: GUDHI 2.0.0 | + | | coming from an unknown manifold. The running time depends only linearly| | + | | on the extrinsic dimension :math:`d` and exponentially on the intrinsic| :License: MIT (`GPL v3 `_) | | | dimension :math:`k`. | | | | | :Requires: `Eigen `_ :math:`\geq` 3.1.0 and `CGAL `_ :math:`\geq` 4.11.0 | +----------------------------------------------------------------+------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------+ -- cgit v1.2.3 From 841dac596c9a2ce8e1882e382a9cc1d003edfbee Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 5 Jun 2020 18:03:04 +0200 Subject: Code review: type is float --- 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 c1ed0eaa..a75a0347 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -25,7 +25,7 @@ Remarks 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 - ones converted to the filtration value type of the simplicial complex. This can be very slow. + ones converted to float. This can be very slow. If you pass :code:`complexity = 'safe'` (the default) or :code:`complexity = 'fast'`, the filtration values are only guaranteed to have a small multiplicative error compared to the exact value, see `CGAL::Lazy_exact_nt::set_relative_precision_of_to_double `_ -- cgit v1.2.3 From c8f5c9fc0691c8539ca164805f34554227061ba7 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 5 Jun 2020 18:07:25 +0200 Subject: Code review: no link to CGAL::Lazy_exact_nt and no guarantee on fast precision --- src/python/doc/alpha_complex_user.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 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 a75a0347..bc9fe513 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -26,10 +26,9 @@ Remarks * 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 ones converted to float. This can be very slow. - If you pass :code:`complexity = 'safe'` (the default) or :code:`complexity = 'fast'`, the filtration values are only - guaranteed to have a small multiplicative error compared to the exact value, see - `CGAL::Lazy_exact_nt::set_relative_precision_of_to_double `_ - for details. A drawback, when computing persistence, is that an empty exact interval [10^12,10^12] may become a + If you pass :code:`complexity = '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 the computation of filtration values can exceptionally be arbitrarily bad. In all cases, we still guarantee that the -- 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/doc/alpha_complex_user.rst') 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 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/doc/alpha_complex_user.rst') 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 92235328f549fe610102ce3b58731d5877067f0e Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Sun, 28 Jun 2020 13:22:02 +0200 Subject: Duplicated comment --- src/python/doc/alpha_complex_user.rst | 2 -- 1 file changed, 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 bcc2fc51..714c5343 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -35,8 +35,6 @@ Remarks 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. -For performances reasons, it is advised to use CGAL :math:`\geq` 5.0.0. - Example from points ------------------- -- 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/doc/alpha_complex_user.rst') 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 From f39473b7c1de0fe42b3f4ebf5cb37bca0a84a247 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau <10407034+VincentRouvreau@users.noreply.github.com> Date: Wed, 1 Jul 2020 22:51:48 -0700 Subject: doc typo Co-authored-by: Marc Glisse --- 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 fd4a2372..fffcb3db 100644 --- a/src/python/doc/alpha_complex_user.rst +++ b/src/python/doc/alpha_complex_user.rst @@ -180,7 +180,7 @@ Example from OFF file 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 computes the persistence diagram and displays it: .. plot:: :include-source: -- cgit v1.2.3