Multi_field_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-24 Inria
6  *
7  * Modification(s):
8  * - YYYY/MM Author: Description of the modification
9  */
10 
17 #ifndef MATRIX_FIELD_MULTI_OPERATORS_H_
18 #define MATRIX_FIELD_MULTI_OPERATORS_H_
19 
20 #include <utility>
21 #include <vector>
22 #include <gmpxx.h>
23 #include <stdexcept>
24 
25 namespace Gudhi {
26 namespace persistence_fields {
27 
35 {
36  public:
37  using element_type = mpz_class;
43  Multi_field_operators() : productOfAllCharacteristics_(0) /* , multiplicativeID_(1) */
44  {}
51  Multi_field_operators(int minCharacteristic, int maxCharacteristic)
52  : productOfAllCharacteristics_(0) //, multiplicativeID_(1)
53  {
54  set_characteristic(minCharacteristic, maxCharacteristic);
55  }
62  : primes_(toCopy.primes_),
63  productOfAllCharacteristics_(toCopy.productOfAllCharacteristics_),
64  partials_(toCopy.partials_) /* ,
65  multiplicativeID_(toCopy.multiplicativeID_) */
66  {}
73  : primes_(std::move(toMove.primes_)),
74  productOfAllCharacteristics_(std::move(toMove.productOfAllCharacteristics_)),
75  partials_(std::move(toMove.partials_)) /* ,
76  multiplicativeID_(std::move(toMove.multiplicativeID_)) */
77  {}
78 
86  void set_characteristic(int minimum, int maximum) {
87  if (maximum < 2) throw std::invalid_argument("Characteristic must be strictly positive");
88  if (minimum > maximum) throw std::invalid_argument("The given interval is not valid.");
89  if (minimum == maximum && !_is_prime(minimum))
90  throw std::invalid_argument("The given interval does not contain a prime number.");
91 
92  unsigned int curr_prime = minimum;
93  mpz_t tmp_prime;
94  mpz_init_set_ui(tmp_prime, minimum);
95  // test if min_prime is prime
96  int is_prime = mpz_probab_prime_p(tmp_prime, 25); // probabilistic primality test
97 
98  if (is_prime == 0) { // min_prime is composite
99  mpz_nextprime(tmp_prime, tmp_prime);
100  curr_prime = mpz_get_ui(tmp_prime);
101  }
102 
103  primes_.clear();
104  while (curr_prime <= static_cast<unsigned int>(maximum)) {
105  primes_.push_back(curr_prime);
106  mpz_nextprime(tmp_prime, tmp_prime);
107  curr_prime = mpz_get_ui(tmp_prime);
108  }
109  mpz_clear(tmp_prime);
110 
111  if (primes_.empty()) throw std::invalid_argument("The given interval does not contain a prime number.");
112 
113  productOfAllCharacteristics_ = 1;
114  for (const unsigned int p : primes_) {
115  productOfAllCharacteristics_ *= p;
116  }
117 
118  partials_.resize(primes_.size());
119  for (unsigned int i = 0; i < primes_.size(); ++i) {
120  unsigned int p = primes_[i];
121  partials_[i] = productOfAllCharacteristics_ / p;
122  mpz_powm_ui(partials_[i].get_mpz_t(), partials_[i].get_mpz_t(), p - 1, productOfAllCharacteristics_.get_mpz_t());
123  }
124 
125  // If I understood the paper well, multiplicativeID_ always equals to 1. But in Clement's code,
126  // multiplicativeID_ is computed (see commented loop below). TODO: verify with Clement.
127  // for (unsigned int i = 0; i < partials_.size(); ++i) {
128  // multiplicativeID_ = (multiplicativeID_ + partials_[i]) % productOfAllCharacteristics_;
129  // }
130  }
136  const characteristic_type& get_characteristic() const { return productOfAllCharacteristics_; }
137 
147  return e;
148  }
149 
157  if (e >= productOfAllCharacteristics_ || e < -productOfAllCharacteristics_)
158  mpz_mod(e.get_mpz_t(), e.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t());
159  if (e < 0) e += productOfAllCharacteristics_;
160  }
161 
169  element_type add(element_type e1, const element_type& e2) const {
170  add_inplace(e1, e2);
171  return e1;
172  }
173 
181  void add_inplace(element_type& e1, const element_type& e2) const {
182  e1 += e2;
183  get_value_inplace(e1);
184  }
185 
194  substract_inplace_front(e1, e2);
195  return e1;
196  }
197 
205  void substract_inplace_front(element_type& e1, const element_type& e2) const {
206  e1 -= e2;
207  get_value_inplace(e1);
208  }
216  void substract_inplace_back(const element_type& e1, element_type& e2) const {
217  mpz_sub(e2.get_mpz_t(), e1.get_mpz_t(), e2.get_mpz_t());
218  get_value_inplace(e2);
219  }
220 
229  multiply_inplace(e1, e2);
230  return e1;
231  }
232 
240  void multiply_inplace(element_type& e1, const element_type& e2) const {
241  e1 *= e2;
242  get_value_inplace(e1);
243  }
244 
255  return e;
256  }
257 
268  e *= m;
269  e += a;
271  }
282  a += e * m;
284  }
285 
297  return e;
298  }
299 
310  e += a;
311  e *= m;
313  }
324  m *= e + a;
326  }
327 
336  bool are_equal(const element_type& e1, const element_type& e2) const {
337  if (e1 == e2) return true;
338  return get_value(e1) == get_value(e2);
339  }
340 
349  return get_partial_inverse(e, productOfAllCharacteristics_).first;
350  }
359  std::pair<element_type, characteristic_type> get_partial_inverse(
360  const element_type& e, const characteristic_type& productOfCharacteristics) const {
362  mpz_gcd(QR.get_mpz_t(), e.get_mpz_t(), productOfCharacteristics.get_mpz_t()); // QR <- gcd(x,QS)
363 
364  if (QR == productOfCharacteristics) return {0, get_multiplicative_identity()}; // partial inverse is 0
365 
366  characteristic_type QT = productOfCharacteristics / QR;
367 
368  characteristic_type inv_qt;
369  mpz_invert(inv_qt.get_mpz_t(), e.get_mpz_t(), QT.get_mpz_t());
370 
371  std::pair<element_type, characteristic_type> res(get_partial_multiplicative_identity(QT), QT);
372  res.first *= inv_qt;
373  get_value_inplace(res.first);
374 
375  return res;
376  }
377 
383  static const element_type& get_additive_identity() { return additiveID_; }
389  static const element_type& get_multiplicative_identity() { return multiplicativeID_; }
390 
399  if (productOfCharacteristics == 0) {
401  }
402  element_type multIdentity(0);
403  for (unsigned int idx = 0; idx < primes_.size(); ++idx) {
404  if ((productOfCharacteristics % primes_[idx]) == 0) {
405  multIdentity += partials_[idx];
406  }
407  }
408  get_value_inplace(multIdentity);
409  return multIdentity;
410  }
411 
412  // static constexpr bool handles_only_z2() { return false; }
413 
418  primes_.swap(other.primes_);
419  productOfAllCharacteristics_ = other.productOfAllCharacteristics_;
420  partials_.swap(other.partials_);
421 
422  return *this;
423  }
428  f1.primes_.swap(f2.primes_);
429  std::swap(f1.productOfAllCharacteristics_, f2.productOfAllCharacteristics_);
430  f1.partials_.swap(f2.partials_);
431  }
432 
433  private:
434  std::vector<unsigned int> primes_;
435  characteristic_type productOfAllCharacteristics_;
436  std::vector<characteristic_type> partials_;
437  inline static const element_type multiplicativeID_ = 1;
438  inline static const element_type additiveID_ = 0;
439 
440  static constexpr bool _is_prime(const int p) {
441  if (p <= 1) return false;
442  if (p <= 3) return true;
443  if (p % 2 == 0 || p % 3 == 0) return false;
444 
445  for (long i = 5; i * i <= p; i = i + 6)
446  if (p % i == 0 || p % (i + 2) == 0) return false;
447 
448  return true;
449  }
450 };
451 
452 } // namespace persistence_fields
453 } // namespace Gudhi
454 
455 #endif // MATRIX_FIELD_MULTI_OPERATORS_H_
Class defining operators for a multi-field with "consecutive" charateristic range.
Definition: Multi_field_operators.h:35
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_operators.h:86
element_type multiply(element_type e1, const element_type &e2) const
Returns the multiplication of two elements in the field.
Definition: Multi_field_operators.h:228
friend void swap(Multi_field_operators &f1, Multi_field_operators &f2)
Swap operator.
Definition: Multi_field_operators.h:427
Multi_field_operators()
Default constructor, sets the product of all characteristics to 0.
Definition: Multi_field_operators.h:43
element_type get_partial_multiplicative_identity(const characteristic_type &productOfCharacteristics) const
Returns the partial multiplicative identity of the multi-field from the given product....
Definition: Multi_field_operators.h:398
void substract_inplace_front(element_type &e1, const element_type &e2) const
Stores in the first element the substraction in the field of the first element by the second element,...
Definition: Multi_field_operators.h:205
std::pair< element_type, characteristic_type > get_partial_inverse(const element_type &e, const characteristic_type &productOfCharacteristics) const
Returns the inverse of the given element in the multi-field corresponding to the given sub-product of...
Definition: Multi_field_operators.h:359
mpz_class element_type
Definition: Multi_field_operators.h:37
element_type characteristic_type
Definition: Multi_field_operators.h:38
void multiply_and_add_inplace_back(const element_type &e, const element_type &m, element_type &a) const
Multiplies the first element with the second one and adds the third one, that is (e * m + a) % produc...
Definition: Multi_field_operators.h:281
void multiply_and_add_inplace_front(element_type &e, const element_type &m, const element_type &a) const
Multiplies the first element with the second one and adds the third one, that is (e * m + a) % produc...
Definition: Multi_field_operators.h:267
Multi_field_operators & operator=(Multi_field_operators other)
Assign operator.
Definition: Multi_field_operators.h:417
bool are_equal(const element_type &e1, const element_type &e2) const
Returns true if the two given elements are equal in the field, false otherwise.
Definition: Multi_field_operators.h:336
element_type get_value(element_type 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_operators.h:145
element_type substract(element_type e1, const element_type &e2) const
Returns the substraction in the field of the first element by the second element.
Definition: Multi_field_operators.h:193
void add_inplace(element_type &e1, const element_type &e2) const
Stores in the first element the sum of two given elements in the field, that is (e1 + e2) % productOf...
Definition: Multi_field_operators.h:181
Multi_field_operators(const Multi_field_operators &toCopy)
Copy constructor.
Definition: Multi_field_operators.h:61
void get_value_inplace(element_type &e) const
Stores in the given element the value of this element in the field. That is the positive value of the...
Definition: Multi_field_operators.h:156
element_type add(element_type e1, const element_type &e2) const
Returns the sum of two elements in the field.
Definition: Multi_field_operators.h:169
element_type multiply_and_add(element_type e, const element_type &m, const element_type &a) const
Multiplies the first element with the second one and adds the third one. Returns the result in the fi...
Definition: Multi_field_operators.h:253
void add_and_multiply_inplace_front(element_type &e, const element_type &a, const element_type &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_operators.h:309
static const element_type & get_multiplicative_identity()
Returns the multiplicative identity of a field.
Definition: Multi_field_operators.h:389
static const element_type & get_additive_identity()
Returns the additive identity of a field.
Definition: Multi_field_operators.h:383
element_type add_and_multiply(element_type e, const element_type &a, const element_type &m) const
Adds the first element to the second one and multiplies the third one with it. Returns the result in ...
Definition: Multi_field_operators.h:295
const characteristic_type & get_characteristic() const
Returns the current characteristics as the product of all of them.
Definition: Multi_field_operators.h:136
void substract_inplace_back(const element_type &e1, element_type &e2) const
Stores in the second element the substraction in the field of the first element by the second element...
Definition: Multi_field_operators.h:216
element_type get_inverse(const element_type &e) const
Returns the inverse of the given element in the sense of with respect to the product of all characte...
Definition: Multi_field_operators.h:348
Multi_field_operators(int minCharacteristic, int maxCharacteristic)
Constructor setting the characteristics to all prime numbers between the two given integers.
Definition: Multi_field_operators.h:51
void multiply_inplace(element_type &e1, const element_type &e2) const
Stores in the first element the multiplication of two given elements in the field,...
Definition: Multi_field_operators.h:240
Multi_field_operators(Multi_field_operators &&toMove) noexcept
Move constructor.
Definition: Multi_field_operators.h:72
void add_and_multiply_inplace_back(const element_type &e, const element_type &a, element_type &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_operators.h:323
Gudhi namespace.
Definition: SimplicialComplexForAlpha.h:14