Multi_field_small_shared.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-24 Inria
6 *
7 * Modification(s):
8 * - YYYY/MM Author: Description of the modification
9 */
10
17#ifndef MATRIX_FIELD_MULTI_SMALL_SHARED_H_
18#define MATRIX_FIELD_MULTI_SMALL_SHARED_H_
19
20#include <utility>
21#include <vector>
22#include <limits.h>
23#include <stdexcept>
24#include <numeric>
25
26namespace Gudhi {
27namespace persistence_fields {
28
43template <typename Unsigned_integer_type = unsigned int,
44 class = std::enable_if_t<std::is_unsigned_v<Unsigned_integer_type> > >
46 public:
47 using Element = Unsigned_integer_type;
49 template <class T>
50 using isInteger = std::enable_if_t<std::is_integral_v<T> >;
51
62 template <typename Integer_type, class = isInteger<Integer_type> >
63 Shared_multi_field_element_with_small_characteristics(Integer_type element) : element_(_get_value(element)) {}
71 : element_(toCopy.element_) {}
79 : element_(std::exchange(toMove.element_, 0)) {}
80
89 static void initialize(unsigned int minimum, unsigned int maximum) {
90 if (maximum < 2) throw std::invalid_argument("Characteristic must be strictly positive");
91 if (minimum > maximum) throw std::invalid_argument("The given interval is not valid.");
92 if (minimum == maximum && !_is_prime(minimum))
93 throw std::invalid_argument("The given interval does not contain a prime number.");
94
95 productOfAllCharacteristics_ = 1;
96 primes_.clear();
97 for (unsigned int i = minimum; i <= maximum; ++i) {
98 if (_is_prime(i)) {
99 primes_.push_back(i);
100 productOfAllCharacteristics_ *= i;
101 }
102 }
103
104 if (primes_.empty()) throw std::invalid_argument("The given interval does not contain a prime number.");
105
106 partials_.resize(primes_.size());
107 for (Characteristic i = 0; i < primes_.size(); ++i) {
108 Characteristic p = primes_[i];
109 Characteristic base = productOfAllCharacteristics_ / p;
110 Characteristic exp = p - 1;
111 partials_[i] = 1;
112
113 while (exp > 0) {
114 // If exp is odd, multiply with result
115 if (exp & 1) partials_[i] = _multiply(partials_[i], base);
116 // y must be even now
117 exp = exp >> 1; // y = y/2
118 base = _multiply(base, base);
119 }
120 }
121
122 // If I understood the paper well, multiplicativeID_ always equals to 1. But in Clement's code,
123 // multiplicativeID_ is computed (see commented loop below). TODO: verify with Clement.
124 // for (unsigned int i = 0; i < partials_.size(); ++i){
125 // multiplicativeID_ = (multiplicativeID_ + partials_[i]) % productOfAllCharacteristics_;
126 // }
127 }
128
134 f1.element_ = _add(f1.element_, f2.element_);
135 }
142 f1 += f2;
143 return f1;
144 }
150 template <typename Integer_type, class = isInteger<Integer_type> >
152 f.element_ = _add(f.element_, _get_value(v));
153 }
159 template <typename Integer_type, class = isInteger<Integer_type> >
162 f += v;
163 return f;
164 }
170 template <typename Integer_type, class = isInteger<Integer_type> >
171 friend Integer_type operator+(const Integer_type& v, Shared_multi_field_element_with_small_characteristics f) {
172 f += v;
173 return f.element_;
174 }
175
181 f1.element_ = _subtract(f1.element_, f2.element_);
182 }
189 f1 -= f2;
190 return f1;
191 }
197 template <typename Integer_type, class = isInteger<Integer_type> >
199 f.element_ = _subtract(f.element_, _get_value(v));
200 }
206 template <typename Integer_type, class = isInteger<Integer_type> >
209 f -= v;
210 return f;
211 }
217 template <typename Integer_type, class = isInteger<Integer_type> >
218 friend Integer_type operator-(const Integer_type& v, const Shared_multi_field_element_with_small_characteristics& f) {
219 return _subtract(_get_value(v), f.element_);
220 }
221
227 f1.element_ = _multiply(f1.element_, f2.element_);
228 }
235 f1 *= f2;
236 return f1;
237 }
243 template <typename Integer_type, class = isInteger<Integer_type> >
245 f.element_ = _multiply(f.element_, _get_value(v));
246 }
252 template <typename Integer_type, class = isInteger<Integer_type> >
255 f *= v;
256 return f;
257 }
263 template <typename Integer_type, class = isInteger<Integer_type> >
264 friend Integer_type operator*(const Integer_type& v, Shared_multi_field_element_with_small_characteristics f) {
265 f *= v;
266 return f.element_;
267 }
268
274 return f1.element_ == f2.element_;
275 }
281 template <typename Integer_type, class = isInteger<Integer_type> >
282 friend bool operator==(const Integer_type& v, const Shared_multi_field_element_with_small_characteristics& f) {
283 return _get_value(v) == f.element_;
284 }
290 template <typename Integer_type, class = isInteger<Integer_type> >
291 friend bool operator==(const Shared_multi_field_element_with_small_characteristics& f, const Integer_type& v) {
292 return _get_value(v) == f.element_;
293 }
299 return !(f1 == f2);
300 }
306 template <typename Integer_type, class = isInteger<Integer_type> >
307 friend bool operator!=(const Integer_type v, const Shared_multi_field_element_with_small_characteristics& f) {
308 return !(v == f);
309 }
315 template <typename Integer_type, class = isInteger<Integer_type> >
316 friend bool operator!=(const Shared_multi_field_element_with_small_characteristics& f, const Integer_type v) {
317 return !(v == f);
318 }
319
325 std::swap(element_, other.element_);
326 return *this;
327 }
333 template <typename Integer_type, class = isInteger<Integer_type> >
335 element_ = _get_value(value);
336 return *this;
337 }
343 std::swap(f1.element_, f2.element_);
344 }
345
349 operator unsigned int() const { return element_; }
350
357 return get_partial_inverse(productOfAllCharacteristics_).first;
358 }
366 std::pair<Shared_multi_field_element_with_small_characteristics,Characteristic> get_partial_inverse(
367 Characteristic productOfCharacteristics) const {
368 Characteristic gcd = std::gcd(element_, productOfAllCharacteristics_);
369
370 if (gcd == productOfCharacteristics)
371 return {Shared_multi_field_element_with_small_characteristics(), multiplicativeID_}; // partial inverse is 0
372
373 Characteristic QT = productOfCharacteristics / gcd;
374
375 const Element inv_qt = _get_inverse(element_, QT);
376
378 res *= inv_qt;
379
380 return {res, QT};
381 }
382
390 }
398 }
407 const Characteristic& productOfCharacteristics) {
408 if (productOfCharacteristics == 0) {
410 }
412 for (Characteristic idx = 0; idx < primes_.size(); ++idx) {
413 if ((productOfCharacteristics % primes_[idx]) == 0) {
414 mult += partials_[idx];
415 }
416 }
417 return mult;
418 }
424 static Characteristic get_characteristic() { return productOfAllCharacteristics_; }
425
431 Element get_value() const { return element_; }
432
433 // static constexpr bool handles_only_z2() { return false; }
434
435 private:
436 static constexpr bool _is_prime(const unsigned int p) {
437 if (p <= 1) return false;
438 if (p <= 3) return true;
439 if (p % 2 == 0 || p % 3 == 0) return false;
440
441 for (unsigned long i = 5; i * i <= p; i = i + 6)
442 if (p % i == 0 || p % (i + 2) == 0) return false;
443
444 return true;
445 }
446 static Element _multiply(Element a, Element b) {
447 Element res = 0;
448 Element temp_b = 0;
449
450 if (b < a) std::swap(a, b);
451
452 while (a != 0) {
453 if (a & 1) {
454 /* Add b to res, modulo m, without overflow */
455 if (b >= productOfAllCharacteristics_ - res) res -= productOfAllCharacteristics_;
456 res += b;
457 }
458 a >>= 1;
459
460 /* Double b, modulo m */
461 temp_b = b;
462 if (b >= productOfAllCharacteristics_ - b) temp_b -= productOfAllCharacteristics_;
463 b += temp_b;
464 }
465 return res;
466 }
467 static Element _add(Element element, Element v) {
468 if (UINT_MAX - element < v) {
469 // automatic unsigned integer overflow behaviour will make it work
470 element += v;
471 element -= productOfAllCharacteristics_;
472 return element;
473 }
474
475 element += v;
476 if (element >= productOfAllCharacteristics_) element -= productOfAllCharacteristics_;
477
478 return element;
479 }
480 static Element _subtract(Element element, Element v) {
481 if (element < v) {
482 element += productOfAllCharacteristics_;
483 }
484 element -= v;
485
486 return element;
487 }
488 static constexpr int _get_inverse(Element element, const Characteristic mod) {
489 // to solve: Ax + My = 1
490 int M = mod;
491 int A = element;
492 int y = 0, x = 1;
493 // extended euclidean division
494 while (A > 1) {
495 int quotient = A / M;
496 int temp = M;
497
498 M = A % M, A = temp;
499 temp = y;
500
501 y = x - quotient * y;
502 x = temp;
503 }
504
505 if (x < 0) x += mod;
506
507 return x;
508 }
509
510 template <typename Integer_type, class = isInteger<Integer_type> >
511 static constexpr Element _get_value(Integer_type e) {
512 if constexpr (std::is_signed_v<Integer_type>){
513 if (e < -static_cast<Integer_type>(productOfAllCharacteristics_)) e = e % productOfAllCharacteristics_;
514 if (e < 0) return e += productOfAllCharacteristics_;
515 return e < static_cast<Integer_type>(productOfAllCharacteristics_) ? e : e % productOfAllCharacteristics_;
516 } else {
517 return e < productOfAllCharacteristics_ ? e : e % productOfAllCharacteristics_;
518 }
519 }
520
521 Element element_;
522 static inline std::vector<Characteristic> primes_;
523 static inline Characteristic productOfAllCharacteristics_;
524 static inline std::vector<Characteristic> partials_;
525 static inline constexpr Element multiplicativeID_ = 1;
526};
527
528} // namespace persistence_fields
529} // namespace Gudhi
530
531#endif // MATRIX_FIELD_MULTI_SMALL_SHARED_H_
Class representing an element of a multi-field, such that productOfAllCharacteristics ^ 2 fits into t...
Definition: Multi_field_small_shared.h:45
friend Integer_type operator*(const Integer_type &v, Shared_multi_field_element_with_small_characteristics f)
operator*
Definition: Multi_field_small_shared.h:264
static void initialize(unsigned int minimum, unsigned int maximum)
Initialize the multi-field to the characteristics (primes) contained in the given interval....
Definition: Multi_field_small_shared.h:89
Shared_multi_field_element_with_small_characteristics get_inverse() const
Returns the inverse of the element in the multi-field, see .
Definition: Multi_field_small_shared.h:356
friend Shared_multi_field_element_with_small_characteristics operator+(Shared_multi_field_element_with_small_characteristics f, const Integer_type &v)
operator+
Definition: Multi_field_small_shared.h:160
friend Integer_type operator+(const Integer_type &v, Shared_multi_field_element_with_small_characteristics f)
operator+
Definition: Multi_field_small_shared.h:171
friend Shared_multi_field_element_with_small_characteristics operator*(Shared_multi_field_element_with_small_characteristics f, const Integer_type &v)
operator*
Definition: Multi_field_small_shared.h:253
friend void operator+=(Shared_multi_field_element_with_small_characteristics &f1, Shared_multi_field_element_with_small_characteristics const &f2)
operator+=
Definition: Multi_field_small_shared.h:132
Shared_multi_field_element_with_small_characteristics(Integer_type element)
Constructor setting the element to the given value.
Definition: Multi_field_small_shared.h:63
friend void operator-=(Shared_multi_field_element_with_small_characteristics &f, const Integer_type &v)
operator-=
Definition: Multi_field_small_shared.h:198
friend bool operator!=(const Shared_multi_field_element_with_small_characteristics &f1, const Shared_multi_field_element_with_small_characteristics &f2)
operator!=
Definition: Multi_field_small_shared.h:297
friend bool operator==(const Integer_type &v, const Shared_multi_field_element_with_small_characteristics &f)
operator==
Definition: Multi_field_small_shared.h:282
static Shared_multi_field_element_with_small_characteristics get_multiplicative_identity()
Returns the multiplicative identity of a field.
Definition: Multi_field_small_shared.h:396
Shared_multi_field_element_with_small_characteristics & operator=(const Integer_type &value)
Assign operator.
Definition: Multi_field_small_shared.h:334
friend Shared_multi_field_element_with_small_characteristics operator-(Shared_multi_field_element_with_small_characteristics f, const Integer_type &v)
operator-
Definition: Multi_field_small_shared.h:207
Unsigned_integer_type Element
Definition: Multi_field_small_shared.h:47
Shared_multi_field_element_with_small_characteristics(const Shared_multi_field_element_with_small_characteristics &toCopy)
Copy constructor.
Definition: Multi_field_small_shared.h:69
friend Shared_multi_field_element_with_small_characteristics operator-(Shared_multi_field_element_with_small_characteristics f1, Shared_multi_field_element_with_small_characteristics const &f2)
operator-
Definition: Multi_field_small_shared.h:186
friend bool operator!=(const Integer_type v, const Shared_multi_field_element_with_small_characteristics &f)
operator!=
Definition: Multi_field_small_shared.h:307
static Shared_multi_field_element_with_small_characteristics get_partial_multiplicative_identity(const Characteristic &productOfCharacteristics)
Returns the partial multiplicative identity of the multi-field from the given product....
Definition: Multi_field_small_shared.h:406
friend void operator+=(Shared_multi_field_element_with_small_characteristics &f, const Integer_type &v)
operator+=
Definition: Multi_field_small_shared.h:151
static Characteristic get_characteristic()
Returns the product of all characteristics.
Definition: Multi_field_small_shared.h:424
Shared_multi_field_element_with_small_characteristics & operator=(Shared_multi_field_element_with_small_characteristics other)
Assign operator.
Definition: Multi_field_small_shared.h:323
static Shared_multi_field_element_with_small_characteristics get_additive_identity()
Returns the additive identity of a field.
Definition: Multi_field_small_shared.h:388
friend Shared_multi_field_element_with_small_characteristics operator+(Shared_multi_field_element_with_small_characteristics f1, Shared_multi_field_element_with_small_characteristics const &f2)
operator+
Definition: Multi_field_small_shared.h:139
std::pair< Shared_multi_field_element_with_small_characteristics, Characteristic > get_partial_inverse(Characteristic productOfCharacteristics) const
Returns the inverse of the element with respect to a sub-product of the characteristics in the multi-...
Definition: Multi_field_small_shared.h:366
Shared_multi_field_element_with_small_characteristics()
Default constructor. Sets the element to 0.
Definition: Multi_field_small_shared.h:55
friend Integer_type operator-(const Integer_type &v, const Shared_multi_field_element_with_small_characteristics &f)
operator-
Definition: Multi_field_small_shared.h:218
friend Shared_multi_field_element_with_small_characteristics operator*(Shared_multi_field_element_with_small_characteristics f1, Shared_multi_field_element_with_small_characteristics const &f2)
operator*
Definition: Multi_field_small_shared.h:232
Shared_multi_field_element_with_small_characteristics(Shared_multi_field_element_with_small_characteristics &&toMove) noexcept
Move constructor.
Definition: Multi_field_small_shared.h:77
friend bool operator==(const Shared_multi_field_element_with_small_characteristics &f, const Integer_type &v)
operator==
Definition: Multi_field_small_shared.h:291
friend void operator*=(Shared_multi_field_element_with_small_characteristics &f, const Integer_type &v)
operator*=
Definition: Multi_field_small_shared.h:244
friend void operator-=(Shared_multi_field_element_with_small_characteristics &f1, Shared_multi_field_element_with_small_characteristics const &f2)
operator-=
Definition: Multi_field_small_shared.h:179
friend void operator*=(Shared_multi_field_element_with_small_characteristics &f1, Shared_multi_field_element_with_small_characteristics const &f2)
operator*=
Definition: Multi_field_small_shared.h:225
Element get_value() const
Returns the value of the element.
Definition: Multi_field_small_shared.h:431
friend bool operator==(const Shared_multi_field_element_with_small_characteristics &f1, const Shared_multi_field_element_with_small_characteristics &f2)
operator==
Definition: Multi_field_small_shared.h:272
friend void swap(Shared_multi_field_element_with_small_characteristics &f1, Shared_multi_field_element_with_small_characteristics &f2)
Swap operator.
Definition: Multi_field_small_shared.h:341
friend bool operator!=(const Shared_multi_field_element_with_small_characteristics &f, const Integer_type v)
operator!=
Definition: Multi_field_small_shared.h:316
Gudhi namespace.
Definition: SimplicialComplexForAlpha.h:14