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