Loading...
Searching...
No Matches
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
31namespace Gudhi {
32namespace persistence_matrix {
33
46template <class Master_matrix>
47class Intrusive_list_column : public Master_matrix::Row_access_option,
48 public Master_matrix::Column_dimension_option,
49 public Master_matrix::Chain_column_option
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);
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
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
260template <class Master_matrix>
261inline 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
275template <class Master_matrix>
276template <class Container_type>
277inline 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
301template <class Master_matrix>
302template <class Container_type, class Row_container_type>
303inline 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
336template <class Master_matrix>
337template <class Container_type>
338inline 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
367template <class Master_matrix>
368template <class Container_type, class Row_container_type>
369inline 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
400template <class Master_matrix>
401inline 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
420template <class Master_matrix>
421template <class Row_container_type>
422inline 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
445template <class Master_matrix>
446inline 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
456template <class Master_matrix>
457inline Intrusive_list_column<Master_matrix>::~Intrusive_list_column()
458{
459 column_.clear_and_dispose(delete_disposer(this));
460}
461
462template <class Master_matrix>
463inline std::vector<typename Intrusive_list_column<Master_matrix>::Field_element_type>
464Intrusive_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
483template <class Master_matrix>
484inline 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
495template <class Master_matrix>
496inline bool Intrusive_list_column<Master_matrix>::is_empty() const
497{
498 return column_.empty();
499}
500
501template <class Master_matrix>
502inline std::size_t Intrusive_list_column<Master_matrix>::size() const
503{
504 return column_.size();
505}
506
507template <class Master_matrix>
508template <class Map_type>
509inline 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
537template <class Master_matrix>
538inline 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
546template <class Master_matrix>
547inline 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
557template <class Master_matrix>
558inline typename Intrusive_list_column<Master_matrix>::id_index
559Intrusive_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
572template <class Master_matrix>
573inline typename Intrusive_list_column<Master_matrix>::Field_element_type
574Intrusive_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
595template <class Master_matrix>
596inline typename Intrusive_list_column<Master_matrix>::iterator
597Intrusive_list_column<Master_matrix>::begin() noexcept
598{
599 return column_.begin();
600}
601
602template <class Master_matrix>
603inline typename Intrusive_list_column<Master_matrix>::const_iterator
604Intrusive_list_column<Master_matrix>::begin() const noexcept
605{
606 return column_.begin();
607}
608
609template <class Master_matrix>
610inline typename Intrusive_list_column<Master_matrix>::iterator
611Intrusive_list_column<Master_matrix>::end() noexcept
612{
613 return column_.end();
614}
615
616template <class Master_matrix>
617inline typename Intrusive_list_column<Master_matrix>::const_iterator
618Intrusive_list_column<Master_matrix>::end() const noexcept
619{
620 return column_.end();
621}
622
623template <class Master_matrix>
624inline typename Intrusive_list_column<Master_matrix>::reverse_iterator
625Intrusive_list_column<Master_matrix>::rbegin() noexcept
626{
627 return column_.rbegin();
628}
629
630template <class Master_matrix>
631inline typename Intrusive_list_column<Master_matrix>::const_reverse_iterator
632Intrusive_list_column<Master_matrix>::rbegin() const noexcept
633{
634 return column_.rbegin();
635}
636
637template <class Master_matrix>
638inline typename Intrusive_list_column<Master_matrix>::reverse_iterator
639Intrusive_list_column<Master_matrix>::rend() noexcept
640{
641 return column_.rend();
642}
643
644template <class Master_matrix>
645inline typename Intrusive_list_column<Master_matrix>::const_reverse_iterator
646Intrusive_list_column<Master_matrix>::rend() const noexcept
647{
648 return column_.rend();
649}
650
651template <class Master_matrix>
652template <class Cell_range>
653inline Intrusive_list_column<Master_matrix>&
654Intrusive_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
667template <class Master_matrix>
668inline Intrusive_list_column<Master_matrix>&
669Intrusive_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
684template <class Master_matrix>
685inline Intrusive_list_column<Master_matrix>&
686Intrusive_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
719template <class Master_matrix>
720template <class Cell_range>
721inline Intrusive_list_column<Master_matrix>&
722Intrusive_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
745template <class Master_matrix>
746inline Intrusive_list_column<Master_matrix>&
747Intrusive_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
783template <class Master_matrix>
784template <class Cell_range>
785inline Intrusive_list_column<Master_matrix>&
786Intrusive_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
806template <class Master_matrix>
807inline Intrusive_list_column<Master_matrix>&
808Intrusive_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
839template <class Master_matrix>
840inline Intrusive_list_column<Master_matrix>&
841Intrusive_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
857template <class Master_matrix>
858inline void Intrusive_list_column<Master_matrix>::_delete_cell(iterator& it)
859{
860 it = column_.erase_and_dispose(it, delete_disposer(this));
861}
862
863template <class Master_matrix>
864inline 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
881template <class Master_matrix>
882inline 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
895template <class Master_matrix>
896template <class Cell_range>
897inline bool Intrusive_list_column<Master_matrix>::_add(const Cell_range& column)
898{
899 return _add_to_column(column, *this);
900}
901
902template <class Master_matrix>
903template <class Cell_range>
904inline 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
910template <class Master_matrix>
911template <class Cell_range>
912inline 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
929template <class Master_matrix>
930struct 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.
Gudhi namespace.
Definition SimplicialComplexForAlpha.h:14