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