Hypercomplex
Abstract & fast header-only C++ template library for lattice-based cryptosystems in high-dimensional algebras
Loading...
Searching...
No Matches
Hypercomplex_MPFR.hpp
Go to the documentation of this file.
1// Copyright 2020 <Maciek Bak>
3/*
4###############################################################################
5#
6# Hypercomplex header-only library.
7# Explicit template specialisation & function overloading for mpfr_t type
8#
9# AUTHOR: Maciek_Bak
10# AFFILIATION: Department_of_Mathematics_City_University_of_London
11# CONTACT: wsciekly.maciek@gmail.com
12# CREATED: 05-08-2023
13# LICENSE: Apache 2.0
14#
15###############################################################################
16*/
17
18// mark that we included this library
19#ifndef HYPERCOMPLEX_HYPERCOMPLEX_MPFR_HPP_
20#define HYPERCOMPLEX_HYPERCOMPLEX_MPFR_HPP_
21
22#include "./Hypercomplex.hpp"
23
24static uint64_t MPFR_global_precision;
25
30 return MPFR_global_precision;
31}
32
36void set_mpfr_precision(uint64_t n) {
37 MPFR_global_precision = n;
38}
39
43 mpfr_free_cache();
44 assert(!mpfr_mp_memory_cleanup());
45}
46
49template <const uint64_t dim>
50class Hypercomplex<mpfr_t, dim> {
51 private:
52 mpfr_t* arr = new mpfr_t[dim]; // NOLINT
53 static inline uint64_t** baseprodabs;
54 static inline bool** baseprodpos;
55
56 public:
59 static void init() {
60 int64_t** M = new int64_t*[dim];
61 for (uint64_t i = 0; i < dim; i++) M[i] = new int64_t[dim];
62 M[0][0] = 1;
63 uint64_t n = 1;
64 while (n != dim) {
65 for (uint64_t i=0; i < n; i++) {
66 for (uint64_t j=0; j < n; j++) {
67 M[i][n+j] = M[j][i] > 0 ? M[j][i] + n : M[j][i] - n;
68 M[i+n][j] = M[i][j] > 0 ? M[i][j] + n : M[i][j] - n;
69 M[i+n][j] = M[i+n][j] * (j ? -1 : 1);
70 M[i+n][j+n] = -M[j][i] * (j ? -1 : 1);
71 }
72 }
73 n *= 2;
74 }
75 baseprodabs = new uint64_t*[dim];
76 baseprodpos = new bool*[dim];
77 for (uint64_t i = 0; i < dim; i++) {
78 baseprodabs[i] = new uint64_t[dim];
79 baseprodpos[i] = new bool[dim];
80 }
81 for (uint64_t i=0; i < dim; i++) {
82 for (uint64_t j=0; j < dim; j++) {
83 baseprodabs[i][j] = std::abs(M[i][j]) - 1;
84 baseprodpos[i][j] = (0 < M[i][j]);
85 }
86 }
87 for (uint64_t i = 0; i < dim; i++) {
88 delete[] M[i];
89 }
90 delete[] M;
91 }
92
95 static void clear() {
96 for (uint64_t i = 0; i < dim; i++) {
97 delete[] baseprodabs[i];
98 delete[] baseprodpos[i];
99 }
100 delete[] baseprodabs;
101 delete[] baseprodpos;
102 }
103
110 const Hypercomplex &H1,
111 const Hypercomplex &H2
112 ) {
113 mpfr_t prod;
114 mpfr_init2(prod, MPFR_global_precision);
115 mpfr_t temparr[dim]; // NOLINT
116 for (uint64_t i=0; i < dim; i++)
117 mpfr_init2(temparr[i], MPFR_global_precision);
118 for (uint64_t i=0; i < dim; i++) mpfr_set_zero(temparr[i], 0);
119 for (uint64_t i=0; i < dim; i++) {
120 for (uint64_t j=0; j < dim; j++) {
121 mpfr_mul(prod, H1[i], H2[j], MPFR_RNDN);
122 if (Hypercomplex::baseprodpos[i][j]) {
123 mpfr_add(
124 temparr[Hypercomplex::baseprodabs[i][j]],
125 temparr[Hypercomplex::baseprodabs[i][j]],
126 prod,
127 MPFR_RNDN);
128 } else {
129 mpfr_sub(
130 temparr[Hypercomplex::baseprodabs[i][j]],
131 temparr[Hypercomplex::baseprodabs[i][j]],
132 prod,
133 MPFR_RNDN);
134 }
135 }
136 }
137 Hypercomplex H(temparr);
138 for (uint64_t i=0; i < dim; i++) mpfr_clear(temparr[i]);
139 mpfr_clear(prod);
140 return H;
141 }
142
149 explicit Hypercomplex(const mpfr_t* ARR) {
150 if (dim == 0) {
151 delete[] arr;
152 throw std::invalid_argument("invalid dimension");
153 }
154 if ((dim & (dim - 1)) != 0) {
155 delete[] arr;
156 throw std::invalid_argument("invalid dimension");
157 }
158 for (uint64_t i=0; i < dim; i++)
159 mpfr_init2(arr[i], MPFR_global_precision);
160 for (uint64_t i=0; i < dim; i++)
161 mpfr_set(arr[i], ARR[i], MPFR_RNDN);
162 }
163
171 for (uint64_t i=0; i < dim; i++)
172 mpfr_init2(arr[i], MPFR_global_precision);
173 for (uint64_t i=0; i < dim; i++)
174 mpfr_set(arr[i], H[i], MPFR_RNDN);
175 }
176
177 Hypercomplex() = delete;
178
179 ~Hypercomplex() {
180 for (uint64_t i=0; i < dim; i++) mpfr_clear(arr[i]);
181 delete[] arr;
182 }
183
187 uint64_t _() const { return dim; }
188
198 int32_t norm(mpfr_t norm) const {
199 mpfr_t temp;
200 mpfr_init2(temp, MPFR_global_precision);
201 mpfr_set_zero(norm, 0);
202 for (uint64_t i=0; i < dim; i++) {
203 mpfr_mul(temp, arr[i], arr[i], MPFR_RNDN);
204 mpfr_add(norm, norm, temp, MPFR_RNDN);
205 }
206 mpfr_sqrt(norm, norm, MPFR_RNDN);
207 mpfr_clear(temp);
208 return 0;
209 }
210
215 mpfr_t zero, norm;
216 mpfr_init2(zero, MPFR_global_precision);
217 mpfr_init2(norm, MPFR_global_precision);
218 mpfr_set_zero(zero, 0);
219 (*this).norm(norm);
220 if (mpfr_equal_p(norm, zero)) {
221 mpfr_clear(zero);
222 mpfr_clear(norm);
223 throw std::invalid_argument("division by zero");
224 } else {
225 mpfr_t temparr[dim]; // NOLINT
226 for (uint64_t i=0; i < dim; i++)
227 mpfr_init2(temparr[i], MPFR_global_precision);
228 mpfr_mul(norm, norm, norm, MPFR_RNDN);
229 mpfr_div(temparr[0], arr[0], norm, MPFR_RNDN);
230 for (uint64_t i=1; i < dim; i++) {
231 mpfr_div(temparr[i], arr[i], norm, MPFR_RNDN);
232 mpfr_sub(temparr[i], zero, temparr[i], MPFR_RNDN);
233 }
234 Hypercomplex<mpfr_t, dim> H(temparr);
235 mpfr_clear(zero);
236 mpfr_clear(norm);
237 for (uint64_t i=0; i < dim; i++) mpfr_clear(temparr[i]);
238 return H;
239 }
240 }
241
248 template <const uint64_t newdim>
250 if (newdim <= dim) throw std::invalid_argument("invalid dimension");
251 mpfr_t temparr[newdim]; // NOLINT
252 for (uint64_t i=0; i < newdim; i++)
253 mpfr_init2(temparr[i], MPFR_global_precision);
254 for (uint64_t i=0; i < dim; i++)
255 mpfr_set(temparr[i], arr[i], MPFR_RNDN);
256 for (uint64_t i=dim; i < newdim; i++) mpfr_set_zero(temparr[i], 0);
258 for (uint64_t i=0; i < newdim; i++) mpfr_clear(temparr[i]);
259 return H;
260 }
261
266 mpfr_t zero;
267 mpfr_init2(zero, MPFR_global_precision);
268 mpfr_set_zero(zero, 0);
269 mpfr_t temparr[dim]; // NOLINT
270 for (uint64_t i=0; i < dim; i++)
271 mpfr_init2(temparr[i], MPFR_global_precision);
272 mpfr_set(temparr[0], arr[0], MPFR_RNDN);
273 for (uint64_t i=1; i < dim; i++)
274 mpfr_sub(temparr[i], zero, arr[i], MPFR_RNDN);
275 Hypercomplex<mpfr_t, dim> H(temparr);
276 for (uint64_t i=0; i < dim; i++) mpfr_clear(temparr[i]);
277 mpfr_clear(zero);
278 return H;
279 }
280
285 mpfr_t zero;
286 mpfr_init2(zero, MPFR_global_precision);
287 mpfr_set_zero(zero, 0);
288 mpfr_t temparr[dim]; // NOLINT
289 for (uint64_t i=0; i < dim; i++)
290 mpfr_init2(temparr[i], MPFR_global_precision);
291 for (uint64_t i=0; i < dim; i++)
292 mpfr_sub(temparr[i], zero, arr[i], MPFR_RNDN);
293 Hypercomplex<mpfr_t, dim> H(temparr);
294 for (uint64_t i=0; i < dim; i++) mpfr_clear(temparr[i]);
295 mpfr_clear(zero);
296 return H;
297 }
298
304 if (this == &H) return *this;
305 for (uint64_t i=0; i < dim; i++)
306 mpfr_set(arr[i], H[i], MPFR_RNDN);
307 return *this;
308 }
309
314 mpfr_t const & operator[] (const uint64_t i) const {
315 assert(0 <= i && i < dim);
316 return arr[i];
317 }
318
323 mpfr_t & operator[] (const uint64_t i) {
324 assert(0 <= i && i < dim);
325 return arr[i];
326 }
327
333 Hypercomplex<mpfr_t, dim> result = (*this) + H;
334 for (uint64_t i=0; i < dim; i++)
335 mpfr_set((*this)[i], result[i], MPFR_RNDN);
336 return *this;
337 }
338
344 Hypercomplex<mpfr_t, dim> result = (*this) - H;
345 for (uint64_t i=0; i < dim; i++)
346 mpfr_set((*this)[i], result[i], MPFR_RNDN);
347 return *this;
348 }
349
355 Hypercomplex<mpfr_t, dim> result = (*this) * H;
356 for (uint64_t i=0; i < dim; i++)
357 mpfr_set((*this)[i], result[i], MPFR_RNDN);
358 return *this;
359 }
360
365 Hypercomplex& operator^= (const uint64_t x) {
366 Hypercomplex<mpfr_t, dim> result = (*this) ^ x;
367 for (uint64_t i=0; i < dim; i++)
368 mpfr_set((*this)[i], result[i], MPFR_RNDN);
369 return *this;
370 }
371
377 Hypercomplex<mpfr_t, dim> result = (*this) / H;
378 for (uint64_t i=0; i < dim; i++)
379 mpfr_set((*this)[i], result[i], MPFR_RNDN);
380 return *this;
381 }
382};
383
389template <const uint64_t dim>
393) {
394 for (uint64_t i=0; i < dim; i++) {
395 if (!mpfr_equal_p(H1[i], H2[i])) return false;
396 }
397 return true;
398}
399
405template <const uint64_t dim>
409) {
410 return !(H1 == H2);
411}
412
418template <const uint64_t dim>
422) {
423 mpfr_t temparr[dim]; // NOLINT
424 for (uint64_t i=0; i < dim; i++)
425 mpfr_init2(temparr[i], MPFR_global_precision);
426 for (uint64_t i=0; i < dim; i++)
427 mpfr_add(temparr[i], H1[i], H2[i], MPFR_RNDN);
428 Hypercomplex<mpfr_t, dim> H(temparr);
429 for (uint64_t i=0; i < dim; i++) mpfr_clear(temparr[i]);
430 return H;
431}
432
438template <const uint64_t dim>
442) {
443 mpfr_t temparr[dim]; // NOLINT
444 for (uint64_t i=0; i < dim; i++)
445 mpfr_init2(temparr[i], MPFR_global_precision);
446 for (uint64_t i=0; i < dim; i++)
447 mpfr_sub(temparr[i], H1[i], H2[i], MPFR_RNDN);
448 Hypercomplex<mpfr_t, dim> H(temparr);
449 for (uint64_t i=0; i < dim; i++) mpfr_clear(temparr[i]);
450 return H;
451}
452
458template <const uint64_t dim>
462) {
463 // recursion base:
464 if constexpr (dim == 1) {
465 mpfr_t result;
466 mpfr_init2(result, MPFR_global_precision);
467 mpfr_mul(result, H1[0], H2[0], MPFR_RNDN);
468 mpfr_t temparr[1];
469 mpfr_init2(temparr[0], MPFR_global_precision);
470 mpfr_set(temparr[0], result, MPFR_RNDN);
471 Hypercomplex<mpfr_t, 1> H_(temparr);
472 mpfr_clear(result);
473 mpfr_clear(temparr[0]);
474 return H_;
475 // recursion step:
476 } else {
477 // shared objects:
478 const uint64_t halfd = dim / 2;
479 mpfr_t temparr[dim]; // NOLINT
480 for (uint64_t i=0; i < dim; i++)
481 mpfr_init2(temparr[i], MPFR_global_precision);
482 // construct helper objects:
483 for (uint64_t i=0; i < halfd; i++)
484 mpfr_set(temparr[i], H1[i], MPFR_RNDN);
485 Hypercomplex<mpfr_t, halfd> H1a(temparr);
486 for (uint64_t i=0; i < halfd; i++)
487 mpfr_set(temparr[i], H1[i+halfd], MPFR_RNDN);
488 Hypercomplex<mpfr_t, halfd> H1b(temparr);
489 for (uint64_t i=0; i < halfd; i++)
490 mpfr_set(temparr[i], H2[i], MPFR_RNDN);
491 Hypercomplex<mpfr_t, halfd> H2a(temparr);
492 for (uint64_t i=0; i < halfd; i++)
493 mpfr_set(temparr[i], H2[i+halfd], MPFR_RNDN);
494 Hypercomplex<mpfr_t, halfd> H2b(temparr);
495 // multiply recursively:
496 Hypercomplex<mpfr_t, halfd> H1a2a = H1a * H2a;
497 Hypercomplex<mpfr_t, halfd> H2b_1b = ~H2b * H1b;
498 Hypercomplex<mpfr_t, halfd> H2b1a = H2b * H1a;
499 Hypercomplex<mpfr_t, halfd> H1b2a_ = H1b * ~H2a;
500 // construct the final object
501 Hypercomplex<mpfr_t, halfd> Ha = H1a2a - H2b_1b;
502 Hypercomplex<mpfr_t, halfd> Hb = H2b1a + H1b2a_;
503 for (uint64_t i=0; i < halfd; i++)
504 mpfr_set(temparr[i], Ha[i], MPFR_RNDN);
505 for (uint64_t i=0; i < halfd; i++)
506 mpfr_set(temparr[i+halfd], Hb[i], MPFR_RNDN);
507 Hypercomplex<mpfr_t, dim> H(temparr);
508 for (uint64_t i=0; i < dim; i++) mpfr_clear(temparr[i]);
509 return H;
510 }
511}
512
518template <const uint64_t dim>
521 const uint64_t x
522) {
523 if (!(x)) {
524 throw std::invalid_argument("zero is not a valid argument");
525 } else {
527 for (uint64_t i=0; i < x-1; i++) Hx *= H;
528 return Hx;
529 }
530}
531
537template <const uint64_t dim>
541) {
542 Hypercomplex<mpfr_t, dim> H = H1 * H2.inv();
543 return(H);
544}
545
551template <const uint64_t dim>
552std::ostream& operator<<(
553 std::ostream &os,
555) {
556 mpfr_exp_t exponent = 0;
557 char* outstr;
558 for (uint64_t i=0; i < dim - 1; i++) {
559 outstr = mpfr_get_str(NULL, &exponent, 10, 0, H[i], MPFR_RNDN);
560 os << outstr << "E" << exponent << " ";
561 mpfr_free_str(outstr);
562 }
563 outstr = mpfr_get_str(NULL, &exponent, 10, 0, H[dim - 1], MPFR_RNDN);
564 os << outstr << "E" << exponent;
565 mpfr_free_str(outstr);
566 return os;
567}
568
573template <const uint64_t dim>
575 Hypercomplex<mpfr_t, dim> result = H;
576 for (uint64_t i=1; i < dim; i++) mpfr_set_zero(result[i], 0);
577 return result;
578}
579
584template <const uint64_t dim>
586 Hypercomplex<mpfr_t, dim> result = H;
587 mpfr_set_zero(result[0], 0);
588 return result;
589}
590
595template <const uint64_t dim>
597 Hypercomplex<mpfr_t, dim> result = Im(H);
598 mpfr_t zero, norm, expreal;
599 mpfr_init2(zero, MPFR_global_precision);
600 mpfr_init2(norm, MPFR_global_precision);
601 mpfr_init2(expreal, MPFR_global_precision);
602 mpfr_set_zero(zero, 0);
603 result.norm(norm);
604 mpfr_exp(expreal, H[0], MPFR_RNDN);
605
606 if (mpfr_equal_p(norm, zero)) {
607 mpfr_set(result[0], expreal, MPFR_RNDN);
608 for (uint64_t i=1; i < dim; i++) mpfr_set_zero(result[i], 0);
609 } else {
610 mpfr_t sinv_v;
611 mpfr_init2(sinv_v, MPFR_global_precision);
612 mpfr_sin(sinv_v, norm, MPFR_RNDN);
613 mpfr_div(sinv_v, sinv_v, norm, MPFR_RNDN);
614 for (uint64_t i=0; i < dim; i++) {
615 mpfr_mul(result[i], result[i], sinv_v, MPFR_RNDN);
616 }
617 mpfr_cos(norm, norm, MPFR_RNDN);
618 mpfr_add(result[0], result[0], norm, MPFR_RNDN);
619 for (uint64_t i=0; i < dim; i++) {
620 mpfr_mul(result[i], result[i], expreal, MPFR_RNDN);
621 }
622 mpfr_clear(sinv_v);
623 }
624 mpfr_clear(zero);
625 mpfr_clear(norm);
626 mpfr_clear(expreal);
627 return result;
628}
629
630#endif // HYPERCOMPLEX_HYPERCOMPLEX_MPFR_HPP_
std::ostream & operator<<(std::ostream &os, const Hypercomplex< mpfr_t, dim > &H)
Print operator.
Definition: Hypercomplex_MPFR.hpp:552
uint64_t get_mpfr_precision()
Getter for the global precision of the MPFR variables.
Definition: Hypercomplex_MPFR.hpp:29
Hypercomplex< mpfr_t, dim > Re(const Hypercomplex< mpfr_t, dim > &H)
Real part of a hypercomplex number.
Definition: Hypercomplex_MPFR.hpp:574
void clear_mpfr_memory()
Wrapper for MPFR memory cleanup.
Definition: Hypercomplex_MPFR.hpp:42
bool operator!=(const Hypercomplex< mpfr_t, dim > &H1, const Hypercomplex< mpfr_t, dim > &H2)
Inequality operator.
Definition: Hypercomplex_MPFR.hpp:406
bool operator==(const Hypercomplex< mpfr_t, dim > &H1, const Hypercomplex< mpfr_t, dim > &H2)
Equality operator.
Definition: Hypercomplex_MPFR.hpp:390
Hypercomplex< mpfr_t, dim > operator/(const Hypercomplex< mpfr_t, dim > &H1, const Hypercomplex< mpfr_t, dim > &H2)
Division operator.
Definition: Hypercomplex_MPFR.hpp:538
Hypercomplex< mpfr_t, dim > exp(const Hypercomplex< mpfr_t, dim > &H)
Exponentiation operation on a hypercomplex number.
Definition: Hypercomplex_MPFR.hpp:596
void set_mpfr_precision(uint64_t n)
Setter for the global precision of the MPFR variables.
Definition: Hypercomplex_MPFR.hpp:36
Hypercomplex< mpfr_t, dim > operator+(const Hypercomplex< mpfr_t, dim > &H1, const Hypercomplex< mpfr_t, dim > &H2)
Addition operator.
Definition: Hypercomplex_MPFR.hpp:419
Hypercomplex< mpfr_t, dim > Im(const Hypercomplex< mpfr_t, dim > &H)
Imaginary part of a hypercomplex number.
Definition: Hypercomplex_MPFR.hpp:585
Hypercomplex< mpfr_t, dim > operator-(const Hypercomplex< mpfr_t, dim > &H1, const Hypercomplex< mpfr_t, dim > &H2)
Subtraction operator.
Definition: Hypercomplex_MPFR.hpp:439
Hypercomplex< mpfr_t, dim > operator^(const Hypercomplex< mpfr_t, dim > &H, const uint64_t x)
Power operator.
Definition: Hypercomplex_MPFR.hpp:519
Hypercomplex< mpfr_t, dim > operator*(const Hypercomplex< mpfr_t, dim > &H1, const Hypercomplex< mpfr_t, dim > &H2)
Multiplication operator.
Definition: Hypercomplex_MPFR.hpp:459
static void clear()
Cleanup function: free all memory.
Definition: Hypercomplex_MPFR.hpp:95
Hypercomplex(const Hypercomplex &H)
This is the copy constructor.
Definition: Hypercomplex_MPFR.hpp:170
Hypercomplex inv() const
Calculate inverse of a given number.
Definition: Hypercomplex_MPFR.hpp:214
Hypercomplex(const mpfr_t *ARR)
This is the main constructor.
Definition: Hypercomplex_MPFR.hpp:149
Hypercomplex< mpfr_t, newdim > expand() const
Cast a number into a higher dimension.
Definition: Hypercomplex_MPFR.hpp:249
static Hypercomplex MUL(const Hypercomplex &H1, const Hypercomplex &H2)
Optimised multiplication function.
Definition: Hypercomplex_MPFR.hpp:109
static void init()
Basis multiplication table initialiser.
Definition: Hypercomplex_MPFR.hpp:59
int32_t norm(mpfr_t norm) const
Calculate Euclidean norm of a number.
Definition: Hypercomplex_MPFR.hpp:198
uint64_t _() const
Dimensionality getter.
Definition: Hypercomplex_MPFR.hpp:187
Definition: Hypercomplex.hpp:48
Hypercomplex & operator^=(const uint64_t x)
Power-Assignment operator.
Definition: Hypercomplex.hpp:608
Hypercomplex & operator+=(const Hypercomplex &H)
Addition-Assignment operator.
Definition: Hypercomplex.hpp:578
Hypercomplex operator~() const
Create a complex conjugate.
Definition: Hypercomplex.hpp:421
Hypercomplex & operator/=(const Hypercomplex &H)
Division-Assignment operator.
Definition: Hypercomplex.hpp:618
Hypercomplex & operator=(const Hypercomplex &H)
Assignment operator.
Definition: Hypercomplex.hpp:440
T norm() const
Calculate Euclidean norm of a number.
Definition: Hypercomplex.hpp:384
T const & operator[](const uint64_t i) const
Access operator (const)
Definition: Hypercomplex.hpp:453
Hypercomplex operator-() const
Create an additive inverse of a given number.
Definition: Hypercomplex.hpp:431
Hypercomplex & operator*=(const Hypercomplex &H)
Multiplication-Assignment operator.
Definition: Hypercomplex.hpp:598
Hypercomplex & operator-=(const Hypercomplex &H)
Subtraction-Assignment operator.
Definition: Hypercomplex.hpp:588
Hypercomplex inv() const
Calculate inverse of a given number.
Definition: Hypercomplex.hpp:392