Loading...
Searching...
No Matches
Bitmap_cubical_complex_periodic_boundary_conditions_base.h
1/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
2 * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
3 * Author(s): Pawel Dlotko
4 *
5 * Copyright (C) 2015 Inria
6 *
7 * Modification(s):
8 * - YYYY/MM Author: Description of the modification
9 */
10
11#ifndef BITMAP_CUBICAL_COMPLEX_PERIODIC_BOUNDARY_CONDITIONS_BASE_H_
12#define BITMAP_CUBICAL_COMPLEX_PERIODIC_BOUNDARY_CONDITIONS_BASE_H_
13
14#include <gudhi/Bitmap_cubical_complex_base.h>
15#include <gudhi/Debug_utils.h>
16
17#include <cmath>
18#include <limits> // for numeric_limits<>
19#include <vector>
20#include <stdexcept>
21#include <cstddef>
22
23namespace Gudhi {
24
25namespace cubical_complex {
26
27// in this class, we are storing all the elements which are in normal bitmap (i.e. the bitmap without the periodic
28// boundary conditions). But, we set up the iterators and the procedures to compute boundary and coboundary in the way
29// that it is all right. We assume here that all the cells that are on the left / bottom and so on remains, while all
30// the cells on the right / top are not in the Bitmap_cubical_complex_periodic_boundary_conditions_base
31
40template <typename T>
42 public:
43 // constructors that take an extra parameter:
44
57 const std::vector<unsigned>& sizes,
58 const std::vector<bool>& directions_in_which_periodic_b_cond_are_to_be_imposed);
63 explicit Bitmap_cubical_complex_periodic_boundary_conditions_base(const char* perseusStyleFile);
72 const std::vector<unsigned>& dimensions, const std::vector<T>& cells,
73 const std::vector<bool>& directions_in_which_periodic_b_cond_are_to_be_imposed,
74 bool input_top_cells);
75
80
81 // overwritten methods co compute boundary and coboundary
88 virtual std::vector<std::size_t> get_boundary_of_a_cell(std::size_t cell) const override;
89
98 virtual std::vector<std::size_t> get_coboundary_of_a_cell(std::size_t cell) const override;
99
119 virtual int compute_incidence_between_cells(std::size_t coface, std::size_t face) const override {
120 // first get the counters for coface and face:
121 std::vector<unsigned> coface_counter = this->compute_counter_for_given_cell(coface);
122 std::vector<unsigned> face_counter = this->compute_counter_for_given_cell(face);
123
124 // coface_counter and face_counter should agree at all positions except from one:
125 int number_of_position_in_which_counters_do_not_agree = -1;
126 std::size_t number_of_full_faces_that_comes_before = 0;
127 for (std::size_t i = 0; i != coface_counter.size(); ++i) {
128 if ((coface_counter[i] % 2 == 1) && (number_of_position_in_which_counters_do_not_agree == -1)) {
129 ++number_of_full_faces_that_comes_before;
130 }
131 if (coface_counter[i] != face_counter[i]) {
132 if (number_of_position_in_which_counters_do_not_agree != -1) {
133 std::cerr << "Cells given to compute_incidence_between_cells procedure do not form a pair of coface-face.\n";
134 throw std::logic_error(
135 "Cells given to compute_incidence_between_cells procedure do not form a pair of coface-face.");
136 }
137 number_of_position_in_which_counters_do_not_agree = i;
138 }
139 }
140
141 int incidence = 1;
142 if (number_of_full_faces_that_comes_before % 2) incidence = -1;
143 // if the face cell is on the right from coface cell:
144 if ((coface_counter[number_of_position_in_which_counters_do_not_agree] + 1 ==
145 face_counter[number_of_position_in_which_counters_do_not_agree]) ||
146 ((coface_counter[number_of_position_in_which_counters_do_not_agree] != 1) &&
147 (face_counter[number_of_position_in_which_counters_do_not_agree] == 0))) {
148 incidence *= -1;
149 }
150
151 return incidence;
152 }
153
154 // The non-periodic code works for top dimensional cells, but not vertices.
155 class Vertices_iterator {
156 public:
157 typedef std::input_iterator_tag iterator_category;
158 typedef std::size_t value_type;
159 typedef std::ptrdiff_t difference_type;
160 typedef value_type* pointer;
161 typedef value_type reference;
162
163 Vertices_iterator(Bitmap_cubical_complex_periodic_boundary_conditions_base* b) : counter(b->dimension()), b(b) {}
164
165 Vertices_iterator operator++() {
166 // first find first element of the counter that can be increased:
167 std::size_t dim = 0;
168 while ((dim != this->b->dimension()) && (this->counter[dim] == this->b->sizes[dim] - this->b->directions_in_which_periodic_b_cond_are_to_be_imposed[dim])) ++dim;
169
170 if (dim != this->b->dimension()) {
171 ++this->counter[dim];
172 for (std::size_t i = 0; i != dim; ++i) {
173 this->counter[i] = 0;
174 }
175 } else {
176 ++this->counter[0];
177 }
178 return *this;
179 }
180
181 Vertices_iterator operator++(int) {
182 Vertices_iterator result = *this;
183 ++(*this);
184 return result;
185 }
186
187 bool operator==(const Vertices_iterator& rhs) const {
188 if (this->b != rhs.b) return false;
189 GUDHI_CHECK(this->counter.size() == rhs.counter.size(), "impossible");
190 for (std::size_t i = 0; i != this->counter.size(); ++i) {
191 if (this->counter[i] != rhs.counter[i]) return false;
192 }
193 return true;
194 }
195
196 bool operator!=(const Vertices_iterator& rhs) const { return !(*this == rhs); }
197
198 /*
199 * The operator * returns position of a cube in the structure of cubical complex. This position can be then used as
200 * an argument of the following functions:
201 * get_boundary_of_a_cell, get_coboundary_of_a_cell, get_dimension_of_a_cell to get information about the cell
202 * boundary and coboundary and dimension
203 * and in function get_cell_data to get a filtration of a cell.
204 */
205 std::size_t operator*() const { return this->compute_index_in_bitmap(); }
206
207 std::size_t compute_index_in_bitmap() const {
208 std::size_t index = 0;
209 for (std::size_t i = 0; i != this->counter.size(); ++i) {
210 index += 2 * this->counter[i] * this->b->multipliers[i];
211 }
212 return index;
213 }
214
215 void print_counter() const {
216 for (std::size_t i = 0; i != this->counter.size(); ++i) {
217 std::clog << this->counter[i] << " ";
218 }
219 }
220 friend class Bitmap_cubical_complex_periodic_boundary_conditions_base;
221
222 protected:
223 std::vector<std::size_t> counter;
224 Bitmap_cubical_complex_periodic_boundary_conditions_base* b;
225 };
226
227 /*
228 * Function returning a Vertices_iterator to the first vertex of the bitmap.
229 */
230 Vertices_iterator vertices_iterator_begin() {
231 Vertices_iterator a(this);
232 return a;
233 }
234
235 /*
236 * Function returning a Vertices_iterator to the last vertex of the bitmap.
237 */
238 Vertices_iterator vertices_iterator_end() {
239 Vertices_iterator a(this);
240 for (std::size_t i = 0; i != this->dimension(); ++i) {
241 a.counter[i] = this->sizes[i] - this->directions_in_which_periodic_b_cond_are_to_be_imposed[i];
242 }
243 a.counter[0]++;
244 return a;
245 }
246
247 /*
248 * @brief Vertices_iterator_range class provides ranges for Vertices_iterator_range
249 */
250 class Vertices_range {
251 public:
253
254 Vertices_iterator begin() { return b->vertices_iterator_begin(); }
255
256 Vertices_iterator end() { return b->vertices_iterator_end(); }
257
258 private:
260 };
261
262 /* Returns a range over all vertices. */
263 Vertices_range vertices_range() { return Vertices_range(this); }
264
270
271 protected:
272 std::vector<bool> directions_in_which_periodic_b_cond_are_to_be_imposed;
273
274 void set_up_containers(const std::vector<unsigned>& sizes, bool is_pos_inf) {
275 // The fact that multipliers[0]=1 is relied on by optimizations in other functions
276 unsigned multiplier = 1;
277 for (std::size_t i = 0; i != sizes.size(); ++i) {
278 this->sizes.push_back(sizes[i]);
279 this->multipliers.push_back(multiplier);
280
281 if (directions_in_which_periodic_b_cond_are_to_be_imposed[i]) {
282 multiplier *= 2 * sizes[i];
283 } else {
284 multiplier *= 2 * sizes[i] + 1;
285 }
286 }
287 // std::reverse( this->sizes.begin() , this->sizes.end() );
288 if (is_pos_inf)
289 this->data = std::vector<T>(multiplier, std::numeric_limits<T>::infinity());
290 else
291 this->data = std::vector<T>(multiplier, -std::numeric_limits<T>::infinity());
292 }
293 Bitmap_cubical_complex_periodic_boundary_conditions_base(const std::vector<unsigned>& sizes);
294 Bitmap_cubical_complex_periodic_boundary_conditions_base(const std::vector<unsigned>& dimensions,
295 const std::vector<T>& cells,
296 bool input_top_cells);
297
301 void construct_complex_based_on_top_dimensional_cells(
302 const std::vector<unsigned>& dimensions, const std::vector<T>& topDimensionalCells,
303 const std::vector<bool>& directions_in_which_periodic_b_cond_are_to_be_imposed);
304 void construct_complex_based_on_vertices(const std::vector<unsigned>& dimensions, const std::vector<T>& vertices,
305 const std::vector<bool>& directions_in_which_periodic_b_cond_are_to_be_imposed);
306};
307
308template <typename T>
309void Bitmap_cubical_complex_periodic_boundary_conditions_base<T>::construct_complex_based_on_top_dimensional_cells(
310 const std::vector<unsigned>& dimensions, const std::vector<T>& topDimensionalCells,
311 const std::vector<bool>& directions_in_which_periodic_b_cond_are_to_be_imposed) {
312 this->directions_in_which_periodic_b_cond_are_to_be_imposed = directions_in_which_periodic_b_cond_are_to_be_imposed;
313 this->set_up_containers(dimensions, true);
314
315 std::size_t i = 0;
316 for (auto it = this->top_dimensional_cells_iterator_begin(); it != this->top_dimensional_cells_iterator_end(); ++it) {
317 this->get_cell_data(*it) = topDimensionalCells[i];
318 ++i;
319 }
320 this->impose_lower_star_filtration();
321}
322
323template <typename T>
324void Bitmap_cubical_complex_periodic_boundary_conditions_base<T>::construct_complex_based_on_vertices(
325 const std::vector<unsigned>& dimensions, const std::vector<T>& vertices,
326 const std::vector<bool>& directions_in_which_periodic_b_cond_are_to_be_imposed) {
327 this->directions_in_which_periodic_b_cond_are_to_be_imposed = directions_in_which_periodic_b_cond_are_to_be_imposed;
328
329 std::vector<unsigned> top_cells_sizes;
330 std::transform (dimensions.begin(), dimensions.end(), directions_in_which_periodic_b_cond_are_to_be_imposed.begin(),
331 std::back_inserter(top_cells_sizes), [](unsigned i, bool b){ return i - !b;});
332 this->set_up_containers(top_cells_sizes, false);
333
334 std::size_t i = 0;
335 for (auto it = this->vertices_iterator_begin(); it != this->vertices_iterator_end(); ++it) {
336 this->get_cell_data(*it) = vertices[i];
337 ++i;
338 }
339 this->impose_lower_star_filtration_from_vertices();
340}
341
342template <typename T>
344 const std::vector<unsigned>& sizes,
345 const std::vector<bool>& directions_in_which_periodic_b_cond_are_to_be_imposed) {
346 this->directions_in_which_periodic_b_cond_are_to_be_imposed(directions_in_which_periodic_b_cond_are_to_be_imposed);
347 this->set_up_containers(sizes, true);
348}
349
350template <typename T>
352 const char* perseus_style_file) {
353 // for Perseus style files:
354
355 std::ifstream inFiltration(perseus_style_file);
356 if(!inFiltration) throw std::ios_base::failure(std::string("Could not open the file ") + perseus_style_file);
357 unsigned dimensionOfData;
358 inFiltration >> dimensionOfData;
359
360 this->directions_in_which_periodic_b_cond_are_to_be_imposed = std::vector<bool>(dimensionOfData, false);
361
362 std::vector<unsigned> sizes;
363 sizes.reserve(dimensionOfData);
364 for (std::size_t i = 0; i != dimensionOfData; ++i) {
365 int size_in_this_dimension;
366 inFiltration >> size_in_this_dimension;
367 if (size_in_this_dimension < 0) {
368 this->directions_in_which_periodic_b_cond_are_to_be_imposed[i] = true;
369 }
370 sizes.push_back(abs(size_in_this_dimension));
371 }
372 this->set_up_containers(sizes, true);
373
375 it = this->top_dimensional_cells_iterator_begin();
376
377 while (!inFiltration.eof()) {
378 double filtrationLevel;
379 inFiltration >> filtrationLevel;
380 if (inFiltration.eof()) break;
381
382#ifdef DEBUG_TRACES
383 std::clog << "Cell of an index : " << it.compute_index_in_bitmap()
384 << " and dimension: " << this->get_dimension_of_a_cell(it.compute_index_in_bitmap())
385 << " get the value : " << filtrationLevel << std::endl;
386#endif
387 this->get_cell_data(*it) = filtrationLevel;
388 ++it;
389 }
390 inFiltration.close();
391 this->impose_lower_star_filtration();
392}
393
394template <typename T>
396 const std::vector<unsigned>& sizes) {
397 this->directions_in_which_periodic_b_cond_are_to_be_imposed = std::vector<bool>(sizes.size(), false);
398 this->set_up_containers(sizes, true);
399}
400
401template <typename T>
403 const std::vector<unsigned>& dimensions, const std::vector<T>& cells, bool input_top_cells) {
404 std::vector<bool> directions_in_which_periodic_b_cond_are_to_be_imposed = std::vector<bool>(dimensions.size(), false);
405 if (input_top_cells) {
406 this->construct_complex_based_on_top_dimensional_cells(dimensions, cells,
407 directions_in_which_periodic_b_cond_are_to_be_imposed);
408 } else {
409 this->construct_complex_based_on_vertices(dimensions, cells,
410 directions_in_which_periodic_b_cond_are_to_be_imposed);
411 }
412}
413
414template <typename T>
416 const std::vector<unsigned>& dimensions, const std::vector<T>& cells,
417 const std::vector<bool>& directions_in_which_periodic_b_cond_are_to_be_imposed,
418 bool input_top_cells) {
419 if(input_top_cells) {
420 this->construct_complex_based_on_top_dimensional_cells(dimensions, cells,
421 directions_in_which_periodic_b_cond_are_to_be_imposed);
422 } else {
423 this->construct_complex_based_on_vertices(dimensions, cells,
424 directions_in_which_periodic_b_cond_are_to_be_imposed);
425 }
426}
427
428// ***********************Methods************************ //
429
430template <typename T>
432 std::size_t cell) const {
433#ifdef DEBUG_TRACES
434 std::clog << "Computations of boundary of a cell : " << cell << std::endl;
435#endif
436
437 std::vector<std::size_t> boundary_elements;
438 boundary_elements.reserve(this->dimension() * 2);
439 std::size_t cell1 = cell;
440 std::size_t sum_of_dimensions = 0;
441
442 for (std::size_t i = this->multipliers.size(); i != 0; --i) {
443 unsigned position = cell1 / this->multipliers[i - 1];
444 cell1 = cell1 % this->multipliers[i - 1];
445 // this cell have a nonzero length in this direction, therefore we can compute its boundary in this direction.
446 if (position % 2 == 1) {
447 // if there are no periodic boundary conditions in this direction, we do not have to do anything.
448 if (!directions_in_which_periodic_b_cond_are_to_be_imposed[i - 1]) {
449 if (sum_of_dimensions % 2) {
450 boundary_elements.push_back(cell - this->multipliers[i - 1]);
451 boundary_elements.push_back(cell + this->multipliers[i - 1]);
452 } else {
453 boundary_elements.push_back(cell + this->multipliers[i - 1]);
454 boundary_elements.push_back(cell - this->multipliers[i - 1]);
455 }
456#ifdef DEBUG_TRACES
457 std::clog << cell - this->multipliers[i - 1] << " " << cell + this->multipliers[i - 1] << " ";
458#endif
459 } else {
460 // in this direction we have to do boundary conditions. Therefore, we need to check if we are not at the end.
461 if (position != 2 * this->sizes[i - 1] - 1) {
462 if (sum_of_dimensions % 2) {
463 boundary_elements.push_back(cell - this->multipliers[i - 1]);
464 boundary_elements.push_back(cell + this->multipliers[i - 1]);
465 } else {
466 boundary_elements.push_back(cell + this->multipliers[i - 1]);
467 boundary_elements.push_back(cell - this->multipliers[i - 1]);
468 }
469#ifdef DEBUG_TRACES
470 std::clog << cell - this->multipliers[i - 1] << " " << cell + this->multipliers[i - 1] << " ";
471#endif
472 } else {
473 if (sum_of_dimensions % 2) {
474 boundary_elements.push_back(cell - this->multipliers[i - 1]);
475 boundary_elements.push_back(cell - (2 * this->sizes[i - 1] - 1) * this->multipliers[i - 1]);
476 } else {
477 boundary_elements.push_back(cell - (2 * this->sizes[i - 1] - 1) * this->multipliers[i - 1]);
478 boundary_elements.push_back(cell - this->multipliers[i - 1]);
479 }
480#ifdef DEBUG_TRACES
481 std::clog << cell - this->multipliers[i - 1] << " "
482 << cell - (2 * this->sizes[i - 1] - 1) * this->multipliers[i - 1] << " ";
483#endif
484 }
485 }
486 ++sum_of_dimensions;
487 }
488 }
489 return boundary_elements;
490}
491
492template <typename T>
494 std::size_t cell) const {
495 std::vector<unsigned> counter = this->compute_counter_for_given_cell(cell);
496 std::vector<std::size_t> coboundary_elements;
497 std::size_t cell1 = cell;
498 for (std::size_t i = this->multipliers.size(); i != 0; --i) {
499 unsigned position = cell1 / this->multipliers[i - 1];
500 cell1 = cell1 % this->multipliers[i - 1];
501 // if the cell has zero length in this direction, then it will have cbd in this direction.
502 if (position % 2 == 0) {
503 if (!this->directions_in_which_periodic_b_cond_are_to_be_imposed[i - 1]) {
504 // no periodic boundary conditions in this direction
505 if ((counter[i - 1] != 0) && (cell > this->multipliers[i - 1])) {
506 coboundary_elements.push_back(cell - this->multipliers[i - 1]);
507 }
508 if ((counter[i - 1] != 2 * this->sizes[i - 1]) && (cell + this->multipliers[i - 1] < this->data.size())) {
509 coboundary_elements.push_back(cell + this->multipliers[i - 1]);
510 }
511 } else {
512 // we want to have periodic boundary conditions in this direction
513 if (counter[i - 1] != 0) {
514 coboundary_elements.push_back(cell - this->multipliers[i - 1]);
515 coboundary_elements.push_back(cell + this->multipliers[i - 1]);
516 } else {
517 // in this case counter[i-1] == 0.
518 coboundary_elements.push_back(cell + this->multipliers[i - 1]);
519 coboundary_elements.push_back(cell + (2 * this->sizes[i - 1] - 1) * this->multipliers[i - 1]);
520 }
521 }
522 }
523 }
524 return coboundary_elements;
525}
526
527// Exact same code as the non-periodic version, duplicated for now to ensure it calls the right version of vertices_iterator_begin.
528template <typename T>
530 // this vector will be used to check which elements have already been taken care of in imposing lower star filtration
531 std::vector<bool> is_this_cell_considered(this->data.size(), false);
532
533 std::vector<std::size_t> indices_to_consider;
534 // we assume here that we already have a filtration on the vertices and
535 // we have to extend it to higher ones.
536 for (auto it = this->vertices_iterator_begin();
537 it != this->vertices_iterator_end(); ++it) {
538 indices_to_consider.push_back(it.compute_index_in_bitmap());
539 }
540
541 while (indices_to_consider.size()) { // Iteration on the dimension
542#ifdef DEBUG_TRACES
543 std::clog << "indices_to_consider in this iteration \n";
544 for (auto index : indices_to_consider) {
545 std::clog << index << " ";
546 }
547#endif
548 std::vector<std::size_t> new_indices_to_consider;
549 for (auto index : indices_to_consider) {
550 std::vector<std::size_t> cbd = this->get_coboundary_of_a_cell(index);
551 for (auto coboundary : cbd) {
552#ifdef DEBUG_TRACES
553 std::clog << "filtration of a cell : " << coboundary << " is : " << this->data[coboundary]
554 << " while of a cell: " << index << " is: " << this->data[index]
555 << std::endl;
556#endif
557 if (this->data[coboundary] < this->data[index]) {
558 this->data[coboundary] = this->data[index];
559#ifdef DEBUG_TRACES
560 std::clog << "Setting the value of a cell : " << coboundary
561 << " to : " << this->data[index] << std::endl;
562#endif
563 }
564 if (is_this_cell_considered[coboundary] == false) {
565 new_indices_to_consider.push_back(coboundary);
566 is_this_cell_considered[coboundary] = true;
567 }
568 }
569 }
570 indices_to_consider.swap(new_indices_to_consider);
571 }
572}
573} // namespace cubical_complex
574
575namespace Cubical_complex = cubical_complex;
576
577} // namespace Gudhi
578
579#endif // BITMAP_CUBICAL_COMPLEX_PERIODIC_BOUNDARY_CONDITIONS_BASE_H_
Iterator through top dimensional cells of the complex. The cells appear in order they are stored in t...
Definition: Bitmap_cubical_complex_base.h:315
Cubical complex represented as a bitmap, class with basic implementation.
Definition: Bitmap_cubical_complex_base.h:57
unsigned dimension() const
Definition: Bitmap_cubical_complex_base.h:227
Cubical complex with periodic boundary conditions represented as a bitmap.
Definition: Bitmap_cubical_complex_periodic_boundary_conditions_base.h:41
void impose_lower_star_filtration_from_vertices()
Definition: Bitmap_cubical_complex_periodic_boundary_conditions_base.h:529
Bitmap_cubical_complex_periodic_boundary_conditions_base()
Definition: Bitmap_cubical_complex_periodic_boundary_conditions_base.h:48
virtual ~Bitmap_cubical_complex_periodic_boundary_conditions_base()
Definition: Bitmap_cubical_complex_periodic_boundary_conditions_base.h:79
virtual std::vector< std::size_t > get_coboundary_of_a_cell(std::size_t cell) const override
Definition: Bitmap_cubical_complex_periodic_boundary_conditions_base.h:493
virtual int compute_incidence_between_cells(std::size_t coface, std::size_t face) const override
Definition: Bitmap_cubical_complex_periodic_boundary_conditions_base.h:119
virtual std::vector< std::size_t > get_boundary_of_a_cell(std::size_t cell) const override
Definition: Bitmap_cubical_complex_periodic_boundary_conditions_base.h:431