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
25namespace Gudhi {
26namespace persistence_fields {
27
38template <unsigned int minimum, unsigned int maximum>
40 public:
41 using Element = mpz_class;
53 Multi_field_element(const Element& element);
66
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& 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
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& 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 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
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& 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& v, const Multi_field_element& f) {
191 if (v < productOfAllCharacteristics_) return v == f.element_;
192 Element 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& v) {
200 if (v < productOfAllCharacteristics_) return v == f.element_;
201 Element 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& v, const Multi_field_element& f) { return !(v == f); }
216 friend bool operator!=(const Multi_field_element& f, const Element& 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> get_partial_inverse(
254 const Characteristic& productOfCharacteristics) const;
255
275 static Multi_field_element get_partial_multiplicative_identity(const Characteristic& productOfCharacteristics);
282
288 Element get_value() const;
289
290 // static constexpr bool handles_only_z2() { return false; }
291
292 private:
293 Element 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 productOfAllCharacteristics_ = []() {
318 Characteristic res = 1;
319 for (const auto p : primes_) {
320 res *= p;
321 }
322
323 return res;
324 }();
325 static inline const std::vector<Characteristic> partials_ = []() {
326 std::vector<Characteristic> 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 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
352template <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
362template <unsigned int minimum, unsigned int maximum>
363inline Multi_field_element<minimum, maximum>::Multi_field_element(const Element& element) : element_(element) {
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
374template <unsigned int minimum, unsigned int maximum>
376 : element_(toCopy.element_) {}
377
378template <unsigned int minimum, unsigned int maximum>
381 : element_(std::move(toMove.element_)) {}
382
383template <unsigned int minimum, unsigned int maximum>
385 Multi_field_element other) {
386 std::swap(element_, other.element_);
387 return *this;
388}
389
390template <unsigned int minimum, unsigned int maximum>
392 const Element& value) {
393 mpz_mod(element_.get_mpz_t(), value.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t());
394 return *this;
395}
396
397template <unsigned int minimum, unsigned int maximum>
399 return element_.get_ui();
400}
401
402template <unsigned int minimum, unsigned int maximum>
404 return element_;
405}
406
407template <unsigned int minimum, unsigned int maximum>
409 return get_partial_inverse(productOfAllCharacteristics_).first;
410}
411
412template <unsigned int minimum, unsigned int maximum>
413inline 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 QT = productOfCharacteristics / QR;
422
423 Characteristic 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
432template <unsigned int minimum, unsigned int maximum>
435}
436
437template <unsigned int minimum, unsigned int maximum>
439 return Multi_field_element<minimum, maximum>(multiplicativeID_);
440}
441
442template <unsigned int minimum, unsigned int maximum>
444 const Characteristic& 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
457template <unsigned int minimum, unsigned int maximum>
460 return productOfAllCharacteristics_;
461}
462
463template <unsigned int minimum, unsigned int maximum>
465 const {
466 return element_;
467}
468
469template <unsigned int minimum, unsigned int maximum>
470inline 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 bool operator!=(const Multi_field_element &f, const Element &v)
operator!=
Definition: Multi_field.h:216
mpz_class Element
Definition: Multi_field.h:41
Element Characteristic
Definition: Multi_field.h:42
friend Multi_field_element operator-(Multi_field_element f1, Multi_field_element const &f2)
operator-
Definition: Multi_field.h:114
friend bool operator==(const Multi_field_element &f, const Element &v)
operator==
Definition: Multi_field.h:199
static Multi_field_element get_additive_identity()
Returns the additive identity of a field.
Definition: Multi_field.h:433
friend Multi_field_element operator+(Multi_field_element f1, Multi_field_element const &f2)
operator+
Definition: Multi_field.h:77
friend bool operator!=(const Element &v, const Multi_field_element &f)
operator!=
Definition: Multi_field.h:212
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
friend void operator*=(Multi_field_element &f, const Element &v)
operator*=
Definition: Multi_field.h:161
friend Multi_field_element operator*(Multi_field_element f, const Element &v)
operator*
Definition: Multi_field.h:168
static Characteristic get_characteristic()
Returns the product of all characteristics.
Definition: Multi_field.h:459
friend bool operator!=(const Multi_field_element &f1, const Multi_field_element &f2)
operator!=
Definition: Multi_field.h:208
friend Element operator+(Element v, Multi_field_element const &f)
operator+
Definition: Multi_field.h:98
friend Multi_field_element operator*(Multi_field_element f1, Multi_field_element const &f2)
operator*
Definition: Multi_field.h:154
friend bool operator==(const Element &v, const Multi_field_element &f)
operator==
Definition: Multi_field.h:190
friend Multi_field_element operator+(Multi_field_element f, const Element &v)
operator+
Definition: Multi_field.h:91
friend Element operator*(Element v, Multi_field_element const &f)
operator*
Definition: Multi_field.h:175
friend void swap(Multi_field_element &f1, Multi_field_element &f2)
Swap operator.
Definition: Multi_field.h:229
Multi_field_element()
Default constructor. Sets the element to 0.
Definition: Multi_field.h:353
friend Element operator-(Element v, Multi_field_element const &f)
operator-
Definition: Multi_field.h:135
friend void operator+=(Multi_field_element &f, const Element &v)
operator+=
Definition: Multi_field.h:84
Multi_field_element & operator=(Multi_field_element other)
Assign operator.
Definition: Multi_field.h:384
friend void operator-=(Multi_field_element &f, const Element &v)
operator-=
Definition: Multi_field.h:121
Element 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
std::pair< Multi_field_element, Characteristic > get_partial_inverse(const Characteristic &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 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
static Multi_field_element get_partial_multiplicative_identity(const Characteristic &productOfCharacteristics)
Returns the partial multiplicative identity of the multi-field from the given product....
Definition: Multi_field.h:443
friend Multi_field_element operator-(Multi_field_element f, const Element &v)
operator-
Definition: Multi_field.h:128
Gudhi namespace.
Definition: SimplicialComplexForAlpha.h:14