From 46ddaf79ecc9e8a6798c5d95683a2d979a50df00 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 17 Sep 2020 18:45:45 -0700 Subject: [PATCH 1/4] Added new EmptyArray function. --- src/Simulation/QsharpCore/Arrays/Empty.cs | 19 ++ src/Simulation/QsharpCore/Arrays/Empty.qs | 24 +++ .../IntrinsicTests/Arrays/Tests.qs | 203 ++++++++++++++++++ .../IntrinsicTests/Random/Tests.qs | 3 + 4 files changed, 249 insertions(+) create mode 100644 src/Simulation/QsharpCore/Arrays/Empty.cs create mode 100644 src/Simulation/QsharpCore/Arrays/Empty.qs create mode 100644 src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/Arrays/Tests.qs diff --git a/src/Simulation/QsharpCore/Arrays/Empty.cs b/src/Simulation/QsharpCore/Arrays/Empty.cs new file mode 100644 index 00000000000..efd4ae7a050 --- /dev/null +++ b/src/Simulation/QsharpCore/Arrays/Empty.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.Simulation.Core; + +namespace Microsoft.Quantum.Arrays +{ + public partial class EmptyArray + { + public class Native : EmptyArray + { + public Native(IOperationFactory m) : base(m) { } + public override Func> __Body__ => (arg) => + new QArray(); + } + } + +} diff --git a/src/Simulation/QsharpCore/Arrays/Empty.qs b/src/Simulation/QsharpCore/Arrays/Empty.qs new file mode 100644 index 00000000000..0d586def7a2 --- /dev/null +++ b/src/Simulation/QsharpCore/Arrays/Empty.qs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Arrays { + + /// # Summary + /// Returns the empty array of a given type. + /// + /// # Type Parameters + /// ## 'TElement + /// The type of elements of the array. + /// + /// # Output + /// The empty array. + /// + /// # Example + /// ```Q# + /// let empty = EmptyArray(); + /// ``` + function EmptyArray<'TElement>() : 'TElement[] { + body intrinsic; + } + +} diff --git a/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/Arrays/Tests.qs b/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/Arrays/Tests.qs new file mode 100644 index 00000000000..a70cc8ad52c --- /dev/null +++ b/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/Arrays/Tests.qs @@ -0,0 +1,203 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Arrays { + open Microsoft.Quantum.Diagnostics; + + /// # Summary + /// Checks that empty arrays are indeed empty. + @Test("QuantumSimulator") + @Test("ToffoliSimulator") + function EmptyArraysAreEmpty() : Unit { + Fact( + Length(EmptyArray()) == 0, + "Empty array of type Int[] was not actually empty." + ); + Fact( + Length(EmptyArray<(Double, Pauli[])>()) == 0, + "Empty array of type (Double, Pauli[])[] was not actually empty." + ); + } + + /// # Summary + /// Checks that @"microsoft.quantum.random.drawrandomdint" obeys ranges. + @Test("QuantumSimulator") + @Test("ToffoliSimulator") + operation CheckDrawRandomIntObeysRanges() : Unit { + let randomInt = DrawRandomInt(0, 45); + if (randomInt > 45 or randomInt < 0) { + fail $"DrawRandomInt(0, 45) returned {randomInt}, outside the allowed range."; + } + } + + /// # Summary + /// Checks that @"microsoft.quantum.random.continuousuniformdistribution" has the + /// expected moments. + @Test("QuantumSimulator") + operation CheckContinuousUniformDistributionHasRightMoments() : Unit { + CheckMeanAndVariance( + "uniform", + ContinuousUniformDistribution(0.0, 1.0), + 1000000, + (0.5, 1.0 / 12.0), + 0.02 + ); + } + + /// # Summary + /// Checks that @"microsoft.quantum.random.standardnormaldistribution" has the + /// expected moments. + @Test("QuantumSimulator") + operation CheckStandardNormalDistributionHasRightMoments() : Unit { + CheckMeanAndVariance( + "standard normal", + StandardNormalDistribution(), + 1000000, + (0.0, 1.0), + 0.02 + ); + } + + /// # Summary + /// Checks that @"microsoft.quantum.random.normaldistribution" has the + /// expected moments. + @Test("QuantumSimulator") + operation CheckNormalDistributionHasRightMoments() : Unit { + CheckMeanAndVariance( + "normal(-2.0, 5.0)", + NormalDistribution(-2.0, 5.0), + 1000000, + (-2.0, 5.0), + 0.02 + ); + } + + /// # Summary + /// Checks that @"microsoft.quantum.random.drawrandombool" has the right + /// first moment. Note that since DrawRandomBool represents a Bernoulli + /// trial, it is entirely characterized by its first moment; we don't need + /// to check variance here. + @Test("QuantumSimulator") + operation CheckDrawRandomBoolHasRightExpectation() : Unit { + // NB: DrawMany isn't available yet, since it's in the + // Microsoft.Quantum.Standard package, not QSharpCore. + let prHeads = 0.65; + let nFlips = 1000000; + let stdDev = Sqrt(IntAsDouble(nFlips) * prHeads * (1.0 - prHeads)); + let expected = IntAsDouble(nFlips) * prHeads; + let nAllowedStdDev = 4.0; + mutable nHeads = 0; + for (idx in 0..nFlips - 1) { + if (DrawRandomBool(prHeads)) { + set nHeads += 1; + } + } + + let delta = IntAsDouble(nHeads) - expected; + + Fact( + -nAllowedStdDev * stdDev <= delta and + delta <= nAllowedStdDev * stdDev, + "First moment of Bernoulli distribution was incorrect." + ); + } + + /// # Summary + /// Checks that DrawCategorical never draws elements with probability zero. + @Test("QuantumSimulator") + operation CheckImpossibleEventsAreNotDrawn() : Unit { + let distribution = CategoricalDistribution([0.5, 0.0, 0.5]); + let nTrials = 100000; + for (idxTrial in 0..nTrials - 1) { + let variate = distribution::Sample(); + Fact( + variate != 1, + "A variate of 1 was drawn from a categorical distribution, despite having a probability of 0." + ); + } + } + + // We define a couple callables to help us run continuous tests on discrete + // distributions as well. + + internal operation DrawDiscreteAsContinuous(discrete : DiscreteDistribution, delay : Unit) : Double { + return IntAsDouble(discrete::Sample()); + } + + internal function DiscreteAsContinuous(discrete : DiscreteDistribution) : ContinuousDistribution { + return ContinuousDistribution(DrawDiscreteAsContinuous(discrete, _)); + } + + @Test("QuantumSimulator") + operation CheckCategoricalMomentsAreCorrect() : Unit { + let categorical = DiscreteAsContinuous( + CategoricalDistribution([0.2, 0.5, 0.3]) + ); + let expected = 0.0 * 0.2 + 1.0 * 0.5 + 2.0 * 0.3; + let variance = PowD(0.0 - expected, 2.0) * 0.2 + + PowD(1.0 - expected, 2.0) * 0.5 + + PowD(2.0 - expected, 2.0) * 0.3; + + CheckMeanAndVariance( + "categorical([0.2, 0.5, 0.3])", + categorical, + 1000000, + (expected, variance), + 0.04 + ); + } + + @Test("QuantumSimulator") + operation CheckRescaledCategoricalMomentsAreCorrect() : Unit { + let categorical = DiscreteAsContinuous( + CategoricalDistribution([2.0, 5.0, 3.0]) + ); + let expected = 0.0 * 0.2 + 1.0 * 0.5 + 2.0 * 0.3; + let variance = PowD(0.0 - expected, 2.0) * 0.2 + + PowD(1.0 - expected, 2.0) * 0.5 + + PowD(2.0 - expected, 2.0) * 0.3; + + CheckMeanAndVariance( + "categorical([0.2, 0.5, 0.3])", + categorical, + 1000000, + (expected, variance), + 0.04 + ); + } + + @Test("QuantumSimulator") + operation CheckCategoricalHistogramIsCorrect() : Unit { + let categorical = CategoricalDistribution([0.2, 0.5, 0.3]); + mutable counts = new Int[3]; + let nSamples = 1000000; + + for (idx in 0..nSamples - 1) { + let sample = categorical::Sample(); + set counts w/= sample <- counts[sample] + 1; + } + + Fact(190000 <= counts[0] and counts[0] <= 210000, $"counts[0] was {counts[0]}, expected about 200000."); + Fact(490000 <= counts[1] and counts[1] <= 510000, $"counts[1] was {counts[1]}, expected about 500000."); + Fact(290000 <= counts[2] and counts[2] <= 310000, $"counts[2] was {counts[2]}, expected about 300000."); + } + + @Test("QuantumSimulator") + operation CheckDiscreteUniformMomentsAreCorrect() : Unit { + let (min, max) = (-3, 7); + let expected = 0.5 * (IntAsDouble(min + max)); + let variance = (1.0 / 12.0) * ( + PowD(IntAsDouble(max - min + 1), 2.0) - 1.0 + ); + CheckMeanAndVariance( + $"discrete uniform ({min}, {max})", + DiscreteAsContinuous( + DiscreteUniformDistribution(min, max) + ), + 1000000, + (expected, variance), + 0.1 + ); + } + +} diff --git a/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/Random/Tests.qs b/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/Random/Tests.qs index ab8416de9e6..aff82adbc8a 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/Random/Tests.qs +++ b/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/Random/Tests.qs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + namespace Microsoft.Quantum.Tests { open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Canon; From 82be12e8300014e0fed6ed51da366ea0a7bf5825 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 17 Sep 2020 19:24:48 -0700 Subject: [PATCH 2/4] Fix merge issue. --- .../IntrinsicTests/Arrays/Tests.qs | 181 ------------------ 1 file changed, 181 deletions(-) diff --git a/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/Arrays/Tests.qs b/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/Arrays/Tests.qs index a70cc8ad52c..3bbc428984a 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/Arrays/Tests.qs +++ b/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/Arrays/Tests.qs @@ -19,185 +19,4 @@ namespace Microsoft.Quantum.Arrays { ); } - /// # Summary - /// Checks that @"microsoft.quantum.random.drawrandomdint" obeys ranges. - @Test("QuantumSimulator") - @Test("ToffoliSimulator") - operation CheckDrawRandomIntObeysRanges() : Unit { - let randomInt = DrawRandomInt(0, 45); - if (randomInt > 45 or randomInt < 0) { - fail $"DrawRandomInt(0, 45) returned {randomInt}, outside the allowed range."; - } - } - - /// # Summary - /// Checks that @"microsoft.quantum.random.continuousuniformdistribution" has the - /// expected moments. - @Test("QuantumSimulator") - operation CheckContinuousUniformDistributionHasRightMoments() : Unit { - CheckMeanAndVariance( - "uniform", - ContinuousUniformDistribution(0.0, 1.0), - 1000000, - (0.5, 1.0 / 12.0), - 0.02 - ); - } - - /// # Summary - /// Checks that @"microsoft.quantum.random.standardnormaldistribution" has the - /// expected moments. - @Test("QuantumSimulator") - operation CheckStandardNormalDistributionHasRightMoments() : Unit { - CheckMeanAndVariance( - "standard normal", - StandardNormalDistribution(), - 1000000, - (0.0, 1.0), - 0.02 - ); - } - - /// # Summary - /// Checks that @"microsoft.quantum.random.normaldistribution" has the - /// expected moments. - @Test("QuantumSimulator") - operation CheckNormalDistributionHasRightMoments() : Unit { - CheckMeanAndVariance( - "normal(-2.0, 5.0)", - NormalDistribution(-2.0, 5.0), - 1000000, - (-2.0, 5.0), - 0.02 - ); - } - - /// # Summary - /// Checks that @"microsoft.quantum.random.drawrandombool" has the right - /// first moment. Note that since DrawRandomBool represents a Bernoulli - /// trial, it is entirely characterized by its first moment; we don't need - /// to check variance here. - @Test("QuantumSimulator") - operation CheckDrawRandomBoolHasRightExpectation() : Unit { - // NB: DrawMany isn't available yet, since it's in the - // Microsoft.Quantum.Standard package, not QSharpCore. - let prHeads = 0.65; - let nFlips = 1000000; - let stdDev = Sqrt(IntAsDouble(nFlips) * prHeads * (1.0 - prHeads)); - let expected = IntAsDouble(nFlips) * prHeads; - let nAllowedStdDev = 4.0; - mutable nHeads = 0; - for (idx in 0..nFlips - 1) { - if (DrawRandomBool(prHeads)) { - set nHeads += 1; - } - } - - let delta = IntAsDouble(nHeads) - expected; - - Fact( - -nAllowedStdDev * stdDev <= delta and - delta <= nAllowedStdDev * stdDev, - "First moment of Bernoulli distribution was incorrect." - ); - } - - /// # Summary - /// Checks that DrawCategorical never draws elements with probability zero. - @Test("QuantumSimulator") - operation CheckImpossibleEventsAreNotDrawn() : Unit { - let distribution = CategoricalDistribution([0.5, 0.0, 0.5]); - let nTrials = 100000; - for (idxTrial in 0..nTrials - 1) { - let variate = distribution::Sample(); - Fact( - variate != 1, - "A variate of 1 was drawn from a categorical distribution, despite having a probability of 0." - ); - } - } - - // We define a couple callables to help us run continuous tests on discrete - // distributions as well. - - internal operation DrawDiscreteAsContinuous(discrete : DiscreteDistribution, delay : Unit) : Double { - return IntAsDouble(discrete::Sample()); - } - - internal function DiscreteAsContinuous(discrete : DiscreteDistribution) : ContinuousDistribution { - return ContinuousDistribution(DrawDiscreteAsContinuous(discrete, _)); - } - - @Test("QuantumSimulator") - operation CheckCategoricalMomentsAreCorrect() : Unit { - let categorical = DiscreteAsContinuous( - CategoricalDistribution([0.2, 0.5, 0.3]) - ); - let expected = 0.0 * 0.2 + 1.0 * 0.5 + 2.0 * 0.3; - let variance = PowD(0.0 - expected, 2.0) * 0.2 + - PowD(1.0 - expected, 2.0) * 0.5 + - PowD(2.0 - expected, 2.0) * 0.3; - - CheckMeanAndVariance( - "categorical([0.2, 0.5, 0.3])", - categorical, - 1000000, - (expected, variance), - 0.04 - ); - } - - @Test("QuantumSimulator") - operation CheckRescaledCategoricalMomentsAreCorrect() : Unit { - let categorical = DiscreteAsContinuous( - CategoricalDistribution([2.0, 5.0, 3.0]) - ); - let expected = 0.0 * 0.2 + 1.0 * 0.5 + 2.0 * 0.3; - let variance = PowD(0.0 - expected, 2.0) * 0.2 + - PowD(1.0 - expected, 2.0) * 0.5 + - PowD(2.0 - expected, 2.0) * 0.3; - - CheckMeanAndVariance( - "categorical([0.2, 0.5, 0.3])", - categorical, - 1000000, - (expected, variance), - 0.04 - ); - } - - @Test("QuantumSimulator") - operation CheckCategoricalHistogramIsCorrect() : Unit { - let categorical = CategoricalDistribution([0.2, 0.5, 0.3]); - mutable counts = new Int[3]; - let nSamples = 1000000; - - for (idx in 0..nSamples - 1) { - let sample = categorical::Sample(); - set counts w/= sample <- counts[sample] + 1; - } - - Fact(190000 <= counts[0] and counts[0] <= 210000, $"counts[0] was {counts[0]}, expected about 200000."); - Fact(490000 <= counts[1] and counts[1] <= 510000, $"counts[1] was {counts[1]}, expected about 500000."); - Fact(290000 <= counts[2] and counts[2] <= 310000, $"counts[2] was {counts[2]}, expected about 300000."); - } - - @Test("QuantumSimulator") - operation CheckDiscreteUniformMomentsAreCorrect() : Unit { - let (min, max) = (-3, 7); - let expected = 0.5 * (IntAsDouble(min + max)); - let variance = (1.0 / 12.0) * ( - PowD(IntAsDouble(max - min + 1), 2.0) - 1.0 - ); - CheckMeanAndVariance( - $"discrete uniform ({min}, {max})", - DiscreteAsContinuous( - DiscreteUniformDistribution(min, max) - ), - 1000000, - (expected, variance), - 0.1 - ); - } - } From 29a0997ee89cc6d373b4a994f4e25cc0de69bc76 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 17 Sep 2020 19:29:36 -0700 Subject: [PATCH 3/4] Adapt C# names to new dunderscore format. --- src/Simulation/QsharpCore/Arrays/Empty.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Simulation/QsharpCore/Arrays/Empty.cs b/src/Simulation/QsharpCore/Arrays/Empty.cs index efd4ae7a050..74a1c3b0273 100644 --- a/src/Simulation/QsharpCore/Arrays/Empty.cs +++ b/src/Simulation/QsharpCore/Arrays/Empty.cs @@ -6,13 +6,13 @@ namespace Microsoft.Quantum.Arrays { - public partial class EmptyArray + public partial class EmptyArray<__TElement__> { - public class Native : EmptyArray + public class Native : EmptyArray<__TElement__> { public Native(IOperationFactory m) : base(m) { } - public override Func> __Body__ => (arg) => - new QArray(); + public override Func> __Body__ => (arg) => + new QArray<__TElement__>(); } } From 30ad1946279a29dd6b37617a805e7e9b4f512bc5 Mon Sep 17 00:00:00 2001 From: Chris Granade Date: Thu, 17 Sep 2020 23:28:26 -0700 Subject: [PATCH 4/4] Update src/Simulation/QsharpCore/Arrays/Empty.cs Co-authored-by: Mathias Soeken --- src/Simulation/QsharpCore/Arrays/Empty.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Simulation/QsharpCore/Arrays/Empty.cs b/src/Simulation/QsharpCore/Arrays/Empty.cs index 74a1c3b0273..7cb7448a393 100644 --- a/src/Simulation/QsharpCore/Arrays/Empty.cs +++ b/src/Simulation/QsharpCore/Arrays/Empty.cs @@ -11,7 +11,7 @@ public partial class EmptyArray<__TElement__> public class Native : EmptyArray<__TElement__> { public Native(IOperationFactory m) : base(m) { } - public override Func> __Body__ => (arg) => + public override Func> __Body__ => _ => new QArray<__TElement__>(); } }