vector_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_VECTOR_COLUMN_H
19#define PM_VECTOR_COLUMN_H
20
21#include <cstddef>
22#include <vector>
23#include <stdexcept>
24#include <type_traits>
25#include <algorithm> //binary_search
26#include <unordered_set>
27#include <utility> //std::swap, std::move & std::exchange
28
29#include <boost/iterator/indirect_iterator.hpp>
31
32namespace Gudhi {
33namespace persistence_matrix {
34
48template <class Master_matrix>
52{
53 public:
54 using Master = Master_matrix;
55 using Index = typename Master_matrix::Index;
56 using ID_index = typename Master_matrix::ID_index;
57 using Dimension = typename Master_matrix::Dimension;
58 using Field_element = typename Master_matrix::Element;
59 using Entry = typename Master_matrix::Matrix_entry;
60 using Column_settings = typename Master_matrix::Column_settings;
61
62 private:
63 using Field_operators = typename Master_matrix::Field_operators;
64 using Column_support = std::vector<Entry*>;
65 using Entry_constructor = typename Master_matrix::Entry_constructor;
66
67 public:
68 using iterator = boost::indirect_iterator<typename Column_support::iterator>;
69 using const_iterator = boost::indirect_iterator<typename Column_support::const_iterator>;
70 using reverse_iterator = boost::indirect_iterator<typename Column_support::reverse_iterator>;
71 using const_reverse_iterator = boost::indirect_iterator<typename Column_support::const_reverse_iterator>;
72
73 Vector_column(Column_settings* colSettings = nullptr);
74 template <class Container = typename Master_matrix::Boundary>
75 Vector_column(const Container& nonZeroRowIndices, Column_settings* colSettings);
76 template <class Container = typename Master_matrix::Boundary, class Row_container>
77 Vector_column(Index columnIndex,
78 const Container& nonZeroRowIndices,
79 Row_container* rowContainer,
80 Column_settings* colSettings);
81 template <class Container = typename Master_matrix::Boundary>
82 Vector_column(const Container& nonZeroChainRowIndices, Dimension dimension, Column_settings* colSettings);
83 template <class Container = typename Master_matrix::Boundary, class Row_container>
84 Vector_column(Index columnIndex,
85 const Container& nonZeroChainRowIndices,
86 Dimension dimension,
87 Row_container* rowContainer,
88 Column_settings* colSettings);
89 Vector_column(const Vector_column& column, Column_settings* colSettings = nullptr);
90 template <class Row_container>
91 Vector_column(const Vector_column& column,
92 Index columnIndex,
93 Row_container* rowContainer,
94 Column_settings* colSettings = nullptr);
95 Vector_column(Vector_column&& column) noexcept;
97
98 std::vector<Field_element> get_content(int columnLength = -1) const;
99 bool is_non_zero(ID_index rowIndex) const;
100 bool is_empty() const;
101 std::size_t size() const;
102
103 template <class Row_index_map>
104 void reorder(const Row_index_map& valueMap,
105 [[maybe_unused]] Index columnIndex = Master_matrix::template get_null_value<Index>());
106 void clear();
107 // do not clear an entry to 0 if the entry was already 0, otherwise size/is_empty will be wrong.
108 void clear(ID_index rowIndex);
109
110 ID_index get_pivot();
111 Field_element get_pivot_value();
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 Entry_range>
123 Vector_column& operator+=(const Entry_range& column);
124 Vector_column& operator+=(Vector_column& column);
125
126 Vector_column& operator*=(unsigned int v);
127
128 // this = v * this + column
129 template <class Entry_range>
130 Vector_column& multiply_target_and_add(const Field_element& val, const Entry_range& column);
131 Vector_column& multiply_target_and_add(const Field_element& val, Vector_column& column);
132 // this = this + column * v
133 template <class Entry_range>
134 Vector_column& multiply_source_and_add(const Entry_range& column, const Field_element& val);
135 Vector_column& multiply_source_and_add(Vector_column& column, const Field_element& val);
136
137 void push_back(const Entry& entry);
138
139 std::size_t compute_hash_value();
140
141 friend bool operator==(const Vector_column& c1, const Vector_column& c2) {
142 if (&c1 == &c2) return true;
143 if (c1.erasedValues_.empty() && c2.erasedValues_.empty() && c1.column_.size() != c2.column_.size()) return false;
144
145 auto it1 = c1.column_.begin();
146 auto it2 = c2.column_.begin();
147 while (it1 != c1.column_.end() && it2 != c2.column_.end()) {
148 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
149 while (it1 != c1.column_.end() && c1.erasedValues_.find((*it1)->get_row_index()) != c1.erasedValues_.end())
150 ++it1;
151 while (it2 != c2.column_.end() && c2.erasedValues_.find((*it2)->get_row_index()) != c2.erasedValues_.end())
152 ++it2;
153 if (it1 == c1.column_.end() || it2 == c2.column_.end()) break;
154 }
155 if constexpr (Master_matrix::Option_list::is_z2) {
156 if ((*it1)->get_row_index() != (*it2)->get_row_index()) return false;
157 } else {
158 if ((*it1)->get_row_index() != (*it2)->get_row_index() || (*it1)->get_element() != (*it2)->get_element())
159 return false;
160 }
161 ++it1;
162 ++it2;
163 }
164
165 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
166 while (it1 != c1.column_.end() && c1.erasedValues_.find((*it1)->get_row_index()) != c1.erasedValues_.end()) ++it1;
167 while (it2 != c2.column_.end() && c2.erasedValues_.find((*it2)->get_row_index()) != c2.erasedValues_.end()) ++it2;
168 return it2 == c2.column_.end() && it1 == c1.column_.end();
169 } else {
170 return true;
171 }
172 }
173
174 friend bool operator<(const Vector_column& c1, const Vector_column& c2) {
175 if (&c1 == &c2) return false;
176
177 auto it1 = c1.column_.begin();
178 auto it2 = c2.column_.begin();
179 while (it1 != c1.column_.end() && it2 != c2.column_.end()) {
180 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
181 while (it1 != c1.column_.end() && c1.erasedValues_.find((*it1)->get_row_index()) != c1.erasedValues_.end())
182 ++it1;
183 while (it2 != c2.column_.end() && c2.erasedValues_.find((*it2)->get_row_index()) != c2.erasedValues_.end())
184 ++it2;
185 if (it1 == c1.column_.end() || it2 == c2.column_.end()) break;
186 }
187
188 if ((*it1)->get_row_index() != (*it2)->get_row_index()) return (*it1)->get_row_index() < (*it2)->get_row_index();
189 if constexpr (!Master_matrix::Option_list::is_z2) {
190 if ((*it1)->get_element() != (*it2)->get_element()) return (*it1)->get_element() < (*it2)->get_element();
191 }
192 ++it1;
193 ++it2;
194 }
195 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
196 while (it1 != c1.column_.end() && c1.erasedValues_.find((*it1)->get_row_index()) != c1.erasedValues_.end()) ++it1;
197 while (it2 != c2.column_.end() && c2.erasedValues_.find((*it2)->get_row_index()) != c2.erasedValues_.end()) ++it2;
198 }
199 return it2 != c2.column_.end();
200 }
201
202 // Disabled with row access.
203 Vector_column& operator=(const Vector_column& other);
204
205 friend void swap(Vector_column& col1, Vector_column& col2) {
206 swap(static_cast<typename Master_matrix::Row_access_option&>(col1),
207 static_cast<typename Master_matrix::Row_access_option&>(col2));
208 swap(static_cast<typename Master_matrix::Column_dimension_option&>(col1),
209 static_cast<typename Master_matrix::Column_dimension_option&>(col2));
210 swap(static_cast<typename Master_matrix::Chain_column_option&>(col1),
211 static_cast<typename Master_matrix::Chain_column_option&>(col2));
212 col1.column_.swap(col2.column_);
213 col1.erasedValues_.swap(col2.erasedValues_);
214 std::swap(col1.operators_, col2.operators_);
215 std::swap(col1.entryPool_, col2.entryPool_);
216 }
217
218 private:
219 using RA_opt = typename Master_matrix::Row_access_option;
220 using Dim_opt = typename Master_matrix::Column_dimension_option;
221 using Chain_opt = typename Master_matrix::Chain_column_option;
222
223 Column_support column_;
224 std::unordered_set<ID_index> erasedValues_; // TODO: test other containers? Useless when clear(Index) is never
225 // called, how much is it worth it?
226 Field_operators* operators_;
227 Entry_constructor* entryPool_;
228
229 template <class Column, class Entry_iterator, typename F1, typename F2, typename F3, typename F4>
230 friend void _generic_merge_entry_to_column(Column& targetColumn,
231 Entry_iterator& itSource,
232 typename Column::Column_support::iterator& itTarget,
233 F1&& process_target,
234 F2&& process_source,
235 F3&& update_target1,
236 F4&& update_target2,
237 bool& pivotIsZeroed);
238
239 void _delete_entry(Entry* entry);
240 void _delete_entry(typename Column_support::iterator& it);
241 Entry* _insert_entry(const Field_element& value, ID_index rowIndex, Column_support& column);
242 void _insert_entry(ID_index rowIndex, Column_support& column);
243 void _update_entry(const Field_element& value, ID_index rowIndex, Index position);
244 void _update_entry(ID_index rowIndex, Index position);
245 template <class Entry_range>
246 bool _add(const Entry_range& column);
247 template <class Entry_range>
248 bool _multiply_target_and_add(const Field_element& val, const Entry_range& column);
249 template <class Entry_range>
250 bool _multiply_source_and_add(const Entry_range& column, const Field_element& val);
251 template <class Entry_range, typename F1, typename F2, typename F3, typename F4>
252 bool _generic_add(const Entry_range& source,
253 F1&& process_target,
254 F2&& process_source,
255 F3&& update_target1,
256 F4&& update_target2);
257};
258
259template <class Master_matrix>
260inline Vector_column<Master_matrix>::Vector_column(Column_settings* colSettings)
261 : RA_opt(),
262 Dim_opt(),
263 Chain_opt(),
264 operators_(nullptr),
265 entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor))
266{
267 if (operators_ == nullptr && entryPool_ == nullptr)
268 return; // to allow default constructor which gives a dummy column
269 if constexpr (!Master_matrix::Option_list::is_z2) {
270 operators_ = &(colSettings->operators);
271 }
272}
273
274template <class Master_matrix>
275template <class Container>
276inline Vector_column<Master_matrix>::Vector_column(const Container& nonZeroRowIndices, Column_settings* colSettings)
277 : RA_opt(),
278 Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1),
279 Chain_opt(),
280 column_(nonZeroRowIndices.size(), nullptr),
281 operators_(nullptr),
282 entryPool_(&(colSettings->entryConstructor))
283{
284 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
285 "Constructor not available for chain columns, please specify the dimension of the chain.");
286
287 if constexpr (!Master_matrix::Option_list::is_z2) {
288 operators_ = &(colSettings->operators);
289 }
290
291 Index i = 0;
292 if constexpr (Master_matrix::Option_list::is_z2) {
293 for (ID_index id : nonZeroRowIndices) {
294 _update_entry(id, i++);
295 }
296 } else {
297 for (const auto& p : nonZeroRowIndices) {
298 _update_entry(operators_->get_value(p.second), p.first, i++);
299 }
300 }
301}
302
303template <class Master_matrix>
304template <class Container, class Row_container>
305inline Vector_column<Master_matrix>::Vector_column(Index columnIndex,
306 const Container& nonZeroRowIndices,
307 Row_container* rowContainer,
308 Column_settings* colSettings)
309 : RA_opt(columnIndex, rowContainer),
310 Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1),
311 Chain_opt([&] {
312 if constexpr (Master_matrix::Option_list::is_z2) {
313 return nonZeroRowIndices.begin() == nonZeroRowIndices.end()
314 ? Master_matrix::template get_null_value<ID_index>()
315 : *std::prev(nonZeroRowIndices.end());
316 } else {
317 return nonZeroRowIndices.begin() == nonZeroRowIndices.end()
318 ? Master_matrix::template get_null_value<ID_index>()
319 : std::prev(nonZeroRowIndices.end())->first;
320 }
321 }()),
322 column_(nonZeroRowIndices.size(), nullptr),
323 operators_(nullptr),
324 entryPool_(&(colSettings->entryConstructor))
325{
326 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
327 "Constructor not available for chain columns, please specify the dimension of the chain.");
328
329 if constexpr (!Master_matrix::Option_list::is_z2) {
330 operators_ = &(colSettings->operators);
331 }
332
333 Index i = 0;
334 if constexpr (Master_matrix::Option_list::is_z2) {
335 for (ID_index id : nonZeroRowIndices) {
336 _update_entry(id, i++);
337 }
338 } else {
339 for (const auto& p : nonZeroRowIndices) {
340 _update_entry(operators_->get_value(p.second), p.first, i++);
341 }
342 }
343}
344
345template <class Master_matrix>
346template <class Container>
347inline Vector_column<Master_matrix>::Vector_column(const Container& nonZeroRowIndices,
348 Dimension dimension,
349 Column_settings* colSettings)
350 : RA_opt(),
351 Dim_opt(dimension),
352 Chain_opt([&] {
353 if constexpr (Master_matrix::Option_list::is_z2) {
354 return nonZeroRowIndices.begin() == nonZeroRowIndices.end()
355 ? Master_matrix::template get_null_value<ID_index>()
356 : *std::prev(nonZeroRowIndices.end());
357 } else {
358 return nonZeroRowIndices.begin() == nonZeroRowIndices.end()
359 ? Master_matrix::template get_null_value<ID_index>()
360 : std::prev(nonZeroRowIndices.end())->first;
361 }
362 }()),
363 column_(nonZeroRowIndices.size(), nullptr),
364 operators_(nullptr),
365 entryPool_(&(colSettings->entryConstructor))
366{
367 if constexpr (!Master_matrix::Option_list::is_z2) {
368 operators_ = &(colSettings->operators);
369 }
370
371 Index i = 0;
372 if constexpr (Master_matrix::Option_list::is_z2) {
373 for (ID_index id : nonZeroRowIndices) {
374 _update_entry(id, i++);
375 }
376 } else {
377 for (const auto& p : nonZeroRowIndices) {
378 _update_entry(operators_->get_value(p.second), p.first, i++);
379 }
380 }
381}
382
383template <class Master_matrix>
384template <class Container, class Row_container>
385inline Vector_column<Master_matrix>::Vector_column(Index columnIndex,
386 const Container& nonZeroRowIndices,
387 Dimension dimension,
388 Row_container* rowContainer,
389 Column_settings* colSettings)
390 : RA_opt(columnIndex, rowContainer),
391 Dim_opt(dimension),
392 Chain_opt([&] {
393 if constexpr (Master_matrix::Option_list::is_z2) {
394 return nonZeroRowIndices.begin() == nonZeroRowIndices.end()
395 ? Master_matrix::template get_null_value<ID_index>()
396 : *std::prev(nonZeroRowIndices.end());
397 } else {
398 return nonZeroRowIndices.begin() == nonZeroRowIndices.end()
399 ? Master_matrix::template get_null_value<ID_index>()
400 : std::prev(nonZeroRowIndices.end())->first;
401 }
402 }()),
403 column_(nonZeroRowIndices.size(), nullptr),
404 operators_(nullptr),
405 entryPool_(&(colSettings->entryConstructor))
406{
407 if constexpr (!Master_matrix::Option_list::is_z2) {
408 operators_ = &(colSettings->operators);
409 }
410
411 Index i = 0;
412 if constexpr (Master_matrix::Option_list::is_z2) {
413 for (ID_index id : nonZeroRowIndices) {
414 _update_entry(id, i++);
415 }
416 } else {
417 for (const auto& p : nonZeroRowIndices) {
418 _update_entry(operators_->get_value(p.second), p.first, i++);
419 }
420 }
421}
422
423template <class Master_matrix>
424inline Vector_column<Master_matrix>::Vector_column(const Vector_column& column, Column_settings* colSettings)
425 : RA_opt(),
426 Dim_opt(static_cast<const Dim_opt&>(column)),
427 Chain_opt(static_cast<const Chain_opt&>(column)),
428 column_(column.column_.size(), nullptr),
429 erasedValues_(column.erasedValues_),
430 operators_(colSettings == nullptr ? column.operators_ : nullptr),
431 entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor))
432{
433 static_assert(!Master_matrix::Option_list::has_row_access,
434 "Simple copy constructor not available when row access option enabled. Please specify the new column "
435 "index and the row container.");
436
437 if constexpr (!Master_matrix::Option_list::is_z2) {
438 if (colSettings != nullptr) operators_ = &(colSettings->operators);
439 }
440
441 Index i = 0;
442 for (const Entry* entry : column.column_) {
443 if constexpr (Master_matrix::Option_list::is_z2) {
444 _update_entry(entry->get_row_index(), i++);
445 } else {
446 _update_entry(entry->get_element(), entry->get_row_index(), i++);
447 }
448 }
449}
450
451template <class Master_matrix>
452template <class Row_container>
453inline Vector_column<Master_matrix>::Vector_column(const Vector_column& column,
454 Index columnIndex,
455 Row_container* rowContainer,
456 Column_settings* colSettings)
457 : RA_opt(columnIndex, rowContainer),
458 Dim_opt(static_cast<const Dim_opt&>(column)),
459 Chain_opt(static_cast<const Chain_opt&>(column)),
460 column_(column.column_.size(), nullptr),
461 erasedValues_(column.erasedValues_),
462 operators_(colSettings == nullptr ? column.operators_ : nullptr),
463 entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor))
464{
465 if constexpr (!Master_matrix::Option_list::is_z2) {
466 if (colSettings != nullptr) operators_ = &(colSettings->operators);
467 }
468
469 Index i = 0;
470 for (const Entry* entry : column.column_) {
471 if constexpr (Master_matrix::Option_list::is_z2) {
472 _update_entry(entry->get_row_index(), i++);
473 } else {
474 _update_entry(entry->get_element(), entry->get_row_index(), i++);
475 }
476 }
477}
478
479template <class Master_matrix>
480inline Vector_column<Master_matrix>::Vector_column(Vector_column&& column) noexcept
481 : RA_opt(std::move(static_cast<RA_opt&>(column))),
482 Dim_opt(std::move(static_cast<Dim_opt&>(column))),
483 Chain_opt(std::move(static_cast<Chain_opt&>(column))),
484 column_(std::move(column.column_)),
485 erasedValues_(std::move(column.erasedValues_)),
486 operators_(std::exchange(column.operators_, nullptr)),
487 entryPool_(std::exchange(column.entryPool_, nullptr))
488{}
489
490template <class Master_matrix>
491inline Vector_column<Master_matrix>::~Vector_column()
492{
493 for (auto* entry : column_) {
494 _delete_entry(entry);
495 }
496}
497
498template <class Master_matrix>
499inline std::vector<typename Vector_column<Master_matrix>::Field_element> Vector_column<Master_matrix>::get_content(
500 int columnLength) const
501{
502 if (columnLength < 0 && column_.size() > 0)
503 columnLength = column_.back()->get_row_index() + 1;
504 else if (columnLength < 0)
505 return std::vector<Field_element>();
506
507 std::vector<Field_element> container(columnLength, 0);
508 for (auto it = column_.begin(); it != column_.end() && (*it)->get_row_index() < static_cast<ID_index>(columnLength);
509 ++it) {
510 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
511 if (erasedValues_.find((*it)->get_row_index()) != erasedValues_.end()) continue;
512 }
513 if constexpr (Master_matrix::Option_list::is_z2) {
514 container[(*it)->get_row_index()] = 1;
515 } else {
516 container[(*it)->get_row_index()] = (*it)->get_element();
517 }
518 }
519 return container;
520}
521
522template <class Master_matrix>
523inline bool Vector_column<Master_matrix>::is_non_zero(ID_index rowIndex) const
524{
525 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type)
526 if (erasedValues_.find(rowIndex) != erasedValues_.end()) return false;
527
528 Entry entry(rowIndex);
529 return std::binary_search(column_.begin(), column_.end(), &entry, [](const Entry* a, const Entry* b) {
530 return a->get_row_index() < b->get_row_index();
531 });
532}
533
534template <class Master_matrix>
535inline bool Vector_column<Master_matrix>::is_empty() const
536{
537 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
538 return column_.size() == erasedValues_.size(); // assumes that erasedValues is always a subset of column_, which is
539 // wrong if someone cleared an non existing value...
540 } else {
541 return column_.empty();
542 }
543}
544
545template <class Master_matrix>
546inline std::size_t Vector_column<Master_matrix>::size() const
547{
548 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
549 return column_.size() - erasedValues_.size(); // assumes that erasedValues is always a subset of column_, which is
550 // wrong if someone cleared an non existing value...
551 } else {
552 return column_.size();
553 }
554}
555
556template <class Master_matrix>
557template <class Row_index_map>
558inline void Vector_column<Master_matrix>::reorder(const Row_index_map& valueMap, [[maybe_unused]] Index columnIndex)
559{
560 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
561 "Method not available for chain columns.");
562
563 if (erasedValues_.empty()) { // to avoid useless push_backs.
564 for (Entry* entry : column_) {
565 if constexpr (Master_matrix::Option_list::has_row_access) {
566 RA_opt::unlink(entry);
567 if (columnIndex != Master_matrix::template get_null_value<Index>()) entry->set_column_index(columnIndex);
568 }
569 entry->set_row_index(valueMap.at(entry->get_row_index()));
570 if constexpr (Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access)
571 RA_opt::insert_entry(entry->get_row_index(), entry);
572 }
573
574 // all entries have to be deleted first, to avoid problem with insertion when row is a set
575 if constexpr (!Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access) {
576 for (Entry* entry : column_) {
577 RA_opt::insert_entry(entry->get_row_index(), entry);
578 }
579 }
580
581 std::sort(column_.begin(), column_.end(), [](const Entry* c1, const Entry* c2) { return *c1 < *c2; });
582 } else {
583 Column_support newColumn;
584 for (Entry* entry : column_) {
585 if (erasedValues_.find(entry->get_row_index()) == erasedValues_.end()) {
586 if constexpr (Master_matrix::Option_list::has_row_access) {
587 RA_opt::unlink(entry);
588 if (columnIndex != Master_matrix::template get_null_value<Index>()) entry->set_column_index(columnIndex);
589 }
590 entry->set_row_index(valueMap.at(entry->get_row_index()));
591 newColumn.push_back(entry);
592 if constexpr (Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access)
593 RA_opt::insert_entry(entry->get_row_index(), entry);
594 } else {
595 _delete_entry(entry);
596 }
597 }
598 // all entries have to be deleted first, to avoid problem with insertion when row is a set
599 if constexpr (!Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access) {
600 for (Entry* entry : column_) {
601 RA_opt::insert_entry(entry->get_row_index(), entry);
602 }
603 }
604 std::sort(newColumn.begin(), newColumn.end(), [](const Entry* c1, const Entry* c2) { return *c1 < *c2; });
605 erasedValues_.clear();
606 column_.swap(newColumn);
607 }
608}
609
610template <class Master_matrix>
611inline void Vector_column<Master_matrix>::clear()
612{
613 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
614 "Method not available for chain columns as a base element should not be empty.");
615
616 for (auto* entry : column_) {
617 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(entry);
618 entryPool_->destroy(entry);
619 }
620
621 column_.clear();
622 erasedValues_.clear();
623}
624
625template <class Master_matrix>
626inline void Vector_column<Master_matrix>::clear(ID_index rowIndex)
627{
628 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
629 "Method not available for chain columns.");
630
631 erasedValues_.insert(rowIndex);
632}
633
634template <class Master_matrix>
635inline typename Vector_column<Master_matrix>::ID_index Vector_column<Master_matrix>::get_pivot()
636{
637 static_assert(Master_matrix::isNonBasic,
638 "Method not available for base columns."); // could technically be, but is the notion useful then?
639
640 if constexpr (Master_matrix::Option_list::is_of_boundary_type) {
641 if (column_.empty()) return Master_matrix::template get_null_value<ID_index>();
642 if (erasedValues_.empty()) return column_.back()->get_row_index();
643
644 auto it = erasedValues_.find(column_.back()->get_row_index());
645 while (!column_.empty() && it != erasedValues_.end()) {
646 erasedValues_.erase(it);
647 _delete_entry(column_.back());
648 column_.pop_back();
649 if (!column_.empty()) it = erasedValues_.find(column_.back()->get_row_index());
650 }
651
652 if (column_.empty()) return Master_matrix::template get_null_value<ID_index>();
653 return column_.back()->get_row_index();
654 } else {
655 return Chain_opt::get_pivot();
656 }
657}
658
659template <class Master_matrix>
660inline typename Vector_column<Master_matrix>::Field_element Vector_column<Master_matrix>::get_pivot_value()
661{
662 static_assert(Master_matrix::isNonBasic,
663 "Method not available for base columns."); // could technically be, but is the notion useful then?
664
665 if constexpr (Master_matrix::Option_list::is_z2) {
666 return 1;
667 } else {
668 if constexpr (Master_matrix::Option_list::is_of_boundary_type) {
669 if (column_.empty()) return 0;
670 if (erasedValues_.empty()) return column_.back()->get_element();
671
672 auto it = erasedValues_.find(column_.back()->get_row_index());
673 while (!column_.empty() && it != erasedValues_.end()) {
674 erasedValues_.erase(it);
675 _delete_entry(column_.back());
676 column_.pop_back();
677 if (!column_.empty()) it = erasedValues_.find(column_.back()->get_row_index());
678 }
679
680 if (column_.empty()) return 0;
681 return column_.back()->get_element();
682 } else {
683 if (Chain_opt::get_pivot() == Master_matrix::template get_null_value<ID_index>()) return Field_element();
684 for (const Entry* entry : column_) {
685 if (entry->get_row_index() == Chain_opt::get_pivot()) return entry->get_element();
686 }
687 return Field_element(); // should never happen if chain column is used properly
688 }
689 }
690}
691
692template <class Master_matrix>
693inline typename Vector_column<Master_matrix>::iterator Vector_column<Master_matrix>::begin() noexcept
694{
695 return column_.begin();
696}
697
698template <class Master_matrix>
699inline typename Vector_column<Master_matrix>::const_iterator Vector_column<Master_matrix>::begin() const noexcept
700{
701 return column_.begin();
702}
703
704template <class Master_matrix>
705inline typename Vector_column<Master_matrix>::iterator Vector_column<Master_matrix>::end() noexcept
706{
707 return column_.end();
708}
709
710template <class Master_matrix>
711inline typename Vector_column<Master_matrix>::const_iterator Vector_column<Master_matrix>::end() const noexcept
712{
713 return column_.end();
714}
715
716template <class Master_matrix>
717inline typename Vector_column<Master_matrix>::reverse_iterator Vector_column<Master_matrix>::rbegin() noexcept
718{
719 return column_.rbegin();
720}
721
722template <class Master_matrix>
723inline typename Vector_column<Master_matrix>::const_reverse_iterator Vector_column<Master_matrix>::rbegin()
724 const noexcept
725{
726 return column_.rbegin();
727}
728
729template <class Master_matrix>
730inline typename Vector_column<Master_matrix>::reverse_iterator Vector_column<Master_matrix>::rend() noexcept
731{
732 return column_.rend();
733}
734
735template <class Master_matrix>
736inline typename Vector_column<Master_matrix>::const_reverse_iterator Vector_column<Master_matrix>::rend() const noexcept
737{
738 return column_.rend();
739}
740
741template <class Master_matrix>
742template <class Entry_range>
743inline Vector_column<Master_matrix>& Vector_column<Master_matrix>::operator+=(const Entry_range& column)
744{
745 static_assert((!Master_matrix::isNonBasic || std::is_same_v<Entry_range, Vector_column>),
746 "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
747 "base element."); // could be removed, if we give the responsibility to the user.
748 static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
749 "For chain columns, the given column cannot be constant.");
750
751 _add(column);
752
753 return *this;
754}
755
756template <class Master_matrix>
757inline Vector_column<Master_matrix>& Vector_column<Master_matrix>::operator+=(Vector_column& column)
758{
759 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
760 // assumes that the addition never zeros out this column.
761 if (_add(column)) {
762 Chain_opt::swap_pivots(column);
763 Dim_opt::swap_dimension(column);
764 }
765 } else {
766 _add(column);
767 }
768
769 return *this;
770}
771
772template <class Master_matrix>
773inline Vector_column<Master_matrix>& Vector_column<Master_matrix>::operator*=(unsigned int v)
774{
775 if constexpr (Master_matrix::Option_list::is_z2) {
776 if (v % 2 == 0) {
777 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
778 throw std::invalid_argument("A chain column should not be multiplied by 0.");
779 } else {
780 clear();
781 }
782 }
783 } else {
784 Field_element val = operators_->get_value(v);
785
786 if (val == Field_operators::get_additive_identity()) {
787 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
788 throw std::invalid_argument("A chain column should not be multiplied by 0.");
789 } else {
790 clear();
791 }
792 return *this;
793 }
794
795 if (val == Field_operators::get_multiplicative_identity()) return *this;
796
797 for (Entry* entry : column_) {
798 operators_->multiply_inplace(entry->get_element(), val);
799 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entry);
800 }
801 }
802
803 return *this;
804}
805
806template <class Master_matrix>
807template <class Entry_range>
808inline Vector_column<Master_matrix>& Vector_column<Master_matrix>::multiply_target_and_add(const Field_element& val,
809 const Entry_range& column)
810{
811 static_assert((!Master_matrix::isNonBasic || std::is_same_v<Entry_range, Vector_column>),
812 "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
813 "base element."); // could be removed, if we give the responsibility to the user.
814 static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
815 "For chain columns, the given column cannot be constant.");
816
817 if constexpr (Master_matrix::Option_list::is_z2) {
818 if (val) {
819 _add(column);
820 } else {
821 clear();
822 _add(column);
823 }
824 } else {
825 _multiply_target_and_add(val, column);
826 }
827
828 return *this;
829}
830
831template <class Master_matrix>
832inline Vector_column<Master_matrix>& Vector_column<Master_matrix>::multiply_target_and_add(const Field_element& val,
833 Vector_column& column)
834{
835 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
836 // assumes that the addition never zeros out this column.
837 if constexpr (Master_matrix::Option_list::is_z2) {
838 if (val) {
839 if (_add(column)) {
840 Chain_opt::swap_pivots(column);
841 Dim_opt::swap_dimension(column);
842 }
843 } else {
844 throw std::invalid_argument("A chain column should not be multiplied by 0.");
845 }
846 } else {
847 if (_multiply_target_and_add(val, column)) {
848 Chain_opt::swap_pivots(column);
849 Dim_opt::swap_dimension(column);
850 }
851 }
852 } else {
853 if constexpr (Master_matrix::Option_list::is_z2) {
854 if (val) {
855 _add(column);
856 } else {
857 clear();
858 _add(column);
859 }
860 } else {
861 _multiply_target_and_add(val, column);
862 }
863 }
864
865 return *this;
866}
867
868template <class Master_matrix>
869template <class Entry_range>
870inline Vector_column<Master_matrix>& Vector_column<Master_matrix>::multiply_source_and_add(const Entry_range& column,
871 const Field_element& val)
872{
873 static_assert((!Master_matrix::isNonBasic || std::is_same_v<Entry_range, Vector_column>),
874 "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
875 "base element."); // could be removed, if we give the responsibility to the user.
876 static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
877 "For chain columns, the given column cannot be constant.");
878
879 if constexpr (Master_matrix::Option_list::is_z2) {
880 if (val) {
881 _add(column);
882 }
883 } else {
884 _multiply_source_and_add(column, val);
885 }
886
887 return *this;
888}
889
890template <class Master_matrix>
891inline Vector_column<Master_matrix>& Vector_column<Master_matrix>::multiply_source_and_add(Vector_column& column,
892 const Field_element& val)
893{
894 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
895 // assumes that the addition never zeros out this column.
896 if constexpr (Master_matrix::Option_list::is_z2) {
897 if (val) {
898 if (_add(column)) {
899 Chain_opt::swap_pivots(column);
900 Dim_opt::swap_dimension(column);
901 }
902 }
903 } else {
904 if (_multiply_source_and_add(column, val)) {
905 Chain_opt::swap_pivots(column);
906 Dim_opt::swap_dimension(column);
907 }
908 }
909 } else {
910 if constexpr (Master_matrix::Option_list::is_z2) {
911 if (val) {
912 _add(column);
913 }
914 } else {
915 _multiply_source_and_add(column, val);
916 }
917 }
918
919 return *this;
920}
921
922template <class Master_matrix>
923inline void Vector_column<Master_matrix>::push_back(const Entry& entry)
924{
925 static_assert(Master_matrix::Option_list::is_of_boundary_type, "`push_back` is not available for Chain matrices.");
926
927 GUDHI_CHECK(entry.get_row_index() > get_pivot(), "The new row index has to be higher than the current pivot.");
928
929 if constexpr (Master_matrix::Option_list::is_z2) {
930 _insert_entry(entry.get_row_index(), column_);
931 } else {
932 _insert_entry(entry.get_element(), entry.get_row_index(), column_);
933 }
934}
935
936template <class Master_matrix>
937inline Vector_column<Master_matrix>& Vector_column<Master_matrix>::operator=(const Vector_column& other)
938{
939 static_assert(!Master_matrix::Option_list::has_row_access, "= assignment not enabled with row access option.");
940
941 Dim_opt::operator=(other);
942 Chain_opt::operator=(other);
943
944 auto tmpPool = entryPool_;
945 entryPool_ = other.entryPool_;
946
947 while (column_.size() > other.column_.size()) {
948 if (column_.back() != nullptr) {
949 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(column_.back());
950 tmpPool->destroy(column_.back());
951 }
952 column_.pop_back();
953 }
954
955 column_.resize(other.column_.size(), nullptr);
956 Index i = 0;
957 for (const Entry* entry : other.column_) {
958 if (column_[i] != nullptr) {
959 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(column_[i]);
960 tmpPool->destroy(column_[i]);
961 }
962 if constexpr (Master_matrix::Option_list::is_z2) {
963 _update_entry(entry->get_row_index(), i++);
964 } else {
965 _update_entry(entry->get_element(), entry->get_row_index(), i++);
966 }
967 }
968 erasedValues_ = other.erasedValues_;
969 operators_ = other.operators_;
970
971 return *this;
972}
973
974template <class Master_matrix>
975inline std::size_t Vector_column<Master_matrix>::compute_hash_value()
976{
977 std::size_t seed = 0;
978 for (Entry* entry : column_) {
979 if (erasedValues_.find(entry->get_row_index()) == erasedValues_.end()) {
980 seed ^= std::hash<unsigned int>()(entry->get_row_index() * static_cast<unsigned int>(entry->get_element())) +
981 0x9e3779b9 + (seed << 6) + (seed >> 2);
982 }
983 }
984 return seed;
985}
986
987template <class Master_matrix>
988inline void Vector_column<Master_matrix>::_delete_entry(Entry* entry)
989{
990 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(entry);
991 entryPool_->destroy(entry);
992}
993
994template <class Master_matrix>
995inline void Vector_column<Master_matrix>::_delete_entry(typename Column_support::iterator& it)
996{
997 _delete_entry(*it);
998 ++it;
999}
1000
1001template <class Master_matrix>
1002inline typename Vector_column<Master_matrix>::Entry*
1003Vector_column<Master_matrix>::_insert_entry(const Field_element& value, ID_index rowIndex, Column_support& column)
1004{
1005 if constexpr (Master_matrix::Option_list::has_row_access) {
1006 Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex);
1007 newEntry->set_element(value);
1008 column.push_back(newEntry);
1009 RA_opt::insert_entry(rowIndex, newEntry);
1010 return newEntry;
1011 } else {
1012 Entry* newEntry = entryPool_->construct(rowIndex);
1013 newEntry->set_element(value);
1014 column.push_back(newEntry);
1015 return newEntry;
1016 }
1017}
1018
1019template <class Master_matrix>
1020inline void Vector_column<Master_matrix>::_insert_entry(ID_index rowIndex, Column_support& column)
1021{
1022 if constexpr (Master_matrix::Option_list::has_row_access) {
1023 Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex);
1024 column.push_back(newEntry);
1025 RA_opt::insert_entry(rowIndex, newEntry);
1026 } else {
1027 Entry* newEntry = entryPool_->construct(rowIndex);
1028 column.push_back(newEntry);
1029 }
1030}
1031
1032template <class Master_matrix>
1033inline void Vector_column<Master_matrix>::_update_entry(const Field_element& value, ID_index rowIndex, Index position)
1034{
1035 if constexpr (Master_matrix::Option_list::has_row_access) {
1036 Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex);
1037 newEntry->set_element(value);
1038 column_[position] = newEntry;
1039 RA_opt::insert_entry(rowIndex, newEntry);
1040 } else {
1041 column_[position] = entryPool_->construct(rowIndex);
1042 column_[position]->set_element(value);
1043 }
1044}
1045
1046template <class Master_matrix>
1047inline void Vector_column<Master_matrix>::_update_entry(ID_index rowIndex, Index position)
1048{
1049 if constexpr (Master_matrix::Option_list::has_row_access) {
1050 Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex);
1051 column_[position] = newEntry;
1052 RA_opt::insert_entry(rowIndex, newEntry);
1053 } else {
1054 column_[position] = entryPool_->construct(rowIndex);
1055 }
1056}
1057
1058template <class Master_matrix>
1059template <class Entry_range>
1060inline bool Vector_column<Master_matrix>::_add(const Entry_range& column)
1061{
1062 if (column.begin() == column.end()) return false;
1063 if (column_.empty()) { // chain should never enter here.
1064 column_.resize(column.size());
1065 Index i = 0;
1066 for (const Entry& entry : column) {
1067 if constexpr (Master_matrix::Option_list::is_z2) {
1068 _update_entry(entry.get_row_index(), i++);
1069 } else {
1070 _update_entry(entry.get_element(), entry.get_row_index(), i++);
1071 }
1072 }
1073 return true;
1074 }
1075
1076 Column_support newColumn;
1077 newColumn.reserve(column_.size() + column.size()); // safe upper bound
1078
1079 auto pivotIsZeroed = _generic_add(
1080 column,
1081 [&](Entry* entryTarget) { newColumn.push_back(entryTarget); },
1082 [&](typename Entry_range::const_iterator& itSource,
1083 [[maybe_unused]] const typename Column_support::iterator& itTarget) {
1084 if constexpr (Master_matrix::Option_list::is_z2) {
1085 _insert_entry(itSource->get_row_index(), newColumn);
1086 } else {
1087 _insert_entry(itSource->get_element(), itSource->get_row_index(), newColumn);
1088 }
1089 },
1090 [&](Field_element& targetElement, typename Entry_range::const_iterator& itSource) {
1091 if constexpr (!Master_matrix::Option_list::is_z2)
1092 operators_->add_inplace(targetElement, itSource->get_element());
1093 },
1094 [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }
1095 );
1096
1097 column_.swap(newColumn);
1098
1099 return pivotIsZeroed;
1100}
1101
1102template <class Master_matrix>
1103template <class Entry_range>
1104inline bool Vector_column<Master_matrix>::_multiply_target_and_add(const Field_element& val, const Entry_range& column)
1105{
1106 if (val == 0u) {
1107 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
1108 throw std::invalid_argument("A chain column should not be multiplied by 0.");
1109 // this would not only mess up the base, but also the pivots stored.
1110 } else {
1111 clear();
1112 }
1113 }
1114 if (column_.empty()) { // chain should never enter here.
1115 column_.resize(column.size());
1116 Index i = 0;
1117 for (const Entry& entry : column) {
1118 if constexpr (Master_matrix::Option_list::is_z2) {
1119 _update_entry(entry.get_row_index(), i++);
1120 } else {
1121 _update_entry(entry.get_element(), entry.get_row_index(), i++);
1122 }
1123 }
1124 if constexpr (std::is_same_v<Entry_range, Vector_column<Master_matrix> >) erasedValues_ = column.erasedValues_;
1125 return true;
1126 }
1127
1128 Column_support newColumn;
1129 newColumn.reserve(column_.size() + column.size()); // safe upper bound
1130
1131 auto pivotIsZeroed = _generic_add(
1132 column,
1133 [&](Entry* entryTarget) {
1134 operators_->multiply_inplace(entryTarget->get_element(), val);
1135 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entryTarget);
1136 newColumn.push_back(entryTarget);
1137 },
1138 [&](typename Entry_range::const_iterator& itSource, const typename Column_support::iterator& itTarget) {
1139 _insert_entry(itSource->get_element(), itSource->get_row_index(), newColumn);
1140 },
1141 [&](Field_element& targetElement, typename Entry_range::const_iterator& itSource) {
1142 operators_->multiply_and_add_inplace_front(targetElement, val, itSource->get_element());
1143 },
1144 [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }
1145 );
1146
1147 column_.swap(newColumn);
1148
1149 return pivotIsZeroed;
1150}
1151
1152template <class Master_matrix>
1153template <class Entry_range>
1154inline bool Vector_column<Master_matrix>::_multiply_source_and_add(const Entry_range& column, const Field_element& val)
1155{
1156 if (val == 0u || column.begin() == column.end()) {
1157 return false;
1158 }
1159
1160 Column_support newColumn;
1161 newColumn.reserve(column_.size() + column.size()); // safe upper bound
1162
1163 auto pivotIsZeroed = _generic_add(
1164 column,
1165 [&](Entry* entryTarget) { newColumn.push_back(entryTarget); },
1166 [&](typename Entry_range::const_iterator& itSource, const typename Column_support::iterator& itTarget) {
1167 Entry* newEntry = _insert_entry(itSource->get_element(), itSource->get_row_index(), newColumn);
1168 operators_->multiply_inplace(newEntry->get_element(), val);
1169 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*newEntry);
1170 },
1171 [&](Field_element& targetElement, typename Entry_range::const_iterator& itSource) {
1172 operators_->multiply_and_add_inplace_back(itSource->get_element(), val, targetElement);
1173 },
1174 [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }
1175 );
1176
1177 column_.swap(newColumn);
1178
1179 return pivotIsZeroed;
1180}
1181
1182template <class Master_matrix>
1183template <class Entry_range, typename F1, typename F2, typename F3, typename F4>
1184inline bool Vector_column<Master_matrix>::_generic_add(const Entry_range& column,
1185 F1&& process_target,
1186 F2&& process_source,
1187 F3&& update_target1,
1188 F4&& update_target2)
1189{
1190 auto updateTargetIterator = [&](typename Column_support::iterator& itTarget) {
1191 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
1192 while (itTarget != column_.end() && erasedValues_.find((*itTarget)->get_row_index()) != erasedValues_.end()) {
1193 _delete_entry(*itTarget);
1194 ++itTarget;
1195 }
1196 }
1197 };
1198 auto updateSourceIterator = [&](typename Entry_range::const_iterator& itSource) {
1199 if constexpr (std::is_same_v<Entry_range, Vector_column<Master_matrix> > &&
1200 (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type)) {
1201 while (itSource != column.end() &&
1202 column.erasedValues_.find(itSource->get_row_index()) != column.erasedValues_.end())
1203 ++itSource;
1204 }
1205 };
1206
1207 bool pivotIsZeroed = false;
1208
1209 auto itTarget = column_.begin();
1210 auto itSource = column.begin();
1211 while (itTarget != column_.end() && itSource != column.end()) {
1212 updateTargetIterator(itTarget);
1213 updateSourceIterator(itSource);
1214 if (itTarget == column_.end() || itSource == column.end()) break;
1215
1216 _generic_merge_entry_to_column(*this, itSource, itTarget,
1217 process_target, process_source, update_target1, update_target2,
1218 pivotIsZeroed);
1219 }
1220
1221 while (itSource != column.end()) {
1222 updateSourceIterator(itSource);
1223 if (itSource == column.end()) break;
1224
1225 process_source(itSource, column_.end());
1226 ++itSource;
1227 }
1228
1229 while (itTarget != column_.end()) {
1230 updateTargetIterator(itTarget);
1231 if (itTarget == column_.end()) break;
1232
1233 process_target(*itTarget);
1234 ++itTarget;
1235 }
1236
1237 erasedValues_.clear();
1238
1239 return pivotIsZeroed;
1240}
1241
1242} // namespace persistence_matrix
1243} // namespace Gudhi
1244
1253template <class Master_matrix>
1254struct std::hash<Gudhi::persistence_matrix::Vector_column<Master_matrix> > {
1255 std::size_t operator()(const Gudhi::persistence_matrix::Vector_column<Master_matrix>& column) const {
1256 return column.compute_hash_value();
1257 }
1258};
1259
1260#endif // PM_VECTOR_COLUMN_H
Column class following the PersistenceMatrixColumn concept.
Definition: vector_column.h:52
Contains helper methods for column addition and column hasher.
Chain_column_extra_properties Chain_column_option
If PersistenceMatrixOptions::is_of_boundary_type is false, and, PersistenceMatrixOptions::has_column_...
Definition: PersistenceMatrixColumn.h:45
Row_access Row_access_option
If PersistenceMatrixOptions::has_row_access is true, then Row_access. Otherwise Dummy_row_access....
Definition: PersistenceMatrixColumn.h:28
Column_dimension_holder Column_dimension_option
If PersistenceMatrixOptions::has_column_pairings or PersistenceMatrixOptions::has_vine_update or Pers...
Definition: PersistenceMatrixColumn.h:36
Gudhi namespace.
Definition: SimplicialComplexForAlpha.h:14
STL namespace.