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

Multiparameter simplextree #817

Open
wants to merge 35 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
6f3aa21
added a first implementation of multiparameter simplextrees
DavidLapous Feb 15, 2023
8abadb5
Fixes and renaming
DavidLapous Feb 15, 2023
8ab7de0
Doc, cleaning
DavidLapous Feb 15, 2023
8e6ef26
Warning remove: Comment OpenMP parallel pragmas (need to rewrite this…
DavidLapous Feb 15, 2023
9525fe7
Removed unnecessary files, multi_filtration class, insert_batch, cleanup
DavidLapous Feb 17, 2023
3ab6d2c
Better filtration_domination citation
DavidLapous Feb 17, 2023
87821b9
Merge branch 'GUDHI:master' into master
DavidLapous Feb 21, 2023
7ac6fab
Merge branch 'GUDHI:master' into master
DavidLapous Mar 10, 2023
a603ef7
cleaner Filtration_type class
DavidLapous Mar 10, 2023
0b0cd34
Merge branch 'master' of github.com:DavidLapous/gudhi-devel-multi
DavidLapous Mar 10, 2023
a4ea7d0
Merge branch 'GUDHI:master' into master
DavidLapous Mar 21, 2023
a7d1609
fixed make_filtration_non_decreasing, disabled simplex insert filtrat…
DavidLapous Mar 26, 2023
ff0c9b9
Merge branch 'GUDHI:master' into master
DavidLapous Mar 26, 2023
44c89a4
Merge branch 'GUDHI:master' into master
DavidLapous Mar 28, 2023
3129205
merge with upstream
DavidLapous Sep 5, 2023
cb5eb3c
Merge branch 'GUDHI:master' into master
DavidLapous Sep 6, 2023
18054a3
update
DavidLapous Sep 6, 2023
a67628c
simplextree signatures fix
DavidLapous Sep 6, 2023
3b5734b
Merge branch 'GUDHI:master' into master
DavidLapous Sep 8, 2023
44abf0d
namespace multiparameter, added options to tests
DavidLapous Sep 11, 2023
dcfc551
Merge branch 'GUDHI:master' into master
DavidLapous Sep 11, 2023
79a42b4
add multipers option to tests of pcoh
DavidLapous Sep 11, 2023
79c52cd
set filtration to const by default and add a mutable filtration method
DavidLapous Sep 13, 2023
962f6e3
typo
DavidLapous Sep 13, 2023
b73577f
fixed dummy filtration with ref
DavidLapous Sep 13, 2023
5bb12cc
merge upstream
DavidLapous Sep 15, 2023
4f89234
Merge branch 'GUDHI:master' into master
DavidLapous Sep 17, 2023
6267d41
add prune wrt dim
DavidLapous Sep 21, 2023
f4b355a
Merge branch 'master' into master
DavidLapous Sep 21, 2023
32a6a49
Merge branch 'GUDHI:master' into master
DavidLapous Sep 25, 2023
36de642
safe+slow simplextree conversion and optimizations
DavidLapous Sep 25, 2023
82ce7d0
cleaning
DavidLapous Sep 26, 2023
8fd1ccd
Merge branch 'GUDHI:master' into master
DavidLapous Sep 28, 2023
b212c16
Merge branch 'GUDHI:master' into master
DavidLapous Oct 11, 2023
655fd08
Merge branch 'GUDHI:master' into master
DavidLapous Nov 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Persistent_cohomology/test/betti_numbers_unit_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ struct MiniSTOptions : Gudhi::Simplex_tree_options_full_featured {
static const bool store_key = true;
// I have few vertices
typedef short Vertex_handle;

static const bool is_multi_parameter = false;
};

using Mini_simplex_tree = Gudhi::Simplex_tree<MiniSTOptions>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ struct MiniSTOptions {
static const bool contiguous_vertices = false;
static const bool link_nodes_by_label = false;
static const bool stable_simplex_handles = false;
static const bool is_multi_parameter = false;
};

using Mini_simplex_tree = Gudhi::Simplex_tree<MiniSTOptions>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ struct Simplex_tree_options_stable_simplex_handles {
static const bool contiguous_vertices = false;
static const bool link_nodes_by_label = true;
static const bool stable_simplex_handles = true;
static const bool is_multi_parameter = false;
};

int main(int argc, char *argv[]) {
Expand Down
2 changes: 2 additions & 0 deletions src/Simplex_tree/concept/SimplexTreeOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,7 @@ struct SimplexTreeOptions {
static const bool link_nodes_by_label;
/// If true, Simplex_handle will not be invalidated after insertions or removals.
static const bool stable_simplex_handles;

static const bool is_multi_parameter;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of the attribute has to be described here like the others (the concepts are used for documentation).

};

102 changes: 79 additions & 23 deletions src/Simplex_tree/include/gudhi/Simplex_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,16 +151,19 @@ class Simplex_tree {
Key_simplex_base;

struct Filtration_simplex_base_real {
Filtration_simplex_base_real() : filt_(0) {}
void assign_filtration(Filtration_value f) { filt_ = f; }
Filtration_value filtration() const { return filt_; }
Filtration_simplex_base_real() : filt_{} {}
void assign_filtration(const Filtration_value& f) { filt_ = f; }
// Filtration_value filtration() const { return filt_; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be clearer if you remove all the unused code you commented (not only here, there is commented code a bit everywhere).

const Filtration_value& filtration() const { return filt_; }
Filtration_value& filtration() { return filt_; }
private:
Filtration_value filt_;
};
struct Filtration_simplex_base_dummy {
Filtration_simplex_base_dummy() {}
void assign_filtration(Filtration_value GUDHI_CHECK_code(f)) { GUDHI_CHECK(f == 0, "filtration value specified for a complex that does not store them"); }
Filtration_value filtration() const { return 0; }
const Filtration_value& filtration() const { return null_value; }
static constexpr Filtration_value null_value={};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would probably be more part of another PR, but now that we use C++ standard 17, we could stop calling filtration() with the dummy and use if constexpr instead. This makes conceptually more sense for me and it would allow to clean out the dummy completely (and therefore make it a real dummy). For this PR, it would mean that we don't need to add the null_value to get around the problem that dummy::filtration() is literally called and therefore has to return something.
@mglisse @VincentRouvreau, what do you think? Should I make an issue?

};
typedef typename std::conditional<Options::store_filtration, Filtration_simplex_base_real,
Filtration_simplex_base_dummy>::type Filtration_simplex_base;
Expand Down Expand Up @@ -576,7 +579,7 @@ class Simplex_tree {
*
* Same as `filtration()`, but does not handle `null_simplex()`.
*/
static Filtration_value filtration_(Simplex_handle sh) {
static const Filtration_value& filtration_(Simplex_handle sh) {
GUDHI_CHECK (sh != null_simplex(), "null simplex");
return sh->second.filtration();
}
Expand Down Expand Up @@ -604,18 +607,25 @@ class Simplex_tree {
* Called on the null_simplex, it returns infinity.
* If SimplexTreeOptions::store_filtration is false, returns 0.
*/
static Filtration_value filtration(Simplex_handle sh) {
static const Filtration_value& filtration(Simplex_handle sh){
if (sh != null_simplex()) {
return sh->second.filtration();
} else {
return std::numeric_limits<Filtration_value>::infinity();
return inf_;
}
}
static Filtration_value& filtration_mutable(Simplex_handle sh){
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering if we could not just keep the version with the non const, as the validity of the filtration in the simplex tree is already responsibility of the user. This would avoid having to find a different name when it does exactly the same thing than filtration(). Or could there be performance issues when using non const references for numerical values (i.e., when the simplex tree is not multi)?
If it is the case, an ugly way to solve this would be to return a std::conditional to switch between Filtration_value& and Filtration_value depending on the value of is_multi_parameter.

if (sh != null_simplex()) {
return sh->second.filtration();
} else {
return inf_;
}
}

/** \brief Sets the filtration value of a simplex.
* \exception std::invalid_argument In debug mode, if sh is a null_simplex.
*/
void assign_filtration(Simplex_handle sh, Filtration_value fv) {
void assign_filtration(Simplex_handle sh, const Filtration_value& fv) {
GUDHI_CHECK(sh != null_simplex(),
std::invalid_argument("Simplex_tree::assign_filtration - cannot assign filtration on null_simplex"));
sh->second.assign_filtration(fv);
Expand Down Expand Up @@ -829,7 +839,7 @@ class Simplex_tree {
*/
template <class RandomVertexHandleRange = std::initializer_list<Vertex_handle>>
std::pair<Simplex_handle, bool> insert_simplex_raw(const RandomVertexHandleRange& simplex,
Filtration_value filtration) {
const Filtration_value& filtration) {
Siblings * curr_sib = &root_;
std::pair<Simplex_handle, bool> res_insert;
auto vi = simplex.begin();
Expand Down Expand Up @@ -895,7 +905,7 @@ class Simplex_tree {
* .end() return input iterators, with 'value_type' Vertex_handle. */
template<class InputVertexRange = std::initializer_list<Vertex_handle>>
std::pair<Simplex_handle, bool> insert_simplex(const InputVertexRange & simplex,
Filtration_value filtration = 0) {
const Filtration_value& filtration = {}) {
auto first = std::begin(simplex);
auto last = std::end(simplex);

Expand Down Expand Up @@ -924,7 +934,7 @@ class Simplex_tree {
*/
template<class InputVertexRange = std::initializer_list<Vertex_handle>>
std::pair<Simplex_handle, bool> insert_simplex_and_subfaces(const InputVertexRange& Nsimplex,
Filtration_value filtration = 0) {
const Filtration_value& filtration = {}) {
auto first = std::begin(Nsimplex);
auto last = std::end(Nsimplex);

Expand Down Expand Up @@ -953,7 +963,7 @@ class Simplex_tree {
std::pair<Simplex_handle, bool> rec_insert_simplex_and_subfaces_sorted(Siblings* sib,
ForwardVertexIterator first,
ForwardVertexIterator last,
Filtration_value filt) {
const Filtration_value& filt) {
// An alternative strategy would be:
// - try to find the complete simplex, if found (and low filtration) exit
// - insert all the vertices at once in sib
Expand All @@ -970,8 +980,28 @@ class Simplex_tree {
Simplex_handle simplex_one = insertion_result.first;
bool one_is_new = insertion_result.second;
if (!one_is_new) {
if (filtration(simplex_one) > filt) {
assign_filtration(simplex_one, filt);
if (!(filtration(simplex_one) <= filt)) { // TODO : For multipersistence, it's not clear what should be the default, especially for multicritical filtrations
if constexpr (SimplexTreeOptions::is_multi_parameter){
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section seems to be work in progress?

Copy link
Contributor Author

@DavidLapous DavidLapous Sep 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, as multiparameter filtrations have to be done carefully, I don't want the insertion to change the filtration values of the other simplices. We could define a behavior based on if the filtration value is comparable to the previous filtration value and create a multicritical filtration / change the values of the other simplices (that's what the if is doing), but I'm not sure that someone would want to deal with this complicated behavior; doing this by hand seems fine. I thus assume here that the user is smart. I will just remove these comments.

if (filt < filtration(simplex_one)){
// assign_filtration(simplex_one, filt);
// I don't really like this behavior.
// It prevents inserting simplices by default at the smallest possible position after its childrens.
// e.g., if (python) we type : st.insert([0], [1,0]), st.insert([1], [0,1]), st.insert([0,1])
// we may want st.filtration([0,1]) to be [1,1]. (maybe after a make_filtration_decreasing from user)
// Furthermore, this may more sense as default value -> 0 can erase filtration values of childrens...
}
else{ // As multicritical filtrations are not well supported yet, its not safe to concatenate yet.
// two incomparables filtrations values -> we concatenate
// std::cout << "incomparable -> concatenate" << std::endl;
// Filtration_value new_filtration = filtration(simplex_one);
// new_filtration.insert_new(filt); // we assume then that Filtration_value has a insert_new method.
// assign_filtration(simplex_one, new_filtration);
}
}
else{ // non-multiparameter
assign_filtration(simplex_one, filt);
}

} else {
// FIXME: this interface makes no sense, and it doesn't seem to be tested.
insertion_result.first = null_simplex();
Expand Down Expand Up @@ -1316,7 +1346,7 @@ class Simplex_tree {
* The complex does not need to be empty before calling this function. However, if a vertex is
* already present, its filtration value is not modified, unlike with other insertion functions. */
template <class VertexRange>
void insert_batch_vertices(VertexRange const& vertices, Filtration_value filt = 0) {
void insert_batch_vertices(VertexRange const& vertices, const Filtration_value& filt ={}) {
auto verts = vertices | boost::adaptors::transformed([&](auto v){
return Dit_value_t(v, Node(&root_, filt)); });
root_.members_.insert(boost::begin(verts), boost::end(verts));
Expand Down Expand Up @@ -1396,7 +1426,7 @@ class Simplex_tree {
static void intersection(std::vector<std::pair<Vertex_handle, Node> >& intersection,
Dictionary_it begin1, Dictionary_it end1,
Dictionary_it begin2, Dictionary_it end2,
Filtration_value filtration_) {
const Filtration_value& filtration_) {
if (begin1 == end1 || begin2 == end2)
return; // ----->>
while (true) {
Expand Down Expand Up @@ -1603,12 +1633,22 @@ class Simplex_tree {
if (dim == 0) return;
// Find the maximum filtration value in the border
Boundary_simplex_range&& boundary = boundary_simplex_range(sh);
Boundary_simplex_iterator max_border = std::max_element(std::begin(boundary), std::end(boundary),
typename SimplexTreeOptions::Filtration_value max_filt_border_value;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typename SimplexTreeOptions::Filtration_value can simply be written as Filtration_value. Again at line 1639.

if constexpr (SimplexTreeOptions::is_multi_parameter){
// in that case, we assume that Filtration_value has a `push_to` member to handle this.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is super specific and should be mentioned in the documentation and the concepts. I would also move finitely_critical_filtrations.h to here (inside include/gudhi/Simplex_tree folder) and mention that it realizes the concept for the multi simplex tree filtration values to make it accessible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a possibility, but I'm only using python, and I will not maintain / deal with a c++ interface that I don't use.

Copy link
Collaborator

@hschreiber hschreiber Sep 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not about making a C++ interface. Just move the file, include it in Simplex_tree.h and add something like:

struct Simplex_tree_options_multi_parameter {
  typedef linear_indexing_tag Indexing_tag;
  typedef int Vertex_handle;
  typedef Finitely_critical_multi_filtration<float> Filtration_value;
  typedef std::uint32_t Simplex_key;
  static const bool store_key = true;
  static const bool store_filtration = true;
  static const bool contiguous_vertices = false;
  static const bool link_nodes_by_label = false;
  static const bool stable_simplex_handles = false;
  static const bool is_multi_parameter = true;
};

at the end of the file with the other options instead of having it in /python/include/Simplex_tree_multi.h. That is the only change. Then for the documentation, in the concept of the options (concept/SimplexTreeOptions.h) you mention the need of push_to and that you can find an example of implementation as Finitely_critical_multi_filtration<T>.

The difference is that it will make the tree usable for C++ users without you having to change much or to maintain anything.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hschreiber IIUC you are suggesting defining this Simplex_tree_options_multi_parameter in (a file included by) Simplex_tree.h? We need to have a conversation about #905, but in my opinion we should define very few of those by default and Simplex_tree_options_fast_persistence may already have been a mistake. There is no particular reason why someone using multiparameters should particularly want float vs double for instance. Having it in python, as "what we use for SimplexTreeMulti", makes sense to me. On the other hand, maybe more functions could be implemented more generically, to work with any option that has is_multi_parameter==true, and those could end up in the C++ part, although that's more work.

Copy link
Collaborator

@hschreiber hschreiber Sep 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mglisse Not really, it was just to illustrate how we would use it. If Filtration_value needs a special method like push_to, we cannot just let it hang there without an explanation for the user, in particular if code was already written. We can also put this just in the tests or in an example, but at least in the concept, the implementation of Finitely_critical_multi_filtration<T> should be mentioned and not hidden away in the python folder.

max_filt_border_value = typename SimplexTreeOptions::Filtration_value(this->number_of_parameters_);
for (auto &face_sh : boundary){
max_filt_border_value.push_to(filtration(face_sh)); // pushes the value of max_filt_border_value to reach simplex' filtration
}
}
else{
Boundary_simplex_iterator max_border = std::max_element(std::begin(boundary), std::end(boundary),
[](Simplex_handle sh1, Simplex_handle sh2) {
return filtration(sh1) < filtration(sh2);
});

Filtration_value max_filt_border_value = filtration(*max_border);
max_filt_border_value = filtration(*max_border);
}

// Replacing if(f<max) with if(!(f>=max)) would mean that if f is NaN, we replace it with the max of the children.
// That seems more useful than keeping NaN.
if (!(sh->second.filtration() >= max_filt_border_value)) {
Expand Down Expand Up @@ -1643,7 +1683,7 @@ class Simplex_tree {
* than it was before. However, `upper_bound_dimension()` will return the old value, which remains a valid upper
* bound. If you care, you can call `dimension()` to recompute the exact dimension.
*/
bool prune_above_filtration(Filtration_value filtration) {
bool prune_above_filtration(const Filtration_value& filtration) {
if (std::numeric_limits<Filtration_value>::has_infinity && filtration == std::numeric_limits<Filtration_value>::infinity())
return false; // ---->>
bool modified = rec_prune_above_filtration(root(), filtration);
Expand All @@ -1653,7 +1693,7 @@ class Simplex_tree {
}

private:
bool rec_prune_above_filtration(Siblings* sib, Filtration_value filt) {
bool rec_prune_above_filtration(Siblings* sib, const Filtration_value& filt) {
auto&& list = sib->members();
auto last = std::remove_if(list.begin(), list.end(), [this,filt](Dit_value_t& simplex) {
if (simplex.second.filtration() <= filt) return false;
Expand Down Expand Up @@ -2063,7 +2103,7 @@ class Simplex_tree {
* @param[in] filt_value The new filtration value.
* @param[in] min_dim The minimal dimension. Default value is 0.
*/
void reset_filtration(Filtration_value filt_value, int min_dim = 0) {
void reset_filtration(const Filtration_value& filt_value, int min_dim = 0) {
rec_reset_filtration(&root_, filt_value, min_dim);
clear_filtration(); // Drop the cache.
}
Expand All @@ -2074,7 +2114,7 @@ class Simplex_tree {
* @param[in] filt_value The new filtration value.
* @param[in] min_depth The minimal depth.
*/
void rec_reset_filtration(Siblings * sib, Filtration_value filt_value, int min_depth) {
void rec_reset_filtration(Siblings * sib, const Filtration_value& filt_value, int min_depth) {
for (auto sh = sib->members().begin(); sh != sib->members().end(); ++sh) {
if (min_depth <= 0) {
sh->second.assign_filtration(filt_value);
Expand Down Expand Up @@ -2239,6 +2279,18 @@ class Simplex_tree {
/** \brief Upper bound on the dimension of the simplicial complex.*/
int dimension_;
bool dimension_to_be_lowered_ = false;

//MULTIPERS STUFF
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be consistent with the option strategy of the simplex tree so far, this (except for the inf_) should be put in a mixin with a dummy like struct Filtration_simplex_base_real and struct Filtration_simplex_base_dummy.

public:
void set_number_of_parameters(int num){
number_of_parameters_ = num;
}
int get_number_of_parameters() const{
return number_of_parameters_;
}
inline static Filtration_value inf_ = std::numeric_limits<Filtration_value>::infinity();
private:
int number_of_parameters_;
};

// Print a Simplex_tree in os.
Expand Down Expand Up @@ -2290,6 +2342,7 @@ struct Simplex_tree_options_full_featured {
static const bool contiguous_vertices = false;
static const bool link_nodes_by_label = false;
static const bool stable_simplex_handles = false;
static const bool is_multi_parameter = false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it not be has_multi_parameter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

either has_multiple_parameters or is_multi_parameter. I prefer the second one.

};

/** Model of SimplexTreeOptions, faster than `Simplex_tree_options_full_featured` but note the unsafe
Expand All @@ -2307,6 +2360,7 @@ struct Simplex_tree_options_fast_persistence {
static const bool contiguous_vertices = true;
static const bool link_nodes_by_label = false;
static const bool stable_simplex_handles = false;
static const bool is_multi_parameter = false;
};

/** Model of SimplexTreeOptions, faster cofaces than `Simplex_tree_options_full_featured`, note the
Expand All @@ -2324,6 +2378,8 @@ struct Simplex_tree_options_fast_cofaces {
static const bool contiguous_vertices = false;
static const bool link_nodes_by_label = true;
static const bool stable_simplex_handles = false;
static const bool is_multi_parameter = false;

};

/** @}*/ // end addtogroup simplex_tree
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ struct GUDHI_EMPTY_BASE_CLASS_OPTIMIZATION Simplex_tree_node_explicit_storage :
typedef typename SimplexTree::Simplex_key Simplex_key;

Simplex_tree_node_explicit_storage(Siblings * sib = nullptr,
Filtration_value filtration = 0)
const Filtration_value& filtration = {})
: children_(sib) {
this->assign_filtration(filtration);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ struct Simplex_tree_options_stable_simplex_handles {
static const bool contiguous_vertices = false;
static const bool link_nodes_by_label = true;
static const bool stable_simplex_handles = true;
static const bool is_multi_parameter = false;
};

typedef boost::mpl::list<Simplex_tree<>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct Simplex_tree_options_stable_simplex_handles {
static const bool contiguous_vertices = false;
static const bool link_nodes_by_label = false;
static const bool stable_simplex_handles = true;
static const bool is_multi_parameter = false;
};

typedef boost::mpl::list<Simplex_tree<>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ struct Simplex_tree_options_stable_simplex_handles {
static const bool contiguous_vertices = false;
static const bool link_nodes_by_label = false;
static const bool stable_simplex_handles = true;
static const bool is_multi_parameter = false;
};

typedef boost::mpl::list<Simplex_tree<>,
Expand Down
1 change: 1 addition & 0 deletions src/Simplex_tree/test/simplex_tree_unit_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ struct Simplex_tree_options_stable_simplex_handles {
static const bool contiguous_vertices = false;
static const bool link_nodes_by_label = true;
static const bool stable_simplex_handles = true;
static const bool is_multi_parameter = false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to also add some tests with is_multi_parameter set to true.

};

typedef boost::mpl::list<Simplex_tree<>,
Expand Down
2 changes: 2 additions & 0 deletions src/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ if(PYTHONINTERP_FOUND)
# Cython modules
set(GUDHI_PYTHON_MODULES "${GUDHI_PYTHON_MODULES}'off_utils', ")
set(GUDHI_PYTHON_MODULES "${GUDHI_PYTHON_MODULES}'simplex_tree', ")
set(GUDHI_PYTHON_MODULES "${GUDHI_PYTHON_MODULES}'simplex_tree_multi', ")
set(GUDHI_PYTHON_MODULES "${GUDHI_PYTHON_MODULES}'edge_collapse', ")
set(GUDHI_PYTHON_MODULES "${GUDHI_PYTHON_MODULES}'rips_complex', ")
set(GUDHI_PYTHON_MODULES "${GUDHI_PYTHON_MODULES}'cubical_complex', ")
Expand Down Expand Up @@ -165,6 +166,7 @@ if(PYTHONINTERP_FOUND)

set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'off_utils', ")
set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'simplex_tree', ")
set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'simplex_tree_multi', ")
set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'rips_complex', ")
set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'cubical_complex', ")
set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'periodic_cubical_complex', ")
Expand Down
29 changes: 29 additions & 0 deletions src/python/gudhi/multiparameter_edge_collapse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from tqdm import tqdm
from filtration_domination import remove_strongly_filtration_dominated, remove_filtration_dominated

def _collapse_edge_list(edges, num:int=0, full:bool=False, strong:bool=False, progress:bool=False):
"""
Given an edge list defining a 1 critical 2 parameter 1 dimensional simplicial complex, simplificates this filtered simplicial complex, using filtration-domination's edge collapser.
"""
n = len(edges)
if full:
num = 100
with tqdm(range(num), total=num, desc="Removing edges", disable=not(progress)) as I:
for i in I:
if strong:
edges = remove_strongly_filtration_dominated(edges) # nogil ?
else:
edges = remove_filtration_dominated(edges)
# Prevents doing useless collapses
if len(edges) >= n:
if full and strong:
strong = False
n = len(edges)
# n = edges.size() # len(edges)
else :
break
else:
n = len(edges)
# n = edges.size()
return edges

Loading