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