poulpy/poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/spqlios/reim4/reim4_arithmetic_ref.c
poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/spqlios/reim4/reim4_arithmetic_ref.cRaw
1#include <assert.h>
2#include <string.h>
3
4#include "reim4_arithmetic.h"
5
6// Stores the first 4 values (RE) of src + blk*4 and he first 4 values (IM) of src + blk*4 + m
7// contiguously into dst
8void reim4_extract_1blk_from_reim_ref(uint64_t m, uint64_t blk,
9 double* const dst, // 8 doubles
10 const double* const src // one reim4 vector
11) {
12 assert(blk < (m >> 2));
13 const double* src_ptr = src + (blk << 2);
14 // copy the real parts
15 dst[0] = src_ptr[0];
16 dst[1] = src_ptr[1];
17 dst[2] = src_ptr[2];
18 dst[3] = src_ptr[3];
19 src_ptr += m;
20 // copy the imaginary parts
21 dst[4] = src_ptr[0];
22 dst[5] = src_ptr[1];
23 dst[6] = src_ptr[2];
24 dst[7] = src_ptr[3];
25}
26
27void reim4_extract_reim_from_1blk_ref(uint64_t m, uint64_t blk,
28 double* const dst, // 8 doubles
29 const double* const src // one reim4 vector
30) {
31 assert(blk < (m >> 2));
32 double* dst_ptr = dst + (blk << 2);
33 // copy the real parts
34 dst_ptr[0] = src[0];
35 dst_ptr[1] = src[1];
36 dst_ptr[2] = src[2];
37 dst_ptr[3] = src[3];
38 dst_ptr += m;
39 // copy the imaginary parts
40 dst_ptr[0] = src[4];
41 dst_ptr[1] = src[5];
42 dst_ptr[2] = src[6];
43 dst_ptr[3] = src[7];
44}
45
46EXPORT void reim4_extract_1blk_from_contiguous_reim_ref(uint64_t m, uint64_t nrows, uint64_t blk, double* const dst,
47 const double* const src) {
48 assert(blk < (m >> 2));
49
50 const double* src_ptr = src + (blk << 2);
51 double* dst_ptr = dst;
52 for (uint64_t i = 0; i < nrows * 2; ++i) {
53 dst_ptr[0] = src_ptr[0];
54 dst_ptr[1] = src_ptr[1];
55 dst_ptr[2] = src_ptr[2];
56 dst_ptr[3] = src_ptr[3];
57 dst_ptr += 4;
58 src_ptr += m;
59 }
60}
61
62EXPORT void reim4_extract_1blk_from_contiguous_reim_sl_ref(uint64_t m, uint64_t sl, uint64_t nrows, uint64_t blk,
63 double* const dst, const double* const src) {
64 assert(blk < (m >> 2));
65
66 const double* src_ptr = src + (blk << 2);
67 double* dst_ptr = dst;
68 const uint64_t sl_minus_m = sl - m;
69 for (uint64_t i = 0; i < nrows; ++i) {
70 dst_ptr[0] = src_ptr[0];
71 dst_ptr[1] = src_ptr[1];
72 dst_ptr[2] = src_ptr[2];
73 dst_ptr[3] = src_ptr[3];
74 dst_ptr += 4;
75 src_ptr += m;
76 dst_ptr[0] = src_ptr[0];
77 dst_ptr[1] = src_ptr[1];
78 dst_ptr[2] = src_ptr[2];
79 dst_ptr[3] = src_ptr[3];
80 dst_ptr += 4;
81 src_ptr += sl_minus_m;
82 }
83}
84
85// dest(i)=src
86// use scalar or sse or avx? Code
87// should be the inverse of reim4_extract_1col_from_reim
88void reim4_save_1blk_to_reim_ref(uint64_t m, uint64_t blk,
89 double* dst, // 1 reim vector of length m
90 const double* src // 8 doubles
91) {
92 assert(blk < (m >> 2));
93 double* dst_ptr = dst + (blk << 2);
94 // save the real part
95 dst_ptr[0] = src[0];
96 dst_ptr[1] = src[1];
97 dst_ptr[2] = src[2];
98 dst_ptr[3] = src[3];
99 dst_ptr += m;
100 // save the imag part
101 dst_ptr[0] = src[4];
102 dst_ptr[1] = src[5];
103 dst_ptr[2] = src[6];
104 dst_ptr[3] = src[7];
105}
106
107void reim4_add_1blk_to_reim_ref(uint64_t m, uint64_t blk,
108 double* dst, // 1 reim vector of length m
109 const double* src // 8 doubles
110) {
111 assert(blk < (m >> 2));
112 double* dst_ptr = dst + (blk << 2);
113 // add the real part
114 dst_ptr[0] += src[0];
115 dst_ptr[1] += src[1];
116 dst_ptr[2] += src[2];
117 dst_ptr[3] += src[3];
118 dst_ptr += m;
119 // add the imag part
120 dst_ptr[0] += src[4];
121 dst_ptr[1] += src[5];
122 dst_ptr[2] += src[6];
123 dst_ptr[3] += src[7];
124}
125
126// dest = 0
127void reim4_zero(double* const dst // 8 doubles
128) {
129 for (uint64_t i = 0; i < 8; ++i) dst[i] = 0;
130}
131
132/** @brief dest = a + b */
133void reim4_add(double* const dst, // 8 doubles
134 const double* const u, // nrows * 8 doubles
135 const double* const v // nrows * 8 doubles
136) {
137 for (uint64_t k = 0; k < 4; ++k) {
138 const double a = u[k];
139 const double c = v[k];
140 const double b = u[k + 4];
141 const double d = v[k + 4];
142
143 dst[k] = a + c;
144 dst[k + 4] = b + d;
145 }
146}
147
148/** @brief dest = a * b */
149void reim4_mul(double* const dst, // 8 doubles
150 const double* const u, // 8 doubles
151 const double* const v // 8 doubles
152) {
153 for (uint64_t k = 0; k < 4; ++k) {
154 const double a = u[k];
155 const double c = v[k];
156 const double b = u[k + 4];
157 const double d = v[k + 4];
158
159 dst[k] = a * c - b * d;
160 dst[k + 4] = a * d + b * c;
161 }
162}
163
164/** @brief dest += a * b */
165void reim4_add_mul(double* const dst, // 8 doubles
166 const double* const u, // 8 doubles
167 const double* const v // 8 doubles
168) {
169 for (uint64_t k = 0; k < 4; ++k) {
170 const double a = u[k];
171 const double c = v[k];
172 const double b = u[k + 4];
173 const double d = v[k + 4];
174
175 dst[k] += a * c - b * d;
176 dst[k + 4] += a * d + b * c;
177 }
178}
179
180/** dest = uT * v where u is a vector of size nrows, and v is a nrows x 1 matrix */
181void reim4_vec_mat1col_product_ref(const uint64_t nrows,
182 double* const dst, // 8 doubles
183 const double* const u, // nrows * 8 doubles
184 const double* const v // nrows * 8 doubles
185) {
186 reim4_zero(dst);
187
188 for (uint64_t i = 0, j = 0; i < nrows; ++i, j += 8) {
189 reim4_add_mul(dst, u + j, v + j);
190 }
191}
192
193/** dest = uT * v where u is a vector of size nrows, and v is a nrows x 2 matrix */
194void reim4_vec_mat2cols_product_ref(const uint64_t nrows,
195 double* const dst, // 16 doubles
196 const double* const u, // nrows * 8 doubles
197 const double* const v // nrows * 16 doubles
198) {
199 reim4_zero(dst);
200 reim4_zero(dst + 8);
201
202 double* dst1 = dst;
203 double* dst2 = dst + 8;
204
205 for (uint64_t i = 0, j = 0; i < nrows; ++i, j += 8) {
206 uint64_t double_j = j << 1;
207 reim4_add_mul(dst1, u + j, v + double_j);
208 reim4_add_mul(dst2, u + j, v + double_j + 8);
209 }
210}
211
212/**
213 * @brief k-th coefficient of the convolution product a * b.
214 *
215 * The k-th coefficient is defined as sum_{i+j=k} a[i].b[j].
216 * (in this sum, i and j must remain within the bounds [0,sizea[ and [0,sizeb[)
217 *
218 * In practice, accounting for these bounds, the convolution function boils down to
219 * ```
220 * res := 0
221 * if (k<sizeb+sizea-1) then
222 * for j from max(0,k+1-sizea) incl to min(sizeb,k+1) excl do
223 * res += a[k-j] * b[j]
224 * return res
225 * ```
226 */
227EXPORT void reim4_convolution_1coeff_ref(uint64_t k, double* dest, const double* a, uint64_t sizea, const double* b,
228 uint64_t sizeb) {
229 reim4_zero(dest);
230 if (k >= sizea + sizeb) return;
231 uint64_t jmin = k >= sizea ? k + 1 - sizea : 0;
232 uint64_t jmax = k < sizeb ? k + 1 : sizeb;
233 for (uint64_t j = jmin; j < jmax; ++j) {
234 reim4_add_mul(dest, a + 8 * (k - j), b + 8 * j);
235 }
236}
237
238/** @brief returns two consecutive convolution coefficients: k and k+1 */
239EXPORT void reim4_convolution_2coeff_ref(uint64_t k, double* dest, const double* a, uint64_t sizea, const double* b,
240 uint64_t sizeb) {
241 reim4_convolution_1coeff_ref(k, dest, a, sizea, b, sizeb);
242 reim4_convolution_1coeff_ref(k + 1, dest + 8, a, sizea, b, sizeb);
243}
244
245/**
246 * @brief From the convolution a * b, return the coefficients between offset and offset + size
247 * For the full convolution, use offset=0 and size=sizea+sizeb-1.
248 */
249EXPORT void reim4_convolution_ref(double* dest, uint64_t dest_size, uint64_t dest_offset, const double* a,
250 uint64_t sizea, const double* b, uint64_t sizeb) {
251 for (uint64_t k = 0; k < dest_size; ++k) {
252 reim4_convolution_1coeff_ref(k + dest_offset, dest + 8 * k, a, sizea, b, sizeb);
253 }
254}