Example #1
0
        /// <summary>
        /// Takes an array of doubles as
        /// input, and returns a randomly-selected index into the array
        /// as an `Int`. The probability of selecting a specific index
        /// is proportional to the value of the array element at that index.
        /// Array elements that are equal to zero are ignored and their indices
        /// are never returned.If any array element is less than zero, or if
        /// no array element is greater than zero, then the operation fails.
        /// As a source of randomness uses a number uniformly distributed between 0 and 1.
        /// Used for Quantum.Intrinsic.Random
        /// </summary>
        /// <param name="uniformZeroOneSample"> Number between Zero and one, uniformly distributed</param>
        public static long SampleDistribution(IQArray <double> unnormalizedDistribution, double uniformZeroOneSample)
        {
            if (unnormalizedDistribution.Any(prob => prob < 0.0))
            {
                throw new ExecutionFailException("Random expects array of non-negative doubles.");
            }

            var total = unnormalizedDistribution.Sum();

            if (total == 0)
            {
                throw new ExecutionFailException("Random expects array of non-negative doubles with positive sum.");
            }

            var sample = uniformZeroOneSample * total;

            return(unnormalizedDistribution
                   // Get the unnormalized CDF of the distribution.
                   .SelectAggregates((double acc, double x) => acc + x)
                   // Look for the first index at which the CDF is bigger
                   // than the random sample of 𝑈(0, 1) that we were given
                   // as a parameter.
                   .Select((cumulativeProb, idx) => (cumulativeProb, idx))
                   .Where(item => item.cumulativeProb >= sample)
                   // Cast that index to long, and default to returning
                   // the last item.
                   .Select(
                       item => (long)item.idx
                       )
                   .DefaultIfEmpty(
                       unnormalizedDistribution.Length - 1
                       )
                   .First());
        }