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 
23 namespace Gudhi {
24 
25 namespace 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 
40 template <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  }
221 
222  protected:
223  std::vector<std::size_t> counter;
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 
308 template <typename T>
309 void 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 
323 template <typename T>
324 void 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 
342 template <typename T>
344  const std::vector<unsigned>& sizes,
345  const std::vector<bool>& directions_in_which_periodic_b_cond_are_to_be_imposed)
346  : 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 
350 template <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 
394 template <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 
401 template <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 
414 template <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 
430 template <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 
492 template <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.
528 template <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 
575 namespace 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
Gudhi namespace.
Definition: SimplicialComplexForAlpha.h:14