intrusive_set_column.h
Go to the documentation of this file.
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): Hannah Schreiber
4  *
5  * Copyright (C) 2022-24 Inria
6  *
7  * Modification(s):
8  * - YYYY/MM Author: Description of the modification
9  */
10 
18 #ifndef PM_INTRUSIVE_SET_COLUMN_H
19 #define PM_INTRUSIVE_SET_COLUMN_H
20 
21 #include <vector>
22 #include <stdexcept>
23 #include <type_traits>
24 #include <utility> //std::swap, std::move & std::exchange
25 
26 #include <boost/intrusive/set.hpp>
27 
28 #include <gudhi/Debug_utils.h>
31 
32 namespace Gudhi {
33 namespace persistence_matrix {
34 
47 template <class Master_matrix>
51 {
52  public:
53  using Master = Master_matrix;
54  using index = typename Master_matrix::index;
55  using id_index = typename Master_matrix::id_index;
56  using dimension_type = typename Master_matrix::dimension_type;
57  using Field_element_type = typename Master_matrix::element_type;
58  using Cell = typename Master_matrix::Cell_type;
59  using Column_settings = typename Master_matrix::Column_settings;
60 
61  private:
62  using Field_operators = typename Master_matrix::Field_operators;
63  using Column_type =
64  boost::intrusive::set<Cell,
65  boost::intrusive::constant_time_size<false>,
66  boost::intrusive::base_hook<typename Master_matrix::base_hook_matrix_set_column> >;
67  using Cell_constructor = typename Master_matrix::Cell_constructor;
68 
69  public:
70  using iterator = typename Column_type::iterator;
71  using const_iterator = typename Column_type::const_iterator;
72  using reverse_iterator = typename Column_type::reverse_iterator;
73  using const_reverse_iterator = typename Column_type::const_reverse_iterator;
74 
75  Intrusive_set_column(Column_settings* colSettings = nullptr);
76  template <class Container_type = typename Master_matrix::boundary_type>
77  Intrusive_set_column(const Container_type& nonZeroRowIndices,
78  Column_settings* colSettings);
79  template <class Container_type = typename Master_matrix::boundary_type, class Row_container_type>
80  Intrusive_set_column(index columnIndex,
81  const Container_type& nonZeroRowIndices,
82  Row_container_type* rowContainer,
83  Column_settings* colSettings);
84  template <class Container_type = typename Master_matrix::boundary_type>
85  Intrusive_set_column(const Container_type& nonZeroChainRowIndices,
86  dimension_type dimension,
87  Column_settings* colSettings);
88  template <class Container_type = typename Master_matrix::boundary_type, class Row_container_type>
89  Intrusive_set_column(index columnIndex,
90  const Container_type& nonZeroChainRowIndices,
91  dimension_type dimension,
92  Row_container_type* rowContainer,
93  Column_settings* colSettings);
95  Column_settings* colSettings = nullptr);
96  template <class Row_container_type>
98  index columnIndex,
99  Row_container_type* rowContainer,
100  Column_settings* colSettings = nullptr);
101  Intrusive_set_column(Intrusive_set_column&& column) noexcept;
103 
104  std::vector<Field_element_type> get_content(int columnLength = -1) const;
105  bool is_non_zero(id_index rowIndex) const;
106  bool is_empty() const;
107  std::size_t size() const;
108 
109  template <class Map_type>
110  void reorder(const Map_type& valueMap, [[maybe_unused]] index columnIndex = -1);
111  void clear();
112  void clear(id_index rowIndex);
113 
114  id_index get_pivot() const;
115  Field_element_type get_pivot_value() const;
116 
117  iterator begin() noexcept;
118  const_iterator begin() const noexcept;
119  iterator end() noexcept;
120  const_iterator end() const noexcept;
121  reverse_iterator rbegin() noexcept;
122  const_reverse_iterator rbegin() const noexcept;
123  reverse_iterator rend() noexcept;
124  const_reverse_iterator rend() const noexcept;
125 
126  template <class Cell_range>
127  Intrusive_set_column& operator+=(const Cell_range& column);
128  Intrusive_set_column& operator+=(Intrusive_set_column& column);
129 
130  Intrusive_set_column& operator*=(unsigned int v);
131 
132  // this = v * this + column
133  template <class Cell_range>
134  Intrusive_set_column& multiply_target_and_add(const Field_element_type& val, const Cell_range& column);
135  Intrusive_set_column& multiply_target_and_add(const Field_element_type& val, Intrusive_set_column& column);
136  // this = this + column * v
137  template <class Cell_range>
138  Intrusive_set_column& multiply_source_and_add(const Cell_range& column, const Field_element_type& val);
139  Intrusive_set_column& multiply_source_and_add(Intrusive_set_column& column, const Field_element_type& val);
140 
141  friend bool operator==(const Intrusive_set_column& c1, const Intrusive_set_column& c2) {
142  if (&c1 == &c2) return true;
143 
144  if constexpr (Master_matrix::Option_list::is_z2) {
145  return c1.column_ == c2.column_;
146  } else {
147  auto it1 = c1.column_.begin();
148  auto it2 = c2.column_.begin();
149  if (c1.column_.size() != c2.column_.size()) return false;
150  while (it1 != c1.column_.end() && it2 != c2.column_.end()) {
151  if (it1->get_row_index() != it2->get_row_index() || it1->get_element() != it2->get_element()) return false;
152  ++it1;
153  ++it2;
154  }
155  return true;
156  }
157  }
158  friend bool operator<(const Intrusive_set_column& c1, const Intrusive_set_column& c2) {
159  if (&c1 == &c2) return false;
160 
161  if constexpr (Master_matrix::Option_list::is_z2) {
162  return c1.column_ < c2.column_;
163  } else {
164  auto it1 = c1.column_.begin();
165  auto it2 = c2.column_.begin();
166  while (it1 != c1.column_.end() && it2 != c2.column_.end()) {
167  if (it1->get_row_index() != it2->get_row_index()) return it1->get_row_index() < it2->get_row_index();
168  if (it1->get_element() != it2->get_element()) return it1->get_element() < it2->get_element();
169  ++it1;
170  ++it2;
171  }
172  return it2 != c2.column_.end();
173  }
174  }
175 
176  // Disabled with row access.
177  Intrusive_set_column& operator=(const Intrusive_set_column& other);
178 
179  friend void swap(Intrusive_set_column& col1, Intrusive_set_column& col2) {
180  swap(static_cast<typename Master_matrix::Row_access_option&>(col1),
181  static_cast<typename Master_matrix::Row_access_option&>(col2));
182  swap(static_cast<typename Master_matrix::Column_dimension_option&>(col1),
183  static_cast<typename Master_matrix::Column_dimension_option&>(col2));
184  swap(static_cast<typename Master_matrix::Chain_column_option&>(col1),
185  static_cast<typename Master_matrix::Chain_column_option&>(col2));
186  col1.column_.swap(col2.column_);
187  std::swap(col1.operators_, col2.operators_);
188  std::swap(col1.cellPool_, col2.cellPool_);
189  }
190 
191  private:
192  using ra_opt = typename Master_matrix::Row_access_option;
193  using dim_opt = typename Master_matrix::Column_dimension_option;
194  using chain_opt = typename Master_matrix::Chain_column_option;
195 
196  // Cloner object function for boost intrusive container
197  struct new_cloner {
198  new_cloner(Cell_constructor* cellPool) : cellPool_(cellPool){};
199 
200  Cell* operator()(const Cell& clone_this) { return cellPool_->construct(clone_this); }
201 
202  Cell_constructor* cellPool_;
203  };
204 
205  // The disposer object function for boost intrusive container
206  struct delete_disposer {
207  delete_disposer(){};
208  delete_disposer(Intrusive_set_column* col) : col_(col){};
209 
210  void operator()(Cell* delete_this) {
211  if constexpr (Master_matrix::Option_list::has_row_access) col_->unlink(delete_this);
212  col_->cellPool_->destroy(delete_this);
213  }
214 
215  Intrusive_set_column* col_;
216  };
217 
218  Column_type column_;
219  Field_operators* operators_;
220  Cell_constructor* cellPool_;
221 
222  template <class Column_type, class Cell_iterator, typename F1, typename F2, typename F3, typename F4>
223  friend void _generic_merge_cell_to_column(Column_type& targetColumn,
224  Cell_iterator& itSource,
225  typename Column_type::Column_type::iterator& itTarget,
226  F1&& process_target,
227  F2&& process_source,
228  F3&& update_target1,
229  F4&& update_target2,
230  bool& pivotIsZeroed);
231  template <class Column_type, class Cell_range, typename F1, typename F2, typename F3, typename F4, typename F5>
232  friend bool _generic_add_to_column(const Cell_range& source,
233  Column_type& targetColumn,
234  F1&& process_target,
235  F2&& process_source,
236  F3&& update_target1,
237  F4&& update_target2,
238  F5&& finish_target);
239  template <class Column_type, class Cell_range>
240  friend bool _add_to_column(const Cell_range& source, Column_type& targetColumn);
241  template <class Column_type, class Cell_range>
242  friend bool _multiply_target_and_add_to_column(const typename Column_type::Field_element_type& val,
243  const Cell_range& source,
244  Column_type& targetColumn);
245  template <class Column_type, class Cell_range>
246  friend bool _multiply_source_and_add_to_column(const typename Column_type::Field_element_type& val,
247  const Cell_range& source,
248  Column_type& targetColumn);
249 
250  void _delete_cell(iterator& it);
251  Cell* _insert_cell(const Field_element_type& value, id_index rowIndex, const iterator& position);
252  void _insert_cell(id_index rowIndex, const iterator& position);
253  template <class Cell_range>
254  bool _add(const Cell_range& column);
255  template <class Cell_range>
256  bool _multiply_target_and_add(const Field_element_type& val, const Cell_range& column);
257  template <class Cell_range>
258  bool _multiply_source_and_add(const Cell_range& column, const Field_element_type& val);
259 };
260 
261 template <class Master_matrix>
262 inline Intrusive_set_column<Master_matrix>::Intrusive_set_column(Column_settings* colSettings)
263  : ra_opt(),
264  dim_opt(),
265  chain_opt(),
266  operators_(nullptr),
267  cellPool_(colSettings == nullptr ? nullptr : &(colSettings->cellConstructor))
268 {
269  if (operators_ == nullptr && cellPool_ == nullptr) return; // to allow default constructor which gives a dummy column
270  if constexpr (!Master_matrix::Option_list::is_z2) {
271  operators_ = &(colSettings->operators);
272  }
273 }
274 
275 template <class Master_matrix>
276 template <class Container_type>
277 inline Intrusive_set_column<Master_matrix>::Intrusive_set_column(
278  const Container_type& nonZeroRowIndices, Column_settings* colSettings)
279  : ra_opt(),
280  dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1),
281  chain_opt(),
282  operators_(nullptr),
283  cellPool_(&(colSettings->cellConstructor))
284 {
285  static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
286  "Constructor not available for chain columns, please specify the dimension of the chain.");
287 
288  if constexpr (Master_matrix::Option_list::is_z2) {
289  for (id_index id : nonZeroRowIndices) {
290  _insert_cell(id, column_.end());
291  }
292  } else {
293  operators_ = &(colSettings->operators);
294  for (const auto& p : nonZeroRowIndices) {
295  _insert_cell(operators_->get_value(p.second), p.first, column_.end());
296  }
297  }
298 }
299 
300 template <class Master_matrix>
301 template <class Container_type, class Row_container_type>
302 inline Intrusive_set_column<Master_matrix>::Intrusive_set_column(
303  index columnIndex,
304  const Container_type& nonZeroRowIndices,
305  Row_container_type* rowContainer,
306  Column_settings* colSettings)
307  : ra_opt(columnIndex, rowContainer),
308  dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1),
309  chain_opt([&] {
310  if constexpr (Master_matrix::Option_list::is_z2) {
311  return nonZeroRowIndices.begin() == nonZeroRowIndices.end() ? -1 : *std::prev(nonZeroRowIndices.end());
312  } else {
313  return nonZeroRowIndices.begin() == nonZeroRowIndices.end() ? -1 : std::prev(nonZeroRowIndices.end())->first;
314  }
315  }()),
316  operators_(nullptr),
317  cellPool_(&(colSettings->cellConstructor))
318 {
319  static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
320  "Constructor not available for chain columns, please specify the dimension of the chain.");
321 
322  if constexpr (Master_matrix::Option_list::is_z2) {
323  for (id_index id : nonZeroRowIndices) {
324  _insert_cell(id, column_.end());
325  }
326  } else {
327  operators_ = &(colSettings->operators);
328  for (const auto& p : nonZeroRowIndices) {
329  _insert_cell(operators_->get_value(p.second), p.first, column_.end());
330  }
331  }
332 }
333 
334 template <class Master_matrix>
335 template <class Container_type>
336 inline Intrusive_set_column<Master_matrix>::Intrusive_set_column(
337  const Container_type& nonZeroRowIndices,
338  dimension_type dimension,
339  Column_settings* colSettings)
340  : ra_opt(),
341  dim_opt(dimension),
342  chain_opt([&] {
343  if constexpr (Master_matrix::Option_list::is_z2) {
344  return nonZeroRowIndices.begin() == nonZeroRowIndices.end() ? -1 : *std::prev(nonZeroRowIndices.end());
345  } else {
346  return nonZeroRowIndices.begin() == nonZeroRowIndices.end() ? -1 : std::prev(nonZeroRowIndices.end())->first;
347  }
348  }()),
349  operators_(nullptr),
350  cellPool_(&(colSettings->cellConstructor))
351 {
352  if constexpr (Master_matrix::Option_list::is_z2) {
353  for (id_index id : nonZeroRowIndices) {
354  _insert_cell(id, column_.end());
355  }
356  } else {
357  operators_ = &(colSettings->operators);
358  for (const auto& p : nonZeroRowIndices) {
359  _insert_cell(operators_->get_value(p.second), p.first, column_.end());
360  }
361  }
362 }
363 
364 template <class Master_matrix>
365 template <class Container_type, class Row_container_type>
366 inline Intrusive_set_column<Master_matrix>::Intrusive_set_column(
367  index columnIndex,
368  const Container_type& nonZeroRowIndices,
369  dimension_type dimension,
370  Row_container_type* rowContainer,
371  Column_settings* colSettings)
372  : ra_opt(columnIndex, rowContainer),
373  dim_opt(dimension),
374  chain_opt([&] {
375  if constexpr (Master_matrix::Option_list::is_z2) {
376  return nonZeroRowIndices.begin() == nonZeroRowIndices.end() ? -1 : *std::prev(nonZeroRowIndices.end());
377  } else {
378  return nonZeroRowIndices.begin() == nonZeroRowIndices.end() ? -1 : std::prev(nonZeroRowIndices.end())->first;
379  }
380  }()),
381  operators_(nullptr),
382  cellPool_(&(colSettings->cellConstructor))
383 {
384  if constexpr (Master_matrix::Option_list::is_z2) {
385  for (id_index id : nonZeroRowIndices) {
386  _insert_cell(id, column_.end());
387  }
388  } else {
389  operators_ = &(colSettings->operators);
390  for (const auto& p : nonZeroRowIndices) {
391  _insert_cell(operators_->get_value(p.second), p.first, column_.end());
392  }
393  }
394 }
395 
396 template <class Master_matrix>
397 inline Intrusive_set_column<Master_matrix>::Intrusive_set_column(const Intrusive_set_column& column,
398  Column_settings* colSettings)
399  : ra_opt(),
400  dim_opt(static_cast<const dim_opt&>(column)),
401  chain_opt(static_cast<const chain_opt&>(column)),
402  operators_(colSettings == nullptr ? column.operators_ : nullptr),
403  cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor))
404 {
405  static_assert(!Master_matrix::Option_list::has_row_access,
406  "Simple copy constructor not available when row access option enabled. Please specify the new column "
407  "index and the row container.");
408 
409  if constexpr (!Master_matrix::Option_list::is_z2){
410  if (colSettings != nullptr) operators_ = &(colSettings->operators);
411  }
412 
413  column_.clone_from(column.column_, new_cloner(cellPool_), delete_disposer(this));
414 }
415 
416 template <class Master_matrix>
417 template <class Row_container_type>
418 inline Intrusive_set_column<Master_matrix>::Intrusive_set_column(const Intrusive_set_column& column,
419  index columnIndex,
420  Row_container_type* rowContainer,
421  Column_settings* colSettings)
422  : ra_opt(columnIndex, rowContainer),
423  dim_opt(static_cast<const dim_opt&>(column)),
424  chain_opt(static_cast<const chain_opt&>(column)),
425  operators_(colSettings == nullptr ? column.operators_ : nullptr),
426  cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor))
427 {
428  if constexpr (!Master_matrix::Option_list::is_z2){
429  if (colSettings != nullptr) operators_ = &(colSettings->operators);
430  }
431 
432  for (const Cell& cell : column.column_) {
433  if constexpr (Master_matrix::Option_list::is_z2) {
434  _insert_cell(cell.get_row_index(), column_.end());
435  } else {
436  _insert_cell(cell.get_element(), cell.get_row_index(), column_.end());
437  }
438  }
439 }
440 
441 template <class Master_matrix>
442 inline Intrusive_set_column<Master_matrix>::Intrusive_set_column(
443  Intrusive_set_column&& column) noexcept
444  : ra_opt(std::move(static_cast<ra_opt&>(column))),
445  dim_opt(std::move(static_cast<dim_opt&>(column))),
446  chain_opt(std::move(static_cast<chain_opt&>(column))),
447  column_(std::move(column.column_)),
448  operators_(std::exchange(column.operators_, nullptr)),
449  cellPool_(std::exchange(column.cellPool_, nullptr))
450 {}
451 
452 template <class Master_matrix>
453 inline Intrusive_set_column<Master_matrix>::~Intrusive_set_column()
454 {
455  column_.clear_and_dispose(delete_disposer(this));
456 }
457 
458 template <class Master_matrix>
459 inline std::vector<typename Intrusive_set_column<Master_matrix>::Field_element_type>
460 Intrusive_set_column<Master_matrix>::get_content(int columnLength) const
461 {
462  if (columnLength < 0 && column_.size() > 0)
463  columnLength = column_.rbegin()->get_row_index() + 1;
464  else if (columnLength < 0)
465  return std::vector<Field_element_type>();
466 
467  std::vector<Field_element_type> container(columnLength);
468  for (auto it = column_.begin(); it != column_.end() && it->get_row_index() < static_cast<id_index>(columnLength);
469  ++it) {
470  if constexpr (Master_matrix::Option_list::is_z2) {
471  container[it->get_row_index()] = 1;
472  } else {
473  container[it->get_row_index()] = it->get_element();
474  }
475  }
476  return container;
477 }
478 
479 template <class Master_matrix>
480 inline bool Intrusive_set_column<Master_matrix>::is_non_zero(id_index rowIndex) const
481 {
482  return column_.find(Cell(rowIndex)) != column_.end();
483 }
484 
485 template <class Master_matrix>
486 inline bool Intrusive_set_column<Master_matrix>::is_empty() const
487 {
488  return column_.empty();
489 }
490 
491 template <class Master_matrix>
492 inline std::size_t Intrusive_set_column<Master_matrix>::size() const
493 {
494  return column_.size();
495 }
496 
497 template <class Master_matrix>
498 template <class Map_type>
499 inline void Intrusive_set_column<Master_matrix>::reorder(const Map_type& valueMap,
500  [[maybe_unused]] index columnIndex)
501 {
502  static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
503  "Method not available for chain columns.");
504 
505  Column_type newSet;
506 
507  if constexpr (Master_matrix::Option_list::has_row_access) {
508  for (auto it = column_.begin(); it != column_.end();) {
509  Cell* newCell = cellPool_->construct(columnIndex == static_cast<index>(-1) ?
510  ra_opt::columnIndex_ : columnIndex,
511  valueMap.at(it->get_row_index()));
512  if constexpr (!Master_matrix::Option_list::is_z2) {
513  newCell->set_element(it->get_element());
514  }
515  newSet.insert(newSet.end(), *newCell);
516  _delete_cell(it); // increases it
517  if constexpr (Master_matrix::Option_list::has_intrusive_rows) // intrusive list
518  ra_opt::insert_cell(newCell->get_row_index(), newCell);
519  }
520 
521  // when row is a set, all cells have to be deleted first, to avoid colliding when inserting
522  if constexpr (!Master_matrix::Option_list::has_intrusive_rows) { // set
523  for (Cell& cell : newSet) {
524  ra_opt::insert_cell(cell.get_row_index(), &cell);
525  }
526  }
527  } else {
528  for (auto it = column_.begin(); it != column_.end();) {
529  Cell* newCell = cellPool_->construct(valueMap.at(it->get_row_index()));
530  if constexpr (!Master_matrix::Option_list::is_z2) {
531  newCell->set_element(it->get_element());
532  }
533  newSet.insert(newSet.end(), *newCell);
534  _delete_cell(it); // increases it
535  }
536  }
537 
538  column_.swap(newSet);
539 }
540 
541 template <class Master_matrix>
542 inline void Intrusive_set_column<Master_matrix>::clear()
543 {
544  static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
545  "Method not available for chain columns as a base element should not be empty.");
546 
547  column_.clear_and_dispose(delete_disposer(this));
548 }
549 
550 template <class Master_matrix>
551 inline void Intrusive_set_column<Master_matrix>::clear(id_index rowIndex)
552 {
553  static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
554  "Method not available for chain columns.");
555 
556  auto it = column_.find(Cell(rowIndex));
557  if (it != column_.end()) {
558  _delete_cell(it);
559  }
560 }
561 
562 template <class Master_matrix>
563 inline typename Intrusive_set_column<Master_matrix>::id_index
564 Intrusive_set_column<Master_matrix>::get_pivot() const
565 {
566  static_assert(Master_matrix::isNonBasic,
567  "Method not available for base columns."); // could technically be, but is the notion usefull then?
568 
569  if constexpr (Master_matrix::Option_list::is_of_boundary_type) {
570  if (column_.empty()) return -1;
571  return column_.rbegin()->get_row_index();
572  } else {
573  return chain_opt::get_pivot();
574  }
575 }
576 
577 template <class Master_matrix>
578 inline typename Intrusive_set_column<Master_matrix>::Field_element_type
579 Intrusive_set_column<Master_matrix>::get_pivot_value() const
580 {
581  static_assert(Master_matrix::isNonBasic,
582  "Method not available for base columns."); // could technically be, but is the notion usefull then?
583 
584  if constexpr (Master_matrix::Option_list::is_z2) {
585  return 1;
586  } else {
587  if constexpr (Master_matrix::Option_list::is_of_boundary_type) {
588  if (column_.empty()) return 0;
589  return column_.rbegin()->get_element();
590  } else {
591  if (chain_opt::get_pivot() == static_cast<id_index>(-1)) return 0;
592  auto it = column_.find(Cell(chain_opt::get_pivot()));
593  GUDHI_CHECK(it != column_.end(),
594  "Intrusive_set_column::get_pivot_value - Pivot not found only if the column was misused.");
595  return it->get_element();
596  }
597  }
598 }
599 
600 template <class Master_matrix>
601 inline typename Intrusive_set_column<Master_matrix>::iterator
602 Intrusive_set_column<Master_matrix>::begin() noexcept
603 {
604  return column_.begin();
605 }
606 
607 template <class Master_matrix>
608 inline typename Intrusive_set_column<Master_matrix>::const_iterator
609 Intrusive_set_column<Master_matrix>::begin() const noexcept
610 {
611  return column_.begin();
612 }
613 
614 template <class Master_matrix>
615 inline typename Intrusive_set_column<Master_matrix>::iterator
616 Intrusive_set_column<Master_matrix>::end() noexcept
617 {
618  return column_.end();
619 }
620 
621 template <class Master_matrix>
622 inline typename Intrusive_set_column<Master_matrix>::const_iterator
623 Intrusive_set_column<Master_matrix>::end() const noexcept
624 {
625  return column_.end();
626 }
627 
628 template <class Master_matrix>
629 inline typename Intrusive_set_column<Master_matrix>::reverse_iterator
630 Intrusive_set_column<Master_matrix>::rbegin() noexcept
631 {
632  return column_.rbegin();
633 }
634 
635 template <class Master_matrix>
636 inline typename Intrusive_set_column<Master_matrix>::const_reverse_iterator
637 Intrusive_set_column<Master_matrix>::rbegin() const noexcept
638 {
639  return column_.rbegin();
640 }
641 
642 template <class Master_matrix>
643 inline typename Intrusive_set_column<Master_matrix>::reverse_iterator
644 Intrusive_set_column<Master_matrix>::rend() noexcept
645 {
646  return column_.rend();
647 }
648 
649 template <class Master_matrix>
650 inline typename Intrusive_set_column<Master_matrix>::const_reverse_iterator
651 Intrusive_set_column<Master_matrix>::rend() const noexcept
652 {
653  return column_.rend();
654 }
655 
656 template <class Master_matrix>
657 template <class Cell_range>
658 inline Intrusive_set_column<Master_matrix>&
659 Intrusive_set_column<Master_matrix>::operator+=(const Cell_range& column)
660 {
661  static_assert((!Master_matrix::isNonBasic || std::is_same_v<Cell_range, Intrusive_set_column>),
662  "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
663  "base element."); // could be removed, if we give the responsability to the user.
664  static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
665  "For chain columns, the given column cannot be constant.");
666 
667  _add(column);
668 
669  return *this;
670 }
671 
672 template <class Master_matrix>
673 inline Intrusive_set_column<Master_matrix>&
674 Intrusive_set_column<Master_matrix>::operator+=(Intrusive_set_column& column)
675 {
676  if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
677  // assumes that the addition never zeros out this column.
678  if (_add(column)) {
679  chain_opt::swap_pivots(column);
680  dim_opt::swap_dimension(column);
681  }
682  } else {
683  _add(column);
684  }
685 
686  return *this;
687 }
688 
689 template <class Master_matrix>
690 inline Intrusive_set_column<Master_matrix>&
691 Intrusive_set_column<Master_matrix>::operator*=(unsigned int v)
692 {
693  if constexpr (Master_matrix::Option_list::is_z2) {
694  if (v % 2 == 0) {
695  if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
696  throw std::invalid_argument("A chain column should not be multiplied by 0.");
697  } else {
698  clear();
699  }
700  }
701  } else {
702  Field_element_type val = operators_->get_value(v);
703 
704  if (val == Field_operators::get_additive_identity()) {
705  if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
706  throw std::invalid_argument("A chain column should not be multiplied by 0.");
707  } else {
708  clear();
709  }
710  return *this;
711  }
712 
713  if (val == Field_operators::get_multiplicative_identity()) return *this;
714 
715  for (Cell& cell : column_) {
716  operators_->multiply_inplace(cell.get_element(), val);
717  if constexpr (Master_matrix::Option_list::has_row_access) ra_opt::update_cell(cell);
718  }
719  }
720 
721  return *this;
722 }
723 
724 template <class Master_matrix>
725 template <class Cell_range>
726 inline Intrusive_set_column<Master_matrix>&
727 Intrusive_set_column<Master_matrix>::multiply_target_and_add(const Field_element_type& val,
728  const Cell_range& column)
729 {
730  static_assert((!Master_matrix::isNonBasic || std::is_same_v<Cell_range, Intrusive_set_column>),
731  "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
732  "base element."); // could be removed, if we give the responsability to the user.
733  static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
734  "For chain columns, the given column cannot be constant.");
735 
736  if constexpr (Master_matrix::Option_list::is_z2) {
737  if (val) {
738  _add(column);
739  } else {
740  clear();
741  _add(column);
742  }
743  } else {
744  _multiply_target_and_add(val, column);
745  }
746 
747  return *this;
748 }
749 
750 template <class Master_matrix>
751 inline Intrusive_set_column<Master_matrix>&
752 Intrusive_set_column<Master_matrix>::multiply_target_and_add(const Field_element_type& val,
753  Intrusive_set_column& column)
754 {
755  if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
756  // assumes that the addition never zeros out this column.
757  if constexpr (Master_matrix::Option_list::is_z2) {
758  if (val) {
759  if (_add(column)) {
760  chain_opt::swap_pivots(column);
761  dim_opt::swap_dimension(column);
762  }
763  } else {
764  throw std::invalid_argument("A chain column should not be multiplied by 0.");
765  }
766  } else {
767  if (_multiply_target_and_add(val, column)) {
768  chain_opt::swap_pivots(column);
769  dim_opt::swap_dimension(column);
770  }
771  }
772  } else {
773  if constexpr (Master_matrix::Option_list::is_z2) {
774  if (val) {
775  _add(column);
776  } else {
777  clear();
778  _add(column);
779  }
780  } else {
781  _multiply_target_and_add(val, column);
782  }
783  }
784 
785  return *this;
786 }
787 
788 template <class Master_matrix>
789 template <class Cell_range>
790 inline Intrusive_set_column<Master_matrix>&
791 Intrusive_set_column<Master_matrix>::multiply_source_and_add(const Cell_range& column,
792  const Field_element_type& val)
793 {
794  static_assert((!Master_matrix::isNonBasic || std::is_same_v<Cell_range, Intrusive_set_column>),
795  "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
796  "base element."); // could be removed, if we give the responsability to the user.
797  static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
798  "For chain columns, the given column cannot be constant.");
799 
800  if constexpr (Master_matrix::Option_list::is_z2) {
801  if (val) {
802  _add(column);
803  }
804  } else {
805  _multiply_source_and_add(column, val);
806  }
807 
808  return *this;
809 }
810 
811 template <class Master_matrix>
812 inline Intrusive_set_column<Master_matrix>&
813 Intrusive_set_column<Master_matrix>::multiply_source_and_add(Intrusive_set_column& column,
814  const Field_element_type& val)
815 {
816  if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
817  // assumes that the addition never zeros out this column.
818  if constexpr (Master_matrix::Option_list::is_z2) {
819  if (val) {
820  if (_add(column)) {
821  chain_opt::swap_pivots(column);
822  dim_opt::swap_dimension(column);
823  }
824  }
825  } else {
826  if (_multiply_source_and_add(column, val)) {
827  chain_opt::swap_pivots(column);
828  dim_opt::swap_dimension(column);
829  }
830  }
831  } else {
832  if constexpr (Master_matrix::Option_list::is_z2) {
833  if (val) {
834  _add(column);
835  }
836  } else {
837  _multiply_source_and_add(column, val);
838  }
839  }
840 
841  return *this;
842 }
843 
844 template <class Master_matrix>
845 inline Intrusive_set_column<Master_matrix>&
846 Intrusive_set_column<Master_matrix>::operator=(const Intrusive_set_column& other)
847 {
848  static_assert(!Master_matrix::Option_list::has_row_access, "= assignement not enabled with row access option.");
849 
850  dim_opt::operator=(other);
851  chain_opt::operator=(other);
852 
853  // order is important
854  column_.clear_and_dispose(delete_disposer(this));
855  operators_ = other.operators_;
856  cellPool_ = other.cellPool_;
857  column_.clone_from(other.column_, new_cloner(cellPool_), delete_disposer(this));
858 
859  return *this;
860 }
861 
862 template <class Master_matrix>
863 inline void Intrusive_set_column<Master_matrix>::_delete_cell(iterator& it)
864 {
865  it = column_.erase_and_dispose(it, delete_disposer(this));
866 }
867 
868 template <class Master_matrix>
869 inline typename Intrusive_set_column<Master_matrix>::Cell* Intrusive_set_column<Master_matrix>::_insert_cell(
870  const Field_element_type& value, id_index rowIndex, const iterator& position)
871 {
872  if constexpr (Master_matrix::Option_list::has_row_access) {
873  Cell* newCell = cellPool_->construct(ra_opt::columnIndex_, rowIndex);
874  newCell->set_element(value);
875  column_.insert(position, *newCell);
876  ra_opt::insert_cell(rowIndex, newCell);
877  return newCell;
878  } else {
879  Cell* newCell = cellPool_->construct(rowIndex);
880  newCell->set_element(value);
881  column_.insert(position, *newCell);
882  return newCell;
883  }
884 }
885 
886 template <class Master_matrix>
887 inline void Intrusive_set_column<Master_matrix>::_insert_cell(id_index rowIndex,
888  const iterator& position)
889 {
890  if constexpr (Master_matrix::Option_list::has_row_access) {
891  Cell* newCell = cellPool_->construct(ra_opt::columnIndex_, rowIndex);
892  column_.insert(position, *newCell);
893  ra_opt::insert_cell(rowIndex, newCell);
894  } else {
895  Cell* newCell = cellPool_->construct(rowIndex);
896  column_.insert(position, *newCell);
897  }
898 }
899 
900 template <class Master_matrix>
901 template <class Cell_range>
902 inline bool Intrusive_set_column<Master_matrix>::_add(const Cell_range& column)
903 {
904  return _add_to_column(column, *this);
905 }
906 
907 template <class Master_matrix>
908 template <class Cell_range>
909 inline bool Intrusive_set_column<Master_matrix>::_multiply_target_and_add(const Field_element_type& val,
910  const Cell_range& column)
911 {
912  return _multiply_target_and_add_to_column(val, column, *this);
913 }
914 
915 template <class Master_matrix>
916 template <class Cell_range>
917 inline bool Intrusive_set_column<Master_matrix>::_multiply_source_and_add(const Cell_range& column,
918  const Field_element_type& val)
919 {
920  return _multiply_source_and_add_to_column(val, column, *this);
921 }
922 
923 } // namespace persistence_matrix
924 } // namespace Gudhi
925 
926 
935 template <class Master_matrix>
936 struct std::hash<Gudhi::persistence_matrix::Intrusive_set_column<Master_matrix> >
937 {
938  std::size_t operator()(const Gudhi::persistence_matrix::Intrusive_set_column<Master_matrix>& column) const {
939  return Gudhi::persistence_matrix::hash_column(column);
940  }
941 };
942 
943 #endif // PM_INTRUSIVE_SET_COLUMN_H
Contains the New_cell_constructor and Pool_cell_constructor structures.
Column class following the PersistenceMatrixColumn concept.
Definition: intrusive_set_column.h:51
Contains helper methods for column addition and column hasher.
Chain_column_extra_properties Chain_column_option
If PersistenceMatrixOptions::is_of_boundary_type is false, and, PersistenceMatrixOptions::has_column_...
Definition: PersistenceMatrixColumn.h:45
Row_access Row_access_option
If PersistenceMatrixOptions::has_row_access is true, then Row_access. Otherwise Dummy_row_access....
Definition: PersistenceMatrixColumn.h:28
Column_dimension_holder Column_dimension_option
If PersistenceMatrixOptions::has_column_pairings or PersistenceMatrixOptions::has_vine_update or Pers...
Definition: PersistenceMatrixColumn.h:36
Gudhi namespace.
Definition: SimplicialComplexForAlpha.h:14