23 #ifndef PERSISTENT_COHOMOLOGY_H_ 24 #define PERSISTENT_COHOMOLOGY_H_ 26 #include <gudhi/Persistent_cohomology/Persistent_cohomology_column.h> 27 #include <gudhi/Persistent_cohomology/Field_Zp.h> 28 #include <gudhi/Simple_object_pool.h> 30 #include <boost/intrusive/set.hpp> 31 #include <boost/pending/disjoint_sets.hpp> 32 #include <boost/intrusive/list.hpp> 48 namespace persistent_cohomology {
63 template<
class FilteredComplex,
class CoefficientField>
74 typedef Persistent_cohomology_column<Simplex_key, Arith_element> Column;
76 typedef typename Column::Cell Cell;
78 typedef boost::intrusive::list<Cell,
79 boost::intrusive::constant_time_size<false>,
80 boost::intrusive::base_hook<base_hook_cam_h> > Hcell;
82 typedef boost::intrusive::set<Column,
83 boost::intrusive::constant_time_size<false> > Cam;
85 typedef std::vector<std::pair<Simplex_key, Arith_element> > A_ds_type;
87 typedef std::tuple<Simplex_handle, Simplex_handle, Arith_element> Persistent_interval;
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_[0], &ds_parent_[0]),
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.");
115 Simplex_key idx_fil = 0;
119 dsets_.make_set(cpx_->
key(sh));
133 if (persistence_dim_max) {
140 for (
auto & transverse_ref : transverse_idx_) {
142 transverse_ref.second.row_->clear_and_dispose([&](Cell*p){p->~Cell();});
143 delete transverse_ref.second.row_;
148 struct length_interval {
149 length_interval(Complex_ds * cpx, Filtration_value min_length)
151 min_length_(min_length) {
154 bool operator()(Simplex_handle sh1, Simplex_handle sh2) {
155 return cpx_->filtration(sh2) - cpx_->filtration(sh1) > min_length_;
158 void set_length(Filtration_value new_length) {
159 min_length_ = new_length;
163 Filtration_value min_length_;
169 coeff_field_.init(charac);
173 coeff_field_.init(charac_min, charac_max);
185 interval_length_policy.set_length(min_interval_length);
187 for (
auto sh : cpx_->filtration_simplex_range()) {
188 int dim_simplex = cpx_->dimension(sh);
189 switch (dim_simplex) {
193 update_cohomology_groups_edge(sh);
196 update_cohomology_groups(sh, dim_simplex);
202 for (
auto v_sh : cpx_->skeleton_simplex_range(0)) {
203 key = cpx_->key(v_sh);
205 if (ds_parent_[key] == key
206 && zero_cocycles_.find(key) == zero_cocycles_.end()) {
207 persistent_pairs_.emplace_back(
208 cpx_->simplex(key), cpx_->null_simplex(), coeff_field_.characteristic());
211 for (
auto zero_idx : zero_cocycles_) {
212 persistent_pairs_.emplace_back(
213 cpx_->simplex(zero_idx.second), cpx_->null_simplex(), coeff_field_.characteristic());
216 for (
auto cocycle : transverse_idx_) {
217 persistent_pairs_.emplace_back(
218 cpx_->simplex(cocycle.first), cpx_->null_simplex(), cocycle.second.characteristics_);
227 void update_cohomology_groups_edge(Simplex_handle sigma) {
229 boost::tie(u, v) = cpx_->endpoints(sigma);
231 Simplex_key ku = dsets_.find_set(cpx_->key(u));
232 Simplex_key kv = dsets_.find_set(cpx_->key(v));
238 Simplex_key idx_coc_u, idx_coc_v;
239 auto map_it_u = zero_cocycles_.find(ku);
241 if (map_it_u == zero_cocycles_.end()) {
244 idx_coc_u = map_it_u->second;
247 auto map_it_v = zero_cocycles_.find(kv);
249 if (map_it_v == zero_cocycles_.end()) {
252 idx_coc_v = map_it_v->second;
255 if (cpx_->filtration(cpx_->simplex(idx_coc_u))
256 < cpx_->filtration(cpx_->simplex(idx_coc_v))) {
257 if (interval_length_policy(cpx_->simplex(idx_coc_v), sigma)) {
258 persistent_pairs_.emplace_back(
259 cpx_->simplex(idx_coc_v), sigma, coeff_field_.characteristic());
262 if (kv != idx_coc_v) {
263 zero_cocycles_.erase(map_it_v);
265 if (kv == dsets_.find_set(kv)) {
266 if (ku != idx_coc_u) {
267 zero_cocycles_.erase(map_it_u);
269 zero_cocycles_[kv] = idx_coc_u;
272 if (interval_length_policy(cpx_->simplex(idx_coc_u), sigma)) {
273 persistent_pairs_.emplace_back(
274 cpx_->simplex(idx_coc_u), sigma, coeff_field_.characteristic());
277 if (ku != idx_coc_u) {
278 zero_cocycles_.erase(map_it_u);
280 if (ku == dsets_.find_set(ku)) {
281 if (kv != idx_coc_v) {
282 zero_cocycles_.erase(map_it_v);
284 zero_cocycles_[ku] = idx_coc_v;
287 cpx_->assign_key(sigma, cpx_->null_key());
289 create_cocycle(sigma, coeff_field_.multiplicative_identity(), coeff_field_.characteristic());
296 void annotation_of_the_boundary(
297 std::map<Simplex_key, Arith_element> & map_a_ds, Simplex_handle sigma,
302 typedef std::pair<Column *, int> annotation_t;
303 thread_local std::vector<annotation_t> annotations_in_boundary;
304 annotations_in_boundary.clear();
305 int sign = 1 - 2 * (dim_sigma % 2);
310 for (
auto sh : cpx_->boundary_simplex_range(sigma)) {
312 if (key != cpx_->null_key()) {
314 curr_col = ds_repr_[dsets_.find_set(key)];
315 if (curr_col != NULL) {
316 annotations_in_boundary.emplace_back(curr_col, sign);
322 std::sort(annotations_in_boundary.begin(), annotations_in_boundary.end(),
323 [](annotation_t
const& a, annotation_t
const& b) {
return a.first < b.first; });
327 std::pair<typename std::map<Simplex_key, Arith_element>::iterator,
bool> result_insert_a_ds;
329 for (
auto ann_it = annotations_in_boundary.begin(); ann_it != annotations_in_boundary.end(); ) {
330 Column* col = ann_it->first;
331 int mult = ann_it->second;
332 while (++ann_it != annotations_in_boundary.end() && ann_it->first == col) {
333 mult += ann_it->second;
336 if (mult != coeff_field_.additive_identity()) {
337 for (
auto cell_ref : col->col_) {
338 Arith_element w_y = coeff_field_.times(cell_ref.coefficient_, mult);
340 if (w_y != coeff_field_.additive_identity()) {
341 result_insert_a_ds = map_a_ds.insert(std::pair<Simplex_key, Arith_element>(cell_ref.key_, w_y));
342 if (!(result_insert_a_ds.second)) {
343 result_insert_a_ds.first->second = coeff_field_.plus_equal(result_insert_a_ds.first->second, w_y);
344 if (result_insert_a_ds.first->second == coeff_field_.additive_identity()) {
345 map_a_ds.erase(result_insert_a_ds.first);
357 void update_cohomology_groups(Simplex_handle sigma,
int dim_sigma) {
359 std::map<Simplex_key, Arith_element> map_a_ds;
360 annotation_of_the_boundary(map_a_ds, sigma, dim_sigma);
362 if (map_a_ds.empty()) {
363 if (dim_sigma < dim_max_) {
364 create_cocycle(sigma, coeff_field_.multiplicative_identity(),
365 coeff_field_.characteristic());
370 for (
auto map_a_ds_ref : map_a_ds) {
372 std::pair<Simplex_key, Arith_element>(map_a_ds_ref.first,
373 map_a_ds_ref.second));
376 Arith_element inv_x, charac;
377 Arith_element prod = coeff_field_.characteristic();
378 for (
auto a_ds_rit = a_ds.rbegin();
379 (a_ds_rit != a_ds.rend())
380 && (prod != coeff_field_.multiplicative_identity()); ++a_ds_rit) {
381 std::tie(inv_x, charac) = coeff_field_.inverse(a_ds_rit->second, prod);
383 if (inv_x != coeff_field_.additive_identity()) {
384 destroy_cocycle(sigma, a_ds, a_ds_rit->first, inv_x, charac);
388 if (prod != coeff_field_.multiplicative_identity()
389 && dim_sigma < dim_max_) {
390 create_cocycle(sigma, coeff_field_.multiplicative_identity(prod), prod);
402 void create_cocycle(Simplex_handle sigma, Arith_element x,
403 Arith_element charac) {
404 Simplex_key key = cpx_->key(sigma);
406 Column * new_col = column_pool_.construct(key);
407 Cell * new_cell = cell_pool_.construct(key, x, new_col);
408 new_col->col_.push_back(*new_cell);
412 cam_.insert(cam_.end(), *new_col);
414 Hcell * new_hcell =
new Hcell;
415 new_hcell->push_back(*new_cell);
416 transverse_idx_[key] = cocycle(charac, new_hcell);
417 ds_repr_[key] = new_col;
428 void destroy_cocycle(Simplex_handle sigma, A_ds_type
const& a_ds,
429 Simplex_key death_key, Arith_element inv_x,
430 Arith_element charac) {
432 if (interval_length_policy(cpx_->simplex(death_key), sigma)) {
433 persistent_pairs_.emplace_back(cpx_->simplex(death_key)
438 auto death_key_row = transverse_idx_.find(death_key);
439 std::pair<typename Cam::iterator, bool> result_insert_cam;
441 auto row_cell_it = death_key_row->second.row_->begin();
443 while (row_cell_it != death_key_row->second.row_->end()) {
445 Arith_element w = coeff_field_.times_minus(inv_x, row_cell_it->coefficient_);
447 if (w != coeff_field_.additive_identity()) {
448 Column * curr_col = row_cell_it->self_col_;
451 for (
auto& col_cell : curr_col->col_) {
452 col_cell.base_hook_cam_h::unlink();
456 cam_.erase(cam_.iterator_to(*curr_col));
458 plus_equal_column(*curr_col, a_ds, w);
460 if (curr_col->col_.empty()) {
461 ds_repr_[curr_col->class_key_] = NULL;
462 column_pool_.destroy(curr_col);
465 result_insert_cam = cam_.insert(*curr_col);
466 if (result_insert_cam.second) {
467 for (
auto& col_cell : curr_col->col_) {
469 transverse_idx_[col_cell.key_].row_->push_front(col_cell);
473 dsets_.link(curr_col->class_key_,
474 result_insert_cam.first->class_key_);
476 Simplex_key key_tmp = dsets_.find_set(curr_col->class_key_);
477 ds_repr_[key_tmp] = &(*(result_insert_cam.first));
478 result_insert_cam.first->class_key_ = key_tmp;
480 curr_col->col_.clear_and_dispose([&](Cell*p){cell_pool_.destroy(p);});
481 column_pool_.destroy(curr_col);
490 if (charac == coeff_field_.characteristic()) {
491 cpx_->assign_key(sigma, cpx_->null_key());
493 if (death_key_row->second.characteristics_ == charac) {
494 delete death_key_row->second.row_;
495 transverse_idx_.erase(death_key_row);
497 death_key_row->second.characteristics_ /= charac;
504 void plus_equal_column(Column & target, A_ds_type
const& other
506 auto target_it = target.col_.begin();
507 auto other_it = other.begin();
508 while (target_it != target.col_.end() && other_it != other.end()) {
509 if (target_it->key_ < other_it->first) {
512 if (target_it->key_ > other_it->first) {
513 Cell * cell_tmp = cell_pool_.construct(Cell(other_it->first
514 , coeff_field_.additive_identity(), &target));
516 cell_tmp->coefficient_ = coeff_field_.plus_times_equal(cell_tmp->coefficient_, other_it->second, w);
518 target.col_.insert(target_it, *cell_tmp);
523 target_it->coefficient_ = coeff_field_.plus_times_equal(target_it->coefficient_, other_it->second, w);
524 if (target_it->coefficient_ == coeff_field_.additive_identity()) {
525 auto tmp_it = target_it;
528 Cell * tmp_cell_ptr = &(*tmp_it);
529 target.col_.erase(tmp_it);
531 cell_pool_.destroy(tmp_cell_ptr);
539 while (other_it != other.end()) {
540 Cell * cell_tmp = cell_pool_.construct(Cell(other_it->first, coeff_field_.additive_identity(), &target));
541 cell_tmp->coefficient_ = coeff_field_.plus_times_equal(cell_tmp->coefficient_, other_it->second, w);
542 target.col_.insert(target.col_.end(), *cell_tmp);
551 struct cmp_intervals_by_length {
552 explicit cmp_intervals_by_length(Complex_ds * sc)
555 bool operator()(
const Persistent_interval & p1,
const Persistent_interval & p2) {
556 return (sc_->filtration(get < 1 > (p1)) - sc_->filtration(get < 0 > (p1))
557 > sc_->filtration(get < 1 > (p2)) - sc_->filtration(get < 0 > (p2)));
574 cmp_intervals_by_length cmp(cpx_);
575 std::sort(std::begin(persistent_pairs_), std::end(persistent_pairs_), cmp);
576 bool has_infinity = std::numeric_limits<Filtration_value>::has_infinity;
577 for (
auto pair : persistent_pairs_) {
579 if (has_infinity && cpx_->filtration(get<1>(pair)) == std::numeric_limits<Filtration_value>::infinity()) {
580 ostream << get<2>(pair) <<
" " << cpx_->dimension(get<0>(pair)) <<
" " 581 << cpx_->filtration(get<0>(pair)) <<
" inf " << std::endl;
583 ostream << get<2>(pair) <<
" " << cpx_->dimension(get<0>(pair)) <<
" " 584 << cpx_->filtration(get<0>(pair)) <<
" " 585 << cpx_->filtration(get<1>(pair)) <<
" " << std::endl;
590 void write_output_diagram(std::string diagram_name) {
591 std::ofstream diagram_out(diagram_name.c_str());
592 cmp_intervals_by_length cmp(cpx_);
593 std::sort(std::begin(persistent_pairs_), std::end(persistent_pairs_), cmp);
594 bool has_infinity = std::numeric_limits<Filtration_value>::has_infinity;
595 for (
auto pair : persistent_pairs_) {
597 if (has_infinity && cpx_->filtration(get<1>(pair)) == std::numeric_limits<Filtration_value>::infinity()) {
598 diagram_out << cpx_->dimension(get<0>(pair)) <<
" " 599 << cpx_->filtration(get<0>(pair)) <<
" inf" << std::endl;
601 diagram_out << cpx_->dimension(get<0>(pair)) <<
" " 602 << cpx_->filtration(get<0>(pair)) <<
" " 603 << cpx_->filtration(get<1>(pair)) << std::endl;
615 for (
auto pair : persistent_pairs_) {
617 if (cpx_->null_simplex() == get<1>(pair)) {
619 betti_numbers[cpx_->dimension(get<0>(pair))] += 1;
633 for (
auto pair : persistent_pairs_) {
635 if (cpx_->null_simplex() == get<1>(pair)) {
636 if (cpx_->dimension(get<0>(pair)) == dimension) {
653 for (
auto pair : persistent_pairs_) {
657 if (cpx_->filtration(get<0>(pair)) <= from &&
658 (get<1>(pair) == cpx_->null_simplex() || cpx_->filtration(get<1>(pair)) > to)) {
660 betti_numbers[cpx_->dimension(get<0>(pair))] += 1;
675 for (
auto pair : persistent_pairs_) {
679 if (cpx_->filtration(get<0>(pair)) <= from &&
680 (get<1>(pair) == cpx_->null_simplex() || cpx_->filtration(get<1>(pair)) > to)) {
681 if (cpx_->dimension(get<0>(pair)) == dimension) {
695 return persistent_pairs_;
702 std::vector< std::pair< Filtration_value , Filtration_value > >
704 std::vector< std::pair< Filtration_value , Filtration_value > > result;
706 for (
auto && pair : persistent_pairs_) {
707 if (cpx_->dimension(get<0>(pair)) == dimension) {
708 result.emplace_back(cpx_->filtration(get<0>(pair)), cpx_->filtration(get<1>(pair)));
723 cocycle(Arith_element characteristics, Hcell * row)
725 characteristics_(characteristics) {
729 Arith_element characteristics_;
736 size_t num_simplices_;
742 std::vector<int> ds_rank_;
743 std::vector<Simplex_key> ds_parent_;
744 std::vector<Column *> ds_repr_;
745 boost::disjoint_sets<int *, Simplex_key *> dsets_;
751 std::map<Simplex_key, Simplex_key> zero_cocycles_;
753 std::map<Simplex_key, cocycle> transverse_idx_;
755 std::vector<Persistent_interval> persistent_pairs_;
756 length_interval interval_length_policy;
758 Simple_object_pool<Column> column_pool_;
759 Simple_object_pool<Cell> cell_pool_;
766 #endif // PERSISTENT_COHOMOLOGY_H_ std::vector< int > betti_numbers() const
Returns Betti numbers.
Definition: Persistent_cohomology.h:611
void init_coefficients(int charac)
Initializes the coefficient field.
Definition: Persistent_cohomology.h:168
unspecified Element
Type of element of the field.
Definition: CoefficientField.h:31
unspecified Simplex_key
Key associated to each simplex.
Definition: FilteredComplex.h:35
const std::vector< Persistent_interval > & get_persistent_pairs() const
Returns the persistent pairs.
Definition: Persistent_cohomology.h:694
int betti_number(int dimension) const
Returns the Betti number of the dimension passed by parameter.
Definition: Persistent_cohomology.h:630
Computes the persistent cohomology of a filtered complex.
Definition: Persistent_cohomology.h:64
void assign_key(Simplex_handle sh, Simplex_key key)
Assign a key to a simplex.
Persistent_cohomology(Complex_ds &cpx)
Initializes the Persistent_cohomology class.
Definition: Persistent_cohomology.h:95
Definition: SimplicialComplexForAlpha.h:26
Simplex_key key(Simplex_handle sh)
Returns the key associated to a simplex.
std::vector< std::pair< Filtration_value, Filtration_value > > intervals_in_dimension(int dimension)
Returns persistence intervals for a given dimension.
Definition: Persistent_cohomology.h:703
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:672
void output_diagram(std::ostream &ostream=std::cout)
Output the persistence diagram in ostream.
Definition: Persistent_cohomology.h:573
Filtration_simplex_range filtration_simplex_range()
Returns a range over the simplices of the complex in the order of the filtration. ...
void init_coefficients(int charac_min, int charac_max)
Initializes the coefficient field for multi-field persistent homology.
Definition: Persistent_cohomology.h:172
size_t num_simplices()
Returns the number of simplices in the complex.
unspecified Simplex_handle
Definition: FilteredComplex.h:31
Persistent_cohomology(Complex_ds &cpx, bool persistence_dim_max)
Initializes the Persistent_cohomology class.
Definition: Persistent_cohomology.h:131
std::vector< int > persistent_betti_numbers(Filtration_value from, Filtration_value to) const
Returns the persistent Betti numbers.
Definition: Persistent_cohomology.h:650
Concept describing the requirements for a class to represent a field of coefficients to compute persi...
Definition: CoefficientField.h:26
void compute_persistent_cohomology(Filtration_value min_interval_length=0)
Compute the persistent homology of the filtered simplicial complex.
Definition: Persistent_cohomology.h:184
The concept FilteredComplex describes the requirements for a type to implement a filtered cell comple...
Definition: FilteredComplex.h:28
unspecified Filtration_value
Type for the value of the filtration function.
Definition: FilteredComplex.h:39