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