Loading...
Searching...
No Matches
list_column.h
Go to the documentation of this file.
1/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
2 * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
3 * Author(s): Hannah Schreiber
4 *
5 * Copyright (C) 2022-24 Inria
6 *
7 * Modification(s):
8 * - YYYY/MM Author: Description of the modification
9 */
10
18#ifndef PM_LIST_COLUMN_H
19#define PM_LIST_COLUMN_H
20
21#include <vector>
22#include <stdexcept>
23#include <type_traits>
24#include <list>
25#include <utility> //std::swap, std::move & std::exchange
26
27#include <boost/iterator/indirect_iterator.hpp>
28
31
32namespace Gudhi {
33namespace persistence_matrix {
34
47template <class Master_matrix>
48class List_column : public Master_matrix::Row_access_option,
49 public Master_matrix::Column_dimension_option,
50 public Master_matrix::Chain_column_option
51{
52 public:
53 using Master = Master_matrix;
54 using index = typename Master_matrix::index;
55 using id_index = typename Master_matrix::id_index;
56 using dimension_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 using Column_type = std::list<Cell*>;
64 using Cell_constructor = typename Master_matrix::Cell_constructor;
65
66 public:
67 using iterator = boost::indirect_iterator<typename Column_type::iterator>;
68 using const_iterator = boost::indirect_iterator<typename Column_type::const_iterator>;
69 using reverse_iterator = boost::indirect_iterator<typename Column_type::reverse_iterator>;
70 using const_reverse_iterator = boost::indirect_iterator<typename Column_type::const_reverse_iterator>;
71
72 List_column(Column_settings* colSettings = nullptr);
73 template <class Container_type = typename Master_matrix::boundary_type>
74 List_column(const Container_type& nonZeroRowIndices, Column_settings* colSettings);
75 template <class Container_type = typename Master_matrix::boundary_type, class Row_container_type>
76 List_column(index columnIndex,
77 const Container_type& nonZeroRowIndices,
78 Row_container_type* rowContainer,
79 Column_settings* colSettings);
80 template <class Container_type = typename Master_matrix::boundary_type>
81 List_column(const Container_type& nonZeroChainRowIndices,
82 dimension_type dimension,
83 Column_settings* colSettings);
84 template <class Container_type = typename Master_matrix::boundary_type, class Row_container_type>
85 List_column(index columnIndex,
86 const Container_type& nonZeroChainRowIndices,
87 dimension_type dimension,
88 Row_container_type* rowContainer,
89 Column_settings* colSettings);
90 List_column(const List_column& column,
91 Column_settings* colSettings = nullptr);
92 template <class Row_container_type>
93 List_column(const List_column& column,
94 index columnIndex,
95 Row_container_type* rowContainer,
96 Column_settings* colSettings = nullptr);
97 List_column(List_column&& column) noexcept;
99
100 std::vector<Field_element_type> get_content(int columnLength = -1) const;
101 bool is_non_zero(id_index rowIndex) const;
102 bool is_empty() const;
103 std::size_t size() const;
104
105 template <class Map_type>
106 void reorder(const Map_type& valueMap, [[maybe_unused]] index columnIndex = -1);
107 void clear();
108 void clear(id_index rowIndex);
109
110 id_index get_pivot() const;
111 Field_element_type get_pivot_value() const;
112
113 iterator begin() noexcept;
114 const_iterator begin() const noexcept;
115 iterator end() noexcept;
116 const_iterator end() const noexcept;
117 reverse_iterator rbegin() noexcept;
118 const_reverse_iterator rbegin() const noexcept;
119 reverse_iterator rend() noexcept;
120 const_reverse_iterator rend() const noexcept;
121
122 template <class Cell_range>
123 List_column& operator+=(const Cell_range& column);
124 List_column& operator+=(List_column& column);
125
126 List_column& operator*=(unsigned int v);
127
128 // this = v * this + column
129 template <class Cell_range>
130 List_column& multiply_target_and_add(const Field_element_type& val, const Cell_range& column);
131 List_column& multiply_target_and_add(const Field_element_type& val, List_column& column);
132 // this = this + column * v
133 template <class Cell_range>
134 List_column& multiply_source_and_add(const Cell_range& column, const Field_element_type& val);
135 List_column& multiply_source_and_add(List_column& column, const Field_element_type& val);
136
137 friend bool operator==(const List_column& c1, const List_column& c2) {
138 if (&c1 == &c2) return true;
139
140 auto it1 = c1.column_.begin();
141 auto it2 = c2.column_.begin();
142 if (c1.column_.size() != c2.column_.size()) return false;
143 while (it1 != c1.column_.end() && it2 != c2.column_.end()) {
144 if constexpr (Master_matrix::Option_list::is_z2) {
145 if ((*it1)->get_row_index() != (*it2)->get_row_index()) return false;
146 } else {
147 if ((*it1)->get_row_index() != (*it2)->get_row_index() || (*it1)->get_element() != (*it2)->get_element())
148 return false;
149 }
150 ++it1;
151 ++it2;
152 }
153 return true;
154 }
155 friend bool operator<(const List_column& c1, const List_column& c2) {
156 if (&c1 == &c2) return false;
157
158 auto it1 = c1.column_.begin();
159 auto it2 = c2.column_.begin();
160 while (it1 != c1.column_.end() && it2 != c2.column_.end()) {
161 if ((*it1)->get_row_index() != (*it2)->get_row_index()) return (*it1)->get_row_index() < (*it2)->get_row_index();
162 if constexpr (!Master_matrix::Option_list::is_z2) {
163 if ((*it1)->get_element() != (*it2)->get_element()) return (*it1)->get_element() < (*it2)->get_element();
164 }
165 ++it1;
166 ++it2;
167 }
168 return it2 != c2.column_.end();
169 }
170
171 // Disabled with row access.
172 List_column& operator=(const List_column& other);
173
174 friend void swap(List_column& col1, List_column& col2) {
175 swap(static_cast<typename Master_matrix::Row_access_option&>(col1),
176 static_cast<typename Master_matrix::Row_access_option&>(col2));
177 swap(static_cast<typename Master_matrix::Column_dimension_option&>(col1),
178 static_cast<typename Master_matrix::Column_dimension_option&>(col2));
179 swap(static_cast<typename Master_matrix::Chain_column_option&>(col1),
180 static_cast<typename Master_matrix::Chain_column_option&>(col2));
181 col1.column_.swap(col2.column_);
182 std::swap(col1.operators_, col2.operators_);
183 std::swap(col1.cellPool_, col2.cellPool_);
184 }
185
186 private:
187 using ra_opt = typename Master_matrix::Row_access_option;
188 using dim_opt = typename Master_matrix::Column_dimension_option;
189 using chain_opt = typename Master_matrix::Chain_column_option;
190
191 Column_type column_;
192 Field_operators* operators_;
193 Cell_constructor* cellPool_;
194
195 template <class Column_type, class Cell_iterator, typename F1, typename F2, typename F3, typename F4>
196 friend void _generic_merge_cell_to_column(Column_type& targetColumn,
197 Cell_iterator& itSource,
198 typename Column_type::Column_type::iterator& itTarget,
199 F1&& process_target,
200 F2&& process_source,
201 F3&& update_target1,
202 F4&& update_target2,
203 bool& pivotIsZeroed);
204 template <class Column_type, class Cell_range, typename F1, typename F2, typename F3, typename F4, typename F5>
205 friend bool _generic_add_to_column(const Cell_range& source,
206 Column_type& targetColumn,
207 F1&& process_target,
208 F2&& process_source,
209 F3&& update_target1,
210 F4&& update_target2,
211 F5&& finish_target);
212 template <class Column_type, class Cell_range>
213 friend bool _add_to_column(const Cell_range& source, Column_type& targetColumn);
214 template <class Column_type, class Cell_range>
215 friend bool _multiply_target_and_add_to_column(const typename Column_type::Field_element_type& val,
216 const Cell_range& source,
217 Column_type& targetColumn);
218 template <class Column_type, class Cell_range>
219 friend bool _multiply_source_and_add_to_column(const typename Column_type::Field_element_type& val,
220 const Cell_range& source,
221 Column_type& targetColumn);
222
223 void _delete_cell(typename Column_type::iterator& it);
224 Cell* _insert_cell(const Field_element_type& value,
225 id_index rowIndex,
226 const typename Column_type::iterator& position);
227 void _insert_cell(id_index rowIndex, const typename Column_type::iterator& position);
228 void _update_cell(const Field_element_type& value, id_index rowIndex, const typename Column_type::iterator& position);
229 void _update_cell(id_index rowIndex, const typename Column_type::iterator& position);
230 template <class Cell_range>
231 bool _add(const Cell_range& column);
232 template <class Cell_range>
233 bool _multiply_target_and_add(const Field_element_type& val, const Cell_range& column);
234 template <class Cell_range>
235 bool _multiply_source_and_add(const Cell_range& column, const Field_element_type& val);
236};
237
238template <class Master_matrix>
239inline List_column<Master_matrix>::List_column(Column_settings* colSettings)
240 : ra_opt(),
241 dim_opt(),
242 chain_opt(),
243 operators_(nullptr),
244 cellPool_(colSettings == nullptr ? nullptr : &(colSettings->cellConstructor))
245{
246 if (operators_ == nullptr && cellPool_ == nullptr) return; // to allow default constructor which gives a dummy column
247 if constexpr (!Master_matrix::Option_list::is_z2) {
248 operators_ = &(colSettings->operators);
249 }
250}
251
252template <class Master_matrix>
253template <class Container_type>
254inline List_column<Master_matrix>::List_column(const Container_type& nonZeroRowIndices,
255 Column_settings* colSettings)
256 : ra_opt(),
257 dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1),
258 chain_opt(),
259 column_(nonZeroRowIndices.size()),
260 operators_(nullptr),
261 cellPool_(&(colSettings->cellConstructor))
262{
263 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
264 "Constructor not available for chain columns, please specify the dimension of the chain.");
265
266 auto it = column_.begin();
267 if constexpr (Master_matrix::Option_list::is_z2) {
268 for (id_index id : nonZeroRowIndices) {
269 _update_cell(id, it++);
270 }
271 } else {
272 operators_ = &(colSettings->operators);
273 for (const auto& p : nonZeroRowIndices) {
274 _update_cell(operators_->get_value(p.second), p.first, it++);
275 }
276 }
277}
278
279template <class Master_matrix>
280template <class Container_type, class Row_container_type>
281inline List_column<Master_matrix>::List_column(index columnIndex,
282 const Container_type& nonZeroRowIndices,
283 Row_container_type* rowContainer,
284 Column_settings* colSettings)
285 : ra_opt(columnIndex, rowContainer),
286 dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1),
287 chain_opt([&] {
288 if constexpr (Master_matrix::Option_list::is_z2) {
289 return nonZeroRowIndices.begin() == nonZeroRowIndices.end() ? -1 : *std::prev(nonZeroRowIndices.end());
290 } else {
291 return nonZeroRowIndices.begin() == nonZeroRowIndices.end() ? -1 : std::prev(nonZeroRowIndices.end())->first;
292 }
293 }()),
294 column_(nonZeroRowIndices.size()),
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 auto it = column_.begin();
302 if constexpr (Master_matrix::Option_list::is_z2) {
303 for (id_index id : nonZeroRowIndices) {
304 _update_cell(id, it++);
305 }
306 } else {
307 operators_ = &(colSettings->operators);
308 for (const auto& p : nonZeroRowIndices) {
309 _update_cell(operators_->get_value(p.second), p.first, it++);
310 }
311 }
312}
313
314template <class Master_matrix>
315template <class Container_type>
316inline List_column<Master_matrix>::List_column(const Container_type& nonZeroRowIndices,
317 dimension_type dimension,
318 Column_settings* colSettings)
319 : ra_opt(),
320 dim_opt(dimension),
321 chain_opt([&] {
322 if constexpr (Master_matrix::Option_list::is_z2) {
323 return nonZeroRowIndices.begin() == nonZeroRowIndices.end() ? -1 : *std::prev(nonZeroRowIndices.end());
324 } else {
325 return nonZeroRowIndices.begin() == nonZeroRowIndices.end() ? -1 : std::prev(nonZeroRowIndices.end())->first;
326 }
327 }()),
328 column_(nonZeroRowIndices.size()),
329 operators_(nullptr),
330 cellPool_(&(colSettings->cellConstructor))
331{
332 auto it = column_.begin();
333 if constexpr (Master_matrix::Option_list::is_z2) {
334 for (id_index id : nonZeroRowIndices) {
335 _update_cell(id, it++);
336 }
337 } else {
338 operators_ = &(colSettings->operators);
339 for (const auto& p : nonZeroRowIndices) {
340 _update_cell(operators_->get_value(p.second), p.first, it++);
341 }
342 }
343}
344
345template <class Master_matrix>
346template <class Container_type, class Row_container_type>
347inline List_column<Master_matrix>::List_column(
348 index columnIndex,
349 const Container_type& nonZeroRowIndices,
350 dimension_type dimension,
351 Row_container_type* rowContainer,
352 Column_settings* colSettings)
353 : ra_opt(columnIndex, rowContainer),
354 dim_opt(dimension),
355 chain_opt([&] {
356 if constexpr (Master_matrix::Option_list::is_z2) {
357 return nonZeroRowIndices.begin() == nonZeroRowIndices.end() ? -1 : *std::prev(nonZeroRowIndices.end());
358 } else {
359 return nonZeroRowIndices.begin() == nonZeroRowIndices.end() ? -1 : std::prev(nonZeroRowIndices.end())->first;
360 }
361 }()),
362 column_(nonZeroRowIndices.size()),
363 operators_(nullptr),
364 cellPool_(&(colSettings->cellConstructor))
365{
366 auto it = column_.begin();
367 if constexpr (Master_matrix::Option_list::is_z2) {
368 for (id_index id : nonZeroRowIndices) {
369 _update_cell(id, it++);
370 }
371 } else {
372 operators_ = &(colSettings->operators);
373 for (const auto& p : nonZeroRowIndices) {
374 _update_cell(operators_->get_value(p.second), p.first, it++);
375 }
376 }
377}
378
379template <class Master_matrix>
380inline List_column<Master_matrix>::List_column(const List_column& column,
381 Column_settings* colSettings)
382 : ra_opt(),
383 dim_opt(static_cast<const dim_opt&>(column)),
384 chain_opt(static_cast<const chain_opt&>(column)),
385 column_(column.column_.size()),
386 operators_(colSettings == nullptr ? column.operators_ : nullptr),
387 cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor))
388{
389 static_assert(!Master_matrix::Option_list::has_row_access,
390 "Simple copy constructor not available when row access option enabled. Please specify the new column "
391 "index and the row container.");
392
393 if constexpr (!Master_matrix::Option_list::is_z2){
394 if (colSettings != nullptr) operators_ = &(colSettings->operators);
395 }
396
397 auto it = column_.begin();
398 for (const Cell* cell : column.column_) {
399 if constexpr (Master_matrix::Option_list::is_z2) {
400 _update_cell(cell->get_row_index(), it++);
401 } else {
402 _update_cell(cell->get_element(), cell->get_row_index(), it++);
403 }
404 }
405}
406
407template <class Master_matrix>
408template <class Row_container_type>
409inline List_column<Master_matrix>::List_column(const List_column& column,
410 index columnIndex,
411 Row_container_type* rowContainer,
412 Column_settings* colSettings)
413 : ra_opt(columnIndex, rowContainer),
414 dim_opt(static_cast<const dim_opt&>(column)),
415 chain_opt(static_cast<const chain_opt&>(column)),
416 column_(column.column_.size()),
417 operators_(colSettings == nullptr ? column.operators_ : nullptr),
418 cellPool_(colSettings == nullptr ? column.cellPool_ : &(colSettings->cellConstructor))
419{
420 if constexpr (!Master_matrix::Option_list::is_z2){
421 if (colSettings != nullptr) operators_ = &(colSettings->operators);
422 }
423
424 auto it = column_.begin();
425 for (const Cell* cell : column.column_) {
426 if constexpr (Master_matrix::Option_list::is_z2) {
427 _update_cell(cell->get_row_index(), it++);
428 } else {
429 _update_cell(cell->get_element(), cell->get_row_index(), it++);
430 }
431 }
432}
433
434template <class Master_matrix>
435inline List_column<Master_matrix>::List_column(List_column&& column) noexcept
436 : ra_opt(std::move(static_cast<ra_opt&>(column))),
437 dim_opt(std::move(static_cast<dim_opt&>(column))),
438 chain_opt(std::move(static_cast<chain_opt&>(column))),
439 column_(std::move(column.column_)),
440 operators_(std::exchange(column.operators_, nullptr)),
441 cellPool_(std::exchange(column.cellPool_, nullptr))
442{}
443
444template <class Master_matrix>
445inline List_column<Master_matrix>::~List_column()
446{
447 for (auto* cell : column_) {
448 if constexpr (Master_matrix::Option_list::has_row_access) ra_opt::unlink(cell);
449 cellPool_->destroy(cell);
450 }
451}
452
453template <class Master_matrix>
454inline std::vector<typename List_column<Master_matrix>::Field_element_type>
455List_column<Master_matrix>::get_content(int columnLength) const
456{
457 if (columnLength < 0 && column_.size() > 0)
458 columnLength = column_.back()->get_row_index() + 1;
459 else if (columnLength < 0)
460 return std::vector<Field_element_type>();
461
462 std::vector<Field_element_type> container(columnLength, 0);
463 for (auto it = column_.begin(); it != column_.end() && (*it)->get_row_index() < static_cast<id_index>(columnLength);
464 ++it) {
465 if constexpr (Master_matrix::Option_list::is_z2) {
466 container[(*it)->get_row_index()] = 1;
467 } else {
468 container[(*it)->get_row_index()] = (*it)->get_element();
469 }
470 }
471 return container;
472}
473
474template <class Master_matrix>
475inline bool List_column<Master_matrix>::is_non_zero(id_index rowIndex) const
476{
477 // could be changed to dichotomic search as column is ordered by row index,
478 // but I am not sure if it is really worth it as there is no random access
479 // and the columns should not be that long anyway.
480 for (const Cell* cell : column_)
481 if (cell->get_row_index() == rowIndex) return true;
482
483 return false;
484}
485
486template <class Master_matrix>
487inline bool List_column<Master_matrix>::is_empty() const
488{
489 return column_.empty();
490}
491
492template <class Master_matrix>
493inline std::size_t List_column<Master_matrix>::size() const
494{
495 return column_.size();
496}
497
498template <class Master_matrix>
499template <class Map_type>
500inline void List_column<Master_matrix>::reorder(const Map_type& valueMap, [[maybe_unused]] index columnIndex)
501{
502 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
503 "Method not available for chain columns.");
504
505 for (auto it = column_.begin(); it != column_.end(); ++it) {
506 Cell* cell = *it;
507 if constexpr (Master_matrix::Option_list::has_row_access) {
508 ra_opt::unlink(cell);
509 if (columnIndex != static_cast<index>(-1)) cell->set_column_index(columnIndex);
510 }
511 cell->set_row_index(valueMap.at(cell->get_row_index()));
512 if constexpr (Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access)
513 ra_opt::insert_cell(cell->get_row_index(), cell);
514 }
515
516 // all cells have to be deleted first, to avoid problem with insertion when row is a set
517 if constexpr (!Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access) {
518 for (auto it = column_.begin(); it != column_.end(); ++it) {
519 Cell* cell = *it;
520 ra_opt::insert_cell(cell->get_row_index(), cell);
521 }
522 }
523
524 column_.sort([](const Cell* c1, const Cell* c2) { return *c1 < *c2; });
525}
526
527template <class Master_matrix>
528inline void List_column<Master_matrix>::clear()
529{
530 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
531 "Method not available for chain columns as a base element should not be empty.");
532
533 for (auto* cell : column_) {
534 if constexpr (Master_matrix::Option_list::has_row_access) ra_opt::unlink(cell);
535 cellPool_->destroy(cell);
536 }
537
538 column_.clear();
539}
540
541template <class Master_matrix>
542inline void List_column<Master_matrix>::clear(id_index rowIndex)
543{
544 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
545 "Method not available for chain columns.");
546
547 auto it = column_.begin();
548 while (it != column_.end() && (*it)->get_row_index() != rowIndex) it++;
549 if (it != column_.end()) _delete_cell(it);
550}
551
552template <class Master_matrix>
553inline typename List_column<Master_matrix>::id_index
554List_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 usefull then?
558
559 if constexpr (Master_matrix::Option_list::is_of_boundary_type) {
560 if (column_.empty()) return -1;
561 return column_.back()->get_row_index();
562 } else {
563 return chain_opt::get_pivot();
564 }
565}
566
567template <class Master_matrix>
568inline typename List_column<Master_matrix>::Field_element_type
569List_column<Master_matrix>::get_pivot_value() const
570{
571 static_assert(Master_matrix::isNonBasic,
572 "Method not available for base columns."); // could technically be, but is the notion usefull then?
573
574 if constexpr (Master_matrix::Option_list::is_z2) {
575 return 1;
576 } else {
577 if constexpr (Master_matrix::Option_list::is_of_boundary_type) {
578 if (column_.empty()) return 0;
579 return column_.back()->get_element();
580 } else {
581 if (chain_opt::get_pivot() == static_cast<id_index>(-1)) return Field_element_type();
582 for (const Cell* cell : column_) {
583 if (cell->get_row_index() == chain_opt::get_pivot()) return cell->get_element();
584 }
585 return Field_element_type(); // should never happen if chain column is used properly
586 }
587 }
588}
589
590template <class Master_matrix>
591inline typename List_column<Master_matrix>::iterator
592List_column<Master_matrix>::begin() noexcept
593{
594 return column_.begin();
595}
596
597template <class Master_matrix>
598inline typename List_column<Master_matrix>::const_iterator
599List_column<Master_matrix>::begin() const noexcept
600{
601 return column_.begin();
602}
603
604template <class Master_matrix>
605inline typename List_column<Master_matrix>::iterator
606List_column<Master_matrix>::end() noexcept
607{
608 return column_.end();
609}
610
611template <class Master_matrix>
612inline typename List_column<Master_matrix>::const_iterator
613List_column<Master_matrix>::end() const noexcept
614{
615 return column_.end();
616}
617
618template <class Master_matrix>
619inline typename List_column<Master_matrix>::reverse_iterator
620List_column<Master_matrix>::rbegin() noexcept
621{
622 return column_.rbegin();
623}
624
625template <class Master_matrix>
626inline typename List_column<Master_matrix>::const_reverse_iterator
627List_column<Master_matrix>::rbegin() const noexcept
628{
629 return column_.rbegin();
630}
631
632template <class Master_matrix>
633inline typename List_column<Master_matrix>::reverse_iterator
634List_column<Master_matrix>::rend() noexcept
635{
636 return column_.rend();
637}
638
639template <class Master_matrix>
640inline typename List_column<Master_matrix>::const_reverse_iterator
641List_column<Master_matrix>::rend() const noexcept
642{
643 return column_.rend();
644}
645
646template <class Master_matrix>
647template <class Cell_range>
648inline List_column<Master_matrix>& List_column<Master_matrix>::operator+=(
649 const Cell_range& column)
650{
651 static_assert((!Master_matrix::isNonBasic || std::is_same_v<Cell_range, List_column>),
652 "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
653 "base element."); // could be removed, if we give the responsability to the user.
654 static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
655 "For chain columns, the given column cannot be constant.");
656
657 _add(column);
658
659 return *this;
660}
661
662template <class Master_matrix>
663inline List_column<Master_matrix>& List_column<Master_matrix>::operator+=(
664 List_column& column)
665{
666 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
667 // assumes that the addition never zeros out this column.
668 if (_add(column)) {
669 chain_opt::swap_pivots(column);
670 dim_opt::swap_dimension(column);
671 }
672 } else {
673 _add(column);
674 }
675
676 return *this;
677}
678
679template <class Master_matrix>
680inline List_column<Master_matrix>& List_column<Master_matrix>::operator*=(
681 unsigned int v)
682{
683 if constexpr (Master_matrix::Option_list::is_z2) {
684 if (v % 2 == 0) {
685 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
686 throw std::invalid_argument("A chain column should not be multiplied by 0.");
687 } else {
688 clear();
689 }
690 }
691 } else {
692 Field_element_type val = operators_->get_value(v);
693
694 if (val == 0u) {
695 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
696 throw std::invalid_argument("A chain column should not be multiplied by 0.");
697 } else {
698 clear();
699 }
700 return *this;
701 }
702
703 if (val == 1u) return *this;
704
705 for (Cell* cell : column_) {
706 operators_->multiply_inplace(cell->get_element(), val);
707 if constexpr (Master_matrix::Option_list::has_row_access) ra_opt::update_cell(*cell);
708 }
709 }
710
711 return *this;
712}
713
714template <class Master_matrix>
715template <class Cell_range>
716inline List_column<Master_matrix>& List_column<Master_matrix>::multiply_target_and_add(
717 const Field_element_type& val, const Cell_range& column)
718{
719 static_assert((!Master_matrix::isNonBasic || std::is_same_v<Cell_range, List_column>),
720 "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
721 "base element."); // could be removed, if we give the responsability to the user.
722 static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
723 "For chain columns, the given column cannot be constant.");
724
725 if constexpr (Master_matrix::Option_list::is_z2) {
726 if (val) {
727 _add(column);
728 } else {
729 clear();
730 _add(column);
731 }
732 } else {
733 _multiply_target_and_add(val, column);
734 }
735
736 return *this;
737}
738
739template <class Master_matrix>
740inline List_column<Master_matrix>& List_column<Master_matrix>::multiply_target_and_add(
741 const Field_element_type& val, List_column& column)
742{
743 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
744 // assumes that the addition never zeros out this column.
745 if constexpr (Master_matrix::Option_list::is_z2) {
746 if (val) {
747 if (_add(column)) {
748 chain_opt::swap_pivots(column);
749 dim_opt::swap_dimension(column);
750 }
751 } else {
752 throw std::invalid_argument("A chain column should not be multiplied by 0.");
753 }
754 } else {
755 if (_multiply_target_and_add(val, column)) {
756 chain_opt::swap_pivots(column);
757 dim_opt::swap_dimension(column);
758 }
759 }
760 } else {
761 if constexpr (Master_matrix::Option_list::is_z2) {
762 if (val) {
763 _add(column);
764 } else {
765 clear();
766 _add(column);
767 }
768 } else {
769 _multiply_target_and_add(val, column);
770 }
771 }
772
773 return *this;
774}
775
776template <class Master_matrix>
777template <class Cell_range>
778inline List_column<Master_matrix>& List_column<Master_matrix>::multiply_source_and_add(
779 const Cell_range& column, const Field_element_type& val)
780{
781 static_assert((!Master_matrix::isNonBasic || std::is_same_v<Cell_range, List_column>),
782 "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
783 "base element."); // could be removed, if we give the responsability to the user.
784 static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
785 "For chain columns, the given column cannot be constant.");
786
787 if constexpr (Master_matrix::Option_list::is_z2) {
788 if (val) {
789 _add(column);
790 }
791 } else {
792 _multiply_source_and_add(column, val);
793 }
794
795 return *this;
796}
797
798template <class Master_matrix>
799inline List_column<Master_matrix>& List_column<Master_matrix>::multiply_source_and_add(
800 List_column& column, const Field_element_type& val)
801{
802 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
803 // assumes that the addition never zeros out this column.
804 if constexpr (Master_matrix::Option_list::is_z2) {
805 if (val) {
806 if (_add(column)) {
807 chain_opt::swap_pivots(column);
808 dim_opt::swap_dimension(column);
809 }
810 }
811 } else {
812 if (_multiply_source_and_add(column, val)) {
813 chain_opt::swap_pivots(column);
814 dim_opt::swap_dimension(column);
815 }
816 }
817 } else {
818 if constexpr (Master_matrix::Option_list::is_z2) {
819 if (val) {
820 _add(column);
821 }
822 } else {
823 _multiply_source_and_add(column, val);
824 }
825 }
826
827 return *this;
828}
829
830template <class Master_matrix>
831inline List_column<Master_matrix>& List_column<Master_matrix>::operator=(const List_column& other)
832{
833 static_assert(!Master_matrix::Option_list::has_row_access, "= assignement not enabled with row access option.");
834
835 dim_opt::operator=(other);
836 chain_opt::operator=(other);
837
838 auto tmpPool = cellPool_;
839 cellPool_ = other.cellPool_;
840
841 while (column_.size() > other.column_.size()) {
842 if (column_.back() != nullptr) {
843 if constexpr (Master_matrix::Option_list::has_row_access) ra_opt::unlink(column_.back());
844 tmpPool->destroy(column_.back());
845 }
846 column_.pop_back();
847 }
848
849 column_.resize(other.column_.size(), nullptr);
850 auto it = column_.begin();
851 for (const Cell* cell : other.column_) {
852 if (*it != nullptr) {
853 if constexpr (Master_matrix::Option_list::has_row_access) ra_opt::unlink(*it);
854 tmpPool->destroy(*it);
855 }
856 if constexpr (Master_matrix::Option_list::is_z2) {
857 _update_cell(cell->get_row_index(), it++);
858 } else {
859 _update_cell(cell->get_element(), cell->get_row_index(), it++);
860 }
861 }
862
863 operators_ = other.operators_;
864
865 return *this;
866}
867
868template <class Master_matrix>
869inline void List_column<Master_matrix>::_delete_cell(typename Column_type::iterator& it)
870{
871 if constexpr (Master_matrix::Option_list::has_row_access) ra_opt::unlink(*it);
872 cellPool_->destroy(*it);
873 it = column_.erase(it);
874}
875
876template <class Master_matrix>
877inline typename List_column<Master_matrix>::Cell* List_column<Master_matrix>::_insert_cell(
878 const Field_element_type& value, id_index rowIndex, 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 newCell->set_element(value);
883 column_.insert(position, newCell);
884 ra_opt::insert_cell(rowIndex, newCell);
885 return newCell;
886 } else {
887 Cell* newCell = cellPool_->construct(rowIndex);
888 newCell->set_element(value);
889 column_.insert(position, newCell);
890 return newCell;
891 }
892}
893
894template <class Master_matrix>
895inline void List_column<Master_matrix>::_insert_cell(id_index rowIndex,
896 const typename Column_type::iterator& position)
897{
898 if constexpr (Master_matrix::Option_list::has_row_access) {
899 Cell* newCell = cellPool_->construct(ra_opt::columnIndex_, rowIndex);
900 column_.insert(position, newCell);
901 ra_opt::insert_cell(rowIndex, newCell);
902 } else {
903 Cell* newCell = cellPool_->construct(rowIndex);
904 column_.insert(position, newCell);
905 }
906}
907
908template <class Master_matrix>
909inline void List_column<Master_matrix>::_update_cell(const Field_element_type& value,
910 id_index rowIndex,
911 const typename Column_type::iterator& position)
912{
913 if constexpr (Master_matrix::Option_list::has_row_access) {
914 *position = cellPool_->construct(ra_opt::columnIndex_, rowIndex);
915 (*position)->set_element(value);
916 ra_opt::insert_cell(rowIndex, *position);
917 } else {
918 *position = cellPool_->construct(rowIndex);
919 (*position)->set_element(value);
920 }
921}
922
923template <class Master_matrix>
924inline void List_column<Master_matrix>::_update_cell(id_index rowIndex,
925 const typename Column_type::iterator& position)
926{
927 if constexpr (Master_matrix::Option_list::has_row_access) {
928 *position = cellPool_->construct(ra_opt::columnIndex_, rowIndex);
929 ra_opt::insert_cell(rowIndex, *position);
930 } else {
931 *position = cellPool_->construct(rowIndex);
932 }
933}
934
935template <class Master_matrix>
936template <class Cell_range>
937inline bool List_column<Master_matrix>::_add(const Cell_range& column)
938{
939 if (column.begin() == column.end()) return false;
940 if (column_.empty()) { // chain should never enter here.
941 column_.resize(column.size());
942 auto it = column_.begin();
943 for (const Cell& cell : column) {
944 if constexpr (Master_matrix::Option_list::is_z2) {
945 _update_cell(cell.get_row_index(), it++);
946 } else {
947 _update_cell(cell.get_element(), cell.get_row_index(), it++);
948 }
949 }
950 return true;
951 }
952
953 return _add_to_column(column, *this);
954}
955
956template <class Master_matrix>
957template <class Cell_range>
958inline bool List_column<Master_matrix>::_multiply_target_and_add(const Field_element_type& val,
959 const Cell_range& column)
960{
961 return _multiply_target_and_add_to_column(val, column, *this);
962}
963
964template <class Master_matrix>
965template <class Cell_range>
966inline bool List_column<Master_matrix>::_multiply_source_and_add(const Cell_range& column,
967 const Field_element_type& val)
968{
969 return _multiply_source_and_add_to_column(val, column, *this);
970}
971
972} // namespace persistence_matrix
973} // namespace Gudhi
974
983template <class Master_matrix>
984struct std::hash<Gudhi::persistence_matrix::List_column<Master_matrix> >
985{
986 std::size_t operator()(const Gudhi::persistence_matrix::List_column<Master_matrix>& column) const {
987 return Gudhi::persistence_matrix::hash_column(column);
988 }
989};
990
991#endif // PM_LIST_COLUMN_H
Contains the New_cell_constructor and Pool_cell_constructor structures.
Column class following the PersistenceMatrixColumn concept.
Definition list_column.h:51
Contains helper methods for column addition and column hasher.
Gudhi namespace.
Definition SimplicialComplexForAlpha.h:14