arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/spqlios/reim/reim_fftvec_ref.c
poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/spqlios/reim/reim_fftvec_ref.cRaw
  1#include <string.h>
  2
  3#include "../commons_private.h"
  4#include "reim_fft_internal.h"
  5#include "reim_fft_private.h"
  6
  7// Computes X^i -> X^(p*i) in the fourier domain for a reim vector is size 2 * m * size
  8// This function cannot be evaluated in place.
  9EXPORT void reim_fftvec_automorphism_ref(const REIM_FFTVEC_AUTOMORPHISM_PRECOMP* tables, int64_t p, double* r,
 10                                         const double* a, uint64_t a_size) {
 11  const uint64_t m = tables->m;
 12  const uint64_t nn = 2 * m;
 13  const uint64_t* irev = tables->irev;
 14  const uint64_t mask = (4 * m - 1);
 15  const uint64_t conj = !((p & 3) == 1);
 16  p = p & mask;
 17  p *= 1 - (conj << 1);
 18  if (a_size == 1) {
 19    for (uint64_t i = 0; i < m; ++i) {
 20      uint64_t i_rev = 2 * irev[i] + 1;
 21      i_rev = (((p * i_rev) & mask) - 1) >> 1;
 22      uint64_t j = irev[i_rev];
 23      r[i] = a[j];
 24      double x = a[j + m];
 25      r[i + m] = conj ? -x : x;
 26    }
 27  } else {
 28    for (uint64_t i = 0; i < m; ++i) {
 29      uint64_t i_rev = 2 * irev[i] + 1;
 30      i_rev = (((p * i_rev) & mask) - 1) >> 1;
 31      uint64_t j = irev[i_rev];
 32      for (uint64_t k = 0; k < a_size; ++k) {
 33        uint64_t offset_re = k * nn;
 34        uint64_t offset_im = offset_re + m;
 35        r[i + offset_re] = a[j + offset_re];
 36        double x = a[j + offset_im];
 37        r[i + offset_im] = conj ? -x : x;
 38      }
 39    }
 40  }
 41}
 42
 43// Computes the permutation index for an automorphism X^{i} -> X^{i*p} in the fourier domain.
 44EXPORT void reim_fftvec_automorphism_lut_precomp_ref(const REIM_FFTVEC_AUTOMORPHISM_PRECOMP* tables, int64_t p,
 45                                                     uint64_t* precomp  // size m
 46) {
 47  const uint64_t m = tables->m;
 48  const uint64_t* irev = tables->irev;
 49  const uint64_t mask = (4 * m - 1);
 50  const uint64_t conj = !((p & 3) == 1);
 51  p = p & mask;
 52  p *= 1 - (conj << 1);
 53  for (uint64_t i = 0; i < m; ++i) {
 54    uint64_t i_rev = 2 * irev[i] + 1;
 55    i_rev = (((p * i_rev) & mask) - 1) >> 1;
 56    uint64_t j = irev[i_rev];
 57    precomp[i] = j;
 58  }
 59}
 60
 61// Computes X^{i} -> X^{i*p} in the fourier domain for a reim vector of size m using a precomputed lut permutation.
 62void reim_fftvec_automorphism_with_lut_ref(const REIM_FFTVEC_AUTOMORPHISM_PRECOMP* tables, uint64_t* precomp, double* r,
 63                                           const double* a) {
 64  const uint64_t m = tables->m;
 65  for (uint64_t i = 0; i < m; ++i) {
 66    uint64_t j = precomp[i];
 67    r[i] = a[j];
 68    r[i + m] = a[j + m];
 69  }
 70}
 71
 72// Computes X^{i} -> X^{i*-p} in the fourier domain for a reim vector of size m using a precomputed lut permutation.
 73void reim_fftvec_automorphism_conj_with_lut_ref(const REIM_FFTVEC_AUTOMORPHISM_PRECOMP* tables, uint64_t* precomp,
 74                                                double* r, const double* a) {
 75  const uint64_t m = tables->m;
 76  for (uint64_t i = 0; i < m; ++i) {
 77    uint64_t j = precomp[i];
 78    r[i] = a[j];
 79    r[i + m] = -a[j + m];
 80  }
 81}
 82
 83// Returns the minimum number of temporary bytes used by reim_fftvec_automorphism_inplace_ref.
 84EXPORT uint64_t reim_fftvec_automorphism_inplace_tmp_bytes_ref(const REIM_FFTVEC_AUTOMORPHISM_PRECOMP* tables) {
 85  const uint64_t m = tables->m;
 86  return m * (2 * sizeof(double) + sizeof(uint64_t));
 87}
 88
 89// Computes X^i -> X^(p*i) in the fourier domain for a reim vector is size 2 * m * a_size
 90// This function cannot be evaluated in place.
 91EXPORT void reim_fftvec_automorphism_inplace_ref(const REIM_FFTVEC_AUTOMORPHISM_PRECOMP* tables, int64_t p, double* a,
 92                                                 uint64_t a_size,
 93                                                 uint8_t* tmp_bytes  // m * (2*sizeof(double) + sizeof(uint64_t))
 94) {
 95  const uint64_t m = tables->m;
 96  const uint64_t nn = 2 * m;
 97  const uint64_t* irev = tables->irev;
 98  const uint64_t mask = (4 * m - 1);
 99  const uint64_t conj = !((p & 3) == 1);
100
101  double* tmp = (double*)tmp_bytes;
102  p = p & mask;
103  if (a_size == 1) {
104    p *= 1 - (conj << 1);
105    for (uint64_t i = 0; i < m; ++i) {
106      uint64_t i_rev = 2 * irev[i] + 1;
107      i_rev = (((p * i_rev) & mask) - 1) >> 1;
108      uint64_t j = irev[i_rev];
109      tmp[i] = a[j];
110      double x = a[j + m];
111      tmp[i + m] = conj ? -x : x;
112    }
113    memcpy(a, tmp, nn * sizeof(double));
114  } else {
115    uint64_t* lut = (uint64_t*)(tmp_bytes + nn * sizeof(double));
116    reim_fftvec_automorphism_lut_precomp_ref(tables, p, lut);
117    for (uint64_t i = 0; i < a_size; ++i) {
118      if (conj == 1) {
119        reim_fftvec_automorphism_conj_with_lut_ref(tables, lut, tmp, a + i * nn);
120      } else {
121        reim_fftvec_automorphism_with_lut_ref(tables, lut, tmp, a + i * nn);
122      }
123      memcpy(a + i * nn, tmp, nn * sizeof(double));
124    }
125  }
126}
127
128EXPORT void reim_fftvec_addmul_ref(const REIM_FFTVEC_ADDMUL_PRECOMP* tables, double* r, const double* a,
129                                   const double* b) {
130  const uint64_t m = tables->m;
131  for (uint64_t i = 0; i < m; ++i) {
132    double re = a[i] * b[i] - a[i + m] * b[i + m];
133    double im = a[i] * b[i + m] + a[i + m] * b[i];
134    r[i] += re;
135    r[i + m] += im;
136  }
137}
138
139EXPORT void reim_fftvec_add_ref(const REIM_FFTVEC_ADD_PRECOMP* precomp, double* r, const double* a, const double* b) {
140  const uint64_t m = precomp->m;
141  for (uint64_t i = 0; i < m; ++i) {
142    double re = a[i] + b[i];
143    double im = a[i + m] + b[i + m];
144    r[i] = re;
145    r[i + m] = im;
146  }
147}
148
149EXPORT void reim_fftvec_sub_ref(const REIM_FFTVEC_SUB_PRECOMP* precomp, double* r, const double* a, const double* b) {
150  const uint64_t m = precomp->m;
151  for (uint64_t i = 0; i < m; ++i) {
152    double re = a[i] - b[i];
153    double im = a[i + m] - b[i + m];
154    r[i] = re;
155    r[i + m] = im;
156  }
157}
158
159EXPORT void reim_fftvec_mul_ref(const REIM_FFTVEC_MUL_PRECOMP* tables, double* r, const double* a, const double* b) {
160  const uint64_t m = tables->m;
161  for (uint64_t i = 0; i < m; ++i) {
162    double re = a[i] * b[i] - a[i + m] * b[i + m];
163    double im = a[i] * b[i + m] + a[i + m] * b[i];
164    r[i] = re;
165    r[i + m] = im;
166  }
167}
168
169EXPORT REIM_FFTVEC_ADDMUL_PRECOMP* new_reim_fftvec_addmul_precomp(uint32_t m) {
170  REIM_FFTVEC_ADDMUL_PRECOMP* reps = malloc(sizeof(REIM_FFTVEC_ADDMUL_PRECOMP));
171  reps->m = m;
172  if (CPU_SUPPORTS("fma")) {
173    if (m >= 4) {
174      reps->function = reim_fftvec_addmul_fma;
175    } else {
176      reps->function = reim_fftvec_addmul_ref;
177    }
178  } else {
179    reps->function = reim_fftvec_addmul_ref;
180  }
181  return reps;
182}
183
184EXPORT REIM_FFTVEC_ADD_PRECOMP* new_reim_fftvec_add_precomp(uint32_t m) {
185  REIM_FFTVEC_ADD_PRECOMP* reps = malloc(sizeof(REIM_FFTVEC_ADD_PRECOMP));
186  reps->m = m;
187  if (CPU_SUPPORTS("fma")) {
188    if (m >= 4) {
189      reps->function = reim_fftvec_add_fma;
190    } else {
191      reps->function = reim_fftvec_add_ref;
192    }
193  } else {
194    reps->function = reim_fftvec_add_ref;
195  }
196  return reps;
197}
198
199EXPORT REIM_FFTVEC_SUB_PRECOMP* new_reim_fftvec_sub_precomp(uint32_t m) {
200  REIM_FFTVEC_SUB_PRECOMP* reps = malloc(sizeof(REIM_FFTVEC_SUB_PRECOMP));
201  reps->m = m;
202  if (CPU_SUPPORTS("fma")) {
203    if (m >= 4) {
204      reps->function = reim_fftvec_sub_fma;
205    } else {
206      reps->function = reim_fftvec_sub_ref;
207    }
208  } else {
209    reps->function = reim_fftvec_sub_ref;
210  }
211  return reps;
212}
213
214EXPORT REIM_FFTVEC_MUL_PRECOMP* new_reim_fftvec_mul_precomp(uint32_t m) {
215  REIM_FFTVEC_MUL_PRECOMP* reps = malloc(sizeof(REIM_FFTVEC_MUL_PRECOMP));
216  reps->m = m;
217  if (CPU_SUPPORTS("fma")) {
218    if (m >= 4) {
219      reps->function = reim_fftvec_mul_fma;
220    } else {
221      reps->function = reim_fftvec_mul_ref;
222    }
223  } else {
224    reps->function = reim_fftvec_mul_ref;
225  }
226  return reps;
227}
228
229EXPORT REIM_FFTVEC_AUTOMORPHISM_PRECOMP* new_reim_fftvec_automorphism_precomp(uint32_t m) {
230  REIM_FFTVEC_AUTOMORPHISM_PRECOMP* reps = malloc(sizeof(REIM_FFTVEC_AUTOMORPHISM_PRECOMP));
231  reps->m = m;
232  reps->function.apply = reim_fftvec_automorphism_ref;
233  reps->function.apply_inplace = reim_fftvec_automorphism_inplace_ref;
234  reps->function.apply_inplace_tmp_bytes = reim_fftvec_automorphism_inplace_tmp_bytes_ref;
235  const uint64_t nn = 2 * m;
236  reps->irev = malloc(sizeof(uint64_t) * nn);
237  uint32_t lognn = log2m(nn);
238  for (uint32_t i = 0; i < nn; i++) {
239    reps->irev[i] = (uint64_t)revbits(lognn, i);
240  }
241  return reps;
242}