197 const unsigned int n = x.rows();
199 tree_[0].emplace_back(x);
202 const unsigned int ndiv2 = n >> 1U;
203 const unsigned int idx = log2i(ndiv2);
205 cfloatmat s00(x(Eigen::seq(Eigen::fix<0>, EIGEN_LAST, Eigen::fix<2>), Eigen::seq(Eigen::fix<0>, EIGEN_LAST, Eigen::fix<2>)));
206 cfloatmat s01(x(Eigen::seq(Eigen::fix<0>, EIGEN_LAST, Eigen::fix<2>), Eigen::seq(Eigen::fix<1>, EIGEN_LAST, Eigen::fix<2>)));
207 cfloatmat s10(x(Eigen::seq(Eigen::fix<1>, EIGEN_LAST, Eigen::fix<2>), Eigen::seq(Eigen::fix<0>, EIGEN_LAST, Eigen::fix<2>)));
208 cfloatmat s11(x(Eigen::seq(Eigen::fix<1>, EIGEN_LAST, Eigen::fix<2>), Eigen::seq(Eigen::fix<1>, EIGEN_LAST, Eigen::fix<2>)));
214 const cfloatmat &x00 = tree_[idx][offset];
215 const cfloatmat &x01 = tree_[idx][offset + 1];
216 const cfloatmat &x10 = tree_[idx][offset + 2];
217 const cfloatmat &x11 = tree_[idx][offset + 3];
218 const unsigned int Nn = N * n;
219 for(
unsigned int i = 0; i < ndiv2; i++) {
220 for(
unsigned int j = 0; j < ndiv2; j++) {
221 const cfloat tu = twiddle_[j + Nn] * x01(i, j);
222 const cfloat td = twiddle_[(i + j) + Nn] * x11(i, j);
223 const cfloat ts = twiddle_[i + Nn] * x10(i, j);
225 const cfloat a = x00(i, j) + tu;
226 const cfloat b = x00(i, j) - tu;
227 const cfloat c = ts + td;
228 const cfloat d = ts - td;
231 x(i, j + ndiv2) = b + d;
232 x(i + ndiv2, j) = a - c;
233 x(i + ndiv2, j + ndiv2) = b - d;
236 tree_[log2i(n)].emplace_back(x);
255 const unsigned int n = x.rows();
257 return std::exchange(x(0, 0), p.state).real() !=
static_cast<float>(p.state);
259 const unsigned int ndiv2 = n >> 1U;
260 const unsigned int nndiv2 = n * ndiv2;
261 const unsigned int idx = log2i(ndiv2);
263 bool changed =
false;
264 if(
static_cast<bool>(p.row & 1U)) {
265 if(
static_cast<bool>(p.col & 1U)) {
266 changed =
update(tree_[idx][offset + 3], {p.row >> 1U, p.col >> 1U, p.state}, 4 * offset + 12);
268 changed =
update(tree_[idx][offset + 2], {p.row >> 1U, p.col >> 1U, p.state}, 4 * offset + 8);
271 if(
static_cast<bool>(p.col & 1U)) {
272 changed =
update(tree_[idx][offset + 1], {p.row >> 1U, p.col >> 1U, p.state}, 4 * offset + 4);
274 changed =
update(tree_[idx][offset], {p.row >> 1U, p.col >> 1U, p.state}, 4 * offset);
279 const cfloat *x00 = tree_[idx][offset].data();
280 const cfloat *x01 = tree_[idx][offset + 1].data();
281 const cfloat *x10 = tree_[idx][offset + 2].data();
282 const cfloat *x11 = tree_[idx][offset + 3].data();
283 cfloat *xp = x.data();
284 const unsigned int Nn = N * n;
286 for(
unsigned int j = 0; j < ndiv2; j++) {
287 const unsigned int ndiv2j = ndiv2 * j, nj = n * j;
288 for(
unsigned int i = 0; i < ndiv2; i++) {
289 const unsigned int k = i + ndiv2j, k1 = i + nj, k2 = k1 + ndiv2;
291 const cfloat tu = twiddle_[j + Nn] * x01[k];
292 const cfloat td = twiddle_[i + j + Nn] * x11[k];
293 const cfloat ts = twiddle_[i + Nn] * x10[k];
295 const cfloat x00_k = x00[k];
296 const cfloat a = x00_k + tu;
297 const cfloat b = x00_k - tu;
298 const cfloat c = ts + td;
299 const cfloat d = ts - td;
302 xp[k1 + nndiv2] = b + d;
304 xp[k2 + nndiv2] = b - d;
327 bool update(cfloatmat &x, Stimuli::iterator b0, Stimuli::iterator e0,
const unsigned int offset = 0) {
328 const unsigned int n = x.rows();
331 return std::exchange(x(0, 0), b0->state).real() !=
static_cast<float>(b0->state);
333 const bool state = std::any_of(b0, e0, [](
const Stimulus &p) {
return p.state; });
334 return std::exchange(x(0, 0), state).real() !=
static_cast<float>(state);
336 const unsigned int ndiv2 = n >> 1U;
337 const unsigned int nndiv2 = n * ndiv2;
338 const unsigned int idx = log2i(ndiv2);
340 Stimuli::iterator e1, e2, e3;
341 e2 = std::partition(b0, e0, [](
const Stimulus &p) {
return p.row & 1U; });
342 e1 = std::partition(b0, e2, [](
const Stimulus &p) {
return p.col & 1U; });
343 e3 = std::partition(e2, e0, [](
const Stimulus &p) {
return p.col & 1U; });
345 auto transformStimuli = [](Stimuli::iterator begin, Stimuli::iterator end) {
346 for(
auto it = begin; it != end; ++it) {
351 transformStimuli(b0, e1);
352 transformStimuli(e1, e2);
353 transformStimuli(e2, e3);
354 transformStimuli(e3, e0);
356 bool changed =
false;
358 changed =
update(tree_[idx][offset + 3], b0, e1, 4 * offset + 12) || changed;
361 changed =
update(tree_[idx][offset + 2], e1, e2, 4 * offset + 8) || changed;
364 changed =
update(tree_[idx][offset + 1], e2, e3, 4 * offset + 4) || changed;
367 changed =
update(tree_[idx][offset], e3, e0, 4 * offset) || changed;
371 const cfloat *x00 = tree_[idx][offset].data();
372 const cfloat *x01 = tree_[idx][offset + 1].data();
373 const cfloat *x10 = tree_[idx][offset + 2].data();
374 const cfloat *x11 = tree_[idx][offset + 3].data();
375 cfloat *xp = x.data();
376 const unsigned int Nn = N * n;
378 for(
unsigned int j = 0; j < ndiv2; j++) {
379 const unsigned int ndiv2j = ndiv2 * j, nj = n * j;
380 for(
unsigned int i = 0; i < ndiv2; i++) {
381 const unsigned int k = i + ndiv2j, k1 = i + nj, k2 = k1 + ndiv2;
383 const cfloat tu = twiddle_[j + Nn] * x01[k];
384 const cfloat td = twiddle_[i + j + Nn] * x11[k];
385 const cfloat ts = twiddle_[i + Nn] * x10[k];
387 const cfloat x00_k = x00[k];
388 const cfloat a = x00_k + tu;
389 const cfloat b = x00_k - tu;
390 const cfloat c = ts + td;
391 const cfloat d = ts - td;
394 xp[k1 + nndiv2] = b + d;
396 xp[k2 + nndiv2] = b - d;
410 plan_ = fftw_plan_dft_2d(N, N, fftwInput_, fftwOutput_, FFTW_FORWARD, FFTW_ESTIMATE | FFTW_UNALIGNED | FFTW_NO_SIMD | FFTW_PRESERVE_INPUT);
467 return Eigen::Map<const Eigen::Matrix<std::complex<double>, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>(
reinterpret_cast<const std::complex<double> *
>(fftwOutput_), N, N).
template cast<cfloat>();