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
25namespace Gudhi {
26namespace persistence_fields {
27
35{
36 public:
37 using Element = 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& get_characteristic() const { return productOfAllCharacteristics_; }
137
147 return e;
148 }
149
156 void get_value_inplace(Element& e) const {
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 add(Element e1, const Element& e2) const {
170 add_inplace(e1, e2);
171 return e1;
172 }
173
181 void add_inplace(Element& e1, const Element& e2) const {
182 e1 += e2;
184 }
185
193 Element subtract(Element e1, const Element& e2) const {
195 return e1;
196 }
197
205 void subtract_inplace_front(Element& e1, const Element& e2) const {
206 e1 -= e2;
208 }
216 void subtract_inplace_back(const Element& e1, Element& e2) const {
217 mpz_sub(e2.get_mpz_t(), e1.get_mpz_t(), e2.get_mpz_t());
219 }
220
228 Element multiply(Element e1, const Element& e2) const {
229 multiply_inplace(e1, e2);
230 return e1;
231 }
232
240 void multiply_inplace(Element& e1, const Element& e2) const {
241 e1 *= e2;
243 }
244
253 Element multiply_and_add(Element e, const Element& m, const Element& a) const {
255 return e;
256 }
257
267 void multiply_and_add_inplace_front(Element& e, const Element& m, const Element& a) const {
268 e *= m;
269 e += a;
271 }
281 void multiply_and_add_inplace_back(const Element& e, const Element& m, Element& a) const {
282 a += e * m;
284 }
285
295 Element add_and_multiply(Element e, const Element& a, const Element& m) const {
297 return e;
298 }
299
309 void add_and_multiply_inplace_front(Element& e, const Element& a, const Element& m) const {
310 e += a;
311 e *= m;
313 }
323 void add_and_multiply_inplace_back(const Element& e, const Element& a, Element& m) const {
324 m *= e + a;
326 }
327
336 bool are_equal(const Element& e1, const Element& e2) const {
337 if (e1 == e2) return true;
338 return get_value(e1) == get_value(e2);
339 }
340
348 Element get_inverse(const Element& e) const {
349 return get_partial_inverse(e, productOfAllCharacteristics_).first;
350 }
359 std::pair<Element, Characteristic> get_partial_inverse(
360 const Element& e, const Characteristic& 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 QT = productOfCharacteristics / QR;
367
368 Characteristic inv_qt;
369 mpz_invert(inv_qt.get_mpz_t(), e.get_mpz_t(), QT.get_mpz_t());
370
371 std::pair<Element, Characteristic> 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& get_additive_identity() { return additiveID_; }
389 static const Element& get_multiplicative_identity() { return multiplicativeID_; }
390
398 Element get_partial_multiplicative_identity(const Characteristic& productOfCharacteristics) const {
399 if (productOfCharacteristics == 0) {
401 }
402 Element 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 productOfAllCharacteristics_;
436 std::vector<Characteristic> partials_;
437 inline static const Element multiplicativeID_ = 1;
438 inline static const Element 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" characteristic range.
Definition: Multi_field_operators.h:35
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:323
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
static const Element & get_multiplicative_identity()
Returns the multiplicative identity of a field.
Definition: Multi_field_operators.h:389
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
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:336
Element Characteristic
Definition: Multi_field_operators.h:38
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:267
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:205
const Characteristic & get_characteristic() const
Returns the current characteristics as the product of all of them.
Definition: Multi_field_operators.h:136
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:216
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:281
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:240
Multi_field_operators & operator=(Multi_field_operators other)
Assign operator.
Definition: Multi_field_operators.h:417
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:253
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:156
static const Element & get_additive_identity()
Returns the additive identity of a field.
Definition: Multi_field_operators.h:383
Multi_field_operators(const Multi_field_operators &toCopy)
Copy constructor.
Definition: Multi_field_operators.h:61
mpz_class Element
Definition: Multi_field_operators.h:37
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:359
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:193
Element multiply(Element e1, const Element &e2) const
Returns the multiplication of two elements in the field.
Definition: Multi_field_operators.h:228
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:181
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:145
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:309
Element get_inverse(const Element &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
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:295
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
Element add(Element e1, const Element &e2) const
Returns the sum of two elements in the field.
Definition: Multi_field_operators.h:169
Multi_field_operators(Multi_field_operators &&toMove) noexcept
Move constructor.
Definition: Multi_field_operators.h:72
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:398
Gudhi namespace.
Definition: SimplicialComplexForAlpha.h:14