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
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 F3&& update_target1,
47 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 process_target(targetEntry);
54 ++itTarget;
55 } else if (targetEntry->get_row_index() > itSource->get_row_index()) {
56 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 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 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, itSource, itTarget,
99 process_target, process_source, update_target1, update_target2,
100 pivotIsZeroed);
101 }
102
103 finish_target(itTarget);
104
105 while (itSource != source.end()) {
106 process_source(itSource, target.end());
107 ++itSource;
108 }
109
110 return pivotIsZeroed;
111}
112
113template <class Column, class Entry_range>
114bool _add_to_column(const Entry_range& source, Column& targetColumn)
115{
116 return _generic_add_to_column(
117 source,
118 targetColumn,
119 [&]([[maybe_unused]] typename Column::Entry* entryTarget) {},
120 [&](typename Entry_range::const_iterator& itSource, const typename Column::Column_support::iterator& itTarget) {
121 if constexpr (Column::Master::Option_list::is_z2) {
122 targetColumn._insert_entry(itSource->get_row_index(), itTarget);
123 } else {
124 targetColumn._insert_entry(itSource->get_element(), itSource->get_row_index(), itTarget);
125 }
126 },
127 [&](typename Column::Field_element& targetElement, typename Entry_range::const_iterator& itSource) {
128 if constexpr (!Column::Master::Option_list::is_z2)
129 targetColumn.operators_->add_inplace(targetElement, itSource->get_element());
130 },
131 [&]([[maybe_unused]] typename Column::Entry* entryTarget) {},
132 [&]([[maybe_unused]] typename Column::Column_support::iterator& itTarget) {}
133 );
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 == 0u) {
142 if constexpr (Column::Master::isNonBasic && !Column::Master::Option_list::is_of_boundary_type) {
143 throw std::invalid_argument("A chain column should not be multiplied by 0.");
144 // this would not only mess up the base, but also the pivots stored.
145 } else {
146 targetColumn.clear();
147 }
148 }
149
150 return _generic_add_to_column(
151 source,
152 targetColumn,
153 [&](typename Column::Entry* entryTarget) {
154 targetColumn.operators_->multiply_inplace(entryTarget->get_element(), val);
155 // targetColumn.RA_opt::update_entry(*itTarget) produces an internal compiler error
156 // even though it works in _generic_add_to_column... Probably because of the lambda.
157 if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_entry(*entryTarget);
158 },
159 [&](typename Entry_range::const_iterator& itSource, const typename Column::Column_support::iterator& itTarget) {
160 targetColumn._insert_entry(itSource->get_element(), itSource->get_row_index(), itTarget);
161 },
162 [&](typename Column::Field_element& targetElement, typename Entry_range::const_iterator& itSource) {
163 targetColumn.operators_->multiply_and_add_inplace_front(targetElement, val, itSource->get_element());
164 },
165 [&]([[maybe_unused]] typename Column::Entry* entryTarget) {},
166 [&](typename Column::Column_support::iterator& itTarget) {
167 while (itTarget != targetColumn.column_.end()) {
168 typename Column::Entry* targetEntry = _get_entry<typename Column::Entry>(itTarget);
169 targetColumn.operators_->multiply_inplace(targetEntry->get_element(), val);
170 if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_entry(*targetEntry);
171 itTarget++;
172 }
173 }
174 );
175}
176
177template <class Column, class Entry_range>
178bool _multiply_source_and_add_to_column(const typename Column::Field_element& val,
179 const Entry_range& source,
180 Column& targetColumn)
181{
182 if (val == 0u) {
183 return false;
184 }
185
186 return _generic_add_to_column(
187 source,
188 targetColumn,
189 []([[maybe_unused]] typename Column::Entry* entryTarget) {},
190 [&](typename Entry_range::const_iterator& itSource, const typename Column::Column_support::iterator& itTarget) {
191 typename Column::Entry* entry =
192 targetColumn._insert_entry(itSource->get_element(), itSource->get_row_index(), itTarget);
193 targetColumn.operators_->multiply_inplace(entry->get_element(), val);
194 if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_entry(*entry);
195 },
196 [&](typename Column::Field_element& targetElement, typename Entry_range::const_iterator& itSource) {
197 targetColumn.operators_->multiply_and_add_inplace_back(itSource->get_element(), val, targetElement);
198 },
199 [&]([[maybe_unused]] typename Column::Entry* entryTarget) {},
200 []([[maybe_unused]] typename Column::Column_support::iterator& itTarget) {});
201}
202
203// column has to be ordered (ie. not suited for unordered_map and heap) and contain the exact values
204// (ie. not suited for vector and heap). A same column but ordered differently will have another hash value.
205template <class Column>
206std::size_t hash_column(const Column& column)
207{
208 std::size_t seed = 0;
209 for (auto& entry : column) {
210 seed ^= std::hash<unsigned int>()(entry.get_row_index() * static_cast<unsigned int>(entry.get_element())) +
211 0x9e3779b9 + (seed << 6) + (seed >> 2);
212 }
213 return seed;
214}
215
216} // namespace persistence_matrix
217} // namespace Gudhi
218
219#endif // PM_COLUMN_UTILITIES_H
Gudhi namespace.
Definition: SimplicialComplexForAlpha.h:14
Contains the options for the matrix template.