From de268e32ceb8fc46a36e3f221ef0e7392a587544 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 5 Jul 2019 16:28:08 +0200 Subject: Available/missing python modules are now managed by the __init__.py --- src/cython/CMakeLists.txt | 58 +++++++++++++++++------------------------------ src/cython/__init__.py.in | 40 ++++++++++++++++++++++++++++++++ src/cython/setup.py.in | 10 ++++---- 3 files changed, 66 insertions(+), 42 deletions(-) create mode 100644 src/cython/__init__.py.in diff --git a/src/cython/CMakeLists.txt b/src/cython/CMakeLists.txt index 509a122e..b69b2c7d 100644 --- a/src/cython/CMakeLists.txt +++ b/src/cython/CMakeLists.txt @@ -33,15 +33,23 @@ endfunction( add_gudhi_debug_info ) if(PYTHONINTERP_FOUND) if(CYTHON_FOUND) - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}off_reader;") - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}simplex_tree;") - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}rips_complex;") - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}cubical_complex;") - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}periodic_cubical_complex;") - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}persistence_graphical_tools;") - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}reader_utils;") - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}witness_complex;") - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}strong_witness_complex;") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'off_reader', ") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'simplex_tree', ") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'rips_complex', ") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'cubical_complex', ") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'periodic_cubical_complex', ") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'persistence_graphical_tools', ") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'reader_utils', ") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'witness_complex', ") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'strong_witness_complex', ") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'persistence_graphical_tools' ") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'bottleneck_distance', ") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'nerve_gic', ") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'subsampling', ") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'tangential_complex', ") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'alpha_complex', ") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'euclidean_witness_complex', ") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'euclidean_strong_witness_complex', ") add_gudhi_debug_info("Python version ${PYTHON_VERSION_STRING}") add_gudhi_debug_info("Cython version ${CYTHON_VERSION}") @@ -57,11 +65,6 @@ if(PYTHONINTERP_FOUND) if(SCIPY_FOUND) add_gudhi_debug_info("Scipy version ${SCIPY_VERSION}") endif() - if(MATPLOTLIB_FOUND AND NUMPY_FOUND AND SCIPY_FOUND) - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}persistence_graphical_tools;") - else() - set(GUDHI_CYTHON_MISSING_MODULES "${GUDHI_CYTHON_MODULES}persistence_graphical_tools;") - endif() message("++ ${PYTHON_EXECUTABLE} v.${PYTHON_VERSION_STRING} - Cython is ${CYTHON_VERSION} - Sphinx is ${SPHINX_PATH}") set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DBOOST_RESULT_OF_USE_DECLTYPE', ") @@ -93,43 +96,20 @@ if(PYTHONINTERP_FOUND) if (NOT CGAL_VERSION VERSION_LESS 4.11.0) set(GUDHI_CYTHON_BOTTLENECK_DISTANCE "include '${CMAKE_CURRENT_SOURCE_DIR}/cython/bottleneck_distance.pyx'") - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}bottleneck_distance;") set(GUDHI_CYTHON_NERVE_GIC "include '${CMAKE_CURRENT_SOURCE_DIR}/cython/nerve_gic.pyx'") - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}nerve_gic;") - else() - set(GUDHI_CYTHON_MISSING_MODULES "${GUDHI_CYTHON_MISSING_MODULES}bottleneck_distance;") - set(GUDHI_CYTHON_MISSING_MODULES "${GUDHI_CYTHON_MISSING_MODULES}nerve_gic;") endif () if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0) set(GUDHI_CYTHON_SUBSAMPLING "include '${CMAKE_CURRENT_SOURCE_DIR}/cython/subsampling.pyx'") - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}subsampling;") set(GUDHI_CYTHON_TANGENTIAL_COMPLEX "include '${CMAKE_CURRENT_SOURCE_DIR}/cython/tangential_complex.pyx'") - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}tangential_complex;") - else() - set(GUDHI_CYTHON_MISSING_MODULES "${GUDHI_CYTHON_MISSING_MODULES}subsampling;") - set(GUDHI_CYTHON_MISSING_MODULES "${GUDHI_CYTHON_MISSING_MODULES}tangential_complex;") endif () if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0) set(GUDHI_CYTHON_ALPHA_COMPLEX "include '${CMAKE_CURRENT_SOURCE_DIR}/cython/alpha_complex.pyx'") - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}alpha_complex;") - else() - set(GUDHI_CYTHON_MISSING_MODULES "${GUDHI_CYTHON_MISSING_MODULES}alpha_complex;") endif () if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0) set(GUDHI_CYTHON_EUCLIDEAN_WITNESS_COMPLEX "include '${CMAKE_CURRENT_SOURCE_DIR}/cython/euclidean_witness_complex.pyx'\ninclude '${CMAKE_CURRENT_SOURCE_DIR}/cython/euclidean_strong_witness_complex.pyx'\n") - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}euclidean_witness_complex;") - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}euclidean_strong_witness_complex;") - else() - set(GUDHI_CYTHON_MISSING_MODULES "${GUDHI_CYTHON_MISSING_MODULES}euclidean_witness_complex;") - set(GUDHI_CYTHON_MISSING_MODULES "${GUDHI_CYTHON_MISSING_MODULES}euclidean_strong_witness_complex;") endif () - add_gudhi_debug_info("Installed modules are: ${GUDHI_CYTHON_MODULES}") - if(GUDHI_CYTHON_MISSING_MODULES) - add_gudhi_debug_info("Missing modules are: ${GUDHI_CYTHON_MISSING_MODULES}") - endif() - if(CGAL_FOUND) can_cgal_use_cxx11_thread_local() if (NOT CGAL_CAN_USE_CXX11_THREAD_LOCAL_RESULT) @@ -213,6 +193,10 @@ if(PYTHONINTERP_FOUND) # Generate gudhi.pyx - Gudhi cython file configure_file(gudhi.pyx.in "${CMAKE_CURRENT_BINARY_DIR}/gudhi.pyx" @ONLY) + # Generate gudhi/__init__.py + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/gudhi") + configure_file(__init__.py.in "${CMAKE_CURRENT_BINARY_DIR}/gudhi/__init__.py" @ONLY) + add_custom_command( OUTPUT gudhi.so WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} diff --git a/src/cython/__init__.py.in b/src/cython/__init__.py.in new file mode 100644 index 00000000..60ad7865 --- /dev/null +++ b/src/cython/__init__.py.in @@ -0,0 +1,40 @@ +from importlib import import_module + +"""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) 2016 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 Inria" +__license__ = "https://gudhi.inria.fr/licensing/" +__version__ = "@GUDHI_VERSION@" +# This variable is used by doctest to find files +__root_source_dir__ = "@CMAKE_SOURCE_DIR@" +__debug_info__ = @GUDHI_CYTHON_DEBUG_INFO@ + +from sys import exc_info +from importlib import import_module + +__all__ = [@GUDHI_CYTHON_MODULES@] + +__available_modules__ = '' +__missing_modules__ = '' + +# try to import * from gudhi.__module_name__ +for __module_name__ in __all__: + try: + __module__ = import_module('gudhi.' + __module_name__) + try: + __to_import__ = __module__.__all__ + except AttributeError: + __to_import__ = [name for name in __module__.__dict__ if not name.startswith('_')] + globals().update({name: __module__.__dict__[name] for name in __to_import__}) + __available_modules__ += __module_name__ + ";" + except: + __missing_modules__ += __module_name__ + ";" diff --git a/src/cython/setup.py.in b/src/cython/setup.py.in index 70c85852..454be9af 100644 --- a/src/cython/setup.py.in +++ b/src/cython/setup.py.in @@ -14,11 +14,11 @@ from numpy import get_include as numpy_get_include __author__ = "GUDHI Editorial Board" __copyright__ = "Copyright (C) 2016 Inria" -__license__ = "GPL v3" +__license__ = "MIT" -gudhi = Extension( - "gudhi", - sources = ['@CMAKE_CURRENT_BINARY_DIR@/gudhi.pyx',], +simplextree = Extension( + "gudhi.simplextree", + sources = ['@CMAKE_CURRENT_SOURCE_DIR@/cython/simplex_tree.pyx',], language = 'c++', extra_compile_args=[@GUDHI_CYTHON_EXTRA_COMPILE_ARGS@], extra_link_args=[@GUDHI_CYTHON_EXTRA_LINK_ARGS@], @@ -34,7 +34,7 @@ setup( author_email='gudhi-contact@lists.gforge.inria.fr', version='@GUDHI_VERSION@', url='http://gudhi.gforge.inria.fr/', - ext_modules = cythonize(gudhi), + ext_modules = cythonize(simplextree), install_requires = ['cython','numpy >= 1.9',], setup_requires = ['numpy >= 1.9',], ) -- cgit v1.2.3 From 0a4a42e38dffaea03083e39e5eafed2e1f32ff05 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 5 Jul 2019 17:14:53 +0200 Subject: move cython in a gudhi directory - like the python package one --- src/cython/CMakeLists.txt | 2 +- src/cython/__init__.py.in | 40 -- src/cython/cython/alpha_complex.pyx | 109 ----- src/cython/cython/bottleneck_distance.pyx | 49 -- src/cython/cython/cubical_complex.pyx | 188 ------- .../cython/euclidean_strong_witness_complex.pyx | 85 ---- src/cython/cython/euclidean_witness_complex.pyx | 85 ---- src/cython/cython/nerve_gic.pyx | 407 ---------------- src/cython/cython/off_reader.pyx | 38 -- src/cython/cython/periodic_cubical_complex.pyx | 190 -------- src/cython/cython/persistence_graphical_tools.py | 420 ---------------- src/cython/cython/reader_utils.pyx | 87 ---- src/cython/cython/rips_complex.pyx | 98 ---- src/cython/cython/simplex_tree.pyx | 542 --------------------- src/cython/cython/strong_witness_complex.pyx | 71 --- src/cython/cython/subsampling.pyx | 130 ----- src/cython/cython/tangential_complex.pyx | 168 ------- src/cython/cython/witness_complex.pyx | 71 --- src/cython/gudhi/__init__.py.in | 40 ++ src/cython/gudhi/alpha_complex.pyx | 115 +++++ src/cython/gudhi/bottleneck_distance.pyx | 49 ++ src/cython/gudhi/cubical_complex.pyx | 188 +++++++ .../gudhi/euclidean_strong_witness_complex.pyx | 85 ++++ src/cython/gudhi/euclidean_witness_complex.pyx | 85 ++++ src/cython/gudhi/nerve_gic.pyx | 407 ++++++++++++++++ src/cython/gudhi/off_reader.pyx | 38 ++ src/cython/gudhi/periodic_cubical_complex.pyx | 190 ++++++++ src/cython/gudhi/persistence_graphical_tools.py | 420 ++++++++++++++++ src/cython/gudhi/reader_utils.pyx | 87 ++++ src/cython/gudhi/rips_complex.pyx | 102 ++++ src/cython/gudhi/simplex_tree.pxd | 46 ++ src/cython/gudhi/simplex_tree.pyx | 518 ++++++++++++++++++++ src/cython/gudhi/strong_witness_complex.pyx | 78 +++ src/cython/gudhi/subsampling.pyx | 130 +++++ src/cython/gudhi/tangential_complex.pyx | 177 +++++++ src/cython/gudhi/witness_complex.pyx | 78 +++ 36 files changed, 2834 insertions(+), 2779 deletions(-) delete mode 100644 src/cython/__init__.py.in delete mode 100644 src/cython/cython/alpha_complex.pyx delete mode 100644 src/cython/cython/bottleneck_distance.pyx delete mode 100644 src/cython/cython/cubical_complex.pyx delete mode 100644 src/cython/cython/euclidean_strong_witness_complex.pyx delete mode 100644 src/cython/cython/euclidean_witness_complex.pyx delete mode 100644 src/cython/cython/nerve_gic.pyx delete mode 100644 src/cython/cython/off_reader.pyx delete mode 100644 src/cython/cython/periodic_cubical_complex.pyx delete mode 100644 src/cython/cython/persistence_graphical_tools.py delete mode 100644 src/cython/cython/reader_utils.pyx delete mode 100644 src/cython/cython/rips_complex.pyx delete mode 100644 src/cython/cython/simplex_tree.pyx delete mode 100644 src/cython/cython/strong_witness_complex.pyx delete mode 100644 src/cython/cython/subsampling.pyx delete mode 100644 src/cython/cython/tangential_complex.pyx delete mode 100644 src/cython/cython/witness_complex.pyx create mode 100644 src/cython/gudhi/__init__.py.in create mode 100644 src/cython/gudhi/alpha_complex.pyx create mode 100644 src/cython/gudhi/bottleneck_distance.pyx create mode 100644 src/cython/gudhi/cubical_complex.pyx create mode 100644 src/cython/gudhi/euclidean_strong_witness_complex.pyx create mode 100644 src/cython/gudhi/euclidean_witness_complex.pyx create mode 100644 src/cython/gudhi/nerve_gic.pyx create mode 100644 src/cython/gudhi/off_reader.pyx create mode 100644 src/cython/gudhi/periodic_cubical_complex.pyx create mode 100644 src/cython/gudhi/persistence_graphical_tools.py create mode 100644 src/cython/gudhi/reader_utils.pyx create mode 100644 src/cython/gudhi/rips_complex.pyx create mode 100644 src/cython/gudhi/simplex_tree.pxd create mode 100644 src/cython/gudhi/simplex_tree.pyx create mode 100644 src/cython/gudhi/strong_witness_complex.pyx create mode 100644 src/cython/gudhi/subsampling.pyx create mode 100644 src/cython/gudhi/tangential_complex.pyx create mode 100644 src/cython/gudhi/witness_complex.pyx diff --git a/src/cython/CMakeLists.txt b/src/cython/CMakeLists.txt index b69b2c7d..cd99f70b 100644 --- a/src/cython/CMakeLists.txt +++ b/src/cython/CMakeLists.txt @@ -195,7 +195,7 @@ if(PYTHONINTERP_FOUND) # Generate gudhi/__init__.py file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/gudhi") - configure_file(__init__.py.in "${CMAKE_CURRENT_BINARY_DIR}/gudhi/__init__.py" @ONLY) + configure_file("gudhi/__init__.py.in" "${CMAKE_CURRENT_BINARY_DIR}/gudhi/__init__.py" @ONLY) add_custom_command( OUTPUT gudhi.so diff --git a/src/cython/__init__.py.in b/src/cython/__init__.py.in deleted file mode 100644 index 60ad7865..00000000 --- a/src/cython/__init__.py.in +++ /dev/null @@ -1,40 +0,0 @@ -from importlib import import_module - -"""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) 2016 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 Inria" -__license__ = "https://gudhi.inria.fr/licensing/" -__version__ = "@GUDHI_VERSION@" -# This variable is used by doctest to find files -__root_source_dir__ = "@CMAKE_SOURCE_DIR@" -__debug_info__ = @GUDHI_CYTHON_DEBUG_INFO@ - -from sys import exc_info -from importlib import import_module - -__all__ = [@GUDHI_CYTHON_MODULES@] - -__available_modules__ = '' -__missing_modules__ = '' - -# try to import * from gudhi.__module_name__ -for __module_name__ in __all__: - try: - __module__ = import_module('gudhi.' + __module_name__) - try: - __to_import__ = __module__.__all__ - except AttributeError: - __to_import__ = [name for name in __module__.__dict__ if not name.startswith('_')] - globals().update({name: __module__.__dict__[name] for name in __to_import__}) - __available_modules__ += __module_name__ + ";" - except: - __missing_modules__ += __module_name__ + ";" diff --git a/src/cython/cython/alpha_complex.pyx b/src/cython/cython/alpha_complex.pyx deleted file mode 100644 index 249d51d0..00000000 --- a/src/cython/cython/alpha_complex.pyx +++ /dev/null @@ -1,109 +0,0 @@ -from cython cimport numeric -from libcpp.vector cimport vector -from libcpp.utility cimport pair -from libcpp.string cimport string -from libcpp cimport bool -import os - -""" 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) 2016 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 Inria" -__license__ = "GPL v3" - -cdef extern from "Alpha_complex_interface.h" namespace "Gudhi": - cdef cppclass Alpha_complex_interface "Gudhi::alpha_complex::Alpha_complex_interface": - Alpha_complex_interface(vector[vector[double]] points) - # bool from_file is a workaround for cython to find the correct signature - Alpha_complex_interface(string off_file, bool from_file) - vector[double] get_point(int vertex) - void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square) - -# AlphaComplex python interface -cdef class AlphaComplex: - """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. - - 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. - - """ - - cdef Alpha_complex_interface * thisptr - - # Fake constructor that does nothing but documenting the constructor - def __init__(self, points=None, off_file=''): - """AlphaComplex constructor. - - :param points: A list of points in d-Dimension. - :type points: list of list of double - - Or - - :param off_file: An OFF file style name. - :type off_file: string - """ - - # The real cython constructor - def __cinit__(self, points=None, off_file=''): - if off_file is not '': - if os.path.isfile(off_file): - self.thisptr = new Alpha_complex_interface(str.encode(off_file), True) - else: - print("file " + off_file + " not found.") - else: - if points is None: - # Empty Alpha construction - points=[] - self.thisptr = new Alpha_complex_interface(points) - - - def __dealloc__(self): - if self.thisptr != NULL: - del self.thisptr - - def __is_defined(self): - """Returns true if AlphaComplex pointer is not NULL. - """ - return self.thisptr != NULL - - def get_point(self, vertex): - """This function returns the point corresponding to a given vertex. - - :param vertex: The vertex. - :type vertex: int - :rtype: list of float - :returns: the point. - """ - cdef vector[double] point = self.thisptr.get_point(vertex) - return point - - 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. - :type max_alpha_square: float - :returns: A simplex tree created from the Delaunay Triangulation. - :rtype: SimplexTree - """ - simplex_tree = SimplexTree() - self.thisptr.create_simplex_tree(simplex_tree.thisptr, max_alpha_square) - return simplex_tree diff --git a/src/cython/cython/bottleneck_distance.pyx b/src/cython/cython/bottleneck_distance.pyx deleted file mode 100644 index 4b378cbc..00000000 --- a/src/cython/cython/bottleneck_distance.pyx +++ /dev/null @@ -1,49 +0,0 @@ -from cython cimport numeric -from libcpp.vector cimport vector -from libcpp.utility cimport pair -import os - -""" 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) 2016 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 Inria" -__license__ = "GPL v3" - -cdef extern from "Bottleneck_distance_interface.h" namespace "Gudhi::persistence_diagram": - double bottleneck(vector[pair[double, double]], vector[pair[double, double]], double) - double bottleneck(vector[pair[double, double]], vector[pair[double, double]]) - -def bottleneck_distance(diagram_1, diagram_2, e=None): - """This function returns the point corresponding to a given vertex. - - :param diagram_1: The first diagram. - :type diagram_1: vector[pair[double, double]] - :param diagram_2: The second diagram. - :type diagram_2: vector[pair[double, double]] - :param e: If `e` is 0, this uses an expensive algorithm to compute the - exact distance. - If `e` is not 0, it asks for an additive `e`-approximation, and - currently also allows a small multiplicative error (the last 2 or 3 - bits of the mantissa may be wrong). This version of the algorithm takes - advantage of the limited precision of `double` and is usually a lot - faster to compute, whatever the value of `e`. - - Thus, by default, `e` is the smallest positive double. - :type e: float - :rtype: float - :returns: the bottleneck distance. - """ - if e is None: - # Default value is the smallest double value (not 0, 0 is for exact version) - return bottleneck(diagram_1, diagram_2) - else: - # Can be 0 for exact version - return bottleneck(diagram_1, diagram_2, e) diff --git a/src/cython/cython/cubical_complex.pyx b/src/cython/cython/cubical_complex.pyx deleted file mode 100644 index 0dc133d1..00000000 --- a/src/cython/cython/cubical_complex.pyx +++ /dev/null @@ -1,188 +0,0 @@ -from cython cimport numeric -from libcpp.vector cimport vector -from libcpp.utility cimport pair -from libcpp.string cimport string -from libcpp cimport bool -import os - -from numpy import array as np_array - -""" 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) 2016 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 Inria" -__license__ = "MIT" - -cdef extern from "Cubical_complex_interface.h" namespace "Gudhi": - cdef cppclass Bitmap_cubical_complex_base_interface "Gudhi::Cubical_complex::Cubical_complex_interface<>": - Bitmap_cubical_complex_base_interface(vector[unsigned] dimensions, vector[double] top_dimensional_cells) - Bitmap_cubical_complex_base_interface(string perseus_file) - int num_simplices() - int dimension() - -cdef extern from "Persistent_cohomology_interface.h" namespace "Gudhi": - cdef cppclass Cubical_complex_persistence_interface "Gudhi::Persistent_cohomology_interface>": - Cubical_complex_persistence_interface(Bitmap_cubical_complex_base_interface * st, bool persistence_dim_max) - vector[pair[int, pair[double, double]]] get_persistence(int homology_coeff_field, double min_persistence) - vector[int] betti_numbers() - vector[int] persistent_betti_numbers(double from_value, double to_value) - vector[pair[double,double]] intervals_in_dimension(int dimension) - -# CubicalComplex python interface -cdef class CubicalComplex: - """The CubicalComplex is an example of a structured complex useful in - computational mathematics (specially rigorous numerics) and image - analysis. - """ - cdef Bitmap_cubical_complex_base_interface * thisptr - - cdef Cubical_complex_persistence_interface * pcohptr - - # Fake constructor that does nothing but documenting the constructor - def __init__(self, dimensions=None, top_dimensional_cells=None, - perseus_file=''): - """CubicalComplex constructor from dimensions and - top_dimensional_cells or from a Perseus-style file name. - - :param dimensions: A list of number of top dimensional cells. - :type dimensions: list of int - :param top_dimensional_cells: A list of cells filtration values. - :type top_dimensional_cells: list of double - - Or - - :param perseus_file: A Perseus-style file name. - :type perseus_file: string - """ - - # The real cython constructor - def __cinit__(self, dimensions=None, top_dimensional_cells=None, - perseus_file=''): - if (dimensions is not None) and (top_dimensional_cells is not None) and (perseus_file is ''): - self.thisptr = new Bitmap_cubical_complex_base_interface(dimensions, top_dimensional_cells) - elif (dimensions is None) and (top_dimensional_cells is None) and (perseus_file is not ''): - if os.path.isfile(perseus_file): - self.thisptr = new Bitmap_cubical_complex_base_interface(str.encode(perseus_file)) - else: - print("file " + perseus_file + " not found.") - else: - print("CubicalComplex can be constructed from dimensions and " - "top_dimensional_cells or from a Perseus-style file name.") - - def __dealloc__(self): - if self.thisptr != NULL: - del self.thisptr - if self.pcohptr != NULL: - del self.pcohptr - - def __is_defined(self): - """Returns true if CubicalComplex pointer is not NULL. - """ - return self.thisptr != NULL - - def __is_persistence_defined(self): - """Returns true if Persistence pointer is not NULL. - """ - return self.pcohptr != NULL - - def num_simplices(self): - """This function returns the number of all cubes in the complex. - - :returns: int -- the number of all cubes in the complex. - """ - return self.thisptr.num_simplices() - - def dimension(self): - """This function returns the dimension of the complex. - - :returns: int -- the complex dimension. - """ - return self.thisptr.dimension() - - def persistence(self, homology_coeff_field=11, min_persistence=0): - """This function returns the persistence of the complex. - - :param homology_coeff_field: The homology coefficient field. Must be a - prime number - :type homology_coeff_field: int. - :param min_persistence: The minimum persistence value to take into - account (strictly greater than min_persistence). Default value is - 0.0. - Sets min_persistence to -1.0 to see all values. - :type min_persistence: float. - :returns: list of pairs(dimension, pair(birth, death)) -- the - persistence of the complex. - """ - if self.pcohptr != NULL: - del self.pcohptr - if self.thisptr != NULL: - self.pcohptr = new Cubical_complex_persistence_interface(self.thisptr, True) - cdef vector[pair[int, pair[double, double]]] persistence_result - if self.pcohptr != NULL: - persistence_result = self.pcohptr.get_persistence(homology_coeff_field, min_persistence) - return persistence_result - - def betti_numbers(self): - """This function returns the Betti numbers of the complex. - - :returns: list of int -- The Betti numbers ([B0, B1, ..., Bn]). - - :note: betti_numbers function requires persistence function to be - launched first. - - :note: betti_numbers function always returns [1, 0, 0, ...] as infinity - filtration cubes are not removed from the complex. - """ - cdef vector[int] bn_result - if self.pcohptr != NULL: - bn_result = self.pcohptr.betti_numbers() - return bn_result - - def persistent_betti_numbers(self, from_value, to_value): - """This function returns the persistent Betti numbers of the complex. - - :param from_value: The persistence birth limit to be added in the - numbers (persistent birth <= from_value). - :type from_value: float. - :param to_value: The persistence death limit to be added in the - numbers (persistent death > to_value). - :type to_value: float. - - :returns: list of int -- The persistent Betti numbers ([B0, B1, ..., - Bn]). - - :note: persistent_betti_numbers function requires persistence - function to be launched first. - """ - cdef vector[int] pbn_result - if self.pcohptr != NULL: - pbn_result = self.pcohptr.persistent_betti_numbers(from_value, to_value) - return pbn_result - - def persistence_intervals_in_dimension(self, dimension): - """This function returns the persistence intervals of the complex in a - specific dimension. - - :param dimension: The specific dimension. - :type dimension: int. - :returns: The persistence intervals. - :rtype: numpy array of dimension 2 - - :note: intervals_in_dim function requires persistence function to be - launched first. - """ - cdef vector[pair[double,double]] intervals_result - if self.pcohptr != NULL: - intervals_result = self.pcohptr.intervals_in_dimension(dimension) - else: - print("intervals_in_dim function requires persistence function" - " to be launched first.") - return np_array(intervals_result) diff --git a/src/cython/cython/euclidean_strong_witness_complex.pyx b/src/cython/cython/euclidean_strong_witness_complex.pyx deleted file mode 100644 index 26bd8375..00000000 --- a/src/cython/cython/euclidean_strong_witness_complex.pyx +++ /dev/null @@ -1,85 +0,0 @@ -from cython cimport numeric -from libcpp.vector cimport vector -from libcpp.utility cimport pair - -""" 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) 2016 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 Inria" -__license__ = "GPL v3" - -cdef extern from "Euclidean_strong_witness_complex_interface.h" namespace "Gudhi": - cdef cppclass Euclidean_strong_witness_complex_interface "Gudhi::witness_complex::Euclidean_strong_witness_complex_interface": - Euclidean_strong_witness_complex_interface(vector[vector[double]] landmarks, vector[vector[double]] witnesses) - void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square) - void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square, - unsigned limit_dimension) - vector[double] get_point(unsigned vertex) - -# EuclideanStrongWitnessComplex python interface -cdef class EuclideanStrongWitnessComplex: - """Constructs strong witness complex for given sets of witnesses and - landmarks in Euclidean space. - """ - - cdef Euclidean_strong_witness_complex_interface * thisptr - - # Fake constructor that does nothing but documenting the constructor - def __init__(self, landmarks=None, witnesses=None): - """WitnessComplex constructor. - - :param landmarks: A list of landmarks (in the point cloud). - :type landmarks: list of list of double - - :param witnesses: The point cloud. - :type witnesses: list of list of double - """ - - # The real cython constructor - def __cinit__(self, landmarks=None, witnesses=None): - if landmarks is not None and witnesses is not None: - self.thisptr = new Euclidean_strong_witness_complex_interface(landmarks, witnesses) - - def __dealloc__(self): - if self.thisptr != NULL: - del self.thisptr - - def __is_defined(self): - """Returns true if WitnessComplex pointer is not NULL. - """ - return self.thisptr != NULL - - def create_simplex_tree(self, max_alpha_square, limit_dimension = -1): - """ - :param max_alpha_square: The maximum alpha square threshold the - simplices shall not exceed. Default is set to infinity. - :type max_alpha_square: float - :returns: A simplex tree created from the Delaunay Triangulation. - :rtype: SimplexTree - """ - simplex_tree = SimplexTree() - if limit_dimension is not -1: - self.thisptr.create_simplex_tree(simplex_tree.thisptr, max_alpha_square, limit_dimension) - else: - self.thisptr.create_simplex_tree(simplex_tree.thisptr, max_alpha_square) - return simplex_tree - - def get_point(self, vertex): - """This function returns the point corresponding to a given vertex. - - :param vertex: The vertex. - :type vertex: int. - :returns: The point. - :rtype: list of float - """ - cdef vector[double] point = self.thisptr.get_point(vertex) - return point - diff --git a/src/cython/cython/euclidean_witness_complex.pyx b/src/cython/cython/euclidean_witness_complex.pyx deleted file mode 100644 index e687c6f3..00000000 --- a/src/cython/cython/euclidean_witness_complex.pyx +++ /dev/null @@ -1,85 +0,0 @@ -from cython cimport numeric -from libcpp.vector cimport vector -from libcpp.utility cimport pair - -""" 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) 2016 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 Inria" -__license__ = "GPL v3" - -cdef extern from "Euclidean_witness_complex_interface.h" namespace "Gudhi": - cdef cppclass Euclidean_witness_complex_interface "Gudhi::witness_complex::Euclidean_witness_complex_interface": - Euclidean_witness_complex_interface(vector[vector[double]] landmarks, vector[vector[double]] witnesses) - void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square) - void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square, - unsigned limit_dimension) - vector[double] get_point(unsigned vertex) - -# EuclideanWitnessComplex python interface -cdef class EuclideanWitnessComplex: - """Constructs (weak) witness complex for given sets of witnesses and - landmarks in Euclidean space. - """ - - cdef Euclidean_witness_complex_interface * thisptr - - # Fake constructor that does nothing but documenting the constructor - def __init__(self, landmarks=None, witnesses=None): - """WitnessComplex constructor. - - :param landmarks: A list of landmarks (in the point cloud). - :type landmarks: list of list of double - - :param witnesses: The point cloud. - :type witnesses: list of list of double - """ - - # The real cython constructor - def __cinit__(self, landmarks=None, witnesses=None): - if landmarks is not None and witnesses is not None: - self.thisptr = new Euclidean_witness_complex_interface(landmarks, witnesses) - - def __dealloc__(self): - if self.thisptr != NULL: - del self.thisptr - - def __is_defined(self): - """Returns true if WitnessComplex pointer is not NULL. - """ - return self.thisptr != NULL - - def create_simplex_tree(self, max_alpha_square, limit_dimension = -1): - """ - :param max_alpha_square: The maximum alpha square threshold the - simplices shall not exceed. Default is set to infinity. - :type max_alpha_square: float - :returns: A simplex tree created from the Delaunay Triangulation. - :rtype: SimplexTree - """ - simplex_tree = SimplexTree() - if limit_dimension is not -1: - self.thisptr.create_simplex_tree(simplex_tree.thisptr, max_alpha_square, limit_dimension) - else: - self.thisptr.create_simplex_tree(simplex_tree.thisptr, max_alpha_square) - return simplex_tree - - def get_point(self, vertex): - """This function returns the point corresponding to a given vertex. - - :param vertex: The vertex. - :type vertex: int. - :returns: The point. - :rtype: list of float - """ - cdef vector[double] point = self.thisptr.get_point(vertex) - return point - diff --git a/src/cython/cython/nerve_gic.pyx b/src/cython/cython/nerve_gic.pyx deleted file mode 100644 index 3c8f1200..00000000 --- a/src/cython/cython/nerve_gic.pyx +++ /dev/null @@ -1,407 +0,0 @@ -from cython cimport numeric -from libcpp.vector cimport vector -from libcpp.utility cimport pair -from libcpp.string cimport string -from libcpp cimport bool -import os - -""" 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) 2018 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2018 Inria" -__license__ = "GPL v3" - -cdef extern from "Nerve_gic_interface.h" namespace "Gudhi": - cdef cppclass Nerve_gic_interface "Gudhi::cover_complex::Nerve_gic_interface": - Nerve_gic_interface() - double compute_confidence_level_from_distance(double distance) - double compute_distance_from_confidence_level(double alpha) - void compute_distribution(int N) - double compute_p_value() - vector[pair[double, double]] compute_PD() - void find_simplices() - void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree) - bool read_point_cloud(string off_file_name) - double set_automatic_resolution() - void set_color_from_coordinate(int k) - void set_color_from_file(string color_file_name) - void set_color_from_range(vector[double] color) - void set_cover_from_file(string cover_file_name) - void set_cover_from_function() - void set_cover_from_Euclidean_Voronoi(int m) - void set_function_from_coordinate(int k) - void set_function_from_file(string func_file_name) - void set_function_from_range(vector[double] function) - void set_gain(double g) - double set_graph_from_automatic_euclidean_rips(int N) - void set_graph_from_file(string graph_file_name) - void set_graph_from_OFF() - void set_graph_from_euclidean_rips(double threshold) - void set_mask(int nodemask) - void set_resolution_with_interval_length(double resolution) - void set_resolution_with_interval_number(int resolution) - void set_subsampling(double constant, double power) - void set_type(string type) - void set_verbose(bool verbose) - vector[int] subpopulation(int c) - void write_info() - void plot_DOT() - void plot_OFF() - void set_point_cloud_from_range(vector[vector[double]] cloud) - void set_distances_from_range(vector[vector[double]] distance_matrix) - -# CoverComplex python interface -cdef class CoverComplex: - """Cover complex data structure. - - The data structure is a simplicial complex, representing a Graph Induced - simplicial Complex (GIC) or a Nerve, and whose simplices are computed with - a cover C of a point cloud P, which often comes from the preimages of - intervals covering the image of a function f defined on P. These intervals - are parameterized by their resolution (either their length or their number) - and their gain (percentage of overlap). To compute a GIC, one also needs a - graph G built on top of P, whose cliques with vertices belonging to - different elements of C correspond to the simplices of the GIC. - """ - - cdef Nerve_gic_interface * thisptr - - # Fake constructor that does nothing but documenting the constructor - def __init__(self): - """CoverComplex constructor. - """ - - # The real cython constructor - def __cinit__(self): - self.thisptr = new Nerve_gic_interface() - - def __dealloc__(self): - if self.thisptr != NULL: - del self.thisptr - - def __is_defined(self): - """Returns true if CoverComplex pointer is not NULL. - """ - return self.thisptr != NULL - - def set_point_cloud_from_range(self, cloud): - """ Reads and stores the input point cloud from a vector stored in memory. - - :param cloud: Input vector containing the point cloud. - :type cloud: vector[vector[double]] - """ - return self.thisptr.set_point_cloud_from_range(cloud) - - def set_distances_from_range(self, distance_matrix): - """ Reads and stores the input distance matrix from a vector stored in memory. - - :param distance_matrix: Input vector containing the distance matrix. - :type distance_matrix: vector[vector[double]] - """ - return self.thisptr.set_distances_from_range(distance_matrix) - - def compute_confidence_level_from_distance(self, distance): - """Computes the confidence level of a specific bottleneck distance - threshold. - - :param distance: Bottleneck distance. - :type distance: double - :rtype: double - :returns: Confidence level. - """ - return self.thisptr.compute_confidence_level_from_distance(distance) - - def compute_distance_from_confidence_level(self, alpha): - """Computes the bottleneck distance threshold corresponding to a - specific confidence level. - - :param alpha: Confidence level. - :type alpha: double - :rtype: double - :returns: Bottleneck distance. - """ - return self.thisptr.compute_distance_from_confidence_level(alpha) - - def compute_distribution(self, N=100): - """Computes bootstrapped distances distribution. - - :param N: Loop number (default value is 100). - :type alpha: int - """ - self.thisptr.compute_distribution(N) - - def compute_p_value(self): - """Computes the p-value, i.e. the opposite of the confidence level of - the largest bottleneck distance preserving the points in the - persistence diagram of the output simplicial complex. - - :rtype: double - :returns: p-value. - """ - return self.thisptr.compute_p_value() - - def compute_PD(self): - """Computes the extended persistence diagram of the complex. - """ - return self.thisptr.compute_PD() - - def create_simplex_tree(self): - """ - :returns: A simplex tree created from the Cover complex. - :rtype: SimplexTree - """ - simplex_tree = SimplexTree() - self.thisptr.create_simplex_tree(simplex_tree.thisptr) - return simplex_tree - - def find_simplices(self): - """Computes the simplices of the simplicial complex. - """ - self.thisptr.find_simplices() - - def read_point_cloud(self, off_file): - """Reads and stores the input point cloud from .(n)OFF file. - - :param off_file: Name of the input .OFF or .nOFF file. - :type off_file: string - :rtype: bool - :returns: Read file status. - """ - if os.path.isfile(off_file): - return self.thisptr.read_point_cloud(str.encode(off_file)) - else: - print("file " + off_file + " not found.") - return False - - def set_automatic_resolution(self): - """Computes the optimal length of intervals (i.e. the smallest interval - length avoiding discretization artifacts—see :cite:`Carriere17c`) for a - functional cover. - - :rtype: double - :returns: reso interval length used to compute the cover. - """ - return self.thisptr.set_automatic_resolution() - - def set_color_from_coordinate(self, k=0): - """Computes the function used to color the nodes of the simplicial - complex from the k-th coordinate. - - :param k: Coordinate to use (start at 0). Default value is 0. - :type k: int - """ - return self.thisptr.set_color_from_coordinate(k) - - def set_color_from_file(self, color_file_name): - """Computes the function used to color the nodes of the simplicial - complex from a file containing the function values. - - :param color_file_name: Name of the input color file. - :type color_file_name: string - """ - if os.path.isfile(color_file_name): - self.thisptr.set_color_from_file(str.encode(color_file_name)) - else: - print("file " + color_file_name + " not found.") - - def set_color_from_range(self, color): - """Computes the function used to color the nodes of the simplicial - complex from a vector stored in memory. - - :param color: Input vector of values. - :type color: vector[double] - """ - self.thisptr.set_color_from_range(color) - - def set_cover_from_file(self, cover_file_name): - """Creates the cover C from a file containing the cover elements of - each point (the order has to be the same as in the input file!). - - :param cover_file_name: Name of the input cover file. - :type cover_file_name: string - """ - if os.path.isfile(cover_file_name): - self.thisptr.set_cover_from_file(str.encode(cover_file_name)) - else: - print("file " + cover_file_name + " not found.") - - def set_cover_from_function(self): - """Creates a cover C from the preimages of the function f. - """ - self.thisptr.set_cover_from_function() - - def set_cover_from_Voronoi(self, m=100): - """Creates the cover C from the Voronoï cells of a subsampling of the - point cloud. - - :param m: Number of points in the subsample. Default value is 100. - :type m: int - """ - self.thisptr.set_cover_from_Euclidean_Voronoi(m) - - def set_function_from_coordinate(self, k): - """Creates the function f from the k-th coordinate of the point cloud. - - :param k: Coordinate to use (start at 0). - :type k: int - """ - self.thisptr.set_function_from_coordinate(k) - - def set_function_from_file(self, func_file_name): - """Creates the function f from a file containing the function values. - - :param func_file_name: Name of the input function file. - :type func_file_name: string - """ - if os.path.isfile(func_file_name): - self.thisptr.set_function_from_file(str.encode(func_file_name)) - else: - print("file " + func_file_name + " not found.") - - def set_function_from_range(self, function): - """Creates the function f from a vector stored in memory. - - :param function: Input vector of values. - :type function: vector[double] - """ - self.thisptr.set_function_from_range(function) - - def set_gain(self, g = 0.3): - """Sets a gain from a value stored in memory. - - :param g: Gain (default value is 0.3). - :type g: double - """ - self.thisptr.set_gain(g) - - def set_graph_from_automatic_rips(self, N=100): - """Creates a graph G from a Rips complex whose threshold value is - automatically tuned with subsampling—see. - - :param N: Number of subsampling iteration (the default reasonable value - is 100, but there is no guarantee on how to choose it). - :type N: int - :rtype: double - :returns: Delta threshold used for computing the Rips complex. - """ - return self.thisptr.set_graph_from_automatic_euclidean_rips(N) - - def set_graph_from_file(self, graph_file_name): - """Creates a graph G from a file containing the edges. - - :param graph_file_name: Name of the input graph file. The graph file - contains one edge per line, each edge being represented by the IDs of - its two nodes. - :type graph_file_name: string - """ - if os.path.isfile(graph_file_name): - self.thisptr.set_graph_from_file(str.encode(graph_file_name)) - else: - print("file " + graph_file_name + " not found.") - - def set_graph_from_OFF(self): - """Creates a graph G from the triangulation given by the input OFF - file. - """ - self.thisptr.set_graph_from_OFF() - - def set_graph_from_rips(self, threshold): - """Creates a graph G from a Rips complex. - - :param threshold: Threshold value for the Rips complex. - :type threshold: double - """ - self.thisptr.set_graph_from_euclidean_rips(threshold) - - def set_mask(self, nodemask): - """Sets the mask, which is a threshold integer such that nodes in the - complex that contain a number of data points which is less than or - equal to this threshold are not displayed. - - :param nodemask: Threshold. - :type nodemask: int - """ - self.thisptr.set_mask(nodemask) - - def set_resolution_with_interval_length(self, resolution): - """Sets a length of intervals from a value stored in memory. - - :param resolution: Length of intervals. - :type resolution: double - """ - self.thisptr.set_resolution_with_interval_length(resolution) - - def set_resolution_with_interval_number(self, resolution): - """Sets a number of intervals from a value stored in memory. - - :param resolution: Number of intervals. - :type resolution: int - """ - self.thisptr.set_resolution_with_interval_number(resolution) - - def set_subsampling(self, constant, power): - """Sets the constants used to subsample the data set. These constants - are explained in :cite:`Carriere17c`. - - :param constant: Constant. - :type constant: double - :param power: Power. - :type resolution: double - """ - self.thisptr.set_subsampling(constant, power) - - def set_type(self, type): - """Specifies whether the type of the output simplicial complex. - - :param type: either "GIC" or "Nerve". - :type type: string - """ - self.thisptr.set_type(str.encode(type)) - - def set_verbose(self, verbose): - """Specifies whether the program should display information or not. - - :param verbose: true = display info, false = do not display info. - :type verbose: boolean - """ - self.thisptr.set_verbose(verbose) - - def subpopulation(self, c): - """Returns the data subset corresponding to a specific node of the - created complex. - - :param c: ID of the node. - :type c: int - :rtype: vector[int] - :returns: Vector of IDs of data points. - """ - return self.thisptr.subpopulation(c) - - def write_info(self): - """Creates a .txt file called SC.txt describing the 1-skeleton, which can - then be plotted with e.g. KeplerMapper. - """ - return self.thisptr.write_info() - - def plot_dot(self): - """Creates a .dot file called SC.dot for neato (part of the graphviz - package) once the simplicial complex is computed to get a visualization of - its 1-skeleton in a .pdf file. - """ - return self.thisptr.plot_DOT() - - def plot_off(self): - """Creates a .off file called SC.off for 3D visualization, which contains - the 2-skeleton of the GIC. This function assumes that the cover has been - computed with Voronoi. If data points are in 1D or 2D, the remaining - coordinates of the points embedded in 3D are set to 0. - """ - return self.thisptr.plot_OFF() diff --git a/src/cython/cython/off_reader.pyx b/src/cython/cython/off_reader.pyx deleted file mode 100644 index 9efd97ff..00000000 --- a/src/cython/cython/off_reader.pyx +++ /dev/null @@ -1,38 +0,0 @@ -from cython cimport numeric -from libcpp.vector cimport vector -from libcpp.string cimport string -import os - -""" 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) 2016 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 Inria" -__license__ = "MIT" - -cdef extern from "Off_reader_interface.h" namespace "Gudhi": - vector[vector[double]] read_points_from_OFF_file(string off_file) - -def read_off(off_file=''): - """Read points from OFF file. - - :param off_file: An OFF file style name. - :type off_file: string - - :returns: The point set. - :rtype: vector[vector[double]] - """ - if off_file is not '': - if os.path.isfile(off_file): - return read_points_from_OFF_file(str.encode(off_file)) - else: - print("file " + off_file + " not found.") - return [] - diff --git a/src/cython/cython/periodic_cubical_complex.pyx b/src/cython/cython/periodic_cubical_complex.pyx deleted file mode 100644 index 724fadd4..00000000 --- a/src/cython/cython/periodic_cubical_complex.pyx +++ /dev/null @@ -1,190 +0,0 @@ -from cython cimport numeric -from libcpp.vector cimport vector -from libcpp.utility cimport pair -from libcpp.string cimport string -from libcpp cimport bool -import os - -from numpy import array as np_array - -""" 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) 2016 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 Inria" -__license__ = "MIT" - -cdef extern from "Cubical_complex_interface.h" namespace "Gudhi": - cdef cppclass Periodic_cubical_complex_base_interface "Gudhi::Cubical_complex::Cubical_complex_interface>": - Periodic_cubical_complex_base_interface(vector[unsigned] dimensions, vector[double] top_dimensional_cells, vector[bool] periodic_dimensions) - Periodic_cubical_complex_base_interface(string perseus_file) - int num_simplices() - int dimension() - -cdef extern from "Persistent_cohomology_interface.h" namespace "Gudhi": - cdef cppclass Periodic_cubical_complex_persistence_interface "Gudhi::Persistent_cohomology_interface>>": - Periodic_cubical_complex_persistence_interface(Periodic_cubical_complex_base_interface * st, bool persistence_dim_max) - vector[pair[int, pair[double, double]]] get_persistence(int homology_coeff_field, double min_persistence) - vector[int] betti_numbers() - vector[int] persistent_betti_numbers(double from_value, double to_value) - vector[pair[double,double]] intervals_in_dimension(int dimension) - -# PeriodicCubicalComplex python interface -cdef class PeriodicCubicalComplex: - """The PeriodicCubicalComplex is an example of a structured complex useful - in computational mathematics (specially rigorous numerics) and image - analysis. - """ - cdef Periodic_cubical_complex_base_interface * thisptr - - cdef Periodic_cubical_complex_persistence_interface * pcohptr - - # Fake constructor that does nothing but documenting the constructor - def __init__(self, dimensions=None, top_dimensional_cells=None, - periodic_dimensions=None, perseus_file=''): - """PeriodicCubicalComplex constructor from dimensions and - top_dimensional_cells or from a Perseus-style file name. - - :param dimensions: A list of number of top dimensional cells. - :type dimensions: list of int - :param top_dimensional_cells: A list of cells filtration values. - :type top_dimensional_cells: list of double - :param periodic_dimensions: A list of top dimensional cells periodicity value. - :type periodic_dimensions: list of boolean - - Or - - :param perseus_file: A Perseus-style file name. - :type perseus_file: string - """ - - # The real cython constructor - def __cinit__(self, dimensions=None, top_dimensional_cells=None, - periodic_dimensions=None, perseus_file=''): - if (dimensions is not None) and (top_dimensional_cells is not None) and (periodic_dimensions is not None) and (perseus_file is ''): - self.thisptr = new Periodic_cubical_complex_base_interface(dimensions, top_dimensional_cells, periodic_dimensions) - elif (dimensions is None) and (top_dimensional_cells is None) and (periodic_dimensions is None) and (perseus_file is not ''): - if os.path.isfile(perseus_file): - self.thisptr = new Periodic_cubical_complex_base_interface(str.encode(perseus_file)) - else: - print("file " + perseus_file + " not found.") - else: - print("CubicalComplex can be constructed from dimensions and " - "top_dimensional_cells or from a Perseus-style file name.") - - def __dealloc__(self): - if self.thisptr != NULL: - del self.thisptr - if self.pcohptr != NULL: - del self.pcohptr - - def __is_defined(self): - """Returns true if PeriodicCubicalComplex pointer is not NULL. - """ - return self.thisptr != NULL - - def __is_persistence_defined(self): - """Returns true if Persistence pointer is not NULL. - """ - return self.pcohptr != NULL - - def num_simplices(self): - """This function returns the number of all cubes in the complex. - - :returns: int -- the number of all cubes in the complex. - """ - return self.thisptr.num_simplices() - - def dimension(self): - """This function returns the dimension of the complex. - - :returns: int -- the complex dimension. - """ - return self.thisptr.dimension() - - def persistence(self, homology_coeff_field=11, min_persistence=0): - """This function returns the persistence of the complex. - - :param homology_coeff_field: The homology coefficient field. Must be a - prime number - :type homology_coeff_field: int. - :param min_persistence: The minimum persistence value to take into - account (strictly greater than min_persistence). Default value is - 0.0. - Sets min_persistence to -1.0 to see all values. - :type min_persistence: float. - :returns: list of pairs(dimension, pair(birth, death)) -- the - persistence of the complex. - """ - if self.pcohptr != NULL: - del self.pcohptr - if self.thisptr != NULL: - self.pcohptr = new Periodic_cubical_complex_persistence_interface(self.thisptr, True) - cdef vector[pair[int, pair[double, double]]] persistence_result - if self.pcohptr != NULL: - persistence_result = self.pcohptr.get_persistence(homology_coeff_field, min_persistence) - return persistence_result - - def betti_numbers(self): - """This function returns the Betti numbers of the complex. - - :returns: list of int -- The Betti numbers ([B0, B1, ..., Bn]). - - :note: betti_numbers function requires persistence function to be - launched first. - - :note: betti_numbers function always returns [1, 0, 0, ...] as infinity - filtration cubes are not removed from the complex. - """ - cdef vector[int] bn_result - if self.pcohptr != NULL: - bn_result = self.pcohptr.betti_numbers() - return bn_result - - def persistent_betti_numbers(self, from_value, to_value): - """This function returns the persistent Betti numbers of the complex. - - :param from_value: The persistence birth limit to be added in the - numbers (persistent birth <= from_value). - :type from_value: float. - :param to_value: The persistence death limit to be added in the - numbers (persistent death > to_value). - :type to_value: float. - - :returns: list of int -- The persistent Betti numbers ([B0, B1, ..., - Bn]). - - :note: persistent_betti_numbers function requires persistence - function to be launched first. - """ - cdef vector[int] pbn_result - if self.pcohptr != NULL: - pbn_result = self.pcohptr.persistent_betti_numbers(from_value, to_value) - return pbn_result - - def persistence_intervals_in_dimension(self, dimension): - """This function returns the persistence intervals of the complex in a - specific dimension. - - :param dimension: The specific dimension. - :type dimension: int. - :returns: The persistence intervals. - :rtype: numpy array of dimension 2 - - :note: intervals_in_dim function requires persistence function to be - launched first. - """ - cdef vector[pair[double,double]] intervals_result - if self.pcohptr != NULL: - intervals_result = self.pcohptr.intervals_in_dimension(dimension) - else: - print("intervals_in_dim function requires persistence function" - " to be launched first.") - return np_array(intervals_result) diff --git a/src/cython/cython/persistence_graphical_tools.py b/src/cython/cython/persistence_graphical_tools.py deleted file mode 100644 index 34803222..00000000 --- a/src/cython/cython/persistence_graphical_tools.py +++ /dev/null @@ -1,420 +0,0 @@ -from os import path -from math import isfinite -import numpy as np - -""" 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, Bertrand Michel - - Copyright (C) 2016 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -__author__ = "Vincent Rouvreau, Bertrand Michel" -__copyright__ = "Copyright (C) 2016 Inria" -__license__ = "MIT" - - -def __min_birth_max_death(persistence, band=0.0): - """This function returns (min_birth, max_death) from the persistence. - - :param persistence: The persistence to plot. - :type persistence: list of tuples(dimension, tuple(birth, death)). - :param band: band - :type band: float. - :returns: (float, float) -- (min_birth, max_death). - """ - # Look for minimum birth date and maximum death date for plot optimisation - max_death = 0 - min_birth = persistence[0][1][0] - for interval in reversed(persistence): - if float(interval[1][1]) != float("inf"): - if float(interval[1][1]) > max_death: - max_death = float(interval[1][1]) - if float(interval[1][0]) > max_death: - max_death = float(interval[1][0]) - if float(interval[1][0]) < min_birth: - min_birth = float(interval[1][0]) - if band > 0.0: - max_death += band - return (min_birth, max_death) - - -""" -Only 13 colors for the palette -""" -palette = [ - "#ff0000", - "#00ff00", - "#0000ff", - "#00ffff", - "#ff00ff", - "#ffff00", - "#000000", - "#880000", - "#008800", - "#000088", - "#888800", - "#880088", - "#008888", -] - - -def plot_persistence_barcode( - persistence=[], - persistence_file="", - alpha=0.6, - max_intervals=1000, - max_barcodes=1000, - inf_delta=0.1, - legend=False, -): - """This function plots the persistence bar code from persistence values list - or from a :doc:`persistence file `. - - :param persistence: Persistence intervals values list grouped by dimension. - :type persistence: list of tuples(dimension, tuple(birth, death)). - :param persistence_file: A :doc:`persistence file ` style name - (reset persistence if both are set). - :type persistence_file: string - :param alpha: barcode transparency value (0.0 transparent through 1.0 - opaque - default is 0.6). - :type alpha: float. - :param max_intervals: maximal number of intervals to display. - Selected intervals are those with the longest life time. Set it - to 0 to see all. Default value is 1000. - :type max_intervals: int. - :param inf_delta: Infinity is placed at :code:`((max_death - min_birth) x - inf_delta)` above :code:`max_death` value. A reasonable value is - between 0.05 and 0.5 - default is 0.1. - :type inf_delta: float. - :param legend: Display the dimension color legend (default is False). - :type legend: boolean. - :returns: A matplotlib object containing horizontal bar plot of persistence - (launch `show()` method on it to display it). - """ - try: - import matplotlib.pyplot as plt - import matplotlib.patches as mpatches - - if persistence_file is not "": - if path.isfile(persistence_file): - # Reset persistence - persistence = [] - diag = read_persistence_intervals_grouped_by_dimension( - persistence_file=persistence_file - ) - for key in diag.keys(): - for persistence_interval in diag[key]: - persistence.append((key, persistence_interval)) - else: - print("file " + persistence_file + " not found.") - return None - - if max_barcodes is not 1000: - print("Deprecated parameter. It has been replaced by max_intervals") - max_intervals = max_barcodes - - if max_intervals > 0 and max_intervals < len(persistence): - # Sort by life time, then takes only the max_intervals elements - persistence = sorted( - persistence, - key=lambda life_time: life_time[1][1] - life_time[1][0], - reverse=True, - )[:max_intervals] - - persistence = sorted(persistence, key=lambda birth: birth[1][0]) - - (min_birth, max_death) = __min_birth_max_death(persistence) - ind = 0 - delta = (max_death - min_birth) * inf_delta - # Replace infinity values with max_death + delta for bar code to be more - # readable - infinity = max_death + delta - axis_start = min_birth - delta - # Draw horizontal bars in loop - for interval in reversed(persistence): - if float(interval[1][1]) != float("inf"): - # Finite death case - plt.barh( - ind, - (interval[1][1] - interval[1][0]), - height=0.8, - left=interval[1][0], - alpha=alpha, - color=palette[interval[0]], - linewidth=0, - ) - else: - # Infinite death case for diagram to be nicer - plt.barh( - ind, - (infinity - interval[1][0]), - height=0.8, - left=interval[1][0], - alpha=alpha, - color=palette[interval[0]], - linewidth=0, - ) - ind = ind + 1 - - if legend: - dimensions = list(set(item[0] for item in persistence)) - plt.legend( - handles=[ - mpatches.Patch(color=palette[dim], label=str(dim)) - for dim in dimensions - ], - loc="lower right", - ) - plt.title("Persistence barcode") - # Ends plot on infinity value and starts a little bit before min_birth - plt.axis([axis_start, infinity, 0, ind]) - return plt - - except ImportError: - print("This function is not available, you may be missing matplotlib.") - - -def plot_persistence_diagram( - persistence=[], - persistence_file="", - alpha=0.6, - band=0.0, - max_intervals=1000, - max_plots=1000, - inf_delta=0.1, - legend=False, -): - """This function plots the persistence diagram from persistence values - list or from a :doc:`persistence file `. - - :param persistence: Persistence intervals values list grouped by dimension. - :type persistence: list of tuples(dimension, tuple(birth, death)). - :param persistence_file: A :doc:`persistence file ` style name - (reset persistence if both are set). - :type persistence_file: string - :param alpha: plot transparency value (0.0 transparent through 1.0 - opaque - default is 0.6). - :type alpha: float. - :param band: band (not displayed if :math:`\leq` 0. - default is 0.) - :type band: float. - :param max_intervals: maximal number of intervals to display. - Selected intervals are those with the longest life time. Set it - to 0 to see all. Default value is 1000. - :type max_intervals: int. - :param inf_delta: Infinity is placed at :code:`((max_death - min_birth) x - inf_delta)` above :code:`max_death` value. A reasonable value is - between 0.05 and 0.5 - default is 0.1. - :type inf_delta: float. - :param legend: Display the dimension color legend (default is False). - :type legend: boolean. - :returns: A matplotlib object containing diagram plot of persistence - (launch `show()` method on it to display it). - """ - try: - import matplotlib.pyplot as plt - import matplotlib.patches as mpatches - - if persistence_file is not "": - if path.isfile(persistence_file): - # Reset persistence - persistence = [] - diag = read_persistence_intervals_grouped_by_dimension( - persistence_file=persistence_file - ) - for key in diag.keys(): - for persistence_interval in diag[key]: - persistence.append((key, persistence_interval)) - else: - print("file " + persistence_file + " not found.") - return None - - if max_plots is not 1000: - print("Deprecated parameter. It has been replaced by max_intervals") - max_intervals = max_plots - - if max_intervals > 0 and max_intervals < len(persistence): - # Sort by life time, then takes only the max_intervals elements - persistence = sorted( - persistence, - key=lambda life_time: life_time[1][1] - life_time[1][0], - reverse=True, - )[:max_intervals] - - (min_birth, max_death) = __min_birth_max_death(persistence, band) - delta = (max_death - min_birth) * inf_delta - # Replace infinity values with max_death + delta for diagram to be more - # readable - infinity = max_death + delta - axis_start = min_birth - delta - - # line display of equation : birth = death - x = np.linspace(axis_start, infinity, 1000) - # infinity line and text - plt.plot(x, x, color="k", linewidth=1.0) - plt.plot(x, [infinity] * len(x), linewidth=1.0, color="k", alpha=alpha) - plt.text(axis_start, infinity, r"$\infty$", color="k", alpha=alpha) - # bootstrap band - if band > 0.0: - plt.fill_between(x, x, x + band, alpha=alpha, facecolor="red") - - # Draw points in loop - for interval in reversed(persistence): - if float(interval[1][1]) != float("inf"): - # Finite death case - plt.scatter( - interval[1][0], - interval[1][1], - alpha=alpha, - color=palette[interval[0]], - ) - else: - # Infinite death case for diagram to be nicer - plt.scatter( - interval[1][0], infinity, alpha=alpha, color=palette[interval[0]] - ) - - if legend: - dimensions = list(set(item[0] for item in persistence)) - plt.legend( - handles=[ - mpatches.Patch(color=palette[dim], label=str(dim)) - for dim in dimensions - ] - ) - - plt.title("Persistence diagram") - plt.xlabel("Birth") - plt.ylabel("Death") - # Ends plot on infinity value and starts a little bit before min_birth - plt.axis([axis_start, infinity, axis_start, infinity + delta]) - return plt - - except ImportError: - print("This function is not available, you may be missing matplotlib.") - - -def plot_persistence_density( - persistence=[], - persistence_file="", - nbins=300, - bw_method=None, - max_intervals=1000, - dimension=None, - cmap=None, - legend=False, -): - """This function plots the persistence density from persistence - values list or from a :doc:`persistence file `. Be - aware that this function does not distinguish the dimension, it is - up to you to select the required one. This function also does not handle - degenerate data set (scipy correlation matrix inversion can fail). - - :param persistence: Persistence intervals values list grouped by dimension. - :type persistence: list of tuples(dimension, tuple(birth, death)). - :param persistence_file: A :doc:`persistence file ` - style name (reset persistence if both are set). - :type persistence_file: string - :param nbins: Evaluate a gaussian kde on a regular grid of nbins x - nbins over data extents (default is 300) - :type nbins: int. - :param bw_method: The method used to calculate the estimator - bandwidth. This can be 'scott', 'silverman', a scalar constant - or a callable. If a scalar, this will be used directly as - kde.factor. If a callable, it should take a gaussian_kde - instance as only parameter and return a scalar. If None - (default), 'scott' is used. See - `scipy.stats.gaussian_kde documentation - `_ - for more details. - :type bw_method: str, scalar or callable, optional. - :param max_intervals: maximal number of points used in the density - estimation. - Selected intervals are those with the longest life time. Set it - to 0 to see all. Default value is 1000. - :type max_intervals: int. - :param dimension: the dimension to be selected in the intervals - (default is None to mix all dimensions). - :type dimension: int. - :param cmap: A matplotlib colormap (default is - matplotlib.pyplot.cm.hot_r). - :type cmap: cf. matplotlib colormap. - :param legend: Display the color bar values (default is False). - :type legend: boolean. - :returns: A matplotlib object containing diagram plot of persistence - (launch `show()` method on it to display it). - """ - try: - import matplotlib.pyplot as plt - from scipy.stats import kde - - if persistence_file is not "": - if dimension is None: - # All dimension case - dimension = -1 - if path.isfile(persistence_file): - persistence_dim = read_persistence_intervals_in_dimension( - persistence_file=persistence_file, only_this_dim=dimension - ) - print(persistence_dim) - else: - print("file " + persistence_file + " not found.") - return None - - if len(persistence) > 0: - persistence_dim = np.array( - [ - (dim_interval[1][0], dim_interval[1][1]) - for dim_interval in persistence - if (dim_interval[0] == dimension) or (dimension is None) - ] - ) - - persistence_dim = persistence_dim[np.isfinite(persistence_dim[:, 1])] - if max_intervals > 0 and max_intervals < len(persistence_dim): - # Sort by life time, then takes only the max_intervals elements - persistence_dim = np.array( - sorted( - persistence_dim, - key=lambda life_time: life_time[1] - life_time[0], - reverse=True, - )[:max_intervals] - ) - - # Set as numpy array birth and death (remove undefined values - inf and NaN) - birth = persistence_dim[:, 0] - death = persistence_dim[:, 1] - - # line display of equation : birth = death - x = np.linspace(death.min(), birth.max(), 1000) - plt.plot(x, x, color="k", linewidth=1.0) - - # Evaluate a gaussian kde on a regular grid of nbins x nbins over data extents - k = kde.gaussian_kde([birth, death], bw_method=bw_method) - xi, yi = np.mgrid[ - birth.min() : birth.max() : nbins * 1j, - death.min() : death.max() : nbins * 1j, - ] - zi = k(np.vstack([xi.flatten(), yi.flatten()])) - - # default cmap value cannot be done at argument definition level as matplotlib is not yet defined. - if cmap is None: - cmap = plt.cm.hot_r - # Make the plot - plt.pcolormesh(xi, yi, zi.reshape(xi.shape), cmap=cmap) - - if legend: - plt.colorbar() - - plt.title("Persistence density") - plt.xlabel("Birth") - plt.ylabel("Death") - return plt - - except ImportError: - print( - "This function is not available, you may be missing matplotlib and/or scipy." - ) diff --git a/src/cython/cython/reader_utils.pyx b/src/cython/cython/reader_utils.pyx deleted file mode 100644 index 147fae71..00000000 --- a/src/cython/cython/reader_utils.pyx +++ /dev/null @@ -1,87 +0,0 @@ -from cython cimport numeric -from libcpp.vector cimport vector -from libcpp.string cimport string -from libcpp.map cimport map -from libcpp.pair cimport pair - -from os import path -from numpy import array as np_array - -""" 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) 2017 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2017 Inria" -__license__ = "MIT" - -cdef extern from "Reader_utils_interface.h" namespace "Gudhi": - vector[vector[double]] read_matrix_from_csv_file(string off_file, char separator) - map[int, vector[pair[double, double]]] read_pers_intervals_grouped_by_dimension(string filename) - vector[pair[double, double]] read_pers_intervals_in_dimension(string filename, int only_this_dim) - -def read_lower_triangular_matrix_from_csv_file(csv_file='', separator=';'): - """Read lower triangular matrix from a CSV style file. - - :param csv_file: A CSV file style name. - :type csv_file: string - :param separator: The value separator in the CSV file. Default value is ';' - :type separator: char - - :returns: The lower triangular matrix. - :rtype: vector[vector[double]] - """ - if csv_file is not '': - if path.isfile(csv_file): - return read_matrix_from_csv_file(str.encode(csv_file), ord(separator[0])) - print("file " + csv_file + " not set or not found.") - return [] - -def read_persistence_intervals_grouped_by_dimension(persistence_file=''): - """Reads a file containing persistence intervals. - Each line might contain 2, 3 or 4 values: [[field] dimension] birth death - The return value is an `map[dim, vector[pair[birth, death]]]` - where `dim` is an `int`, `birth` a `double`, and `death` a `double`. - Note: the function does not check that birth <= death. - - :param persistence_file: A persistence file style name. - :type persistence_file: string - - :returns: The persistence pairs grouped by dimension. - :rtype: map[int, vector[pair[double, double]]] - """ - if persistence_file is not '': - if path.isfile(persistence_file): - return read_pers_intervals_grouped_by_dimension(str.encode(persistence_file)) - print("file " + persistence_file + " not set or not found.") - return [] - -def read_persistence_intervals_in_dimension(persistence_file='', only_this_dim=-1): - """Reads a file containing persistence intervals. - Each line of persistence_file might contain 2, 3 or 4 values: - [[field] dimension] birth death - Note: the function does not check that birth <= death. - - :param persistence_file: A persistence file style name. - :type persistence_file: string - :param only_this_dim: The specific dimension. Default value is -1. - If `only_this_dim` = -1, dimension is ignored and all lines are returned. - If `only_this_dim` is >= 0, only the lines where dimension = - `only_this_dim` (or where dimension is not specified) are returned. - :type only_this_dim: int. - - :returns: The persistence intervals. - :rtype: numpy array of dimension 2 - """ - if persistence_file is not '': - if path.isfile(persistence_file): - return np_array(read_pers_intervals_in_dimension(str.encode( - persistence_file), only_this_dim)) - print("file " + persistence_file + " not set or not found.") - return [] diff --git a/src/cython/cython/rips_complex.pyx b/src/cython/cython/rips_complex.pyx deleted file mode 100644 index b9a2331f..00000000 --- a/src/cython/cython/rips_complex.pyx +++ /dev/null @@ -1,98 +0,0 @@ -from cython cimport numeric -from libcpp.vector cimport vector -from libcpp.utility cimport pair -from libcpp.string cimport string -from libcpp cimport bool -import os - -""" 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) 2016 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 Inria" -__license__ = "MIT" - -cdef extern from "Rips_complex_interface.h" namespace "Gudhi": - cdef cppclass Rips_complex_interface "Gudhi::rips_complex::Rips_complex_interface": - Rips_complex_interface() - void init_points(vector[vector[double]] values, double threshold) - void init_matrix(vector[vector[double]] values, double threshold) - void init_points_sparse(vector[vector[double]] values, double threshold, double sparse) - void init_matrix_sparse(vector[vector[double]] values, double threshold, double sparse) - void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, int dim_max) - -# RipsComplex python interface -cdef class RipsComplex: - """The data structure is a one skeleton graph, or Rips graph, containing - edges when the edge length is less or equal to a given threshold. Edge - length is computed from a user given point cloud with a given distance - function, or a distance matrix. - """ - - cdef Rips_complex_interface thisref - - # Fake constructor that does nothing but documenting the constructor - def __init__(self, points=None, distance_matrix=None, - max_edge_length=float('inf'), sparse=None): - """RipsComplex constructor. - - :param max_edge_length: Rips value. - :type max_edge_length: float - - :param points: A list of points in d-Dimension. - :type points: list of list of double - - Or - - :param distance_matrix: A distance matrix (full square or lower - triangular). - :type points: list of list of double - - And in both cases - - :param sparse: If this is not None, it switches to building a sparse - Rips and represents the approximation parameter epsilon. - :type sparse: float - """ - - # The real cython constructor - def __cinit__(self, points=None, distance_matrix=None, - max_edge_length=float('inf'), sparse=None): - if sparse is not None: - if distance_matrix is not None: - self.thisref.init_matrix_sparse(distance_matrix, - max_edge_length, - sparse) - else: - if points is None: - # Empty Rips construction - points=[] - self.thisref.init_points_sparse(points, max_edge_length, sparse) - else: - if distance_matrix is not None: - self.thisref.init_matrix(distance_matrix, max_edge_length) - else: - if points is None: - # Empty Rips construction - points=[] - self.thisref.init_points(points, max_edge_length) - - - def create_simplex_tree(self, max_dimension=1): - """ - :param max_dimension: graph expansion for rips until this given maximal - dimension. - :type max_dimension: int - :returns: A simplex tree created from the Delaunay Triangulation. - :rtype: SimplexTree - """ - simplex_tree = SimplexTree() - self.thisref.create_simplex_tree(simplex_tree.thisptr, max_dimension) - return simplex_tree diff --git a/src/cython/cython/simplex_tree.pyx b/src/cython/cython/simplex_tree.pyx deleted file mode 100644 index 8e791c17..00000000 --- a/src/cython/cython/simplex_tree.pyx +++ /dev/null @@ -1,542 +0,0 @@ -from cython cimport numeric -from libcpp.vector cimport vector -from libcpp.utility cimport pair -from libcpp cimport bool -from libcpp.string cimport string - -from numpy import array as np_array - -""" 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) 2016 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 Inria" -__license__ = "MIT" - -cdef extern from "Simplex_tree_interface.h" namespace "Gudhi": - cdef cppclass Simplex_tree_options_full_featured: - pass - - cdef cppclass Simplex_tree_interface_full_featured "Gudhi::Simplex_tree_interface": - Simplex_tree() - double simplex_filtration(vector[int] simplex) - void assign_simplex_filtration(vector[int] simplex, double filtration) - void initialize_filtration() - int num_vertices() - int num_simplices() - void set_dimension(int dimension) - int dimension() - int upper_bound_dimension() - bool find_simplex(vector[int] simplex) - bool insert_simplex_and_subfaces(vector[int] simplex, - double filtration) - vector[pair[vector[int], double]] get_filtration() - vector[pair[vector[int], double]] get_skeleton(int dimension) - vector[pair[vector[int], double]] get_star(vector[int] simplex) - vector[pair[vector[int], double]] get_cofaces(vector[int] simplex, - int dimension) - void expansion(int max_dim) - void remove_maximal_simplex(vector[int] simplex) - bool prune_above_filtration(double filtration) - bool make_filtration_non_decreasing() - -cdef extern from "Persistent_cohomology_interface.h" namespace "Gudhi": - cdef cppclass Simplex_tree_persistence_interface "Gudhi::Persistent_cohomology_interface>": - Simplex_tree_persistence_interface(Simplex_tree_interface_full_featured * st, bool persistence_dim_max) - vector[pair[int, pair[double, double]]] get_persistence(int homology_coeff_field, double min_persistence) - vector[int] betti_numbers() - vector[int] persistent_betti_numbers(double from_value, double to_value) - vector[pair[double,double]] intervals_in_dimension(int dimension) - void write_output_diagram(string diagram_file_name) - vector[pair[vector[int], vector[int]]] persistence_pairs() - -# SimplexTree python interface -cdef class SimplexTree: - """The simplex tree is an efficient and flexible data structure for - representing general (filtered) simplicial complexes. The data structure - is described in Jean-Daniel Boissonnat and Clément Maria. The Simplex - Tree: An Efficient Data Structure for General Simplicial Complexes. - Algorithmica, pages 1–22, 2014. - - This class is a filtered, with keys, and non contiguous vertices version - of the simplex tree. - """ - cdef Simplex_tree_interface_full_featured * thisptr - - cdef Simplex_tree_persistence_interface * pcohptr - - # Fake constructor that does nothing but documenting the constructor - def __init__(self): - """SimplexTree constructor. - """ - - # The real cython constructor - def __cinit__(self): - self.thisptr = new Simplex_tree_interface_full_featured() - - def __dealloc__(self): - if self.thisptr != NULL: - del self.thisptr - if self.pcohptr != NULL: - del self.pcohptr - - def __is_defined(self): - """Returns true if SimplexTree pointer is not NULL. - """ - return self.thisptr != NULL - - def __is_persistence_defined(self): - """Returns true if Persistence pointer is not NULL. - """ - return self.pcohptr != NULL - - def filtration(self, simplex): - """This function returns the filtration value for a given N-simplex in - this simplicial complex, or +infinity if it is not in the complex. - - :param simplex: The N-simplex, represented by a list of vertex. - :type simplex: list of int. - :returns: The simplicial complex filtration value. - :rtype: float - """ - return self.thisptr.simplex_filtration(simplex) - - def assign_filtration(self, simplex, filtration): - """This function assigns the simplicial complex filtration value for a - given N-simplex. - - :param simplex: The N-simplex, represented by a list of vertex. - :type simplex: list of int. - :param filtration: The simplicial complex filtration value. - :type filtration: float - """ - self.thisptr.assign_simplex_filtration(simplex, filtration) - - def initialize_filtration(self): - """This function initializes and sorts the simplicial complex - filtration vector. - - .. note:: - - This function must be launched before - :func:`persistence()`, - :func:`betti_numbers()`, - :func:`persistent_betti_numbers()`, - or :func:`get_filtration()` - after :func:`inserting` or - :func:`removing` - simplices. - """ - self.thisptr.initialize_filtration() - - def num_vertices(self): - """This function returns the number of vertices of the simplicial - complex. - - :returns: The simplicial complex number of vertices. - :rtype: int - """ - return self.thisptr.num_vertices() - - def num_simplices(self): - """This function returns the number of simplices of the simplicial - complex. - - :returns: the simplicial complex number of simplices. - :rtype: int - """ - return self.thisptr.num_simplices() - - def dimension(self): - """This function returns the dimension of the simplicial complex. - - :returns: the simplicial complex dimension. - :rtype: int - - .. note:: - - This function is not constant time because it can recompute - dimension if required (can be triggered by - :func:`remove_maximal_simplex()` - or - :func:`prune_above_filtration()` - methods). - """ - return self.thisptr.dimension() - - def upper_bound_dimension(self): - """This function returns a valid dimension upper bound of the - simplicial complex. - - :returns: an upper bound on the dimension of the simplicial complex. - :rtype: int - """ - return self.thisptr.upper_bound_dimension() - - def set_dimension(self, dimension): - """This function sets the dimension of the simplicial complex. - - :param dimension: The new dimension value. - :type dimension: int. - - .. note:: - - This function must be used with caution because it disables - dimension recomputation when required - (this recomputation can be triggered by - :func:`remove_maximal_simplex()` - or - :func:`prune_above_filtration()` - ). - """ - self.thisptr.set_dimension(dimension) - - def find(self, simplex): - """This function returns if the N-simplex was found in the simplicial - complex or not. - - :param simplex: The N-simplex to find, represented by a list of vertex. - :type simplex: list of int. - :returns: true if the simplex was found, false otherwise. - :rtype: bool - """ - cdef vector[int] csimplex - for i in simplex: - csimplex.push_back(i) - return self.thisptr.find_simplex(csimplex) - - def insert(self, simplex, filtration=0.0): - """This function inserts the given N-simplex and its subfaces with the - given filtration value (default value is '0.0'). If some of those - simplices are already present with a higher filtration value, their - filtration value is lowered. - - :param simplex: The N-simplex to insert, represented by a list of - vertex. - :type simplex: list of int. - :param filtration: The filtration value of the simplex. - :type filtration: float. - :returns: true if the simplex was not yet in the complex, false - otherwise (whatever its original filtration value). - :rtype: bool - """ - cdef vector[int] csimplex - for i in simplex: - csimplex.push_back(i) - return self.thisptr.insert_simplex_and_subfaces(csimplex, - filtration) - - def get_filtration(self): - """This function returns a list of all simplices with their given - filtration values. - - :returns: The simplices sorted by increasing filtration values. - :rtype: list of tuples(simplex, filtration) - """ - cdef vector[pair[vector[int], double]] filtration \ - = self.thisptr.get_filtration() - ct = [] - for filtered_complex in filtration: - v = [] - for vertex in filtered_complex.first: - v.append(vertex) - ct.append((v, filtered_complex.second)) - return ct - - def get_skeleton(self, dimension): - """This function returns the (simplices of the) skeleton of a maximum - given dimension. - - :param dimension: The skeleton dimension value. - :type dimension: int. - :returns: The (simplices of the) skeleton of a maximum dimension. - :rtype: list of tuples(simplex, filtration) - """ - cdef vector[pair[vector[int], double]] skeleton \ - = self.thisptr.get_skeleton(dimension) - ct = [] - for filtered_simplex in skeleton: - v = [] - for vertex in filtered_simplex.first: - v.append(vertex) - ct.append((v, filtered_simplex.second)) - return ct - - def get_star(self, simplex): - """This function returns the star of a given N-simplex. - - :param simplex: The N-simplex, represented by a list of vertex. - :type simplex: list of int. - :returns: The (simplices of the) star of a simplex. - :rtype: list of tuples(simplex, filtration) - """ - cdef vector[int] csimplex - for i in simplex: - csimplex.push_back(i) - cdef vector[pair[vector[int], double]] star \ - = self.thisptr.get_star(csimplex) - ct = [] - for filtered_simplex in star: - v = [] - for vertex in filtered_simplex.first: - v.append(vertex) - ct.append((v, filtered_simplex.second)) - return ct - - def get_cofaces(self, simplex, codimension): - """This function returns the cofaces of a given N-simplex with a - given codimension. - - :param simplex: The N-simplex, represented by a list of vertex. - :type simplex: list of int. - :param codimension: The codimension. If codimension = 0, all cofaces - are returned (equivalent of get_star function) - :type codimension: int. - :returns: The (simplices of the) cofaces of a simplex - :rtype: list of tuples(simplex, filtration) - """ - cdef vector[int] csimplex - for i in simplex: - csimplex.push_back(i) - cdef vector[pair[vector[int], double]] cofaces \ - = self.thisptr.get_cofaces(csimplex, codimension) - ct = [] - for filtered_simplex in cofaces: - v = [] - for vertex in filtered_simplex.first: - v.append(vertex) - ct.append((v, filtered_simplex.second)) - return ct - - def remove_maximal_simplex(self, simplex): - """This function removes a given maximal N-simplex from the simplicial - complex. - - :param simplex: The N-simplex, represented by a list of vertex. - :type simplex: list of int. - - .. note:: - - Be aware that removing is shifting data in a flat_map - (:func:`initialize_filtration()` to be done). - - .. note:: - - The dimension of the simplicial complex may be lower after calling - remove_maximal_simplex than it was before. However, - :func:`upper_bound_dimension()` - method will return the old value, which - remains a valid upper bound. If you care, you can call - :func:`dimension()` - to recompute the exact dimension. - """ - self.thisptr.remove_maximal_simplex(simplex) - - def prune_above_filtration(self, filtration): - """Prune above filtration value given as parameter. - - :param filtration: Maximum threshold value. - :type filtration: float. - :returns: The filtration modification information. - :rtype: bool - - - .. note:: - - Some simplex tree functions require the filtration to be valid. - prune_above_filtration function is not launching - :func:`initialize_filtration()` - but returns the filtration modification - information. If the complex has changed , please call - :func:`initialize_filtration()` - to recompute it. - - .. note:: - - Note that the dimension of the simplicial complex may be lower - after calling - :func:`prune_above_filtration()` - than it was before. However, - :func:`upper_bound_dimension()` - will return the old value, which remains a - valid upper bound. If you care, you can call - :func:`dimension()` - method to recompute the exact dimension. - """ - return self.thisptr.prune_above_filtration(filtration) - - def expansion(self, max_dim): - """Expands the Simplex_tree containing only its one skeleton - until dimension max_dim. - - The expanded simplicial complex until dimension :math:`d` - attached to a graph :math:`G` is the maximal simplicial complex of - dimension at most :math:`d` admitting the graph :math:`G` as - :math:`1`-skeleton. - The filtration value assigned to a simplex is the maximal filtration - value of one of its edges. - - The Simplex_tree must contain no simplex of dimension bigger than - 1 when calling the method. - - :param max_dim: The maximal dimension. - :type max_dim: int. - """ - self.thisptr.expansion(max_dim) - - def make_filtration_non_decreasing(self): - """This function ensures that each simplex has a higher filtration - value than its faces by increasing the filtration values. - - :returns: True if any filtration value was modified, - False if the filtration was already non-decreasing. - :rtype: bool - - - .. note:: - - Some simplex tree functions require the filtration to be valid. - make_filtration_non_decreasing function is not launching - :func:`initialize_filtration()` - but returns the filtration modification - information. If the complex has changed , please call - :func:`initialize_filtration()` - to recompute it. - """ - return self.thisptr.make_filtration_non_decreasing() - - def persistence(self, homology_coeff_field=11, min_persistence=0, persistence_dim_max = False): - """This function returns the persistence of the simplicial complex. - - :param homology_coeff_field: The homology coefficient field. Must be a - prime number. Default value is 11. - :type homology_coeff_field: int. - :param min_persistence: The minimum persistence value to take into - account (strictly greater than min_persistence). Default value is - 0.0. - Sets min_persistence to -1.0 to see all values. - :type min_persistence: float. - :param persistence_dim_max: If true, the persistent homology for the - maximal dimension in the complex is computed. If false, it is - ignored. Default is false. - :type persistence_dim_max: bool - :returns: The persistence of the simplicial complex. - :rtype: list of pairs(dimension, pair(birth, death)) - """ - if self.pcohptr != NULL: - del self.pcohptr - self.pcohptr = new Simplex_tree_persistence_interface(self.thisptr, persistence_dim_max) - cdef vector[pair[int, pair[double, double]]] persistence_result - if self.pcohptr != NULL: - persistence_result = self.pcohptr.get_persistence(homology_coeff_field, min_persistence) - return persistence_result - - def betti_numbers(self): - """This function returns the Betti numbers of the simplicial complex. - - :returns: The Betti numbers ([B0, B1, ..., Bn]). - :rtype: list of int - - :note: betti_numbers function requires - :func:`persistence()` - function to be launched first. - """ - cdef vector[int] bn_result - if self.pcohptr != NULL: - bn_result = self.pcohptr.betti_numbers() - else: - print("betti_numbers function requires persistence function" - " to be launched first.") - return bn_result - - def persistent_betti_numbers(self, from_value, to_value): - """This function returns the persistent Betti numbers of the - simplicial complex. - - :param from_value: The persistence birth limit to be added in the - numbers (persistent birth <= from_value). - :type from_value: float. - :param to_value: The persistence death limit to be added in the - numbers (persistent death > to_value). - :type to_value: float. - - :returns: The persistent Betti numbers ([B0, B1, ..., Bn]). - :rtype: list of int - - :note: persistent_betti_numbers function requires - :func:`persistence()` - function to be launched first. - """ - cdef vector[int] pbn_result - if self.pcohptr != NULL: - pbn_result = self.pcohptr.persistent_betti_numbers(from_value, to_value) - else: - print("persistent_betti_numbers function requires persistence function" - " to be launched first.") - return pbn_result - - def persistence_intervals_in_dimension(self, dimension): - """This function returns the persistence intervals of the simplicial - complex in a specific dimension. - - :param dimension: The specific dimension. - :type dimension: int. - :returns: The persistence intervals. - :rtype: numpy array of dimension 2 - - :note: intervals_in_dim function requires - :func:`persistence()` - function to be launched first. - """ - cdef vector[pair[double,double]] intervals_result - if self.pcohptr != NULL: - intervals_result = self.pcohptr.intervals_in_dimension(dimension) - else: - print("intervals_in_dim function requires persistence function" - " to be launched first.") - return np_array(intervals_result) - - def persistence_pairs(self): - """This function returns a list of persistence birth and death simplices pairs. - - :returns: A list of persistence simplices intervals. - :rtype: list of pair of list of int - - :note: persistence_pairs function requires - :func:`persistence()` - function to be launched first. - """ - cdef vector[pair[vector[int],vector[int]]] persistence_pairs_result - if self.pcohptr != NULL: - persistence_pairs_result = self.pcohptr.persistence_pairs() - else: - print("persistence_pairs function requires persistence function" - " to be launched first.") - return persistence_pairs_result - - def write_persistence_diagram(self, persistence_file=''): - """This function writes the persistence intervals of the simplicial - complex in a user given file name. - - :param persistence_file: The specific dimension. - :type persistence_file: string. - - :note: intervals_in_dim function requires - :func:`persistence()` - function to be launched first. - """ - if self.pcohptr != NULL: - if persistence_file != '': - self.pcohptr.write_output_diagram(str.encode(persistence_file)) - else: - print("persistence_file must be specified") - else: - print("intervals_in_dim function requires persistence function" - " to be launched first.") diff --git a/src/cython/cython/strong_witness_complex.pyx b/src/cython/cython/strong_witness_complex.pyx deleted file mode 100644 index 8c155815..00000000 --- a/src/cython/cython/strong_witness_complex.pyx +++ /dev/null @@ -1,71 +0,0 @@ -from cython cimport numeric -from libcpp.vector cimport vector -from libcpp.utility cimport pair - -""" 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) 2016 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 Inria" -__license__ = "MIT" - -cdef extern from "Strong_witness_complex_interface.h" namespace "Gudhi": - cdef cppclass Strong_witness_complex_interface "Gudhi::witness_complex::Strong_witness_complex_interface": - Strong_witness_complex_interface(vector[vector[pair[size_t, double]]] nearest_landmark_table) - void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square) - void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square, - unsigned limit_dimension) - -# StrongWitnessComplex python interface -cdef class StrongWitnessComplex: - """Constructs (strong) witness complex for a given table of nearest - landmarks with respect to witnesses. - """ - - cdef Strong_witness_complex_interface * thisptr - - # Fake constructor that does nothing but documenting the constructor - def __init__(self, nearest_landmark_table=None): - """StrongWitnessComplex constructor. - - :param nearest_landmark_table: A list of lists of nearest landmarks and their distances. - `nearest_landmark_table[w][k]==(l,d)` means that l is the k-th nearest landmark to - witness w, and d is the (squared) distance between l and w. - :type nearest_landmark_table: list of list of pair of int and float - """ - - # The real cython constructor - def __cinit__(self, nearest_landmark_table=None): - if nearest_landmark_table is not None: - self.thisptr = new Strong_witness_complex_interface(nearest_landmark_table) - - def __dealloc__(self): - if self.thisptr != NULL: - del self.thisptr - - def __is_defined(self): - """Returns true if StrongWitnessComplex pointer is not NULL. - """ - return self.thisptr != NULL - - def create_simplex_tree(self, max_alpha_square = float('inf'), limit_dimension = -1): - """ - :param max_alpha_square: The maximum relaxation parameter. - Default is set to infinity. - :type max_alpha_square: float - :returns: A simplex tree created from the Delaunay Triangulation. - :rtype: SimplexTree - """ - simplex_tree = SimplexTree() - if limit_dimension is not -1: - self.thisptr.create_simplex_tree(simplex_tree.thisptr, max_alpha_square, limit_dimension) - else: - self.thisptr.create_simplex_tree(simplex_tree.thisptr, max_alpha_square) - return simplex_tree diff --git a/src/cython/cython/subsampling.pyx b/src/cython/cython/subsampling.pyx deleted file mode 100644 index 1135c1fb..00000000 --- a/src/cython/cython/subsampling.pyx +++ /dev/null @@ -1,130 +0,0 @@ -from cython cimport numeric -from libcpp.vector cimport vector -from libcpp.string cimport string -from libcpp cimport bool -import os - -""" 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) 2016 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 Inria" -__license__ = "GPL v3" - -cdef extern from "Subsampling_interface.h" namespace "Gudhi::subsampling": - vector[vector[double]] subsampling_n_farthest_points(vector[vector[double]] points, unsigned nb_points) - vector[vector[double]] subsampling_n_farthest_points(vector[vector[double]] points, unsigned nb_points, unsigned starting_point) - vector[vector[double]] subsampling_n_farthest_points_from_file(string off_file, unsigned nb_points) - vector[vector[double]] subsampling_n_farthest_points_from_file(string off_file, unsigned nb_points, unsigned starting_point) - vector[vector[double]] subsampling_n_random_points(vector[vector[double]] points, unsigned nb_points) - vector[vector[double]] subsampling_n_random_points_from_file(string off_file, unsigned nb_points) - vector[vector[double]] subsampling_sparsify_points(vector[vector[double]] points, double min_squared_dist) - vector[vector[double]] subsampling_sparsify_points_from_file(string off_file, double min_squared_dist) - -def choose_n_farthest_points(points=None, off_file='', nb_points=0, starting_point = ''): - """Subsample by a greedy strategy of iteratively adding the farthest point - from the current chosen point set to the subsampling. - The iteration starts with the landmark `starting point`. - - :param points: The input point set. - :type points: vector[vector[double]]. - - Or - - :param off_file: An OFF file style name. - :type off_file: string - - :param nb_points: Number of points of the subsample. - :type nb_points: unsigned. - :param starting_point: The iteration starts with the landmark `starting \ - point`,which is the index of the poit to start with. If not set, this \ - index is choosen randomly. - :type starting_point: unsigned. - :returns: The subsample point set. - :rtype: vector[vector[double]] - """ - if off_file is not '': - if os.path.isfile(off_file): - if starting_point is '': - return subsampling_n_farthest_points_from_file(str.encode(off_file), - nb_points) - else: - return subsampling_n_farthest_points_from_file(str.encode(off_file), - nb_points, - starting_point) - else: - print("file " + off_file + " not found.") - else: - if points is None: - # Empty points - points=[] - if starting_point is '': - return subsampling_n_farthest_points(points, nb_points) - else: - return subsampling_n_farthest_points(points, nb_points, - starting_point) - -def pick_n_random_points(points=None, off_file='', nb_points=0): - """Subsample a point set by picking random vertices. - - :param points: The input point set. - :type points: vector[vector[double]]. - - Or - - :param off_file: An OFF file style name. - :type off_file: string - - :param nb_points: Number of points of the subsample. - :type nb_points: unsigned. - :returns: The subsample point set. - :rtype: vector[vector[double]] - """ - if off_file is not '': - if os.path.isfile(off_file): - return subsampling_n_random_points_from_file(str.encode(off_file), - nb_points) - else: - print("file " + off_file + " not found.") - else: - if points is None: - # Empty points - points=[] - return subsampling_n_random_points(points, nb_points) - -def sparsify_point_set(points=None, off_file='', min_squared_dist=0.0): - """Outputs a subset of the input points so that the squared distance - between any two points is greater than or equal to min_squared_dist. - - :param points: The input point set. - :type points: vector[vector[double]]. - - Or - - :param off_file: An OFF file style name. - :type off_file: string - - :param min_squared_dist: Minimum squared distance separating the output \ - points. - :type min_squared_dist: float. - :returns: The subsample point set. - :rtype: vector[vector[double]] - """ - if off_file is not '': - if os.path.isfile(off_file): - return subsampling_sparsify_points_from_file(str.encode(off_file), - min_squared_dist) - else: - print("file " + off_file + " not found.") - else: - if points is None: - # Empty points - points=[] - return subsampling_sparsify_points(points, min_squared_dist) diff --git a/src/cython/cython/tangential_complex.pyx b/src/cython/cython/tangential_complex.pyx deleted file mode 100644 index 00a84810..00000000 --- a/src/cython/cython/tangential_complex.pyx +++ /dev/null @@ -1,168 +0,0 @@ -from cython cimport numeric -from libcpp.vector cimport vector -from libcpp.utility cimport pair -from libcpp.string cimport string -from libcpp cimport bool -import os - -""" 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) 2016 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 Inria" -__license__ = "GPL v3" - -cdef extern from "Tangential_complex_interface.h" namespace "Gudhi": - cdef cppclass Tangential_complex_interface "Gudhi::tangential_complex::Tangential_complex_interface": - Tangential_complex_interface(int intrisic_dim, vector[vector[double]] points) - # bool from_file is a workaround for cython to find the correct signature - Tangential_complex_interface(int intrisic_dim, string off_file, bool from_file) - void compute_tangential_complex() except + - vector[double] get_point(unsigned vertex) - unsigned number_of_vertices() - unsigned number_of_simplices() - unsigned number_of_inconsistent_simplices() - unsigned number_of_inconsistent_stars() - void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree) - void fix_inconsistencies_using_perturbation(double max_perturb, double time_limit) - void set_max_squared_edge_length(double max_squared_edge_length) - -# TangentialComplex python interface -cdef class TangentialComplex: - """The class Tangential_complex represents a tangential complex. After the - computation of the complex, an optional post-processing called perturbation - can be run to attempt to remove inconsistencies. - """ - - cdef Tangential_complex_interface * thisptr - - # Fake constructor that does nothing but documenting the constructor - def __init__(self, intrisic_dim, points=None, off_file=''): - """TangentialComplex constructor. - - :param intrisic_dim: Intrinsic dimension of the manifold. - :type intrisic_dim: integer - - :param points: A list of points in d-Dimension. - :type points: list of list of double - - Or - - :param off_file: An OFF file style name. - :type off_file: string - """ - - # The real cython constructor - def __cinit__(self, intrisic_dim, points=None, off_file=''): - if off_file is not '': - if os.path.isfile(off_file): - self.thisptr = new Tangential_complex_interface(intrisic_dim, str.encode(off_file), True) - else: - print("file " + off_file + " not found.") - else: - if points is None: - # Empty tangential construction - points=[] - self.thisptr = new Tangential_complex_interface(intrisic_dim, points) - - - def __dealloc__(self): - if self.thisptr != NULL: - del self.thisptr - - def __is_defined(self): - """Returns true if TangentialComplex pointer is not NULL. - """ - return self.thisptr != NULL - - def compute_tangential_complex(self): - """This function computes the tangential complex. - - Raises: - ValueError: In debug mode, if the computed star dimension is too - low. Try to set a bigger maximal edge length value with - :func:`~gudhi.Tangential_complex.set_max_squared_edge_length` - if this happens. - """ - self.thisptr.compute_tangential_complex() - - def get_point(self, vertex): - """This function returns the point corresponding to a given vertex. - - :param vertex: The vertex. - :type vertex: int. - :returns: The point. - :rtype: list of float - """ - cdef vector[double] point = self.thisptr.get_point(vertex) - return point - - def num_vertices(self): - """ - :returns: The number of vertices. - :rtype: unsigned - """ - return self.thisptr.number_of_vertices() - - def num_simplices(self): - """ - :returns: Total number of simplices in stars (including duplicates that appear in several stars). - :rtype: unsigned - """ - return self.thisptr.number_of_simplices() - - def num_inconsistent_simplices(self): - """ - :returns: The number of inconsistent simplices. - :rtype: unsigned - """ - return self.thisptr.number_of_inconsistent_simplices() - - def num_inconsistent_stars(self): - """ - :returns: The number of stars containing at least one inconsistent simplex. - :rtype: unsigned - """ - return self.thisptr.number_of_inconsistent_stars() - - def create_simplex_tree(self): - """Exports the complex into a simplex tree. - - :returns: A simplex tree created from the complex. - :rtype: SimplexTree - """ - simplex_tree = SimplexTree() - self.thisptr.create_simplex_tree(simplex_tree.thisptr) - return simplex_tree - - def fix_inconsistencies_using_perturbation(self, max_perturb, time_limit=-1.0): - """Attempts to fix inconsistencies by perturbing the point positions. - - :param max_perturb: Maximum length of the translations used by the - perturbation. - :type max_perturb: double - :param time_limit: Time limit in seconds. If -1, no time limit is set. - :type time_limit: double - """ - self.thisptr.fix_inconsistencies_using_perturbation(max_perturb, - time_limit) - - def set_max_squared_edge_length(self, max_squared_edge_length): - """Sets the maximal possible squared edge length for the edges in the - triangulations. - - :param max_squared_edge_length: Maximal possible squared edge length. - :type max_squared_edge_length: double - - If the maximal edge length value is too low - :func:`~gudhi.Tangential_complex.compute_tangential_complex` - will throw an exception in debug mode. - """ - self.thisptr.set_max_squared_edge_length(max_squared_edge_length) diff --git a/src/cython/cython/witness_complex.pyx b/src/cython/cython/witness_complex.pyx deleted file mode 100644 index 91046f57..00000000 --- a/src/cython/cython/witness_complex.pyx +++ /dev/null @@ -1,71 +0,0 @@ -from cython cimport numeric -from libcpp.vector cimport vector -from libcpp.utility cimport pair - -""" 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) 2016 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 Inria" -__license__ = "MIT" - -cdef extern from "Witness_complex_interface.h" namespace "Gudhi": - cdef cppclass Witness_complex_interface "Gudhi::witness_complex::Witness_complex_interface": - Witness_complex_interface(vector[vector[pair[size_t, double]]] nearest_landmark_table) - void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square) - void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square, - unsigned limit_dimension) - -# WitnessComplex python interface -cdef class WitnessComplex: - """Constructs (weak) witness complex for a given table of nearest landmarks - with respect to witnesses. - """ - - cdef Witness_complex_interface * thisptr - - # Fake constructor that does nothing but documenting the constructor - def __init__(self, nearest_landmark_table=None): - """WitnessComplex constructor. - - :param nearest_landmark_table: A list of lists of nearest landmarks and their distances. - `nearest_landmark_table[w][k]==(l,d)` means that l is the k-th nearest landmark to - witness w, and d is the (squared) distance between l and w. - :type nearest_landmark_table: list of list of pair of int and float - """ - - # The real cython constructor - def __cinit__(self, nearest_landmark_table=None): - if nearest_landmark_table is not None: - self.thisptr = new Witness_complex_interface(nearest_landmark_table) - - def __dealloc__(self): - if self.thisptr != NULL: - del self.thisptr - - def __is_defined(self): - """Returns true if WitnessComplex pointer is not NULL. - """ - return self.thisptr != NULL - - def create_simplex_tree(self, max_alpha_square = float('inf'), limit_dimension = -1): - """ - :param max_alpha_square: The maximum relaxation parameter. - Default is set to infinity. - :type max_alpha_square: float - :returns: A simplex tree created from the Delaunay Triangulation. - :rtype: SimplexTree - """ - simplex_tree = SimplexTree() - if limit_dimension is not -1: - self.thisptr.create_simplex_tree(simplex_tree.thisptr, max_alpha_square, limit_dimension) - else: - self.thisptr.create_simplex_tree(simplex_tree.thisptr, max_alpha_square) - return simplex_tree diff --git a/src/cython/gudhi/__init__.py.in b/src/cython/gudhi/__init__.py.in new file mode 100644 index 00000000..60ad7865 --- /dev/null +++ b/src/cython/gudhi/__init__.py.in @@ -0,0 +1,40 @@ +from importlib import import_module + +"""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) 2016 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 Inria" +__license__ = "https://gudhi.inria.fr/licensing/" +__version__ = "@GUDHI_VERSION@" +# This variable is used by doctest to find files +__root_source_dir__ = "@CMAKE_SOURCE_DIR@" +__debug_info__ = @GUDHI_CYTHON_DEBUG_INFO@ + +from sys import exc_info +from importlib import import_module + +__all__ = [@GUDHI_CYTHON_MODULES@] + +__available_modules__ = '' +__missing_modules__ = '' + +# try to import * from gudhi.__module_name__ +for __module_name__ in __all__: + try: + __module__ = import_module('gudhi.' + __module_name__) + try: + __to_import__ = __module__.__all__ + except AttributeError: + __to_import__ = [name for name in __module__.__dict__ if not name.startswith('_')] + globals().update({name: __module__.__dict__[name] for name in __to_import__}) + __available_modules__ += __module_name__ + ";" + except: + __missing_modules__ += __module_name__ + ";" diff --git a/src/cython/gudhi/alpha_complex.pyx b/src/cython/gudhi/alpha_complex.pyx new file mode 100644 index 00000000..85131780 --- /dev/null +++ b/src/cython/gudhi/alpha_complex.pyx @@ -0,0 +1,115 @@ +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 os + +from gudhi.simplex_tree cimport * +from gudhi.simplex_tree import SimplexTree + +""" 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) 2016 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 Inria" +__license__ = "GPL v3" + +cdef extern from "Alpha_complex_interface.h" namespace "Gudhi": + cdef cppclass Alpha_complex_interface "Gudhi::alpha_complex::Alpha_complex_interface": + Alpha_complex_interface(vector[vector[double]] points) + # bool from_file is a workaround for cython to find the correct signature + Alpha_complex_interface(string off_file, bool from_file) + vector[double] get_point(int vertex) + void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square) + +# AlphaComplex python interface +cdef class AlphaComplex: + """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. + + 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. + + """ + + cdef Alpha_complex_interface * thisptr + + # Fake constructor that does nothing but documenting the constructor + def __init__(self, points=None, off_file=''): + """AlphaComplex constructor. + + :param points: A list of points in d-Dimension. + :type points: list of list of double + + Or + + :param off_file: An OFF file style name. + :type off_file: string + """ + + # The real cython constructor + def __cinit__(self, points=None, off_file=''): + if off_file is not '': + if os.path.isfile(off_file): + self.thisptr = new Alpha_complex_interface(str.encode(off_file), True) + else: + print("file " + off_file + " not found.") + else: + if points is None: + # Empty Alpha construction + points=[] + self.thisptr = new Alpha_complex_interface(points) + + + def __dealloc__(self): + if self.thisptr != NULL: + del self.thisptr + + def __is_defined(self): + """Returns true if AlphaComplex pointer is not NULL. + """ + return self.thisptr != NULL + + def get_point(self, vertex): + """This function returns the point corresponding to a given vertex. + + :param vertex: The vertex. + :type vertex: int + :rtype: list of float + :returns: the point. + """ + cdef vector[double] point = self.thisptr.get_point(vertex) + return point + + 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. + :type max_alpha_square: float + :returns: A simplex tree created from the Delaunay Triangulation. + :rtype: SimplexTree + """ + stree = SimplexTree() + cdef intptr_t stree_int_ptr=stree.thisptr + cdef Simplex_tree_interface_full_featured* stree_ptr = stree_int_ptr + self.thisptr.create_simplex_tree(stree_ptr, max_alpha_square) + return stree diff --git a/src/cython/gudhi/bottleneck_distance.pyx b/src/cython/gudhi/bottleneck_distance.pyx new file mode 100644 index 00000000..4b378cbc --- /dev/null +++ b/src/cython/gudhi/bottleneck_distance.pyx @@ -0,0 +1,49 @@ +from cython cimport numeric +from libcpp.vector cimport vector +from libcpp.utility cimport pair +import os + +""" 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) 2016 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 Inria" +__license__ = "GPL v3" + +cdef extern from "Bottleneck_distance_interface.h" namespace "Gudhi::persistence_diagram": + double bottleneck(vector[pair[double, double]], vector[pair[double, double]], double) + double bottleneck(vector[pair[double, double]], vector[pair[double, double]]) + +def bottleneck_distance(diagram_1, diagram_2, e=None): + """This function returns the point corresponding to a given vertex. + + :param diagram_1: The first diagram. + :type diagram_1: vector[pair[double, double]] + :param diagram_2: The second diagram. + :type diagram_2: vector[pair[double, double]] + :param e: If `e` is 0, this uses an expensive algorithm to compute the + exact distance. + If `e` is not 0, it asks for an additive `e`-approximation, and + currently also allows a small multiplicative error (the last 2 or 3 + bits of the mantissa may be wrong). This version of the algorithm takes + advantage of the limited precision of `double` and is usually a lot + faster to compute, whatever the value of `e`. + + Thus, by default, `e` is the smallest positive double. + :type e: float + :rtype: float + :returns: the bottleneck distance. + """ + if e is None: + # Default value is the smallest double value (not 0, 0 is for exact version) + return bottleneck(diagram_1, diagram_2) + else: + # Can be 0 for exact version + return bottleneck(diagram_1, diagram_2, e) diff --git a/src/cython/gudhi/cubical_complex.pyx b/src/cython/gudhi/cubical_complex.pyx new file mode 100644 index 00000000..0dc133d1 --- /dev/null +++ b/src/cython/gudhi/cubical_complex.pyx @@ -0,0 +1,188 @@ +from cython cimport numeric +from libcpp.vector cimport vector +from libcpp.utility cimport pair +from libcpp.string cimport string +from libcpp cimport bool +import os + +from numpy import array as np_array + +""" 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) 2016 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 Inria" +__license__ = "MIT" + +cdef extern from "Cubical_complex_interface.h" namespace "Gudhi": + cdef cppclass Bitmap_cubical_complex_base_interface "Gudhi::Cubical_complex::Cubical_complex_interface<>": + Bitmap_cubical_complex_base_interface(vector[unsigned] dimensions, vector[double] top_dimensional_cells) + Bitmap_cubical_complex_base_interface(string perseus_file) + int num_simplices() + int dimension() + +cdef extern from "Persistent_cohomology_interface.h" namespace "Gudhi": + cdef cppclass Cubical_complex_persistence_interface "Gudhi::Persistent_cohomology_interface>": + Cubical_complex_persistence_interface(Bitmap_cubical_complex_base_interface * st, bool persistence_dim_max) + vector[pair[int, pair[double, double]]] get_persistence(int homology_coeff_field, double min_persistence) + vector[int] betti_numbers() + vector[int] persistent_betti_numbers(double from_value, double to_value) + vector[pair[double,double]] intervals_in_dimension(int dimension) + +# CubicalComplex python interface +cdef class CubicalComplex: + """The CubicalComplex is an example of a structured complex useful in + computational mathematics (specially rigorous numerics) and image + analysis. + """ + cdef Bitmap_cubical_complex_base_interface * thisptr + + cdef Cubical_complex_persistence_interface * pcohptr + + # Fake constructor that does nothing but documenting the constructor + def __init__(self, dimensions=None, top_dimensional_cells=None, + perseus_file=''): + """CubicalComplex constructor from dimensions and + top_dimensional_cells or from a Perseus-style file name. + + :param dimensions: A list of number of top dimensional cells. + :type dimensions: list of int + :param top_dimensional_cells: A list of cells filtration values. + :type top_dimensional_cells: list of double + + Or + + :param perseus_file: A Perseus-style file name. + :type perseus_file: string + """ + + # The real cython constructor + def __cinit__(self, dimensions=None, top_dimensional_cells=None, + perseus_file=''): + if (dimensions is not None) and (top_dimensional_cells is not None) and (perseus_file is ''): + self.thisptr = new Bitmap_cubical_complex_base_interface(dimensions, top_dimensional_cells) + elif (dimensions is None) and (top_dimensional_cells is None) and (perseus_file is not ''): + if os.path.isfile(perseus_file): + self.thisptr = new Bitmap_cubical_complex_base_interface(str.encode(perseus_file)) + else: + print("file " + perseus_file + " not found.") + else: + print("CubicalComplex can be constructed from dimensions and " + "top_dimensional_cells or from a Perseus-style file name.") + + def __dealloc__(self): + if self.thisptr != NULL: + del self.thisptr + if self.pcohptr != NULL: + del self.pcohptr + + def __is_defined(self): + """Returns true if CubicalComplex pointer is not NULL. + """ + return self.thisptr != NULL + + def __is_persistence_defined(self): + """Returns true if Persistence pointer is not NULL. + """ + return self.pcohptr != NULL + + def num_simplices(self): + """This function returns the number of all cubes in the complex. + + :returns: int -- the number of all cubes in the complex. + """ + return self.thisptr.num_simplices() + + def dimension(self): + """This function returns the dimension of the complex. + + :returns: int -- the complex dimension. + """ + return self.thisptr.dimension() + + def persistence(self, homology_coeff_field=11, min_persistence=0): + """This function returns the persistence of the complex. + + :param homology_coeff_field: The homology coefficient field. Must be a + prime number + :type homology_coeff_field: int. + :param min_persistence: The minimum persistence value to take into + account (strictly greater than min_persistence). Default value is + 0.0. + Sets min_persistence to -1.0 to see all values. + :type min_persistence: float. + :returns: list of pairs(dimension, pair(birth, death)) -- the + persistence of the complex. + """ + if self.pcohptr != NULL: + del self.pcohptr + if self.thisptr != NULL: + self.pcohptr = new Cubical_complex_persistence_interface(self.thisptr, True) + cdef vector[pair[int, pair[double, double]]] persistence_result + if self.pcohptr != NULL: + persistence_result = self.pcohptr.get_persistence(homology_coeff_field, min_persistence) + return persistence_result + + def betti_numbers(self): + """This function returns the Betti numbers of the complex. + + :returns: list of int -- The Betti numbers ([B0, B1, ..., Bn]). + + :note: betti_numbers function requires persistence function to be + launched first. + + :note: betti_numbers function always returns [1, 0, 0, ...] as infinity + filtration cubes are not removed from the complex. + """ + cdef vector[int] bn_result + if self.pcohptr != NULL: + bn_result = self.pcohptr.betti_numbers() + return bn_result + + def persistent_betti_numbers(self, from_value, to_value): + """This function returns the persistent Betti numbers of the complex. + + :param from_value: The persistence birth limit to be added in the + numbers (persistent birth <= from_value). + :type from_value: float. + :param to_value: The persistence death limit to be added in the + numbers (persistent death > to_value). + :type to_value: float. + + :returns: list of int -- The persistent Betti numbers ([B0, B1, ..., + Bn]). + + :note: persistent_betti_numbers function requires persistence + function to be launched first. + """ + cdef vector[int] pbn_result + if self.pcohptr != NULL: + pbn_result = self.pcohptr.persistent_betti_numbers(from_value, to_value) + return pbn_result + + def persistence_intervals_in_dimension(self, dimension): + """This function returns the persistence intervals of the complex in a + specific dimension. + + :param dimension: The specific dimension. + :type dimension: int. + :returns: The persistence intervals. + :rtype: numpy array of dimension 2 + + :note: intervals_in_dim function requires persistence function to be + launched first. + """ + cdef vector[pair[double,double]] intervals_result + if self.pcohptr != NULL: + intervals_result = self.pcohptr.intervals_in_dimension(dimension) + else: + print("intervals_in_dim function requires persistence function" + " to be launched first.") + return np_array(intervals_result) diff --git a/src/cython/gudhi/euclidean_strong_witness_complex.pyx b/src/cython/gudhi/euclidean_strong_witness_complex.pyx new file mode 100644 index 00000000..26bd8375 --- /dev/null +++ b/src/cython/gudhi/euclidean_strong_witness_complex.pyx @@ -0,0 +1,85 @@ +from cython cimport numeric +from libcpp.vector cimport vector +from libcpp.utility cimport pair + +""" 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) 2016 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 Inria" +__license__ = "GPL v3" + +cdef extern from "Euclidean_strong_witness_complex_interface.h" namespace "Gudhi": + cdef cppclass Euclidean_strong_witness_complex_interface "Gudhi::witness_complex::Euclidean_strong_witness_complex_interface": + Euclidean_strong_witness_complex_interface(vector[vector[double]] landmarks, vector[vector[double]] witnesses) + void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square) + void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square, + unsigned limit_dimension) + vector[double] get_point(unsigned vertex) + +# EuclideanStrongWitnessComplex python interface +cdef class EuclideanStrongWitnessComplex: + """Constructs strong witness complex for given sets of witnesses and + landmarks in Euclidean space. + """ + + cdef Euclidean_strong_witness_complex_interface * thisptr + + # Fake constructor that does nothing but documenting the constructor + def __init__(self, landmarks=None, witnesses=None): + """WitnessComplex constructor. + + :param landmarks: A list of landmarks (in the point cloud). + :type landmarks: list of list of double + + :param witnesses: The point cloud. + :type witnesses: list of list of double + """ + + # The real cython constructor + def __cinit__(self, landmarks=None, witnesses=None): + if landmarks is not None and witnesses is not None: + self.thisptr = new Euclidean_strong_witness_complex_interface(landmarks, witnesses) + + def __dealloc__(self): + if self.thisptr != NULL: + del self.thisptr + + def __is_defined(self): + """Returns true if WitnessComplex pointer is not NULL. + """ + return self.thisptr != NULL + + def create_simplex_tree(self, max_alpha_square, limit_dimension = -1): + """ + :param max_alpha_square: The maximum alpha square threshold the + simplices shall not exceed. Default is set to infinity. + :type max_alpha_square: float + :returns: A simplex tree created from the Delaunay Triangulation. + :rtype: SimplexTree + """ + simplex_tree = SimplexTree() + if limit_dimension is not -1: + self.thisptr.create_simplex_tree(simplex_tree.thisptr, max_alpha_square, limit_dimension) + else: + self.thisptr.create_simplex_tree(simplex_tree.thisptr, max_alpha_square) + return simplex_tree + + def get_point(self, vertex): + """This function returns the point corresponding to a given vertex. + + :param vertex: The vertex. + :type vertex: int. + :returns: The point. + :rtype: list of float + """ + cdef vector[double] point = self.thisptr.get_point(vertex) + return point + diff --git a/src/cython/gudhi/euclidean_witness_complex.pyx b/src/cython/gudhi/euclidean_witness_complex.pyx new file mode 100644 index 00000000..e687c6f3 --- /dev/null +++ b/src/cython/gudhi/euclidean_witness_complex.pyx @@ -0,0 +1,85 @@ +from cython cimport numeric +from libcpp.vector cimport vector +from libcpp.utility cimport pair + +""" 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) 2016 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 Inria" +__license__ = "GPL v3" + +cdef extern from "Euclidean_witness_complex_interface.h" namespace "Gudhi": + cdef cppclass Euclidean_witness_complex_interface "Gudhi::witness_complex::Euclidean_witness_complex_interface": + Euclidean_witness_complex_interface(vector[vector[double]] landmarks, vector[vector[double]] witnesses) + void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square) + void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square, + unsigned limit_dimension) + vector[double] get_point(unsigned vertex) + +# EuclideanWitnessComplex python interface +cdef class EuclideanWitnessComplex: + """Constructs (weak) witness complex for given sets of witnesses and + landmarks in Euclidean space. + """ + + cdef Euclidean_witness_complex_interface * thisptr + + # Fake constructor that does nothing but documenting the constructor + def __init__(self, landmarks=None, witnesses=None): + """WitnessComplex constructor. + + :param landmarks: A list of landmarks (in the point cloud). + :type landmarks: list of list of double + + :param witnesses: The point cloud. + :type witnesses: list of list of double + """ + + # The real cython constructor + def __cinit__(self, landmarks=None, witnesses=None): + if landmarks is not None and witnesses is not None: + self.thisptr = new Euclidean_witness_complex_interface(landmarks, witnesses) + + def __dealloc__(self): + if self.thisptr != NULL: + del self.thisptr + + def __is_defined(self): + """Returns true if WitnessComplex pointer is not NULL. + """ + return self.thisptr != NULL + + def create_simplex_tree(self, max_alpha_square, limit_dimension = -1): + """ + :param max_alpha_square: The maximum alpha square threshold the + simplices shall not exceed. Default is set to infinity. + :type max_alpha_square: float + :returns: A simplex tree created from the Delaunay Triangulation. + :rtype: SimplexTree + """ + simplex_tree = SimplexTree() + if limit_dimension is not -1: + self.thisptr.create_simplex_tree(simplex_tree.thisptr, max_alpha_square, limit_dimension) + else: + self.thisptr.create_simplex_tree(simplex_tree.thisptr, max_alpha_square) + return simplex_tree + + def get_point(self, vertex): + """This function returns the point corresponding to a given vertex. + + :param vertex: The vertex. + :type vertex: int. + :returns: The point. + :rtype: list of float + """ + cdef vector[double] point = self.thisptr.get_point(vertex) + return point + diff --git a/src/cython/gudhi/nerve_gic.pyx b/src/cython/gudhi/nerve_gic.pyx new file mode 100644 index 00000000..3c8f1200 --- /dev/null +++ b/src/cython/gudhi/nerve_gic.pyx @@ -0,0 +1,407 @@ +from cython cimport numeric +from libcpp.vector cimport vector +from libcpp.utility cimport pair +from libcpp.string cimport string +from libcpp cimport bool +import os + +""" 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) 2018 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2018 Inria" +__license__ = "GPL v3" + +cdef extern from "Nerve_gic_interface.h" namespace "Gudhi": + cdef cppclass Nerve_gic_interface "Gudhi::cover_complex::Nerve_gic_interface": + Nerve_gic_interface() + double compute_confidence_level_from_distance(double distance) + double compute_distance_from_confidence_level(double alpha) + void compute_distribution(int N) + double compute_p_value() + vector[pair[double, double]] compute_PD() + void find_simplices() + void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree) + bool read_point_cloud(string off_file_name) + double set_automatic_resolution() + void set_color_from_coordinate(int k) + void set_color_from_file(string color_file_name) + void set_color_from_range(vector[double] color) + void set_cover_from_file(string cover_file_name) + void set_cover_from_function() + void set_cover_from_Euclidean_Voronoi(int m) + void set_function_from_coordinate(int k) + void set_function_from_file(string func_file_name) + void set_function_from_range(vector[double] function) + void set_gain(double g) + double set_graph_from_automatic_euclidean_rips(int N) + void set_graph_from_file(string graph_file_name) + void set_graph_from_OFF() + void set_graph_from_euclidean_rips(double threshold) + void set_mask(int nodemask) + void set_resolution_with_interval_length(double resolution) + void set_resolution_with_interval_number(int resolution) + void set_subsampling(double constant, double power) + void set_type(string type) + void set_verbose(bool verbose) + vector[int] subpopulation(int c) + void write_info() + void plot_DOT() + void plot_OFF() + void set_point_cloud_from_range(vector[vector[double]] cloud) + void set_distances_from_range(vector[vector[double]] distance_matrix) + +# CoverComplex python interface +cdef class CoverComplex: + """Cover complex data structure. + + The data structure is a simplicial complex, representing a Graph Induced + simplicial Complex (GIC) or a Nerve, and whose simplices are computed with + a cover C of a point cloud P, which often comes from the preimages of + intervals covering the image of a function f defined on P. These intervals + are parameterized by their resolution (either their length or their number) + and their gain (percentage of overlap). To compute a GIC, one also needs a + graph G built on top of P, whose cliques with vertices belonging to + different elements of C correspond to the simplices of the GIC. + """ + + cdef Nerve_gic_interface * thisptr + + # Fake constructor that does nothing but documenting the constructor + def __init__(self): + """CoverComplex constructor. + """ + + # The real cython constructor + def __cinit__(self): + self.thisptr = new Nerve_gic_interface() + + def __dealloc__(self): + if self.thisptr != NULL: + del self.thisptr + + def __is_defined(self): + """Returns true if CoverComplex pointer is not NULL. + """ + return self.thisptr != NULL + + def set_point_cloud_from_range(self, cloud): + """ Reads and stores the input point cloud from a vector stored in memory. + + :param cloud: Input vector containing the point cloud. + :type cloud: vector[vector[double]] + """ + return self.thisptr.set_point_cloud_from_range(cloud) + + def set_distances_from_range(self, distance_matrix): + """ Reads and stores the input distance matrix from a vector stored in memory. + + :param distance_matrix: Input vector containing the distance matrix. + :type distance_matrix: vector[vector[double]] + """ + return self.thisptr.set_distances_from_range(distance_matrix) + + def compute_confidence_level_from_distance(self, distance): + """Computes the confidence level of a specific bottleneck distance + threshold. + + :param distance: Bottleneck distance. + :type distance: double + :rtype: double + :returns: Confidence level. + """ + return self.thisptr.compute_confidence_level_from_distance(distance) + + def compute_distance_from_confidence_level(self, alpha): + """Computes the bottleneck distance threshold corresponding to a + specific confidence level. + + :param alpha: Confidence level. + :type alpha: double + :rtype: double + :returns: Bottleneck distance. + """ + return self.thisptr.compute_distance_from_confidence_level(alpha) + + def compute_distribution(self, N=100): + """Computes bootstrapped distances distribution. + + :param N: Loop number (default value is 100). + :type alpha: int + """ + self.thisptr.compute_distribution(N) + + def compute_p_value(self): + """Computes the p-value, i.e. the opposite of the confidence level of + the largest bottleneck distance preserving the points in the + persistence diagram of the output simplicial complex. + + :rtype: double + :returns: p-value. + """ + return self.thisptr.compute_p_value() + + def compute_PD(self): + """Computes the extended persistence diagram of the complex. + """ + return self.thisptr.compute_PD() + + def create_simplex_tree(self): + """ + :returns: A simplex tree created from the Cover complex. + :rtype: SimplexTree + """ + simplex_tree = SimplexTree() + self.thisptr.create_simplex_tree(simplex_tree.thisptr) + return simplex_tree + + def find_simplices(self): + """Computes the simplices of the simplicial complex. + """ + self.thisptr.find_simplices() + + def read_point_cloud(self, off_file): + """Reads and stores the input point cloud from .(n)OFF file. + + :param off_file: Name of the input .OFF or .nOFF file. + :type off_file: string + :rtype: bool + :returns: Read file status. + """ + if os.path.isfile(off_file): + return self.thisptr.read_point_cloud(str.encode(off_file)) + else: + print("file " + off_file + " not found.") + return False + + def set_automatic_resolution(self): + """Computes the optimal length of intervals (i.e. the smallest interval + length avoiding discretization artifacts—see :cite:`Carriere17c`) for a + functional cover. + + :rtype: double + :returns: reso interval length used to compute the cover. + """ + return self.thisptr.set_automatic_resolution() + + def set_color_from_coordinate(self, k=0): + """Computes the function used to color the nodes of the simplicial + complex from the k-th coordinate. + + :param k: Coordinate to use (start at 0). Default value is 0. + :type k: int + """ + return self.thisptr.set_color_from_coordinate(k) + + def set_color_from_file(self, color_file_name): + """Computes the function used to color the nodes of the simplicial + complex from a file containing the function values. + + :param color_file_name: Name of the input color file. + :type color_file_name: string + """ + if os.path.isfile(color_file_name): + self.thisptr.set_color_from_file(str.encode(color_file_name)) + else: + print("file " + color_file_name + " not found.") + + def set_color_from_range(self, color): + """Computes the function used to color the nodes of the simplicial + complex from a vector stored in memory. + + :param color: Input vector of values. + :type color: vector[double] + """ + self.thisptr.set_color_from_range(color) + + def set_cover_from_file(self, cover_file_name): + """Creates the cover C from a file containing the cover elements of + each point (the order has to be the same as in the input file!). + + :param cover_file_name: Name of the input cover file. + :type cover_file_name: string + """ + if os.path.isfile(cover_file_name): + self.thisptr.set_cover_from_file(str.encode(cover_file_name)) + else: + print("file " + cover_file_name + " not found.") + + def set_cover_from_function(self): + """Creates a cover C from the preimages of the function f. + """ + self.thisptr.set_cover_from_function() + + def set_cover_from_Voronoi(self, m=100): + """Creates the cover C from the Voronoï cells of a subsampling of the + point cloud. + + :param m: Number of points in the subsample. Default value is 100. + :type m: int + """ + self.thisptr.set_cover_from_Euclidean_Voronoi(m) + + def set_function_from_coordinate(self, k): + """Creates the function f from the k-th coordinate of the point cloud. + + :param k: Coordinate to use (start at 0). + :type k: int + """ + self.thisptr.set_function_from_coordinate(k) + + def set_function_from_file(self, func_file_name): + """Creates the function f from a file containing the function values. + + :param func_file_name: Name of the input function file. + :type func_file_name: string + """ + if os.path.isfile(func_file_name): + self.thisptr.set_function_from_file(str.encode(func_file_name)) + else: + print("file " + func_file_name + " not found.") + + def set_function_from_range(self, function): + """Creates the function f from a vector stored in memory. + + :param function: Input vector of values. + :type function: vector[double] + """ + self.thisptr.set_function_from_range(function) + + def set_gain(self, g = 0.3): + """Sets a gain from a value stored in memory. + + :param g: Gain (default value is 0.3). + :type g: double + """ + self.thisptr.set_gain(g) + + def set_graph_from_automatic_rips(self, N=100): + """Creates a graph G from a Rips complex whose threshold value is + automatically tuned with subsampling—see. + + :param N: Number of subsampling iteration (the default reasonable value + is 100, but there is no guarantee on how to choose it). + :type N: int + :rtype: double + :returns: Delta threshold used for computing the Rips complex. + """ + return self.thisptr.set_graph_from_automatic_euclidean_rips(N) + + def set_graph_from_file(self, graph_file_name): + """Creates a graph G from a file containing the edges. + + :param graph_file_name: Name of the input graph file. The graph file + contains one edge per line, each edge being represented by the IDs of + its two nodes. + :type graph_file_name: string + """ + if os.path.isfile(graph_file_name): + self.thisptr.set_graph_from_file(str.encode(graph_file_name)) + else: + print("file " + graph_file_name + " not found.") + + def set_graph_from_OFF(self): + """Creates a graph G from the triangulation given by the input OFF + file. + """ + self.thisptr.set_graph_from_OFF() + + def set_graph_from_rips(self, threshold): + """Creates a graph G from a Rips complex. + + :param threshold: Threshold value for the Rips complex. + :type threshold: double + """ + self.thisptr.set_graph_from_euclidean_rips(threshold) + + def set_mask(self, nodemask): + """Sets the mask, which is a threshold integer such that nodes in the + complex that contain a number of data points which is less than or + equal to this threshold are not displayed. + + :param nodemask: Threshold. + :type nodemask: int + """ + self.thisptr.set_mask(nodemask) + + def set_resolution_with_interval_length(self, resolution): + """Sets a length of intervals from a value stored in memory. + + :param resolution: Length of intervals. + :type resolution: double + """ + self.thisptr.set_resolution_with_interval_length(resolution) + + def set_resolution_with_interval_number(self, resolution): + """Sets a number of intervals from a value stored in memory. + + :param resolution: Number of intervals. + :type resolution: int + """ + self.thisptr.set_resolution_with_interval_number(resolution) + + def set_subsampling(self, constant, power): + """Sets the constants used to subsample the data set. These constants + are explained in :cite:`Carriere17c`. + + :param constant: Constant. + :type constant: double + :param power: Power. + :type resolution: double + """ + self.thisptr.set_subsampling(constant, power) + + def set_type(self, type): + """Specifies whether the type of the output simplicial complex. + + :param type: either "GIC" or "Nerve". + :type type: string + """ + self.thisptr.set_type(str.encode(type)) + + def set_verbose(self, verbose): + """Specifies whether the program should display information or not. + + :param verbose: true = display info, false = do not display info. + :type verbose: boolean + """ + self.thisptr.set_verbose(verbose) + + def subpopulation(self, c): + """Returns the data subset corresponding to a specific node of the + created complex. + + :param c: ID of the node. + :type c: int + :rtype: vector[int] + :returns: Vector of IDs of data points. + """ + return self.thisptr.subpopulation(c) + + def write_info(self): + """Creates a .txt file called SC.txt describing the 1-skeleton, which can + then be plotted with e.g. KeplerMapper. + """ + return self.thisptr.write_info() + + def plot_dot(self): + """Creates a .dot file called SC.dot for neato (part of the graphviz + package) once the simplicial complex is computed to get a visualization of + its 1-skeleton in a .pdf file. + """ + return self.thisptr.plot_DOT() + + def plot_off(self): + """Creates a .off file called SC.off for 3D visualization, which contains + the 2-skeleton of the GIC. This function assumes that the cover has been + computed with Voronoi. If data points are in 1D or 2D, the remaining + coordinates of the points embedded in 3D are set to 0. + """ + return self.thisptr.plot_OFF() diff --git a/src/cython/gudhi/off_reader.pyx b/src/cython/gudhi/off_reader.pyx new file mode 100644 index 00000000..9efd97ff --- /dev/null +++ b/src/cython/gudhi/off_reader.pyx @@ -0,0 +1,38 @@ +from cython cimport numeric +from libcpp.vector cimport vector +from libcpp.string cimport string +import os + +""" 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) 2016 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 Inria" +__license__ = "MIT" + +cdef extern from "Off_reader_interface.h" namespace "Gudhi": + vector[vector[double]] read_points_from_OFF_file(string off_file) + +def read_off(off_file=''): + """Read points from OFF file. + + :param off_file: An OFF file style name. + :type off_file: string + + :returns: The point set. + :rtype: vector[vector[double]] + """ + if off_file is not '': + if os.path.isfile(off_file): + return read_points_from_OFF_file(str.encode(off_file)) + else: + print("file " + off_file + " not found.") + return [] + diff --git a/src/cython/gudhi/periodic_cubical_complex.pyx b/src/cython/gudhi/periodic_cubical_complex.pyx new file mode 100644 index 00000000..724fadd4 --- /dev/null +++ b/src/cython/gudhi/periodic_cubical_complex.pyx @@ -0,0 +1,190 @@ +from cython cimport numeric +from libcpp.vector cimport vector +from libcpp.utility cimport pair +from libcpp.string cimport string +from libcpp cimport bool +import os + +from numpy import array as np_array + +""" 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) 2016 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 Inria" +__license__ = "MIT" + +cdef extern from "Cubical_complex_interface.h" namespace "Gudhi": + cdef cppclass Periodic_cubical_complex_base_interface "Gudhi::Cubical_complex::Cubical_complex_interface>": + Periodic_cubical_complex_base_interface(vector[unsigned] dimensions, vector[double] top_dimensional_cells, vector[bool] periodic_dimensions) + Periodic_cubical_complex_base_interface(string perseus_file) + int num_simplices() + int dimension() + +cdef extern from "Persistent_cohomology_interface.h" namespace "Gudhi": + cdef cppclass Periodic_cubical_complex_persistence_interface "Gudhi::Persistent_cohomology_interface>>": + Periodic_cubical_complex_persistence_interface(Periodic_cubical_complex_base_interface * st, bool persistence_dim_max) + vector[pair[int, pair[double, double]]] get_persistence(int homology_coeff_field, double min_persistence) + vector[int] betti_numbers() + vector[int] persistent_betti_numbers(double from_value, double to_value) + vector[pair[double,double]] intervals_in_dimension(int dimension) + +# PeriodicCubicalComplex python interface +cdef class PeriodicCubicalComplex: + """The PeriodicCubicalComplex is an example of a structured complex useful + in computational mathematics (specially rigorous numerics) and image + analysis. + """ + cdef Periodic_cubical_complex_base_interface * thisptr + + cdef Periodic_cubical_complex_persistence_interface * pcohptr + + # Fake constructor that does nothing but documenting the constructor + def __init__(self, dimensions=None, top_dimensional_cells=None, + periodic_dimensions=None, perseus_file=''): + """PeriodicCubicalComplex constructor from dimensions and + top_dimensional_cells or from a Perseus-style file name. + + :param dimensions: A list of number of top dimensional cells. + :type dimensions: list of int + :param top_dimensional_cells: A list of cells filtration values. + :type top_dimensional_cells: list of double + :param periodic_dimensions: A list of top dimensional cells periodicity value. + :type periodic_dimensions: list of boolean + + Or + + :param perseus_file: A Perseus-style file name. + :type perseus_file: string + """ + + # The real cython constructor + def __cinit__(self, dimensions=None, top_dimensional_cells=None, + periodic_dimensions=None, perseus_file=''): + if (dimensions is not None) and (top_dimensional_cells is not None) and (periodic_dimensions is not None) and (perseus_file is ''): + self.thisptr = new Periodic_cubical_complex_base_interface(dimensions, top_dimensional_cells, periodic_dimensions) + elif (dimensions is None) and (top_dimensional_cells is None) and (periodic_dimensions is None) and (perseus_file is not ''): + if os.path.isfile(perseus_file): + self.thisptr = new Periodic_cubical_complex_base_interface(str.encode(perseus_file)) + else: + print("file " + perseus_file + " not found.") + else: + print("CubicalComplex can be constructed from dimensions and " + "top_dimensional_cells or from a Perseus-style file name.") + + def __dealloc__(self): + if self.thisptr != NULL: + del self.thisptr + if self.pcohptr != NULL: + del self.pcohptr + + def __is_defined(self): + """Returns true if PeriodicCubicalComplex pointer is not NULL. + """ + return self.thisptr != NULL + + def __is_persistence_defined(self): + """Returns true if Persistence pointer is not NULL. + """ + return self.pcohptr != NULL + + def num_simplices(self): + """This function returns the number of all cubes in the complex. + + :returns: int -- the number of all cubes in the complex. + """ + return self.thisptr.num_simplices() + + def dimension(self): + """This function returns the dimension of the complex. + + :returns: int -- the complex dimension. + """ + return self.thisptr.dimension() + + def persistence(self, homology_coeff_field=11, min_persistence=0): + """This function returns the persistence of the complex. + + :param homology_coeff_field: The homology coefficient field. Must be a + prime number + :type homology_coeff_field: int. + :param min_persistence: The minimum persistence value to take into + account (strictly greater than min_persistence). Default value is + 0.0. + Sets min_persistence to -1.0 to see all values. + :type min_persistence: float. + :returns: list of pairs(dimension, pair(birth, death)) -- the + persistence of the complex. + """ + if self.pcohptr != NULL: + del self.pcohptr + if self.thisptr != NULL: + self.pcohptr = new Periodic_cubical_complex_persistence_interface(self.thisptr, True) + cdef vector[pair[int, pair[double, double]]] persistence_result + if self.pcohptr != NULL: + persistence_result = self.pcohptr.get_persistence(homology_coeff_field, min_persistence) + return persistence_result + + def betti_numbers(self): + """This function returns the Betti numbers of the complex. + + :returns: list of int -- The Betti numbers ([B0, B1, ..., Bn]). + + :note: betti_numbers function requires persistence function to be + launched first. + + :note: betti_numbers function always returns [1, 0, 0, ...] as infinity + filtration cubes are not removed from the complex. + """ + cdef vector[int] bn_result + if self.pcohptr != NULL: + bn_result = self.pcohptr.betti_numbers() + return bn_result + + def persistent_betti_numbers(self, from_value, to_value): + """This function returns the persistent Betti numbers of the complex. + + :param from_value: The persistence birth limit to be added in the + numbers (persistent birth <= from_value). + :type from_value: float. + :param to_value: The persistence death limit to be added in the + numbers (persistent death > to_value). + :type to_value: float. + + :returns: list of int -- The persistent Betti numbers ([B0, B1, ..., + Bn]). + + :note: persistent_betti_numbers function requires persistence + function to be launched first. + """ + cdef vector[int] pbn_result + if self.pcohptr != NULL: + pbn_result = self.pcohptr.persistent_betti_numbers(from_value, to_value) + return pbn_result + + def persistence_intervals_in_dimension(self, dimension): + """This function returns the persistence intervals of the complex in a + specific dimension. + + :param dimension: The specific dimension. + :type dimension: int. + :returns: The persistence intervals. + :rtype: numpy array of dimension 2 + + :note: intervals_in_dim function requires persistence function to be + launched first. + """ + cdef vector[pair[double,double]] intervals_result + if self.pcohptr != NULL: + intervals_result = self.pcohptr.intervals_in_dimension(dimension) + else: + print("intervals_in_dim function requires persistence function" + " to be launched first.") + return np_array(intervals_result) diff --git a/src/cython/gudhi/persistence_graphical_tools.py b/src/cython/gudhi/persistence_graphical_tools.py new file mode 100644 index 00000000..34803222 --- /dev/null +++ b/src/cython/gudhi/persistence_graphical_tools.py @@ -0,0 +1,420 @@ +from os import path +from math import isfinite +import numpy as np + +""" 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, Bertrand Michel + + Copyright (C) 2016 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau, Bertrand Michel" +__copyright__ = "Copyright (C) 2016 Inria" +__license__ = "MIT" + + +def __min_birth_max_death(persistence, band=0.0): + """This function returns (min_birth, max_death) from the persistence. + + :param persistence: The persistence to plot. + :type persistence: list of tuples(dimension, tuple(birth, death)). + :param band: band + :type band: float. + :returns: (float, float) -- (min_birth, max_death). + """ + # Look for minimum birth date and maximum death date for plot optimisation + max_death = 0 + min_birth = persistence[0][1][0] + for interval in reversed(persistence): + if float(interval[1][1]) != float("inf"): + if float(interval[1][1]) > max_death: + max_death = float(interval[1][1]) + if float(interval[1][0]) > max_death: + max_death = float(interval[1][0]) + if float(interval[1][0]) < min_birth: + min_birth = float(interval[1][0]) + if band > 0.0: + max_death += band + return (min_birth, max_death) + + +""" +Only 13 colors for the palette +""" +palette = [ + "#ff0000", + "#00ff00", + "#0000ff", + "#00ffff", + "#ff00ff", + "#ffff00", + "#000000", + "#880000", + "#008800", + "#000088", + "#888800", + "#880088", + "#008888", +] + + +def plot_persistence_barcode( + persistence=[], + persistence_file="", + alpha=0.6, + max_intervals=1000, + max_barcodes=1000, + inf_delta=0.1, + legend=False, +): + """This function plots the persistence bar code from persistence values list + or from a :doc:`persistence file `. + + :param persistence: Persistence intervals values list grouped by dimension. + :type persistence: list of tuples(dimension, tuple(birth, death)). + :param persistence_file: A :doc:`persistence file ` style name + (reset persistence if both are set). + :type persistence_file: string + :param alpha: barcode transparency value (0.0 transparent through 1.0 + opaque - default is 0.6). + :type alpha: float. + :param max_intervals: maximal number of intervals to display. + Selected intervals are those with the longest life time. Set it + to 0 to see all. Default value is 1000. + :type max_intervals: int. + :param inf_delta: Infinity is placed at :code:`((max_death - min_birth) x + inf_delta)` above :code:`max_death` value. A reasonable value is + between 0.05 and 0.5 - default is 0.1. + :type inf_delta: float. + :param legend: Display the dimension color legend (default is False). + :type legend: boolean. + :returns: A matplotlib object containing horizontal bar plot of persistence + (launch `show()` method on it to display it). + """ + try: + import matplotlib.pyplot as plt + import matplotlib.patches as mpatches + + if persistence_file is not "": + if path.isfile(persistence_file): + # Reset persistence + persistence = [] + diag = read_persistence_intervals_grouped_by_dimension( + persistence_file=persistence_file + ) + for key in diag.keys(): + for persistence_interval in diag[key]: + persistence.append((key, persistence_interval)) + else: + print("file " + persistence_file + " not found.") + return None + + if max_barcodes is not 1000: + print("Deprecated parameter. It has been replaced by max_intervals") + max_intervals = max_barcodes + + if max_intervals > 0 and max_intervals < len(persistence): + # Sort by life time, then takes only the max_intervals elements + persistence = sorted( + persistence, + key=lambda life_time: life_time[1][1] - life_time[1][0], + reverse=True, + )[:max_intervals] + + persistence = sorted(persistence, key=lambda birth: birth[1][0]) + + (min_birth, max_death) = __min_birth_max_death(persistence) + ind = 0 + delta = (max_death - min_birth) * inf_delta + # Replace infinity values with max_death + delta for bar code to be more + # readable + infinity = max_death + delta + axis_start = min_birth - delta + # Draw horizontal bars in loop + for interval in reversed(persistence): + if float(interval[1][1]) != float("inf"): + # Finite death case + plt.barh( + ind, + (interval[1][1] - interval[1][0]), + height=0.8, + left=interval[1][0], + alpha=alpha, + color=palette[interval[0]], + linewidth=0, + ) + else: + # Infinite death case for diagram to be nicer + plt.barh( + ind, + (infinity - interval[1][0]), + height=0.8, + left=interval[1][0], + alpha=alpha, + color=palette[interval[0]], + linewidth=0, + ) + ind = ind + 1 + + if legend: + dimensions = list(set(item[0] for item in persistence)) + plt.legend( + handles=[ + mpatches.Patch(color=palette[dim], label=str(dim)) + for dim in dimensions + ], + loc="lower right", + ) + plt.title("Persistence barcode") + # Ends plot on infinity value and starts a little bit before min_birth + plt.axis([axis_start, infinity, 0, ind]) + return plt + + except ImportError: + print("This function is not available, you may be missing matplotlib.") + + +def plot_persistence_diagram( + persistence=[], + persistence_file="", + alpha=0.6, + band=0.0, + max_intervals=1000, + max_plots=1000, + inf_delta=0.1, + legend=False, +): + """This function plots the persistence diagram from persistence values + list or from a :doc:`persistence file `. + + :param persistence: Persistence intervals values list grouped by dimension. + :type persistence: list of tuples(dimension, tuple(birth, death)). + :param persistence_file: A :doc:`persistence file ` style name + (reset persistence if both are set). + :type persistence_file: string + :param alpha: plot transparency value (0.0 transparent through 1.0 + opaque - default is 0.6). + :type alpha: float. + :param band: band (not displayed if :math:`\leq` 0. - default is 0.) + :type band: float. + :param max_intervals: maximal number of intervals to display. + Selected intervals are those with the longest life time. Set it + to 0 to see all. Default value is 1000. + :type max_intervals: int. + :param inf_delta: Infinity is placed at :code:`((max_death - min_birth) x + inf_delta)` above :code:`max_death` value. A reasonable value is + between 0.05 and 0.5 - default is 0.1. + :type inf_delta: float. + :param legend: Display the dimension color legend (default is False). + :type legend: boolean. + :returns: A matplotlib object containing diagram plot of persistence + (launch `show()` method on it to display it). + """ + try: + import matplotlib.pyplot as plt + import matplotlib.patches as mpatches + + if persistence_file is not "": + if path.isfile(persistence_file): + # Reset persistence + persistence = [] + diag = read_persistence_intervals_grouped_by_dimension( + persistence_file=persistence_file + ) + for key in diag.keys(): + for persistence_interval in diag[key]: + persistence.append((key, persistence_interval)) + else: + print("file " + persistence_file + " not found.") + return None + + if max_plots is not 1000: + print("Deprecated parameter. It has been replaced by max_intervals") + max_intervals = max_plots + + if max_intervals > 0 and max_intervals < len(persistence): + # Sort by life time, then takes only the max_intervals elements + persistence = sorted( + persistence, + key=lambda life_time: life_time[1][1] - life_time[1][0], + reverse=True, + )[:max_intervals] + + (min_birth, max_death) = __min_birth_max_death(persistence, band) + delta = (max_death - min_birth) * inf_delta + # Replace infinity values with max_death + delta for diagram to be more + # readable + infinity = max_death + delta + axis_start = min_birth - delta + + # line display of equation : birth = death + x = np.linspace(axis_start, infinity, 1000) + # infinity line and text + plt.plot(x, x, color="k", linewidth=1.0) + plt.plot(x, [infinity] * len(x), linewidth=1.0, color="k", alpha=alpha) + plt.text(axis_start, infinity, r"$\infty$", color="k", alpha=alpha) + # bootstrap band + if band > 0.0: + plt.fill_between(x, x, x + band, alpha=alpha, facecolor="red") + + # Draw points in loop + for interval in reversed(persistence): + if float(interval[1][1]) != float("inf"): + # Finite death case + plt.scatter( + interval[1][0], + interval[1][1], + alpha=alpha, + color=palette[interval[0]], + ) + else: + # Infinite death case for diagram to be nicer + plt.scatter( + interval[1][0], infinity, alpha=alpha, color=palette[interval[0]] + ) + + if legend: + dimensions = list(set(item[0] for item in persistence)) + plt.legend( + handles=[ + mpatches.Patch(color=palette[dim], label=str(dim)) + for dim in dimensions + ] + ) + + plt.title("Persistence diagram") + plt.xlabel("Birth") + plt.ylabel("Death") + # Ends plot on infinity value and starts a little bit before min_birth + plt.axis([axis_start, infinity, axis_start, infinity + delta]) + return plt + + except ImportError: + print("This function is not available, you may be missing matplotlib.") + + +def plot_persistence_density( + persistence=[], + persistence_file="", + nbins=300, + bw_method=None, + max_intervals=1000, + dimension=None, + cmap=None, + legend=False, +): + """This function plots the persistence density from persistence + values list or from a :doc:`persistence file `. Be + aware that this function does not distinguish the dimension, it is + up to you to select the required one. This function also does not handle + degenerate data set (scipy correlation matrix inversion can fail). + + :param persistence: Persistence intervals values list grouped by dimension. + :type persistence: list of tuples(dimension, tuple(birth, death)). + :param persistence_file: A :doc:`persistence file ` + style name (reset persistence if both are set). + :type persistence_file: string + :param nbins: Evaluate a gaussian kde on a regular grid of nbins x + nbins over data extents (default is 300) + :type nbins: int. + :param bw_method: The method used to calculate the estimator + bandwidth. This can be 'scott', 'silverman', a scalar constant + or a callable. If a scalar, this will be used directly as + kde.factor. If a callable, it should take a gaussian_kde + instance as only parameter and return a scalar. If None + (default), 'scott' is used. See + `scipy.stats.gaussian_kde documentation + `_ + for more details. + :type bw_method: str, scalar or callable, optional. + :param max_intervals: maximal number of points used in the density + estimation. + Selected intervals are those with the longest life time. Set it + to 0 to see all. Default value is 1000. + :type max_intervals: int. + :param dimension: the dimension to be selected in the intervals + (default is None to mix all dimensions). + :type dimension: int. + :param cmap: A matplotlib colormap (default is + matplotlib.pyplot.cm.hot_r). + :type cmap: cf. matplotlib colormap. + :param legend: Display the color bar values (default is False). + :type legend: boolean. + :returns: A matplotlib object containing diagram plot of persistence + (launch `show()` method on it to display it). + """ + try: + import matplotlib.pyplot as plt + from scipy.stats import kde + + if persistence_file is not "": + if dimension is None: + # All dimension case + dimension = -1 + if path.isfile(persistence_file): + persistence_dim = read_persistence_intervals_in_dimension( + persistence_file=persistence_file, only_this_dim=dimension + ) + print(persistence_dim) + else: + print("file " + persistence_file + " not found.") + return None + + if len(persistence) > 0: + persistence_dim = np.array( + [ + (dim_interval[1][0], dim_interval[1][1]) + for dim_interval in persistence + if (dim_interval[0] == dimension) or (dimension is None) + ] + ) + + persistence_dim = persistence_dim[np.isfinite(persistence_dim[:, 1])] + if max_intervals > 0 and max_intervals < len(persistence_dim): + # Sort by life time, then takes only the max_intervals elements + persistence_dim = np.array( + sorted( + persistence_dim, + key=lambda life_time: life_time[1] - life_time[0], + reverse=True, + )[:max_intervals] + ) + + # Set as numpy array birth and death (remove undefined values - inf and NaN) + birth = persistence_dim[:, 0] + death = persistence_dim[:, 1] + + # line display of equation : birth = death + x = np.linspace(death.min(), birth.max(), 1000) + plt.plot(x, x, color="k", linewidth=1.0) + + # Evaluate a gaussian kde on a regular grid of nbins x nbins over data extents + k = kde.gaussian_kde([birth, death], bw_method=bw_method) + xi, yi = np.mgrid[ + birth.min() : birth.max() : nbins * 1j, + death.min() : death.max() : nbins * 1j, + ] + zi = k(np.vstack([xi.flatten(), yi.flatten()])) + + # default cmap value cannot be done at argument definition level as matplotlib is not yet defined. + if cmap is None: + cmap = plt.cm.hot_r + # Make the plot + plt.pcolormesh(xi, yi, zi.reshape(xi.shape), cmap=cmap) + + if legend: + plt.colorbar() + + plt.title("Persistence density") + plt.xlabel("Birth") + plt.ylabel("Death") + return plt + + except ImportError: + print( + "This function is not available, you may be missing matplotlib and/or scipy." + ) diff --git a/src/cython/gudhi/reader_utils.pyx b/src/cython/gudhi/reader_utils.pyx new file mode 100644 index 00000000..147fae71 --- /dev/null +++ b/src/cython/gudhi/reader_utils.pyx @@ -0,0 +1,87 @@ +from cython cimport numeric +from libcpp.vector cimport vector +from libcpp.string cimport string +from libcpp.map cimport map +from libcpp.pair cimport pair + +from os import path +from numpy import array as np_array + +""" 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) 2017 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2017 Inria" +__license__ = "MIT" + +cdef extern from "Reader_utils_interface.h" namespace "Gudhi": + vector[vector[double]] read_matrix_from_csv_file(string off_file, char separator) + map[int, vector[pair[double, double]]] read_pers_intervals_grouped_by_dimension(string filename) + vector[pair[double, double]] read_pers_intervals_in_dimension(string filename, int only_this_dim) + +def read_lower_triangular_matrix_from_csv_file(csv_file='', separator=';'): + """Read lower triangular matrix from a CSV style file. + + :param csv_file: A CSV file style name. + :type csv_file: string + :param separator: The value separator in the CSV file. Default value is ';' + :type separator: char + + :returns: The lower triangular matrix. + :rtype: vector[vector[double]] + """ + if csv_file is not '': + if path.isfile(csv_file): + return read_matrix_from_csv_file(str.encode(csv_file), ord(separator[0])) + print("file " + csv_file + " not set or not found.") + return [] + +def read_persistence_intervals_grouped_by_dimension(persistence_file=''): + """Reads a file containing persistence intervals. + Each line might contain 2, 3 or 4 values: [[field] dimension] birth death + The return value is an `map[dim, vector[pair[birth, death]]]` + where `dim` is an `int`, `birth` a `double`, and `death` a `double`. + Note: the function does not check that birth <= death. + + :param persistence_file: A persistence file style name. + :type persistence_file: string + + :returns: The persistence pairs grouped by dimension. + :rtype: map[int, vector[pair[double, double]]] + """ + if persistence_file is not '': + if path.isfile(persistence_file): + return read_pers_intervals_grouped_by_dimension(str.encode(persistence_file)) + print("file " + persistence_file + " not set or not found.") + return [] + +def read_persistence_intervals_in_dimension(persistence_file='', only_this_dim=-1): + """Reads a file containing persistence intervals. + Each line of persistence_file might contain 2, 3 or 4 values: + [[field] dimension] birth death + Note: the function does not check that birth <= death. + + :param persistence_file: A persistence file style name. + :type persistence_file: string + :param only_this_dim: The specific dimension. Default value is -1. + If `only_this_dim` = -1, dimension is ignored and all lines are returned. + If `only_this_dim` is >= 0, only the lines where dimension = + `only_this_dim` (or where dimension is not specified) are returned. + :type only_this_dim: int. + + :returns: The persistence intervals. + :rtype: numpy array of dimension 2 + """ + if persistence_file is not '': + if path.isfile(persistence_file): + return np_array(read_pers_intervals_in_dimension(str.encode( + persistence_file), only_this_dim)) + print("file " + persistence_file + " not set or not found.") + return [] diff --git a/src/cython/gudhi/rips_complex.pyx b/src/cython/gudhi/rips_complex.pyx new file mode 100644 index 00000000..1a6c8571 --- /dev/null +++ b/src/cython/gudhi/rips_complex.pyx @@ -0,0 +1,102 @@ +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 + +from gudhi.simplex_tree cimport * +from gudhi.simplex_tree import SimplexTree + +""" 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) 2016 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 Inria" +__license__ = "MIT" + +cdef extern from "Rips_complex_interface.h" namespace "Gudhi": + cdef cppclass Rips_complex_interface "Gudhi::rips_complex::Rips_complex_interface": + Rips_complex_interface() + void init_points(vector[vector[double]] values, double threshold) + void init_matrix(vector[vector[double]] values, double threshold) + void init_points_sparse(vector[vector[double]] values, double threshold, double sparse) + void init_matrix_sparse(vector[vector[double]] values, double threshold, double sparse) + void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, int dim_max) + +# RipsComplex python interface +cdef class RipsComplex: + """The data structure is a one skeleton graph, or Rips graph, containing + edges when the edge length is less or equal to a given threshold. Edge + length is computed from a user given point cloud with a given distance + function, or a distance matrix. + """ + + cdef Rips_complex_interface thisref + + # Fake constructor that does nothing but documenting the constructor + def __init__(self, points=None, distance_matrix=None, + max_edge_length=float('inf'), sparse=None): + """RipsComplex constructor. + + :param max_edge_length: Rips value. + :type max_edge_length: float + + :param points: A list of points in d-Dimension. + :type points: list of list of double + + Or + + :param distance_matrix: A distance matrix (full square or lower + triangular). + :type points: list of list of double + + And in both cases + + :param sparse: If this is not None, it switches to building a sparse + Rips and represents the approximation parameter epsilon. + :type sparse: float + """ + + # The real cython constructor + def __cinit__(self, points=None, distance_matrix=None, + max_edge_length=float('inf'), sparse=None): + if sparse is not None: + if distance_matrix is not None: + self.thisref.init_matrix_sparse(distance_matrix, + max_edge_length, + sparse) + else: + if points is None: + # Empty Rips construction + points=[] + self.thisref.init_points_sparse(points, max_edge_length, sparse) + else: + if distance_matrix is not None: + self.thisref.init_matrix(distance_matrix, max_edge_length) + else: + if points is None: + # Empty Rips construction + points=[] + self.thisref.init_points(points, max_edge_length) + + + def create_simplex_tree(self, max_dimension=1): + """ + :param max_dimension: graph expansion for rips until this given maximal + dimension. + :type max_dimension: int + :returns: A simplex tree created from the Delaunay Triangulation. + :rtype: SimplexTree + """ + stree = SimplexTree() + cdef intptr_t stree_ptr=stree.thisptr + self.thisref.create_simplex_tree(stree_ptr, max_dimension) + return stree diff --git a/src/cython/gudhi/simplex_tree.pxd b/src/cython/gudhi/simplex_tree.pxd new file mode 100644 index 00000000..25051295 --- /dev/null +++ b/src/cython/gudhi/simplex_tree.pxd @@ -0,0 +1,46 @@ +from cython cimport numeric +from libcpp.vector cimport vector +from libcpp.utility cimport pair +from libcpp cimport bool +from libcpp.string cimport string + +""" 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) 2016 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 Inria" +__license__ = "MIT" + +cdef extern from "Simplex_tree_interface.h" namespace "Gudhi": + cdef cppclass Simplex_tree_options_full_featured: + pass + + cdef cppclass Simplex_tree_interface_full_featured "Gudhi::Simplex_tree_interface": + Simplex_tree() + double simplex_filtration(vector[int] simplex) + void assign_simplex_filtration(vector[int] simplex, double filtration) + void initialize_filtration() + int num_vertices() + int num_simplices() + void set_dimension(int dimension) + int dimension() + int upper_bound_dimension() + bool find_simplex(vector[int] simplex) + bool insert_simplex_and_subfaces(vector[int] simplex, + double filtration) + vector[pair[vector[int], double]] get_filtration() + vector[pair[vector[int], double]] get_skeleton(int dimension) + vector[pair[vector[int], double]] get_star(vector[int] simplex) + vector[pair[vector[int], double]] get_cofaces(vector[int] simplex, + int dimension) + void expansion(int max_dim) + void remove_maximal_simplex(vector[int] simplex) + bool prune_above_filtration(double filtration) + bool make_filtration_non_decreasing() diff --git a/src/cython/gudhi/simplex_tree.pyx b/src/cython/gudhi/simplex_tree.pyx new file mode 100644 index 00000000..e5f9e9d1 --- /dev/null +++ b/src/cython/gudhi/simplex_tree.pyx @@ -0,0 +1,518 @@ +from libc.stdint cimport intptr_t +from numpy import array as np_array + +""" 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) 2016 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 Inria" +__license__ = "MIT" + +cdef extern from "Persistent_cohomology_interface.h" namespace "Gudhi": + cdef cppclass Simplex_tree_persistence_interface "Gudhi::Persistent_cohomology_interface>": + Simplex_tree_persistence_interface(Simplex_tree_interface_full_featured * st, bool persistence_dim_max) + vector[pair[int, pair[double, double]]] get_persistence(int homology_coeff_field, double min_persistence) + vector[int] betti_numbers() + vector[int] persistent_betti_numbers(double from_value, double to_value) + vector[pair[double,double]] intervals_in_dimension(int dimension) + void write_output_diagram(string diagram_file_name) + vector[pair[vector[int], vector[int]]] persistence_pairs() + +# SimplexTree python interface +cdef class SimplexTree: + """The simplex tree is an efficient and flexible data structure for + representing general (filtered) simplicial complexes. The data structure + is described in Jean-Daniel Boissonnat and Clément Maria. The Simplex + Tree: An Efficient Data Structure for General Simplicial Complexes. + Algorithmica, pages 1–22, 2014. + + This class is a filtered, with keys, and non contiguous vertices version + of the simplex tree. + """ + # unfortunately 'cdef public Simplex_tree_interface_full_featured* thisptr' is not possible + # Use intptr_t instead to cast the pointer + cdef public intptr_t thisptr + + # Get the pointer casted as it should be + cdef Simplex_tree_interface_full_featured* get_ptr(self): + return (self.thisptr) + + cdef Simplex_tree_persistence_interface * pcohptr + + # Fake constructor that does nothing but documenting the constructor + def __init__(self): + """SimplexTree constructor. + """ + + # The real cython constructor + def __cinit__(self): + cdef Simplex_tree_interface_full_featured* ptr = new Simplex_tree_interface_full_featured() + self.thisptr = ptr + + def __dealloc__(self): + cdef Simplex_tree_interface_full_featured* ptr = self.get_ptr() + if ptr != NULL: + del ptr + if self.pcohptr != NULL: + del self.pcohptr + + def __is_defined(self): + """Returns true if SimplexTree pointer is not NULL. + """ + return self.get_ptr() != NULL + + def __is_persistence_defined(self): + """Returns true if Persistence pointer is not NULL. + """ + return self.pcohptr != NULL + + def filtration(self, simplex): + """This function returns the filtration value for a given N-simplex in + this simplicial complex, or +infinity if it is not in the complex. + + :param simplex: The N-simplex, represented by a list of vertex. + :type simplex: list of int. + :returns: The simplicial complex filtration value. + :rtype: float + """ + return self.get_ptr().simplex_filtration(simplex) + + def assign_filtration(self, simplex, filtration): + """This function assigns the simplicial complex filtration value for a + given N-simplex. + + :param simplex: The N-simplex, represented by a list of vertex. + :type simplex: list of int. + :param filtration: The simplicial complex filtration value. + :type filtration: float + """ + self.get_ptr().assign_simplex_filtration(simplex, filtration) + + def initialize_filtration(self): + """This function initializes and sorts the simplicial complex + filtration vector. + + .. note:: + + This function must be launched before + :func:`persistence()`, + :func:`betti_numbers()`, + :func:`persistent_betti_numbers()`, + or :func:`get_filtration()` + after :func:`inserting` or + :func:`removing` + simplices. + """ + self.get_ptr().initialize_filtration() + + def num_vertices(self): + """This function returns the number of vertices of the simplicial + complex. + + :returns: The simplicial complex number of vertices. + :rtype: int + """ + return self.get_ptr().num_vertices() + + def num_simplices(self): + """This function returns the number of simplices of the simplicial + complex. + + :returns: the simplicial complex number of simplices. + :rtype: int + """ + return self.get_ptr().num_simplices() + + def dimension(self): + """This function returns the dimension of the simplicial complex. + + :returns: the simplicial complex dimension. + :rtype: int + + .. note:: + + This function is not constant time because it can recompute + dimension if required (can be triggered by + :func:`remove_maximal_simplex()` + or + :func:`prune_above_filtration()` + methods). + """ + return self.get_ptr().dimension() + + def upper_bound_dimension(self): + """This function returns a valid dimension upper bound of the + simplicial complex. + + :returns: an upper bound on the dimension of the simplicial complex. + :rtype: int + """ + return self.get_ptr().upper_bound_dimension() + + def set_dimension(self, dimension): + """This function sets the dimension of the simplicial complex. + + :param dimension: The new dimension value. + :type dimension: int. + + .. note:: + + This function must be used with caution because it disables + dimension recomputation when required + (this recomputation can be triggered by + :func:`remove_maximal_simplex()` + or + :func:`prune_above_filtration()` + ). + """ + self.get_ptr().set_dimension(dimension) + + def find(self, simplex): + """This function returns if the N-simplex was found in the simplicial + complex or not. + + :param simplex: The N-simplex to find, represented by a list of vertex. + :type simplex: list of int. + :returns: true if the simplex was found, false otherwise. + :rtype: bool + """ + cdef vector[int] csimplex + for i in simplex: + csimplex.push_back(i) + return self.get_ptr().find_simplex(csimplex) + + def insert(self, simplex, filtration=0.0): + """This function inserts the given N-simplex and its subfaces with the + given filtration value (default value is '0.0'). If some of those + simplices are already present with a higher filtration value, their + filtration value is lowered. + + :param simplex: The N-simplex to insert, represented by a list of + vertex. + :type simplex: list of int. + :param filtration: The filtration value of the simplex. + :type filtration: float. + :returns: true if the simplex was not yet in the complex, false + otherwise (whatever its original filtration value). + :rtype: bool + """ + cdef vector[int] csimplex + for i in simplex: + csimplex.push_back(i) + return self.get_ptr().insert_simplex_and_subfaces(csimplex, + filtration) + + def get_filtration(self): + """This function returns a list of all simplices with their given + filtration values. + + :returns: The simplices sorted by increasing filtration values. + :rtype: list of tuples(simplex, filtration) + """ + cdef vector[pair[vector[int], double]] filtration \ + = self.get_ptr().get_filtration() + ct = [] + for filtered_complex in filtration: + v = [] + for vertex in filtered_complex.first: + v.append(vertex) + ct.append((v, filtered_complex.second)) + return ct + + def get_skeleton(self, dimension): + """This function returns the (simplices of the) skeleton of a maximum + given dimension. + + :param dimension: The skeleton dimension value. + :type dimension: int. + :returns: The (simplices of the) skeleton of a maximum dimension. + :rtype: list of tuples(simplex, filtration) + """ + cdef vector[pair[vector[int], double]] skeleton \ + = self.get_ptr().get_skeleton(dimension) + ct = [] + for filtered_simplex in skeleton: + v = [] + for vertex in filtered_simplex.first: + v.append(vertex) + ct.append((v, filtered_simplex.second)) + return ct + + def get_star(self, simplex): + """This function returns the star of a given N-simplex. + + :param simplex: The N-simplex, represented by a list of vertex. + :type simplex: list of int. + :returns: The (simplices of the) star of a simplex. + :rtype: list of tuples(simplex, filtration) + """ + cdef vector[int] csimplex + for i in simplex: + csimplex.push_back(i) + cdef vector[pair[vector[int], double]] star \ + = self.get_ptr().get_star(csimplex) + ct = [] + for filtered_simplex in star: + v = [] + for vertex in filtered_simplex.first: + v.append(vertex) + ct.append((v, filtered_simplex.second)) + return ct + + def get_cofaces(self, simplex, codimension): + """This function returns the cofaces of a given N-simplex with a + given codimension. + + :param simplex: The N-simplex, represented by a list of vertex. + :type simplex: list of int. + :param codimension: The codimension. If codimension = 0, all cofaces + are returned (equivalent of get_star function) + :type codimension: int. + :returns: The (simplices of the) cofaces of a simplex + :rtype: list of tuples(simplex, filtration) + """ + cdef vector[int] csimplex + for i in simplex: + csimplex.push_back(i) + cdef vector[pair[vector[int], double]] cofaces \ + = self.get_ptr().get_cofaces(csimplex, codimension) + ct = [] + for filtered_simplex in cofaces: + v = [] + for vertex in filtered_simplex.first: + v.append(vertex) + ct.append((v, filtered_simplex.second)) + return ct + + def remove_maximal_simplex(self, simplex): + """This function removes a given maximal N-simplex from the simplicial + complex. + + :param simplex: The N-simplex, represented by a list of vertex. + :type simplex: list of int. + + .. note:: + + Be aware that removing is shifting data in a flat_map + (:func:`initialize_filtration()` to be done). + + .. note:: + + The dimension of the simplicial complex may be lower after calling + remove_maximal_simplex than it was before. However, + :func:`upper_bound_dimension()` + method will return the old value, which + remains a valid upper bound. If you care, you can call + :func:`dimension()` + to recompute the exact dimension. + """ + self.get_ptr().remove_maximal_simplex(simplex) + + def prune_above_filtration(self, filtration): + """Prune above filtration value given as parameter. + + :param filtration: Maximum threshold value. + :type filtration: float. + :returns: The filtration modification information. + :rtype: bool + + + .. note:: + + Some simplex tree functions require the filtration to be valid. + prune_above_filtration function is not launching + :func:`initialize_filtration()` + but returns the filtration modification + information. If the complex has changed , please call + :func:`initialize_filtration()` + to recompute it. + + .. note:: + + Note that the dimension of the simplicial complex may be lower + after calling + :func:`prune_above_filtration()` + than it was before. However, + :func:`upper_bound_dimension()` + will return the old value, which remains a + valid upper bound. If you care, you can call + :func:`dimension()` + method to recompute the exact dimension. + """ + return self.get_ptr().prune_above_filtration(filtration) + + def expansion(self, max_dim): + """Expands the Simplex_tree containing only its one skeleton + until dimension max_dim. + + The expanded simplicial complex until dimension :math:`d` + attached to a graph :math:`G` is the maximal simplicial complex of + dimension at most :math:`d` admitting the graph :math:`G` as + :math:`1`-skeleton. + The filtration value assigned to a simplex is the maximal filtration + value of one of its edges. + + The Simplex_tree must contain no simplex of dimension bigger than + 1 when calling the method. + + :param max_dim: The maximal dimension. + :type max_dim: int. + """ + self.get_ptr().expansion(max_dim) + + def make_filtration_non_decreasing(self): + """This function ensures that each simplex has a higher filtration + value than its faces by increasing the filtration values. + + :returns: True if any filtration value was modified, + False if the filtration was already non-decreasing. + :rtype: bool + + + .. note:: + + Some simplex tree functions require the filtration to be valid. + make_filtration_non_decreasing function is not launching + :func:`initialize_filtration()` + but returns the filtration modification + information. If the complex has changed , please call + :func:`initialize_filtration()` + to recompute it. + """ + return self.get_ptr().make_filtration_non_decreasing() + + def persistence(self, homology_coeff_field=11, min_persistence=0, persistence_dim_max = False): + """This function returns the persistence of the simplicial complex. + + :param homology_coeff_field: The homology coefficient field. Must be a + prime number. Default value is 11. + :type homology_coeff_field: int. + :param min_persistence: The minimum persistence value to take into + account (strictly greater than min_persistence). Default value is + 0.0. + Sets min_persistence to -1.0 to see all values. + :type min_persistence: float. + :param persistence_dim_max: If true, the persistent homology for the + maximal dimension in the complex is computed. If false, it is + ignored. Default is false. + :type persistence_dim_max: bool + :returns: The persistence of the simplicial complex. + :rtype: list of pairs(dimension, pair(birth, death)) + """ + if self.pcohptr != NULL: + del self.pcohptr + self.pcohptr = new Simplex_tree_persistence_interface(self.get_ptr(), persistence_dim_max) + cdef vector[pair[int, pair[double, double]]] persistence_result + if self.pcohptr != NULL: + persistence_result = self.pcohptr.get_persistence(homology_coeff_field, min_persistence) + return persistence_result + + def betti_numbers(self): + """This function returns the Betti numbers of the simplicial complex. + + :returns: The Betti numbers ([B0, B1, ..., Bn]). + :rtype: list of int + + :note: betti_numbers function requires + :func:`persistence()` + function to be launched first. + """ + cdef vector[int] bn_result + if self.pcohptr != NULL: + bn_result = self.pcohptr.betti_numbers() + else: + print("betti_numbers function requires persistence function" + " to be launched first.") + return bn_result + + def persistent_betti_numbers(self, from_value, to_value): + """This function returns the persistent Betti numbers of the + simplicial complex. + + :param from_value: The persistence birth limit to be added in the + numbers (persistent birth <= from_value). + :type from_value: float. + :param to_value: The persistence death limit to be added in the + numbers (persistent death > to_value). + :type to_value: float. + + :returns: The persistent Betti numbers ([B0, B1, ..., Bn]). + :rtype: list of int + + :note: persistent_betti_numbers function requires + :func:`persistence()` + function to be launched first. + """ + cdef vector[int] pbn_result + if self.pcohptr != NULL: + pbn_result = self.pcohptr.persistent_betti_numbers(from_value, to_value) + else: + print("persistent_betti_numbers function requires persistence function" + " to be launched first.") + return pbn_result + + def persistence_intervals_in_dimension(self, dimension): + """This function returns the persistence intervals of the simplicial + complex in a specific dimension. + + :param dimension: The specific dimension. + :type dimension: int. + :returns: The persistence intervals. + :rtype: numpy array of dimension 2 + + :note: intervals_in_dim function requires + :func:`persistence()` + function to be launched first. + """ + cdef vector[pair[double,double]] intervals_result + if self.pcohptr != NULL: + intervals_result = self.pcohptr.intervals_in_dimension(dimension) + else: + print("intervals_in_dim function requires persistence function" + " to be launched first.") + return np_array(intervals_result) + + def persistence_pairs(self): + """This function returns a list of persistence birth and death simplices pairs. + + :returns: A list of persistence simplices intervals. + :rtype: list of pair of list of int + + :note: persistence_pairs function requires + :func:`persistence()` + function to be launched first. + """ + cdef vector[pair[vector[int],vector[int]]] persistence_pairs_result + if self.pcohptr != NULL: + persistence_pairs_result = self.pcohptr.persistence_pairs() + else: + print("persistence_pairs function requires persistence function" + " to be launched first.") + return persistence_pairs_result + + def write_persistence_diagram(self, persistence_file=''): + """This function writes the persistence intervals of the simplicial + complex in a user given file name. + + :param persistence_file: The specific dimension. + :type persistence_file: string. + + :note: intervals_in_dim function requires + :func:`persistence()` + function to be launched first. + """ + if self.pcohptr != NULL: + if persistence_file != '': + self.pcohptr.write_output_diagram(str.encode(persistence_file)) + else: + print("persistence_file must be specified") + else: + print("intervals_in_dim function requires persistence function" + " to be launched first.") diff --git a/src/cython/gudhi/strong_witness_complex.pyx b/src/cython/gudhi/strong_witness_complex.pyx new file mode 100644 index 00000000..4e3d1b67 --- /dev/null +++ b/src/cython/gudhi/strong_witness_complex.pyx @@ -0,0 +1,78 @@ +from cython cimport numeric +from libcpp.vector cimport vector +from libcpp.utility cimport pair +from libc.stdint cimport intptr_t + +from gudhi.simplex_tree cimport * +from gudhi.simplex_tree import SimplexTree + +""" 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) 2016 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 Inria" +__license__ = "MIT" + +cdef extern from "Strong_witness_complex_interface.h" namespace "Gudhi": + cdef cppclass Strong_witness_complex_interface "Gudhi::witness_complex::Strong_witness_complex_interface": + Strong_witness_complex_interface(vector[vector[pair[size_t, double]]] nearest_landmark_table) + void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square) + void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square, + unsigned limit_dimension) + +# StrongWitnessComplex python interface +cdef class StrongWitnessComplex: + """Constructs (strong) witness complex for a given table of nearest + landmarks with respect to witnesses. + """ + + cdef Strong_witness_complex_interface * thisptr + + # Fake constructor that does nothing but documenting the constructor + def __init__(self, nearest_landmark_table=None): + """StrongWitnessComplex constructor. + + :param nearest_landmark_table: A list of lists of nearest landmarks and their distances. + `nearest_landmark_table[w][k]==(l,d)` means that l is the k-th nearest landmark to + witness w, and d is the (squared) distance between l and w. + :type nearest_landmark_table: list of list of pair of int and float + """ + + # The real cython constructor + def __cinit__(self, nearest_landmark_table=None): + if nearest_landmark_table is not None: + self.thisptr = new Strong_witness_complex_interface(nearest_landmark_table) + + def __dealloc__(self): + if self.thisptr != NULL: + del self.thisptr + + def __is_defined(self): + """Returns true if StrongWitnessComplex pointer is not NULL. + """ + return self.thisptr != NULL + + def create_simplex_tree(self, max_alpha_square = float('inf'), limit_dimension = -1): + """ + :param max_alpha_square: The maximum relaxation parameter. + Default is set to infinity. + :type max_alpha_square: float + :returns: A simplex tree created from the Delaunay Triangulation. + :rtype: SimplexTree + """ + stree = SimplexTree() + cdef intptr_t stree_int_ptr=stree.thisptr + cdef Simplex_tree_interface_full_featured* stree_ptr = stree_int_ptr + if limit_dimension is not -1: + self.thisptr.create_simplex_tree(stree_ptr, + max_alpha_square, limit_dimension) + else: + self.thisptr.create_simplex_tree(stree_ptr, max_alpha_square) + return stree diff --git a/src/cython/gudhi/subsampling.pyx b/src/cython/gudhi/subsampling.pyx new file mode 100644 index 00000000..1135c1fb --- /dev/null +++ b/src/cython/gudhi/subsampling.pyx @@ -0,0 +1,130 @@ +from cython cimport numeric +from libcpp.vector cimport vector +from libcpp.string cimport string +from libcpp cimport bool +import os + +""" 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) 2016 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 Inria" +__license__ = "GPL v3" + +cdef extern from "Subsampling_interface.h" namespace "Gudhi::subsampling": + vector[vector[double]] subsampling_n_farthest_points(vector[vector[double]] points, unsigned nb_points) + vector[vector[double]] subsampling_n_farthest_points(vector[vector[double]] points, unsigned nb_points, unsigned starting_point) + vector[vector[double]] subsampling_n_farthest_points_from_file(string off_file, unsigned nb_points) + vector[vector[double]] subsampling_n_farthest_points_from_file(string off_file, unsigned nb_points, unsigned starting_point) + vector[vector[double]] subsampling_n_random_points(vector[vector[double]] points, unsigned nb_points) + vector[vector[double]] subsampling_n_random_points_from_file(string off_file, unsigned nb_points) + vector[vector[double]] subsampling_sparsify_points(vector[vector[double]] points, double min_squared_dist) + vector[vector[double]] subsampling_sparsify_points_from_file(string off_file, double min_squared_dist) + +def choose_n_farthest_points(points=None, off_file='', nb_points=0, starting_point = ''): + """Subsample by a greedy strategy of iteratively adding the farthest point + from the current chosen point set to the subsampling. + The iteration starts with the landmark `starting point`. + + :param points: The input point set. + :type points: vector[vector[double]]. + + Or + + :param off_file: An OFF file style name. + :type off_file: string + + :param nb_points: Number of points of the subsample. + :type nb_points: unsigned. + :param starting_point: The iteration starts with the landmark `starting \ + point`,which is the index of the poit to start with. If not set, this \ + index is choosen randomly. + :type starting_point: unsigned. + :returns: The subsample point set. + :rtype: vector[vector[double]] + """ + if off_file is not '': + if os.path.isfile(off_file): + if starting_point is '': + return subsampling_n_farthest_points_from_file(str.encode(off_file), + nb_points) + else: + return subsampling_n_farthest_points_from_file(str.encode(off_file), + nb_points, + starting_point) + else: + print("file " + off_file + " not found.") + else: + if points is None: + # Empty points + points=[] + if starting_point is '': + return subsampling_n_farthest_points(points, nb_points) + else: + return subsampling_n_farthest_points(points, nb_points, + starting_point) + +def pick_n_random_points(points=None, off_file='', nb_points=0): + """Subsample a point set by picking random vertices. + + :param points: The input point set. + :type points: vector[vector[double]]. + + Or + + :param off_file: An OFF file style name. + :type off_file: string + + :param nb_points: Number of points of the subsample. + :type nb_points: unsigned. + :returns: The subsample point set. + :rtype: vector[vector[double]] + """ + if off_file is not '': + if os.path.isfile(off_file): + return subsampling_n_random_points_from_file(str.encode(off_file), + nb_points) + else: + print("file " + off_file + " not found.") + else: + if points is None: + # Empty points + points=[] + return subsampling_n_random_points(points, nb_points) + +def sparsify_point_set(points=None, off_file='', min_squared_dist=0.0): + """Outputs a subset of the input points so that the squared distance + between any two points is greater than or equal to min_squared_dist. + + :param points: The input point set. + :type points: vector[vector[double]]. + + Or + + :param off_file: An OFF file style name. + :type off_file: string + + :param min_squared_dist: Minimum squared distance separating the output \ + points. + :type min_squared_dist: float. + :returns: The subsample point set. + :rtype: vector[vector[double]] + """ + if off_file is not '': + if os.path.isfile(off_file): + return subsampling_sparsify_points_from_file(str.encode(off_file), + min_squared_dist) + else: + print("file " + off_file + " not found.") + else: + if points is None: + # Empty points + points=[] + return subsampling_sparsify_points(points, min_squared_dist) diff --git a/src/cython/gudhi/tangential_complex.pyx b/src/cython/gudhi/tangential_complex.pyx new file mode 100644 index 00000000..b2d55520 --- /dev/null +++ b/src/cython/gudhi/tangential_complex.pyx @@ -0,0 +1,177 @@ +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 os + +from gudhi.simplex_tree cimport * +from gudhi.simplex_tree import SimplexTree + +""" 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) 2016 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 Inria" +__license__ = "GPL v3" + +cdef extern from "Tangential_complex_interface.h" namespace "Gudhi": + cdef cppclass Tangential_complex_interface "Gudhi::tangential_complex::Tangential_complex_interface": + Tangential_complex_interface(int intrisic_dim, vector[vector[double]] points) + # bool from_file is a workaround for cython to find the correct signature + Tangential_complex_interface(int intrisic_dim, string off_file, bool from_file) + void compute_tangential_complex() except + + vector[double] get_point(unsigned vertex) + unsigned number_of_vertices() + unsigned number_of_simplices() + unsigned number_of_inconsistent_simplices() + unsigned number_of_inconsistent_stars() + void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree) + void fix_inconsistencies_using_perturbation(double max_perturb, double time_limit) + void set_max_squared_edge_length(double max_squared_edge_length) + +# TangentialComplex python interface +cdef class TangentialComplex: + """The class Tangential_complex represents a tangential complex. After the + computation of the complex, an optional post-processing called perturbation + can be run to attempt to remove inconsistencies. + """ + + cdef Tangential_complex_interface * thisptr + + # Fake constructor that does nothing but documenting the constructor + def __init__(self, intrisic_dim, points=None, off_file=''): + """TangentialComplex constructor. + + :param intrisic_dim: Intrinsic dimension of the manifold. + :type intrisic_dim: integer + + :param points: A list of points in d-Dimension. + :type points: list of list of double + + Or + + :param off_file: An OFF file style name. + :type off_file: string + """ + + # The real cython constructor + def __cinit__(self, intrisic_dim, points=None, off_file=''): + if off_file is not '': + if os.path.isfile(off_file): + self.thisptr = new Tangential_complex_interface(intrisic_dim, str.encode(off_file), True) + else: + print("file " + off_file + " not found.") + else: + if points is None: + # Empty tangential construction + points=[] + self.thisptr = new Tangential_complex_interface(intrisic_dim, points) + + + def __dealloc__(self): + if self.thisptr != NULL: + del self.thisptr + + def __is_defined(self): + """Returns true if TangentialComplex pointer is not NULL. + """ + return self.thisptr != NULL + + def compute_tangential_complex(self): + """This function computes the tangential complex. + + Raises: + ValueError: In debug mode, if the computed star dimension is too + low. Try to set a bigger maximal edge length value with + :func:`~gudhi.Tangential_complex.set_max_squared_edge_length` + if this happens. + """ + self.thisptr.compute_tangential_complex() + + def get_point(self, vertex): + """This function returns the point corresponding to a given vertex. + + :param vertex: The vertex. + :type vertex: int. + :returns: The point. + :rtype: list of float + """ + cdef vector[double] point = self.thisptr.get_point(vertex) + return point + + def num_vertices(self): + """ + :returns: The number of vertices. + :rtype: unsigned + """ + return self.thisptr.number_of_vertices() + + def num_simplices(self): + """ + :returns: Total number of simplices in stars (including duplicates that appear in several stars). + :rtype: unsigned + """ + return self.thisptr.number_of_simplices() + + def num_inconsistent_simplices(self): + """ + :returns: The number of inconsistent simplices. + :rtype: unsigned + """ + return self.thisptr.number_of_inconsistent_simplices() + + def num_inconsistent_stars(self): + """ + :returns: The number of stars containing at least one inconsistent simplex. + :rtype: unsigned + """ + return self.thisptr.number_of_inconsistent_stars() + + def create_simplex_tree(self): + """Exports the complex into a simplex tree. + + :returns: A simplex tree created from the complex. + :rtype: SimplexTree + """ + stree = SimplexTree() + cdef intptr_t stree_int_ptr=stree.thisptr + cdef Simplex_tree_interface_full_featured* stree_ptr = stree_int_ptr + self.thisptr.create_simplex_tree(stree_ptr) + return stree + simplex_tree = SimplexTree() + self.thisptr.create_simplex_tree(simplex_tree.thisptr) + return simplex_tree + + def fix_inconsistencies_using_perturbation(self, max_perturb, time_limit=-1.0): + """Attempts to fix inconsistencies by perturbing the point positions. + + :param max_perturb: Maximum length of the translations used by the + perturbation. + :type max_perturb: double + :param time_limit: Time limit in seconds. If -1, no time limit is set. + :type time_limit: double + """ + self.thisptr.fix_inconsistencies_using_perturbation(max_perturb, + time_limit) + + def set_max_squared_edge_length(self, max_squared_edge_length): + """Sets the maximal possible squared edge length for the edges in the + triangulations. + + :param max_squared_edge_length: Maximal possible squared edge length. + :type max_squared_edge_length: double + + If the maximal edge length value is too low + :func:`~gudhi.Tangential_complex.compute_tangential_complex` + will throw an exception in debug mode. + """ + self.thisptr.set_max_squared_edge_length(max_squared_edge_length) diff --git a/src/cython/gudhi/witness_complex.pyx b/src/cython/gudhi/witness_complex.pyx new file mode 100644 index 00000000..c859877d --- /dev/null +++ b/src/cython/gudhi/witness_complex.pyx @@ -0,0 +1,78 @@ +from cython cimport numeric +from libcpp.vector cimport vector +from libcpp.utility cimport pair +from libc.stdint cimport intptr_t + +from gudhi.simplex_tree cimport * +from gudhi.simplex_tree import SimplexTree + +""" 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) 2016 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 Inria" +__license__ = "MIT" + +cdef extern from "Witness_complex_interface.h" namespace "Gudhi": + cdef cppclass Witness_complex_interface "Gudhi::witness_complex::Witness_complex_interface": + Witness_complex_interface(vector[vector[pair[size_t, double]]] nearest_landmark_table) + void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square) + void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, double max_alpha_square, + unsigned limit_dimension) + +# WitnessComplex python interface +cdef class WitnessComplex: + """Constructs (weak) witness complex for a given table of nearest landmarks + with respect to witnesses. + """ + + cdef Witness_complex_interface * thisptr + + # Fake constructor that does nothing but documenting the constructor + def __init__(self, nearest_landmark_table=None): + """WitnessComplex constructor. + + :param nearest_landmark_table: A list of lists of nearest landmarks and their distances. + `nearest_landmark_table[w][k]==(l,d)` means that l is the k-th nearest landmark to + witness w, and d is the (squared) distance between l and w. + :type nearest_landmark_table: list of list of pair of int and float + """ + + # The real cython constructor + def __cinit__(self, nearest_landmark_table=None): + if nearest_landmark_table is not None: + self.thisptr = new Witness_complex_interface(nearest_landmark_table) + + def __dealloc__(self): + if self.thisptr != NULL: + del self.thisptr + + def __is_defined(self): + """Returns true if WitnessComplex pointer is not NULL. + """ + return self.thisptr != NULL + + def create_simplex_tree(self, max_alpha_square = float('inf'), limit_dimension = -1): + """ + :param max_alpha_square: The maximum relaxation parameter. + Default is set to infinity. + :type max_alpha_square: float + :returns: A simplex tree created from the Delaunay Triangulation. + :rtype: SimplexTree + """ + stree = SimplexTree() + cdef intptr_t stree_int_ptr=stree.thisptr + cdef Simplex_tree_interface_full_featured* stree_ptr = stree_int_ptr + if limit_dimension is not -1: + self.thisptr.create_simplex_tree(stree_ptr, + max_alpha_square, limit_dimension) + else: + self.thisptr.create_simplex_tree(stree_ptr, max_alpha_square) + return stree -- cgit v1.2.3 From 003e9b3e127a3f34c03872b0cc314d0dcbc04bcf Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 2 Aug 2019 11:25:52 +0200 Subject: First version that compiles the simplex_tree module --- src/cython/gudhi/simplex_tree.pxd | 10 ++++++++++ src/cython/gudhi/simplex_tree.pyx | 11 +---------- src/cython/setup.py.in | 6 ++++-- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/cython/gudhi/simplex_tree.pxd b/src/cython/gudhi/simplex_tree.pxd index 25051295..5f86cfe2 100644 --- a/src/cython/gudhi/simplex_tree.pxd +++ b/src/cython/gudhi/simplex_tree.pxd @@ -44,3 +44,13 @@ cdef extern from "Simplex_tree_interface.h" namespace "Gudhi": void remove_maximal_simplex(vector[int] simplex) bool prune_above_filtration(double filtration) bool make_filtration_non_decreasing() + +cdef extern from "Persistent_cohomology_interface.h" namespace "Gudhi": + cdef cppclass Simplex_tree_persistence_interface "Gudhi::Persistent_cohomology_interface>": + Simplex_tree_persistence_interface(Simplex_tree_interface_full_featured * st, bool persistence_dim_max) + vector[pair[int, pair[double, double]]] get_persistence(int homology_coeff_field, double min_persistence) + vector[int] betti_numbers() + vector[int] persistent_betti_numbers(double from_value, double to_value) + vector[pair[double,double]] intervals_in_dimension(int dimension) + void write_output_diagram(string diagram_file_name) + vector[pair[vector[int], vector[int]]] persistence_pairs() diff --git a/src/cython/gudhi/simplex_tree.pyx b/src/cython/gudhi/simplex_tree.pyx index e5f9e9d1..604328e9 100644 --- a/src/cython/gudhi/simplex_tree.pyx +++ b/src/cython/gudhi/simplex_tree.pyx @@ -1,5 +1,6 @@ from libc.stdint cimport intptr_t from numpy import array as np_array +from simplex_tree cimport * """ 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. @@ -15,16 +16,6 @@ __author__ = "Vincent Rouvreau" __copyright__ = "Copyright (C) 2016 Inria" __license__ = "MIT" -cdef extern from "Persistent_cohomology_interface.h" namespace "Gudhi": - cdef cppclass Simplex_tree_persistence_interface "Gudhi::Persistent_cohomology_interface>": - Simplex_tree_persistence_interface(Simplex_tree_interface_full_featured * st, bool persistence_dim_max) - vector[pair[int, pair[double, double]]] get_persistence(int homology_coeff_field, double min_persistence) - vector[int] betti_numbers() - vector[int] persistent_betti_numbers(double from_value, double to_value) - vector[pair[double,double]] intervals_in_dimension(int dimension) - void write_output_diagram(string diagram_file_name) - vector[pair[vector[int], vector[int]]] persistence_pairs() - # SimplexTree python interface cdef class SimplexTree: """The simplex tree is an efficient and flexible data structure for diff --git a/src/cython/setup.py.in b/src/cython/setup.py.in index 454be9af..f158f6cb 100644 --- a/src/cython/setup.py.in +++ b/src/cython/setup.py.in @@ -18,23 +18,25 @@ __license__ = "MIT" simplextree = Extension( "gudhi.simplextree", - sources = ['@CMAKE_CURRENT_SOURCE_DIR@/cython/simplex_tree.pyx',], + sources = ['@CMAKE_CURRENT_SOURCE_DIR@/gudhi/simplex_tree.pyx',], language = 'c++', extra_compile_args=[@GUDHI_CYTHON_EXTRA_COMPILE_ARGS@], extra_link_args=[@GUDHI_CYTHON_EXTRA_LINK_ARGS@], libraries=[@GUDHI_CYTHON_LIBRARIES@], library_dirs=[@GUDHI_CYTHON_LIBRARY_DIRS@], - include_dirs = [numpy_get_include(), @GUDHI_CYTHON_INCLUDE_DIRS@], + include_dirs = [numpy_get_include(), '@CMAKE_CURRENT_SOURCE_DIR@/gudhi/', @GUDHI_CYTHON_INCLUDE_DIRS@], runtime_library_dirs=[@GUDHI_CYTHON_RUNTIME_LIBRARY_DIRS@], ) setup( name = 'gudhi', + packages=["gudhi",], author='GUDHI Editorial Board', author_email='gudhi-contact@lists.gforge.inria.fr', version='@GUDHI_VERSION@', url='http://gudhi.gforge.inria.fr/', ext_modules = cythonize(simplextree), +# cmdclass = {'build_ext': build_ext}, install_requires = ['cython','numpy >= 1.9',], setup_requires = ['numpy >= 1.9',], ) -- cgit v1.2.3 From 48dfd910463c33e0e331f84e151ac7fe1f93dbe2 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Tue, 6 Aug 2019 14:13:52 +0200 Subject: First version with only simplex tree that compiles. Cannot find how not to generate .cpp in sources --- .gitignore | 3 +++ src/cython/gudhi/__init__.py | 1 + src/cython/gudhi/simplex_tree.pyx | 2 +- src/cython/setup.py.in | 8 ++++---- 4 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 src/cython/gudhi/__init__.py diff --git a/.gitignore b/.gitignore index 5c2195be..3c47ca9a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ # Classical CMake build directory build/ +# Generated by Cython +src/cython/gudhi/simplex_tree.cpp + # Generated by tests data/points/COIL_database/lucky_cat.off_dist data/points/COIL_database/lucky_cat.off_sc.dot diff --git a/src/cython/gudhi/__init__.py b/src/cython/gudhi/__init__.py new file mode 100644 index 00000000..fde749eb --- /dev/null +++ b/src/cython/gudhi/__init__.py @@ -0,0 +1 @@ +# Fake empty __init__.py for cython to accept this directory as a Python package diff --git a/src/cython/gudhi/simplex_tree.pyx b/src/cython/gudhi/simplex_tree.pyx index 604328e9..51134681 100644 --- a/src/cython/gudhi/simplex_tree.pyx +++ b/src/cython/gudhi/simplex_tree.pyx @@ -1,6 +1,6 @@ from libc.stdint cimport intptr_t from numpy import array as np_array -from simplex_tree cimport * +cimport simplex_tree """ 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. diff --git a/src/cython/setup.py.in b/src/cython/setup.py.in index f158f6cb..3c37664f 100644 --- a/src/cython/setup.py.in +++ b/src/cython/setup.py.in @@ -16,8 +16,8 @@ __author__ = "GUDHI Editorial Board" __copyright__ = "Copyright (C) 2016 Inria" __license__ = "MIT" -simplextree = Extension( - "gudhi.simplextree", +simplex_tree = Extension( + "gudhi.simplex_tree", sources = ['@CMAKE_CURRENT_SOURCE_DIR@/gudhi/simplex_tree.pyx',], language = 'c++', extra_compile_args=[@GUDHI_CYTHON_EXTRA_COMPILE_ARGS@], @@ -35,8 +35,8 @@ setup( author_email='gudhi-contact@lists.gforge.inria.fr', version='@GUDHI_VERSION@', url='http://gudhi.gforge.inria.fr/', - ext_modules = cythonize(simplextree), -# cmdclass = {'build_ext': build_ext}, + ext_modules = cythonize(simplex_tree), +# cmdclass={'build_ext': Cython.Build.build_ext}, install_requires = ['cython','numpy >= 1.9',], setup_requires = ['numpy >= 1.9',], ) -- cgit v1.2.3 From 9b40c817277fa1de6c2b2e7b796ad0157ace4c61 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Tue, 6 Aug 2019 17:11:49 +0200 Subject: Add all modules that do not depend on Simplex tree --- .gitignore | 9 +++++++++ src/cython/CMakeLists.txt | 30 ++++++++++++++++-------------- src/cython/gudhi/__init__.py.in | 2 +- src/cython/setup.py.in | 39 +++++++++++++++++++++++++-------------- 4 files changed, 51 insertions(+), 29 deletions(-) diff --git a/.gitignore b/.gitignore index 3c47ca9a..2b1817a4 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,15 @@ build/ # Generated by Cython src/cython/gudhi/simplex_tree.cpp +src/cython/gudhi/alpha_complex.cpp +src/cython/gudhi/bottleneck_distance.cpp +src/cython/gudhi/cubical_complex.cpp +src/cython/gudhi/euclidean_strong_witness_complex.cpp +src/cython/gudhi/off_reader.cpp +src/cython/gudhi/periodic_cubical_complex.cpp +src/cython/gudhi/reader_utils.cpp +src/cython/gudhi/rips_complex.cpp +src/cython/gudhi/subsampling.cpp # Generated by tests data/points/COIL_database/lucky_cat.off_dist diff --git a/src/cython/CMakeLists.txt b/src/cython/CMakeLists.txt index cd99f70b..12eec9d9 100644 --- a/src/cython/CMakeLists.txt +++ b/src/cython/CMakeLists.txt @@ -26,7 +26,7 @@ function( add_gudhi_py_test THE_TEST ) endfunction( add_gudhi_py_test ) # Set gudhi.__debug_info__ -# WARNING : to be done before gudhi.pyx.in configure_file +# WARNING : to be done before setup.py.in configure_file function( add_gudhi_debug_info DEBUG_INFO ) set(GUDHI_CYTHON_DEBUG_INFO "${GUDHI_CYTHON_DEBUG_INFO} \"${DEBUG_INFO}\\n\" \\\n" PARENT_SCOPE) endfunction( add_gudhi_debug_info ) @@ -94,20 +94,24 @@ if(PYTHONINTERP_FOUND) set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DCGAL_EIGEN3_ENABLED', ") endif (EIGEN3_FOUND) + set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'off_reader', ") + set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'simplex_tree', ") + set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'rips_complex', ") + set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'cubical_complex', ") + set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'periodic_cubical_complex', ") + set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'reader_utils', ") + #set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'witness_complex', ") + #set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'strong_witness_complex', ") if (NOT CGAL_VERSION VERSION_LESS 4.11.0) - set(GUDHI_CYTHON_BOTTLENECK_DISTANCE "include '${CMAKE_CURRENT_SOURCE_DIR}/cython/bottleneck_distance.pyx'") - set(GUDHI_CYTHON_NERVE_GIC "include '${CMAKE_CURRENT_SOURCE_DIR}/cython/nerve_gic.pyx'") + #set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'bottleneck_distance', ") + #set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'nerve_gic', ") endif () if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0) - set(GUDHI_CYTHON_SUBSAMPLING "include '${CMAKE_CURRENT_SOURCE_DIR}/cython/subsampling.pyx'") - set(GUDHI_CYTHON_TANGENTIAL_COMPLEX "include '${CMAKE_CURRENT_SOURCE_DIR}/cython/tangential_complex.pyx'") - endif () - if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0) - set(GUDHI_CYTHON_ALPHA_COMPLEX "include '${CMAKE_CURRENT_SOURCE_DIR}/cython/alpha_complex.pyx'") - endif () - if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0) - set(GUDHI_CYTHON_EUCLIDEAN_WITNESS_COMPLEX - "include '${CMAKE_CURRENT_SOURCE_DIR}/cython/euclidean_witness_complex.pyx'\ninclude '${CMAKE_CURRENT_SOURCE_DIR}/cython/euclidean_strong_witness_complex.pyx'\n") + set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'subsampling', ") + #set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'tangential_complex', ") + #set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'alpha_complex', ") + #set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'euclidean_witness_complex', ") + #set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'euclidean_strong_witness_complex', ") endif () if(CGAL_FOUND) @@ -190,8 +194,6 @@ if(PYTHONINTERP_FOUND) # Generate setup.py file to cythonize Gudhi - This file must be named setup.py by convention configure_file(setup.py.in "${CMAKE_CURRENT_BINARY_DIR}/setup.py" @ONLY) - # Generate gudhi.pyx - Gudhi cython file - configure_file(gudhi.pyx.in "${CMAKE_CURRENT_BINARY_DIR}/gudhi.pyx" @ONLY) # Generate gudhi/__init__.py file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/gudhi") diff --git a/src/cython/gudhi/__init__.py.in b/src/cython/gudhi/__init__.py.in index 60ad7865..b2d2d3d7 100644 --- a/src/cython/gudhi/__init__.py.in +++ b/src/cython/gudhi/__init__.py.in @@ -10,7 +10,7 @@ from importlib import import_module - YYYY/MM Author: Description of the modification """ -__author__ = "Vincent Rouvreau" +__author__ = "GUDHI Editorial Board" __copyright__ = "Copyright (C) 2016 Inria" __license__ = "https://gudhi.inria.fr/licensing/" __version__ = "@GUDHI_VERSION@" diff --git a/src/cython/setup.py.in b/src/cython/setup.py.in index 3c37664f..fd4307e3 100644 --- a/src/cython/setup.py.in +++ b/src/cython/setup.py.in @@ -12,21 +12,33 @@ from numpy import get_include as numpy_get_include - YYYY/MM Author: Description of the modification """ -__author__ = "GUDHI Editorial Board" +__author__ = "Vincent Rouvreau" __copyright__ = "Copyright (C) 2016 Inria" __license__ = "MIT" -simplex_tree = Extension( - "gudhi.simplex_tree", - sources = ['@CMAKE_CURRENT_SOURCE_DIR@/gudhi/simplex_tree.pyx',], - language = 'c++', - extra_compile_args=[@GUDHI_CYTHON_EXTRA_COMPILE_ARGS@], - extra_link_args=[@GUDHI_CYTHON_EXTRA_LINK_ARGS@], - libraries=[@GUDHI_CYTHON_LIBRARIES@], - library_dirs=[@GUDHI_CYTHON_LIBRARY_DIRS@], - include_dirs = [numpy_get_include(), '@CMAKE_CURRENT_SOURCE_DIR@/gudhi/', @GUDHI_CYTHON_INCLUDE_DIRS@], - runtime_library_dirs=[@GUDHI_CYTHON_RUNTIME_LIBRARY_DIRS@], -) +modules = [@GUDHI_CYTHON_MODULES_TO_COMPILE@] + +source_dir='@CMAKE_CURRENT_SOURCE_DIR@/gudhi/' +extra_compile_args=[@GUDHI_CYTHON_EXTRA_COMPILE_ARGS@] +extra_link_args=[@GUDHI_CYTHON_EXTRA_LINK_ARGS@] +libraries=[@GUDHI_CYTHON_LIBRARIES@] +library_dirs=[@GUDHI_CYTHON_LIBRARY_DIRS@] +include_dirs = [numpy_get_include(), '@CMAKE_CURRENT_SOURCE_DIR@/gudhi/', @GUDHI_CYTHON_INCLUDE_DIRS@] +runtime_library_dirs=[@GUDHI_CYTHON_RUNTIME_LIBRARY_DIRS@] + +# Create ext_modules list from module list +ext_modules = [] +for module in modules: + ext_modules.append(Extension( + 'gudhi.' + module, + sources = [source_dir + module + '.pyx',], + language = 'c++', + extra_compile_args=extra_compile_args, + extra_link_args=extra_link_args, + libraries=libraries, + library_dirs=library_dirs, + include_dirs=include_dirs, + runtime_library_dirs=runtime_library_dirs,)) setup( name = 'gudhi', @@ -35,8 +47,7 @@ setup( author_email='gudhi-contact@lists.gforge.inria.fr', version='@GUDHI_VERSION@', url='http://gudhi.gforge.inria.fr/', - ext_modules = cythonize(simplex_tree), -# cmdclass={'build_ext': Cython.Build.build_ext}, + ext_modules = cythonize(ext_modules), install_requires = ['cython','numpy >= 1.9',], setup_requires = ['numpy >= 1.9',], ) -- cgit v1.2.3 From d7e1a3a81dfa91a29e433887fcfdc73310f8db32 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 7 Aug 2019 11:34:57 +0200 Subject: Add the rest of modules --- .gitignore | 5 ++++ src/cython/CMakeLists.txt | 16 +++++------ src/cython/gudhi.pyx.in | 33 ---------------------- .../gudhi/euclidean_strong_witness_complex.pyx | 14 ++++++--- src/cython/gudhi/euclidean_witness_complex.pyx | 14 ++++++--- src/cython/gudhi/nerve_gic.pyx | 12 ++++++-- src/cython/gudhi/tangential_complex.pyx | 3 -- 7 files changed, 42 insertions(+), 55 deletions(-) delete mode 100644 src/cython/gudhi.pyx.in diff --git a/.gitignore b/.gitignore index 2b1817a4..8f8a8e6d 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,11 @@ src/cython/gudhi/periodic_cubical_complex.cpp src/cython/gudhi/reader_utils.cpp src/cython/gudhi/rips_complex.cpp src/cython/gudhi/subsampling.cpp +src/cython/gudhi/euclidean_witness_complex.cpp +src/cython/gudhi/nerve_gic.cpp +src/cython/gudhi/strong_witness_complex.cpp +src/cython/gudhi/tangential_complex.cpp +src/cython/gudhi/witness_complex.cpp # Generated by tests data/points/COIL_database/lucky_cat.off_dist diff --git a/src/cython/CMakeLists.txt b/src/cython/CMakeLists.txt index 12eec9d9..dc0dd59d 100644 --- a/src/cython/CMakeLists.txt +++ b/src/cython/CMakeLists.txt @@ -100,18 +100,18 @@ if(PYTHONINTERP_FOUND) set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'cubical_complex', ") set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'periodic_cubical_complex', ") set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'reader_utils', ") - #set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'witness_complex', ") - #set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'strong_witness_complex', ") + set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'witness_complex', ") + set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'strong_witness_complex', ") if (NOT CGAL_VERSION VERSION_LESS 4.11.0) - #set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'bottleneck_distance', ") - #set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'nerve_gic', ") + set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'bottleneck_distance', ") + set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'nerve_gic', ") endif () if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0) set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'subsampling', ") - #set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'tangential_complex', ") - #set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'alpha_complex', ") - #set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'euclidean_witness_complex', ") - #set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'euclidean_strong_witness_complex', ") + set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'tangential_complex', ") + set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'alpha_complex', ") + set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'euclidean_witness_complex', ") + set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'euclidean_strong_witness_complex', ") endif () if(CGAL_FOUND) diff --git a/src/cython/gudhi.pyx.in b/src/cython/gudhi.pyx.in deleted file mode 100644 index 1c380308..00000000 --- a/src/cython/gudhi.pyx.in +++ /dev/null @@ -1,33 +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) 2016 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016-2019 Inria" -__license__ = "https://gudhi.inria.fr/licensing/" -__version__ = "@GUDHI_VERSION@" -# This variable is used by doctest to find files -__root_source_dir__ = "@CMAKE_SOURCE_DIR@" -__debug_info__ = @GUDHI_CYTHON_DEBUG_INFO@ - -include '@CMAKE_CURRENT_SOURCE_DIR@/cython/off_reader.pyx' -include '@CMAKE_CURRENT_SOURCE_DIR@/cython/simplex_tree.pyx' -include '@CMAKE_CURRENT_SOURCE_DIR@/cython/rips_complex.pyx' -include '@CMAKE_CURRENT_SOURCE_DIR@/cython/cubical_complex.pyx' -include '@CMAKE_CURRENT_SOURCE_DIR@/cython/periodic_cubical_complex.pyx' -include '@CMAKE_CURRENT_SOURCE_DIR@/cython/persistence_graphical_tools.py' -include '@CMAKE_CURRENT_SOURCE_DIR@/cython/reader_utils.pyx' -include '@CMAKE_CURRENT_SOURCE_DIR@/cython/witness_complex.pyx' -include '@CMAKE_CURRENT_SOURCE_DIR@/cython/strong_witness_complex.pyx' -@GUDHI_CYTHON_ALPHA_COMPLEX@ -@GUDHI_CYTHON_EUCLIDEAN_WITNESS_COMPLEX@ -@GUDHI_CYTHON_SUBSAMPLING@ -@GUDHI_CYTHON_TANGENTIAL_COMPLEX@ -@GUDHI_CYTHON_BOTTLENECK_DISTANCE@ -@GUDHI_CYTHON_NERVE_GIC@ diff --git a/src/cython/gudhi/euclidean_strong_witness_complex.pyx b/src/cython/gudhi/euclidean_strong_witness_complex.pyx index 26bd8375..465635c4 100644 --- a/src/cython/gudhi/euclidean_strong_witness_complex.pyx +++ b/src/cython/gudhi/euclidean_strong_witness_complex.pyx @@ -1,6 +1,10 @@ from cython cimport numeric from libcpp.vector cimport vector from libcpp.utility cimport pair +from libc.stdint cimport intptr_t + +from gudhi.simplex_tree cimport * +from gudhi.simplex_tree import SimplexTree """ 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. @@ -65,12 +69,14 @@ cdef class EuclideanStrongWitnessComplex: :returns: A simplex tree created from the Delaunay Triangulation. :rtype: SimplexTree """ - simplex_tree = SimplexTree() + stree = SimplexTree() + cdef intptr_t stree_int_ptr=stree.thisptr + cdef Simplex_tree_interface_full_featured* stree_ptr = stree_int_ptr if limit_dimension is not -1: - self.thisptr.create_simplex_tree(simplex_tree.thisptr, max_alpha_square, limit_dimension) + self.thisptr.create_simplex_tree(stree_ptr, max_alpha_square, limit_dimension) else: - self.thisptr.create_simplex_tree(simplex_tree.thisptr, max_alpha_square) - return simplex_tree + self.thisptr.create_simplex_tree(stree_ptr, max_alpha_square) + return stree def get_point(self, vertex): """This function returns the point corresponding to a given vertex. diff --git a/src/cython/gudhi/euclidean_witness_complex.pyx b/src/cython/gudhi/euclidean_witness_complex.pyx index e687c6f3..92d54eb5 100644 --- a/src/cython/gudhi/euclidean_witness_complex.pyx +++ b/src/cython/gudhi/euclidean_witness_complex.pyx @@ -1,6 +1,10 @@ from cython cimport numeric from libcpp.vector cimport vector from libcpp.utility cimport pair +from libc.stdint cimport intptr_t + +from gudhi.simplex_tree cimport * +from gudhi.simplex_tree import SimplexTree """ 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. @@ -65,12 +69,14 @@ cdef class EuclideanWitnessComplex: :returns: A simplex tree created from the Delaunay Triangulation. :rtype: SimplexTree """ - simplex_tree = SimplexTree() + stree = SimplexTree() + cdef intptr_t stree_int_ptr=stree.thisptr + cdef Simplex_tree_interface_full_featured* stree_ptr = stree_int_ptr if limit_dimension is not -1: - self.thisptr.create_simplex_tree(simplex_tree.thisptr, max_alpha_square, limit_dimension) + self.thisptr.create_simplex_tree(stree_ptr, max_alpha_square, limit_dimension) else: - self.thisptr.create_simplex_tree(simplex_tree.thisptr, max_alpha_square) - return simplex_tree + self.thisptr.create_simplex_tree(stree_ptr, max_alpha_square) + return stree def get_point(self, vertex): """This function returns the point corresponding to a given vertex. diff --git a/src/cython/gudhi/nerve_gic.pyx b/src/cython/gudhi/nerve_gic.pyx index 3c8f1200..9fec626f 100644 --- a/src/cython/gudhi/nerve_gic.pyx +++ b/src/cython/gudhi/nerve_gic.pyx @@ -4,6 +4,10 @@ from libcpp.utility cimport pair from libcpp.string cimport string from libcpp cimport bool import os +from libc.stdint cimport intptr_t + +from gudhi.simplex_tree cimport * +from gudhi.simplex_tree import SimplexTree """ 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. @@ -158,9 +162,11 @@ cdef class CoverComplex: :returns: A simplex tree created from the Cover complex. :rtype: SimplexTree """ - simplex_tree = SimplexTree() - self.thisptr.create_simplex_tree(simplex_tree.thisptr) - return simplex_tree + stree = SimplexTree() + cdef intptr_t stree_int_ptr=stree.thisptr + cdef Simplex_tree_interface_full_featured* stree_ptr = stree_int_ptr + self.thisptr.create_simplex_tree(stree_ptr) + return stree def find_simplices(self): """Computes the simplices of the simplicial complex. diff --git a/src/cython/gudhi/tangential_complex.pyx b/src/cython/gudhi/tangential_complex.pyx index b2d55520..9eb22115 100644 --- a/src/cython/gudhi/tangential_complex.pyx +++ b/src/cython/gudhi/tangential_complex.pyx @@ -147,9 +147,6 @@ cdef class TangentialComplex: cdef Simplex_tree_interface_full_featured* stree_ptr = stree_int_ptr self.thisptr.create_simplex_tree(stree_ptr) return stree - simplex_tree = SimplexTree() - self.thisptr.create_simplex_tree(simplex_tree.thisptr) - return simplex_tree def fix_inconsistencies_using_perturbation(self, max_perturb, time_limit=-1.0): """Attempts to fix inconsistencies by perturbing the point positions. -- cgit v1.2.3 From c85464b9ea96d21731e710fa7d7a15e645d2c89a Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 8 Aug 2019 10:44:30 +0200 Subject: Rename bottleneck_distance module name as bottleneck. Cannot have gudhi.bottleneck_distance.bottleneck_distance and gudhi.bottleneck_distance. --- .gitignore | 2 +- src/cython/CMakeLists.txt | 6 ++-- src/cython/gudhi/bottleneck.pyx | 49 ++++++++++++++++++++++++++++++++ src/cython/gudhi/bottleneck_distance.pyx | 49 -------------------------------- 4 files changed, 53 insertions(+), 53 deletions(-) create mode 100644 src/cython/gudhi/bottleneck.pyx delete mode 100644 src/cython/gudhi/bottleneck_distance.pyx diff --git a/.gitignore b/.gitignore index 8f8a8e6d..31efc180 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ build/ # Generated by Cython src/cython/gudhi/simplex_tree.cpp src/cython/gudhi/alpha_complex.cpp -src/cython/gudhi/bottleneck_distance.cpp +src/cython/gudhi/bottleneck.cpp src/cython/gudhi/cubical_complex.cpp src/cython/gudhi/euclidean_strong_witness_complex.cpp src/cython/gudhi/off_reader.cpp diff --git a/src/cython/CMakeLists.txt b/src/cython/CMakeLists.txt index dc0dd59d..6dc11400 100644 --- a/src/cython/CMakeLists.txt +++ b/src/cython/CMakeLists.txt @@ -42,8 +42,8 @@ if(PYTHONINTERP_FOUND) set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'reader_utils', ") set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'witness_complex', ") set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'strong_witness_complex', ") - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'persistence_graphical_tools' ") - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'bottleneck_distance', ") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'persistence_graphical_tools', ") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'bottleneck', ") set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'nerve_gic', ") set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'subsampling', ") set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'tangential_complex', ") @@ -103,7 +103,7 @@ if(PYTHONINTERP_FOUND) set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'witness_complex', ") set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'strong_witness_complex', ") if (NOT CGAL_VERSION VERSION_LESS 4.11.0) - set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'bottleneck_distance', ") + set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'bottleneck', ") set(GUDHI_CYTHON_MODULES_TO_COMPILE "${GUDHI_CYTHON_MODULES_TO_COMPILE}'nerve_gic', ") endif () if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0) diff --git a/src/cython/gudhi/bottleneck.pyx b/src/cython/gudhi/bottleneck.pyx new file mode 100644 index 00000000..4b378cbc --- /dev/null +++ b/src/cython/gudhi/bottleneck.pyx @@ -0,0 +1,49 @@ +from cython cimport numeric +from libcpp.vector cimport vector +from libcpp.utility cimport pair +import os + +""" 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) 2016 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 Inria" +__license__ = "GPL v3" + +cdef extern from "Bottleneck_distance_interface.h" namespace "Gudhi::persistence_diagram": + double bottleneck(vector[pair[double, double]], vector[pair[double, double]], double) + double bottleneck(vector[pair[double, double]], vector[pair[double, double]]) + +def bottleneck_distance(diagram_1, diagram_2, e=None): + """This function returns the point corresponding to a given vertex. + + :param diagram_1: The first diagram. + :type diagram_1: vector[pair[double, double]] + :param diagram_2: The second diagram. + :type diagram_2: vector[pair[double, double]] + :param e: If `e` is 0, this uses an expensive algorithm to compute the + exact distance. + If `e` is not 0, it asks for an additive `e`-approximation, and + currently also allows a small multiplicative error (the last 2 or 3 + bits of the mantissa may be wrong). This version of the algorithm takes + advantage of the limited precision of `double` and is usually a lot + faster to compute, whatever the value of `e`. + + Thus, by default, `e` is the smallest positive double. + :type e: float + :rtype: float + :returns: the bottleneck distance. + """ + if e is None: + # Default value is the smallest double value (not 0, 0 is for exact version) + return bottleneck(diagram_1, diagram_2) + else: + # Can be 0 for exact version + return bottleneck(diagram_1, diagram_2, e) diff --git a/src/cython/gudhi/bottleneck_distance.pyx b/src/cython/gudhi/bottleneck_distance.pyx deleted file mode 100644 index 4b378cbc..00000000 --- a/src/cython/gudhi/bottleneck_distance.pyx +++ /dev/null @@ -1,49 +0,0 @@ -from cython cimport numeric -from libcpp.vector cimport vector -from libcpp.utility cimport pair -import os - -""" 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) 2016 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 Inria" -__license__ = "GPL v3" - -cdef extern from "Bottleneck_distance_interface.h" namespace "Gudhi::persistence_diagram": - double bottleneck(vector[pair[double, double]], vector[pair[double, double]], double) - double bottleneck(vector[pair[double, double]], vector[pair[double, double]]) - -def bottleneck_distance(diagram_1, diagram_2, e=None): - """This function returns the point corresponding to a given vertex. - - :param diagram_1: The first diagram. - :type diagram_1: vector[pair[double, double]] - :param diagram_2: The second diagram. - :type diagram_2: vector[pair[double, double]] - :param e: If `e` is 0, this uses an expensive algorithm to compute the - exact distance. - If `e` is not 0, it asks for an additive `e`-approximation, and - currently also allows a small multiplicative error (the last 2 or 3 - bits of the mantissa may be wrong). This version of the algorithm takes - advantage of the limited precision of `double` and is usually a lot - faster to compute, whatever the value of `e`. - - Thus, by default, `e` is the smallest positive double. - :type e: float - :rtype: float - :returns: the bottleneck distance. - """ - if e is None: - # Default value is the smallest double value (not 0, 0 is for exact version) - return bottleneck(diagram_1, diagram_2) - else: - # Can be 0 for exact version - return bottleneck(diagram_1, diagram_2, e) -- cgit v1.2.3 From 5b2bbb23368313f4f1f4ff843d59071ab159b495 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 8 Aug 2019 11:28:20 +0200 Subject: Add persistence_graphical_tools mechanism --- src/cython/CMakeLists.txt | 4 +++- src/cython/gudhi/persistence_graphical_tools.py | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cython/CMakeLists.txt b/src/cython/CMakeLists.txt index 6dc11400..ab20c6e6 100644 --- a/src/cython/CMakeLists.txt +++ b/src/cython/CMakeLists.txt @@ -42,7 +42,6 @@ if(PYTHONINTERP_FOUND) set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'reader_utils', ") set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'witness_complex', ") set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'strong_witness_complex', ") - set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'persistence_graphical_tools', ") set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'bottleneck', ") set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'nerve_gic', ") set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'subsampling', ") @@ -199,6 +198,9 @@ if(PYTHONINTERP_FOUND) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/gudhi") configure_file("gudhi/__init__.py.in" "${CMAKE_CURRENT_BINARY_DIR}/gudhi/__init__.py" @ONLY) + # Other .py files + file(COPY "gudhi/persistence_graphical_tools.py" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/gudhi") + add_custom_command( OUTPUT gudhi.so WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} diff --git a/src/cython/gudhi/persistence_graphical_tools.py b/src/cython/gudhi/persistence_graphical_tools.py index 34803222..181bc8ea 100644 --- a/src/cython/gudhi/persistence_graphical_tools.py +++ b/src/cython/gudhi/persistence_graphical_tools.py @@ -2,6 +2,9 @@ from os import path from math import isfinite import numpy as np +from gudhi.reader_utils import read_persistence_intervals_in_dimension +from gudhi.reader_utils import read_persistence_intervals_grouped_by_dimension + """ 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, Bertrand Michel -- cgit v1.2.3 From d925d9aea81a60d149d7e2658c57658db4bf4deb Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 8 Aug 2019 16:28:09 +0200 Subject: try to debug windows bug --- .appveyor.yml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 31eb48d4..a962bea7 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -13,17 +13,17 @@ environment: APPVEYOR_SAVE_CACHE_ON_ERROR: true matrix: - - target: Examples - CMAKE_FLAGS: -DWITH_GUDHI_EXAMPLE=ON -DWITH_GUDHI_TEST=OFF -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=OFF - PYTHON: "C:\\Python37-x64" + # - target: Examples + # CMAKE_FLAGS: -DWITH_GUDHI_EXAMPLE=ON -DWITH_GUDHI_TEST=OFF -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=OFF + # PYTHON: "C:\\Python37-x64" - - target: UnitaryTests - CMAKE_FLAGS: -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_TEST=ON -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=OFF - PYTHON: "C:\\Python37-x64" + # - target: UnitaryTests + # CMAKE_FLAGS: -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_TEST=ON -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=OFF + # PYTHON: "C:\\Python37-x64" - - target: Utilities - CMAKE_FLAGS: -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_TEST=OFF -DWITH_GUDHI_UTILITIES=ON -DWITH_GUDHI_PYTHON=OFF - PYTHON: "C:\\Python37-x64" + # - target: Utilities + # CMAKE_FLAGS: -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_TEST=OFF -DWITH_GUDHI_UTILITIES=ON -DWITH_GUDHI_PYTHON=OFF + # PYTHON: "C:\\Python37-x64" - target: Python CMAKE_FLAGS: -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_TEST=OFF -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=ON -DGMP_INCLUDE_DIR="c:/Tools/vcpkg/installed/x64-windows/include" -DGMP_LIBRARIES="c:/Tools/vcpkg/installed/x64-windows/lib/mpir.lib" -DGMP_LIBRARIES_DIR="c:/Tools/vcpkg/installed/x64-windows/lib" @@ -56,7 +56,8 @@ build_script: - if [%target%]==[Python] ( cd src/cython & python setup.py install & - MSBuild RUN_TESTS.vcxproj + python -c "import gudhi; print('gudhi.__version__')" + #MSBuild RUN_TESTS.vcxproj ) else ( MSBuild GUDHIdev.sln /m /p:Configuration=Release /p:Platform=x64 & ctest -j 1 -C Release -E diff_files -- cgit v1.2.3 From 69a5dd0bcccf5cd4f5bdca6f6224a7d0e50f6304 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 8 Aug 2019 16:45:34 +0200 Subject: try to debug windows bug --- .appveyor.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index a962bea7..d02e543e 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -57,7 +57,6 @@ build_script: cd src/cython & python setup.py install & python -c "import gudhi; print('gudhi.__version__')" - #MSBuild RUN_TESTS.vcxproj ) else ( MSBuild GUDHIdev.sln /m /p:Configuration=Release /p:Platform=x64 & ctest -j 1 -C Release -E diff_files -- cgit v1.2.3 From 08a55d55f1e874dfaebe512838a0ef7046078522 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 8 Aug 2019 17:15:34 +0200 Subject: try to debug windows bug --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index d02e543e..35acfda2 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -56,7 +56,7 @@ build_script: - if [%target%]==[Python] ( cd src/cython & python setup.py install & - python -c "import gudhi; print('gudhi.__version__')" + python -c "import gudhi; print(gudhi.__version__)" ) else ( MSBuild GUDHIdev.sln /m /p:Configuration=Release /p:Platform=x64 & ctest -j 1 -C Release -E diff_files -- cgit v1.2.3 From ffff6615fe8e444f735767757f669f268542336e Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 8 Aug 2019 17:41:00 +0200 Subject: try to debug windows bug --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 35acfda2..e2a0fd29 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -56,7 +56,7 @@ build_script: - if [%target%]==[Python] ( cd src/cython & python setup.py install & - python -c "import gudhi; print(gudhi.__version__)" + ctest -j 1 ) else ( MSBuild GUDHIdev.sln /m /p:Configuration=Release /p:Platform=x64 & ctest -j 1 -C Release -E diff_files -- cgit v1.2.3 From 2a3423cb1fd5c666ad31c58c23bd394f3f13020d Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 8 Aug 2019 17:51:11 +0200 Subject: ctest requires -C on Windows --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index e2a0fd29..178c5297 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -56,7 +56,7 @@ build_script: - if [%target%]==[Python] ( cd src/cython & python setup.py install & - ctest -j 1 + ctest -j 1 -C Release ) else ( MSBuild GUDHIdev.sln /m /p:Configuration=Release /p:Platform=x64 & ctest -j 1 -C Release -E diff_files -- cgit v1.2.3 From 42776a519c13573c8a38fa71d6316576e0ee4780 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 9 Aug 2019 07:48:20 +0200 Subject: Add verbose for ctest --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 178c5297..6fb396e7 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -56,7 +56,7 @@ build_script: - if [%target%]==[Python] ( cd src/cython & python setup.py install & - ctest -j 1 -C Release + ctest -j 1 -C Release -V ) else ( MSBuild GUDHIdev.sln /m /p:Configuration=Release /p:Platform=x64 & ctest -j 1 -C Release -E diff_files -- cgit v1.2.3 From fe70d07a0e0669c3273165911d4236f956bb959d Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 9 Aug 2019 08:51:21 +0200 Subject: Try with cython.sln --- .appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 6fb396e7..662e5c10 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -55,8 +55,8 @@ build_script: - cmake -G "Visual Studio 15 2017 Win64" %CMAKE_FLAGS% -DCMAKE_TOOLCHAIN_FILE=c:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake .. - if [%target%]==[Python] ( cd src/cython & - python setup.py install & - ctest -j 1 -C Release -V + MSBuild Cython.sln /m /p:Configuration=Release /p:Platform=x64 & + ctest -j 1 -C Release -R test_simplex_tree_py_test -V ) else ( MSBuild GUDHIdev.sln /m /p:Configuration=Release /p:Platform=x64 & ctest -j 1 -C Release -E diff_files -- cgit v1.2.3 From 0f1be95b10de5998b0adb920aab0cc0a95881886 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 9 Aug 2019 08:59:46 +0200 Subject: Seems to work. try all tests --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 662e5c10..f625b384 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -56,7 +56,7 @@ build_script: - if [%target%]==[Python] ( cd src/cython & MSBuild Cython.sln /m /p:Configuration=Release /p:Platform=x64 & - ctest -j 1 -C Release -R test_simplex_tree_py_test -V + ctest -j 1 -C Release ) else ( MSBuild GUDHIdev.sln /m /p:Configuration=Release /p:Platform=x64 & ctest -j 1 -C Release -E diff_files -- cgit v1.2.3 From 51a38f313f633e1c593d77319f3752a010da782c Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 9 Aug 2019 09:20:18 +0200 Subject: Rollback comments as Python version works --- .appveyor.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index f625b384..ab943fb7 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -13,17 +13,17 @@ environment: APPVEYOR_SAVE_CACHE_ON_ERROR: true matrix: - # - target: Examples - # CMAKE_FLAGS: -DWITH_GUDHI_EXAMPLE=ON -DWITH_GUDHI_TEST=OFF -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=OFF - # PYTHON: "C:\\Python37-x64" + - target: Examples + CMAKE_FLAGS: -DWITH_GUDHI_EXAMPLE=ON -DWITH_GUDHI_TEST=OFF -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=OFF + PYTHON: "C:\\Python37-x64" - # - target: UnitaryTests - # CMAKE_FLAGS: -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_TEST=ON -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=OFF - # PYTHON: "C:\\Python37-x64" + - target: UnitaryTests + CMAKE_FLAGS: -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_TEST=ON -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=OFF + PYTHON: "C:\\Python37-x64" - # - target: Utilities - # CMAKE_FLAGS: -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_TEST=OFF -DWITH_GUDHI_UTILITIES=ON -DWITH_GUDHI_PYTHON=OFF - # PYTHON: "C:\\Python37-x64" + - target: Utilities + CMAKE_FLAGS: -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_TEST=OFF -DWITH_GUDHI_UTILITIES=ON -DWITH_GUDHI_PYTHON=OFF + PYTHON: "C:\\Python37-x64" - target: Python CMAKE_FLAGS: -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_TEST=OFF -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=ON -DGMP_INCLUDE_DIR="c:/Tools/vcpkg/installed/x64-windows/include" -DGMP_LIBRARIES="c:/Tools/vcpkg/installed/x64-windows/lib/mpir.lib" -DGMP_LIBRARIES_DIR="c:/Tools/vcpkg/installed/x64-windows/lib" -- cgit v1.2.3