/// <summary>
        /// Performs a reduction using a reduction logic.
        /// </summary>
        /// <typeparam name="T">The underlying type of the reduction.</typeparam>
        /// <typeparam name="TShuffleDown">The type of the shuffle logic.</typeparam>
        /// <typeparam name="TReduction">The type of the reduction logic.</typeparam>
        /// <param name="accelerator">The accelerator.</param>
        /// <param name="stream">The accelerator stream.</param>
        /// <param name="input">The input elements to reduce.</param>
        /// <param name="shuffleDown">The shuffle logic.</param>
        /// <param name="reduction">The reduction logic.</param>
        /// <remarks>Uses the internal cache to realize a temporary output buffer.</remarks>
        /// <returns>The reduced value.</returns>
        public static T Reduce <T, TShuffleDown, TReduction>(
            this Accelerator accelerator,
            AcceleratorStream stream,
            ArrayView <T> input,
            TShuffleDown shuffleDown,
            TReduction reduction)
            where T : struct
            where TShuffleDown : struct, IShuffleDown <T>
            where TReduction : struct, IReduction <T>
        {
            if (!input.IsValid)
            {
                throw new ArgumentNullException(nameof(input));
            }
            if (input.Length < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(input));
            }
            var tempStorageSize = accelerator.ComputeReductionTempStorageSize(input.Length);
            var storage         = accelerator.MemoryCache.Allocate <T>(tempStorageSize + 1);
            var output          = storage.GetSubView(0, 1);
            var temp            = storage.GetSubView(1);

            accelerator.Reduce(
                stream,
                input,
                output,
                temp,
                shuffleDown,
                reduction);
            stream.Synchronize();
            accelerator.MemoryCache.CopyTo(out T result, 0);
            return(result);
        }
        /// <summary>
        /// Performs a reduction using a reduction logic.
        /// </summary>
        /// <typeparam name="T">The underlying type of the reduction.</typeparam>
        /// <typeparam name="TShuffleDown">The type of the shuffle logic.</typeparam>
        /// <typeparam name="TReduction">The type of the reduction logic.</typeparam>
        /// <param name="accelerator">The accelerator.</param>
        /// <param name="stream">The accelerator stream.</param>
        /// <param name="input">The input elements to reduce.</param>
        /// <param name="output">The output view to store the reduced value.</param>
        /// <param name="shuffleDown">The shuffle logic.</param>
        /// <param name="reduction">The reduction logic.</param>
        /// <remarks>Uses the internal cache to realize a temporary output buffer.</remarks>
        public static void Reduce <T, TShuffleDown, TReduction>(
            this Accelerator accelerator,
            AcceleratorStream stream,
            ArrayView <T> input,
            ArrayView <T> output,
            TShuffleDown shuffleDown,
            TReduction reduction)
            where T : struct
            where TShuffleDown : struct, IShuffleDown <T>
            where TReduction : struct, IReduction <T>
        {
            if (!input.IsValid)
            {
                throw new ArgumentNullException(nameof(input));
            }
            if (input.Length < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(input));
            }
            var tempStorageSize = accelerator.ComputeReductionTempStorageSize(input.Length);
            var temp            = accelerator.MemoryCache.Allocate <T>(tempStorageSize);

            accelerator.CreateReduction <T, TShuffleDown, TReduction>()(
                stream,
                input,
                output,
                temp,
                shuffleDown,
                reduction);
        }