示例#1
0
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;
}