11#ifndef PERSISTENT_COHOMOLOGY_H_
12#define PERSISTENT_COHOMOLOGY_H_
14#include <gudhi/Persistent_cohomology/Persistent_cohomology_column.h>
15#include <gudhi/Persistent_cohomology/Field_Zp.h>
16#include <gudhi/Simple_object_pool.h>
18#include <boost/intrusive/set.hpp>
19#include <boost/pending/disjoint_sets.hpp>
20#include <boost/intrusive/list.hpp>
36namespace persistent_cohomology {
51template<
class FilteredComplex,
class CoefficientField>
71 typedef Persistent_cohomology_column<Simplex_key, Arith_element> Column;
73 typedef typename Column::Cell Cell;
75 typedef boost::intrusive::list<Cell,
76 boost::intrusive::constant_time_size<false>,
77 boost::intrusive::base_hook<base_hook_cam_h> > Hcell;
79 typedef boost::intrusive::set<Column,
80 boost::intrusive::constant_time_size<false> > Cam;
82 typedef std::vector<std::pair<Simplex_key, Arith_element> > A_ds_type;
97 dim_max_(cpx.dimension()),
99 num_simplices_(cpx_->num_simplices()),
100 ds_rank_(num_simplices_),
101 ds_parent_(num_simplices_),
102 ds_repr_(num_simplices_, NULL),
103 dsets_(ds_rank_.data(), ds_parent_.data()),
108 interval_length_policy(&cpx, 0),
111 if (cpx_->
num_simplices() > std::numeric_limits<Simplex_key>::max()) {
113 throw std::out_of_range(
"The number of simplices is more than Simplex_key type numeric limit.");
119 dsets_.make_set(cpx_->
key(sh));
121 if (persistence_dim_max) {
128 for (
auto & transverse_ref : transverse_idx_) {
130 transverse_ref.second.row_->clear_and_dispose([&](Cell*p){p->~Cell();});
131 delete transverse_ref.second.row_;
136 struct length_interval {
139 min_length_(min_length) {
142 bool operator()(Simplex_handle sh1, Simplex_handle sh2) {
143 return cpx_->filtration(sh2) - cpx_->filtration(sh1) > min_length_;
147 min_length_ = new_length;
157 coeff_field_.init(charac);
161 coeff_field_.init(charac_min, charac_max);
173 interval_length_policy.set_length(min_interval_length);
177 switch (dim_simplex) {
181 update_cohomology_groups_edge(sh);
184 update_cohomology_groups(sh, dim_simplex);
190 for (
auto v_sh : cpx_->skeleton_simplex_range(0)) {
191 key = cpx_->
key(v_sh);
193 if (ds_parent_[key] == key
194 && zero_cocycles_.find(key) == zero_cocycles_.end()) {
195 persistent_pairs_.emplace_back(
199 for (
auto zero_idx : zero_cocycles_) {
200 persistent_pairs_.emplace_back(
204 for (
auto cocycle : transverse_idx_) {
205 persistent_pairs_.emplace_back(
215 void update_cohomology_groups_edge(Simplex_handle sigma) {
217 boost::tie(u, v) = cpx_->endpoints(sigma);
227 auto map_it_u = zero_cocycles_.find(ku);
229 if (map_it_u == zero_cocycles_.end()) {
232 idx_coc_u = map_it_u->second;
235 auto map_it_v = zero_cocycles_.find(kv);
237 if (map_it_v == zero_cocycles_.end()) {
240 idx_coc_v = map_it_v->second;
245 if (interval_length_policy(cpx_->
simplex(idx_coc_v), sigma)) {
246 persistent_pairs_.emplace_back(
250 if (kv != idx_coc_v) {
251 zero_cocycles_.erase(map_it_v);
253 if (kv == dsets_.find_set(kv)) {
254 if (ku != idx_coc_u) {
255 zero_cocycles_.erase(map_it_u);
257 zero_cocycles_[kv] = idx_coc_u;
260 if (interval_length_policy(cpx_->
simplex(idx_coc_u), sigma)) {
261 persistent_pairs_.emplace_back(
265 if (ku != idx_coc_u) {
266 zero_cocycles_.erase(map_it_u);
268 if (ku == dsets_.find_set(ku)) {
269 if (kv != idx_coc_v) {
270 zero_cocycles_.erase(map_it_v);
272 zero_cocycles_[ku] = idx_coc_v;
276 }
else if (dim_max_ > 1) {
284 void annotation_of_the_boundary(
285 std::map<Simplex_key, Arith_element> & map_a_ds, Simplex_handle sigma,
290 typedef std::pair<Column *, int> annotation_t;
291 thread_local std::vector<annotation_t> annotations_in_boundary;
292 annotations_in_boundary.clear();
293 int sign = 1 - 2 * (dim_sigma % 2);
302 curr_col = ds_repr_[dsets_.find_set(key)];
303 if (curr_col != NULL) {
304 annotations_in_boundary.emplace_back(curr_col, sign);
310 std::sort(annotations_in_boundary.begin(), annotations_in_boundary.end(),
311 [](annotation_t
const& a, annotation_t
const& b) { return a.first < b.first; });
315 std::pair<typename std::map<Simplex_key, Arith_element>::iterator,
bool> result_insert_a_ds;
317 for (
auto ann_it = annotations_in_boundary.begin(); ann_it != annotations_in_boundary.end(); ) {
318 Column* col = ann_it->first;
319 int mult = ann_it->second;
320 while (++ann_it != annotations_in_boundary.end() && ann_it->first == col) {
321 mult += ann_it->second;
325 for (
auto cell_ref : col->col_) {
326 Arith_element w_y = coeff_field_.times(cell_ref.coefficient_, mult);
329 result_insert_a_ds = map_a_ds.insert(std::pair<Simplex_key, Arith_element>(cell_ref.key_, w_y));
330 if (!(result_insert_a_ds.second)) {
331 result_insert_a_ds.first->second = coeff_field_.
plus_equal(result_insert_a_ds.first->second, w_y);
333 map_a_ds.erase(result_insert_a_ds.first);
345 void update_cohomology_groups(Simplex_handle sigma,
int dim_sigma) {
347 std::map<Simplex_key, Arith_element> map_a_ds;
348 annotation_of_the_boundary(map_a_ds, sigma, dim_sigma);
350 if (map_a_ds.empty()) {
351 if (dim_sigma < dim_max_) {
358 for (
auto map_a_ds_ref : map_a_ds) {
360 std::pair<Simplex_key, Arith_element>(map_a_ds_ref.first,
361 map_a_ds_ref.second));
366 for (
auto a_ds_rit = a_ds.rbegin();
367 (a_ds_rit != a_ds.rend())
369 std::tie(inv_x, charac) = coeff_field_.inverse(a_ds_rit->second, prod);
372 destroy_cocycle(sigma, a_ds, a_ds_rit->first, inv_x, charac);
377 && dim_sigma < dim_max_) {
394 Column * new_col = column_pool_.construct(key);
395 Cell * new_cell = cell_pool_.construct(key, x, new_col);
396 new_col->col_.push_back(*new_cell);
400 cam_.insert(cam_.end(), *new_col);
402 Hcell * new_hcell =
new Hcell;
403 new_hcell->push_back(*new_cell);
404 transverse_idx_[key] = cocycle(charac, new_hcell);
405 ds_repr_[key] = new_col;
416 void destroy_cocycle(Simplex_handle sigma, A_ds_type
const& a_ds,
420 if (interval_length_policy(cpx_->
simplex(death_key), sigma)) {
421 persistent_pairs_.emplace_back(cpx_->
simplex(death_key)
426 auto death_key_row = transverse_idx_.find(death_key);
427 std::pair<typename Cam::iterator, bool> result_insert_cam;
429 auto row_cell_it = death_key_row->second.row_->begin();
431 while (row_cell_it != death_key_row->second.row_->end()) {
433 Arith_element w = coeff_field_.times_minus(inv_x, row_cell_it->coefficient_);
436 Column * curr_col = row_cell_it->self_col_;
439 for (
auto& col_cell : curr_col->col_) {
440 col_cell.base_hook_cam_h::unlink();
444 cam_.erase(cam_.iterator_to(*curr_col));
446 plus_equal_column(*curr_col, a_ds, w);
448 if (curr_col->col_.empty()) {
449 ds_repr_[curr_col->class_key_] = NULL;
450 column_pool_.destroy(curr_col);
453 result_insert_cam = cam_.insert(*curr_col);
454 if (result_insert_cam.second) {
455 for (
auto& col_cell : curr_col->col_) {
457 transverse_idx_[col_cell.key_].row_->push_front(col_cell);
461 dsets_.link(curr_col->class_key_,
462 result_insert_cam.first->class_key_);
464 Simplex_key key_tmp = dsets_.find_set(curr_col->class_key_);
465 ds_repr_[key_tmp] = &(*(result_insert_cam.first));
466 result_insert_cam.first->class_key_ = key_tmp;
468 curr_col->col_.clear_and_dispose([&](Cell*p){cell_pool_.destroy(p);});
469 column_pool_.destroy(curr_col);
481 if (death_key_row->second.characteristics_ == charac) {
482 delete death_key_row->second.row_;
483 transverse_idx_.erase(death_key_row);
485 death_key_row->second.characteristics_ /= charac;
492 void plus_equal_column(Column & target, A_ds_type
const& other
494 auto target_it = target.col_.begin();
495 auto other_it = other.begin();
496 while (target_it != target.col_.end() && other_it != other.end()) {
497 if (target_it->key_ < other_it->first) {
500 if (target_it->key_ > other_it->first) {
501 Cell * cell_tmp = cell_pool_.construct(Cell(other_it->first
504 cell_tmp->coefficient_ = coeff_field_.plus_times_equal(cell_tmp->coefficient_, other_it->second, w);
506 target.col_.insert(target_it, *cell_tmp);
511 target_it->coefficient_ = coeff_field_.plus_times_equal(target_it->coefficient_, other_it->second, w);
513 auto tmp_it = target_it;
516 Cell * tmp_cell_ptr = &(*tmp_it);
517 target.col_.erase(tmp_it);
519 cell_pool_.destroy(tmp_cell_ptr);
527 while (other_it != other.end()) {
528 Cell * cell_tmp = cell_pool_.construct(Cell(other_it->first, coeff_field_.
additive_identity(), &target));
529 cell_tmp->coefficient_ = coeff_field_.plus_times_equal(cell_tmp->coefficient_, other_it->second, w);
530 target.col_.insert(target.col_.end(), *cell_tmp);
539 struct cmp_intervals_by_length {
544 return (sc_->filtration(get < 1 > (p1)) - sc_->filtration(get < 0 > (p1))
545 > sc_->filtration(get < 1 > (p2)) - sc_->filtration(get < 0 > (p2)));
562 cmp_intervals_by_length cmp(cpx_);
563 std::sort(std::begin(persistent_pairs_), std::end(persistent_pairs_), cmp);
564 for (
auto pair : persistent_pairs_) {
565 ostream << get<2>(pair) <<
" " << cpx_->
dimension(get<0>(pair)) <<
" "
567 << cpx_->
filtration(get<1>(pair)) <<
" " << std::endl;
571 void write_output_diagram(std::string diagram_name) {
572 std::ofstream diagram_out(diagram_name.c_str());
573 diagram_out.exceptions(diagram_out.failbit);
574 cmp_intervals_by_length cmp(cpx_);
575 std::sort(std::begin(persistent_pairs_), std::end(persistent_pairs_), cmp);
576 for (
auto pair : persistent_pairs_) {
577 diagram_out << cpx_->
dimension(get<0>(pair)) <<
" "
579 << cpx_->
filtration(get<1>(pair)) << std::endl;
588 int siz = std::max(dim_max_, 0);
592 for (
auto pair : persistent_pairs_) {
610 for (
auto pair : persistent_pairs_) {
613 if (cpx_->
dimension(get<0>(pair)) == dimension) {
629 int siz = std::max(dim_max_, 0);
632 for (
auto pair : persistent_pairs_) {
654 for (
auto pair : persistent_pairs_) {
660 if (cpx_->
dimension(get<0>(pair)) == dimension) {
673 return persistent_pairs_;
680 std::vector< std::pair< Filtration_value , Filtration_value > >
682 std::vector< std::pair< Filtration_value , Filtration_value > > result;
684 for (
auto && pair : persistent_pairs_) {
685 if (cpx_->
dimension(get<0>(pair)) == dimension) {
703 characteristics_(characteristics) {
714 size_t num_simplices_;
720 std::vector<int> ds_rank_;
721 std::vector<Simplex_key> ds_parent_;
722 std::vector<Column *> ds_repr_;
723 boost::disjoint_sets<int *, Simplex_key *> dsets_;
729 std::map<Simplex_key, Simplex_key> zero_cocycles_;
731 std::map<Simplex_key, cocycle> transverse_idx_;
733 std::vector<Persistent_interval> persistent_pairs_;
734 length_interval interval_length_policy;
736 Simple_object_pool<Column> column_pool_;
737 Simple_object_pool<Cell> cell_pool_;
Computes the persistent cohomology of a filtered complex.
Definition: Persistent_cohomology.h:52
std::vector< int > persistent_betti_numbers(Filtration_value from, Filtration_value to) const
Returns the persistent Betti numbers.
Definition: Persistent_cohomology.h:627
std::vector< std::pair< Filtration_value, Filtration_value > > intervals_in_dimension(int dimension)
Returns persistence intervals for a given dimension.
Definition: Persistent_cohomology.h:681
std::vector< int > betti_numbers() const
Returns Betti numbers.
Definition: Persistent_cohomology.h:586
void output_diagram(std::ostream &ostream=std::cout)
Output the persistence diagram in ostream.
Definition: Persistent_cohomology.h:561
std::tuple< Simplex_handle, Simplex_handle, Arith_element > Persistent_interval
Type for birth and death FilteredComplex::Simplex_handle. The Arith_element field is used for the mul...
Definition: Persistent_cohomology.h:66
FilteredComplex::Simplex_handle Simplex_handle
Handle to specify a simplex.
Definition: Persistent_cohomology.h:59
Persistent_cohomology(FilteredComplex &cpx, bool persistence_dim_max=false)
Initializes the Persistent_cohomology class.
Definition: Persistent_cohomology.h:95
int persistent_betti_number(int dimension, Filtration_value from, Filtration_value to) const
Returns the persistent Betti number of the dimension passed by parameter.
Definition: Persistent_cohomology.h:651
int betti_number(int dimension) const
Returns the Betti number of the dimension passed by parameter.
Definition: Persistent_cohomology.h:607
FilteredComplex::Simplex_key Simplex_key
Data stored for each simplex.
Definition: Persistent_cohomology.h:57
void compute_persistent_cohomology(Filtration_value min_interval_length=0)
Compute the persistent homology of the filtered simplicial complex.
Definition: Persistent_cohomology.h:172
void init_coefficients(int charac)
Initializes the coefficient field.
Definition: Persistent_cohomology.h:156
void init_coefficients(int charac_min, int charac_max)
Initializes the coefficient field for multi-field persistent homology.
Definition: Persistent_cohomology.h:160
CoefficientField::Element Arith_element
Type of element of the field.
Definition: Persistent_cohomology.h:63
FilteredComplex::Filtration_value Filtration_value
Type for the value of the filtration function.
Definition: Persistent_cohomology.h:61
const std::vector< Persistent_interval > & get_persistent_pairs() const
Returns a list of persistence birth and death FilteredComplex::Simplex_handle pairs.
Definition: Persistent_cohomology.h:672
Concept describing the requirements for a class to represent a field of coefficients to compute persi...
Definition: CoefficientField.h:14
Element additive_identity()
Element multiplicative_identity()
unspecified Element
Type of element of the field.
Definition: CoefficientField.h:19
void plus_equal(Element x, Element y)
The concept FilteredComplex describes the requirements for a type to implement a filtered cell comple...
Definition: FilteredComplex.h:17
unspecified Simplex_key
Data stored for each simplex.
Definition: FilteredComplex.h:91
Filtration_value filtration(Simplex_handle sh)
Returns the filtration value of a simplex.
void assign_key(Simplex_handle sh, Simplex_key n)
Store a number for a simplex, which can later be retrieved with key(sh).
Simplex_handle null_simplex()
Returns a Simplex_handle that is different from all simplex handles of the simplices.
Filtration_simplex_range filtration_simplex_range()
Returns a range over the simplices of the complex in the order of the filtration.
unspecified Simplex_handle
Handle to specify a simplex.
Definition: FilteredComplex.h:19
Simplex_key null_key()
Returns a constant dummy number that is either negative, or at least as large as num_simplices()....
Simplex_key key(Simplex_handle sh)
Returns the number stored for a simplex by assign_key.
unspecified Filtration_value
Type for the value of the filtration function.
Definition: FilteredComplex.h:23
int dimension(Simplex_handle sh)
Returns the dimension of a simplex.
Simplex_handle simplex(size_t idx)
Returns the simplex that has index idx in the filtration.
Boundary_simplex_range boundary_simplex_range(Simplex_handle sh)
Returns a range giving access to all simplices of the boundary of a simplex, i.e. the set of codimens...
size_t num_simplices()
Returns the number of simplices in the complex.
Value type for a filtration function on a cell complex.
Definition: FiltrationValue.h:20