/// <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()); }