134 const unsigned int n = x.rows();
136 tree_[0].emplace_back(x);
139 const unsigned int ndiv2 = n >> 1U;
140 const unsigned int idx = log2i(ndiv2);
142 cfloatmat s00(x(Eigen::seq(Eigen::fix<0>, Eigen::last, Eigen::fix<2>), Eigen::seq(Eigen::fix<0>, Eigen::last, Eigen::fix<2>)));
143 cfloatmat s01(x(Eigen::seq(Eigen::fix<0>, Eigen::last, Eigen::fix<2>), Eigen::seq(Eigen::fix<1>, Eigen::last, Eigen::fix<2>)));
144 cfloatmat s10(x(Eigen::seq(Eigen::fix<1>, Eigen::last, Eigen::fix<2>), Eigen::seq(Eigen::fix<0>, Eigen::last, Eigen::fix<2>)));
145 cfloatmat s11(x(Eigen::seq(Eigen::fix<1>, Eigen::last, Eigen::fix<2>), Eigen::seq(Eigen::fix<1>, Eigen::last, Eigen::fix<2>)));
151 const cfloatmat &x00 = tree_[idx][offset];
152 const cfloatmat &x01 = tree_[idx][offset + 1];
153 const cfloatmat &x10 = tree_[idx][offset + 2];
154 const cfloatmat &x11 = tree_[idx][offset + 3];
155 const unsigned int Nn = N * n;
156 for(
unsigned int i = 0; i < ndiv2; i++) {
157 for(
unsigned int j = 0; j < ndiv2; j++) {
158 const cfloat tu = twiddle_[j + Nn] * x01(i, j);
159 const cfloat td = twiddle_[(i + j) + Nn] * x11(i, j);
160 const cfloat ts = twiddle_[i + Nn] * x10(i, j);
162 const cfloat a = x00(i, j) + tu;
163 const cfloat b = x00(i, j) - tu;
164 const cfloat c = ts + td;
165 const cfloat d = ts - td;
168 x(i, j + ndiv2) = b + d;
169 x(i + ndiv2, j) = a - c;
170 x(i + ndiv2, j + ndiv2) = b - d;
173 tree_[log2i(n)].emplace_back(x);
192 const unsigned int n = x.rows();
194 return std::exchange(x(0, 0), p.state).real() !=
static_cast<float>(p.state);
196 const unsigned int ndiv2 = n >> 1U;
197 const unsigned int nndiv2 = n * ndiv2;
198 const unsigned int idx = log2i(ndiv2);
200 bool changed =
false;
201 if(
static_cast<bool>(p.row & 1U)) {
202 if(
static_cast<bool>(p.col & 1U)) {
203 changed =
update(tree_[idx][offset + 3], {p.row >> 1U, p.col >> 1U, p.state}, 4 * offset + 12);
205 changed =
update(tree_[idx][offset + 2], {p.row >> 1U, p.col >> 1U, p.state}, 4 * offset + 8);
208 if(
static_cast<bool>(p.col & 1U)) {
209 changed =
update(tree_[idx][offset + 1], {p.row >> 1U, p.col >> 1U, p.state}, 4 * offset + 4);
211 changed =
update(tree_[idx][offset], {p.row >> 1U, p.col >> 1U, p.state}, 4 * offset);
216 const cfloat *x00 = tree_[idx][offset].data();
217 const cfloat *x01 = tree_[idx][offset + 1].data();
218 const cfloat *x10 = tree_[idx][offset + 2].data();
219 const cfloat *x11 = tree_[idx][offset + 3].data();
220 cfloat *xp = x.data();
221 const unsigned int Nn = N * n;
223 for(
unsigned int j = 0; j < ndiv2; j++) {
224 const unsigned int ndiv2j = ndiv2 * j, nj = n * j;
225 for(
unsigned int i = 0; i < ndiv2; i++) {
226 const unsigned int k = i + ndiv2j, k1 = i + nj, k2 = k1 + ndiv2;
228 const cfloat tu = twiddle_[j + Nn] * x01[k];
229 const cfloat td = twiddle_[i + j + Nn] * x11[k];
230 const cfloat ts = twiddle_[i + Nn] * x10[k];
232 const cfloat x00_k = x00[k];
233 const cfloat a = x00_k + tu;
234 const cfloat b = x00_k - tu;
235 const cfloat c = ts + td;
236 const cfloat d = ts - td;
239 xp[k1 + nndiv2] = b + d;
241 xp[k2 + nndiv2] = b - d;
264 bool update(cfloatmat &x, Stimuli::iterator b0, Stimuli::iterator e0,
const unsigned int offset = 0) {
265 const unsigned int n = x.rows();
268 return std::exchange(x(0, 0), b0->state).real() !=
static_cast<float>(b0->state);
270 const bool state = std::any_of(b0, e0, [](
const Stimulus &p) {
return p.state; });
271 return std::exchange(x(0, 0), state).real() !=
static_cast<float>(state);
273 const unsigned int ndiv2 = n >> 1U;
274 const unsigned int nndiv2 = n * ndiv2;
275 const unsigned int idx = log2i(ndiv2);
277 Stimuli::iterator e1, e2, e3;
278 e2 = std::partition(b0, e0, [](
const Stimulus &p) {
return p.row & 1U; });
279 e1 = std::partition(b0, e2, [](
const Stimulus &p) {
return p.col & 1U; });
280 e3 = std::partition(e2, e0, [](
const Stimulus &p) {
return p.col & 1U; });
281 std::transform(b0, e1, b0, [](
const Stimulus &p) {
return Stimulus{p.row >> 1U, p.col >> 1U, p.state}; });
282 std::transform(e1, e2, e1, [](
const Stimulus &p) {
return Stimulus{p.row >> 1U, p.col >> 1U, p.state}; });
283 std::transform(e2, e3, e2, [](
const Stimulus &p) {
return Stimulus{p.row >> 1U, p.col >> 1U, p.state}; });
284 std::transform(e3, e0, e3, [](
const Stimulus &p) {
return Stimulus{p.row >> 1U, p.col >> 1U, p.state}; });
286 bool changed =
false;
288 changed =
update(tree_[idx][offset + 3], b0, e1, 4 * offset + 12) || changed;
291 changed =
update(tree_[idx][offset + 2], e1, e2, 4 * offset + 8) || changed;
294 changed =
update(tree_[idx][offset + 1], e2, e3, 4 * offset + 4) || changed;
297 changed =
update(tree_[idx][offset], e3, e0, 4 * offset) || changed;
301 const cfloat *x00 = tree_[idx][offset].data();
302 const cfloat *x01 = tree_[idx][offset + 1].data();
303 const cfloat *x10 = tree_[idx][offset + 2].data();
304 const cfloat *x11 = tree_[idx][offset + 3].data();
305 cfloat *xp = x.data();
306 const unsigned int Nn = N * n;
308 for(
unsigned int j = 0; j < ndiv2; j++) {
309 const unsigned int ndiv2j = ndiv2 * j, nj = n * j;
310 for(
unsigned int i = 0; i < ndiv2; i++) {
311 const unsigned int k = i + ndiv2j, k1 = i + nj, k2 = k1 + ndiv2;
313 const cfloat tu = twiddle_[j + Nn] * x01[k];
314 const cfloat td = twiddle_[i + j + Nn] * x11[k];
315 const cfloat ts = twiddle_[i + Nn] * x10[k];
317 const cfloat x00_k = x00[k];
318 const cfloat a = x00_k + tu;
319 const cfloat b = x00_k - tu;
320 const cfloat c = ts + td;
321 const cfloat d = ts - td;
324 xp[k1 + nndiv2] = b + d;
326 xp[k2 + nndiv2] = b - d;
340 plan_ = fftw_plan_dft_2d(N, N, fftwInput_.data(), fftwOutput_.data(), FFTW_FORWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
397 return Eigen::Map<const Eigen::Matrix<std::complex<double>, N, N, Eigen::RowMajor>>(
reinterpret_cast<const std::complex<double> *
>(fftwOutput_.data())).template cast<cfloat>();