From 3e57f921ab2c35a6621b3a755c260cc031a27285 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Tue, 16 Jun 2020 14:36:15 -0700 Subject: [PATCH 1/5] Fix #256. --- .../QCTraceSimulator/InterfaceUtils.cs | 15 +++++++ .../Simulators/QCTraceSimulator/Utils.cs | 42 +++++++++++-------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/Simulation/Simulators/QCTraceSimulator/InterfaceUtils.cs b/src/Simulation/Simulators/QCTraceSimulator/InterfaceUtils.cs index 79395f62ec6..f3beba01330 100644 --- a/src/Simulation/Simulators/QCTraceSimulator/InterfaceUtils.cs +++ b/src/Simulation/Simulators/QCTraceSimulator/InterfaceUtils.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Collections.Generic; using System.Diagnostics; using Microsoft.Quantum.Simulation.Core; @@ -73,5 +74,19 @@ public static partial class Extensions { return InterfaceType(t, typeof(IControllable<>)); } + + internal static IEnumerable SelectAggregates( + this IEnumerable source, + Func aggregate, + TResult initial = default + ) + { + var acc = initial; + foreach (var element in source) + { + acc = aggregate(acc, element); + yield return acc; + } + } } } \ No newline at end of file diff --git a/src/Simulation/Simulators/QCTraceSimulator/Utils.cs b/src/Simulation/Simulators/QCTraceSimulator/Utils.cs index 203173c3137..9f991e7ed0c 100644 --- a/src/Simulation/Simulators/QCTraceSimulator/Utils.cs +++ b/src/Simulation/Simulators/QCTraceSimulator/Utils.cs @@ -1,7 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; using System.Collections.Generic; +using System.Linq; using Microsoft.Quantum.Simulation.Core; using Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime; @@ -214,32 +216,36 @@ static class SimulatorsUtils /// Number between Zero and one, uniformly distributed public static long SampleDistribution(IQArray unnormalizedDistribution, double uniformZeroOneSample) { - double total = 0.0; - foreach (double prob in unnormalizedDistribution) + if (unnormalizedDistribution.Any(prob => prob < 0.0)) { - if (prob < 0) - { - throw new ExecutionFailException("Random expects array of non-negative doubles."); - } - total += prob; + 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."); } - double sample = uniformZeroOneSample * total; - double sum = unnormalizedDistribution[0]; - for (int i = 0; i < unnormalizedDistribution.Length - 1; ++i) - { - if (sum >= sample) - { - return i; - } - sum += unnormalizedDistribution[i]; - } - return unnormalizedDistribution.Length; + 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(); } } } From 0aa836ea32efc75476885269d8733aea2030a106 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Tue, 16 Jun 2020 14:39:32 -0700 Subject: [PATCH 2/5] Added regression test. --- .../Circuits/RandomTests.qs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/Simulation/QCTraceSimulator.Tests/Circuits/RandomTests.qs diff --git a/src/Simulation/QCTraceSimulator.Tests/Circuits/RandomTests.qs b/src/Simulation/QCTraceSimulator.Tests/Circuits/RandomTests.qs new file mode 100644 index 00000000000..23557589e92 --- /dev/null +++ b/src/Simulation/QCTraceSimulator.Tests/Circuits/RandomTests.qs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + + +namespace Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime.Tests { + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Diagnostics; + + @Test("QCTraceSimulator") + /// # Summary + /// Checks for regression against microsoft/qsharp-runtime#256. + operation CheckRandomInCorrectRange() : Unit { + for (idxTrial in 0..99) { + let sample = Random([1.0, 2.0, 2.0]); + Fact(0 <= sample <= 2, $"sample was {sample}, not in range [0, 2]"); + } + } +} From 87e31f80b85ca0e8705b0f930735f83406427a73 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Tue, 16 Jun 2020 15:40:37 -0700 Subject: [PATCH 3/5] Fixed test target. --- src/Simulation/QCTraceSimulator.Tests/Circuits/RandomTests.qs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Simulation/QCTraceSimulator.Tests/Circuits/RandomTests.qs b/src/Simulation/QCTraceSimulator.Tests/Circuits/RandomTests.qs index 23557589e92..5b78aaac83e 100644 --- a/src/Simulation/QCTraceSimulator.Tests/Circuits/RandomTests.qs +++ b/src/Simulation/QCTraceSimulator.Tests/Circuits/RandomTests.qs @@ -6,7 +6,7 @@ namespace Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime.Tests { open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Diagnostics; - @Test("QCTraceSimulator") + @Test("ResourcesEstimator") /// # Summary /// Checks for regression against microsoft/qsharp-runtime#256. operation CheckRandomInCorrectRange() : Unit { From ffb1bf39dc9a35b1ba24d48eb28cce0e8b642974 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Tue, 16 Jun 2020 21:18:49 -0700 Subject: [PATCH 4/5] Add internal fact. --- .../QCTraceSimulator.Tests/Circuits/RandomTests.qs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Simulation/QCTraceSimulator.Tests/Circuits/RandomTests.qs b/src/Simulation/QCTraceSimulator.Tests/Circuits/RandomTests.qs index 5b78aaac83e..b70b0b19878 100644 --- a/src/Simulation/QCTraceSimulator.Tests/Circuits/RandomTests.qs +++ b/src/Simulation/QCTraceSimulator.Tests/Circuits/RandomTests.qs @@ -6,12 +6,19 @@ namespace Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime.Tests { open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Diagnostics; + internal function Fact(condition : Bool, message : String) : Unit { + if (not condition) { + fail message; + } + } + @Test("ResourcesEstimator") /// # Summary /// Checks for regression against microsoft/qsharp-runtime#256. operation CheckRandomInCorrectRange() : Unit { for (idxTrial in 0..99) { let sample = Random([1.0, 2.0, 2.0]); + Fact(0 <= sample <= 2, $"sample was {sample}, not in range [0, 2]"); } } From 81334f2874569e3662979ddbd8afd2649c5bedfe Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Tue, 16 Jun 2020 21:30:29 -0700 Subject: [PATCH 5/5] Fix fact. --- src/Simulation/QCTraceSimulator.Tests/Circuits/RandomTests.qs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Simulation/QCTraceSimulator.Tests/Circuits/RandomTests.qs b/src/Simulation/QCTraceSimulator.Tests/Circuits/RandomTests.qs index b70b0b19878..b37c8c0c33f 100644 --- a/src/Simulation/QCTraceSimulator.Tests/Circuits/RandomTests.qs +++ b/src/Simulation/QCTraceSimulator.Tests/Circuits/RandomTests.qs @@ -19,7 +19,7 @@ namespace Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime.Tests { for (idxTrial in 0..99) { let sample = Random([1.0, 2.0, 2.0]); - Fact(0 <= sample <= 2, $"sample was {sample}, not in range [0, 2]"); + Fact(0 <= sample and sample <= 2, $"sample was {sample}, not in range [0, 2]"); } } }