Loading...
Searching...
No Matches
column_utilities.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) 2024 Inria
6 *
7 * Modification(s):
8 * - YYYY/MM Author: Description of the modification
9 */
10
16
17#ifndef PM_COLUMN_UTILITIES_H
18#define PM_COLUMN_UTILITIES_H
19
20#include <cstddef>
21#include <stdexcept>
22
24
25namespace Gudhi {
26namespace persistence_matrix {
27
28template <class Entry, typename Entry_iterator>
29Entry* _get_entry(const Entry_iterator& itTarget)
30{
31 if constexpr (Entry::Master::Option_list::column_type == Column_types::INTRUSIVE_LIST ||
32 Entry::Master::Option_list::column_type == Column_types::INTRUSIVE_SET) {
33 return &*itTarget;
34 } else {
35 return *itTarget;
36 }
37}
38
39// works only for ordered columns
40template <class Column, class Entry_iterator, typename F1, typename F2, typename F3, typename F4>
41void _generic_merge_entry_to_column(Column& targetColumn,
42 Entry_iterator& itSource,
43 typename Column::Column_support::iterator& itTarget,
44 F1&& process_target,
45 F2&& process_source,
46 [[maybe_unused]] F3&& update_target1,
47 [[maybe_unused]] F4&& update_target2,
48 bool& pivotIsZeroed)
49{
50 typename Column::Entry* targetEntry = _get_entry<typename Column::Entry>(itTarget);
51
52 if (targetEntry->get_row_index() < itSource->get_row_index()) {
53 std::forward<F1>(process_target)(targetEntry);
54 ++itTarget;
55 } else if (targetEntry->get_row_index() > itSource->get_row_index()) {
56 std::forward<F2>(process_source)(itSource, itTarget);
57 ++itSource;
58 } else {
59 if constexpr (Column::Master::Option_list::is_z2) {
60 //_multiply_*_and_add never enters here so not treated
61 if constexpr (Column::Master::isNonBasic && !Column::Master::Option_list::is_of_boundary_type) {
62 if (targetEntry->get_row_index() == targetColumn.get_pivot()) pivotIsZeroed = true;
63 }
64 targetColumn._delete_entry(itTarget);
65 } else {
66 std::forward<F3>(update_target1)(targetEntry->get_element(), itSource);
67 if (targetEntry->get_element() == Column::Field_operators::get_additive_identity()) {
68 if constexpr (Column::Master::isNonBasic && !Column::Master::Option_list::is_of_boundary_type) {
69 if (targetEntry->get_row_index() == targetColumn.get_pivot()) pivotIsZeroed = true;
70 }
71 targetColumn._delete_entry(itTarget);
72 } else {
73 std::forward<F4>(update_target2)(targetEntry);
74 if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_entry(*targetEntry);
75 ++itTarget;
76 }
77 }
78 ++itSource;
79 }
80}
81
82// works only for ordered columns
83template <class Column, class Entry_range, typename F1, typename F2, typename F3, typename F4, typename F5>
84bool _generic_add_to_column(const Entry_range& source,
85 Column& targetColumn,
86 F1&& process_target,
87 F2&& process_source,
88 F3&& update_target1,
89 F4&& update_target2,
90 F5&& finish_target)
91{
92 bool pivotIsZeroed = false;
93
94 auto& target = targetColumn.column_;
95 auto itTarget = target.begin();
96 auto itSource = source.begin();
97 while (itTarget != target.end() && itSource != source.end()) {
98 _generic_merge_entry_to_column(targetColumn,
99 itSource,
100 itTarget,
101 std::forward<F1>(process_target),
102 std::forward<F2>(process_source),
103 std::forward<F3>(update_target1),
104 std::forward<F4>(update_target2),
105 pivotIsZeroed);
106 }
107
108 std::forward<F5>(finish_target)(itTarget);
109
110 while (itSource != source.end()) {
111 std::forward<F2>(process_source)(itSource, target.end());
112 ++itSource;
113 }
114
115 return pivotIsZeroed;
116}
117
118template <class Column, class Entry_range>
119bool _add_to_column(const Entry_range& source, Column& targetColumn)
120{
121 return _generic_add_to_column(
122 source,
123 targetColumn,
124 [&]([[maybe_unused]] typename Column::Entry* entryTarget) {},
125 [&](typename Entry_range::const_iterator& itSource, const typename Column::Column_support::iterator& itTarget) {
126 targetColumn._insert_entry(itTarget, itSource->get_row_index(), itSource->get_element());
127 },
128 [&](typename Column::Field_element& targetElement, typename Entry_range::const_iterator& itSource) {
129 if constexpr (!Column::Master::Option_list::is_z2)
130 targetColumn.operators_->add_inplace(targetElement, itSource->get_element());
131 },
132 [&]([[maybe_unused]] typename Column::Entry* entryTarget) {},
133 [&]([[maybe_unused]] typename Column::Column_support::iterator& itTarget) {});
134}
135
136template <class Column, class Entry_range>
137bool _multiply_target_and_add_to_column(const typename Column::Field_element& val,
138 const Entry_range& source,
139 Column& targetColumn)
140{
141 if (val == Column::Field_operators::get_additive_identity()) {
142 if constexpr (Column::Master::isNonBasic && !Column::Master::Option_list::is_of_boundary_type) {
143 // this would not only mess up the base, but also the pivots stored.
144 throw std::invalid_argument("A chain column should not be multiplied by 0.");
145 } else {
146 targetColumn.clear();
147 return _add_to_column(source, targetColumn);
148 }
149 }
150
151 if (val == Column::Field_operators::get_multiplicative_identity()) {
152 return _add_to_column(source, targetColumn);
153 }
154
155 if constexpr (!Column::Master::Option_list::is_z2) {
156 return _generic_add_to_column(
157 source,
158 targetColumn,
159 [&](typename Column::Entry* entryTarget) {
160 targetColumn.operators_->multiply_inplace(entryTarget->get_element(), val);
161 // targetColumn.RA_opt::update_entry(*itTarget) produces an internal compiler error
162 // even though it works in _generic_add_to_column... Probably because of the lambda.
163 if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_entry(*entryTarget);
164 },
165 [&](typename Entry_range::const_iterator& itSource, const typename Column::Column_support::iterator& itTarget) {
166 targetColumn._insert_entry(itTarget, itSource->get_row_index(), itSource->get_element());
167 },
168 [&](typename Column::Field_element& targetElement, typename Entry_range::const_iterator& itSource) {
169 targetColumn.operators_->multiply_and_add_inplace_front(targetElement, val, itSource->get_element());
170 },
171 [&]([[maybe_unused]] typename Column::Entry* entryTarget) {},
172 [&](typename Column::Column_support::iterator& itTarget) {
173 while (itTarget != targetColumn.column_.end()) {
174 typename Column::Entry* targetEntry = _get_entry<typename Column::Entry>(itTarget);
175 targetColumn.operators_->multiply_inplace(targetEntry->get_element(), val);
176 if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_entry(*targetEntry);
177 itTarget++;
178 }
179 });
180 } else {
181 return false; // we should never arrive here, just to suppress the warning
182 }
183}
184
185template <class Column, class Entry_range>
186bool _multiply_source_and_add_to_column(const typename Column::Field_element& val,
187 const Entry_range& source,
188 Column& targetColumn)
189{
190 if (val == Column::Field_operators::get_additive_identity()) {
191 return false;
192 }
193
194 if (val == Column::Field_operators::get_multiplicative_identity()) {
195 return _add_to_column(source, targetColumn);
196 }
197
198 if constexpr (!Column::Master::Option_list::is_z2) {
199 return _generic_add_to_column(
200 source,
201 targetColumn,
202 []([[maybe_unused]] typename Column::Entry* entryTarget) {},
203 [&](typename Entry_range::const_iterator& itSource, const typename Column::Column_support::iterator& itTarget) {
204 typename Column::Entry* entry =
205 targetColumn._insert_entry(itTarget, itSource->get_row_index(), itSource->get_element());
206 targetColumn.operators_->multiply_inplace(entry->get_element(), val);
207 if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_entry(*entry);
208 },
209 [&](typename Column::Field_element& targetElement, typename Entry_range::const_iterator& itSource) {
210 targetColumn.operators_->multiply_and_add_inplace_back(itSource->get_element(), val, targetElement);
211 },
212 [&]([[maybe_unused]] typename Column::Entry* entryTarget) {},
213 []([[maybe_unused]] typename Column::Column_support::iterator& itTarget) {});
214 } else {
215 return false; // we should never arrive here, just to suppress the warning
216 }
217}
218
219// column has to be ordered (ie. not suited for unordered_map and heap) and contain the exact values
220// (ie. not suited for vector and heap). A same column but ordered differently will have another hash value.
221template <class Column>
222std::size_t hash_column(const Column& column)
223{
224 std::size_t seed = 0;
225 for (auto& entry : column) {
226 seed ^= std::hash<unsigned int>()(entry.get_row_index() * static_cast<unsigned int>(entry.get_element())) +
227 0x9e3779b9 + (seed << 6) + (seed >> 2);
228 }
229 return seed;
230}
231
232} // namespace persistence_matrix
233} // namespace Gudhi
234
235#endif // PM_COLUMN_UTILITIES_H
Matrix entry class. Stores by default only the row index it belongs to, but can also store its column...
Definition entry_types.h:163
@ INTRUSIVE_SET
Definition persistence_matrix_options.h:44
@ INTRUSIVE_LIST
Definition persistence_matrix_options.h:43
Persistence matrix namespace.
Definition FieldOperators.h:18
Gudhi namespace.
Definition SimplicialComplexForAlpha.h:14
Contains the options for the matrix template.