Loading...
Searching...
No Matches
Multi_field_small.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_H_
18#define MATRIX_FIELD_MULTI_SMALL_H_
19
20#include <utility>
21#include <vector>
22#include <limits.h>
23#include <numeric>
24
25#include <gudhi/Debug_utils.h>
26
27namespace Gudhi {
28namespace persistence_fields {
29
43template <unsigned int minimum,
44 unsigned int maximum,
45 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 {
60 static_assert(maximum >= 2, "Characteristics have to be positive.");
61 static_assert(minimum <= maximum, "The given interval is not valid.");
62 static_assert(minimum != maximum || _is_prime(minimum), "The given interval does not contain a prime number.");
63 static_assert(productOfAllCharacteristics_ != 1, "The given interval does not contain a prime number.");
64 }
65
71 template <typename Integer_type, class = isInteger<Integer_type> >
72 Multi_field_element_with_small_characteristics(Integer_type element) : element_(_get_value(element))
73 {
74 static_assert(maximum >= 2, "Characteristics has to be positive.");
75 static_assert(minimum <= maximum, "The given interval is not valid.");
76 static_assert(minimum != maximum || _is_prime(minimum), "The given interval does not contain a prime number.");
77 static_assert(productOfAllCharacteristics_ != 1, "The given interval does not contain a prime number.");
78 }
79
85 {
86 f1.element_ = _add(f1.element_, f2.element_);
87 }
88
99
105 template <typename Integer_type, class = isInteger<Integer_type> >
106 friend void operator+=(Multi_field_element_with_small_characteristics& f, const Integer_type& v)
107 {
108 f.element_ = _add(f.element_, _get_value(v));
109 }
110
116 template <typename Integer_type, class = isInteger<Integer_type> >
118 const Integer_type& v)
119 {
120 f += v;
121 return f;
122 }
123
129 template <typename Integer_type, class = isInteger<Integer_type> >
130 friend Integer_type operator+(const Integer_type& v, Multi_field_element_with_small_characteristics f)
131 {
132 f += v;
133 return f.element_;
134 }
135
141 {
142 f1.element_ = _subtract(f1.element_, f2.element_);
143 }
144
155
161 template <typename Integer_type, class = isInteger<Integer_type> >
162 friend void operator-=(Multi_field_element_with_small_characteristics& f, const Integer_type& v)
163 {
164 f.element_ = _subtract(f.element_, _get_value(v));
165 }
166
172 template <typename Integer_type, class = isInteger<Integer_type> >
174 const Integer_type& v)
175 {
176 f -= v;
177 return f;
178 }
179
185 template <typename Integer_type, class = isInteger<Integer_type> >
186 friend Integer_type operator-(const Integer_type& v, const Multi_field_element_with_small_characteristics& f)
187 {
188 return _subtract(_get_value(v), f.element_);
189 }
190
196 {
197 f1.element_ = _multiply(f1.element_, f2.element_);
198 }
199
210
216 template <typename Integer_type, class = isInteger<Integer_type> >
217 friend void operator*=(Multi_field_element_with_small_characteristics& f, const Integer_type& v)
218 {
219 f.element_ = _multiply(f.element_, _get_value(v));
220 }
221
227 template <typename Integer_type, class = isInteger<Integer_type> >
229 const Integer_type& v)
230 {
231 f *= v;
232 return f;
233 }
234
240 template <typename Integer_type, class = isInteger<Integer_type> >
241 friend Integer_type operator*(const Integer_type& v, Multi_field_element_with_small_characteristics f)
242 {
243 f *= v;
244 return f.element_;
245 }
246
252 {
253 return f1.element_ == f2.element_;
254 }
255
261 template <typename Integer_type, class = isInteger<Integer_type> >
262 friend bool operator==(const Integer_type v, const Multi_field_element_with_small_characteristics& f)
263 {
264 return _get_value(v) == f.element_;
265 }
266
272 template <typename Integer_type, class = isInteger<Integer_type> >
273 friend bool operator==(const Multi_field_element_with_small_characteristics& f, const Integer_type v)
274 {
275 return _get_value(v) == f.element_;
276 }
277
283 {
284 return !(f1 == f2);
285 }
286
292 template <typename Integer_type, class = isInteger<Integer_type> >
293 friend bool operator!=(const Integer_type v, const Multi_field_element_with_small_characteristics& f)
294 {
295 return !(v == f);
296 }
297
303 template <typename Integer_type, class = isInteger<Integer_type> >
304 friend bool operator!=(const Multi_field_element_with_small_characteristics& f, const Integer_type v)
305 {
306 return !(v == f);
307 }
308
309 // /**
310 // * @brief Assign operator.
311 // *
312 // * @tparam Integer_type A native integer type. Should be able to contain the characteristic if signed.
313 // */
314 // template <typename Integer_type, class = isInteger<Integer_type> >
315 // Multi_field_element_with_small_characteristics& operator=(const Integer_type& value)
316 // {
317 // element_ = _get_value(value);
318 // return *this;
319 // }
320
326 {
327 std::swap(f1.element_, f2.element_);
328 }
329
333 operator unsigned int() const { return element_; }
334
341 {
342 return get_partial_inverse(productOfAllCharacteristics_).first;
343 }
344
352 std::pair<Multi_field_element_with_small_characteristics, Characteristic> get_partial_inverse(
353 Characteristic productOfCharacteristics) const
354 {
355 GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_,
356 std::invalid_argument(
357 "The given product is not the product of a subset of the current Multi-field characteristics."));
358
359 Characteristic gcd = std::gcd(element_, productOfAllCharacteristics_);
360
361 if (gcd == productOfCharacteristics)
362 return {Multi_field_element_with_small_characteristics(), multiplicativeID_}; // partial inverse is 0
363
364 Characteristic QT = productOfCharacteristics / gcd;
365
366 const Element inv_qt = _get_inverse(element_, QT);
367
369 res *= inv_qt;
370
371 return {res, QT};
372 }
373
383
393
402 const Characteristic& productOfCharacteristics)
403 {
404 GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_,
405 std::invalid_argument(
406 "The given product is not the product of a subset of the current Multi-field characteristics."));
407
408 if (productOfCharacteristics == 0 || productOfCharacteristics == productOfAllCharacteristics_) {
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 }
419
425 static constexpr Characteristic get_characteristic() { return productOfAllCharacteristics_; }
426
432 Element get_value() const { return element_; }
433
434 private:
435 static constexpr bool _is_prime(const unsigned int p)
436 {
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
447 static constexpr Element _multiply(Element a, Element b)
448 {
449 Element res = 0;
450 Element temp_b = 0;
451
452 if (b < a) std::swap(a, b);
453
454 while (a != 0) {
455 if (a & 1) {
456 /* Add b to res, modulo m, without overflow */
457 if (b >= productOfAllCharacteristics_ - res) res -= productOfAllCharacteristics_;
458 res += b;
459 }
460 a >>= 1;
461
462 /* Double b, modulo m */
463 temp_b = b;
464 if (b >= productOfAllCharacteristics_ - b) temp_b -= productOfAllCharacteristics_;
465 b += temp_b;
466 }
467 return res;
468 }
469
470 static constexpr Element _add(Element element, Element v)
471 {
472 if (UINT_MAX - element < v) {
473 // automatic unsigned integer overflow behaviour will make it work
474 element += v;
475 element -= productOfAllCharacteristics_;
476 return element;
477 }
478
479 element += v;
480 if (element >= productOfAllCharacteristics_) element -= productOfAllCharacteristics_;
481
482 return element;
483 }
484
485 static constexpr Element _subtract(Element element, Element v)
486 {
487 if (element < v) {
488 element += productOfAllCharacteristics_;
489 }
490 element -= v;
491
492 return element;
493 }
494
495 static constexpr int _get_inverse(Element element, const Element mod)
496 {
497 // to solve: Ax + My = 1
498 int M = mod;
499 int A = element;
500 int y = 0, x = 1;
501 // extended euclidean division
502 while (A > 1) {
503 int quotient = A / M;
504 int temp = M;
505
506 M = A % M, A = temp;
507 temp = y;
508
509 y = x - quotient * y;
510 x = temp;
511 }
512
513 if (x < 0) x += mod;
514
515 return x;
516 }
517
518 template <typename Integer_type, class = isInteger<Integer_type> >
519 static constexpr Element _get_value(Integer_type e)
520 {
521 if constexpr (std::is_signed_v<Integer_type>) {
522 if (e < -static_cast<Integer_type>(productOfAllCharacteristics_)) e = e % productOfAllCharacteristics_;
523 if (e < 0) return e += productOfAllCharacteristics_;
524 return e < static_cast<Integer_type>(productOfAllCharacteristics_) ? e : e % productOfAllCharacteristics_;
525 } else {
526 return e < productOfAllCharacteristics_ ? e : e % productOfAllCharacteristics_;
527 }
528 }
529
530 Element element_;
531 static inline const std::vector<Characteristic> primes_ = []() {
532 std::vector<Characteristic> res;
533 for (Characteristic i = minimum; i <= maximum; ++i) {
534 if (_is_prime(i)) {
535 res.push_back(i);
536 }
537 }
538 return res;
539 }();
540 static constexpr Characteristic productOfAllCharacteristics_ = []() {
541 Characteristic res = 1;
542 for (Characteristic i = minimum; i <= maximum; ++i) {
543 if (_is_prime(i)) {
544 res *= i;
545 }
546 }
547 return res;
548 }();
549 static inline const std::vector<Characteristic> partials_ = []() {
550 std::vector<Characteristic> res;
551
552 if (productOfAllCharacteristics_ == 1) return res;
553
554 for (Characteristic i = 0; i < primes_.size(); ++i) {
555 Characteristic p = primes_[i];
556 Characteristic base = productOfAllCharacteristics_ / p;
557 Characteristic exp = p - 1;
558 res.push_back(1);
559
560 while (exp > 0) {
561 // If exp is odd, multiply with result
562 if (exp & 1) res.back() = _multiply(res.back(), base);
563 // y must be even now
564 exp = exp >> 1;
565 base = _multiply(base, base);
566 }
567 }
568
569 return res;
570 }();
571 // If I understood the paper well, multiplicativeID_ always equals to 1. But in Clement's code,
572 // multiplicativeID_ is computed (see commented lambda function below). TODO: verify with Clement.
573 static constexpr Element multiplicativeID_ = 1; /*= [](){
574 unsigned int res = 0;
575 for (unsigned int i = 0; i < partials_.size(); ++i){
576 res = (res + partials_[i]) % productOfAllCharacteristics_;
577 }
578
579 return res;
580 }();*/
581};
582
583} // namespace persistence_fields
584} // namespace Gudhi
585
586#endif // MATRIX_FIELD_MULTI_SMALL_H_
friend Multi_field_element_with_small_characteristics operator-(Multi_field_element_with_small_characteristics f1, Multi_field_element_with_small_characteristics const &f2)
operator-
Definition Multi_field_small.h:148
friend void swap(Multi_field_element_with_small_characteristics &f1, Multi_field_element_with_small_characteristics &f2) noexcept
Assign operator.
Definition Multi_field_small.h:324
friend void operator+=(Multi_field_element_with_small_characteristics &f, const Integer_type &v)
operator+=
Definition Multi_field_small.h:106
friend void operator-=(Multi_field_element_with_small_characteristics &f, const Integer_type &v)
operator-=
Definition Multi_field_small.h:162
friend void operator*=(Multi_field_element_with_small_characteristics &f1, Multi_field_element_with_small_characteristics const &f2)
operator*=
Definition Multi_field_small.h:194
friend bool operator!=(const Integer_type v, const Multi_field_element_with_small_characteristics &f)
operator!=
Definition Multi_field_small.h:293
friend void operator-=(Multi_field_element_with_small_characteristics &f1, Multi_field_element_with_small_characteristics const &f2)
operator-=
Definition Multi_field_small.h:139
Element get_value() const
Returns the value of the element.
Definition Multi_field_small.h:432
friend bool operator==(const Integer_type v, const Multi_field_element_with_small_characteristics &f)
operator==
Definition Multi_field_small.h:262
Multi_field_element_with_small_characteristics()
Default constructor. Sets the element to 0.
Definition Multi_field_small.h:58
friend Integer_type operator-(const Integer_type &v, const Multi_field_element_with_small_characteristics &f)
operator-
Definition Multi_field_small.h:186
std::pair< 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.h:352
friend Multi_field_element_with_small_characteristics operator*(Multi_field_element_with_small_characteristics f, const Integer_type &v)
operator*
Definition Multi_field_small.h:228
friend Integer_type operator+(const Integer_type &v, Multi_field_element_with_small_characteristics f)
operator+
Definition Multi_field_small.h:130
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.h:340
friend Multi_field_element_with_small_characteristics operator+(Multi_field_element_with_small_characteristics f1, Multi_field_element_with_small_characteristics const &f2)
operator+
Definition Multi_field_small.h:92
static 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.h:401
Multi_field_element_with_small_characteristics(Integer_type element)
Constructor setting the element to the given value.
Definition Multi_field_small.h:72
friend Multi_field_element_with_small_characteristics operator-(Multi_field_element_with_small_characteristics f, const Integer_type &v)
operator-
Definition Multi_field_small.h:173
Unsigned_integer_type Element
Definition Multi_field_small.h:50
friend Multi_field_element_with_small_characteristics operator*(Multi_field_element_with_small_characteristics f1, Multi_field_element_with_small_characteristics const &f2)
operator*
Definition Multi_field_small.h:203
friend bool operator==(const Multi_field_element_with_small_characteristics &f, const Integer_type v)
operator==
Definition Multi_field_small.h:273
friend void operator+=(Multi_field_element_with_small_characteristics &f1, Multi_field_element_with_small_characteristics const &f2)
operator+=
Definition Multi_field_small.h:83
static Multi_field_element_with_small_characteristics get_additive_identity()
Returns the additive identity of a field.
Definition Multi_field_small.h:379
friend bool operator!=(const Multi_field_element_with_small_characteristics &f, const Integer_type v)
operator!=
Definition Multi_field_small.h:304
friend bool operator!=(const Multi_field_element_with_small_characteristics &f1, const Multi_field_element_with_small_characteristics &f2)
operator!=
Definition Multi_field_small.h:281
static Multi_field_element_with_small_characteristics get_multiplicative_identity()
Returns the multiplicative identity of a field.
Definition Multi_field_small.h:389
static constexpr Characteristic get_characteristic()
Returns the product of all characteristics.
Definition Multi_field_small.h:425
friend Integer_type operator*(const Integer_type &v, Multi_field_element_with_small_characteristics f)
operator*
Definition Multi_field_small.h:241
friend void operator*=(Multi_field_element_with_small_characteristics &f, const Integer_type &v)
operator*=
Definition Multi_field_small.h:217
friend Multi_field_element_with_small_characteristics operator+(Multi_field_element_with_small_characteristics f, const Integer_type &v)
operator+
Definition Multi_field_small.h:117
friend bool operator==(const Multi_field_element_with_small_characteristics &f1, const Multi_field_element_with_small_characteristics &f2)
operator==
Definition Multi_field_small.h:250
Field namespace.
Definition Intro_field_elements_and_operators.h:16
Gudhi namespace.
Definition SimplicialComplexForAlpha.h:14