Multi_field.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_H_
18 #define MATRIX_FIELD_MULTI_H_
19 
20 #include <utility>
21 #include <vector>
22 #include <gmpxx.h>
23 #include <stdexcept>
24 
25 namespace Gudhi {
26 namespace persistence_fields {
27 
38 template <unsigned int minimum, unsigned int maximum>
40  public:
41  using element_type = mpz_class;
53  Multi_field_element(const element_type& element);
65  Multi_field_element(Multi_field_element&& toMove) noexcept;
66 
70  friend void operator+=(Multi_field_element& f1, Multi_field_element const& f2) {
71  f1.element_ += f2.element_;
72  mpz_mod(f1.element_.get_mpz_t(), f1.element_.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t());
73  }
78  f1 += f2;
79  return f1;
80  }
84  friend void operator+=(Multi_field_element& f, const element_type& v) {
85  f.element_ += v;
86  mpz_mod(f.element_.get_mpz_t(), f.element_.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t());
87  }
92  f += v;
93  return f;
94  }
99  v += f.element_;
100  mpz_mod(v.get_mpz_t(), v.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t());
101  return v;
102  }
103 
107  friend void operator-=(Multi_field_element& f1, Multi_field_element const& f2) {
108  f1.element_ -= f2.element_;
109  mpz_mod(f1.element_.get_mpz_t(), f1.element_.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t());
110  }
115  f1 -= f2;
116  return f1;
117  }
121  friend void operator-=(Multi_field_element& f, const element_type& v) {
122  f.element_ -= v;
123  mpz_mod(f.element_.get_mpz_t(), f.element_.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t());
124  }
129  f -= v;
130  return f;
131  }
136  // element_type e(v);
137  if (v >= productOfAllCharacteristics_)
138  mpz_mod(v.get_mpz_t(), v.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t());
139  if (f.element_ > v) v += productOfAllCharacteristics_;
140  v -= f.element_;
141  return v;
142  }
143 
147  friend void operator*=(Multi_field_element& f1, Multi_field_element const& f2) {
148  f1.element_ *= f2.element_;
149  mpz_mod(f1.element_.get_mpz_t(), f1.element_.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t());
150  }
155  f1 *= f2;
156  return f1;
157  }
161  friend void operator*=(Multi_field_element& f, const element_type& v) {
162  f.element_ *= v;
163  mpz_mod(f.element_.get_mpz_t(), f.element_.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t());
164  }
169  f *= v;
170  return f;
171  }
176  v *= f.element_;
177  mpz_mod(v.get_mpz_t(), v.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t());
178  return v;
179  }
180 
184  friend bool operator==(const Multi_field_element& f1, const Multi_field_element& f2) {
185  return f1.element_ == f2.element_;
186  }
190  friend bool operator==(const element_type& v, const Multi_field_element& f) {
191  if (v < productOfAllCharacteristics_) return v == f.element_;
192  element_type e(v);
193  mpz_mod(e.get_mpz_t(), e.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t());
194  return e == f.element_;
195  }
199  friend bool operator==(const Multi_field_element& f, const element_type& v) {
200  if (v < productOfAllCharacteristics_) return v == f.element_;
201  element_type e(v);
202  mpz_mod(e.get_mpz_t(), e.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t());
203  return e == f.element_;
204  }
208  friend bool operator!=(const Multi_field_element& f1, const Multi_field_element& f2) { return !(f1 == f2); }
212  friend bool operator!=(const element_type& v, const Multi_field_element& f) { return !(v == f); }
216  friend bool operator!=(const Multi_field_element& f, const element_type& v) { return !(v == f); }
217 
229  friend void swap(Multi_field_element& f1, Multi_field_element& f2) { std::swap(f1.element_, f2.element_); }
230 
234  operator unsigned int() const;
238  operator mpz_class() const;
239 
253  std::pair<Multi_field_element, characteristic_type> get_partial_inverse(
254  const characteristic_type& productOfCharacteristics) const;
255 
275  static Multi_field_element get_partial_multiplicative_identity(const characteristic_type& productOfCharacteristics);
282 
288  element_type get_value() const;
289 
290  // static constexpr bool handles_only_z2() { return false; }
291 
292  private:
293  element_type element_;
294  static inline const std::vector<unsigned int> primes_ = []() {
295  std::vector<unsigned int> res;
296 
297  unsigned int curr_prime = minimum;
298  mpz_t tmp_prime;
299  mpz_init_set_ui(tmp_prime, minimum);
300  // test if min_prime is prime
301  int is_prime = mpz_probab_prime_p(tmp_prime, 25); // probabilistic primality test
302 
303  if (is_prime == 0) { // min_prime is composite
304  mpz_nextprime(tmp_prime, tmp_prime);
305  curr_prime = mpz_get_ui(tmp_prime);
306  }
307 
308  while (curr_prime <= maximum) {
309  res.push_back(curr_prime);
310  mpz_nextprime(tmp_prime, tmp_prime);
311  curr_prime = mpz_get_ui(tmp_prime);
312  }
313  mpz_clear(tmp_prime);
314 
315  return res;
316  }();
317  static inline const characteristic_type productOfAllCharacteristics_ = []() {
318  characteristic_type res = 1;
319  for (const auto p : primes_) {
320  res *= p;
321  }
322 
323  return res;
324  }();
325  static inline const std::vector<characteristic_type> partials_ = []() {
326  std::vector<characteristic_type> res;
327 
328  if (productOfAllCharacteristics_ == 1) return res;
329 
330  for (unsigned int i = 0; i < primes_.size(); ++i) {
331  unsigned int p = primes_[i];
332  res.push_back(productOfAllCharacteristics_ / p);
333  mpz_powm_ui(res.back().get_mpz_t(), res.back().get_mpz_t(), p - 1, productOfAllCharacteristics_.get_mpz_t());
334  }
335 
336  return res;
337  }();
338  // If I understood the paper well, multiplicativeID_ always equals to 1. But in Clement's code,
339  // multiplicativeID_ is computed (see commented lambda function below). TODO: verify with Clement.
340  static inline const element_type multiplicativeID_ = 1; /*[](){
341  mpz_class res = 0;
342  for (unsigned int i = 0; i < partials_.size(); ++i){
343  res = (res + partials_[i]) % productOfAllCharacteristics_;
344  }
345 
346  return res;
347  }();*/
348 
349  static constexpr bool _is_prime(const int p);
350 };
351 
352 template <unsigned int minimum, unsigned int maximum>
354  static_assert(maximum >= 2, "Characteristics have to be positive.");
355  static_assert(minimum <= maximum, "The given interval is not valid.");
356  static_assert(minimum != maximum || _is_prime(minimum), "The given interval does not contain a prime number.");
357 
358  if (productOfAllCharacteristics_ == 1)
359  throw std::runtime_error("The given interval does not contain a prime number.");
360 }
361 
362 template <unsigned int minimum, unsigned int maximum>
364  static_assert(maximum >= 2, "Characteristics has to be positive.");
365  static_assert(minimum <= maximum, "The given interval is not valid.");
366  static_assert(minimum != maximum || _is_prime(minimum), "The given interval does not contain a prime number.");
367 
368  if (productOfAllCharacteristics_ == 1)
369  throw std::runtime_error("The given interval does not contain a prime number.");
370 
371  mpz_mod(element_.get_mpz_t(), element_.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t());
372 }
373 
374 template <unsigned int minimum, unsigned int maximum>
376  : element_(toCopy.element_) {}
377 
378 template <unsigned int minimum, unsigned int maximum>
380  Multi_field_element<minimum, maximum>&& toMove) noexcept
381  : element_(std::move(toMove.element_)) {}
382 
383 template <unsigned int minimum, unsigned int maximum>
385  Multi_field_element other) {
386  std::swap(element_, other.element_);
387  return *this;
388 }
389 
390 template <unsigned int minimum, unsigned int maximum>
392  const element_type& value) {
393  mpz_mod(element_.get_mpz_t(), value.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t());
394  return *this;
395 }
396 
397 template <unsigned int minimum, unsigned int maximum>
399  return element_.get_ui();
400 }
401 
402 template <unsigned int minimum, unsigned int maximum>
404  return element_;
405 }
406 
407 template <unsigned int minimum, unsigned int maximum>
409  return get_partial_inverse(productOfAllCharacteristics_).first;
410 }
411 
412 template <unsigned int minimum, unsigned int maximum>
413 inline std::pair<Multi_field_element<minimum, maximum>,
417  mpz_gcd(QR.get_mpz_t(), element_.get_mpz_t(), productOfCharacteristics.get_mpz_t()); // QR <- gcd(x,QS)
418 
419  if (QR == productOfCharacteristics) return {Multi_field_element(), multiplicativeID_}; // partial inverse is 0
420 
421  characteristic_type QT = productOfCharacteristics / QR;
422 
423  characteristic_type inv_qt;
424  mpz_invert(inv_qt.get_mpz_t(), element_.get_mpz_t(), QT.get_mpz_t());
425 
426  auto res = get_partial_multiplicative_identity(QT);
427  res *= inv_qt;
428 
429  return {res, QT};
430 }
431 
432 template <unsigned int minimum, unsigned int maximum>
435 }
436 
437 template <unsigned int minimum, unsigned int maximum>
439  return Multi_field_element<minimum, maximum>(multiplicativeID_);
440 }
441 
442 template <unsigned int minimum, unsigned int maximum>
444  const characteristic_type& productOfCharacteristics) {
445  if (productOfCharacteristics == 0) {
446  return Multi_field_element<minimum, maximum>(multiplicativeID_);
447  }
449  for (unsigned int idx = 0; idx < primes_.size(); ++idx) {
450  if ((productOfCharacteristics % primes_[idx]) == 0) {
451  mult += partials_[idx];
452  }
453  }
454  return mult;
455 }
456 
457 template <unsigned int minimum, unsigned int maximum>
460  return productOfAllCharacteristics_;
461 }
462 
463 template <unsigned int minimum, unsigned int maximum>
465  const {
466  return element_;
467 }
468 
469 template <unsigned int minimum, unsigned int maximum>
470 inline constexpr bool Multi_field_element<minimum, maximum>::_is_prime(const int p) {
471  if (p <= 1) return false;
472  if (p <= 3) return true;
473  if (p % 2 == 0 || p % 3 == 0) return false;
474 
475  for (long i = 5; i * i <= p; i = i + 6)
476  if (p % i == 0 || p % (i + 2) == 0) return false;
477 
478  return true;
479 }
480 
481 } // namespace persistence_fields
482 } // namespace Gudhi
483 
484 #endif // MATRIX_FIELD_MULTI_H_
Class representing an element of a multi-field. The characteristics will corresponds to all prime num...
Definition: Multi_field.h:39
friend element_type operator-(element_type v, Multi_field_element const &f)
operator-
Definition: Multi_field.h:135
friend element_type operator*(element_type v, Multi_field_element const &f)
operator*
Definition: Multi_field.h:175
friend Multi_field_element operator+(Multi_field_element f, const element_type &v)
operator+
Definition: Multi_field.h:91
std::pair< Multi_field_element, characteristic_type > get_partial_inverse(const characteristic_type &productOfCharacteristics) const
Returns the inverse of the element with respect to a sub-product of the characteristics in the multi-...
Definition: Multi_field.h:415
friend Multi_field_element operator-(Multi_field_element f1, Multi_field_element const &f2)
operator-
Definition: Multi_field.h:114
static Multi_field_element get_additive_identity()
Returns the additive identity of a field.
Definition: Multi_field.h:433
friend bool operator==(const Multi_field_element &f, const element_type &v)
operator==
Definition: Multi_field.h:199
friend Multi_field_element operator+(Multi_field_element f1, Multi_field_element const &f2)
operator+
Definition: Multi_field.h:77
mpz_class element_type
Definition: Multi_field.h:41
static Multi_field_element get_multiplicative_identity()
Returns the multiplicative identity of a field.
Definition: Multi_field.h:438
friend void operator+=(Multi_field_element &f1, Multi_field_element const &f2)
operator+=
Definition: Multi_field.h:70
static characteristic_type get_characteristic()
Returns the product of all characteristics.
Definition: Multi_field.h:459
friend bool operator!=(const element_type &v, const Multi_field_element &f)
operator!=
Definition: Multi_field.h:212
friend Multi_field_element operator*(Multi_field_element f, const element_type &v)
operator*
Definition: Multi_field.h:168
friend Multi_field_element operator-(Multi_field_element f, const element_type &v)
operator-
Definition: Multi_field.h:128
friend void operator-=(Multi_field_element &f, const element_type &v)
operator-=
Definition: Multi_field.h:121
friend element_type operator+(element_type v, Multi_field_element const &f)
operator+
Definition: Multi_field.h:98
friend bool operator!=(const Multi_field_element &f1, const Multi_field_element &f2)
operator!=
Definition: Multi_field.h:208
friend Multi_field_element operator*(Multi_field_element f1, Multi_field_element const &f2)
operator*
Definition: Multi_field.h:154
friend bool operator!=(const Multi_field_element &f, const element_type &v)
operator!=
Definition: Multi_field.h:216
friend void operator+=(Multi_field_element &f, const element_type &v)
operator+=
Definition: Multi_field.h:84
friend void swap(Multi_field_element &f1, Multi_field_element &f2)
Swap operator.
Definition: Multi_field.h:229
element_type characteristic_type
Definition: Multi_field.h:42
friend bool operator==(const element_type &v, const Multi_field_element &f)
operator==
Definition: Multi_field.h:190
Multi_field_element()
Default constructor. Sets the element to 0.
Definition: Multi_field.h:353
Multi_field_element & operator=(Multi_field_element other)
Assign operator.
Definition: Multi_field.h:384
friend void operator*=(Multi_field_element &f, const element_type &v)
operator*=
Definition: Multi_field.h:161
element_type get_value() const
Returns the value of the element.
Definition: Multi_field.h:464
Multi_field_element get_inverse() const
Returns the inverse of the element in the multi-field, see .
Definition: Multi_field.h:408
friend bool operator==(const Multi_field_element &f1, const Multi_field_element &f2)
operator==
Definition: Multi_field.h:184
static Multi_field_element get_partial_multiplicative_identity(const characteristic_type &productOfCharacteristics)
Returns the partial multiplicative identity of the multi-field from the given product....
Definition: Multi_field.h:443
friend void operator*=(Multi_field_element &f1, Multi_field_element const &f2)
operator*=
Definition: Multi_field.h:147
friend void operator-=(Multi_field_element &f1, Multi_field_element const &f2)
operator-=
Definition: Multi_field.h:107
Gudhi namespace.
Definition: SimplicialComplexForAlpha.h:14