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