summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorvrouvrea <vrouvrea@636b058d-ea47-450e-bf9e-a15bfbe3eedb>2018-11-14 07:10:50 +0000
committervrouvrea <vrouvrea@636b058d-ea47-450e-bf9e-a15bfbe3eedb>2018-11-14 07:10:50 +0000
commitbf7fcb97a34875107bf249c3d0c42cb3b1b27544 (patch)
treee7ec1bf9cced8234012ed8f4aa931bc6f268bcbf /src
parent5f4229227fe747ce08b1f296596343d9fdf79535 (diff)
parent65d609bbf5d688552ad0f5535b6c42abffe27a1f (diff)
Merge last trunk modifications
git-svn-id: svn+ssh://scm.gforge.inria.fr/svnroot/gudhi/branches/simplex_tree_fix_vincent@3976 636b058d-ea47-450e-bf9e-a15bfbe3eedb Former-commit-id: b246c9007b06ed57d59dc1d18b02262d9c765fb9
Diffstat (limited to 'src')
-rw-r--r--src/Alpha_complex/utilities/alphacomplex.md4
-rw-r--r--src/Bottleneck_distance/utilities/bottleneckdistance.md2
-rw-r--r--src/CMakeLists.txt12
-rw-r--r--src/GudhUI/CMakeLists.txt81
-rw-r--r--src/Nerve_GIC/include/gudhi/GIC.h88
-rw-r--r--src/Rips_complex/doc/Intro_rips_complex.h7
-rw-r--r--src/Rips_complex/utilities/ripscomplex.md4
-rw-r--r--src/Simplex_tree/include/gudhi/Simplex_tree.h6
-rw-r--r--src/Witness_complex/utilities/witnesscomplex.md2
-rw-r--r--src/cmake/modules/GUDHI_compilation_flags.cmake13
-rw-r--r--src/cmake/modules/GUDHI_doxygen_target.cmake8
-rw-r--r--src/cmake/modules/GUDHI_modules.cmake5
-rw-r--r--src/cmake/modules/GUDHI_third_party_libraries.cmake11
-rw-r--r--src/common/doc/installation.h4
-rw-r--r--src/cython/CMakeLists.txt686
-rw-r--r--src/cython/cython/nerve_gic.pyx30
-rw-r--r--[-rwxr-xr-x]src/cython/cython/persistence_graphical_tools.py310
-rw-r--r--src/cython/cython/rips_complex.pyx56
-rw-r--r--src/cython/cython/simplex_tree.pyx14
-rw-r--r--src/cython/doc/examples.rst1
-rw-r--r--src/cython/doc/installation.rst11
-rw-r--r--src/cython/doc/nerve_gic_complex_sum.rst2
-rw-r--r--src/cython/doc/persistence_graphical_tools_ref.rst1
-rw-r--r--src/cython/doc/persistence_graphical_tools_sum.inc4
-rw-r--r--src/cython/doc/persistence_graphical_tools_user.rst37
-rw-r--r--src/cython/doc/rips_complex_sum.inc6
-rw-r--r--src/cython/doc/rips_complex_user.rst67
-rwxr-xr-xsrc/cython/example/sparse_rips_persistence_diagram.py43
-rw-r--r--src/cython/include/Alpha_complex_interface.h2
-rw-r--r--src/cython/include/Rips_complex_interface.h41
-rwxr-xr-xsrc/cython/test/test_rips_complex.py20
31 files changed, 1008 insertions, 570 deletions
diff --git a/src/Alpha_complex/utilities/alphacomplex.md b/src/Alpha_complex/utilities/alphacomplex.md
index 0fe98837..b1a33e4b 100644
--- a/src/Alpha_complex/utilities/alphacomplex.md
+++ b/src/Alpha_complex/utilities/alphacomplex.md
@@ -143,7 +143,7 @@ where
* `<input OFF file>` is the path to the input point cloud in [nOFF ASCII format](http://www.geomview.org/docs/html/OFF.html).
* `<cuboid file>` is the path to the file describing the periodic domain. It must be in the format described
-[here](/doc/latest/fileformats.html#FileFormatsIsoCuboid).
+[here]({{ site.officialurl }}/doc/latest/fileformats.html#FileFormatsIsoCuboid).
**Allowed options**
@@ -161,5 +161,5 @@ periodic_alpha_complex_3d_persistence ../../data/points/grid_10_10_10_in_0_1.off
N.B.:
-* Cuboid file must be in the format described [here](/doc/latest/fileformats.html#FileFormatsIsoCuboid).
+* Cuboid file must be in the format described [here]({{ site.officialurl }}/doc/latest/fileformats.html#FileFormatsIsoCuboid).
* Filtration values are alpha square values.
diff --git a/src/Bottleneck_distance/utilities/bottleneckdistance.md b/src/Bottleneck_distance/utilities/bottleneckdistance.md
index 939eb911..a81426cf 100644
--- a/src/Bottleneck_distance/utilities/bottleneckdistance.md
+++ b/src/Bottleneck_distance/utilities/bottleneckdistance.md
@@ -22,5 +22,5 @@ This program computes the Bottleneck distance between two persistence diagram fi
where
-* `<file_1.pers>` and `<file_2.pers>` must be in the format described [here](/doc/latest/fileformats.html#FileFormatsPers).
+* `<file_1.pers>` and `<file_2.pers>` must be in the format described [here]({{ site.officialurl }}/doc/latest/fileformats.html#FileFormatsPers).
* `<tolerance>` is an error bound on the bottleneck distance (set by default to the smallest positive double value).
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6c446104..b40d506a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -6,6 +6,9 @@ include(CMakeGUDHIVersion.txt)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules/")
+set(GUDHI_MODULES "" CACHE INTERNAL "GUDHI_MODULES")
+set(GUDHI_MISSING_MODULES "" CACHE INTERNAL "GUDHI_MISSING_MODULES")
+
# This variable is used by Cython CMakeLists.txt and by GUDHI_third_party_libraries to know its path
set(GUDHI_CYTHON_PATH "cython")
@@ -35,8 +38,6 @@ add_gudhi_module(Tangential_complex)
add_gudhi_module(Witness_complex)
add_gudhi_module(Nerve_GIC)
-message("++ GUDHI_MODULES list is:\"${GUDHI_MODULES}\"")
-
# For "make doxygen" - Requires GUDHI_USER_VERSION_DIR to be set
set(GUDHI_USER_VERSION_DIR ${CMAKE_SOURCE_DIR})
include(GUDHI_doxygen_target)
@@ -60,7 +61,14 @@ add_subdirectory(GudhUI)
if (WITH_GUDHI_PYTHON)
# specific for cython module
add_subdirectory(${GUDHI_CYTHON_PATH})
+else()
+ message("++ Python module will not be compiled because WITH_GUDHI_PYTHON is set to OFF")
+ set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python")
endif()
+
+message("++ GUDHI_MODULES list is:\"${GUDHI_MODULES}\"")
+message("++ GUDHI_MISSING_MODULES list is:\"${GUDHI_MISSING_MODULES}\"")
+
#---------------------------------------------------------------------------------------
#---------------------------------------------------------------------------------------
diff --git a/src/GudhUI/CMakeLists.txt b/src/GudhUI/CMakeLists.txt
index b357b8f7..0945e758 100644
--- a/src/GudhUI/CMakeLists.txt
+++ b/src/GudhUI/CMakeLists.txt
@@ -1,40 +1,55 @@
project(GudhUI)
# Need to find OpenGL first as find_package(Qt5) tries to #include"GL/gl.h" on some platforms
-find_package(OpenGL)
+find_package(OpenGL QUIET)
if (OPENGL_FOUND)
- find_package(Qt5 COMPONENTS Widgets Xml OpenGL)
- find_package(QGLViewer)
-
- if ( CGAL_FOUND AND Qt5_FOUND AND QGLVIEWER_FOUND AND NOT CGAL_VERSION VERSION_EQUAL 4.8.0)
-
- set(CMAKE_AUTOMOC ON)
- set(CMAKE_AUTOUIC ON)
- set(CMAKE_INCLUDE_CURRENT_DIR ON)
-
- SET(Boost_USE_STATIC_LIBS ON)
- SET(Boost_USE_MULTITHREAD OFF)
- include_directories (${QGLVIEWER_INCLUDE_DIR})
-
- add_executable ( GudhUI
- gui/gudhui.cpp
- gui/MainWindow.cpp
- gui/Menu_k_nearest_neighbors.cpp
- gui/Menu_uniform_neighbors.cpp
- gui/Menu_edge_contraction.cpp
- gui/Menu_persistence.cpp
- view/Viewer_instructor.cpp
- view/Viewer.cpp
- )
- target_link_libraries( GudhUI Qt5::Widgets Qt5::Xml Qt5::OpenGL )
- target_link_libraries( GudhUI ${QGLVIEWER_LIBRARIES} )
- target_link_libraries( GudhUI ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} )
- if (TBB_FOUND)
- target_link_libraries( GudhUI ${TBB_LIBRARIES})
+ find_package(Qt5 COMPONENTS Widgets Xml OpenGL QUIET)
+ if (Qt5_FOUND)
+ find_package(QGLViewer QUIET)
+ if ( QGLVIEWER_FOUND)
+
+ if ( CGAL_FOUND AND NOT CGAL_VERSION VERSION_EQUAL 4.8.0)
+ set(CMAKE_AUTOMOC ON)
+ set(CMAKE_AUTOUIC ON)
+ set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+ SET(Boost_USE_STATIC_LIBS ON)
+ SET(Boost_USE_MULTITHREAD OFF)
+ include_directories (${QGLVIEWER_INCLUDE_DIR})
+
+ add_executable ( GudhUI
+ gui/gudhui.cpp
+ gui/MainWindow.cpp
+ gui/Menu_k_nearest_neighbors.cpp
+ gui/Menu_uniform_neighbors.cpp
+ gui/Menu_edge_contraction.cpp
+ gui/Menu_persistence.cpp
+ view/Viewer_instructor.cpp
+ view/Viewer.cpp
+ )
+ target_link_libraries( GudhUI Qt5::Widgets Qt5::Xml Qt5::OpenGL )
+ target_link_libraries( GudhUI ${QGLVIEWER_LIBRARIES} )
+ target_link_libraries( GudhUI ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} )
+ if (TBB_FOUND)
+ target_link_libraries( GudhUI ${TBB_LIBRARIES})
+ endif()
+
+ install(TARGETS GudhUI DESTINATION bin)
+ set(GUDHI_MODULES ${GUDHI_MODULES} "GudhUI" CACHE INTERNAL "GUDHI_MODULES")
+ else()
+ message("++ GudhUI will not be compiled because CGAL < 4.8.0 or not found")
+ set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "GudhUI" CACHE INTERNAL "GUDHI_MISSING_MODULES")
+ endif()
+ else()
+ message("++ GudhUI will not be compiled because QGLViewer is not found")
+ set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "GudhUI" CACHE INTERNAL "GUDHI_MISSING_MODULES")
endif()
-
- install(TARGETS GudhUI DESTINATION bin)
-
+ else()
+ message("++ GudhUI will not be compiled because Qt5 COMPONENTS Widgets Xml OpenGL are not found")
+ set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "GudhUI" CACHE INTERNAL "GUDHI_MISSING_MODULES")
endif()
-endif(OPENGL_FOUND)
+else()
+ message("++ GudhUI will not be compiled because OpenGL is not found")
+ set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "GudhUI" CACHE INTERNAL "GUDHI_MISSING_MODULES")
+endif()
diff --git a/src/Nerve_GIC/include/gudhi/GIC.h b/src/Nerve_GIC/include/gudhi/GIC.h
index fea0b861..30f89d65 100644
--- a/src/Nerve_GIC/include/gudhi/GIC.h
+++ b/src/Nerve_GIC/include/gudhi/GIC.h
@@ -226,7 +226,25 @@ class Cover_complex {
void set_mask(int nodemask) { mask = nodemask; }
public:
- /** \brief Reads and stores the input point cloud.
+
+
+ /** \brief Reads and stores the input point cloud from vector stored in memory.
+ *
+ * @param[in] cloud input vector representing the point cloud. Each row is a point and each coordinate is a vector.
+ *
+ */
+ template <class InputRange>
+ void set_point_cloud_from_range(InputRange const & cloud) {
+ n = cloud.size(); data_dimension = cloud[0].size(); point_cloud_name = "matrix";
+ for(int i = 0; i < n; i++){
+ point_cloud.emplace_back(cloud[i].begin(), cloud[i].begin() + data_dimension);
+ boost::add_vertex(one_skeleton_OFF);
+ vertices.push_back(boost::add_vertex(one_skeleton));
+ cover.emplace_back();
+ }
+ }
+
+ /** \brief Reads and stores the input point cloud from .(n)OFF file.
*
* @param[in] off_file_name name of the input .OFF or .nOFF file.
*
@@ -371,6 +389,28 @@ class Cover_complex {
distances[index[boost::source(*ei, one_skeleton)]][index[boost::target(*ei, one_skeleton)]]);
}
+ public:
+ /** \brief Reads and stores the distance matrices from vector stored in memory.
+ *
+ * @param[in] distance_matrix input vector representing the distance matrix.
+ *
+ */
+ template <class InputRange>
+ void set_distances_from_range(InputRange const & distance_matrix) {
+ if(point_cloud.size() == 0){
+ n = distance_matrix.size();
+ point_cloud_name = "matrix";
+ data_dimension = 0;
+ for(int i = 0; i < n; i++){
+ point_cloud.emplace_back();
+ boost::add_vertex(one_skeleton_OFF);
+ vertices.push_back(boost::add_vertex(one_skeleton));
+ cover.emplace_back();
+ }
+ }
+ distances = distance_matrix;
+ }
+
public: // Pairwise distances.
/** \private \brief Computes all pairwise distances.
*/
@@ -500,9 +540,17 @@ class Cover_complex {
*
*/
void set_function_from_coordinate(int k) {
- for (int i = 0; i < n; i++) func.push_back(point_cloud[i][k]);
- functional_cover = true;
- cover_name = "coordinate " + std::to_string(k);
+ if(point_cloud[0].size() > 0){
+ for (int i = 0; i < n; i++) func.push_back(point_cloud[i][k]);
+ functional_cover = true;
+ cover_name = "coordinate " + std::to_string(k);
+ }
+ else{
+ std::cout << "Only pairwise distances provided---cannot access " << k << "th coordinate; returning null vector instead" << std::endl;
+ for (int i = 0; i < n; i++) func.push_back(0.0);
+ functional_cover = true;
+ cover_name = "null";
+ }
}
public: // Set function from vector.
@@ -953,9 +1001,17 @@ class Cover_complex {
*
*/
void set_color_from_coordinate(int k = 0) {
- for (int i = 0; i < n; i++) func_color.push_back(point_cloud[i][k]);
- color_name = "coordinate ";
- color_name.append(std::to_string(k));
+ if(point_cloud[0].size() > 0){
+ for (int i = 0; i < n; i++) func_color.push_back(point_cloud[i][k]);
+ color_name = "coordinate ";
+ color_name.append(std::to_string(k));
+ }
+ else{
+ std::cout << "Only pairwise distances provided---cannot access " << k << "th coordinate; returning null vector instead" << std::endl;
+ for (int i = 0; i < n; i++) func.push_back(0.0);
+ functional_cover = true;
+ cover_name = "null";
+ }
}
public: // Set color from vector.
@@ -964,7 +1020,7 @@ class Cover_complex {
* @param[in] color input vector of values.
*
*/
- void set_color_from_vector(std::vector<double> color) {
+ void set_color_from_range(std::vector<double> color) {
for (unsigned int i = 0; i < color.size(); i++) func_color.push_back(color[i]);
}
@@ -1108,7 +1164,7 @@ class Cover_complex {
/** \brief Computes the extended persistence diagram of the complex.
*
*/
- void compute_PD() {
+ Persistence_diagram compute_PD() {
Simplex_tree st;
// Compute max and min
@@ -1121,15 +1177,18 @@ class Cover_complex {
// Build filtration
for (auto const& simplex : simplices) {
- std::vector<int> splx = simplex; splx.push_back(-2);
+ std::vector<int> splx = simplex;
+ splx.push_back(-2);
st.insert_simplex_and_subfaces(splx, -3);
}
for (std::map<int, double>::iterator it = cover_std.begin(); it != cover_std.end(); it++) {
int vertex = it->first; float val = it->second;
int vert[] = {vertex}; int edge[] = {vertex, -2};
- st.assign_filtration(st.find(vert), -2 + (val - minf)/(maxf - minf));
- st.assign_filtration(st.find(edge), 2 - (val - minf)/(maxf - minf));
+ if(st.find(vert) != st.null_simplex()){
+ st.assign_filtration(st.find(vert), -2 + (val - minf)/(maxf - minf));
+ st.assign_filtration(st.find(edge), 2 - (val - minf)/(maxf - minf));
+ }
}
st.make_filtration_non_decreasing();
@@ -1159,6 +1218,7 @@ class Cover_complex {
if (verbose) std::cout << " [" << birth << ", " << death << "]" << std::endl;
}
}
+ return PD;
}
public:
@@ -1184,7 +1244,7 @@ class Cover_complex {
Cboot.point_cloud.push_back(this->point_cloud[id]); Cboot.cover.emplace_back(); Cboot.func.push_back(this->func[id]);
boost::add_vertex(Cboot.one_skeleton_OFF); Cboot.vertices.push_back(boost::add_vertex(Cboot.one_skeleton));
}
- Cboot.set_color_from_vector(Cboot.func);
+ Cboot.set_color_from_range(Cboot.func);
for (int j = 0; j < n; j++) {
std::vector<double> dist(n);
@@ -1230,7 +1290,7 @@ class Cover_complex {
unsigned int N = distribution.size();
double level = 1;
for (unsigned int i = 0; i < N; i++)
- if (distribution[i] > d){ level = i * 1.0 / N; break; }
+ if (distribution[i] >= d){ level = i * 1.0 / N; break; }
if (verbose) std::cout << "Confidence level of distance " << d << " is " << level << std::endl;
return level;
}
diff --git a/src/Rips_complex/doc/Intro_rips_complex.h b/src/Rips_complex/doc/Intro_rips_complex.h
index 712d3b6e..a2537036 100644
--- a/src/Rips_complex/doc/Intro_rips_complex.h
+++ b/src/Rips_complex/doc/Intro_rips_complex.h
@@ -39,7 +39,7 @@ namespace rips_complex {
* <a target="_blank" href="https://en.wikipedia.org/wiki/Vietoris%E2%80%93Rips_complex">(Wikipedia)</a>
* is an abstract simplicial complex
* defined on a finite metric space, where each simplex corresponds to a subset
- * of point whose diameter is smaller that some given threshold.
+ * of points whose diameter is smaller that some given threshold.
* Varying the threshold, we can also see the Rips complex as a filtration of
* the \f$(n-1)-\f$dimensional simplex, where the filtration value of each
* simplex is the diameter of the corresponding subset of points.
@@ -53,7 +53,10 @@ namespace rips_complex {
* The number of simplices in the full Rips complex is exponential in the
* number of vertices, it is thus usually restricted, by excluding all the
* simplices with filtration value larger than some threshold, and keeping only
- * the dim_max-skeleton.
+ * the dim_max-skeleton. It may also be a good idea to start by making the
+ * point set sparser, for instance with
+ * `Gudhi::subsampling::sparsify_point_set()`, since small clusters of points
+ * have a disproportionate cost without affecting the persistence diagram much.
*
* In order to build this complex, the algorithm first builds the graph.
* The filtration value of each edge is computed from a user-given distance
diff --git a/src/Rips_complex/utilities/ripscomplex.md b/src/Rips_complex/utilities/ripscomplex.md
index 6df49310..108cdd50 100644
--- a/src/Rips_complex/utilities/ripscomplex.md
+++ b/src/Rips_complex/utilities/ripscomplex.md
@@ -85,7 +85,7 @@ properly, this is a known issue.
## sparse_rips_persistence ##
This program computes the persistent homology with coefficient field *Z/pZ*
-of a sparse (1+epsilon)-approximation of the Rips complex defined on a set of input Euclidean points. The output diagram contains one bar per line, written with the convention:
+of a sparse (1+epsilon)/(1-epsilon)-approximation of the Rips complex defined on a set of input Euclidean points. The output diagram contains one bar per line, written with the convention:
`p dim birth death`
@@ -99,7 +99,7 @@ where `dim` is the dimension of the homological feature, `birth` and `death` are
* `-h [ --help ]` Produce help message
* `-o [ --output-file ]` Name of file in which the persistence diagram is written. Default print in standard output.
-* `-e [ --approximation ]` (default = .5) Epsilon, where the sparse Rips complex is a (1+epsilon)-approximation of the Rips complex.
+* `-e [ --approximation ]` (default = .5) Epsilon, where the sparse Rips complex is a (1+epsilon)/(1-epsilon)-approximation of the Rips complex.
* `-d [ --cpx-dimension ]` (default = 1) Maximal dimension of the Rips complex we want to compute.
* `-p [ --field-charac ]` (default = 11) Characteristic p of the coefficient field Z/pZ for computing homology.
* `-m [ --min-persistence ]` (default = 0) Minimal lifetime of homology feature to be recorded. Enter a negative value to see zero length intervals.
diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree.h b/src/Simplex_tree/include/gudhi/Simplex_tree.h
index 4df4e529..13d7372c 100644
--- a/src/Simplex_tree/include/gudhi/Simplex_tree.h
+++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h
@@ -1116,6 +1116,7 @@ class Simplex_tree {
* The Simplex_tree must contain no simplex of dimension bigger than
* 1 when calling the method. */
void expansion(int max_dim) {
+ if (max_dim <= 1) return;
dimension_ = max_dim;
for (Dictionary_it root_it = root_.members_.begin();
root_it != root_.members_.end(); ++root_it) {
@@ -1138,7 +1139,10 @@ class Simplex_tree {
Dictionary_it next = siblings->members().begin();
++next;
- thread_local std::vector<std::pair<Vertex_handle, Node> > inter;
+#ifdef GUDHI_CAN_USE_CXX11_THREAD_LOCAL
+ thread_local
+#endif // GUDHI_CAN_USE_CXX11_THREAD_LOCAL
+ std::vector<std::pair<Vertex_handle, Node> > inter;
for (Dictionary_it s_h = siblings->members().begin();
s_h != siblings->members().end(); ++s_h, ++next) {
Simplex_handle root_sh = find_vertex(s_h->first);
diff --git a/src/Witness_complex/utilities/witnesscomplex.md b/src/Witness_complex/utilities/witnesscomplex.md
index da453cce..7ea397b9 100644
--- a/src/Witness_complex/utilities/witnesscomplex.md
+++ b/src/Witness_complex/utilities/witnesscomplex.md
@@ -10,7 +10,7 @@ Leave the lines above as it is required by the web site generator 'Jekyll'
{:/comment}
-For more details about the witness complex, please read the [user manual of the package](/doc/latest/group__witness__complex.html).
+For more details about the witness complex, please read the [user manual of the package]({{ site.officialurl }}/doc/latest/group__witness__complex.html).
## weak_witness_persistence ##
This program computes the persistent homology with coefficient field *Z/pZ* of a Weak witness complex defined on a set of input points.
diff --git a/src/cmake/modules/GUDHI_compilation_flags.cmake b/src/cmake/modules/GUDHI_compilation_flags.cmake
index a01d6e13..86cd531b 100644
--- a/src/cmake/modules/GUDHI_compilation_flags.cmake
+++ b/src/cmake/modules/GUDHI_compilation_flags.cmake
@@ -5,7 +5,7 @@ include(CheckCXXSourceCompiles)
# add a compiler flag only if it is accepted
macro(add_cxx_compiler_flag _flag)
- string(REPLACE "-" "_" _flag_var ${_flag})
+ string(REPLACE "-" "_" "/" _flag_var ${_flag})
check_cxx_accepts_flag("${_flag}" CXX_COMPILER_${_flag_var}_OK)
if(CXX_COMPILER_${_flag_var}_OK)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_flag}")
@@ -43,12 +43,15 @@ set (CMAKE_CXX_STANDARD 11)
enable_testing()
if(MSVC)
- # Turn off some VC++ warnings
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267 /wd4668 /wd4311 /wd4800 /wd4820 /wd4503 /wd4244 /wd4345 /wd4996 /wd4396 /wd4018")
+ add_cxx_compiler_flag("/W3")
+else()
+ add_cxx_compiler_flag("-Wall")
+ # Only for dev version
+ if(PROJECT_NAME STREQUAL "GUDHIdev")
+ add_cxx_compiler_flag("-pedantic")
+ endif()
endif()
-add_cxx_compiler_flag("-Wall")
-
if (DEBUG_TRACES)
# For programs to be more verbose
message(STATUS "DEBUG_TRACES are activated")
diff --git a/src/cmake/modules/GUDHI_doxygen_target.cmake b/src/cmake/modules/GUDHI_doxygen_target.cmake
index 9e10e566..7a84c4e0 100644
--- a/src/cmake/modules/GUDHI_doxygen_target.cmake
+++ b/src/cmake/modules/GUDHI_doxygen_target.cmake
@@ -1,7 +1,7 @@
# add a target to generate API documentation with Doxygen
-find_package(Doxygen)
+find_package(Doxygen QUIET)
if(DOXYGEN_FOUND)
- # configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
+ set(GUDHI_MODULES ${GUDHI_MODULES} "cpp-documentation" CACHE INTERNAL "GUDHI_MODULES")
# starting from cmake 3.9 the usage of DOXYGEN_EXECUTABLE is deprecated
if(TARGET Doxygen::doxygen)
@@ -16,4 +16,6 @@ if(DOXYGEN_FOUND)
# In dev version, doxygen target depends on user_version target. Not existing in user version
add_dependencies(doxygen user_version)
endif()
-endif(DOXYGEN_FOUND)
+else()
+ set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "cpp-documentation" CACHE INTERNAL "GUDHI_MISSING_MODULES")
+endif()
diff --git a/src/cmake/modules/GUDHI_modules.cmake b/src/cmake/modules/GUDHI_modules.cmake
index f95d0c34..aab1dd08 100644
--- a/src/cmake/modules/GUDHI_modules.cmake
+++ b/src/cmake/modules/GUDHI_modules.cmake
@@ -1,11 +1,12 @@
# A function to add a new module in GUDHI
-set(GUDHI_MODULES "")
set(GUDHI_MODULES_FULL_LIST "")
function(add_gudhi_module file_path)
option("WITH_MODULE_GUDHI_${file_path}" "Activate/desactivate ${file_path} compilation and installation" ON)
if (WITH_MODULE_GUDHI_${file_path})
- set(GUDHI_MODULES ${GUDHI_MODULES} ${file_path} PARENT_SCOPE)
+ set(GUDHI_MODULES ${GUDHI_MODULES} ${file_path} CACHE INTERNAL "GUDHI_MODULES")
+ else()
+ set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} ${file_path} CACHE INTERNAL "GUDHI_MISSING_MODULES")
endif()
# Required by user_version
set(GUDHI_MODULES_FULL_LIST ${GUDHI_MODULES_FULL_LIST} ${file_path} PARENT_SCOPE)
diff --git a/src/cmake/modules/GUDHI_third_party_libraries.cmake b/src/cmake/modules/GUDHI_third_party_libraries.cmake
index f03c2177..cde3725c 100644
--- a/src/cmake/modules/GUDHI_third_party_libraries.cmake
+++ b/src/cmake/modules/GUDHI_third_party_libraries.cmake
@@ -1,6 +1,6 @@
# This files manage third party libraries required by GUDHI
-find_package(Boost 1.48.0 REQUIRED COMPONENTS system filesystem unit_test_framework program_options thread)
+find_package(Boost 1.56.0 REQUIRED COMPONENTS system filesystem unit_test_framework program_options thread)
if(NOT Boost_FOUND)
message(FATAL_ERROR "NOTICE: This program requires Boost and will not be compiled.")
@@ -21,11 +21,11 @@ endif()
# A fix would be to use https://cmake.org/cmake/help/v3.1/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.html
# or even better https://cmake.org/cmake/help/v3.1/variable/CMAKE_CXX_STANDARD.html
# but it implies to use cmake version 3.1 at least.
-find_package(CGAL)
+find_package(CGAL QUIET)
# Only CGAL versions > 4.4 supports what Gudhi uses from CGAL
if (CGAL_VERSION VERSION_LESS 4.4.0)
- message("CGAL version ${CGAL_VERSION} is considered too old to be used by Gudhi.")
+ message("++ CGAL version ${CGAL_VERSION} is considered too old to be used by Gudhi.")
unset(CGAL_FOUND)
endif()
if(CGAL_FOUND)
@@ -127,6 +127,10 @@ function( find_python_module PYTHON_MODULE_NAME )
RESULT_VARIABLE PYTHON_MODULE_RESULT
OUTPUT_VARIABLE PYTHON_MODULE_VERSION
ERROR_VARIABLE PYTHON_MODULE_ERROR)
+ message ("PYTHON_MODULE_NAME = ${PYTHON_MODULE_NAME}
+ - PYTHON_MODULE_RESULT = ${PYTHON_MODULE_RESULT}
+ - PYTHON_MODULE_VERSION = ${PYTHON_MODULE_VERSION}
+ - PYTHON_MODULE_ERROR = ${PYTHON_MODULE_ERROR}")
if(PYTHON_MODULE_RESULT EQUAL 0)
# Remove carriage return
string(STRIP ${PYTHON_MODULE_VERSION} PYTHON_MODULE_VERSION)
@@ -143,6 +147,7 @@ if( PYTHONINTERP_FOUND )
find_python_module("pytest")
find_python_module("matplotlib")
find_python_module("numpy")
+ find_python_module("scipy")
endif()
if(NOT GUDHI_CYTHON_PATH)
diff --git a/src/common/doc/installation.h b/src/common/doc/installation.h
index c27e4f56..bf2d0a87 100644
--- a/src/common/doc/installation.h
+++ b/src/common/doc/installation.h
@@ -5,7 +5,7 @@
* Examples of GUDHI headers inclusion can be found in \ref utilities.
*
* \section compiling Compiling
- * The library uses c++11 and requires <a target="_blank" href="http://www.boost.org/">Boost</a> &ge; 1.48.0
+ * The library uses c++11 and requires <a target="_blank" href="http://www.boost.org/">Boost</a> &ge; 1.56.0
* and <a target="_blank" href="https://www.cmake.org/">CMake</a> &ge; 3.1.
* It is a multi-platform library and compiles on Linux, Mac OSX and Visual Studio 2015.
*
@@ -18,7 +18,7 @@ cmake ..
make \endverbatim
* By default, examples are disabled. You can activate their compilation with
* <a href="https://cmake.org/cmake/help/v3.0/manual/ccmake.1.html">ccmake</a> (on Linux and Mac OSX),
- * <a href="https://cmake.org/cmake/help/v3.0/manual/cmake-gui.1.html">cmake-gui</a> (on Windows) or y mofifying the
+ * <a href="https://cmake.org/cmake/help/v3.0/manual/cmake-gui.1.html">cmake-gui</a> (on Windows) or by modifying the
* cmake command as follows :
\verbatim cmake -DWITH_GUDHI_EXAMPLE=ON ..
make \endverbatim
diff --git a/src/cython/CMakeLists.txt b/src/cython/CMakeLists.txt
index 1849a6ec..dc2e9278 100644
--- a/src/cython/CMakeLists.txt
+++ b/src/cython/CMakeLists.txt
@@ -31,362 +31,414 @@ 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 )
-
-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;")
-
- add_gudhi_debug_info("Python version ${PYTHON_VERSION_STRING}")
- add_gudhi_debug_info("Cython version ${CYTHON_VERSION}")
- if(PYTEST_FOUND)
- add_gudhi_debug_info("Pytest version ${PYTEST_VERSION}")
- endif()
- if(MATPLOTLIB_FOUND)
- add_gudhi_debug_info("Matplotlib version ${MATPLOTLIB_VERSION}")
- endif()
- if(NUMPY_FOUND)
- add_gudhi_debug_info("Numpy version ${NUMPY_VERSION}")
- endif()
- if(MATPLOTLIB_FOUND AND NUMPY_FOUND)
+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;")
- 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', ")
- set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DBOOST_ALL_NO_LIB', ")
- set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DBOOST_SYSTEM_NO_DEPRECATED', ")
-
- # Gudhi and CGAL compilation option
- if(MSVC)
- set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'/fp:strict', ")
- else(MSVC)
- set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-std=c++11', ")
- endif(MSVC)
- if(CMAKE_COMPILER_IS_GNUCXX)
- set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-frounding-math', ")
- endif(CMAKE_COMPILER_IS_GNUCXX)
- if (CMAKE_CXX_COMPILER_ID MATCHES Intel)
- set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-fp-model strict', ")
- endif(CMAKE_CXX_COMPILER_ID MATCHES Intel)
- if (DEBUG_TRACES)
- # For programs to be more verbose
- set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DDEBUG_TRACES', ")
- endif()
+ 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;")
+
+ add_gudhi_debug_info("Python version ${PYTHON_VERSION_STRING}")
+ add_gudhi_debug_info("Cython version ${CYTHON_VERSION}")
+ if(PYTEST_FOUND)
+ add_gudhi_debug_info("Pytest version ${PYTEST_VERSION}")
+ endif()
+ if(MATPLOTLIB_FOUND)
+ add_gudhi_debug_info("Matplotlib version ${MATPLOTLIB_VERSION}")
+ endif()
+ if(NUMPY_FOUND)
+ add_gudhi_debug_info("Numpy version ${NUMPY_VERSION}")
+ endif()
+ 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()
- if (EIGEN3_FOUND)
- add_gudhi_debug_info("Eigen3 version ${EIGEN3_VERSION}")
- # No problem, even if no CGAL found
- set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DCGAL_EIGEN3_ENABLED', ")
- endif (EIGEN3_FOUND)
-
- if (NOT CGAL_VERSION VERSION_LESS 4.8.1)
- 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.8.1)
- 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.7.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.6.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()
+ 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', ")
+ set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DBOOST_ALL_NO_LIB', ")
+ set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DBOOST_SYSTEM_NO_DEPRECATED', ")
+
+ # Gudhi and CGAL compilation option
+ if(MSVC)
+ set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'/fp:strict', ")
+ else(MSVC)
+ set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-std=c++11', ")
+ endif(MSVC)
+ if(CMAKE_COMPILER_IS_GNUCXX)
+ set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-frounding-math', ")
+ endif(CMAKE_COMPILER_IS_GNUCXX)
+ if (CMAKE_CXX_COMPILER_ID MATCHES Intel)
+ set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-fp-model strict', ")
+ endif(CMAKE_CXX_COMPILER_ID MATCHES Intel)
+ if (DEBUG_TRACES)
+ # For programs to be more verbose
+ set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DDEBUG_TRACES', ")
+ endif()
- if(CGAL_FOUND)
- can_cgal_use_cxx11_thread_local()
- if (NOT CGAL_CAN_USE_CXX11_THREAD_LOCAL_RESULT)
- add_gudhi_cython_lib(${Boost_THREAD_LIBRARY})
- set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${Boost_LIBRARY_DIRS}', ")
+ if (EIGEN3_FOUND)
+ add_gudhi_debug_info("Eigen3 version ${EIGEN3_VERSION}")
+ # No problem, even if no CGAL found
+ set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DCGAL_EIGEN3_ENABLED', ")
+ endif (EIGEN3_FOUND)
+
+ if (NOT CGAL_VERSION VERSION_LESS 4.8.1)
+ 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.8.1)
+ 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.7.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.6.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()
- # Add CGAL compilation args
- if(CGAL_HEADER_ONLY)
- add_gudhi_debug_info("CGAL header only version ${CGAL_VERSION}")
- set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DCGAL_HEADER_ONLY', ")
- else(CGAL_HEADER_ONLY)
- add_gudhi_debug_info("CGAL version ${CGAL_VERSION}")
- add_gudhi_cython_lib(${CGAL_LIBRARY})
- set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${CGAL_LIBRARIES_DIR}', ")
- # If CGAL is not header only, CGAL library may link with boost system,
- add_gudhi_cython_lib(${Boost_SYSTEM_LIBRARY})
- set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${Boost_LIBRARY_DIRS}', ")
- endif(CGAL_HEADER_ONLY)
- # GMP and GMPXX are not required, but if present, CGAL will link with them.
- if(GMP_FOUND)
- add_gudhi_debug_info("GMP_LIBRARIES = ${GMP_LIBRARIES}")
- set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DCGAL_USE_GMP', ")
- add_gudhi_cython_lib(${GMP_LIBRARIES})
- set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${GMP_LIBRARIES_DIR}', ")
- if(GMPXX_FOUND)
- add_gudhi_debug_info("GMPXX_LIBRARIES = ${GMPXX_LIBRARIES}")
- set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DCGAL_USE_GMPXX', ")
- add_gudhi_cython_lib(${GMPXX_LIBRARIES})
- set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${GMPXX_LIBRARIES_DIR}', ")
- endif(GMPXX_FOUND)
- endif(GMP_FOUND)
- endif(CGAL_FOUND)
-
- # Specific for Mac
- if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
- set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-mmacosx-version-min=10.12', ")
- set(GUDHI_CYTHON_EXTRA_LINK_ARGS "${GUDHI_CYTHON_EXTRA_LINK_ARGS}'-mmacosx-version-min=10.12', ")
- endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
-
- # Loop on INCLUDE_DIRECTORIES PROPERTY
- get_property(GUDHI_INCLUDE_DIRECTORIES DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
- foreach(GUDHI_INCLUDE_DIRECTORY ${GUDHI_INCLUDE_DIRECTORIES})
- set(GUDHI_CYTHON_INCLUDE_DIRS "${GUDHI_CYTHON_INCLUDE_DIRS}'${GUDHI_INCLUDE_DIRECTORY}', ")
- endforeach()
- set(GUDHI_CYTHON_INCLUDE_DIRS "${GUDHI_CYTHON_INCLUDE_DIRS}'${CMAKE_SOURCE_DIR}/${GUDHI_CYTHON_PATH}/include', ")
-
- if (TBB_FOUND AND WITH_GUDHI_USE_TBB)
- add_gudhi_debug_info("TBB version ${TBB_INTERFACE_VERSION} found and used")
- set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DGUDHI_USE_TBB', ")
- add_gudhi_cython_lib(${TBB_RELEASE_LIBRARY})
- add_gudhi_cython_lib(${TBB_MALLOC_RELEASE_LIBRARY})
- set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${TBB_LIBRARY_DIRS}', ")
- set(GUDHI_CYTHON_INCLUDE_DIRS "${GUDHI_CYTHON_INCLUDE_DIRS}'${TBB_INCLUDE_DIRS}', ")
- endif()
- if(UNIX)
- set( GUDHI_CYTHON_RUNTIME_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}")
- endif(UNIX)
-
- # 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)
-
- add_custom_command(
- OUTPUT gudhi.so
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/setup.py" "build_ext" "--inplace")
-
- 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")
-
- # Test examples
- if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1)
- # Bottleneck and Alpha
- add_test(NAME alpha_rips_persistence_bottleneck_distance_py_test
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/alpha_rips_persistence_bottleneck_distance.py"
- -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -t 0.15 -d 3)
+ if(CGAL_FOUND)
+ can_cgal_use_cxx11_thread_local()
+ if (NOT CGAL_CAN_USE_CXX11_THREAD_LOCAL_RESULT)
+ if(CMAKE_BUILD_TYPE MATCHES Debug)
+ add_gudhi_cython_lib("${Boost_THREAD_LIBRARY_DEBUG}")
+ else()
+ add_gudhi_cython_lib("${Boost_THREAD_LIBRARY_RELEASE}")
+ endif()
+ set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${Boost_LIBRARY_DIRS}', ")
+ endif()
+ # Add CGAL compilation args
+ if(CGAL_HEADER_ONLY)
+ add_gudhi_debug_info("CGAL header only version ${CGAL_VERSION}")
+ set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DCGAL_HEADER_ONLY', ")
+ else(CGAL_HEADER_ONLY)
+ add_gudhi_debug_info("CGAL version ${CGAL_VERSION}")
+ add_gudhi_cython_lib("${CGAL_LIBRARY}")
+ set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${CGAL_LIBRARIES_DIR}', ")
+ # If CGAL is not header only, CGAL library may link with boost system,
+ if(CMAKE_BUILD_TYPE MATCHES Debug)
+ add_gudhi_cython_lib("${Boost_SYSTEM_LIBRARY_DEBUG}")
+ else()
+ add_gudhi_cython_lib("${Boost_SYSTEM_LIBRARY_RELEASE}")
+ endif()
+ set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${Boost_LIBRARY_DIRS}', ")
+ endif(CGAL_HEADER_ONLY)
+ # GMP and GMPXX are not required, but if present, CGAL will link with them.
+ if(GMP_FOUND)
+ add_gudhi_debug_info("GMP_LIBRARIES = ${GMP_LIBRARIES}")
+ set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DCGAL_USE_GMP', ")
+ add_gudhi_cython_lib("${GMP_LIBRARIES}")
+ set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${GMP_LIBRARIES_DIR}', ")
+ if(GMPXX_FOUND)
+ add_gudhi_debug_info("GMPXX_LIBRARIES = ${GMPXX_LIBRARIES}")
+ set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DCGAL_USE_GMPXX', ")
+ add_gudhi_cython_lib("${GMPXX_LIBRARIES}")
+ set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${GMPXX_LIBRARIES_DIR}', ")
+ endif(GMPXX_FOUND)
+ endif(GMP_FOUND)
+ endif(CGAL_FOUND)
+
+ # Specific for Mac
+ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-mmacosx-version-min=10.12', ")
+ set(GUDHI_CYTHON_EXTRA_LINK_ARGS "${GUDHI_CYTHON_EXTRA_LINK_ARGS}'-mmacosx-version-min=10.12', ")
+ endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+
+ # Loop on INCLUDE_DIRECTORIES PROPERTY
+ get_property(GUDHI_INCLUDE_DIRECTORIES DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
+ foreach(GUDHI_INCLUDE_DIRECTORY ${GUDHI_INCLUDE_DIRECTORIES})
+ set(GUDHI_CYTHON_INCLUDE_DIRS "${GUDHI_CYTHON_INCLUDE_DIRS}'${GUDHI_INCLUDE_DIRECTORY}', ")
+ endforeach()
+ set(GUDHI_CYTHON_INCLUDE_DIRS "${GUDHI_CYTHON_INCLUDE_DIRS}'${CMAKE_SOURCE_DIR}/${GUDHI_CYTHON_PATH}/include', ")
+
+ if (TBB_FOUND AND WITH_GUDHI_USE_TBB)
+ add_gudhi_debug_info("TBB version ${TBB_INTERFACE_VERSION} found and used")
+ set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DGUDHI_USE_TBB', ")
+ if(CMAKE_BUILD_TYPE MATCHES Debug)
+ add_gudhi_cython_lib("${TBB_DEBUG_LIBRARY}")
+ add_gudhi_cython_lib("${TBB_MALLOC_DEBUG_LIBRARY}")
+ else()
+ add_gudhi_cython_lib("${TBB_RELEASE_LIBRARY}")
+ add_gudhi_cython_lib("${TBB_MALLOC_RELEASE_LIBRARY}")
+ endif()
+ set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${TBB_LIBRARY_DIRS}', ")
+ set(GUDHI_CYTHON_INCLUDE_DIRS "${GUDHI_CYTHON_INCLUDE_DIRS}'${TBB_INCLUDE_DIRS}', ")
+ endif()
- if(MATPLOTLIB_FOUND AND NUMPY_FOUND)
- # Tangential
- add_test(NAME tangential_complex_plain_homology_from_off_file_example_py_test
+ if(UNIX)
+ set( GUDHI_CYTHON_RUNTIME_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}")
+ endif(UNIX)
+
+ # 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)
+
+ add_custom_command(
+ OUTPUT gudhi.so
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/setup.py" "build_ext" "--inplace")
+
+ 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")
+
+ # Test examples
+ if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1)
+ # Bottleneck and Alpha
+ add_test(NAME alpha_rips_persistence_bottleneck_distance_py_test
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
+ ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/alpha_rips_persistence_bottleneck_distance.py"
+ -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -t 0.15 -d 3)
+
+ if(MATPLOTLIB_FOUND AND NUMPY_FOUND)
+ # Tangential
+ add_test(NAME tangential_complex_plain_homology_from_off_file_example_py_test
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
+ ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/tangential_complex_plain_homology_from_off_file_example.py"
+ --no-diagram -i 2 -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off)
+
+ add_gudhi_py_test(test_tangential_complex)
+
+ # Witness complex AND Subsampling
+ add_test(NAME euclidean_strong_witness_complex_diagram_persistence_from_off_file_example_py_test
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
+ ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py"
+ --no-diagram -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -a 1.0 -n 20 -d 2)
+
+ add_test(NAME euclidean_witness_complex_diagram_persistence_from_off_file_example_py_test
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
+ ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/euclidean_witness_complex_diagram_persistence_from_off_file_example.py"
+ --no-diagram -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -a 1.0 -n 20 -d 2)
+ endif()
+
+ # Subsampling
+ add_gudhi_py_test(test_subsampling)
+
+ endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1)
+ if (NOT CGAL_VERSION VERSION_LESS 4.8.1)
+ # Bottleneck
+ add_test(NAME bottleneck_basic_example_py_test
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/tangential_complex_plain_homology_from_off_file_example.py"
- --no-diagram -i 2 -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off)
+ ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/bottleneck_basic_example.py")
- add_gudhi_py_test(test_tangential_complex)
+ add_gudhi_py_test(test_bottleneck_distance)
- # Witness complex AND Subsampling
- add_test(NAME euclidean_strong_witness_complex_diagram_persistence_from_off_file_example_py_test
+ # Cover complex
+ file(COPY ${CMAKE_SOURCE_DIR}/data/points/human.off DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
+ file(COPY ${CMAKE_SOURCE_DIR}/data/points/COIL_database/lucky_cat.off DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
+ file(COPY ${CMAKE_SOURCE_DIR}/data/points/COIL_database/lucky_cat_PCA1 DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
+ add_test(NAME cover_complex_nerve_example_py_test
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py"
- --no-diagram -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -a 1.0 -n 20 -d 2)
+ ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/nerve_of_a_covering.py"
+ -f human.off -c 2 -r 10 -g 0.3)
- add_test(NAME euclidean_witness_complex_diagram_persistence_from_off_file_example_py_test
+ add_test(NAME cover_complex_coordinate_gic_example_py_test
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/euclidean_witness_complex_diagram_persistence_from_off_file_example.py"
- --no-diagram -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -a 1.0 -n 20 -d 2)
- endif()
+ ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/coordinate_graph_induced_complex.py"
+ -f human.off -c 0 -v)
- # Subsampling
- add_gudhi_py_test(test_subsampling)
+ add_test(NAME cover_complex_functional_gic_example_py_test
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
+ ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/functional_graph_induced_complex.py"
+ -o lucky_cat.off
+ -f lucky_cat_PCA1 -v)
- endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1)
- if (NOT CGAL_VERSION VERSION_LESS 4.8.1)
- # Bottleneck
- add_test(NAME bottleneck_basic_example_py_test
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/bottleneck_basic_example.py")
+ add_test(NAME cover_complex_voronoi_gic_example_py_test
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
+ ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/voronoi_graph_induced_complex.py"
+ -f human.off -n 700 -v)
- add_gudhi_py_test(test_bottleneck_distance)
+ add_gudhi_py_test(test_cover_complex)
+ endif (NOT CGAL_VERSION VERSION_LESS 4.8.1)
- # Cover complex
- file(COPY ${CMAKE_SOURCE_DIR}/data/points/human.off DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
- file(COPY ${CMAKE_SOURCE_DIR}/data/points/COIL_database/lucky_cat.off DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
- file(COPY ${CMAKE_SOURCE_DIR}/data/points/COIL_database/lucky_cat_PCA1 DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
- add_test(NAME cover_complex_nerve_example_py_test
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/nerve_of_a_covering.py"
- -f human.off -c 2 -r 10 -g 0.3)
+ if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0)
+ # Alpha
+ add_test(NAME alpha_complex_from_points_example_py_test
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
+ ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/alpha_complex_from_points_example.py")
- add_test(NAME cover_complex_coordinate_gic_example_py_test
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/coordinate_graph_induced_complex.py"
- -f human.off -c 0 -v)
+ if(MATPLOTLIB_FOUND AND NUMPY_FOUND)
+ add_test(NAME alpha_complex_diagram_persistence_from_off_file_example_py_test
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
+ ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/alpha_complex_diagram_persistence_from_off_file_example.py"
+ --no-diagram -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -a 0.6)
+ endif()
- add_test(NAME cover_complex_functional_gic_example_py_test
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/functional_graph_induced_complex.py"
- -o lucky_cat.off
- -f lucky_cat_PCA1 -v)
+ add_gudhi_py_test(test_alpha_complex)
- add_test(NAME cover_complex_voronoi_gic_example_py_test
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/voronoi_graph_induced_complex.py"
- -f human.off -n 700 -v)
+ endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0)
- add_gudhi_py_test(test_cover_complex)
- endif (NOT CGAL_VERSION VERSION_LESS 4.8.1)
+ if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.6.0)
+ # Euclidean witness
+ add_gudhi_py_test(test_euclidean_witness_complex)
- if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0)
- # Alpha
- add_test(NAME alpha_complex_from_points_example_py_test
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/alpha_complex_from_points_example.py")
+ endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.6.0)
- if(MATPLOTLIB_FOUND AND NUMPY_FOUND)
- add_test(NAME alpha_complex_diagram_persistence_from_off_file_example_py_test
+ # Cubical
+ add_test(NAME periodic_cubical_complex_barcode_persistence_from_perseus_file_example_py_test
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/alpha_complex_diagram_persistence_from_off_file_example.py"
- --no-diagram -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -a 0.6)
- endif()
+ ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/periodic_cubical_complex_barcode_persistence_from_perseus_file_example.py"
+ --no-barcode -f ${CMAKE_SOURCE_DIR}/data/bitmap/CubicalTwoSphere.txt)
- add_gudhi_py_test(test_alpha_complex)
-
- endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0)
+ if(NUMPY_FOUND)
+ add_test(NAME random_cubical_complex_persistence_example_py_test
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
+ ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/random_cubical_complex_persistence_example.py"
+ 10 10 10)
+ endif()
- if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.6.0)
- # Euclidean witness
- add_gudhi_py_test(test_euclidean_witness_complex)
+ add_gudhi_py_test(test_cubical_complex)
- endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.6.0)
+ # Rips
+ if(MATPLOTLIB_FOUND AND NUMPY_FOUND)
+ add_test(NAME rips_complex_diagram_persistence_from_distance_matrix_file_example_py_test
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
+ ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/rips_complex_diagram_persistence_from_distance_matrix_file_example.py"
+ --no-diagram -f ${CMAKE_SOURCE_DIR}/data/distance_matrix/lower_triangular_distance_matrix.csv -e 12.0 -d 3)
- # Cubical
- add_test(NAME periodic_cubical_complex_barcode_persistence_from_perseus_file_example_py_test
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/periodic_cubical_complex_barcode_persistence_from_perseus_file_example.py"
- --no-barcode -f ${CMAKE_SOURCE_DIR}/data/bitmap/CubicalTwoSphere.txt)
+ add_test(NAME rips_complex_diagram_persistence_from_off_file_example_py_test
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
+ ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example/rips_complex_diagram_persistence_from_off_file_example.py
+ --no-diagram -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -e 0.25 -d 3)
+ endif()
- if(NUMPY_FOUND)
- add_test(NAME random_cubical_complex_persistence_example_py_test
+ add_test(NAME rips_complex_from_points_example_py_test
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/random_cubical_complex_persistence_example.py"
- 10 10 10)
- endif()
+ ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example/rips_complex_from_points_example.py)
- add_gudhi_py_test(test_cubical_complex)
+ add_gudhi_py_test(test_rips_complex)
- # Rips
- if(MATPLOTLIB_FOUND AND NUMPY_FOUND)
- add_test(NAME rips_complex_diagram_persistence_from_distance_matrix_file_example_py_test
+ # Simplex tree
+ add_test(NAME simplex_tree_example_py_test
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/rips_complex_diagram_persistence_from_distance_matrix_file_example.py"
- --no-diagram -f ${CMAKE_SOURCE_DIR}/data/distance_matrix/lower_triangular_distance_matrix.csv -e 12.0 -d 3)
-
- add_test(NAME rips_complex_diagram_persistence_from_off_file_example_py_test
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example/rips_complex_diagram_persistence_from_off_file_example.py
- --no-diagram -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -e 0.25 -d 3)
- endif()
-
- add_test(NAME rips_complex_from_points_example_py_test
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example/rips_complex_from_points_example.py)
+ ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example/simplex_tree_example.py)
- add_gudhi_py_test(test_rips_complex)
+ add_gudhi_py_test(test_simplex_tree)
- # Simplex tree
- add_test(NAME simplex_tree_example_py_test
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example/simplex_tree_example.py)
-
- add_gudhi_py_test(test_simplex_tree)
-
- # Witness
- add_test(NAME witness_complex_from_nearest_landmark_table_py_test
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example/witness_complex_from_nearest_landmark_table.py)
-
- add_gudhi_py_test(test_witness_complex)
-
- # Reader utils
- add_gudhi_py_test(test_reader_utils)
-
- # Documentation generation is available through sphinx - requires all modules
- if(SPHINX_PATH AND MATPLOTLIB_FOUND AND NUMPY_FOUND AND NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1)
- set (GUDHI_SPHINX_MESSAGE "Generating API documentation with Sphinx in ${CMAKE_CURRENT_BINARY_DIR}/sphinx/")
- # User warning - Sphinx is a static pages generator, and configured to work fine with user_version
- # Images and biblio warnings because not found on developper version
- if (GUDHI_CYTHON_PATH STREQUAL "src/cython")
- set (GUDHI_SPHINX_MESSAGE "${GUDHI_SPHINX_MESSAGE} \n WARNING : Sphinx is configured for user version, you run it on developper version. Images and biblio will miss")
- endif()
- # sphinx target requires gudhi.so, because conf.py reads gudhi version from it
- add_custom_target(sphinx
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doc
- COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${SPHINX_PATH} -b html ${CMAKE_CURRENT_SOURCE_DIR}/doc ${CMAKE_CURRENT_BINARY_DIR}/sphinx
- DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/gudhi.so"
- COMMENT "${GUDHI_SPHINX_MESSAGE}" VERBATIM)
-
- add_test(NAME sphinx_py_test
+ # Witness
+ add_test(NAME witness_complex_from_nearest_landmark_table_py_test
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
- ${SPHINX_PATH} -b doctest ${CMAKE_CURRENT_SOURCE_DIR}/doc ${CMAKE_CURRENT_BINARY_DIR}/doctest)
-
- endif()
-endif(CYTHON_FOUND)
+ ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example/witness_complex_from_nearest_landmark_table.py)
+
+ add_gudhi_py_test(test_witness_complex)
+
+ # Reader utils
+ add_gudhi_py_test(test_reader_utils)
+
+ # Documentation generation is available through sphinx - requires all modules
+ if(SPHINX_PATH)
+ if(MATPLOTLIB_FOUND)
+ if(NUMPY_FOUND)
+ if(SCIPY_FOUND)
+ if(NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1)
+ set (GUDHI_SPHINX_MESSAGE "Generating API documentation with Sphinx in ${CMAKE_CURRENT_BINARY_DIR}/sphinx/")
+ # User warning - Sphinx is a static pages generator, and configured to work fine with user_version
+ # Images and biblio warnings because not found on developper version
+ if (GUDHI_CYTHON_PATH STREQUAL "src/cython")
+ set (GUDHI_SPHINX_MESSAGE "${GUDHI_SPHINX_MESSAGE} \n WARNING : Sphinx is configured for user version, you run it on developper version. Images and biblio will miss")
+ endif()
+ # sphinx target requires gudhi.so, because conf.py reads gudhi version from it
+ add_custom_target(sphinx
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doc
+ COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
+ ${SPHINX_PATH} -b html ${CMAKE_CURRENT_SOURCE_DIR}/doc ${CMAKE_CURRENT_BINARY_DIR}/sphinx
+ DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/gudhi.so"
+ COMMENT "${GUDHI_SPHINX_MESSAGE}" VERBATIM)
+
+ add_test(NAME sphinx_py_test
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}"
+ ${SPHINX_PATH} -b doctest ${CMAKE_CURRENT_SOURCE_DIR}/doc ${CMAKE_CURRENT_BINARY_DIR}/doctest)
+
+ # Set missing or not modules
+ set(GUDHI_MODULES ${GUDHI_MODULES} "python-documentation" CACHE INTERNAL "GUDHI_MODULES")
+ else(NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1)
+ message("++ Python documentation module will not be compiled because it requires a CGAL with Eigen3 version greater or equal than 4.8.1")
+ set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python-documentation" CACHE INTERNAL "GUDHI_MISSING_MODULES")
+ endif(NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1)
+ else(SCIPY_FOUND)
+ message("++ Python documentation module will not be compiled because scipy was not found")
+ set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python-documentation" CACHE INTERNAL "GUDHI_MISSING_MODULES")
+ endif(SCIPY_FOUND)
+ else(NUMPY_FOUND)
+ message("++ Python documentation module will not be compiled because numpy was not found")
+ set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python-documentation" CACHE INTERNAL "GUDHI_MISSING_MODULES")
+ endif(NUMPY_FOUND)
+ else(MATPLOTLIB_FOUND)
+ message("++ Python documentation module will not be compiled because matplotlib was not found")
+ set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python-documentation" CACHE INTERNAL "GUDHI_MISSING_MODULES")
+ endif(MATPLOTLIB_FOUND)
+ else(SPHINX_PATH)
+ message("++ Python documentation module will not be compiled because sphinx and sphinxcontrib-bibtex were not found")
+ set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python-documentation" CACHE INTERNAL "GUDHI_MISSING_MODULES")
+ endif(SPHINX_PATH)
+
+
+ # Set missing or not modules
+ set(GUDHI_MODULES ${GUDHI_MODULES} "python" CACHE INTERNAL "GUDHI_MODULES")
+ else(CYTHON_FOUND)
+ message("++ Python module will not be compiled because cython was not found")
+ set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python" CACHE INTERNAL "GUDHI_MISSING_MODULES")
+ endif(CYTHON_FOUND)
+else(PYTHONINTERP_FOUND)
+ message("++ Python module will not be compiled because no Python interpreter was found")
+ set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python" CACHE INTERNAL "GUDHI_MISSING_MODULES")
+endif(PYTHONINTERP_FOUND)
diff --git a/src/cython/cython/nerve_gic.pyx b/src/cython/cython/nerve_gic.pyx
index 30a14d3b..5f01b379 100644
--- a/src/cython/cython/nerve_gic.pyx
+++ b/src/cython/cython/nerve_gic.pyx
@@ -38,14 +38,14 @@ cdef extern from "Nerve_gic_interface.h" namespace "Gudhi":
double compute_distance_from_confidence_level(double alpha)
void compute_distribution(int N)
double compute_p_value()
- void compute_PD()
+ 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_vector(vector[double] color)
+ 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)
@@ -67,6 +67,8 @@ cdef extern from "Nerve_gic_interface.h" namespace "Gudhi":
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:
@@ -102,6 +104,22 @@ cdef class CoverComplex:
"""
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.
@@ -145,7 +163,7 @@ cdef class CoverComplex:
def compute_PD(self):
"""Computes the extended persistence diagram of the complex.
"""
- self.thisptr.compute_PD()
+ return self.thisptr.compute_PD()
def create_simplex_tree(self):
"""
@@ -162,7 +180,7 @@ cdef class CoverComplex:
self.thisptr.find_simplices()
def read_point_cloud(self, off_file):
- """Reads and stores the input point cloud.
+ """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
@@ -206,14 +224,14 @@ cdef class CoverComplex:
else:
print("file " + color_file_name + " not found.")
- def set_color_from_vector(self, color):
+ 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_vector(color)
+ 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
diff --git a/src/cython/cython/persistence_graphical_tools.py b/src/cython/cython/persistence_graphical_tools.py
index 314bd6db..d7be936f 100755..100644
--- a/src/cython/cython/persistence_graphical_tools.py
+++ b/src/cython/cython/persistence_graphical_tools.py
@@ -24,65 +24,70 @@ __author__ = "Vincent Rouvreau, Bertrand Michel"
__copyright__ = "Copyright (C) 2016 Inria"
__license__ = "GPL v3"
-try:
- import matplotlib.pyplot as plt
- import matplotlib.patches as mpatches
- import numpy as np
- import os
-
- def __min_birth_max_death(persistence, band=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.:
- max_death += band
- return (min_birth, max_death)
+def __min_birth_max_death(persistence, band=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).
"""
- Only 13 colors for the palette
+ # 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.:
+ 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 <fileformats>`.
+
+ :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 <fileformats>` 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).
"""
- 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_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 <fileformats>`.
-
- :param persistence: Persistence values list.
- :type persistence: list of tuples(dimension, tuple(birth, death)).
- :param persistence_file: A :doc:`persistence file <fileformats>` 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_barcodes: number of maximal barcodes to be displayed.
- Set it to 0 to see all, Default value is 1000.
- (persistence will be sorted by life time if max_barcodes is set)
- :type max_barcodes: int.
- :param inf_delta: Infinity is placed at ((max_death - min_birth) x inf_delta).
- A reasonable value is between 0.05 and 0.5 - default is 0.1.
- :type inf_delta: float.
- :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
+ import numpy as np
+ import os
+
if persistence_file is not '':
if os.path.isfile(persistence_file):
# Reset persistence
@@ -95,9 +100,13 @@ try:
print("file " + persistence_file + " not found.")
return None
- if max_barcodes > 0 and max_barcodes < len(persistence):
- # Sort by life time, then takes only the max_plots elements
- persistence = sorted(persistence, key=lambda life_time: life_time[1][1]-life_time[1][0], reverse=True)[:max_barcodes]
+ 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])
@@ -134,30 +143,43 @@ try:
plt.axis([axis_start, infinity, 0, ind])
return plt
- def plot_persistence_diagram(persistence=[], persistence_file='', alpha=0.6,
- band=0., 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 <fileformats>`.
-
- :param persistence: Persistence values list.
- :type persistence: list of tuples(dimension, tuple(birth, death)).
- :param persistence_file: A :doc:`persistence file <fileformats>` 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_plots: number of maximal plots to be displayed
- Set it to 0 to see all, Default value is 1000.
- (persistence will be sorted by life time if max_plots is set)
- :type max_plots: int.
- :param inf_delta: Infinity is placed at ((max_death - min_birth) x inf_delta).
- A reasonable value is between 0.05 and 0.5 - default is 0.1.
- :type inf_delta: float.
- :returns: A matplotlib object containing diagram plot of persistence
- (launch `show()` method on it to display it).
- """
+ except ImportError:
+ print("This function is not available, you may be missing numpy and/or matplotlib.")
+
+def plot_persistence_diagram(persistence=[], persistence_file='', alpha=0.6,
+ band=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 <fileformats>`.
+
+ :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 <fileformats>` 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
+ import numpy as np
+ import os
+
if persistence_file is not '':
if os.path.isfile(persistence_file):
# Reset persistence
@@ -170,12 +192,15 @@ try:
print("file " + persistence_file + " not found.")
return None
- if max_plots > 0 and max_plots < len(persistence):
- # Sort by life time, then takes only the max_plots elements
- persistence = sorted(persistence, key=lambda life_time: life_time[1][1]-life_time[1][0], reverse=True)[:max_plots]
+ 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)
- ind = 0
delta = ((max_death - min_birth) * inf_delta)
# Replace infinity values with max_death + delta for diagram to be more
# readable
@@ -202,7 +227,6 @@ try:
# Infinite death case for diagram to be nicer
plt.scatter(interval[1][0], infinity, alpha=alpha,
color = palette[interval[0]])
- ind = ind + 1
if legend:
dimensions = list(set(item[0] for item in persistence))
@@ -215,6 +239,110 @@ try:
plt.axis([axis_start, infinity, axis_start, infinity + delta])
return plt
-except ImportError:
- # Continue in case of import error, functions won't be available
- pass
+ except ImportError:
+ print("This function is not available, you may be missing numpy and/or 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 <fileformats>`. 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 <fileformats>`
+ 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
+ <http://scipy.github.io/devdocs/generated/scipy.stats.gaussian_kde.html>`_
+ 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
+ import numpy as np
+ from scipy.stats import kde
+ import os
+ import math
+
+ if persistence_file is not '':
+ if os.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
+
+ persistence_dim = []
+ if dimension is not None:
+ persistence_dim = [(dim_interval) for dim_interval in persistence if (dim_interval[0] == dimension)]
+ else:
+ persistence_dim = persistence
+
+ if max_intervals > 0 and max_intervals < len(persistence_dim):
+ # Sort by life time, then takes only the max_intervals elements
+ persistence_dim = sorted(persistence_dim,
+ key=lambda life_time: life_time[1][1]-life_time[1][0],
+ reverse=True)[:max_intervals]
+
+ # Set as numpy array birth and death (remove undefined values - inf and NaN)
+ birth = np.asarray([(interval[1][0]) for interval in persistence_dim if (math.isfinite(interval[1][1]) and math.isfinite(interval[1][0]))])
+ death = np.asarray([(interval[1][1]) for interval in persistence_dim if (math.isfinite(interval[1][1]) and math.isfinite(interval[1][0]))])
+
+ # 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 numpy, matplotlib and/or scipy.")
diff --git a/src/cython/cython/rips_complex.pyx b/src/cython/cython/rips_complex.pyx
index 30ca4443..7c83241c 100644
--- a/src/cython/cython/rips_complex.pyx
+++ b/src/cython/cython/rips_complex.pyx
@@ -33,7 +33,11 @@ __license__ = "GPL v3"
cdef extern from "Rips_complex_interface.h" namespace "Gudhi":
cdef cppclass Rips_complex_interface "Gudhi::rips_complex::Rips_complex_interface":
- Rips_complex_interface(vector[vector[double]] values, double threshold, bool euclidean)
+ 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
@@ -44,10 +48,11 @@ cdef class RipsComplex:
function, or a distance matrix.
"""
- cdef Rips_complex_interface * thisptr
+ 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')):
+ def __init__(self, points=None, distance_matrix=None,
+ max_edge_length=float('inf'), sparse=None):
"""RipsComplex constructor.
:param max_edge_length: Rips value.
@@ -59,29 +64,38 @@ cdef class RipsComplex:
Or
:param distance_matrix: A distance matrix (full square or lower
- triangular).
+ 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')):
- if distance_matrix is not None:
- self.thisptr = new Rips_complex_interface(distance_matrix, max_edge_length, False)
+ 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 points is None:
- # Empty Rips construction
- points=[]
- self.thisptr = new Rips_complex_interface(points, max_edge_length, True)
-
-
- def __dealloc__(self):
- if self.thisptr != NULL:
- del self.thisptr
+ 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 __is_defined(self):
- """Returns true if RipsComplex pointer is not NULL.
- """
- return self.thisptr != NULL
def create_simplex_tree(self, max_dimension=1):
"""
@@ -92,5 +106,5 @@ cdef class RipsComplex:
:rtype: SimplexTree
"""
simplex_tree = SimplexTree()
- self.thisptr.create_simplex_tree(simplex_tree.thisptr, max_dimension)
+ 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
index e302486b..0ab97f80 100644
--- a/src/cython/cython/simplex_tree.pyx
+++ b/src/cython/cython/simplex_tree.pyx
@@ -44,8 +44,8 @@ cdef extern from "Simplex_tree_interface.h" namespace "Gudhi":
void set_dimension(int dimension)
int dimension()
int upper_bound_dimension()
- bint find_simplex(vector[int] simplex)
- bint insert_simplex_and_subfaces(vector[int] simplex,
+ 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)
@@ -355,7 +355,7 @@ cdef class SimplexTree:
:param filtration: Maximum threshold value.
:type filtration: float.
:returns: The filtration modification information.
- :rtype: bint
+ :rtype: bool
.. note::
@@ -406,7 +406,7 @@ cdef class SimplexTree:
value than its faces by increasing the filtration values.
:returns: The filtration modification information.
- :rtype: bint
+ :rtype: bool
.. note::
@@ -432,6 +432,10 @@ cdef class SimplexTree:
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))
"""
@@ -515,7 +519,7 @@ cdef class SimplexTree:
:returns: The persistence intervals.
:rtype: list of pair of list of int
- :note: intervals_in_dim function requires
+ :note: persistence_pairs function requires
:func:`persistence()<gudhi.SimplexTree.persistence>`
function to be launched first.
"""
diff --git a/src/cython/doc/examples.rst b/src/cython/doc/examples.rst
index 1f02f8a2..edbc2f72 100644
--- a/src/cython/doc/examples.rst
+++ b/src/cython/doc/examples.rst
@@ -22,6 +22,7 @@ Examples
* :download:`rips_complex_diagram_persistence_from_off_file_example.py <../example/rips_complex_diagram_persistence_from_off_file_example.py>`
* :download:`rips_complex_diagram_persistence_from_distance_matrix_file_example.py <../example/rips_complex_diagram_persistence_from_distance_matrix_file_example.py>`
* :download:`rips_persistence_diagram.py <../example/rips_persistence_diagram.py>`
+ * :download:`sparse_rips_persistence_diagram.py <../example/sparse_rips_persistence_diagram.py>`
* :download:`random_cubical_complex_persistence_example.py <../example/random_cubical_complex_persistence_example.py>`
* :download:`coordinate_graph_induced_complex.py <../example/coordinate_graph_induced_complex.py>`
* :download:`functional_graph_induced_complex.py <../example/functional_graph_induced_complex.py>`
diff --git a/src/cython/doc/installation.rst b/src/cython/doc/installation.rst
index 43576ec9..040f6b4a 100644
--- a/src/cython/doc/installation.rst
+++ b/src/cython/doc/installation.rst
@@ -7,7 +7,7 @@ Installation
Compiling
*********
-The library uses c++11 and requires `Boost <https://www.boost.org/>`_ ≥ 1.48.0
+The library uses c++11 and requires `Boost <https://www.boost.org/>`_ ≥ 1.56.0
and `CMake <https://www.cmake.org/>`_ ≥ 3.1.
It is a multi-platform library and compiles on Linux, Mac OSX and Visual
Studio 2015.
@@ -195,7 +195,7 @@ The following examples require the `Matplotlib <http://matplotlib.org>`_:
* :download:`euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py <../example/euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py>`
* :download:`euclidean_witness_complex_diagram_persistence_from_off_file_example.py <../example/euclidean_witness_complex_diagram_persistence_from_off_file_example.py>`
-Numpy
+NumPy
=====
The :doc:`persistence graphical tools </persistence_graphical_tools_user>`
@@ -216,6 +216,13 @@ The following examples require the `NumPy <http://numpy.org>`_:
* :download:`euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py <../example/euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py>`
* :download:`euclidean_witness_complex_diagram_persistence_from_off_file_example.py <../example/euclidean_witness_complex_diagram_persistence_from_off_file_example.py>`
+SciPy
+=====
+
+The :doc:`persistence graphical tools </persistence_graphical_tools_user>`
+module requires `SciPy <http://scipy.org>`_, a Python-based ecosystem of
+open-source software for mathematics, science, and engineering.
+
Threading Building Blocks
=========================
diff --git a/src/cython/doc/nerve_gic_complex_sum.rst b/src/cython/doc/nerve_gic_complex_sum.rst
index 72782c7a..523c119f 100644
--- a/src/cython/doc/nerve_gic_complex_sum.rst
+++ b/src/cython/doc/nerve_gic_complex_sum.rst
@@ -1,5 +1,5 @@
================================================================= =================================== ===================================
-:Author: Mathieu Carrière :Introduced in: GUDHI 2.1.0 :Copyright: GPL v3
+:Author: Mathieu Carrière :Introduced in: GUDHI 2.3.0 :Copyright: GPL v3
:Requires: CGAL :math:`\geq` 4.8.1
================================================================= =================================== ===================================
diff --git a/src/cython/doc/persistence_graphical_tools_ref.rst b/src/cython/doc/persistence_graphical_tools_ref.rst
index a2c6bcef..54aff4bc 100644
--- a/src/cython/doc/persistence_graphical_tools_ref.rst
+++ b/src/cython/doc/persistence_graphical_tools_ref.rst
@@ -9,3 +9,4 @@ Persistence graphical tools reference manual
.. autofunction:: gudhi.__min_birth_max_death
.. autofunction:: gudhi.plot_persistence_barcode
.. autofunction:: gudhi.plot_persistence_diagram
+.. autofunction:: gudhi.plot_persistence_density
diff --git a/src/cython/doc/persistence_graphical_tools_sum.inc b/src/cython/doc/persistence_graphical_tools_sum.inc
index d602daa7..5577cf99 100644
--- a/src/cython/doc/persistence_graphical_tools_sum.inc
+++ b/src/cython/doc/persistence_graphical_tools_sum.inc
@@ -1,11 +1,11 @@
================================================================= =================================== ===================================
:Author: Vincent Rouvreau :Introduced in: GUDHI 2.0.0 :Copyright: GPL v3
-:Requires: Matplotlib Numpy
+:Requires: matplotlib numpy scipy
================================================================= =================================== ===================================
+-----------------------------------------------------------------+-----------------------------------------------------------------------+
| .. figure:: | These graphical tools comes on top of persistence results and allows |
-| img/graphical_tools_representation.png | the user to build easily barcode and persistence diagram. |
+| img/graphical_tools_representation.png | the user to build easily persistence barcode, diagram or density. |
| | |
+-----------------------------------------------------------------+-----------------------------------------------------------------------+
| :doc:`persistence_graphical_tools_user` | :doc:`persistence_graphical_tools_ref` |
diff --git a/src/cython/doc/persistence_graphical_tools_user.rst b/src/cython/doc/persistence_graphical_tools_user.rst
index 292915eb..b2124fdd 100644
--- a/src/cython/doc/persistence_graphical_tools_user.rst
+++ b/src/cython/doc/persistence_graphical_tools_user.rst
@@ -12,6 +12,9 @@ Definition
Show persistence as a barcode
-----------------------------
+.. note::
+ this function requires matplotlib and numpy to be available
+
This function can display the persistence result as a barcode:
.. plot::
@@ -19,16 +22,22 @@ This function can display the persistence result as a barcode:
import gudhi
- perseus_file = gudhi.__root_source_dir__ + '/data/bitmap/3d_torus.txt'
- periodic_cc = gudhi.PeriodicCubicalComplex(perseus_file=perseus_file)
- diag = periodic_cc.persistence()
- print("diag = ", diag)
- plt = gudhi.plot_persistence_barcode(diag)
- plt.show()
+ off_file = gudhi.__root_source_dir__ + '/data/points/tore3D_300.off'
+ point_cloud = gudhi.read_off(off_file=off_file)
+
+ rips_complex = gudhi.RipsComplex(points=point_cloud, max_edge_length=0.7)
+ simplex_tree = rips_complex.create_simplex_tree(max_dimension=3)
+ diag = simplex_tree.persistence(min_persistence=0.4)
+
+ plot = gudhi.plot_persistence_barcode(diag)
+ plot.show()
Show persistence as a diagram
-----------------------------
+.. note::
+ this function requires matplotlib and numpy to be available
+
This function can display the persistence result as a diagram:
.. plot::
@@ -43,6 +52,12 @@ This function can display the persistence result as a diagram:
legend=True)
plt.show()
+Persistence density
+-------------------
+
+.. note::
+ this function requires matplotlib, numpy and scipy to be available
+
If you want more information on a specific dimension, for instance:
.. plot::
@@ -50,13 +65,9 @@ If you want more information on a specific dimension, for instance:
import gudhi
+ # rips_on_tore3D_1307.pers obtained from write_persistence_diagram method
persistence_file=gudhi.__root_source_dir__ + \
'/data/persistence_diagram/rips_on_tore3D_1307.pers'
- diag = \
- gudhi.read_persistence_intervals_grouped_by_dimension(persistence_file=\
- persistence_file)
- dim = 1
- # Display all points with some transparency
- plt = gudhi.plot_persistence_diagram([(dim,interval) for interval in diag[dim]],
- max_plots=0, alpha=0.1)
+ plt = gudhi.plot_persistence_density(persistence_file=persistence_file,
+ max_intervals=0, dimension=1, legend=True)
plt.show()
diff --git a/src/cython/doc/rips_complex_sum.inc b/src/cython/doc/rips_complex_sum.inc
index 5616bfa9..ea26769a 100644
--- a/src/cython/doc/rips_complex_sum.inc
+++ b/src/cython/doc/rips_complex_sum.inc
@@ -1,6 +1,6 @@
-================================================================= =================================== ===================================
-:Author: Clément Maria, Pawel Dlotko, Vincent Rouvreau :Introduced in: GUDHI 2.0.0 :Copyright: GPL v3
-================================================================= =================================== ===================================
+===================================================================== =========================== ===================================
+:Author: Clément Maria, Pawel Dlotko, Vincent Rouvreau, Marc Glisse :Introduced in: GUDHI 2.0.0 :Copyright: GPL v3
+===================================================================== =========================== ===================================
+----------------------------------------------------------------+------------------------------------------------------------------------+
| .. figure:: | Rips complex is a simplicial complex constructed from a one skeleton |
diff --git a/src/cython/doc/rips_complex_user.rst b/src/cython/doc/rips_complex_user.rst
index a8c06cf9..e814b4c3 100644
--- a/src/cython/doc/rips_complex_user.rst
+++ b/src/cython/doc/rips_complex_user.rst
@@ -7,27 +7,27 @@ Rips complex user manual
Definition
----------
-======================================================= ===================================== =====================================
-:Authors: Clément Maria, Pawel Dlotko, Vincent Rouvreau :Introduced in: GUDHI 2.0.0 :Copyright: GPL v3
-======================================================= ===================================== =====================================
+==================================================================== ================================ ======================
+:Authors: Clément Maria, Pawel Dlotko, Vincent Rouvreau, Marc Glisse :Introduced in: GUDHI 2.0.0 :Copyright: GPL v3
+==================================================================== ================================ ======================
+-------------------------------------------+----------------------------------------------------------------------+
| :doc:`rips_complex_user` | :doc:`rips_complex_ref` |
+-------------------------------------------+----------------------------------------------------------------------+
-`Rips complex <https://en.wikipedia.org/wiki/Vietoris%E2%80%93Rips_complex>`_ is a one skeleton graph that allows to
-construct a simplicial complex from it. The input can be a point cloud with a given distance function, or a distance
-matrix.
+The `Rips complex <https://en.wikipedia.org/wiki/Vietoris%E2%80%93Rips_complex>`_ is a simplicial complex that
+generalizes proximity (:math:`\varepsilon`-ball) graphs to higher dimensions. The vertices correspond to the input
+points, and a simplex is present if and only if its diameter is smaller than some parameter α. Considering all
+parameters α defines a filtered simplicial complex, where the filtration value of a simplex is its diameter.
+The filtration can be restricted to values α smaller than some threshold, to reduce its size.
-The filtration value of each edge is computed from a user-given distance function, or directly from the distance
-matrix.
+The input discrete metric space can be provided as a point cloud plus a distance function, or as a distance matrix.
-All edges that have a filtration value strictly greater than a given threshold value are not inserted into the complex.
+When creating a simplicial complex from the graph, :doc:`RipsComplex <rips_complex_ref>` first builds the graph and
+inserts it into the data structure. It then expands the simplicial complex (adds the simplices corresponding to cliques)
+when required. The expansion can be stopped at dimension `max_dimension`, by default 1.
-When creating a simplicial complex from this one skeleton graph, Rips inserts the one skeleton graph into the data
-structure, and then expands the simplicial complex when required.
-
-Vertex name correspond to the index of the point in the given range (aka. the point cloud).
+A vertex name corresponds to the index of the point in the given range (aka. the point cloud).
.. figure::
../../doc/Rips_complex/rips_complex_representation.png
@@ -38,8 +38,27 @@ Vertex name correspond to the index of the point in the given range (aka. the po
On this example, as edges (4,5), (4,6) and (5,6) are in the complex, simplex (4,5,6) is added with the filtration value
set with :math:`max(filtration(4,5), filtration(4,6), filtration(5,6))`. And so on for simplex (0,1,2,3).
-If the Rips_complex interfaces are not detailed enough for your need, please refer to rips_persistence_step_by_step.cpp
-example, where the graph construction over the Simplex_tree is more detailed.
+If the `RipsComplex` interfaces are not detailed enough for your need, please refer to rips_persistence_step_by_step.cpp
+C++ example, where the graph construction over the Simplex_tree is more detailed.
+
+A Rips complex can easily become huge, even if we limit the length of the edges
+and the dimension of the simplices. One easy trick, before building a Rips
+complex on a point cloud, is to call `sparsify_point_set` which removes points
+that are too close to each other. This does not change its persistence diagram
+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
+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
+construction of a `RipsComplex` object asks it to build a sparse Rips with
+parameter :math:`\varepsilon=0.3`, while the default `sparse=None` builds the
+regular Rips complex.
+
Point cloud
-----------
@@ -47,7 +66,7 @@ Point cloud
Example from a point cloud
^^^^^^^^^^^^^^^^^^^^^^^^^^
-This example builds the one skeleton graph from the given points, and max_edge_length value.
+This example builds the neighborhood graph from the given points, up to max_edge_length.
Then it creates a :doc:`Simplex_tree <simplex_tree_ref>` with it.
Finally, it is asked to display information about the simplicial complex.
@@ -56,7 +75,7 @@ Finally, it is asked to display information about the simplicial complex.
import gudhi
rips_complex = gudhi.RipsComplex(points=[[1, 1], [7, 0], [4, 6], [9, 6], [0, 14], [2, 19], [9, 17]],
- max_edge_length=12.0)
+ max_edge_length=12.0)
simplex_tree = rips_complex.create_simplex_tree(max_dimension=1)
result_str = 'Rips complex is of dimension ' + repr(simplex_tree.dimension()) + ' - ' + \
@@ -92,10 +111,20 @@ until dimension 1 - one skeleton graph in other words), the output is:
[4, 6] -> 9.49
[3, 6] -> 11.00
+Notice that if we use
+
+.. code-block:: python
+
+ rips_complex = gudhi.RipsComplex(points=[[1, 1], [7, 0], [4, 6], [9, 6], [0, 14], [2, 19], [9, 17]],
+ max_edge_length=12.0, sparse=2)
+
+asking for a very sparse version (theory only gives some guarantee on the meaning of the output if `sparse<1`),
+2 to 5 edges disappear, depending on the random vertex used to start the sparsification.
+
Example from OFF file
^^^^^^^^^^^^^^^^^^^^^
-This example builds the :doc:`Rips_complex <rips_complex_ref>` from the given
+This example builds the :doc:`RipsComplex <rips_complex_ref>` from the given
points in an OFF file, and max_edge_length value.
Then it creates a :doc:`Simplex_tree <simplex_tree_ref>` with it.
@@ -200,7 +229,7 @@ until dimension 1 - one skeleton graph in other words), the output is:
Example from csv file
^^^^^^^^^^^^^^^^^^^^^
-This example builds the :doc:`Rips_complex <rips_complex_ref>` from the given
+This example builds the :doc:`RipsComplex <rips_complex_ref>` from the given
distance matrix in a csv file, and max_edge_length value.
Then it creates a :doc:`Simplex_tree <simplex_tree_ref>` with it.
diff --git a/src/cython/example/sparse_rips_persistence_diagram.py b/src/cython/example/sparse_rips_persistence_diagram.py
new file mode 100755
index 00000000..d58c244c
--- /dev/null
+++ b/src/cython/example/sparse_rips_persistence_diagram.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+import gudhi
+
+"""This file is part of the Gudhi Library. The Gudhi library
+ (Geometric Understanding in Higher Dimensions) is a generic C++
+ library for computational topology.
+
+ Author(s): Marc Glisse
+
+ Copyright (C) 2018 Inria
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+"""
+
+__author__ = "Marc Glisse"
+__copyright__ = "Copyright (C) 2018 Inria"
+__license__ = "GPL v3"
+
+print("#####################################################################")
+print("Sparse RipsComplex creation from points")
+rips = gudhi.RipsComplex(points=[[0, 0], [0, 0.1], [1, 0], [0, 1], [1, 1]],
+ max_edge_length=42, sparse=.5)
+
+simplex_tree = rips.create_simplex_tree(max_dimension=2)
+
+
+diag = simplex_tree.persistence(homology_coeff_field=2, min_persistence=0)
+print("diag=", diag)
+
+pplot = gudhi.plot_persistence_diagram(diag)
+pplot.show()
diff --git a/src/cython/include/Alpha_complex_interface.h b/src/cython/include/Alpha_complex_interface.h
index 8cf527fc..faa059d1 100644
--- a/src/cython/include/Alpha_complex_interface.h
+++ b/src/cython/include/Alpha_complex_interface.h
@@ -60,7 +60,7 @@ class Alpha_complex_interface {
Point_d ph = alpha_complex_->get_point(vh);
for (auto coord = ph.cartesian_begin(); coord < ph.cartesian_end(); coord++)
vd.push_back(*coord);
- } catch (std::out_of_range outofrange) {
+ } catch (std::out_of_range const&) {
// std::out_of_range is thrown in case not found. Other exceptions must be re-thrown
}
return vd;
diff --git a/src/cython/include/Rips_complex_interface.h b/src/cython/include/Rips_complex_interface.h
index 8b6c9c35..1a6e2477 100644
--- a/src/cython/include/Rips_complex_interface.h
+++ b/src/cython/include/Rips_complex_interface.h
@@ -25,8 +25,11 @@
#include <gudhi/Simplex_tree.h>
#include <gudhi/Rips_complex.h>
+#include <gudhi/Sparse_rips_complex.h>
#include <gudhi/distance_functions.h>
+#include <boost/optional.hpp>
+
#include "Simplex_tree_interface.h"
#include <iostream>
@@ -43,28 +46,40 @@ class Rips_complex_interface {
using Distance_matrix = std::vector<std::vector<Simplex_tree_interface<>::Filtration_value>>;
public:
- Rips_complex_interface(const std::vector<std::vector<double>>& values, double threshold, bool euclidean) {
- if (euclidean) {
- // Rips construction where values is a vector of points
- rips_complex_ = new Rips_complex<Simplex_tree_interface<>::Filtration_value>(values, threshold,
- Gudhi::Euclidean_distance());
- } else {
- // Rips construction where values is a distance matrix
- rips_complex_ = new Rips_complex<Simplex_tree_interface<>::Filtration_value>(values, threshold);
- }
+ void init_points(const std::vector<std::vector<double>>& points, double threshold) {
+ rips_complex_.emplace(points, threshold, Gudhi::Euclidean_distance());
+ }
+ void init_matrix(const std::vector<std::vector<double>>& matrix, double threshold) {
+ rips_complex_.emplace(matrix, threshold);
}
- ~Rips_complex_interface() {
- delete rips_complex_;
+ 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;
+ }
+ void init_matrix_sparse(const std::vector<std::vector<double>>& matrix, double threshold, double epsilon) {
+ sparse_rips_complex_.emplace(matrix, epsilon);
+ threshold_ = threshold;
}
void create_simplex_tree(Simplex_tree_interface<>* simplex_tree, int dim_max) {
- rips_complex_->create_complex(*simplex_tree, dim_max);
+ if (rips_complex_)
+ rips_complex_->create_complex(*simplex_tree, dim_max);
+ 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();
}
private:
- Rips_complex<Simplex_tree_interface<>::Filtration_value>* rips_complex_;
+ // std::variant would work, but we don't require C++17 yet, and boost::variant is not super convenient.
+ // 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/test/test_rips_complex.py b/src/cython/test/test_rips_complex.py
index c37b5400..05dfcaf7 100755
--- a/src/cython/test/test_rips_complex.py
+++ b/src/cython/test/test_rips_complex.py
@@ -30,7 +30,6 @@ __license__ = "GPL v3"
def test_empty_rips():
rips_complex = RipsComplex()
- assert rips_complex.__is_defined() == True
def test_rips_from_points():
point_list = [[0, 0], [1, 0], [0, 1], [1, 1]]
@@ -68,12 +67,26 @@ def test_filtered_rips_from_points():
assert simplex_tree.num_simplices() == 8
assert simplex_tree.num_vertices() == 4
+def test_sparse_filtered_rips_from_points():
+ point_list = [[0, 0], [1, 0], [0, 1], [1, 1]]
+ filtered_rips = RipsComplex(points=point_list, max_edge_length=1.0,
+ sparse=.001)
+
+ simplex_tree = filtered_rips.create_simplex_tree(max_dimension=1)
+
+ assert simplex_tree.__is_defined() == True
+ assert simplex_tree.__is_persistence_defined() == False
+
+ assert simplex_tree.num_simplices() == 8
+ assert simplex_tree.num_vertices() == 4
+
def test_rips_from_distance_matrix():
distance_matrix = [[0],
[1, 0],
[1, sqrt(2), 0],
[sqrt(2), 1, 1, 0]]
- rips_complex = RipsComplex(distance_matrix=distance_matrix, max_edge_length=42)
+ rips_complex = RipsComplex(distance_matrix=distance_matrix,
+ max_edge_length=42)
simplex_tree = rips_complex.create_simplex_tree(max_dimension=1)
@@ -100,7 +113,8 @@ def test_filtered_rips_from_distance_matrix():
[1, 0],
[1, sqrt(2), 0],
[sqrt(2), 1, 1, 0]]
- filtered_rips = RipsComplex(distance_matrix=distance_matrix, max_edge_length=1.0)
+ filtered_rips = RipsComplex(distance_matrix=distance_matrix,
+ max_edge_length=1.0)
simplex_tree = filtered_rips.create_simplex_tree(max_dimension=1)