diff options
author | ROUVREAU Vincent <vincent.rouvreau@inria.fr> | 2019-05-22 09:33:44 +0200 |
---|---|---|
committer | ROUVREAU Vincent <vincent.rouvreau@inria.fr> | 2019-05-22 09:33:44 +0200 |
commit | 2927abe9a4b00bd291703340daaaed7bf20f3753 (patch) | |
tree | 156fc741c434c41fdff7c690eb8f354d582a9ff1 /src/cython | |
parent | 0e17d3cc8b89fc9fae4f358bb6a8cedaeaff6f0b (diff) | |
parent | 0c7d6ae4ddb68422e02a48b6a5575c176041d3e4 (diff) |
Merge branch 'master' into simplex_tree_insert_duplicated_vertices_fix_vincent
Diffstat (limited to 'src/cython')
-rw-r--r-- | src/cython/CMakeLists.txt | 7 | ||||
-rw-r--r-- | src/cython/cython/tangential_complex.pyx | 26 | ||||
-rw-r--r-- | src/cython/doc/installation.rst | 56 | ||||
-rw-r--r-- | src/cython/doc/rips_complex_user.rst | 4 | ||||
-rw-r--r-- | src/cython/doc/tangential_complex_user.rst | 17 | ||||
-rwxr-xr-x | src/cython/example/tangential_complex_plain_homology_from_off_file_example.py | 1 | ||||
-rw-r--r-- | src/cython/include/Rips_complex_interface.h | 13 | ||||
-rw-r--r-- | src/cython/include/Tangential_complex_interface.h | 15 | ||||
-rwxr-xr-x | src/cython/test/test_tangential_complex.py | 9 |
9 files changed, 102 insertions, 46 deletions
diff --git a/src/cython/CMakeLists.txt b/src/cython/CMakeLists.txt index 97859c98..480332d7 100644 --- a/src/cython/CMakeLists.txt +++ b/src/cython/CMakeLists.txt @@ -215,12 +215,7 @@ if(PYTHONINTERP_FOUND) add_custom_target(cython ALL DEPENDS gudhi.so COMMENT "Do not forget to add ${CMAKE_CURRENT_BINARY_DIR}/ to your PYTHONPATH before using examples or tests") - # For installation purpose - # TODO(VR) : files matching pattern mechanism is copying all cython directory - install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" DESTINATION "${PYTHON_SITE_PACKAGES}/" FILES_MATCHING - PATTERN "*.so" - PATTERN "*.dylib" - PATTERN "*.pyd") + install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/setup.py install)") # Test examples if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1) diff --git a/src/cython/cython/tangential_complex.pyx b/src/cython/cython/tangential_complex.pyx index 4bb07076..293ef8cb 100644 --- a/src/cython/cython/tangential_complex.pyx +++ b/src/cython/cython/tangential_complex.pyx @@ -36,6 +36,7 @@ cdef extern from "Tangential_complex_interface.h" namespace "Gudhi": 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() @@ -43,6 +44,7 @@ cdef extern from "Tangential_complex_interface.h" namespace "Gudhi": 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: @@ -92,6 +94,17 @@ cdef class TangentialComplex: """ 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. @@ -152,3 +165,16 @@ cdef class TangentialComplex: """ 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/doc/installation.rst b/src/cython/doc/installation.rst index 040f6b4a..855dea44 100644 --- a/src/cython/doc/installation.rst +++ b/src/cython/doc/installation.rst @@ -7,24 +7,23 @@ Installation Compiling ********* -The library uses c++11 and requires `Boost <https://www.boost.org/>`_ ≥ 1.56.0 -and `CMake <https://www.cmake.org/>`_ ≥ 3.1. +The library uses c++11 and requires `Boost <https://www.boost.org/>`_ ≥ 1.56.0, +`CMake <https://www.cmake.org/>`_ ≥ 3.1 to generate makefiles, and +`Cython <https://www.cython.org/>`_ to compile the GUDHI Python module. It is a multi-platform library and compiles on Linux, Mac OSX and Visual Studio 2015. -It also requires cmake to generate makefiles, and cython to compile the -library. On `Windows <https://wiki.python.org/moin/WindowsCompilers>`_ , only Python 3.5 and 3.6 are available because of the required Visual Studio version. -On other systems, if you have several Python/cython installed, the version 2.X +On other systems, if you have several Python/Cython installed, the version 2.X will be used by default, but you can force it by adding :code:`-DPython_ADDITIONAL_VERSIONS=3` to the cmake command. -GUDHI Cythonization -=================== +GUDHI Python module compilation +=============================== -To build the GUDHI cython module, run the following commands in a terminal: +To build the GUDHI Python module, run the following commands in a terminal: .. code-block:: bash @@ -32,7 +31,28 @@ To build the GUDHI cython module, run the following commands in a terminal: mkdir build cd build/ cmake .. - make cython + cd cython + make + +GUDHI Python module installation +================================ + +Once the compilation succeeds, one can add the GUDHI Python module path to the +PYTHONPATH: + +.. code-block:: bash + + # For windows, you have to set PYTHONPATH environment variable + export PYTHONPATH='$PYTHONPATH:/path-to-gudhi/build/cython' + +Or install it definitely in your Python packages folder: + +.. code-block:: bash + + cd /path-to-gudhi/build/cython + # May require sudo or administrator privileges + make install + Test suites =========== @@ -45,7 +65,7 @@ following command in a terminal: cd /path-to-gudhi/build/cython # For windows, you have to set PYTHONPATH environment variable export PYTHONPATH='$PYTHONPATH:/path-to-gudhi/build/cython' - ctest -R py_test + make test Debugging issues ================ @@ -54,7 +74,7 @@ If tests fail, please check your PYTHONPATH and try to :code:`import gudhi` and check the errors. The problem can come from a third-party library bad link or installation. -If :code:`import gudhi` succeeds, please have a look to debug informations: +If :code:`import gudhi` succeeds, please have a look to debug information: .. code-block:: python @@ -105,13 +125,17 @@ A complete configuration would be : Documentation ============= -To build the documentation, `sphinx-doc <http://http://www.sphinx-doc.org>`_ is -required. Please refer to *conf.py* file to see which -`sphinx-doc <http://http://www.sphinx-doc.org>`_ modules are required to -generate the documentation. Run the following commands in a terminal: +To build the documentation, `sphinx-doc <http://www.sphinx-doc.org>`_ and +`sphinxcontrib-bibtex <https://sphinxcontrib-bibtex.readthedocs.io>`_ are +required. As the documentation is auto-tested, `CGAL`_, `Eigen3`_, +`Matplotlib`_, `NumPy`_ and `SciPy`_ are also mandatory to build the +documentation. + +Run the following commands in a terminal: .. code-block:: bash + cd /path-to-gudhi/build/cython make sphinx Optional third-party library @@ -127,7 +151,7 @@ The :doc:`Alpha complex </alpha_complex_user>`, C++ library which provides easy access to efficient and reliable geometric algorithms. -Having CGAL, the Computational Geometry Algorithms Library, version 4.7.0 or +Having CGAL, the Computational Geometry Algorithms Library, version 4.7.0 or higher installed is recommended. The procedure to install this library according to your operating system is detailed `here <http://doc.cgal.org/latest/Manual/installation.html>`_. diff --git a/src/cython/doc/rips_complex_user.rst b/src/cython/doc/rips_complex_user.rst index e814b4c3..1d340dbe 100644 --- a/src/cython/doc/rips_complex_user.rst +++ b/src/cython/doc/rips_complex_user.rst @@ -50,8 +50,8 @@ by more than the length used to define "too close". A more general technique is to use a sparse approximation of the Rips introduced by Don Sheehy :cite:`sheehy13linear`. We are using the version described in :cite:`buchet16efficient` (except that we multiply all filtration -values by 2, to match the usual Rips complex), which proves a -:math:`\frac{1+\varepsilon}{1-\varepsilon}`-interleaving, although in practice the +values by 2, to match the usual Rips complex). :cite:`cavanna15geometric` proves +a :math:`\frac{1}{1-\varepsilon}`-interleaving, although in practice the error is usually smaller. A more intuitive presentation of the idea is available in :cite:`cavanna15geometric`, and in a video :cite:`cavanna15visualizing`. Passing an extra argument `sparse=0.3` at the diff --git a/src/cython/doc/tangential_complex_user.rst b/src/cython/doc/tangential_complex_user.rst index 5ce69e86..ebfe1e29 100644 --- a/src/cython/doc/tangential_complex_user.rst +++ b/src/cython/doc/tangential_complex_user.rst @@ -23,8 +23,10 @@ What is a Tangential Complex? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Let us start with the description of the Tangential complex of a simple -example, with :math:`k = 1` and :math:`d = 2`. The input data is 4 points -:math:`P` located on a curve embedded in 2D. +example, with :math:`k = 1` and :math:`d = 2`. The point set +:math:`\mathscr P` is located on a closed curve embedded in 2D. +Only 4 points will be displayed (more are required for PCA) to simplify the +figures. .. figure:: ../../doc/Tangential_complex/tc_example_01.png :alt: The input @@ -32,8 +34,7 @@ example, with :math:`k = 1` and :math:`d = 2`. The input data is 4 points The input -For each point :math:`p`, estimate its tangent subspace :math:`T_p` (e.g. -using PCA). +For each point :math:`P`, estimate its tangent subspace :math:`T_P` using PCA. .. figure:: ../../doc/Tangential_complex/tc_example_02.png :alt: The estimated normals @@ -43,8 +44,8 @@ using PCA). Let us add the Voronoi diagram of the points in orange. For each point -:math:`p`, construct its star in the Delaunay triangulation of :math:`P` -restricted to :math:`T_p`. +:math:`P`, construct its star in the Delaunay triangulation of +:math:`\mathscr P` restricted to :math:`T_P`. .. figure:: ../../doc/Tangential_complex/tc_example_03.png :alt: The Voronoi diagram @@ -72,7 +73,7 @@ Let us take the same example. Before -Let us slightly move the tangent subspace :math:`T_q` +Let us slightly move the tangent subspace :math:`T_Q` .. figure:: ../../doc/Tangential_complex/tc_example_07_after.png :alt: After @@ -128,6 +129,7 @@ This example builds the Tangential complex of point set read in an OFF file. import gudhi tc = gudhi.TangentialComplex(intrisic_dim = 1, off_file=gudhi.__root_source_dir__ + '/data/points/alphacomplexdoc.off') + tc.compute_tangential_complex() result_str = 'Tangential contains ' + repr(tc.num_simplices()) + \ ' simplices - ' + repr(tc.num_vertices()) + ' vertices.' print(result_str) @@ -175,6 +177,7 @@ simplices. import gudhi tc = gudhi.TangentialComplex(intrisic_dim = 1, points=[[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]]) + tc.compute_tangential_complex() result_str = 'Tangential contains ' + repr(tc.num_vertices()) + ' vertices.' print(result_str) diff --git a/src/cython/example/tangential_complex_plain_homology_from_off_file_example.py b/src/cython/example/tangential_complex_plain_homology_from_off_file_example.py index 0f8f5e80..536517d1 100755 --- a/src/cython/example/tangential_complex_plain_homology_from_off_file_example.py +++ b/src/cython/example/tangential_complex_plain_homology_from_off_file_example.py @@ -50,6 +50,7 @@ with open(args.file, 'r') as f: print("TangentialComplex creation from points read in a OFF file") tc = gudhi.TangentialComplex(intrisic_dim = args.intrisic_dim, off_file=args.file) + tc.compute_tangential_complex() st = tc.create_simplex_tree() message = "Number of simplices=" + repr(st.num_simplices()) diff --git a/src/cython/include/Rips_complex_interface.h b/src/cython/include/Rips_complex_interface.h index 1a6e2477..40aff299 100644 --- a/src/cython/include/Rips_complex_interface.h +++ b/src/cython/include/Rips_complex_interface.h @@ -54,23 +54,17 @@ class Rips_complex_interface { } void init_points_sparse(const std::vector<std::vector<double>>& points, double threshold, double epsilon) { - sparse_rips_complex_.emplace(points, Gudhi::Euclidean_distance(), epsilon); - threshold_ = threshold; + sparse_rips_complex_.emplace(points, Gudhi::Euclidean_distance(), epsilon, -std::numeric_limits<double>::infinity(), threshold); } void init_matrix_sparse(const std::vector<std::vector<double>>& matrix, double threshold, double epsilon) { - sparse_rips_complex_.emplace(matrix, epsilon); - threshold_ = threshold; + sparse_rips_complex_.emplace(matrix, epsilon, -std::numeric_limits<double>::infinity(), threshold); } void create_simplex_tree(Simplex_tree_interface<>* simplex_tree, int dim_max) { if (rips_complex_) rips_complex_->create_complex(*simplex_tree, dim_max); - else { + else sparse_rips_complex_->create_complex(*simplex_tree, dim_max); - // This pruning should be done much earlier! It isn't that useful for sparse Rips, - // but it would be inconsistent not to do it. - simplex_tree->prune_above_filtration(threshold_); - } simplex_tree->initialize_filtration(); } @@ -79,7 +73,6 @@ class Rips_complex_interface { // Anyway, storing a graph would make more sense. Or changing the interface completely so there is no such storage. boost::optional<Rips_complex<Simplex_tree_interface<>::Filtration_value>> rips_complex_; boost::optional<Sparse_rips_complex<Simplex_tree_interface<>::Filtration_value>> sparse_rips_complex_; - double threshold_; }; } // namespace rips_complex diff --git a/src/cython/include/Tangential_complex_interface.h b/src/cython/include/Tangential_complex_interface.h index 71418886..c4ddbdbe 100644 --- a/src/cython/include/Tangential_complex_interface.h +++ b/src/cython/include/Tangential_complex_interface.h @@ -49,8 +49,6 @@ class Tangential_complex_interface { Dynamic_kernel k; tangential_complex_ = new TC(points, intrisic_dim, k); - tangential_complex_->compute_tangential_complex(); - num_inconsistencies_ = tangential_complex_->number_of_inconsistent_simplices(); } Tangential_complex_interface(int intrisic_dim, const std::string& off_file_name, bool from_file = true) { @@ -60,14 +58,17 @@ class Tangential_complex_interface { std::vector<Point_d> points = off_reader.get_point_cloud(); tangential_complex_ = new TC(points, intrisic_dim, k); - tangential_complex_->compute_tangential_complex(); - num_inconsistencies_ = tangential_complex_->number_of_inconsistent_simplices(); } ~Tangential_complex_interface() { delete tangential_complex_; } + void compute_tangential_complex() { + tangential_complex_->compute_tangential_complex(); + num_inconsistencies_ = tangential_complex_->number_of_inconsistent_simplices(); + } + std::vector<double> get_point(unsigned vh) { std::vector<double> vd; if (vh < tangential_complex_->number_of_vertices()) { @@ -104,7 +105,11 @@ class Tangential_complex_interface { simplex_tree->initialize_filtration(); } - private: + void set_max_squared_edge_length(double max_squared_edge_length) { + tangential_complex_->set_max_squared_edge_length(max_squared_edge_length); + } + +private: TC* tangential_complex_; TC::Num_inconsistencies num_inconsistencies_; }; diff --git a/src/cython/test/test_tangential_complex.py b/src/cython/test/test_tangential_complex.py index 5385a0d3..5c62f278 100755 --- a/src/cython/test/test_tangential_complex.py +++ b/src/cython/test/test_tangential_complex.py @@ -32,6 +32,15 @@ def test_tangential(): tc = TangentialComplex(intrisic_dim = 1, points=point_list) assert tc.__is_defined() == True assert tc.num_vertices() == 4 + assert tc.num_simplices() == 0 + assert tc.num_inconsistent_simplices() == 0 + assert tc.num_inconsistent_stars() == 0 + + tc.compute_tangential_complex() + assert tc.num_vertices() == 4 + assert tc.num_simplices() == 4 + assert tc.num_inconsistent_simplices() == 0 + assert tc.num_inconsistent_stars() == 0 st = tc.create_simplex_tree() assert st.__is_defined() == True |