182 const unsigned int n = x.rows();
184 tree_[0].emplace_back(x);
187 const unsigned int ndiv2 = n >> 1U;
188 const unsigned int idx = log2i(ndiv2);
190 cfloatmat s00(x(Eigen::seq(Eigen::fix<0>, Eigen::last, Eigen::fix<2>), Eigen::seq(Eigen::fix<0>, Eigen::last, Eigen::fix<2>)));
191 cfloatmat s01(x(Eigen::seq(Eigen::fix<0>, Eigen::last, Eigen::fix<2>), Eigen::seq(Eigen::fix<1>, Eigen::last, Eigen::fix<2>)));
192 cfloatmat s10(x(Eigen::seq(Eigen::fix<1>, Eigen::last, Eigen::fix<2>), Eigen::seq(Eigen::fix<0>, Eigen::last, Eigen::fix<2>)));
193 cfloatmat s11(x(Eigen::seq(Eigen::fix<1>, Eigen::last, Eigen::fix<2>), Eigen::seq(Eigen::fix<1>, Eigen::last, Eigen::fix<2>)));
199 const cfloatmat &x00 = tree_[idx][offset];
200 const cfloatmat &x01 = tree_[idx][offset + 1];
201 const cfloatmat &x10 = tree_[idx][offset + 2];
202 const cfloatmat &x11 = tree_[idx][offset + 3];
203 const unsigned int Nn = N * n;
204 for(
unsigned int i = 0; i < ndiv2; i++) {
205 for(
unsigned int j = 0; j < ndiv2; j++) {
206 const cfloat tu = twiddle_[j + Nn] * x01(i, j);
207 const cfloat td = twiddle_[(i + j) + Nn] * x11(i, j);
208 const cfloat ts = twiddle_[i + Nn] * x10(i, j);
210 const cfloat a = x00(i, j) + tu;
211 const cfloat b = x00(i, j) - tu;
212 const cfloat c = ts + td;
213 const cfloat d = ts - td;
216 x(i, j + ndiv2) = b + d;
217 x(i + ndiv2, j) = a - c;
218 x(i + ndiv2, j + ndiv2) = b - d;
221 tree_[log2i(n)].emplace_back(x);
240 const unsigned int n = x.rows();
242 return std::exchange(x(0, 0), p.state).real() !=
static_cast<float>(p.state);
244 const unsigned int ndiv2 = n >> 1U;
245 const unsigned int nndiv2 = n * ndiv2;
246 const unsigned int idx = log2i(ndiv2);
248 bool changed =
false;
249 if(
static_cast<bool>(p.row & 1U)) {
250 if(
static_cast<bool>(p.col & 1U)) {
251 changed =
update(tree_[idx][offset + 3], {p.row >> 1U, p.col >> 1U, p.state}, 4 * offset + 12);
253 changed =
update(tree_[idx][offset + 2], {p.row >> 1U, p.col >> 1U, p.state}, 4 * offset + 8);
256 if(
static_cast<bool>(p.col & 1U)) {
257 changed =
update(tree_[idx][offset + 1], {p.row >> 1U, p.col >> 1U, p.state}, 4 * offset + 4);
259 changed =
update(tree_[idx][offset], {p.row >> 1U, p.col >> 1U, p.state}, 4 * offset);
264 const cfloat *x00 = tree_[idx][offset].data();
265 const cfloat *x01 = tree_[idx][offset + 1].data();
266 const cfloat *x10 = tree_[idx][offset + 2].data();
267 const cfloat *x11 = tree_[idx][offset + 3].data();
268 cfloat *xp = x.data();
269 const unsigned int Nn = N * n;
271 for(
unsigned int j = 0; j < ndiv2; j++) {
272 const unsigned int ndiv2j = ndiv2 * j, nj = n * j;
273 for(
unsigned int i = 0; i < ndiv2; i++) {
274 const unsigned int k = i + ndiv2j, k1 = i + nj, k2 = k1 + ndiv2;
276 const cfloat tu = twiddle_[j + Nn] * x01[k];
277 const cfloat td = twiddle_[i + j + Nn] * x11[k];
278 const cfloat ts = twiddle_[i + Nn] * x10[k];
280 const cfloat x00_k = x00[k];
281 const cfloat a = x00_k + tu;
282 const cfloat b = x00_k - tu;
283 const cfloat c = ts + td;
284 const cfloat d = ts - td;
287 xp[k1 + nndiv2] = b + d;
289 xp[k2 + nndiv2] = b - d;
312 bool update(cfloatmat &x, Stimuli::iterator b0, Stimuli::iterator e0,
const unsigned int offset = 0) {
313 const unsigned int n = x.rows();
316 return std::exchange(x(0, 0), b0->state).real() !=
static_cast<float>(b0->state);
318 const bool state = std::any_of(b0, e0, [](
const Stimulus &p) {
return p.state; });
319 return std::exchange(x(0, 0), state).real() !=
static_cast<float>(state);
321 const unsigned int ndiv2 = n >> 1U;
322 const unsigned int nndiv2 = n * ndiv2;
323 const unsigned int idx = log2i(ndiv2);
325 Stimuli::iterator e1, e2, e3;
326 e2 = std::partition(b0, e0, [](
const Stimulus &p) {
return p.row & 1U; });
327 e1 = std::partition(b0, e2, [](
const Stimulus &p) {
return p.col & 1U; });
328 e3 = std::partition(e2, e0, [](
const Stimulus &p) {
return p.col & 1U; });
330 auto transformStimuli = [](Stimuli::iterator begin, Stimuli::iterator end) {
331 for(
auto it = begin; it != end; ++it) {
336 transformStimuli(b0, e1);
337 transformStimuli(e1, e2);
338 transformStimuli(e2, e3);
339 transformStimuli(e3, e0);
341 bool changed =
false;
343 changed =
update(tree_[idx][offset + 3], b0, e1, 4 * offset + 12) || changed;
346 changed =
update(tree_[idx][offset + 2], e1, e2, 4 * offset + 8) || changed;
349 changed =
update(tree_[idx][offset + 1], e2, e3, 4 * offset + 4) || changed;
352 changed =
update(tree_[idx][offset], e3, e0, 4 * offset) || changed;
356 const cfloat *x00 = tree_[idx][offset].data();
357 const cfloat *x01 = tree_[idx][offset + 1].data();
358 const cfloat *x10 = tree_[idx][offset + 2].data();
359 const cfloat *x11 = tree_[idx][offset + 3].data();
360 cfloat *xp = x.data();
361 const unsigned int Nn = N * n;
363 for(
unsigned int j = 0; j < ndiv2; j++) {
364 const unsigned int ndiv2j = ndiv2 * j, nj = n * j;
365 for(
unsigned int i = 0; i < ndiv2; i++) {
366 const unsigned int k = i + ndiv2j, k1 = i + nj, k2 = k1 + ndiv2;
368 const cfloat tu = twiddle_[j + Nn] * x01[k];
369 const cfloat td = twiddle_[i + j + Nn] * x11[k];
370 const cfloat ts = twiddle_[i + Nn] * x10[k];
372 const cfloat x00_k = x00[k];
373 const cfloat a = x00_k + tu;
374 const cfloat b = x00_k - tu;
375 const cfloat c = ts + td;
376 const cfloat d = ts - td;
379 xp[k1 + nndiv2] = b + d;
381 xp[k2 + nndiv2] = b - d;
395 plan_ = fftw_plan_dft_2d(N, N, fftwInput_.data(), fftwOutput_.data(), FFTW_FORWARD, FFTW_ESTIMATE | FFTW_UNALIGNED | FFTW_NO_SIMD | FFTW_PRESERVE_INPUT);
452 return Eigen::Map<const Eigen::Matrix<std::complex<double>, N, N, Eigen::RowMajor>>(
reinterpret_cast<const std::complex<double> *
>(fftwOutput_.data())).template cast<cfloat>();