Skip to content

Commit

Permalink
Merge pull request #389 from VincentRouvreau/expansion_with_blockers_…
Browse files Browse the repository at this point in the history
…python_itf

Simplex tree expansion_with_blockers python interface
  • Loading branch information
VincentRouvreau authored Mar 31, 2022
2 parents bbff86f + f6a4524 commit b066b43
Show file tree
Hide file tree
Showing 7 changed files with 236 additions and 44 deletions.
2 changes: 1 addition & 1 deletion src/Simplex_tree/include/gudhi/Simplex_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -1283,6 +1283,7 @@ class Simplex_tree {
Siblings * new_sib = new Siblings(siblings, // oncles
simplex->first, // parent
boost::adaptors::reverse(intersection)); // boost::container::ordered_unique_range_t
simplex->second.assign_children(new_sib);
std::vector<Vertex_handle> blocked_new_sib_vertex_list;
// As all intersections are inserted, we can call the blocker function on all new_sib members
for (auto new_sib_member = new_sib->members().begin();
Expand All @@ -1305,7 +1306,6 @@ class Simplex_tree {
new_sib->members().erase(blocked_new_sib_member);
}
// ensure recursive call
simplex->second.assign_children(new_sib);
siblings_expansion_with_blockers(new_sib, max_dim, k - 1, block_simplex);
}
} else {
Expand Down
6 changes: 6 additions & 0 deletions src/Simplex_tree/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,9 @@ if (TBB_FOUND)
target_link_libraries(Simplex_tree_make_filtration_non_decreasing_test_unit ${TBB_LIBRARIES})
endif()
gudhi_add_boost_test(Simplex_tree_make_filtration_non_decreasing_test_unit)

add_executable ( Simplex_tree_graph_expansion_test_unit simplex_tree_graph_expansion_unit_test.cpp )
if (TBB_FOUND)
target_link_libraries(Simplex_tree_graph_expansion_test_unit ${TBB_LIBRARIES})
endif()
gudhi_add_boost_test(Simplex_tree_graph_expansion_test_unit)
192 changes: 149 additions & 43 deletions src/Simplex_tree/test/simplex_tree_graph_expansion_unit_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,62 @@
*/

#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <utility> // std::pair, std::make_pair
#include <cmath> // float comparison
#include <limits>
#include <functional> // greater
#include <vector>

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE "simplex_tree"
#define BOOST_TEST_MODULE "simplex_tree_graph_expansion"
#include <boost/test/unit_test.hpp>
#include <boost/mpl/list.hpp>

// ^
// /!\ Nothing else from Simplex_tree shall be included to test includes are well defined.
#include "gudhi/Simplex_tree.h"
#include <gudhi/Unitary_tests_utils.h>

using namespace Gudhi;

typedef boost::mpl::list<Simplex_tree<>, Simplex_tree<Simplex_tree_options_fast_persistence>> list_of_tested_variants;

BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_expansion_all_is_blocked, typeST, list_of_tested_variants) {
std::clog << "********************************************************************\n";
std::clog << "simplex_tree_expansion_all_is_blocked\n";
std::clog << "********************************************************************\n";
using Simplex_handle = typename typeST::Simplex_handle;
// Construct the Simplex Tree with a 1-skeleton graph example
typeST simplex_tree;

simplex_tree.insert_simplex({0, 1}, 0.);
simplex_tree.insert_simplex({0, 2}, 1.);
simplex_tree.insert_simplex({0, 3}, 2.);
simplex_tree.insert_simplex({1, 2}, 3.);
simplex_tree.insert_simplex({1, 3}, 4.);
simplex_tree.insert_simplex({2, 3}, 5.);
simplex_tree.insert_simplex({2, 4}, 6.);
simplex_tree.insert_simplex({3, 6}, 7.);
simplex_tree.insert_simplex({4, 5}, 8.);
simplex_tree.insert_simplex({4, 6}, 9.);
simplex_tree.insert_simplex({5, 6}, 10.);
simplex_tree.insert_simplex({6}, 10.);

bool AreAlmostTheSame(float a, float b) {
return std::fabs(a - b) < std::numeric_limits<float>::epsilon();
typeST stree_copy = simplex_tree;

simplex_tree.expansion_with_blockers(3, [&](Simplex_handle sh){ return true; });

std::clog << "* The complex contains " << simplex_tree.num_simplices() << " simplices";
std::clog << " - dimension " << simplex_tree.dimension() << "\n";
std::clog << "* Iterator on Simplices in the filtration, with [filtration value]:\n";
for (auto f_simplex : simplex_tree.filtration_simplex_range()) {
std::clog << " " << "[" << simplex_tree.filtration(f_simplex) << "] ";
for (auto vertex : simplex_tree.simplex_vertex_range(f_simplex))
std::clog << "(" << vertex << ")";
std::clog << std::endl;
}

BOOST_CHECK(stree_copy == simplex_tree);
}

BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_expansion_with_blockers_3, typeST, list_of_tested_variants) {
std::clog << "********************************************************************\n";
std::clog << "simplex_tree_expansion_with_blockers_3\n";
std::clog << "********************************************************************\n";
using Simplex_handle = typename typeST::Simplex_handle;
// Construct the Simplex Tree with a 1-skeleton graph example
typeST simplex_tree;
Expand Down Expand Up @@ -72,9 +101,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_expansion_with_blockers_3, typeST, li
return result;
});

