Loading...
Searching...
No Matches
Multi_field_small_operators.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, Clément Maria
4 *
5 * Copyright (C) 2022 Inria
6 *
7 * Modification(s):
8 * - YYYY/MM Author: Description of the modification
9 */
10
16
17#ifndef MATRIX_FIELD_MULTI_SMALL_OPERATORS_H_
18#define MATRIX_FIELD_MULTI_SMALL_OPERATORS_H_
19
20#include <utility>
21#include <vector>
22#include <climits>
23#include <stdexcept>
24#include <numeric>
25
26#include <gudhi/Debug_utils.h>
27
28namespace Gudhi {
29namespace persistence_fields {
30
40{
41 public:
42 using Element = unsigned int;
44
45 inline static const Characteristic nullCharacteristic = 0;
46
51 : productOfAllCharacteristics_(nullCharacteristic) /* , multiplicativeID_(1) */
52 {}
53
61 Multi_field_operators_with_small_characteristics(int minCharacteristic, int maxCharacteristic)
62 : productOfAllCharacteristics_(nullCharacteristic) //, multiplicativeID_(1)
63 {
64 set_characteristic(minCharacteristic, maxCharacteristic);
65 }
66
75 void set_characteristic(int minimum, int maximum)
76 {
77 if (maximum < 2) throw std::invalid_argument("Characteristic must be strictly positive");
78 if (minimum > maximum) throw std::invalid_argument("The given interval is not valid.");
79 if (minimum == maximum && !_is_prime(minimum))
80 throw std::invalid_argument("The given interval does not contain a prime number.");
81
82 productOfAllCharacteristics_ = 1;
83 primes_.clear();
84 for (unsigned int i = minimum; i <= static_cast<unsigned int>(maximum); ++i) {
85 if (_is_prime(static_cast<int>(i))) {
86 primes_.push_back(i);
87 productOfAllCharacteristics_ *= i;
88 }
89 }
90
91 if (primes_.empty()) throw std::invalid_argument("The given interval does not contain a prime number.");
92
93 partials_.resize(primes_.size());
94 for (unsigned int i = 0; i < primes_.size(); ++i) {
95 unsigned int p = primes_[i];
96 Characteristic base = productOfAllCharacteristics_ / p;
97 unsigned int exp = p - 1;
98 partials_[i] = 1;
99
100 while (exp > 0) {
101 // If exp is odd, multiply with result
102 if (exp & 1) partials_[i] = _multiply(partials_[i], base, productOfAllCharacteristics_);
103 // y must be even now
104 exp = exp >> 1; // y = y/2
105 base = _multiply(base, base, productOfAllCharacteristics_);
106 }
107 }
108
109 // If I understood the paper well, multiplicativeID_ always equals to 1. But in Clement's code,
110 // multiplicativeID_ is computed (see commented loop below). TODO: verify with Clement.
111 // for (unsigned int i = 0; i < partials_.size(); ++i){
112 // multiplicativeID_ = (multiplicativeID_ + partials_[i]) % productOfAllCharacteristics_;
113 // }
114 }
115
121 [[nodiscard]] const Characteristic& get_characteristic() const { return productOfAllCharacteristics_; }
122
130 [[nodiscard]] Element get_value(Element e) const
131 {
132 return e < productOfAllCharacteristics_ ? e : e % productOfAllCharacteristics_;
133 }
134
142 [[nodiscard]] Element add(Element e1, Element e2) const
143 {
144 return _add(get_value(e1), get_value(e2), productOfAllCharacteristics_);
145 }
146
154 void add_inplace(Element& e1, Element e2) const
155 {
156 e1 = _add(get_value(e1), get_value(e2), productOfAllCharacteristics_);
157 }
158
166 [[nodiscard]] Element subtract(Element e1, Element e2) const
167 {
168 return _subtract(get_value(e1), get_value(e2), productOfAllCharacteristics_);
169 }
170
179 {
180 e1 = _subtract(get_value(e1), get_value(e2), productOfAllCharacteristics_);
181 }
182
191 {
192 e2 = _subtract(get_value(e1), get_value(e2), productOfAllCharacteristics_);
193 }
194
202 [[nodiscard]] Element multiply(Element e1, Element e2) const
203 {
204 return _multiply(get_value(e1), get_value(e2), productOfAllCharacteristics_);
205 }
206
214 void multiply_inplace(Element& e1, Element e2) const
215 {
216 e1 = _multiply(get_value(e1), get_value(e2), productOfAllCharacteristics_);
217 }
218
229 [[nodiscard]] Element multiply_and_add(Element e, Element m, Element a) const { return get_value((e * m) + a); }
230
242 void multiply_and_add_inplace_front(Element& e, Element m, Element a) const { e = get_value((e * m) + a); }
243
255 void multiply_and_add_inplace_back(Element e, Element m, Element& a) const { a = get_value((e * m) + a); }
256
268 [[nodiscard]] Element add_and_multiply(Element e, Element a, Element m) const { return get_value((e + a) * m); }
269
281 void add_and_multiply_inplace_front(Element& e, Element a, Element m) const { e = get_value((e + a) * m); }
282
294 void add_and_multiply_inplace_back(Element e, Element a, Element& m) const { m = get_value((e + a) * m); }
295
304 [[nodiscard]] bool are_equal(Element e1, Element e2) const { return get_value(e1) == get_value(e2); }
305
313 [[nodiscard]] Element get_inverse(const Element& e) const
314 {
315 return get_partial_inverse(e, productOfAllCharacteristics_).first;
316 }
317
326 std::pair<Element, Characteristic> get_partial_inverse(const Element& e,
327 const Characteristic& productOfCharacteristics) const
328 {
329 GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_,
330 std::invalid_argument(
331 "The given product is not the product of a subset of the current Multi-field characteristics."));
332
333 Characteristic gcd = std::gcd(e, productOfAllCharacteristics_);
334
335 if (gcd == productOfCharacteristics) return {0, get_multiplicative_identity()}; // partial inverse is 0
336
337 Characteristic QT = productOfCharacteristics / gcd;
338
339 const Characteristic inv_qt = _get_inverse(e, QT);
340
342 res = _multiply(res, inv_qt, productOfAllCharacteristics_);
343
344 return {res, QT};
345 }
346
352 static constexpr Element get_additive_identity() { return 0; }
353
359 static constexpr Element get_multiplicative_identity() { return 1; }
360
361 // static Element get_multiplicative_identity(){ return multiplicativeID_; }
369 [[nodiscard]] Element get_partial_multiplicative_identity(const Characteristic& productOfCharacteristics) const
370 {
371 GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_,
372 std::invalid_argument(
373 "The given product is not the product of a subset of the current Multi-field characteristics."));
374
375 if (productOfCharacteristics == nullCharacteristic || productOfCharacteristics == productOfAllCharacteristics_) {
377 }
378 Element multIdentity = 0;
379 for (unsigned int idx = 0; idx < primes_.size(); ++idx) {
380 if ((productOfCharacteristics % primes_[idx]) == 0) {
381 multIdentity = _add(multIdentity, partials_[idx], productOfAllCharacteristics_);
382 }
383 }
384 return multIdentity;
385 }
386
392 {
393 f1.primes_.swap(f2.primes_);
394 std::swap(f1.productOfAllCharacteristics_, f2.productOfAllCharacteristics_);
395 f1.partials_.swap(f2.partials_);
396 }
397
398 private:
399 std::vector<unsigned int> primes_;
400 Characteristic productOfAllCharacteristics_;
401 std::vector<Characteristic> partials_;
402
403 // static inline constexpr unsigned int multiplicativeID_ = 1;
404
405 static Element _add(Element element, Element v, Characteristic characteristic)
406 {
407 if (UINT_MAX - element < v) {
408 // automatic unsigned integer overflow behaviour will make it work
409 element += v;
410 element -= characteristic;
411 return element;
412 }
413
414 element += v;
415 if (element >= characteristic) element -= characteristic;
416
417 return element;
418 }
419
420 static Element _subtract(Element element, Element v, Characteristic characteristic)
421 {
422 if (element < v) {
423 element += characteristic;
424 }
425 element -= v;
426
427 return element;
428 }
429
430 static Element _multiply(Element a, Element b, Characteristic characteristic)
431 {
432 Element res = 0;
433 Element temp_b = 0;
434
435 if (b < a) std::swap(a, b);
436
437 while (a != 0) {
438 if (a & 1) {
439 /* Add b to res, modulo m, without overflow */
440 if (b >= characteristic - res) res -= characteristic;
441 res += b;
442 }
443 a >>= 1;
444
445 /* Double b, modulo m */
446 temp_b = b;
447 if (b >= characteristic - b) temp_b -= characteristic;
448 b += temp_b;
449 }
450 return res;
451 }
452
453 static constexpr long int _get_inverse(Element element, Characteristic mod)
454 {
455 // to solve: Ax + My = 1
456 Element M = mod;
457 Element A = element;
458 long int y = 0, x = 1;
459 // extended euclidean division
460 while (A > 1) {
461 int quotient = A / M;
462 int temp = M;
463
464 M = A % M, A = temp;
465 temp = y;
466
467 y = x - quotient * y;
468 x = temp;
469 }
470
471 if (x < 0) x += mod;
472
473 return x;
474 }
475
476 static constexpr bool _is_prime(const int p)
477 {
478 if (p <= 1) return false;
479 if (p <= 3) return true;
480 if (p % 2 == 0 || p % 3 == 0) return false;
481
482 for (long i = 5; i * i <= p; i = i + 6)
483 if (p % i == 0 || p % (i + 2) == 0) return false;
484
485 return true;
486 }
487};
488
489} // namespace persistence_fields
490} // namespace Gudhi
491
492#endif // MATRIX_FIELD_MULTI_SMALL_OPERATORS_H_
Element subtract(Element e1, Element e2) const
Returns the subtraction in the field of the first element by the second element.
Definition Multi_field_small_operators.h:166
Element Characteristic
Definition Multi_field_small_operators.h:43
Element multiply_and_add(Element e, Element m, Element a) const
Multiplies the first element with the second one and adds the third one. Returns the result in the fi...
Definition Multi_field_small_operators.h:229
Element multiply(Element e1, Element e2) const
Returns the multiplication of two elements in the field.
Definition Multi_field_small_operators.h:202
Element add_and_multiply(Element e, Element a, Element m) const
Adds the first element to the second one and multiplies the third one with it. Returns the result in ...
Definition Multi_field_small_operators.h:268
static const Characteristic nullCharacteristic
Definition Multi_field_small_operators.h:45
Element get_partial_multiplicative_identity(const Characteristic &productOfCharacteristics) const
Returns the partial multiplicative identity of the multi-field from the given product....
Definition Multi_field_small_operators.h:369
Element get_value(Element e) const
Returns the value of an element in the field. That is the positive value of the integer modulo the cu...
Definition Multi_field_small_operators.h:130
static constexpr Element get_multiplicative_identity()
Returns the multiplicative identity of a field.
Definition Multi_field_small_operators.h:359
bool are_equal(Element e1, Element e2) const
Returns true if the two given elements are equal in the field, false otherwise.
Definition Multi_field_small_operators.h:304
Multi_field_operators_with_small_characteristics(int minCharacteristic, int maxCharacteristic)
Constructor setting the characteristics to all prime numbers between the two given integers....
Definition Multi_field_small_operators.h:61
static constexpr Element get_additive_identity()
Returns the additive identity of a field.
Definition Multi_field_small_operators.h:352
void add_and_multiply_inplace_front(Element &e, Element a, Element m) const
Adds the first element to the second one and multiplies the third one with it, that is ((e + a) * m) ...
Definition Multi_field_small_operators.h:281
friend void swap(Multi_field_operators_with_small_characteristics &f1, Multi_field_operators_with_small_characteristics &f2) noexcept
Swap operator.
Definition Multi_field_small_operators.h:390
Element add(Element e1, Element e2) const
Returns the sum of two elements in the field.
Definition Multi_field_small_operators.h:142
void set_characteristic(int minimum, int maximum)
Set the characteristics of the field, which are stored in a single value as a product of all of them....
Definition Multi_field_small_operators.h:75
std::pair< Element, Characteristic > get_partial_inverse(const Element &e, const Characteristic &productOfCharacteristics) const
Returns the inverse of the given element in the multi-field corresponding to the given sub-product of...
Definition Multi_field_small_operators.h:326
void add_and_multiply_inplace_back(Element e, Element a, Element &m) const
Adds the first element to the second one and multiplies the third one with it, that is ((e + a) * m) ...
Definition Multi_field_small_operators.h:294
void subtract_inplace_back(Element e1, Element &e2) const
Stores in the second element the subtraction in the field of the first element by the second element,...
Definition Multi_field_small_operators.h:190
unsigned int Element
Definition Multi_field_small_operators.h:42
void multiply_and_add_inplace_back(Element e, Element m, Element &a) const
Multiplies the first element with the second one and adds the third one, that is (e * m + a) % produc...
Definition Multi_field_small_operators.h:255
void multiply_inplace(Element &e1, Element e2) const
Stores in the first element the multiplication of two given elements in the field,...
Definition Multi_field_small_operators.h:214
void subtract_inplace_front(Element &e1, Element e2) const
Stores in the first element the subtraction in the field of the first element by the second element,...
Definition Multi_field_small_operators.h:178
void add_inplace(Element &e1, Element e2) const
Stores in the first element the sum of two given elements in the field, that is (e1 + e2) % productOf...
Definition Multi_field_small_operators.h:154
Element get_inverse(const Element &e) const
Returns the inverse of the given element in the sense of boissonnat:hal-00922572 with respect to the ...
Definition Multi_field_small_operators.h:313
void multiply_and_add_inplace_front(Element &e, Element m, Element a) const
Multiplies the first element with the second one and adds the third one, that is (e * m + a) % produc...
Definition Multi_field_small_operators.h:242
Multi_field_operators_with_small_characteristics()
Default constructor, sets the product of all characteristics to 0.
Definition Multi_field_small_operators.h:50
const Characteristic & get_characteristic() const
Returns the current characteristics as the product of all of them.
Definition Multi_field_small_operators.h:121
Field namespace.
Definition Intro_field_elements_and_operators.h:16
Gudhi namespace.
Definition SimplicialComplexForAlpha.h:14