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