From 89911494eb588e4a96ddd5d814ad16c2b4275a95 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Mon, 15 Mar 2021 17:34:14 -0700 Subject: [PATCH 1/4] Implement quantumlibraries#413. --- .../QSharpFoundation/Diagnostics/Facts.qs | 23 ++++ .../QSharpFoundation/Math/FloatingPoint.qs | 113 ++++++++++++++++++ .../TestProjects/IntrinsicTests/Math/Tests.qs | 35 ++++++ 3 files changed, 171 insertions(+) create mode 100644 src/Simulation/QSharpFoundation/Math/FloatingPoint.qs diff --git a/src/Simulation/QSharpFoundation/Diagnostics/Facts.qs b/src/Simulation/QSharpFoundation/Diagnostics/Facts.qs index df3e8ebe383..7b7ddd703af 100644 --- a/src/Simulation/QSharpFoundation/Diagnostics/Facts.qs +++ b/src/Simulation/QSharpFoundation/Diagnostics/Facts.qs @@ -48,4 +48,27 @@ namespace Microsoft.Quantum.Diagnostics { if (actual) { fail message; } } + /// # Summary + /// Declares that a given floating-point value represents a finite + /// number, failing when this is not the case. + /// + /// # Input + /// ## d + /// The floating-point value that is to be checked. + /// ## message + /// Failure message to be printed in the case that `d` is either + /// not finite, or not a number. + /// + /// # Example + /// The following Q# code will fail when run: + /// ```qsharp + /// FiniteFact(NaN(), "NaN is not a finite number."); + /// ``` + /// + /// # See Also + /// - Microsoft.Quantum.Diagnostics.Fact + function FiniteFact(d : Double, message : String) : Unit { + Fact(IsFinite(d), message); + } + } diff --git a/src/Simulation/QSharpFoundation/Math/FloatingPoint.qs b/src/Simulation/QSharpFoundation/Math/FloatingPoint.qs new file mode 100644 index 00000000000..349d33db1f8 --- /dev/null +++ b/src/Simulation/QSharpFoundation/Math/FloatingPoint.qs @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Math { + + /// # Summary + /// Returns a value that is not a number (i.e. NaN). + /// + /// # Ouputs + /// A double-precision floating point value that is not a number. + /// + /// # Remarks + /// The value output by this function follows IEEE 754 rules for how `NaN` + /// works when used with other double-precision floating point values. + /// For example, for any value `x` of type `Double`, `NaN() == x` is + /// `false`; this holds even if `x` is also `NaN()`. + /// + /// # See Also + /// - Microsoft.Quantum.Math.IsNaN + /// - Microsoft.Quantum.Math.IsInfinite + /// - Microsoft.Quantum.Math.IsFinite + function NaN() : Double { + return 0.0 / 0.0; + } + + /// # Summary + /// Returns whether a given floating-point value is not a number (i.e. + /// is NaN). + /// + /// # Input + /// ## d + /// A floating-point value to be checked. + /// + /// # Output + /// `true` if and only if `d` is not a number. + /// + /// # Remarks + /// Since `NaN()` is the only floating-point value that does not equal + /// itself, this function should be used instead of checking conditions such + /// as `d = NaN()`. + /// + /// # See Also + /// - Microsoft.Quantum.Math.NaN + /// - Microsoft.Quantum.Math.IsInfinite + /// - Microsoft.Quantum.Math.IsFinite + function IsNaN(d : Double) : Bool { + return d != d; + } + + /// # Summary + /// Returns whether a given floating-point value is either positive or + /// negative infinity. + /// + /// # Input + /// ## d + /// The floating-point value to be checked. + /// + /// # Ouput + /// `true` if and only if `d` is either positive or negative infinity. + /// + /// # Remarks + /// `NaN()` is not a number, and is thus neither a finite number nor + /// is it infinite. As such, both `IsInfinite(NaN())` and `IsFinite(NaN())` + /// return `false`. To check a value against `NaN()`, use `IsNaN(d)`. + /// + /// # Example + /// ```qsharp + /// Message($"{IsInfinite(42.0)}"); // false + /// Message($"{IsInfinite(NaN())}"); // false + /// Message($"{IsInfinite(-1.0 / 0.0}"); // true + /// + /// # See Also + /// - Microsoft.Quantum.Math.NaN + /// - Microsoft.Quantum.Math.IsNaN + /// - Microsoft.Quantum.Math.IsFinite + /// ``` + function IsInfinite(d : Double) : Bool { + return d == 1.0 / 0.0 or d == -1.0 / 0.0; + // Positive and negative infinities can still be + // discriminated by checking `d > 0.0` and `d < 0.0`. + } + + /// # Summary + /// Returns whether a given floating-point value is a finite number. + /// + /// # Input + /// ## d + /// The floating-point value to be checked. + /// + /// # Ouput + /// `true` if and only if `d` is a finite number (i.e.: is neither infinite + /// nor NaN). + /// + /// # Remarks + /// `NaN()` is not a number, and is thus neither a finite number nor + /// is it infinite. As such, both `IsInfinite(NaN())` and `IsFinite(NaN())` + /// return `false`. To check a value against `NaN()`, use `IsNaN(d)`. + /// + /// # Example + /// ```qsharp + /// Message($"{IsFinite(42.0)}"); // true + /// Message($"{IsFinite(NaN())}"); // false + /// Message($"{IsFinite(-1.0 / 0.0)}"); // false + /// + /// # See Also + /// - Microsoft.Quantum.Math.NaN + /// - Microsoft.Quantum.Math.IsNaN + /// - Microsoft.Quantum.Math.IsInfinite + /// ``` + function IsFinite(d : Double) : Bool { + return not IsInfinite(d) and not IsNaN(d); + } +} diff --git a/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/Math/Tests.qs b/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/Math/Tests.qs index e9ab0883dbe..f252b3f0309 100644 --- a/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/Math/Tests.qs +++ b/src/Simulation/Simulators.Tests/TestProjects/IntrinsicTests/Math/Tests.qs @@ -84,4 +84,39 @@ namespace Microsoft.Quantum.Tests { EqualityFactL(ModPowL(8675309L, 5792L, 2345678L), 1936199L, "ModPowL(8675309L, 5792L, 2345678L) was incorrect."); } + @Test("QuantumSimulator") + function NaNIsNotEqualToAnything() : Unit { + Contradiction(NaN() == NaN(), "NaN should not equal NaN."); + Contradiction(NaN() == 42.0, "NaN should not equal any finite number."); + Contradiction(NaN() == 1.0 / 0.0, "NaN should not equal any infinite value."); + } + + @Test("QuantumSimulator") + function NaNIsNaN() : Unit { + Fact(IsNaN(NaN()), "NaN was not NaN."); + Contradiction(IsNaN(42.0), "42.0 should not be NaN."); + Contradiction(IsNaN(1.0 / 0.0), "+∞ should not be NaN."); + } + + @Test("QuantumSimulator") + function InfinityIsInfinite() : Unit { + Contradiction(IsInfinite(NaN()), "NaN should not be infinite."); + Contradiction(IsInfinite(42.0), "42.0 should not be infinite."); + Fact(IsInfinite(1.0 / 0.0), "+∞ should be infinite."); + Fact(IsInfinite(-1.0 / 0.0), "-∞ should be infinite."); + } + + @Test("QuantumSimulator") + function FiniteNumbersAreFinite() : Unit { + Contradiction(IsFinite(NaN()), "NaN should not be finite."); + Fact(IsFinite(42.0), "42.0 should be finite."); + Contradiction(IsFinite(1.0 / 0.0), "+∞ should not be finite."); + Contradiction(IsFinite(-1.0 / 0.0), "-∞ should not be finite."); + } + + @Test("QuantumSimulator") + function FiniteFactIsCorrect() : Unit { + FiniteFact(42.0, "42.0 should be finite."); + } + } From 66921d5fc8e559a22d68ff47829220589008cd94 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Mon, 15 Mar 2021 17:46:47 -0700 Subject: [PATCH 2/4] Add missing open statement. --- src/Simulation/QSharpFoundation/Diagnostics/Facts.qs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Simulation/QSharpFoundation/Diagnostics/Facts.qs b/src/Simulation/QSharpFoundation/Diagnostics/Facts.qs index 7b7ddd703af..e2c9ddca222 100644 --- a/src/Simulation/QSharpFoundation/Diagnostics/Facts.qs +++ b/src/Simulation/QSharpFoundation/Diagnostics/Facts.qs @@ -2,6 +2,7 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Diagnostics { + open Microsoft.Quantum.Math; /// # Summary /// Declares that a classical condition is true. From 4e7e3a34632eaa4145b079b611a02ac9cfc3e966 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Mon, 15 Mar 2021 17:48:35 -0700 Subject: [PATCH 3/4] Fix build warnings. --- src/Simulation/QSharpFoundation/Diagnostics/AssertAllZero.qs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Simulation/QSharpFoundation/Diagnostics/AssertAllZero.qs b/src/Simulation/QSharpFoundation/Diagnostics/AssertAllZero.qs index 52470a92f13..e9ab9120a34 100644 --- a/src/Simulation/QSharpFoundation/Diagnostics/AssertAllZero.qs +++ b/src/Simulation/QSharpFoundation/Diagnostics/AssertAllZero.qs @@ -16,7 +16,7 @@ namespace Microsoft.Quantum.Diagnostics { /// - AssertQubit operation AssertAllZero (qubits : Qubit[]) : Unit { body (...) { - for (qubit in qubits) { + for qubit in qubits { AssertQubit(Zero, qubit); } } @@ -40,9 +40,8 @@ namespace Microsoft.Quantum.Diagnostics { /// # See Also /// - AssertQubitWithinTolerance operation AssertAllZeroWithinTolerance(qubits : Qubit[], tolerance : Double) : Unit { - body (...) { - for (qubit in qubits) { + for qubit in qubits { AssertQubitWithinTolerance(Zero, qubit, tolerance); } } From 8c8fd5985d02acd09ee199cbada2f14b92907650 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Tue, 16 Mar 2021 14:49:56 -0700 Subject: [PATCH 4/4] Addressing feedback. --- src/Simulation/QSharpFoundation/Math/FloatingPoint.qs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Simulation/QSharpFoundation/Math/FloatingPoint.qs b/src/Simulation/QSharpFoundation/Math/FloatingPoint.qs index 349d33db1f8..6fd67cca089 100644 --- a/src/Simulation/QSharpFoundation/Math/FloatingPoint.qs +++ b/src/Simulation/QSharpFoundation/Math/FloatingPoint.qs @@ -37,7 +37,7 @@ namespace Microsoft.Quantum.Math { /// # Remarks /// Since `NaN()` is the only floating-point value that does not equal /// itself, this function should be used instead of checking conditions such - /// as `d = NaN()`. + /// as `d == NaN()`. /// /// # See Also /// - Microsoft.Quantum.Math.NaN @@ -63,6 +63,11 @@ namespace Microsoft.Quantum.Math { /// is it infinite. As such, both `IsInfinite(NaN())` and `IsFinite(NaN())` /// return `false`. To check a value against `NaN()`, use `IsNaN(d)`. /// + /// + /// Note that even though this function returns `true` for both + /// positive and negative infinities, these values can still be + /// discriminated by checking `d > 0.0` and `d < 0.0`. + /// /// # Example /// ```qsharp /// Message($"{IsInfinite(42.0)}"); // false @@ -76,8 +81,6 @@ namespace Microsoft.Quantum.Math { /// ``` function IsInfinite(d : Double) : Bool { return d == 1.0 / 0.0 or d == -1.0 / 0.0; - // Positive and negative infinities can still be - // discriminated by checking `d > 0.0` and `d < 0.0`. } /// # Summary