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