Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplex tree expansion_with_blockers python interface #389

Merged
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