From 88a36ffad6c11279990c1c96df32b95c1f6f526c Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 3 Jul 2020 13:57:49 +0200 Subject: A fix proposal for boudaries of a simplex python version --- src/python/test/test_simplex_tree.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/python/test/test_simplex_tree.py') diff --git a/src/python/test/test_simplex_tree.py b/src/python/test/test_simplex_tree.py index 2137d822..7c49cb1a 100755 --- a/src/python/test/test_simplex_tree.py +++ b/src/python/test/test_simplex_tree.py @@ -340,3 +340,12 @@ def test_simplices_iterator(): assert st.find(simplex[0]) == True print("filtration is: ", simplex[1]) assert st.filtration(simplex[0]) == simplex[1] + +def test_boundaries_iterator(): + st = SimplexTree() + + assert st.insert([0, 1, 2, 3], filtration=1.0) == True + assert st.insert([1, 2, 3, 4], filtration=2.0) == True + + assert list(st.get_boundaries([1, 2, 3])) == [([1, 2], 1.0), ([1, 3], 1.0), ([2, 3], 1.0)] + assert list(st.get_boundaries([2, 3, 4])) == [([2, 3], 1.0), ([2, 4], 2.0), ([3, 4], 2.0)] -- cgit v1.2.3 From 85eec1ba750d56b66e3739dc486c6205f49fb31e Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 3 Jul 2020 16:04:45 +0200 Subject: A proposal for simplex_tree reset_filtration (python & C++) --- src/Simplex_tree/include/gudhi/Simplex_tree.h | 30 +++++++++++++++ src/Simplex_tree/test/simplex_tree_unit_test.cpp | 47 ++++++++++++++++++++++++ src/python/gudhi/simplex_tree.pxd | 1 + src/python/gudhi/simplex_tree.pyx | 10 +++++ src/python/test/test_simplex_tree.py | 22 +++++++++++ 5 files changed, 110 insertions(+) (limited to 'src/python/test/test_simplex_tree.py') diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree.h b/src/Simplex_tree/include/gudhi/Simplex_tree.h index 889dbd00..adc8e801 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h @@ -1667,6 +1667,36 @@ class Simplex_tree { return sh; // None of its faces has the same filtration. } + public: + /** \brief This function resets filtration value until a given dimension. + * @param[in] filt_value The new filtration value. + * @param[in] max_dim The maximal dimension. + */ + void reset_filtration(Filtration_value filt_value, int max_dim) { + for (auto& simplex : root_.members()) { + simplex.second.assign_filtration(filt_value); + if (has_children(&simplex) && max_dim > 0) { + rec_reset_filtration(simplex.second.children(), filt_value, (max_dim - 1)); + } + } + clear_filtration(); // Drop the cache. + } + + private: + /** \brief Recursively resets filtration value until a given dimension. + * @param[in] sib Siblings to be parsed. + * @param[in] filt_value The new filtration value. + * @param[in] max_dim The maximal dimension. + */ + void rec_reset_filtration(Siblings * sib, Filtration_value filt_value, int max_dim) { + for (auto& simplex : sib->members()) { + simplex.second.assign_filtration(filt_value); + if (has_children(&simplex) && max_dim > 0) { + rec_reset_filtration(simplex.second.children(), filt_value, (max_dim - 1)); + } + } + } + private: Vertex_handle null_vertex_; /** \brief Total number of simplices in the complex, without the empty simplex.*/ diff --git a/src/Simplex_tree/test/simplex_tree_unit_test.cpp b/src/Simplex_tree/test/simplex_tree_unit_test.cpp index 9b5fa8fe..9780f5b0 100644 --- a/src/Simplex_tree/test/simplex_tree_unit_test.cpp +++ b/src/Simplex_tree/test/simplex_tree_unit_test.cpp @@ -940,3 +940,50 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(generators, typeST, list_of_tested_variants) { BOOST_CHECK(st.edge_with_same_filtration(st.find({1,5}))==st.find({1,5})); } } + +BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_reset_filtration, typeST, list_of_tested_variants) { + std::clog << "********************************************************************" << std::endl; + std::clog << "TEST RESET FILTRATION" << std::endl; + typeST st; + + st.insert_simplex_and_subfaces({2, 1, 0}, 3.); + st.insert_simplex_and_subfaces({3, 0}, 2.); + st.insert_simplex_and_subfaces({3, 4, 5}, 3.); + st.insert_simplex_and_subfaces({0, 1, 6, 7}, 4.); + + /* Inserted simplex: */ + /* 1 6 */ + /* o---o */ + /* /X\7/ */ + /* o---o---o---o */ + /* 2 0 3\X/4 */ + /* o */ + /* 5 */ + + for (auto f_simplex : st.skeleton_simplex_range(3)) { + std::clog << "vertex = ("; + for (auto vertex : st.simplex_vertex_range(f_simplex)) { + std::clog << vertex << ","; + } + std::clog << ") - filtration =" << st.filtration(f_simplex) << std::endl; + BOOST_CHECK(st.filtration(f_simplex) >= 2.); + } + + // dimension until 5 even if simplex tree is of dimension 3 to test the limits + for(int dimension = 0; dimension < 6; dimension ++) { + st.reset_filtration(0., dimension); + for (auto f_simplex : st.skeleton_simplex_range(3)) { + std::clog << "vertex = ("; + for (auto vertex : st.simplex_vertex_range(f_simplex)) { + std::clog << vertex << ","; + } + std::clog << ") - filtration =" << st.filtration(f_simplex) << std::endl; + if (st.dimension(f_simplex) > dimension) + BOOST_CHECK(st.filtration(f_simplex) >= 1.); + else + BOOST_CHECK(st.filtration(f_simplex) == 0.); + } + } + +} + diff --git a/src/python/gudhi/simplex_tree.pxd b/src/python/gudhi/simplex_tree.pxd index e748ac40..12c2065e 100644 --- a/src/python/gudhi/simplex_tree.pxd +++ b/src/python/gudhi/simplex_tree.pxd @@ -57,6 +57,7 @@ cdef extern from "Simplex_tree_interface.h" namespace "Gudhi": bool make_filtration_non_decreasing() nogil void compute_extended_filtration() nogil vector[vector[pair[int, pair[double, double]]]] compute_extended_persistence_subdiagrams(vector[pair[int, pair[double, double]]] dgm, double min_persistence) nogil + void reset_filtration(double filtration, int dimension) nogil # Iterators over Simplex tree pair[vector[int], double] get_simplex_and_filtration(Simplex_tree_simplex_handle f_simplex) nogil Simplex_tree_simplices_iterator get_simplices_iterator_begin() nogil diff --git a/src/python/gudhi/simplex_tree.pyx b/src/python/gudhi/simplex_tree.pyx index 20e66d9f..41b06116 100644 --- a/src/python/gudhi/simplex_tree.pyx +++ b/src/python/gudhi/simplex_tree.pyx @@ -358,6 +358,16 @@ cdef class SimplexTree: """ return self.get_ptr().make_filtration_non_decreasing() + def reset_filtration(self, filtration, max_dim): + """This function resets filtration value until a given dimension. + + :param filtration: New threshold value. + :type filtration: float. + :param max_dim: The maximal dimension. + :type max_dim: int. + """ + self.get_ptr().reset_filtration(filtration, max_dim) + def extend_filtration(self): """ Extend filtration for computing extended persistence. This function only uses the filtration values at the 0-dimensional simplices, and computes the extended persistence diff --git a/src/python/test/test_simplex_tree.py b/src/python/test/test_simplex_tree.py index 2137d822..1ca84c10 100755 --- a/src/python/test/test_simplex_tree.py +++ b/src/python/test/test_simplex_tree.py @@ -340,3 +340,25 @@ def test_simplices_iterator(): assert st.find(simplex[0]) == True print("filtration is: ", simplex[1]) assert st.filtration(simplex[0]) == simplex[1] + +def test_reset_filtration(): + st = SimplexTree() + + assert st.insert([0, 1, 2], 3.) == True + assert st.insert([0, 3], 2.) == True + assert st.insert([3, 4, 5], 3.) == True + assert st.insert([0, 1, 6, 7], 4.) == True + + for simplex in st.get_simplices(): + assert st.filtration(simplex[0]) >= 0. + + # dimension until 5 even if simplex tree is of dimension 3 to test the limits + for dimension in range(0, 6): + st.reset_filtration(0., dimension) + for simplex in st.get_skeleton(3): + print(simplex) + if len(simplex[0]) > (dimension + 1): + assert st.filtration(simplex[0]) >= 1. + else: + assert st.filtration(simplex[0]) == 0. + -- cgit v1.2.3 From 76a61bcd3279a98bd84856b011869a0be2ba99cd Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 30 Jul 2020 12:36:16 +0200 Subject: collapse edges for python simplex tree --- .../example/rips_complex_edge_collapse_example.py | 65 ++++++++++++++++++++++ src/python/gudhi/simplex_tree.pxd | 1 + src/python/gudhi/simplex_tree.pyx | 63 +++++++++++++-------- src/python/include/Simplex_tree_interface.h | 29 ++++++++++ src/python/test/test_simplex_tree.py | 16 ++++++ 5 files changed, 151 insertions(+), 23 deletions(-) create mode 100755 src/python/example/rips_complex_edge_collapse_example.py (limited to 'src/python/test/test_simplex_tree.py') diff --git a/src/python/example/rips_complex_edge_collapse_example.py b/src/python/example/rips_complex_edge_collapse_example.py new file mode 100755 index 00000000..e352c155 --- /dev/null +++ b/src/python/example/rips_complex_edge_collapse_example.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python + +import gudhi +import matplotlib.pyplot as plt +import time + +""" This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + Author(s): Vincent Rouvreau + + Copyright (C) 2016 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2020 Inria" +__license__ = "MIT" + + +print("#####################################################################") +print("RipsComplex (only the one-skeleton) creation from tore3D_300.off file") + +off_file = gudhi.__root_source_dir__ + '/data/points/tore3D_300.off' +point_cloud = gudhi.read_points_from_off_file(off_file = off_file) +rips_complex = gudhi.RipsComplex(points=point_cloud, max_edge_length=12.0) +simplex_tree = rips_complex.create_simplex_tree(max_dimension=1) +result_str = '1. Rips complex is of dimension ' + repr(simplex_tree.dimension()) + ' - ' + \ + repr(simplex_tree.num_simplices()) + ' simplices - ' + \ + repr(simplex_tree.num_vertices()) + ' vertices.' +print(result_str) + +# Expansion of this one-skeleton would require a lot of memory. Let's collapse it +start = time.process_time() +simplex_tree.collapse_edges() +simplex_tree.expansion(3) +diag = simplex_tree.persistence() +print("Collapse, expansion and persistence computation took ", time.process_time() - start, " sec.") +result_str = '2. Rips complex is of dimension ' + repr(simplex_tree.dimension()) + ' - ' + \ + repr(simplex_tree.num_simplices()) + ' simplices - ' + \ + repr(simplex_tree.num_vertices()) + ' vertices.' +print(result_str) + +# Use subplots to display diagram and density side by side +fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(12, 5)) +gudhi.plot_persistence_diagram(diag, axes=axes[0]) +axes[0].set_title("Persistence after 1 collapse") + +# Collapse can be performed several times. Let's collapse it 3 times +start = time.process_time() +simplex_tree.collapse_edges(nb_iterations = 3) +simplex_tree.expansion(3) +diag = simplex_tree.persistence() +print("Collapse, expansion and persistence computation took ", time.process_time() - start, " sec.") +result_str = '3. Rips complex is of dimension ' + repr(simplex_tree.dimension()) + ' - ' + \ + repr(simplex_tree.num_simplices()) + ' simplices - ' + \ + repr(simplex_tree.num_vertices()) + ' vertices.' +print(result_str) + +gudhi.plot_persistence_diagram(diag, axes=axes[1]) +axes[1].set_title("Persistence after 3 more collapses") + +# Plot the 2 persistence diagrams side to side to check the persistence is the same +plt.show() diff --git a/src/python/gudhi/simplex_tree.pxd b/src/python/gudhi/simplex_tree.pxd index e748ac40..75e94e0b 100644 --- a/src/python/gudhi/simplex_tree.pxd +++ b/src/python/gudhi/simplex_tree.pxd @@ -57,6 +57,7 @@ cdef extern from "Simplex_tree_interface.h" namespace "Gudhi": bool make_filtration_non_decreasing() nogil void compute_extended_filtration() nogil vector[vector[pair[int, pair[double, double]]]] compute_extended_persistence_subdiagrams(vector[pair[int, pair[double, double]]] dgm, double min_persistence) nogil + Simplex_tree_interface_full_featured* collapse_edges(int nb_collapse_iteration) nogil # Iterators over Simplex tree pair[vector[int], double] get_simplex_and_filtration(Simplex_tree_simplex_handle f_simplex) nogil Simplex_tree_simplices_iterator get_simplices_iterator_begin() nogil diff --git a/src/python/gudhi/simplex_tree.pyx b/src/python/gudhi/simplex_tree.pyx index 20e66d9f..236435a7 100644 --- a/src/python/gudhi/simplex_tree.pyx +++ b/src/python/gudhi/simplex_tree.pyx @@ -69,7 +69,7 @@ cdef class SimplexTree: this simplicial complex, or +infinity if it is not in the complex. :param simplex: The N-simplex, represented by a list of vertex. - :type simplex: list of int. + :type simplex: list of int :returns: The simplicial complex filtration value. :rtype: float """ @@ -80,7 +80,7 @@ cdef class SimplexTree: given N-simplex. :param simplex: The N-simplex, represented by a list of vertex. - :type simplex: list of int. + :type simplex: list of int :param filtration: The new filtration value. :type filtration: float @@ -153,7 +153,7 @@ cdef class SimplexTree: """This function sets the dimension of the simplicial complex. :param dimension: The new dimension value. - :type dimension: int. + :type dimension: int .. note:: @@ -172,7 +172,7 @@ cdef class SimplexTree: complex or not. :param simplex: The N-simplex to find, represented by a list of vertex. - :type simplex: list of int. + :type simplex: list of int :returns: true if the simplex was found, false otherwise. :rtype: bool """ @@ -186,9 +186,9 @@ cdef class SimplexTree: :param simplex: The N-simplex to insert, represented by a list of vertex. - :type simplex: list of int. + :type simplex: list of int :param filtration: The filtration value of the simplex. - :type filtration: float. + :type filtration: float :returns: true if the simplex was not yet in the complex, false otherwise (whatever its original filtration value). :rtype: bool @@ -228,7 +228,7 @@ cdef class SimplexTree: """This function returns a generator with the (simplices of the) skeleton of a maximum given dimension. :param dimension: The skeleton dimension value. - :type dimension: int. + :type dimension: int :returns: The (simplices of the) skeleton of a maximum dimension. :rtype: generator with tuples(simplex, filtration) """ @@ -243,7 +243,7 @@ cdef class SimplexTree: """This function returns the star of a given N-simplex. :param simplex: The N-simplex, represented by a list of vertex. - :type simplex: list of int. + :type simplex: list of int :returns: The (simplices of the) star of a simplex. :rtype: list of tuples(simplex, filtration) """ @@ -265,10 +265,10 @@ cdef class SimplexTree: given codimension. :param simplex: The N-simplex, represented by a list of vertex. - :type simplex: list of int. + :type simplex: list of int :param codimension: The codimension. If codimension = 0, all cofaces are returned (equivalent of get_star function) - :type codimension: int. + :type codimension: int :returns: The (simplices of the) cofaces of a simplex :rtype: list of tuples(simplex, filtration) """ @@ -290,7 +290,7 @@ cdef class SimplexTree: complex. :param simplex: The N-simplex, represented by a list of vertex. - :type simplex: list of int. + :type simplex: list of int .. note:: @@ -308,7 +308,7 @@ cdef class SimplexTree: """Prune above filtration value given as parameter. :param filtration: Maximum threshold value. - :type filtration: float. + :type filtration: float :returns: The filtration modification information. :rtype: bool @@ -342,7 +342,7 @@ cdef class SimplexTree: 1 when calling the method. :param max_dim: The maximal dimension. - :type max_dim: int. + :type max_dim: int """ cdef int maxdim = max_dim with nogil: @@ -383,12 +383,12 @@ cdef class SimplexTree: :param homology_coeff_field: The homology coefficient field. Must be a prime number. Default value is 11. - :type homology_coeff_field: int. + :type homology_coeff_field: int :param min_persistence: The minimum persistence value (i.e., the absolute value of the difference between the persistence diagram point coordinates) to take into account (strictly greater than min_persistence). Default value is 0.0. Sets min_persistence to -1.0 to see all values. - :type min_persistence: float. + :type min_persistence: float :returns: A list of four persistence diagrams in the format described in :func:`persistence`. The first one is Ordinary, the second one is Relative, the third one is Extended+ and the fourth one is Extended-. See https://link.springer.com/article/10.1007/s10208-008-9027-z and/or section 2.2 in https://link.springer.com/article/10.1007/s10208-017-9370-z for a description of these subtypes. .. note:: @@ -415,12 +415,12 @@ cdef class SimplexTree: :param homology_coeff_field: The homology coefficient field. Must be a prime number. Default value is 11. - :type homology_coeff_field: int. + :type homology_coeff_field: int :param min_persistence: The minimum persistence value to take into account (strictly greater than min_persistence). Default value is 0.0. Set min_persistence to -1.0 to see all values. - :type min_persistence: float. + :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. @@ -438,12 +438,12 @@ cdef class SimplexTree: :param homology_coeff_field: The homology coefficient field. Must be a prime number. Default value is 11. - :type homology_coeff_field: int. + :type homology_coeff_field: int :param min_persistence: The minimum persistence value to take into account (strictly greater than min_persistence). Default value is 0.0. Sets min_persistence to -1.0 to see all values. - :type min_persistence: float. + :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. @@ -478,10 +478,10 @@ cdef class SimplexTree: :param from_value: The persistence birth limit to be added in the numbers (persistent birth <= from_value). - :type from_value: float. + :type from_value: float :param to_value: The persistence death limit to be added in the numbers (persistent death > to_value). - :type to_value: float. + :type to_value: float :returns: The persistent Betti numbers ([B0, B1, ..., Bn]). :rtype: list of int @@ -498,7 +498,7 @@ cdef class SimplexTree: complex in a specific dimension. :param dimension: The specific dimension. - :type dimension: int. + :type dimension: int :returns: The persistence intervals. :rtype: numpy array of dimension 2 @@ -527,7 +527,7 @@ cdef class SimplexTree: complex in a user given file name. :param persistence_file: Name of the file. - :type persistence_file: string. + :type persistence_file: string :note: intervals_in_dim function requires :func:`compute_persistence` @@ -581,3 +581,20 @@ cdef class SimplexTree: infinite0 = np_array(next(l)) infinites = [np_array(d).reshape(-1,2) for d in l] return (normal0, normals, infinite0, infinites) + + def collapse_edges(self, nb_iterations = 1): + """Assuming the simplex tree is a 1-skeleton graph, this function collapse edges and resets the simplex tree + from the remaining edges. + A good candidate is to build a simplex tree on top of a :class:`~gudhi.RipsComplex` of dimension 1 before + collapsing edges. + + :param nb_iterations: The number of edge collapse iterations to perform. Default is 1. + :type nb_iterations: int + """ + # Backup old pointer + cdef Simplex_tree_interface_full_featured* ptr = self.get_ptr() + # New pointer is a new collapsed simplex tree + self.thisptr = (self.get_ptr().collapse_edges(nb_iterations)) + # Delete old pointer + if ptr != NULL: + del ptr diff --git a/src/python/include/Simplex_tree_interface.h b/src/python/include/Simplex_tree_interface.h index 56d7c41d..7500098d 100644 --- a/src/python/include/Simplex_tree_interface.h +++ b/src/python/include/Simplex_tree_interface.h @@ -15,10 +15,12 @@ #include #include #include +#include #include #include #include // std::pair +#include namespace Gudhi { @@ -157,6 +159,33 @@ class Simplex_tree_interface : public Simplex_tree { return new_dgm; } + Simplex_tree_interface* collapse_edges(int nb_collapse_iteration) { + using Filtered_edge = std::tuple; + std::vector edges; + for (Simplex_handle sh : Base::skeleton_simplex_range(1)) { + if (Base::dimension(sh) == 1) { + typename Base::Simplex_vertex_range rg = Base::simplex_vertex_range(sh); + std::vector rips_edge(rg.begin(), rg.end()); + edges.push_back(std::make_tuple(rips_edge[0], rips_edge[1], Base::filtration(sh))); + } + } + + std::vector remaining_edges; + for (int iteration = 0; iteration < nb_collapse_iteration; iteration++) { + remaining_edges = Gudhi::collapse::flag_complex_collapse_edges(edges); + edges = std::move(remaining_edges); + remaining_edges.clear(); + } + Simplex_tree_interface* collapsed_stree_ptr = new Simplex_tree_interface(); + for (auto remaining_edge : edges) { + collapsed_stree_ptr->insert({std::get<0>(remaining_edge)}, 0.); + collapsed_stree_ptr->insert({std::get<1>(remaining_edge)}, 0.); + collapsed_stree_ptr->insert({std::get<0>(remaining_edge), std::get<1>(remaining_edge)}, std::get<2>(remaining_edge)); + } + collapsed_stree_ptr->initialize_filtration(); + return collapsed_stree_ptr; + } + // Iterator over the simplex tree Complex_simplex_iterator get_simplices_iterator_begin() { // this specific case works because the range is just a pair of iterators - won't work if range was a vector diff --git a/src/python/test/test_simplex_tree.py b/src/python/test/test_simplex_tree.py index 2137d822..30a8f5e0 100755 --- a/src/python/test/test_simplex_tree.py +++ b/src/python/test/test_simplex_tree.py @@ -340,3 +340,19 @@ def test_simplices_iterator(): assert st.find(simplex[0]) == True print("filtration is: ", simplex[1]) assert st.filtration(simplex[0]) == simplex[1] + +def test_collapse_edges(): + st = SimplexTree() + + assert st.insert([0, 1], filtration=1.0) == True + assert st.insert([1, 2], filtration=1.0) == True + assert st.insert([2, 3], filtration=1.0) == True + assert st.insert([0, 3], filtration=1.0) == True + assert st.insert([0, 2], filtration=2.0) == True + assert st.insert([1, 3], filtration=2.0) == True + + assert st.num_simplices() == 10 + + st.collapse_edges() + assert st.num_simplices() == 9 + assert st.find([1, 3]) == False -- cgit v1.2.3 From 39fba06ef758483bc237b9375413974c3bbc16e4 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 31 Jul 2020 17:34:47 +0200 Subject: code review: collapse edges should copy the 0-skeleton. A test was added --- src/python/include/Simplex_tree_interface.h | 7 +++++-- src/python/test/test_simplex_tree.py | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src/python/test/test_simplex_tree.py') diff --git a/src/python/include/Simplex_tree_interface.h b/src/python/include/Simplex_tree_interface.h index ad0f9a28..f786ad6e 100644 --- a/src/python/include/Simplex_tree_interface.h +++ b/src/python/include/Simplex_tree_interface.h @@ -176,9 +176,12 @@ class Simplex_tree_interface : public Simplex_tree { edges = Gudhi::collapse::flag_complex_collapse_edges(edges); } Simplex_tree_interface* collapsed_stree_ptr = new Simplex_tree_interface(); + // Copy the original 0-skeleton + for (Simplex_handle sh : Base::skeleton_simplex_range(0)) { + collapsed_stree_ptr->insert({*(Base::simplex_vertex_range(sh).begin())}, Base::filtration(sh)); + } + // Insert remaining edges for (auto remaining_edge : edges) { - collapsed_stree_ptr->insert({std::get<0>(remaining_edge)}, 0.); - collapsed_stree_ptr->insert({std::get<1>(remaining_edge)}, 0.); collapsed_stree_ptr->insert({std::get<0>(remaining_edge), std::get<1>(remaining_edge)}, std::get<2>(remaining_edge)); } return collapsed_stree_ptr; diff --git a/src/python/test/test_simplex_tree.py b/src/python/test/test_simplex_tree.py index 30a8f5e0..83be0602 100755 --- a/src/python/test/test_simplex_tree.py +++ b/src/python/test/test_simplex_tree.py @@ -356,3 +356,5 @@ def test_collapse_edges(): st.collapse_edges() assert st.num_simplices() == 9 assert st.find([1, 3]) == False + for simplex in st.get_skeleton(0): + assert simplex[1] == 1. -- cgit v1.2.3 From 8f9c065df7f4629555ef09292c14c293891f1bdc Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 12 Aug 2020 10:03:26 +0200 Subject: code review: Add test to get boundaries from a vertex --- src/python/test/test_simplex_tree.py | 1 + 1 file changed, 1 insertion(+) (limited to 'src/python/test/test_simplex_tree.py') diff --git a/src/python/test/test_simplex_tree.py b/src/python/test/test_simplex_tree.py index 7c49cb1a..036e88df 100755 --- a/src/python/test/test_simplex_tree.py +++ b/src/python/test/test_simplex_tree.py @@ -349,3 +349,4 @@ def test_boundaries_iterator(): assert list(st.get_boundaries([1, 2, 3])) == [([1, 2], 1.0), ([1, 3], 1.0), ([2, 3], 1.0)] assert list(st.get_boundaries([2, 3, 4])) == [([2, 3], 1.0), ([2, 4], 2.0), ([3, 4], 2.0)] + assert list(st.get_boundaries([2])) == [] -- cgit v1.2.3 From 458bc2dcf5044e1d5fde5326b2be35e526abd457 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 12 Aug 2020 13:06:03 +0200 Subject: code review: boundaries uses only once find and return a pair of iterator. Exception is raised when not found. tested --- src/python/gudhi/simplex_tree.pxd | 3 +-- src/python/gudhi/simplex_tree.pyx | 14 ++++++++------ src/python/include/Simplex_tree_interface.h | 12 +++++------- src/python/test/test_simplex_tree.py | 9 +++++++++ 4 files changed, 23 insertions(+), 15 deletions(-) (limited to 'src/python/test/test_simplex_tree.py') diff --git a/src/python/gudhi/simplex_tree.pxd b/src/python/gudhi/simplex_tree.pxd index a64599e7..e1b03391 100644 --- a/src/python/gudhi/simplex_tree.pxd +++ b/src/python/gudhi/simplex_tree.pxd @@ -71,8 +71,7 @@ cdef extern from "Simplex_tree_interface.h" namespace "Gudhi": vector[Simplex_tree_simplex_handle].const_iterator get_filtration_iterator_end() nogil Simplex_tree_skeleton_iterator get_skeleton_iterator_begin(int dimension) nogil Simplex_tree_skeleton_iterator get_skeleton_iterator_end(int dimension) nogil - Simplex_tree_boundary_iterator get_boundary_iterator_begin(vector[int] simplex) nogil - Simplex_tree_boundary_iterator get_boundary_iterator_end(vector[int] simplex) nogil + pair[Simplex_tree_boundary_iterator, Simplex_tree_boundary_iterator] get_boundary_iterators(vector[int] simplex) nogil except + cdef extern from "Persistent_cohomology_interface.h" namespace "Gudhi": cdef cppclass Simplex_tree_persistence_interface "Gudhi::Persistent_cohomology_interface>": diff --git a/src/python/gudhi/simplex_tree.pyx b/src/python/gudhi/simplex_tree.pyx index 3ebae923..bc5b43f4 100644 --- a/src/python/gudhi/simplex_tree.pyx +++ b/src/python/gudhi/simplex_tree.pyx @@ -293,12 +293,14 @@ cdef class SimplexTree: :returns: The (simplices of the) boundary of a simplex :rtype: generator with tuples(simplex, filtration) """ - cdef Simplex_tree_boundary_iterator it = self.get_ptr().get_boundary_iterator_begin(simplex) - cdef Simplex_tree_boundary_iterator end = self.get_ptr().get_boundary_iterator_end(simplex) - - while it != end: - yield self.get_ptr().get_simplex_and_filtration(dereference(it)) - preincrement(it) + cdef pair[Simplex_tree_boundary_iterator, Simplex_tree_boundary_iterator] it = self.get_ptr().get_boundary_iterators(simplex) + + try: + while it.first != it.second: + yield self.get_ptr().get_simplex_and_filtration(dereference(it.first)) + preincrement(it.first) + except RuntimeError: + print("simplex not found - cannot find boundaries") def remove_maximal_simplex(self, simplex): diff --git a/src/python/include/Simplex_tree_interface.h b/src/python/include/Simplex_tree_interface.h index c4f18eeb..2c695d1b 100644 --- a/src/python/include/Simplex_tree_interface.h +++ b/src/python/include/Simplex_tree_interface.h @@ -190,14 +190,12 @@ class Simplex_tree_interface : public Simplex_tree { return Base::skeleton_simplex_range(dimension).end(); } - Boundary_simplex_iterator get_boundary_iterator_begin(const Simplex& simplex) { + std::pair get_boundary_iterators(const Simplex& simplex) { + auto bd_sh = Base::find(simplex); + if (bd_sh == Base::null_simplex()) + throw std::runtime_error("simplex not found - cannot find boundaries"); // this specific case works because the range is just a pair of iterators - won't work if range was a vector - return Base::boundary_simplex_range(Base::find(simplex)).begin(); - } - - Boundary_simplex_iterator get_boundary_iterator_end(const Simplex& simplex) { - // this specific case works because the range is just a pair of iterators - won't work if range was a vector - return Base::boundary_simplex_range(Base::find(simplex)).end(); + return std::make_pair(Base::boundary_simplex_range(bd_sh).begin(), Base::boundary_simplex_range(bd_sh).end()); } }; diff --git a/src/python/test/test_simplex_tree.py b/src/python/test/test_simplex_tree.py index 036e88df..828400fb 100755 --- a/src/python/test/test_simplex_tree.py +++ b/src/python/test/test_simplex_tree.py @@ -350,3 +350,12 @@ def test_boundaries_iterator(): assert list(st.get_boundaries([1, 2, 3])) == [([1, 2], 1.0), ([1, 3], 1.0), ([2, 3], 1.0)] assert list(st.get_boundaries([2, 3, 4])) == [([2, 3], 1.0), ([2, 4], 2.0), ([3, 4], 2.0)] assert list(st.get_boundaries([2])) == [] + + with pytest.raises(RuntimeError): + list(st.get_boundaries([])) + + with pytest.raises(RuntimeError): + list(st.get_boundaries([0, 4])) # (0, 4) does not exist + + with pytest.raises(RuntimeError): + list(st.get_boundaries([6])) # (6) does not exist -- cgit v1.2.3 From ddb2118f0af865588d7c14b88171dc04bb27c529 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Tue, 18 Aug 2020 14:38:31 +0200 Subject: reset_filtration from a dimension (instead of 'until') --- src/Simplex_tree/include/gudhi/Simplex_tree.h | 31 ++++++++++++++---------- src/Simplex_tree/test/simplex_tree_unit_test.cpp | 14 +++++++---- src/python/gudhi/simplex_tree.pyx | 17 +++++++------ src/python/test/test_simplex_tree.py | 9 ++++--- 4 files changed, 41 insertions(+), 30 deletions(-) (limited to 'src/python/test/test_simplex_tree.py') diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree.h b/src/Simplex_tree/include/gudhi/Simplex_tree.h index adc8e801..89b4a5df 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h @@ -1668,31 +1668,36 @@ class Simplex_tree { } public: - /** \brief This function resets filtration value until a given dimension. + /** \brief This function resets filtration value from a given dimension. Resets all the Simplex_tree when + * `min_dim = 0`. * @param[in] filt_value The new filtration value. - * @param[in] max_dim The maximal dimension. + * @param[in] min_dim The minimal dimension. */ - void reset_filtration(Filtration_value filt_value, int max_dim) { + void reset_filtration(Filtration_value filt_value, int min_dim) { for (auto& simplex : root_.members()) { - simplex.second.assign_filtration(filt_value); - if (has_children(&simplex) && max_dim > 0) { - rec_reset_filtration(simplex.second.children(), filt_value, (max_dim - 1)); + if (min_dim <= 0) { + simplex.second.assign_filtration(filt_value); + } + if (has_children(&simplex)) { + rec_reset_filtration(simplex.second.children(), filt_value, min_dim); } } clear_filtration(); // Drop the cache. } private: - /** \brief Recursively resets filtration value until a given dimension. + /** \brief Recursively resets filtration value from a given dimension. * @param[in] sib Siblings to be parsed. * @param[in] filt_value The new filtration value. - * @param[in] max_dim The maximal dimension. + * @param[in] min_dim The maximal dimension. */ - void rec_reset_filtration(Siblings * sib, Filtration_value filt_value, int max_dim) { - for (auto& simplex : sib->members()) { - simplex.second.assign_filtration(filt_value); - if (has_children(&simplex) && max_dim > 0) { - rec_reset_filtration(simplex.second.children(), filt_value, (max_dim - 1)); + void rec_reset_filtration(Siblings * sib, Filtration_value filt_value, int min_dim) { + for (auto sh = sib->members().begin(); sh != sib->members().end(); ++sh) { + if (min_dim <= dimension(sh)) { + sh->second.assign_filtration(filt_value); + } + if (has_children(sh)) { + rec_reset_filtration(sh->second.children(), filt_value, min_dim); } } } diff --git a/src/Simplex_tree/test/simplex_tree_unit_test.cpp b/src/Simplex_tree/test/simplex_tree_unit_test.cpp index 9780f5b0..bdd41d34 100644 --- a/src/Simplex_tree/test/simplex_tree_unit_test.cpp +++ b/src/Simplex_tree/test/simplex_tree_unit_test.cpp @@ -965,21 +965,25 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_reset_filtration, typeST, list_of_tes for (auto vertex : st.simplex_vertex_range(f_simplex)) { std::clog << vertex << ","; } - std::clog << ") - filtration =" << st.filtration(f_simplex) << std::endl; + std::clog << ") - filtration = " << st.filtration(f_simplex); + std::clog << " - dimension = " << st.dimension(f_simplex) << std::endl; + // Guaranteed by construction BOOST_CHECK(st.filtration(f_simplex) >= 2.); } // dimension until 5 even if simplex tree is of dimension 3 to test the limits - for(int dimension = 0; dimension < 6; dimension ++) { + for(int dimension = 5; dimension >= 0; dimension --) { + std::clog << "### reset_filtration - dimension = " << dimension << "\n"; st.reset_filtration(0., dimension); for (auto f_simplex : st.skeleton_simplex_range(3)) { std::clog << "vertex = ("; for (auto vertex : st.simplex_vertex_range(f_simplex)) { std::clog << vertex << ","; } - std::clog << ") - filtration =" << st.filtration(f_simplex) << std::endl; - if (st.dimension(f_simplex) > dimension) - BOOST_CHECK(st.filtration(f_simplex) >= 1.); + std::clog << ") - filtration = " << st.filtration(f_simplex); + std::clog << " - dimension = " << st.dimension(f_simplex) << std::endl; + if (st.dimension(f_simplex) < dimension) + BOOST_CHECK(st.filtration(f_simplex) >= 2.); else BOOST_CHECK(st.filtration(f_simplex) == 0.); } diff --git a/src/python/gudhi/simplex_tree.pyx b/src/python/gudhi/simplex_tree.pyx index b7682693..657d55be 100644 --- a/src/python/gudhi/simplex_tree.pyx +++ b/src/python/gudhi/simplex_tree.pyx @@ -328,7 +328,7 @@ cdef class SimplexTree: return self.get_ptr().prune_above_filtration(filtration) def expansion(self, max_dim): - """Expands the Simplex_tree containing only its one skeleton + """Expands the simplex tree containing only its one skeleton until dimension max_dim. The expanded simplicial complex until dimension :math:`d` @@ -338,7 +338,7 @@ cdef class SimplexTree: The filtration value assigned to a simplex is the maximal filtration value of one of its edges. - The Simplex_tree must contain no simplex of dimension bigger than + The simplex tree must contain no simplex of dimension bigger than 1 when calling the method. :param max_dim: The maximal dimension. @@ -358,15 +358,16 @@ cdef class SimplexTree: """ return self.get_ptr().make_filtration_non_decreasing() - def reset_filtration(self, filtration, max_dim): - """This function resets filtration value until a given dimension. + def reset_filtration(self, filtration, min_dim): + """This function resets filtration value from a given dimension. + Resets all the simplex tree when `min_dim = 0`. :param filtration: New threshold value. :type filtration: float. - :param max_dim: The maximal dimension. + :param max_dim: The minimal dimension. :type max_dim: int. """ - self.get_ptr().reset_filtration(filtration, max_dim) + self.get_ptr().reset_filtration(filtration, min_dim) def extend_filtration(self): """ Extend filtration for computing extended persistence. This function only uses the @@ -376,14 +377,14 @@ cdef class SimplexTree: .. note:: Note that after calling this function, the filtration - values are actually modified within the Simplex_tree. + values are actually modified within the simplex tree. The function :func:`extended_persistence` retrieves the original values. .. note:: Note that this code creates an extra vertex internally, so you should make sure that - the Simplex_tree does not contain a vertex with the largest possible value (i.e., 4294967295). + the simplex tree does not contain a vertex with the largest possible value (i.e., 4294967295). """ self.get_ptr().compute_extended_filtration() diff --git a/src/python/test/test_simplex_tree.py b/src/python/test/test_simplex_tree.py index 6f1d01cc..ac2b59c7 100755 --- a/src/python/test/test_simplex_tree.py +++ b/src/python/test/test_simplex_tree.py @@ -367,15 +367,16 @@ def test_reset_filtration(): assert st.insert([3, 4, 5], 3.) == True assert st.insert([0, 1, 6, 7], 4.) == True + # Guaranteed by construction for simplex in st.get_simplices(): - assert st.filtration(simplex[0]) >= 0. + assert st.filtration(simplex[0]) >= 2. # dimension until 5 even if simplex tree is of dimension 3 to test the limits - for dimension in range(0, 6): + for dimension in range(5, -1, -1): st.reset_filtration(0., dimension) for simplex in st.get_skeleton(3): print(simplex) - if len(simplex[0]) > (dimension + 1): - assert st.filtration(simplex[0]) >= 1. + if len(simplex[0]) < (dimension) + 1: + assert st.filtration(simplex[0]) >= 2. else: assert st.filtration(simplex[0]) == 0. -- cgit v1.2.3 From fda0084941ece5d41a258d19ca4eb0b3d87384a4 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 9 Dec 2020 09:41:13 +0100 Subject: Fix #388 --- src/cmake/modules/GUDHI_third_party_libraries.cmake | 1 - src/python/CMakeLists.txt | 1 + src/python/gudhi/simplex_tree.pxd | 2 ++ src/python/gudhi/simplex_tree.pyx | 3 +++ src/python/include/Simplex_tree_interface.h | 10 +++++++++- src/python/test/test_simplex_tree.py | 14 +++++++++----- 6 files changed, 24 insertions(+), 7 deletions(-) (limited to 'src/python/test/test_simplex_tree.py') diff --git a/src/cmake/modules/GUDHI_third_party_libraries.cmake b/src/cmake/modules/GUDHI_third_party_libraries.cmake index e2684aa4..e1566877 100644 --- a/src/cmake/modules/GUDHI_third_party_libraries.cmake +++ b/src/cmake/modules/GUDHI_third_party_libraries.cmake @@ -58,7 +58,6 @@ endif(WITH_GUDHI_USE_TBB) set(CGAL_WITH_EIGEN3_VERSION 0.0.0) find_package(Eigen3 3.1.0) if (EIGEN3_FOUND) - add_definitions(-DGUDHI_USE_EIGEN3) include( ${EIGEN3_USE_FILE} ) set(CGAL_WITH_EIGEN3_VERSION ${CGAL_VERSION}) endif (EIGEN3_FOUND) diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index 2d5f793a..45c89609 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -133,6 +133,7 @@ if(PYTHONINTERP_FOUND) add_gudhi_debug_info("Eigen3 version ${EIGEN3_VERSION}") # No problem, even if no CGAL found set(GUDHI_PYTHON_EXTRA_COMPILE_ARGS "${GUDHI_PYTHON_EXTRA_COMPILE_ARGS}'-DCGAL_EIGEN3_ENABLED', ") + set(GUDHI_PYTHON_EXTRA_COMPILE_ARGS "${GUDHI_PYTHON_EXTRA_COMPILE_ARGS}'-DGUDHI_USE_EIGEN3', ") endif (EIGEN3_FOUND) set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'off_reader', ") diff --git a/src/python/gudhi/simplex_tree.pxd b/src/python/gudhi/simplex_tree.pxd index 3c4cbed3..283830ff 100644 --- a/src/python/gudhi/simplex_tree.pxd +++ b/src/python/gudhi/simplex_tree.pxd @@ -74,6 +74,8 @@ cdef extern from "Simplex_tree_interface.h" namespace "Gudhi": Simplex_tree_skeleton_iterator get_skeleton_iterator_begin(int dimension) nogil Simplex_tree_skeleton_iterator get_skeleton_iterator_end(int dimension) nogil pair[Simplex_tree_boundary_iterator, Simplex_tree_boundary_iterator] get_boundary_iterators(vector[int] simplex) nogil except + + + cdef int _GUDHI_USE_EIGEN3 cdef extern from "Persistent_cohomology_interface.h" namespace "Gudhi": cdef cppclass Simplex_tree_persistence_interface "Gudhi::Persistent_cohomology_interface>": diff --git a/src/python/gudhi/simplex_tree.pyx b/src/python/gudhi/simplex_tree.pyx index 7d6ab89a..eb44c0fc 100644 --- a/src/python/gudhi/simplex_tree.pyx +++ b/src/python/gudhi/simplex_tree.pyx @@ -17,6 +17,9 @@ __author__ = "Vincent Rouvreau" __copyright__ = "Copyright (C) 2016 Inria" __license__ = "MIT" +# For unitary tests purpose +__GUDHI_USE_EIGEN3 = _GUDHI_USE_EIGEN3 + # SimplexTree python interface cdef class SimplexTree: """The simplex tree is an efficient and flexible data structure for diff --git a/src/python/include/Simplex_tree_interface.h b/src/python/include/Simplex_tree_interface.h index 2bd704b4..50592e25 100644 --- a/src/python/include/Simplex_tree_interface.h +++ b/src/python/include/Simplex_tree_interface.h @@ -27,6 +27,12 @@ namespace Gudhi { +#ifdef GUDHI_USE_EIGEN3 +const int _GUDHI_USE_EIGEN3 = 1; +#else +const int _GUDHI_USE_EIGEN3 = 0; +#endif + template class Simplex_tree_interface : public Simplex_tree { public: @@ -191,7 +197,9 @@ class Simplex_tree_interface : public Simplex_tree { } return collapsed_stree_ptr; #else - return this; + // If no Eigen3, return a copy, as it will be deleted in pyx + Simplex_tree_interface* collapsed_stree_ptr = new Simplex_tree_interface(*this); + return collapsed_stree_ptr; #endif } diff --git a/src/python/test/test_simplex_tree.py b/src/python/test/test_simplex_tree.py index 3b23fa0b..15b472ee 100755 --- a/src/python/test/test_simplex_tree.py +++ b/src/python/test/test_simplex_tree.py @@ -8,7 +8,7 @@ - YYYY/MM Author: Description of the modification """ -from gudhi import SimplexTree +from gudhi import SimplexTree, simplex_tree import pytest __author__ = "Vincent Rouvreau" @@ -353,11 +353,15 @@ def test_collapse_edges(): assert st.num_simplices() == 10 + # If no Eigen3, collapse_edges just return a copy, no action. Maybe it would require some user warning st.collapse_edges() - assert st.num_simplices() == 9 - assert st.find([1, 3]) == False - for simplex in st.get_skeleton(0): - assert simplex[1] == 1. + if simplex_tree.__GUDHI_USE_EIGEN3: + assert st.num_simplices() == 9 + assert st.find([1, 3]) == False + for simplex in st.get_skeleton(0): + assert simplex[1] == 1. + else: + assert st.num_simplices() == 10 def test_reset_filtration(): st = SimplexTree() -- cgit v1.2.3 From 957da77f9484972ce34d0415502887f92080878e Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 11 Dec 2020 09:38:12 +0100 Subject: code review: GUDHI_USE_EIGEN3 generated by CMake in __init__.py as suggested and roll back the other solution --- src/python/CMakeLists.txt | 2 ++ src/python/gudhi/__init__.py.in | 4 ++++ src/python/gudhi/simplex_tree.pxd | 2 -- src/python/gudhi/simplex_tree.pyx | 3 --- src/python/include/Simplex_tree_interface.h | 6 ------ src/python/test/test_simplex_tree.py | 4 ++-- 6 files changed, 8 insertions(+), 13 deletions(-) (limited to 'src/python/test/test_simplex_tree.py') diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index 45c89609..5a245aac 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -129,11 +129,13 @@ if(PYTHONINTERP_FOUND) set(GUDHI_PYTHON_EXTRA_COMPILE_ARGS "${GUDHI_PYTHON_EXTRA_COMPILE_ARGS}'-DDEBUG_TRACES', ") endif() + set(GUDHI_USE_EIGEN3 "False") if (EIGEN3_FOUND) add_gudhi_debug_info("Eigen3 version ${EIGEN3_VERSION}") # No problem, even if no CGAL found set(GUDHI_PYTHON_EXTRA_COMPILE_ARGS "${GUDHI_PYTHON_EXTRA_COMPILE_ARGS}'-DCGAL_EIGEN3_ENABLED', ") set(GUDHI_PYTHON_EXTRA_COMPILE_ARGS "${GUDHI_PYTHON_EXTRA_COMPILE_ARGS}'-DGUDHI_USE_EIGEN3', ") + set(GUDHI_USE_EIGEN3 "True") endif (EIGEN3_FOUND) set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'off_reader', ") diff --git a/src/python/gudhi/__init__.py.in b/src/python/gudhi/__init__.py.in index 79e12fbc..3043201a 100644 --- a/src/python/gudhi/__init__.py.in +++ b/src/python/gudhi/__init__.py.in @@ -23,6 +23,10 @@ __all__ = [@GUDHI_PYTHON_MODULES@ @GUDHI_PYTHON_MODULES_EXTRA@] __available_modules = '' __missing_modules = '' +# For unitary tests purpose +# could use "if 'collapse_edges' in gudhi.__all__" when collapse edges will have a python module +__GUDHI_USE_EIGEN3 = @GUDHI_USE_EIGEN3@ + # Try to import * from gudhi.__module_name for default modules. # Extra modules require an explicit import by the user (mostly because of # unusual dependencies, but also to avoid cluttering namespace gudhi and diff --git a/src/python/gudhi/simplex_tree.pxd b/src/python/gudhi/simplex_tree.pxd index 283830ff..3c4cbed3 100644 --- a/src/python/gudhi/simplex_tree.pxd +++ b/src/python/gudhi/simplex_tree.pxd @@ -74,8 +74,6 @@ cdef extern from "Simplex_tree_interface.h" namespace "Gudhi": Simplex_tree_skeleton_iterator get_skeleton_iterator_begin(int dimension) nogil Simplex_tree_skeleton_iterator get_skeleton_iterator_end(int dimension) nogil pair[Simplex_tree_boundary_iterator, Simplex_tree_boundary_iterator] get_boundary_iterators(vector[int] simplex) nogil except + - - cdef int _GUDHI_USE_EIGEN3 cdef extern from "Persistent_cohomology_interface.h" namespace "Gudhi": cdef cppclass Simplex_tree_persistence_interface "Gudhi::Persistent_cohomology_interface>": diff --git a/src/python/gudhi/simplex_tree.pyx b/src/python/gudhi/simplex_tree.pyx index eb44c0fc..7d6ab89a 100644 --- a/src/python/gudhi/simplex_tree.pyx +++ b/src/python/gudhi/simplex_tree.pyx @@ -17,9 +17,6 @@ __author__ = "Vincent Rouvreau" __copyright__ = "Copyright (C) 2016 Inria" __license__ = "MIT" -# For unitary tests purpose -__GUDHI_USE_EIGEN3 = _GUDHI_USE_EIGEN3 - # SimplexTree python interface cdef class SimplexTree: """The simplex tree is an efficient and flexible data structure for diff --git a/src/python/include/Simplex_tree_interface.h b/src/python/include/Simplex_tree_interface.h index 50592e25..82444609 100644 --- a/src/python/include/Simplex_tree_interface.h +++ b/src/python/include/Simplex_tree_interface.h @@ -27,12 +27,6 @@ namespace Gudhi { -#ifdef GUDHI_USE_EIGEN3 -const int _GUDHI_USE_EIGEN3 = 1; -#else -const int _GUDHI_USE_EIGEN3 = 0; -#endif - template class Simplex_tree_interface : public Simplex_tree { public: diff --git a/src/python/test/test_simplex_tree.py b/src/python/test/test_simplex_tree.py index 15b472ee..0c072baa 100755 --- a/src/python/test/test_simplex_tree.py +++ b/src/python/test/test_simplex_tree.py @@ -8,7 +8,7 @@ - YYYY/MM Author: Description of the modification """ -from gudhi import SimplexTree, simplex_tree +from gudhi import SimplexTree, __GUDHI_USE_EIGEN3 import pytest __author__ = "Vincent Rouvreau" @@ -355,7 +355,7 @@ def test_collapse_edges(): # If no Eigen3, collapse_edges just return a copy, no action. Maybe it would require some user warning st.collapse_edges() - if simplex_tree.__GUDHI_USE_EIGEN3: + if __GUDHI_USE_EIGEN3: assert st.num_simplices() == 9 assert st.find([1, 3]) == False for simplex in st.get_skeleton(0): -- cgit v1.2.3 From 40e0976e8dae27f0e30f3c9df1fd7de1a7343948 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 11 Dec 2020 10:31:09 +0100 Subject: code review: throw an eception if collapse_edges when no Eigen3 --- src/python/gudhi/simplex_tree.pxd | 2 +- src/python/gudhi/simplex_tree.pyx | 4 ++-- src/python/include/Simplex_tree_interface.h | 4 +--- src/python/test/test_simplex_tree.py | 7 ++++--- 4 files changed, 8 insertions(+), 9 deletions(-) (limited to 'src/python/test/test_simplex_tree.py') diff --git a/src/python/gudhi/simplex_tree.pxd b/src/python/gudhi/simplex_tree.pxd index 3c4cbed3..000323af 100644 --- a/src/python/gudhi/simplex_tree.pxd +++ b/src/python/gudhi/simplex_tree.pxd @@ -63,7 +63,7 @@ cdef extern from "Simplex_tree_interface.h" namespace "Gudhi": bool make_filtration_non_decreasing() nogil void compute_extended_filtration() nogil vector[vector[pair[int, pair[double, double]]]] compute_extended_persistence_subdiagrams(vector[pair[int, pair[double, double]]] dgm, double min_persistence) nogil - Simplex_tree_interface_full_featured* collapse_edges(int nb_collapse_iteration) nogil + Simplex_tree_interface_full_featured* collapse_edges(int nb_collapse_iteration) nogil except + void reset_filtration(double filtration, int dimension) nogil # Iterators over Simplex tree pair[vector[int], double] get_simplex_and_filtration(Simplex_tree_simplex_handle f_simplex) nogil diff --git a/src/python/gudhi/simplex_tree.pyx b/src/python/gudhi/simplex_tree.pyx index 7d6ab89a..665d41e6 100644 --- a/src/python/gudhi/simplex_tree.pyx +++ b/src/python/gudhi/simplex_tree.pyx @@ -628,8 +628,8 @@ cdef class SimplexTree: :param nb_iterations: The number of edge collapse iterations to perform. Default is 1. :type nb_iterations: int - :note: collapse_edges function requires `Eigen `_ >= 3.1.0, otherwise no action is - performed. + :note: collapse_edges method requires `Eigen `_ >= 3.1.0 and an exception is thrown + if this method is not available. """ # Backup old pointer cdef Simplex_tree_interface_full_featured* ptr = self.get_ptr() diff --git a/src/python/include/Simplex_tree_interface.h b/src/python/include/Simplex_tree_interface.h index 82444609..629f6083 100644 --- a/src/python/include/Simplex_tree_interface.h +++ b/src/python/include/Simplex_tree_interface.h @@ -191,9 +191,7 @@ class Simplex_tree_interface : public Simplex_tree { } return collapsed_stree_ptr; #else - // If no Eigen3, return a copy, as it will be deleted in pyx - Simplex_tree_interface* collapsed_stree_ptr = new Simplex_tree_interface(*this); - return collapsed_stree_ptr; + throw std::runtime_error("Unable to collapse edges as it requires Eigen3 >= 3.1.0."); #endif } diff --git a/src/python/test/test_simplex_tree.py b/src/python/test/test_simplex_tree.py index 0c072baa..a3eacaa9 100755 --- a/src/python/test/test_simplex_tree.py +++ b/src/python/test/test_simplex_tree.py @@ -353,15 +353,16 @@ def test_collapse_edges(): assert st.num_simplices() == 10 - # If no Eigen3, collapse_edges just return a copy, no action. Maybe it would require some user warning - st.collapse_edges() if __GUDHI_USE_EIGEN3: + st.collapse_edges() assert st.num_simplices() == 9 assert st.find([1, 3]) == False for simplex in st.get_skeleton(0): assert simplex[1] == 1. else: - assert st.num_simplices() == 10 + # If no Eigen3, collapse_edges throws an exception + with pytest.raises(RuntimeError): + st.collapse_edges() def test_reset_filtration(): st = SimplexTree() -- cgit v1.2.3