Loading...
Searching...
No Matches
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 Inria
6 *
7 * Modification(s):
8 * - YYYY/MM Author: Description of the modification
9 */
10
16
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 <climits>
23#include <stdexcept>
24#include <numeric>
25
26#include <gudhi/Debug_utils.h>
27
28namespace Gudhi {
29namespace persistence_fields {
30
45template <typename Unsigned_integer_type = unsigned int,
46 class = std::enable_if_t<std::is_unsigned_v<Unsigned_integer_type> > >
48{
49 public:
50 using Element = Unsigned_integer_type;
52 template <class T>
53 using isInteger = std::enable_if_t<std::is_integral_v<T> >;
54
59
66 template <typename Integer_type, class = isInteger<Integer_type> >
67 Shared_multi_field_element_with_small_characteristics(Integer_type element) : element_(_get_value(element))
68 {}
69
78 static void initialize(unsigned int minimum, unsigned int maximum)
79 {
80 if (maximum < 2) throw std::invalid_argument("Characteristic must be strictly positive");
81 if (minimum > maximum) throw std::invalid_argument("The given interval is not valid.");
82 if (minimum == maximum && !_is_prime(minimum))
83 throw std::invalid_argument("The given interval does not contain a prime number.");
84
85 productOfAllCharacteristics_ = 1;
86 primes_.clear();
87 for (unsigned int i = minimum; i <= maximum; ++i) {
88 if (_is_prime(i)) {
89 primes_.push_back(i);
90 productOfAllCharacteristics_ *= i;
91 }
92 }
93
94 if (primes_.empty()) throw std::invalid_argument("The given interval does not contain a prime number.");
95
96 partials_.resize(primes_.size());
97 for (Characteristic i = 0; i < primes_.size(); ++i) {
98 Characteristic p = primes_[i];
99 Characteristic base = productOfAllCharacteristics_ / p;
100 Characteristic exp = p - 1;
101 partials_[i] = 1;
102
103 while (exp > 0) {
104 // If exp is odd, multiply with result
105 if (exp & 1) partials_[i] = _multiply(partials_[i], base);
106 // y must be even now
107 exp = exp >> 1; // y = y/2
108 base = _multiply(base, base);
109 }
110 }
111
112 // If I understood the paper well, multiplicativeID_ always equals to 1. But in Clement's code,
113 // multiplicativeID_ is computed (see commented loop below). TODO: verify with Clement.
114 // for (unsigned int i = 0; i < partials_.size(); ++i){
115 // multiplicativeID_ = (multiplicativeID_ + partials_[i]) % productOfAllCharacteristics_;
116 // }
117 }
118
124 {
125 f1.element_ = _add(f1.element_, f2.element_);
126 }
127
138
144 template <typename Integer_type, class = isInteger<Integer_type> >
146 {
147 f.element_ = _add(f.element_, _get_value(v));
148 }
149
155 template <typename Integer_type, class = isInteger<Integer_type> >
158 const Integer_type& v)
159 {
160 f += v;
161 return f;
162 }
163
169 template <typename Integer_type, class = isInteger<Integer_type> >
170 friend Integer_type operator+(const Integer_type& v, Shared_multi_field_element_with_small_characteristics f)
171 {
172 f += v;
173 return f.element_;
174 }
175
181 {
182 f1.element_ = _subtract(f1.element_, f2.element_);
183 }
184
195
201 template <typename Integer_type, class = isInteger<Integer_type> >
203 {
204 f.element_ = _subtract(f.element_, _get_value(v));
205 }
206
212 template <typename Integer_type, class = isInteger<Integer_type> >
215 const Integer_type& v)
216 {
217 f -= v;
218 return f;
219 }
220
226 template <typename Integer_type, class = isInteger<Integer_type> >
227 friend Integer_type operator-(const Integer_type& v, const Shared_multi_field_element_with_small_characteristics& f)
228 {
229 return _subtract(_get_value(v), f.element_);
230 }
231
237 {
238 f1.element_ = _multiply(f1.element_, f2.element_);
239 }
240
251
257 template <typename Integer_type, class = isInteger<Integer_type> >
259 {
260 f.element_ = _multiply(f.element_, _get_value(v));
261 }
262
268 template <typename Integer_type, class = isInteger<Integer_type> >
271 const Integer_type& v)
272 {
273 f *= v;
274 return f;
275 }
276
282 template <typename Integer_type, class = isInteger<Integer_type> >
283 friend Integer_type operator*(const Integer_type& v, Shared_multi_field_element_with_small_characteristics f)
284 {
285 f *= v;
286 return f.element_;
287 }
288
294 {
295 return f1.element_ == f2.element_;
296 }
297
303 template <typename Integer_type, class = isInteger<Integer_type> >
304 friend bool operator==(const Integer_type& v, const Shared_multi_field_element_with_small_characteristics& f)
305 {
306 return _get_value(v) == f.element_;
307 }
308
314 template <typename Integer_type, class = isInteger<Integer_type> >
315 friend bool operator==(const Shared_multi_field_element_with_small_characteristics& f, const Integer_type& v)
316 {
317 return _get_value(v) == f.element_;
318 }
319
328
334 template <typename Integer_type, class = isInteger<Integer_type> >
335 friend bool operator!=(const Integer_type v, const Shared_multi_field_element_with_small_characteristics& f)
336 {
337 return !(v == f);
338 }
339
345 template <typename Integer_type, class = isInteger<Integer_type> >
346 friend bool operator!=(const Shared_multi_field_element_with_small_characteristics& f, const Integer_type v)
347 {
348 return !(v == f);
349 }
350
351 // /**
352 // * @brief Assign operator.
353 // *
354 // * @tparam Integer_type A native integer type. Should be able to contain the characteristic if signed.
355 // */
356 // template <typename Integer_type, class = isInteger<Integer_type> >
357 // Shared_multi_field_element_with_small_characteristics& operator=(const Integer_type& value)
358 // {
359 // element_ = _get_value(value);
360 // return *this;
361 // }
362
368 {
369 std::swap(f1.element_, f2.element_);
370 }
371
375 operator unsigned int() const { return element_; }
376
383 {
384 return get_partial_inverse(productOfAllCharacteristics_).first;
385 }
386
394 std::pair<Shared_multi_field_element_with_small_characteristics, Characteristic> get_partial_inverse(
395 Characteristic productOfCharacteristics) const
396 {
397 GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_,
398 std::invalid_argument(
399 "The given product is not the product of a subset of the current Multi-field characteristics."));
400
401 Characteristic gcd = std::gcd(element_, productOfAllCharacteristics_);
402
403 if (gcd == productOfCharacteristics)
404 return {Shared_multi_field_element_with_small_characteristics(), multiplicativeID_}; // partial inverse is 0
405
406 Characteristic QT = productOfCharacteristics / gcd;
407
408 const Element inv_qt = _get_inverse(element_, QT);
409
411 res *= inv_qt;
412
413 return {res, QT};
414 }
415
425
435
444 const Characteristic& productOfCharacteristics)
445 {
446 GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_,
447 std::invalid_argument(
448 "The given product is not the product of a subset of the current Multi-field characteristics."));
449
450 if (productOfCharacteristics == 0 || productOfCharacteristics == productOfAllCharacteristics_) {
452 }
454 for (Characteristic idx = 0; idx < primes_.size(); ++idx) {
455 if ((productOfCharacteristics % primes_[idx]) == 0) {
456 mult += partials_[idx];
457 }
458 }
459 return mult;
460 }
461
467 static Characteristic get_characteristic() { return productOfAllCharacteristics_; }
468
474 Element get_value() const { return element_; }
475
476 private:
477 static constexpr bool _is_prime(const unsigned int p)
478 {
479 if (p <= 1) return false;
480 if (p <= 3) return true;
481 if (p % 2 == 0 || p % 3 == 0) return false;
482
483 for (unsigned long i = 5; i * i <= p; i = i + 6)
484 if (p % i == 0 || p % (i + 2) == 0) return false;
485
486 return true;
487 }
488
489 static Element _multiply(Element a, Element b)
490 {
491 Element res = 0;
492 Element temp_b = 0;
493
494 if (b < a) std::swap(a, b);
495
496 while (a != 0) {
497 if (a & 1) {
498 /* Add b to res, modulo m, without overflow */
499 if (b >= productOfAllCharacteristics_ - res) res -= productOfAllCharacteristics_;
500 res += b;
501 }
502 a >>= 1;
503
504 /* Double b, modulo m */
505 temp_b = b;
506 if (b >= productOfAllCharacteristics_ - b) temp_b -= productOfAllCharacteristics_;
507 b += temp_b;
508 }
509 return res;
510 }
511
512 static Element _add(Element element, Element v)
513 {
514 if (UINT_MAX - element < v) {
515 // automatic unsigned integer overflow behaviour will make it work
516 element += v;
517 element -= productOfAllCharacteristics_;
518 return element;
519 }
520
521 element += v;
522 if (element >= productOfAllCharacteristics_) element -= productOfAllCharacteristics_;
523
524 return element;
525 }
526
527 static Element _subtract(Element element, Element v)
528 {
529 if (element < v) {
530 element += productOfAllCharacteristics_;
531 }
532 element -= v;
533
534 return element;
535 }
536
537 static constexpr int _get_inverse(Element element, const Characteristic mod)
538 {
539 // to solve: Ax + My = 1
540 int M = mod;
541 int A = element;
542 int y = 0, x = 1;
543 // extended euclidean division
544 while (A > 1) {
545 int quotient = A / M;
546 int temp = M;
547
548 M = A % M, A = temp;
549 temp = y;
550
551 y = x - quotient * y;
552 x = temp;
553 }
554
555 if (x < 0) x += mod;
556
557 return x;
558 }
559
560 template <typename Integer_type, class = isInteger<Integer_type> >
561 static constexpr Element _get_value(Integer_type e)
562 {
563 if constexpr (std::is_signed_v<Integer_type>) {
564 if (e < -static_cast<Integer_type>(productOfAllCharacteristics_)) e = e % productOfAllCharacteristics_;
565 if (e < 0) return e += productOfAllCharacteristics_;
566 return e < static_cast<Integer_type>(productOfAllCharacteristics_) ? e : e % productOfAllCharacteristics_;
567 } else {
568 return e < productOfAllCharacteristics_ ? e : e % productOfAllCharacteristics_;
569 }
570 }
571
572 Element element_;
573 static inline std::vector<Characteristic> primes_;
574 static inline Characteristic productOfAllCharacteristics_;
575 static inline std::vector<Characteristic> partials_;
576 static constexpr Element multiplicativeID_ = 1;
577};
578
579} // namespace persistence_fields
580} // namespace Gudhi
581
582#endif // MATRIX_FIELD_MULTI_SMALL_SHARED_H_
friend Integer_type operator*(const Integer_type &v, Shared_multi_field_element_with_small_characteristics f)
operator*
Definition Multi_field_small_shared.h:283
friend void swap(Shared_multi_field_element_with_small_characteristics &f1, Shared_multi_field_element_with_small_characteristics &f2) noexcept
Assign operator.
Definition Multi_field_small_shared.h:366
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:78
Shared_multi_field_element_with_small_characteristics get_inverse() const
Returns the inverse of the element in the multi-field, see boissonnat:hal-00922572.
Definition Multi_field_small_shared.h:382
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:156
friend Integer_type operator+(const Integer_type &v, Shared_multi_field_element_with_small_characteristics f)
operator+
Definition Multi_field_small_shared.h:170
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:269
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:122
Shared_multi_field_element_with_small_characteristics(Integer_type element)
Constructor setting the element to the given value.
Definition Multi_field_small_shared.h:67
friend void operator-=(Shared_multi_field_element_with_small_characteristics &f, const Integer_type &v)
operator-=
Definition Multi_field_small_shared.h:202
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:323
friend bool operator==(const Integer_type &v, const Shared_multi_field_element_with_small_characteristics &f)
operator==
Definition Multi_field_small_shared.h:304
static Shared_multi_field_element_with_small_characteristics get_multiplicative_identity()
Returns the multiplicative identity of a field.
Definition Multi_field_small_shared.h:431
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:213
Unsigned_integer_type Element
Definition Multi_field_small_shared.h:50
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:188
friend bool operator!=(const Integer_type v, const Shared_multi_field_element_with_small_characteristics &f)
operator!=
Definition Multi_field_small_shared.h:335
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:443
friend void operator+=(Shared_multi_field_element_with_small_characteristics &f, const Integer_type &v)
operator+=
Definition Multi_field_small_shared.h:145
static Characteristic get_characteristic()
Returns the product of all characteristics.
Definition Multi_field_small_shared.h:467
static Shared_multi_field_element_with_small_characteristics get_additive_identity()
Returns the additive identity of a field.
Definition Multi_field_small_shared.h:421
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:131
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:394
Shared_multi_field_element_with_small_characteristics()
Default constructor. Sets the element to 0.
Definition Multi_field_small_shared.h:58
friend Integer_type operator-(const Integer_type &v, const Shared_multi_field_element_with_small_characteristics &f)
operator-
Definition Multi_field_small_shared.h:227
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:244
friend bool operator==(const Shared_multi_field_element_with_small_characteristics &f, const Integer_type &v)
operator==
Definition Multi_field_small_shared.h:315
friend void operator*=(Shared_multi_field_element_with_small_characteristics &f, const Integer_type &v)
operator*=
Definition Multi_field_small_shared.h:258
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:235
Element get_value() const
Returns the value of the element.
Definition Multi_field_small_shared.h:474
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:292
friend bool operator!=(const Shared_multi_field_element_with_small_characteristics &f, const Integer_type v)
operator!=
Definition Multi_field_small_shared.h:346
Field namespace.
Definition Intro_field_elements_and_operators.h:16
Gudhi namespace.
Definition SimplicialComplexForAlpha.h:14