summaryrefslogtreecommitdiff
path: root/src/python
diff options
context:
space:
mode:
authorMathieuCarriere <mathieu.carriere3@gmail.com>2022-04-03 20:30:14 +0200
committerMathieuCarriere <mathieu.carriere3@gmail.com>2022-04-03 20:30:14 +0200
commit6d9e3d393003ac2214426d5b796f560785a7fd3e (patch)
tree6e87645c26e5ce7ee4109eb5b512f3e84d31281a /src/python
parent6f4cc44210113e4c8a295aeeb75f61e1f2be2f02 (diff)
parentb066b4376abf66ddc76e61a6a815a409b05fe59b (diff)
Merge branch 'master' of https://github.com/GUDHI/gudhi-devel into diff
Diffstat (limited to 'src/python')
-rw-r--r--src/python/gudhi/simplex_tree.pxd3
-rw-r--r--src/python/gudhi/simplex_tree.pyx24
-rw-r--r--src/python/include/Simplex_tree_interface.h8
-rwxr-xr-xsrc/python/test/test_simplex_tree.py45
4 files changed, 80 insertions, 0 deletions
diff --git a/src/python/gudhi/simplex_tree.pxd b/src/python/gudhi/simplex_tree.pxd
index 5c98fb4a..4f229663 100644
--- a/src/python/gudhi/simplex_tree.pxd
+++ b/src/python/gudhi/simplex_tree.pxd
@@ -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>>":
diff --git a/src/python/gudhi/simplex_tree.pyx b/src/python/gudhi/simplex_tree.pyx
index b8fabf78..a4914184 100644
--- a/src/python/gudhi/simplex_tree.pyx
+++ b/src/python/gudhi/simplex_tree.pyx
@@ -16,6 +16,9 @@ __author__ = "Vincent Rouvreau"
__copyright__ = "Copyright (C) 2016 Inria"
__license__ = "MIT"
+cdef bool callback(vector[int] simplex, void *blocker_func):
+ return (<object>blocker_func)(simplex)
+
# SimplexTree python interface
cdef class SimplexTree:
"""The simplex tree is an efficient and flexible data structure for
@@ -474,6 +477,27 @@ cdef class SimplexTree:
persistence_result = self.pcohptr.get_persistence()
return self.get_ptr().compute_extended_persistence_subdiagrams(persistence_result, min_persistence)
+ def expansion_with_blocker(self, max_dim, blocker_func):
+ """Expands the Simplex_tree containing only a graph. Simplices corresponding to cliques in the graph are added
+ incrementally, faces before cofaces, unless the simplex has dimension larger than `max_dim` or `blocker_func`
+ returns `True` for this simplex.
+
+ The function identifies a candidate simplex whose faces are all already in the complex, inserts it with a
+ filtration value corresponding to the maximum of the filtration values of the faces, then calls `blocker_func`
+ with this new simplex (represented as a list of int). If `blocker_func` returns `True`, the simplex is removed,
+ otherwise it is kept. The algorithm then proceeds with the next candidate.
+
+ .. warning::
+ Several candidates of the same dimension may be inserted simultaneously before calling `block_simplex`, so
+ if you examine the complex in `block_simplex`, you may hit a few simplices of the same dimension that have
+ not been vetted by `block_simplex` yet, or have already been rejected but not yet removed.
+
+ :param max_dim: Expansion maximal dimension value.
+ :type max_dim: int
+ :param blocker_func: Blocker oracle.
+ :type blocker_func: Callable[[List[int]], bool]
+ """
+ self.get_ptr().expansion_with_blockers_callback(max_dim, callback, <void*>blocker_func)
def persistence(self, homology_coeff_field=11, min_persistence=0, persistence_dim_max = False):
"""This function computes and returns the persistence of the simplicial complex.
diff --git a/src/python/include/Simplex_tree_interface.h b/src/python/include/Simplex_tree_interface.h
index 629f6083..aa3dac18 100644
--- a/src/python/include/Simplex_tree_interface.h
+++ b/src/python/include/Simplex_tree_interface.h
@@ -42,6 +42,7 @@ class Simplex_tree_interface : public Simplex_tree<SimplexTreeOptions> {
using Complex_simplex_iterator = typename Base::Complex_simplex_iterator;
using Extended_filtration_data = typename Base::Extended_filtration_data;
using Boundary_simplex_iterator = typename Base::Boundary_simplex_iterator;
+ typedef bool (*blocker_func_t)(Simplex simplex, void *user_data);
public:
@@ -195,6 +196,13 @@ class Simplex_tree_interface : public Simplex_tree<SimplexTreeOptions> {
#endif
}
+ void expansion_with_blockers_callback(int dimension, blocker_func_t user_func, void *user_data) {
+ Base::expansion_with_blockers(dimension, [&](Simplex_handle sh){
+ Simplex simplex(Base::simplex_vertex_range(sh).begin(), Base::simplex_vertex_range(sh).end());
+ return user_func(simplex, user_data);
+ });
+ }
+
// 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 a8180ce8..eb481a49 100755
--- a/src/python/test/test_simplex_tree.py
+++ b/src/python/test/test_simplex_tree.py
@@ -515,3 +515,48 @@ def test_simplex_tree_deep_copy_constructor():
def test_simplex_tree_constructor_exception():
with pytest.raises(TypeError):
st = SimplexTree(other = "Construction from a string shall raise an exception")
+
+def test_expansion_with_blocker():
+ st=SimplexTree()
+ st.insert([0,1],0)
+ st.insert([0,2],1)
+ st.insert([0,3],2)
+ st.insert([1,2],3)
+ st.insert([1,3],4)
+ st.insert([2,3],5)
+ st.insert([2,4],6)
+ st.insert([3,6],7)
+ st.insert([4,5],8)
+ st.insert([4,6],9)
+ st.insert([5,6],10)
+ st.insert([6],10)
+
+ def blocker(simplex):
+ try:
+ # Block all simplices that countains vertex 6
+ simplex.index(6)
+ print(simplex, ' is blocked')
+ return True
+ except ValueError:
+ print(simplex, ' is accepted')
+ st.assign_filtration(simplex, st.filtration(simplex) + 1.)
+ return False
+
+ st.expansion_with_blocker(2, blocker)
+ assert st.num_simplices() == 22
+ assert st.dimension() == 2
+ assert st.find([4,5,6]) == False
+ assert st.filtration([0,1,2]) == 4.
+ assert st.filtration([0,1,3]) == 5.
+ assert st.filtration([0,2,3]) == 6.
+ assert st.filtration([1,2,3]) == 6.
+
+ st.expansion_with_blocker(3, blocker)
+ assert st.num_simplices() == 23
+ assert st.dimension() == 3
+ assert st.find([4,5,6]) == False
+ assert st.filtration([0,1,2]) == 4.
+ assert st.filtration([0,1,3]) == 5.
+ assert st.filtration([0,2,3]) == 6.
+ assert st.filtration([1,2,3]) == 6.
+ assert st.filtration([0,1,2,3]) == 7.