18#ifndef HYPERCOMPLEX_HYPERCOMPLEX_HPP_
19#define HYPERCOMPLEX_HYPERCOMPLEX_HPP_
47template <
typename T, const u
int64_t dim>
51 static inline uint64_t** baseprodabs;
52 static inline bool** baseprodpos;
58 int64_t** M =
new int64_t*[dim];
59 for (uint64_t i = 0; i < dim; i++) M[i] =
new int64_t[dim];
63 for (uint64_t i=0; i < n; i++) {
64 for (uint64_t j=0; j < n; j++) {
65 M[i][n+j] = M[j][i] > 0 ? M[j][i] + n : M[j][i] - n;
66 M[i+n][j] = M[i][j] > 0 ? M[i][j] + n : M[i][j] - n;
67 M[i+n][j] = M[i+n][j] * (j ? -1 : 1);
68 M[i+n][j+n] = -M[j][i] * (j ? -1 : 1);
73 baseprodabs =
new uint64_t*[dim];
74 baseprodpos =
new bool*[dim];
75 for (uint64_t i = 0; i < dim; i++) {
76 baseprodabs[i] =
new uint64_t[dim];
77 baseprodpos[i] =
new bool[dim];
79 for (uint64_t i=0; i < dim; i++) {
80 for (uint64_t j=0; j < dim; j++) {
81 baseprodabs[i][j] = std::abs(M[i][j]) - 1;
82 baseprodpos[i][j] = (0 < M[i][j]);
85 for (uint64_t i = 0; i < dim; i++) {
94 for (uint64_t i = 0; i < dim; i++) {
95 delete[] baseprodabs[i];
96 delete[] baseprodpos[i];
112 for (uint64_t i=0; i < dim; i++) temp[i] = T();
113 for (uint64_t i=0; i < dim; i++) {
114 for (uint64_t j=0; j < dim; j++) {
115 if (Hypercomplex::baseprodpos[i][j]) {
116 temp[Hypercomplex::baseprodabs[i][j]] =
117 temp[Hypercomplex::baseprodabs[i][j]] + H1[i] * H2[j];
119 temp[Hypercomplex::baseprodabs[i][j]] =
120 temp[Hypercomplex::baseprodabs[i][j]] - H1[i] * H2[j];
153 uint64_t
_()
const {
return dim; }
174 template <const u
int64_t newdim>
200 T
const &
operator[] (
const uint64_t i)
const;
247template <
typename T, const u
int64_t dim>
258template <
typename T, const u
int64_t dim>
269template <
typename T, const u
int64_t dim>
280template <
typename T, const u
int64_t dim>
291template <
typename T, const u
int64_t dim>
302template <
typename T, const u
int64_t dim>
313template <
typename T, const u
int64_t dim>
324template <
typename T, const u
int64_t dim>
331template <
typename T, const u
int64_t dim>
338template <
typename T, const u
int64_t dim>
345template <
typename T, const u
int64_t dim>
357template <
typename T, const u
int64_t dim>
361 throw std::invalid_argument(
"invalid dimension");
363 if ((dim & (dim - 1)) != 0) {
365 throw std::invalid_argument(
"invalid dimension");
367 for (uint64_t i=0; i < dim; i++) arr[i] = ARR[i];
371template <
typename T, const u
int64_t dim>
373 for (uint64_t i=0; i < dim; i++) arr[i] = H[i];
377template <
typename T, const u
int64_t dim>
383template <
typename T, const u
int64_t dim>
386 for (uint64_t i=0; i < dim; i++) result += arr[i] * arr[i];
391template <
typename T, const u
int64_t dim>
394 T norm = (*this).norm();
396 throw std::invalid_argument(
"division by zero");
399 temparr[0] = arr[0] / (norm * norm);
400 for (uint64_t i=1; i < dim; i++)
401 temparr[i] = -arr[i] / (norm * norm);
408template <
typename T, const u
int64_t dim>
409template <const u
int64_t newdim>
411 if (newdim <= dim)
throw std::invalid_argument(
"invalid dimension");
413 for (uint64_t i=0; i < dim; i++) temparr[i] = arr[i];
414 for (uint64_t i=dim; i < newdim; i++) temparr[i] = 0;
420template <
typename T, const u
int64_t dim>
424 for (uint64_t i=1; i < dim; i++) temparr[i] = -arr[i];
430template <
typename T, const u
int64_t dim>
433 for (uint64_t i=0; i < dim; i++) temparr[i] = -arr[i];
439template <
typename T, const u
int64_t dim>
444 if (
this == &H)
return *
this;
446 for (uint64_t i=0; i < dim; i++) arr[i] = H[i];
452template <
typename T, const u
int64_t dim>
454 assert(0 <= i && i < dim);
459template <
typename T, const u
int64_t dim>
461 assert(0 <= i && i < dim);
466template <
typename T, const u
int64_t dim>
471 for (uint64_t i=0; i < dim; i++) {
472 if (H1[i] != H2[i])
return false;
478template <
typename T, const u
int64_t dim>
487template <
typename T, const u
int64_t dim>
493 for (uint64_t i=0; i < dim; i++) temparr[i] = H1[i] + H2[i];
499template <
typename T, const u
int64_t dim>
505 for (uint64_t i=0; i < dim; i++) temparr[i] = H1[i] - H2[i];
511template <
typename T, const u
int64_t dim>
517 if constexpr (dim == 1) {
518 T temparr[] = { H1[0] * H2[0] };
524 const uint64_t halfd = dim / 2;
527 for (uint64_t i=0; i < halfd; i++) temparr[i] = H1[i];
529 for (uint64_t i=0; i < halfd; i++) temparr[i] = H1[i+halfd];
531 for (uint64_t i=0; i < halfd; i++) temparr[i] = H2[i];
533 for (uint64_t i=0; i < halfd; i++) temparr[i] = H2[i+halfd];
543 for (uint64_t i=0; i < halfd; i++) temparr[i] = Ha[i];
544 for (uint64_t i=0; i < halfd; i++) temparr[i+halfd] = Hb[i];
551template <
typename T, const u
int64_t dim>
557 throw std::invalid_argument(
"zero is not a valid argument");
560 for (uint64_t i=0; i < x-1; i++) Hx *= H;
566template <
typename T, const u
int64_t dim>
577template <
typename T, const u
int64_t dim>
582 for (uint64_t i=0; i < dim; i++) (*
this)[i] = result[i];
587template <
typename T, const u
int64_t dim>
592 for (uint64_t i=0; i < dim; i++) (*
this)[i] = result[i];
597template <
typename T, const u
int64_t dim>
602 for (uint64_t i=0; i < dim; i++) (*
this)[i] = result[i];
607template <
typename T, const u
int64_t dim>
612 for (uint64_t i=0; i < dim; i++) (*
this)[i] = result[i];
617template <
typename T, const u
int64_t dim>
622 for (uint64_t i=0; i < dim; i++) (*
this)[i] = result[i];
627template <
typename T, const u
int64_t dim>
629 for (uint64_t i=0; i < dim - 1; i++) os << H[i] <<
" ";
635template <
typename T, const u
int64_t dim>
638 for (uint64_t i=1; i < dim; i++) result[i] = T();
643template <
typename T, const u
int64_t dim>
651template <
typename T, const u
int64_t dim>
655 T norm = result.
norm();
657 result[0] =
exp(H[0]);
658 for (uint64_t i=1; i < dim; i++) result[i] = zero;
660 T sinv_v = sin(norm) / norm;
661 for (uint64_t i=0; i < dim; i++) result[i] *= sinv_v;
662 result[0] += cos(norm);
663 for (uint64_t i=0; i < dim; i++) result[i] *=
exp(H[0]);
678template <const u
int64_t MaxDeg, const u
int64_t dim>
682 static inline uint64_t** baseprodabs;
683 static inline bool** baseprodpos;
689 int64_t** M =
new int64_t*[dim];
690 for (uint64_t i = 0; i < dim; i++) M[i] =
new int64_t[dim];
694 for (uint64_t i=0; i < n; i++) {
695 for (uint64_t j=0; j < n; j++) {
696 M[i][n+j] = M[j][i] > 0 ? M[j][i] + n : M[j][i] - n;
697 M[i+n][j] = M[i][j] > 0 ? M[i][j] + n : M[i][j] - n;
698 M[i+n][j] = M[i+n][j] * (j ? -1 : 1);
699 M[i+n][j+n] = -M[j][i] * (j ? -1 : 1);
704 baseprodabs =
new uint64_t*[dim];
705 baseprodpos =
new bool*[dim];
706 for (uint64_t i = 0; i < dim; i++) {
707 baseprodabs[i] =
new uint64_t[dim];
708 baseprodpos[i] =
new bool[dim];
710 for (uint64_t i=0; i < dim; i++) {
711 for (uint64_t j=0; j < dim; j++) {
712 baseprodabs[i][j] = std::abs(M[i][j]) - 1;
713 baseprodpos[i][j] = (0 < M[i][j]);
716 for (uint64_t i = 0; i < dim; i++) {
725 for (uint64_t i = 0; i < dim; i++) {
726 delete[] baseprodabs[i];
727 delete[] baseprodpos[i];
729 delete[] baseprodabs;
730 delete[] baseprodpos;
743 for (uint64_t i=0; i < dim; i++) {
744 for (uint64_t j=0; j < dim; j++) {
745 if (Hypercomplex::baseprodpos[i][j]) {
746 temp[Hypercomplex::baseprodabs[i][j]] =
747 temp[Hypercomplex::baseprodabs[i][j]] + H1[i] * H2[j];
749 temp[Hypercomplex::baseprodabs[i][j]] =
750 temp[Hypercomplex::baseprodabs[i][j]] - H1[i] * H2[j];
767 throw std::invalid_argument(
"invalid dimension");
769 if ((dim & (dim - 1)) != 0) {
771 throw std::invalid_argument(
"invalid dimension");
773 for (uint64_t i=0; i < dim; i++) arr[i] = ARR[i];
783 for (uint64_t i=0; i < dim; i++) arr[i] = H[i];
795 uint64_t
_()
const {
return dim; }
797 #ifndef DOXYGEN_SHOULD_SKIP_THIS
806 for (uint64_t i=0; i < dim; i++) {
807 norm2 = norm2 + arr[i] * arr[i];
818 template <const u
int64_t newdim>
820 if (newdim <= dim)
throw std::invalid_argument(
"invalid dimension");
823 for (uint64_t i=0; i < dim; i++) temparr[i] = arr[i];
824 for (uint64_t i=dim; i < newdim; i++) temparr[i] = zero;
834 assert(0 <= i && i < dim);
843 assert(0 <= i && i < dim);
853 for (uint64_t i=1; i < dim; i++) temparr[i] = -arr[i];
863 for (uint64_t i=0; i < dim; i++) temparr[i] = -arr[i];
873 if (
this == &H)
return *
this;
874 for (uint64_t i=0; i < dim; i++) arr[i] = H[i];
884 for (uint64_t i=0; i < dim; i++) (*
this)[i] = result[i];
894 for (uint64_t i=0; i < dim; i++) (*
this)[i] = result[i];
905 for (uint64_t i=0; i < dim; i++) (*
this)[i] = result[i];
915 for (uint64_t i=0; i < dim; i++) (*
this)[i] = result[i];
925 for (uint64_t i=0; i < dim; i++) (*
this)[i] = result[i];
935 for (uint64_t i=0; i < dim; i++) (*
this)[i] = result[i];
939 #ifndef DOXYGEN_SHOULD_SKIP_THIS
949template <const u
int64_t MaxDeg, const u
int64_t dim>
954 for (uint64_t i=0; i < dim; i++) {
955 if (H1[i] != H2[i])
return false;
965template <const u
int64_t MaxDeg, const u
int64_t dim>
978template <const u
int64_t MaxDeg, const u
int64_t dim>
984 for (uint64_t i=0; i < dim; i++) temparr[i] = H1[i] + H2[i];
994template <const u
int64_t MaxDeg, const u
int64_t dim>
1000 for (uint64_t i=0; i < dim; i++) temparr[i] = H1[i] - H2[i];
1006#ifndef DOXYGEN_SHOULD_SKIP_THIS
1007template <const u
int64_t MaxDeg, const u
int64_t dim>
1019template <const u
int64_t MaxDeg, const u
int64_t dim>
1024 for (uint64_t i=0; i < dim - 1; i++) os << H[i] << std::endl;
1034template <const u
int64_t MaxDeg, const u
int64_t dim>
1040 for (uint64_t i=0; i < dim; i++) temparr[i] = x * H[i];
1050template <const u
int64_t MaxDeg, const u
int64_t dim>
1056 for (uint64_t i=0; i < dim; i++) temparr[i] = H[i] % mod;
1066template <const u
int64_t MaxDeg, const u
int64_t dim>
1072 if constexpr (dim == 1) {
1079 const uint64_t halfd = dim / 2;
1082 for (uint64_t i=0; i < halfd; i++) temparr[i] = H1[i];
1084 for (uint64_t i=0; i < halfd; i++) temparr[i] = H1[i+halfd];
1086 for (uint64_t i=0; i < halfd; i++) temparr[i] = H2[i];
1088 for (uint64_t i=0; i < halfd; i++) temparr[i] = H2[i+halfd];
1098 for (uint64_t i=0; i < halfd; i++) temparr[i] = Ha[i];
1099 for (uint64_t i=0; i < halfd; i++) temparr[i+halfd] = Hb[i];
1110template <const u
int64_t MaxDeg, const u
int64_t dim>
1116 throw std::invalid_argument(
"zero is not a valid argument");
1119 for (uint64_t i=0; i < x-1; i++) Hx = Hx * H;
1128template <const u
int64_t MaxDeg, const u
int64_t dim>
1133 for (uint64_t i=1; i < dim; i++) result[i] = Polynomial<MaxDeg>();
1141template <const u
int64_t MaxDeg, const u
int64_t dim>
1151#ifndef DOXYGEN_SHOULD_SKIP_THIS
1152template <const u
int64_t MaxDeg, const u
int64_t dim>
1162template <const u
int64_t MaxDeg, const u
int64_t dim>
1167 for (uint64_t i=0; i < dim; i++)
CenteredLift(&(*H)[i], mod);
1175template <const u
int64_t MaxDeg, const u
int64_t dim>
1183 temparr[0] = H[0] * ringinverse % mod;
1184 for (uint64_t i=1; i < dim; i++)
1185 temparr[i] = -H[i] * ringinverse % mod;
1192 assert(result[0] == unity);
1193 for (uint64_t i=1; i < dim; i++) assert(result[i] == zero);
1212template <const u
int64_t MaxDeg, const u
int64_t dim>
1232template <const u
int64_t MaxDeg, const u
int64_t dim>
1252template <const u
int64_t MaxDeg, const u
int64_t dim>
Hypercomplex< T, dim > operator-(const Hypercomplex< T, dim > &H1, const Hypercomplex< T, dim > &H2)
Subtraction operator.
Definition: Hypercomplex.hpp:500
Hypercomplex< T, dim > Re(const Hypercomplex< T, dim > &H)
Real part of a hypercomplex number.
Definition: Hypercomplex.hpp:636
Hypercomplex< Polynomial< MaxDeg >, dim > DECRYPT(const Hypercomplex< Polynomial< MaxDeg >, dim > &F, const Hypercomplex< Polynomial< MaxDeg >, dim > &E, const int64_t &p, const int64_t &q)
Decrypt a message via the cryptosystem.
Definition: Hypercomplex.hpp:1253
bool operator==(const Hypercomplex< T, dim > &H1, const Hypercomplex< T, dim > &H2)
Equality operator.
Definition: Hypercomplex.hpp:467
bool operator!=(const Hypercomplex< T, dim > &H1, const Hypercomplex< T, dim > &H2)
Inequality operator.
Definition: Hypercomplex.hpp:479
Hypercomplex< T, dim > operator+(const Hypercomplex< T, dim > &H1, const Hypercomplex< T, dim > &H2)
Addition operator.
Definition: Hypercomplex.hpp:488
Hypercomplex< Polynomial< MaxDeg >, dim > PUBLICKEY(const Hypercomplex< Polynomial< MaxDeg >, dim > &F, const Hypercomplex< Polynomial< MaxDeg >, dim > &G, const int64_t &q)
Generate public key of the cryptosystem.
Definition: Hypercomplex.hpp:1213
Hypercomplex< Polynomial< MaxDeg >, dim > RingInverse(const Hypercomplex< Polynomial< MaxDeg >, dim > &H, const int64_t &mod)
Hypercomplex inverse in a modular quotient ring.
Definition: Hypercomplex.hpp:1176
Hypercomplex< Polynomial< MaxDeg >, dim > ENCRYPT(const Hypercomplex< Polynomial< MaxDeg >, dim > &H, const Hypercomplex< Polynomial< MaxDeg >, dim > &M, const Hypercomplex< Polynomial< MaxDeg >, dim > &PHI, const int64_t &p, const int64_t &q)
Encrypt a message via the cryptosystem.
Definition: Hypercomplex.hpp:1233
void CenteredLift(Hypercomplex< Polynomial< MaxDeg >, dim > *H, const int64_t &mod)
Center-lift hypercomplex elements in a modular quotient ring.
Definition: Hypercomplex.hpp:1163
Hypercomplex< T, dim > operator*(const Hypercomplex< T, dim > &H1, const Hypercomplex< T, dim > &H2)
Multiplication operator.
Definition: Hypercomplex.hpp:512
std::ostream & operator<<(std::ostream &os, const Hypercomplex< T, dim > &H)
Print operator.
Definition: Hypercomplex.hpp:628
Hypercomplex< T, dim > operator^(const Hypercomplex< T, dim > &H, const uint64_t x)
Power operator.
Definition: Hypercomplex.hpp:552
Hypercomplex< T, dim > Im(const Hypercomplex< T, dim > &H)
Imaginary part of a hypercomplex number.
Definition: Hypercomplex.hpp:644
Hypercomplex< Polynomial< MaxDeg >, dim > operator%(const Hypercomplex< Polynomial< MaxDeg >, dim > &H, const int64_t &mod)
Modular reduction operator.
Definition: Hypercomplex.hpp:1051
Hypercomplex< T, dim > exp(const Hypercomplex< T, dim > &H)
Exponentiation operation on a hypercomplex number.
Definition: Hypercomplex.hpp:652
Hypercomplex< T, dim > operator/(const Hypercomplex< T, dim > &H1, const Hypercomplex< T, dim > &H2)
Division operator.
Definition: Hypercomplex.hpp:567
static void init()
Basis multiplication table initialiser.
Definition: Hypercomplex.hpp:688
Hypercomplex(const Polynomial< MaxDeg > *ARR)
This is the main constructor.
Definition: Hypercomplex.hpp:764
Hypercomplex< Polynomial< MaxDeg >, newdim > expand() const
Cast a number into a higher dimension.
Definition: Hypercomplex.hpp:819
static void clear()
Cleanup function: free all memory.
Definition: Hypercomplex.hpp:724
static Hypercomplex MUL(const Hypercomplex &H1, const Hypercomplex &H2)
Optimised multiplication function.
Definition: Hypercomplex.hpp:738
uint64_t _() const
Dimensionality getter.
Definition: Hypercomplex.hpp:795
Hypercomplex(const Hypercomplex &H)
This is the copy constructor.
Definition: Hypercomplex.hpp:782
Polynomial< MaxDeg > norm2() const
Calculate squared Euclidean norm of a number.
Definition: Hypercomplex.hpp:804
Definition: Hypercomplex.hpp:48
Hypercomplex & operator^=(const uint64_t x)
Power-Assignment operator.
Definition: Hypercomplex.hpp:608
static void init()
Basis multiplication table initialiser.
Definition: Hypercomplex.hpp:57
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
static Hypercomplex MUL(const Hypercomplex &H1, const Hypercomplex &H2)
Optimised multiplication function.
Definition: Hypercomplex.hpp:107
uint64_t _() const
Dimensionality getter.
Definition: Hypercomplex.hpp:153
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
static void clear()
Cleanup function: free all memory.
Definition: Hypercomplex.hpp:93
Hypercomplex inv() const
Calculate inverse of a given number.
Definition: Hypercomplex.hpp:392
Hypercomplex< T, newdim > expand() const
Cast a number into a higher dimension.
Definition: Hypercomplex.hpp:410
Definition: Polynomial.hpp:41