summaryrefslogtreecommitdiff
path: root/src/cython
diff options
context:
space:
mode:
authorROUVREAU Vincent <vincent.rouvreau@inria.fr>2019-05-22 09:33:44 +0200
committerROUVREAU Vincent <vincent.rouvreau@inria.fr>2019-05-22 09:33:44 +0200
commit2927abe9a4b00bd291703340daaaed7bf20f3753 (patch)
tree156fc741c434c41fdff7c690eb8f354d582a9ff1 /src/cython
parent0e17d3cc8b89fc9fae4f358bb6a8cedaeaff6f0b (diff)
parent0c7d6ae4ddb68422e02a48b6a5575c176041d3e4 (diff)
Merge branch 'master' into simplex_tree_insert_duplicated_vertices_fix_vincent
Diffstat (limited to 'src/cython')
-rw-r--r--src/cython/CMakeLists.txt7
-rw-r--r--src/cython/cython/tangential_complex.pyx26
-rw-r--r--src/cython/doc/installation.rst56
-rw-r--r--src/cython/doc/rips_complex_user.rst4
-rw-r--r--src/cython/doc/tangential_complex_user.rst17
-rwxr-xr-xsrc/cython/example/tangential_complex_plain_homology_from_off_file_example.py1
-rw-r--r--src/cython/include/Rips_complex_interface.h13
-rw-r--r--src/cython/include/Tangential_complex_interface.h15
-rwxr-xr-xsrc/cython/test/test_tangential_complex.py9
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