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