void bucket_permutate(tkernel<T> & kernel , const glm::uint16 subkernel_width , const glm::uint16 subkernel_height , const glm::uint16 subkernel_depth , const bool permutate_per_bucket) { assert(subkernel_width > 0); assert(subkernel_height > 0); assert(subkernel_depth > 0); assert(subkernel_width <= kernel.width()); assert(subkernel_height <= kernel.height()); assert(subkernel_depth <= kernel.depth()); assert(kernel.width() % subkernel_width == 0); assert(kernel.height() % subkernel_height == 0); assert(kernel.depth() % subkernel_depth == 0); // the number of the elements required to fill a sub-kernel is the number of required buckets const auto num_buckets = subkernel_width * subkernel_height * subkernel_depth; assert(kernel.size() % num_buckets == 0); if (num_buckets == 0) return; std::srand(static_cast<unsigned int>(std::time(0))); // the number of sub-kernels is also the number of values per bucket const auto num_subkernels = static_cast<int>(kernel.size() / num_buckets); // create buckets by sequentially adding every kernel index and shuffling every // bucket individually to "randomly" pop back from later on ... auto buckets = std::vector<std::vector<size_t>>{ }; buckets.resize(num_buckets); auto index = 0; for (int b = 0; b < buckets.size(); ++b) { for (int i = 0; i < num_subkernels; ++i) buckets[b].push_back(index++); std::random_shuffle(buckets[b].begin(), buckets[b].end()); } // use permutations to pop the last item of each bucket, while // selecting the bucket based on the subkernels permutation ... auto subkernel_indices = std::vector<size_t>{ }; subkernel_indices.resize(num_buckets); // a copy of the given kernel is used to read and reassign values from const auto read_kernel = kernel; const auto kw_over_w = kernel.width() / subkernel_width; const auto kh_over_h = kernel.height() / subkernel_height; const auto w_step = subkernel_width; const auto h_step = subkernel_height * kernel.width(); const auto d_step = subkernel_depth * kernel.width() * kernel.height(); // create permutations (or use single, static permutation) abstract_permutations * permutations{ nullptr }; if (permutate_per_bucket) permutations = new unique_index_permutations{ num_buckets, num_subkernels }; else permutations = new static_index_permutation{ num_buckets }; for (int k = 0; k < num_subkernels; ++k) { const auto offset = w_step * (k % kw_over_w) + h_step * ((k / kw_over_w) % kh_over_h) + d_step * (k / (kw_over_w * kh_over_h)); // retrieve indices to map subkernel indices to the given kernel auto i = 0; for (int d = 0; d < subkernel_depth; ++d) for (int h = 0; h < subkernel_height; ++h) for (int w = 0; w < subkernel_width; ++w) subkernel_indices[i++] = offset + d * kernel.width() * kernel.height() + h * kernel.width() + w; for (int i_permutation = 0; i_permutation < num_buckets; ++i_permutation) { const auto i_bucket = (*permutations)(k, i_permutation); const auto i_read = buckets[i_bucket].back(); const auto i_kernel = subkernel_indices[i_permutation]; kernel[i_kernel] = read_kernel[i_read]; buckets[i_bucket].pop_back(); } } delete permutations; permutations = nullptr; }