private static void FindMaxIndexKernel(
            ArrayView <Point> input,
            int side,
            Point a,
            Point b,
            ArrayView <DataBlock <int, float> > output)
        {
            var stride   = GridExtensions.GridStrideLoopStride;
            var index    = -1;
            var distance = 0f;

            for (var i = Grid.GlobalIndex.X; i < input.Length; i += stride)
            {
                FindMaxIndex(a, b, input[i], side, i, ref index, ref distance);
            }

            var maxGroupDistance = GroupExtensions.Reduce <float, MaxFloat>(distance);

            if (!distance.Equals(maxGroupDistance))
            {
                index = -1;
            }

            var maxGroupIndex = GroupExtensions.Reduce <int, MaxInt32>(index);

            if (Group.IsFirstThread)
            {
                output[Grid.IdxX] = new DataBlock <int, float>(maxGroupIndex, maxGroupDistance);
            }
        }
        public static void ChannelMinMaxKernel(
            int channelIdx,
            int numChannels,
            ArrayView <float> input,
            ArrayView <float> output)
        {
            MinFloat minReduction = default;
            MaxFloat maxReduction = default;

            // Each kernel will apply the reductions locally.
            var stride     = GridExtensions.GridStrideLoopStride;
            var minReduced = minReduction.Identity;
            var maxReduced = maxReduction.Identity;

            for (var idx = Grid.GlobalIndex.X; idx < input.Length; idx += stride)
            {
                if (idx % numChannels == channelIdx)
                {
                    minReduced = minReduction.Apply(minReduced, input[idx]);
                    maxReduced = maxReduction.Apply(maxReduced, input[idx]);
                }
            }

            // Perform a block-wide reduction.
            minReduced = GroupExtensions.Reduce <float, MinFloat>(minReduced);
            maxReduced = GroupExtensions.Reduce <float, MaxFloat>(maxReduced);

            // The first thread of the group is responsible for writing the
            // reduced results.
            if (Group.IsFirstThread)
            {
                minReduction.AtomicApply(ref output[0], minReduced);
                maxReduction.AtomicApply(ref output[1], maxReduced);
            }
        }