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