Loading...
Searching...
No Matches
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 Inria
6 *
7 * Modification(s):
8 * - YYYY/MM Author: Description of the modification
9 */
10
16
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#include <gudhi/Debug_utils.h>
26
27namespace Gudhi {
28namespace persistence_fields {
29
37{
38 public:
39 using Element = mpz_class;
41
42 inline static const Characteristic nullCharacteristic = 0;
43
47 Multi_field_operators() : productOfAllCharacteristics_(nullCharacteristic) /* , multiplicativeID_(1) */ {}
48
55 Multi_field_operators(int minCharacteristic, int maxCharacteristic)
56 : productOfAllCharacteristics_(nullCharacteristic) //, multiplicativeID_(1)
57 {
58 set_characteristic(minCharacteristic, maxCharacteristic);
59 }
60
68 void set_characteristic(int minimum, int maximum)
69 {
70 if (maximum < 2) throw std::invalid_argument("Characteristic must be strictly positive");
71 if (minimum > maximum) throw std::invalid_argument("The given interval is not valid.");
72 if (minimum == maximum && !_is_prime(minimum))
73 throw std::invalid_argument("The given interval does not contain a prime number.");
74
75 unsigned int curr_prime = minimum;
76 mpz_t tmp_prime;
77 mpz_init_set_ui(tmp_prime, minimum);
78 // test if min_prime is prime
79 int is_prime = mpz_probab_prime_p(tmp_prime, 25); // probabilistic primality test
80
81 if (is_prime == 0) { // min_prime is composite
82 mpz_nextprime(tmp_prime, tmp_prime);
83 curr_prime = mpz_get_ui(tmp_prime);
84 }
85
86 primes_.clear();
87 while (curr_prime <= static_cast<unsigned int>(maximum)) {
88 primes_.push_back(curr_prime);
89 mpz_nextprime(tmp_prime, tmp_prime);
90 curr_prime = mpz_get_ui(tmp_prime);
91 }
92 mpz_clear(tmp_prime);
93
94 if (primes_.empty()) throw std::invalid_argument("The given interval does not contain a prime number.");
95
96 productOfAllCharacteristics_ = 1;
97 for (const unsigned int p : primes_) {
98 productOfAllCharacteristics_ *= p;
99 }
100
101 partials_.resize(primes_.size());
102 for (unsigned int i = 0; i < primes_.size(); ++i) {
103 unsigned int p = primes_[i];
104 partials_[i] = productOfAllCharacteristics_ / p;
105 mpz_powm_ui(partials_[i].get_mpz_t(), partials_[i].get_mpz_t(), p - 1, productOfAllCharacteristics_.get_mpz_t());
106 }
107
108 // If I understood the paper well, multiplicativeID_ always equals to 1. But in Clement's code,
109 // multiplicativeID_ is computed (see commented loop below). TODO: verify with Clement.
110 // for (unsigned int i = 0; i < partials_.size(); ++i) {
111 // multiplicativeID_ = (multiplicativeID_ + partials_[i]) % productOfAllCharacteristics_;
112 // }
113 }
114
120 [[nodiscard]] const Characteristic& get_characteristic() const { return productOfAllCharacteristics_; }
121
129 [[nodiscard]] Element get_value(Element e) const
130 {
132 return e;
133 }
134
142 {
143 if (e >= productOfAllCharacteristics_ || e < -productOfAllCharacteristics_)
144 mpz_mod(e.get_mpz_t(), e.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t());
145 if (e < 0) e += productOfAllCharacteristics_;
146 }
147
155 [[nodiscard]] Element add(Element e1, const Element& e2) const
156 {
157 add_inplace(e1, e2);
158 return e1;
159 }
160
168 void add_inplace(Element& e1, const Element& e2) const
169 {
170 e1 += e2;
172 }
173
181 [[nodiscard]] Element subtract(Element e1, const Element& e2) const
182 {
184 return e1;
185 }
186
194 void subtract_inplace_front(Element& e1, const Element& e2) const
195 {
196 e1 -= e2;
198 }
199
207 void subtract_inplace_back(const Element& e1, Element& e2) const
208 {
209 mpz_sub(e2.get_mpz_t(), e1.get_mpz_t(), e2.get_mpz_t());
211 }
212
220 [[nodiscard]] Element multiply(Element e1, const Element& e2) const
221 {
222 multiply_inplace(e1, e2);
223 return e1;
224 }
225
233 void multiply_inplace(Element& e1, const Element& e2) const
234 {
235 e1 *= e2;
237 }
238
247 [[nodiscard]] Element multiply_and_add(Element e, const Element& m, const Element& a) const
248 {
250 return e;
251 }
252
262 void multiply_and_add_inplace_front(Element& e, const Element& m, const Element& a) const
263 {
264 e *= m;
265 e += a;
267 }
268
278 void multiply_and_add_inplace_back(const Element& e, const Element& m, Element& a) const
279 {
280 a += e * m;
282 }
283
293 [[nodiscard]] Element add_and_multiply(Element e, const Element& a, const Element& m) const
294 {
296 return e;
297 }
298
308 void add_and_multiply_inplace_front(Element& e, const Element& a, const Element& m) const
309 {
310 e += a;
311 e *= m;
313 }
314
324 void add_and_multiply_inplace_back(const Element& e, const Element& a, Element& m) const
325 {
326 m *= e + a;
328 }
329
338 bool are_equal(const Element& e1, const Element& e2) const
339 {
340 if (e1 == e2) return true;
341 return get_value(e1) == get_value(e2);
342 }
343
351 [[nodiscard]] Element get_inverse(const Element& e) const
352 {
353 return get_partial_inverse(e, productOfAllCharacteristics_).first;
354 }
355
364 [[nodiscard]] std::pair<Element, Characteristic> get_partial_inverse(
365 const Element& e,
366 const Characteristic& productOfCharacteristics) const
367 {
368 GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_,
369 std::invalid_argument(
370 "The given product is not the product of a subset of the current Multi-field characteristics."));
371
373 mpz_gcd(QR.get_mpz_t(), e.get_mpz_t(), productOfCharacteristics.get_mpz_t()); // QR <- gcd(x,QS)
374
375 if (QR == productOfCharacteristics) return {0, get_multiplicative_identity()}; // partial inverse is 0
376
377 Characteristic QT = productOfCharacteristics / QR;
378
379 Characteristic inv_qt;
380 mpz_invert(inv_qt.get_mpz_t(), e.get_mpz_t(), QT.get_mpz_t());
381
382 std::pair<Element, Characteristic> res(get_partial_multiplicative_identity(QT), QT);
383 res.first *= inv_qt;
384 get_value_inplace(res.first);
385
386 return res;
387 }
388
394 static const Element& get_additive_identity() { return additiveID_; }
395
401 static const Element& get_multiplicative_identity() { return multiplicativeID_; }
402
410 [[nodiscard]] Element get_partial_multiplicative_identity(const Characteristic& productOfCharacteristics) const
411 {
412 GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_,
413 std::invalid_argument(
414 "The given product is not the product of a subset of the current Multi-field characteristics."));
415
416 if (productOfCharacteristics == nullCharacteristic || productOfCharacteristics == productOfAllCharacteristics_) {
418 }
419 Element multIdentity(0);
420 for (unsigned int idx = 0; idx < primes_.size(); ++idx) {
421 if ((productOfCharacteristics % primes_[idx]) == 0) {
422 multIdentity += partials_[idx];
423 }
424 }
425 get_value_inplace(multIdentity);
426 return multIdentity;
427 }
428
432 friend void swap(Multi_field_operators& f1, Multi_field_operators& f2) noexcept
433 {
434 f1.primes_.swap(f2.primes_);
435 std::swap(f1.productOfAllCharacteristics_, f2.productOfAllCharacteristics_);
436 f1.partials_.swap(f2.partials_);
437 }
438
439 private:
440 std::vector<unsigned int> primes_;
441 Characteristic productOfAllCharacteristics_;
442 std::vector<Characteristic> partials_;
443 inline static const Element multiplicativeID_ = 1;
444 inline static const Element additiveID_ = 0;
445
446 static constexpr bool _is_prime(const int p)
447 {
448 if (p <= 1) return false;
449 if (p <= 3) return true;
450 if (p % 2 == 0 || p % 3 == 0) return false;
451
452 for (long i = 5; i * i <= p; i = i + 6)
453 if (p % i == 0 || p % (i + 2) == 0) return false;
454
455 return true;
456 }
457};
458
459} // namespace persistence_fields
460} // namespace Gudhi
461
462#endif // MATRIX_FIELD_MULTI_OPERATORS_H_
void add_and_multiply_inplace_back(const Element &e, const Element &a, Element &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:324
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:68
static const Element & get_multiplicative_identity()
Returns the multiplicative identity of a field.
Definition Multi_field_operators.h:401
Multi_field_operators()
Default constructor, sets the product of all characteristics to 0.
Definition Multi_field_operators.h:47
bool are_equal(const Element &e1, const Element &e2) const
Returns true if the two given elements are equal in the field, false otherwise.
Definition Multi_field_operators.h:338
Element Characteristic
Definition Multi_field_operators.h:40
void multiply_and_add_inplace_front(Element &e, const Element &m, const Element &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:262
void subtract_inplace_front(Element &e1, const Element &e2) const
Stores in the first element the subtraction in the field of the first element by the second element,...
Definition Multi_field_operators.h:194
const Characteristic & get_characteristic() const
Returns the current characteristics as the product of all of them.
Definition Multi_field_operators.h:120
void subtract_inplace_back(const Element &e1, Element &e2) const
Stores in the second element the subtraction in the field of the first element by the second element,...
Definition Multi_field_operators.h:207
void multiply_and_add_inplace_back(const Element &e, const Element &m, Element &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:278
void multiply_inplace(Element &e1, const Element &e2) const
Stores in the first element the multiplication of two given elements in the field,...
Definition Multi_field_operators.h:233
Element multiply_and_add(Element e, const Element &m, const Element &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:247
void get_value_inplace(Element &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:141
static const Element & get_additive_identity()
Returns the additive identity of a field.
Definition Multi_field_operators.h:394
mpz_class Element
Definition Multi_field_operators.h:39
std::pair< Element, Characteristic > get_partial_inverse(const Element &e, const Characteristic &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:364
Element subtract(Element e1, const Element &e2) const
Returns the subtraction in the field of the first element by the second element.
Definition Multi_field_operators.h:181
static const Characteristic nullCharacteristic
Definition Multi_field_operators.h:42
Element multiply(Element e1, const Element &e2) const
Returns the multiplication of two elements in the field.
Definition Multi_field_operators.h:220
void add_inplace(Element &e1, const Element &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:168
Element get_value(Element 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:129
void add_and_multiply_inplace_front(Element &e, const Element &a, const Element &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:308
friend void swap(Multi_field_operators &f1, Multi_field_operators &f2) noexcept
Swap operator.
Definition Multi_field_operators.h:432
Element get_inverse(const Element &e) const
Returns the inverse of the given element in the sense of boissonnat:hal-00922572 with respect to the ...
Definition Multi_field_operators.h:351
Element add_and_multiply(Element e, const Element &a, const Element &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:293
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:55
Element add(Element e1, const Element &e2) const
Returns the sum of two elements in the field.
Definition Multi_field_operators.h:155
Element get_partial_multiplicative_identity(const Characteristic &productOfCharacteristics) const
Returns the partial multiplicative identity of the multi-field from the given product....
Definition Multi_field_operators.h:410
Field namespace.
Definition Intro_field_elements_and_operators.h:16
Gudhi namespace.
Definition SimplicialComplexForAlpha.h:14