std::clog << "********************************************************************\n";
std::clog << "simplex_tree_expansion_with_blockers_3\n";
std::clog << "********************************************************************\n";
std::clog << "* The complex contains " << simplex_tree.num_simplices() << " simplices";
std::clog << " - dimension " << simplex_tree.dimension() << "\n";
std::clog << "* Iterator on Simplices in the filtration, with [filtration value]:\n";
Expand All @@ -89,15 +115,23 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_expansion_with_blockers_3, typeST, li
BOOST_CHECK(simplex_tree.dimension() == 3);
// {4, 5, 6} shall be blocked
BOOST_CHECK(simplex_tree.find({4, 5, 6}) == simplex_tree.null_simplex());
BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,2})), 4.));
BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,3})), 5.));
BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,2,3})), 6.));
BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({1,2,3})), 6.));
BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,2,3})), 7.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({0,1,2})),
static_cast<typename typeST::Filtration_value>(4.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({0,1,3})),
static_cast<typename typeST::Filtration_value>(5.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({0,2,3})),
static_cast<typename typeST::Filtration_value>(6.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({1,2,3})),
static_cast<typename typeST::Filtration_value>(6.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({0,1,2,3})),
static_cast<typename typeST::Filtration_value>(7.));

}

BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_expansion_with_blockers_2, typeST, list_of_tested_variants) {
std::clog << "********************************************************************\n";
std::clog << "simplex_tree_expansion_with_blockers_2\n";
std::clog << "********************************************************************\n";
using Simplex_handle = typename typeST::Simplex_handle;
// Construct the Simplex Tree with a 1-skeleton graph example
typeST simplex_tree;
Expand Down Expand Up @@ -134,9 +168,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_expansion_with_blockers_2, typeST, li
return result;
});

std::clog << "********************************************************************\n";
std::clog << "simplex_tree_expansion_with_blockers_2\n";
std::clog << "********************************************************************\n";
std::clog << "* The complex contains " << simplex_tree.num_simplices() << " simplices";
std::clog << " - dimension " << simplex_tree.dimension() << "\n";
std::clog << "* Iterator on Simplices in the filtration, with [filtration value]:\n";
Expand All @@ -151,14 +182,22 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_expansion_with_blockers_2, typeST, li
BOOST_CHECK(simplex_tree.dimension() == 2);
// {4, 5, 6} shall be blocked
BOOST_CHECK(simplex_tree.find({4, 5, 6}) == simplex_tree.null_simplex());
BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,2})), 4.));
BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,3})), 5.));
BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,2,3})), 6.));
BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({1,2,3})), 6.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({0,1,2})),
static_cast<typename typeST::Filtration_value>(4.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({0,1,3})),
static_cast<typename typeST::Filtration_value>(5.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({0,2,3})),
static_cast<typename typeST::Filtration_value>(6.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({1,2,3})),
static_cast<typename typeST::Filtration_value>(6.));
BOOST_CHECK(simplex_tree.find({0,1,2,3}) == simplex_tree.null_simplex());
}

BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_expansion, typeST, list_of_tested_variants) {
BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_expansion_with_find_simplex_blockers, typeST, list_of_tested_variants) {
std::clog << "********************************************************************\n";
std::clog << "simplex_tree_expansion_with_find_simplex_blockers\n";
std::clog << "********************************************************************\n";
using Simplex_handle = typename typeST::Simplex_handle;
// Construct the Simplex Tree with a 1-skeleton graph example
typeST simplex_tree;

Expand All @@ -175,10 +214,66 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_expansion, typeST, list_of_tested_var
simplex_tree.insert_simplex({5, 6}, 10.);
simplex_tree.insert_simplex({6}, 10.);

simplex_tree.expansion(3);
simplex_tree.expansion_with_blockers(3, [&](Simplex_handle sh){
bool result = false;
std::clog << "Blocker on [";
std::vector<typename typeST::Vertex_handle> simplex;
// User can loop on the vertices from the given simplex_handle i.e.
for (auto vertex : simplex_tree.simplex_vertex_range(sh)) {
// We block the expansion, if the vertex '1' is in the given list of vertices
if (vertex == 1)
result = true;
std::clog << vertex << ", ";
simplex.push_back(vertex);
}
std::clog << "] => " << result << std::endl;
// Not efficient but test it works - required by the python interface
BOOST_CHECK(simplex_tree.find(simplex) == sh);
return result;
});

std::clog << "* The complex contains " << simplex_tree.num_simplices() << " simplices";
std::clog << " - dimension " << simplex_tree.dimension() << "\n";
std::clog << "* Iterator on Simplices in the filtration, with [filtration value]:\n";
for (auto f_simplex : simplex_tree.filtration_simplex_range()) {
std::clog << " " << "[" << simplex_tree.filtration(f_simplex) << "] ";
for (auto vertex : simplex_tree.simplex_vertex_range(f_simplex))
std::clog << "(" << vertex << ")";
std::clog << std::endl;
}

BOOST_CHECK(simplex_tree.num_simplices() == 20);
BOOST_CHECK(simplex_tree.dimension() == 2);

// {1, 2, 3}, {0, 1, 2} and {0, 1, 3} shall be blocked as it contains vertex 1
BOOST_CHECK(simplex_tree.find({4, 5, 6}) != simplex_tree.null_simplex());
BOOST_CHECK(simplex_tree.find({1, 2, 3}) == simplex_tree.null_simplex());
BOOST_CHECK(simplex_tree.find({0, 2, 3}) != simplex_tree.null_simplex());
BOOST_CHECK(simplex_tree.find({0, 1, 2}) == simplex_tree.null_simplex());
BOOST_CHECK(simplex_tree.find({0, 1, 3}) == simplex_tree.null_simplex());
}

BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_expansion_3, typeST, list_of_tested_variants) {
std::clog << "********************************************************************\n";
std::clog << "simplex_tree_expansion_3\n";
std::clog << "********************************************************************\n";
// Construct the Simplex Tree with a 1-skeleton graph example
typeST simplex_tree;

simplex_tree.insert_simplex({0, 1}, 0.);
simplex_tree.insert_simplex({0, 2}, 1.);
simplex_tree.insert_simplex({0, 3}, 2.);
simplex_tree.insert_simplex({1, 2}, 3.);
simplex_tree.insert_simplex({1, 3}, 4.);
simplex_tree.insert_simplex({2, 3}, 5.);
simplex_tree.insert_simplex({2, 4}, 6.);
simplex_tree.insert_simplex({3, 6}, 7.);
simplex_tree.insert_simplex({4, 5}, 8.);
simplex_tree.insert_simplex({4, 6}, 9.);
simplex_tree.insert_simplex({5, 6}, 10.);
simplex_tree.insert_simplex({6}, 10.);

simplex_tree.expansion(3);
std::clog << "* The complex contains " << simplex_tree.num_simplices() << " simplices";
std::clog << " - dimension " << simplex_tree.dimension() << "\n";
std::clog << "* Iterator on Simplices in the filtration, with [filtration value]:\n";
Expand All @@ -192,16 +287,25 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_expansion, typeST, list_of_tested_var
BOOST_CHECK(simplex_tree.num_simplices() == 24);
BOOST_CHECK(simplex_tree.dimension() == 3);

BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({4,5,6})), 10.));
BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,2})), 3.));
BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,3})), 4.));
BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,2,3})), 5.));
BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({1,2,3})), 5.));
BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,2,3})), 5.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({4,5,6})),
static_cast<typename typeST::Filtration_value>(10.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({0,1,2})),
static_cast<typename typeST::Filtration_value>(3.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({0,1,3})),
static_cast<typename typeST::Filtration_value>(4.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({0,2,3})),
static_cast<typename typeST::Filtration_value>(5.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({1,2,3})),
static_cast<typename typeST::Filtration_value>(5.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({0,1,2,3})),
static_cast<typename typeST::Filtration_value>(5.));

}

BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_expansion_2, typeST, list_of_tested_variants) {
std::clog << "********************************************************************\n";
std::clog << "simplex_tree_expansion_2\n";
std::clog << "********************************************************************\n";
// Construct the Simplex Tree with a 1-skeleton graph example
typeST simplex_tree;

Expand All @@ -220,9 +324,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_expansion_2, typeST, list_of_tested_v

simplex_tree.expansion(2);

std::clog << "********************************************************************\n";
std::clog << "simplex_tree_expansion_2\n";
std::clog << "********************************************************************\n";
std::clog << "* The complex contains " << simplex_tree.num_simplices() << " simplices";
std::clog << " - dimension " << simplex_tree.dimension() << "\n";
std::clog << "* Iterator on Simplices in the filtration, with [filtration value]:\n";
Expand All @@ -236,10 +337,15 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_expansion_2, typeST, list_of_tested_v
BOOST_CHECK(simplex_tree.num_simplices() == 23);
BOOST_CHECK(simplex_tree.dimension() == 2);

BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({4,5,6})), 10.));
BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,2})), 3.));
BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,3})), 4.));
BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,2,3})), 5.));
BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({1,2,3})), 5.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({4,5,6})),
static_cast<typename typeST::Filtration_value>(10.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({0,1,2})),
static_cast<typename typeST::Filtration_value>(3.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({0,1,3})),
static_cast<typename typeST::Filtration_value>(4.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({0,2,3})),
static_cast<typename typeST::Filtration_value>(5.));
GUDHI_TEST_FLOAT_EQUALITY_CHECK(simplex_tree.filtration(simplex_tree.find({1,2,3})),
static_cast<typename typeST::Filtration_value>(5.));
BOOST_CHECK(simplex_tree.find({0,1,2,3}) == simplex_tree.null_simplex());
}
3 changes: 3 additions & 0 deletions src/python/gudhi/simplex_tree.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ 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 +
# Expansion with blockers
ctypedef bool (*blocker_func_t)(vector[int], void *user_data)
void expansion_with_blockers_callback(int dimension, blocker_func_t user_func, void *user_data)

cdef extern from "Persistent_cohomology_interface.h" namespace "Gudhi":
cdef cppclass Simplex_tree_persistence_interface "Gudhi::Persistent_cohomology_interface<Gudhi::Simplex_tree<Gudhi::Simplex_tree_options_full_featured>>":
Expand Down
Loading

0 comments on commit b066b43

Please sign in to comment.