forked from microsoft/qsharp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
initial version of min max of durr hoyer algorithm, issues with DrawR…
…andomInt(), reference microsoft#1928
- Loading branch information
Showing
4 changed files
with
323 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
use super::test_expression_with_lib; | ||
use qsc::interpret::Value; | ||
|
||
// Library that includes the necessary DurrHoyerAlgorithm implementation | ||
const DURR_HOYER_LIB: &str = include_str!("resources/src/durrhoyerlibrary.qs"); | ||
|
||
#[test] | ||
fn check_durr_hoyer_minimum_test_case_1() { | ||
test_expression_with_lib( | ||
"Test.RunDurrHoyerMinimumUnitTestWithShots(1000)", | ||
DURR_HOYER_LIB, | ||
); | ||
} | ||
|
||
#[test] | ||
fn check_durr_hoyer_maximum_test_case_3() { | ||
test_expression_with_lib( | ||
"Test.RunDurrHoyerMaximumUnitTestWithShots(1000)", | ||
DURR_HOYER_LIB, | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
namespace Test { | ||
open Microsoft.Quantum.Intrinsic; | ||
open Microsoft.Quantum.Canon; | ||
open Microsoft.Quantum.Math; | ||
open Microsoft.Quantum.Measurement; | ||
open Microsoft.Quantum.Arrays; | ||
open Microsoft.Quantum.Convert; | ||
open Microsoft.Quantum.Random; | ||
open Microsoft.Quantum.Core; | ||
open Microsoft.Quantum.Diagnostics; | ||
open Microsoft.Quantum.DurrHoyerLibrary; | ||
|
||
// Function to find the maximum element in an array | ||
function MaxIntArray(arr : Int[]) : Int { | ||
mutable max = arr[0]; | ||
for i in arr[1..Length(arr) - 1] { | ||
if (arr[i] > max) { | ||
set max = arr[i]; | ||
} | ||
} | ||
return max; | ||
} | ||
|
||
// Function to compute the probability of finding the minimum index | ||
operation RunDurrHoyerMinimumUnitTestWithShots(shots : Int) : Unit { | ||
// Define test lists for the unit test | ||
let testLists = [ | ||
[5, 3, 1, 2, 4], | ||
[6, 5, 4, 3, 1], | ||
[7, 5, 6, 1, 2] | ||
]; | ||
|
||
// Expected results (minimum element index for each list) | ||
let expectedMinIndices = [2, 4, 3]; | ||
|
||
// Iterate over test cases | ||
for (list, expectedMinIndex) in Zipped(testLists, expectedMinIndices) { | ||
let maxValue = MaxIntArray(list); | ||
let double : Double = IntAsDouble(maxValue + 1); | ||
let log : Double = Log(double) / Log(2.0); | ||
let nQubits = Ceiling(log); | ||
|
||
// Variable to track how many times we find the correct minimum index | ||
mutable correctCount = 0; | ||
|
||
// Run the Durr-Hoyer algorithm multiple times (shots) | ||
for _ in 1..shots { | ||
let minIndex : Int = DurrHoyerAlgorithm(list, nQubits, "min"); | ||
|
||
// Check if the found index matches the expected minimum index | ||
if (minIndex == expectedMinIndex) { | ||
set correctCount += 1; | ||
} | ||
} | ||
|
||
// Calculate the probability of finding the correct minimum | ||
let probability = IntAsDouble(correctCount) / IntAsDouble(shots); | ||
|
||
// Assert that the probability is above 50% | ||
Assert(probability > 0.5, $"Probability of finding the minimum for list {list} is less than 50%. Found: {probability * 100.0}%"); | ||
|
||
// Optionally print debugging info | ||
Message($"List: {list}"); | ||
Message($"Probability of finding the minimum is {probability * 100.0}%"); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
open Microsoft.Quantum.Intrinsic; | ||
open Microsoft.Quantum.Canon; | ||
open Microsoft.Quantum.Math; | ||
open Microsoft.Quantum.Measurement; | ||
open Microsoft.Quantum.Arrays; | ||
open Microsoft.Quantum.Convert; | ||
open Microsoft.Quantum.Random; | ||
open Microsoft.Quantum.Core; | ||
open Microsoft.Quantum.Diagnostics; | ||
|
||
function CountElements(list : Int[], threshold : Int, comparisonType : String) : Int { | ||
mutable count = 0; | ||
|
||
for element in list { | ||
if (comparisonType == "min" and element < threshold) { | ||
set count += 1; | ||
} elif (comparisonType == "max" and element > threshold) { | ||
set count += 1; | ||
} | ||
} | ||
|
||
return count; | ||
} | ||
|
||
/// Converts an integer to its binary representation as an array of Results. | ||
/// The least significant bit is at index 0. | ||
function ConvertToBinary(value : Int, length : Int) : Result[] { | ||
// Validate input | ||
if (length <= 0) { | ||
fail "Length must be a positive integer."; | ||
} | ||
|
||
// Ensure the value fits within the specified length | ||
let maxVal = (1 <<< length) - 1; | ||
if (value < 0 or value > maxVal) { | ||
fail $"Value {value} cannot be represented with {length} bits."; | ||
} | ||
|
||
// Initialize the binary array with default values | ||
mutable binary : Result[] = []; | ||
|
||
// Generate the binary array | ||
for i in 0..length - 1 { | ||
let bitValue = value &&& (1 <<< i); // Extract the i-th bit | ||
let res = if (bitValue != 0) { One } else { Zero }; // Determine Result | ||
// Correct syntax to assign to the array | ||
set binary += [res]; | ||
|
||
} | ||
|
||
// Return the constructed binary array | ||
return binary; | ||
} | ||
function ResultAsInt(r : Result) : Int { | ||
if (r == One) { | ||
return 1; | ||
} else { | ||
return 0; | ||
} | ||
} | ||
|
||
function BitsToInt(bits : Result[]) : Int { | ||
mutable result = 0; | ||
for i in 0..Length(bits) - 1 { | ||
if (bits[i] == One) { | ||
set result += (1 <<< i); | ||
} | ||
} | ||
return result; | ||
} | ||
|
||
// Oracle that marks elements less than the threshold through Most Signficant Bit comparision | ||
operation OracleLessThan(threshold : Int, inputQubits : Qubit[], auxQubit : Qubit) : Unit is Adj + Ctl { | ||
// Convert the threshold to binary and compare | ||
let thresholdBits = ConvertToBinary(threshold, Length(inputQubits)); | ||
for i in 0..Length(thresholdBits) - 1 { | ||
if (thresholdBits[i] == Zero) { | ||
// Most Signficant Bit comparision, if There is a zero when the bits are compared we have something less than | ||
X(inputQubits[i]); // Flip qubits that should be zero in the threshold | ||
} | ||
} | ||
|
||
// Controlled-Z gate to flip the phase of the state if the element is less than the threshold | ||
Controlled Z(inputQubits, auxQubit); | ||
|
||
// Undo the X operations to revert qubits | ||
for i in 0..Length(thresholdBits) - 1 { | ||
if (thresholdBits[i] == Zero) { | ||
X(inputQubits[i]); | ||
} | ||
} | ||
} | ||
|
||
// Oracle that marks elements more than the threshold through Most Signficant Bit comparision | ||
operation OracleMoreThan(threshold : Int, inputQubits : Qubit[], auxQubit : Qubit) : Unit is Adj + Ctl { | ||
// Convert the threshold to binary and compare | ||
let thresholdBits = ConvertToBinary(threshold, Length(inputQubits)); | ||
for i in 0..Length(thresholdBits) - 1 { | ||
if (thresholdBits[i] == One) { | ||
// Most Signficant Bit comparision, if tbere is a one when the bits are compared we have something more than | ||
X(inputQubits[i]); // Flip qubits that should be zero in the threshold | ||
} | ||
} | ||
|
||
// Controlled-Z gate to flip the phase of the state if the element is less than the threshold | ||
Controlled Z(inputQubits, auxQubit); | ||
|
||
// Undo the X operations to revert qubits | ||
for i in 0..Length(thresholdBits) - 1 { | ||
if (thresholdBits[i] == One) { | ||
X(inputQubits[i]); | ||
} | ||
} | ||
} | ||
|
||
// Diffusion operator (Grover's diffusion) | ||
operation DiffusionOperator(qubits : Qubit[]) : Unit { | ||
ApplyToEach(H, qubits); | ||
ApplyToEach(X, qubits); | ||
Controlled Z(qubits[0..Length(qubits) - 2], qubits[Length(qubits) - 1]); | ||
ApplyToEach(X, qubits); | ||
ApplyToEach(H, qubits); | ||
} | ||
|
||
// Grover iteration with the oracle and diffusion operator for min | ||
operation GroverIterationMin(threshold : Int, inputQubits : Qubit[], auxQubit : Qubit) : Unit { | ||
OracleLessThan(threshold, inputQubits, auxQubit); | ||
DiffusionOperator(inputQubits); | ||
} | ||
|
||
// Grover iteration with the oracle and diffusion operator for max | ||
operation GroverIterationMax(threshold : Int, inputQubits : Qubit[], auxQubit : Qubit) : Unit { | ||
OracleMoreThan(threshold, inputQubits, auxQubit); | ||
DiffusionOperator(inputQubits); | ||
} | ||
|
||
// Dürr-Høyer for finding min or max algorithm | ||
operation DurrHoyerAlgorithm(list : Int[], nQubits : Int, type : String) : Int { | ||
mutable candidateMin = DrawRandomInt(0, Length(list) - 1); // Random initial candidate | ||
let listSize = Length(list); | ||
|
||
use inputQubits = Qubit[nQubits] { | ||
use auxQubit = Qubit() { | ||
// Create a superposition of all states | ||
ApplyToEach(H, inputQubits); | ||
|
||
// Continue Grover search until no better candidate is found | ||
mutable betterCandidateFound = true; | ||
mutable iterationCount = 1; // Track the iteration count manually | ||
mutable optimalIterations = 5; | ||
mutable validIterations = 0; | ||
|
||
while (validIterations < optimalIterations) { | ||
set betterCandidateFound = false; | ||
|
||
// Calculate M: the number of elements smaller than the current candidate (for min) | ||
let M = CountElements(list, list[candidateMin], type); | ||
|
||
// If there are no more elements smaller/larger, return the candidate | ||
if (M == 0) { | ||
Message("No more elements to compare, search complete."); | ||
ResetAll(inputQubits + [auxQubit]); // Ensure qubits are reset before returning | ||
return candidateMin; | ||
} | ||
|
||
// Calculate the optimal number of Grover iterations | ||
let N = Length(list); | ||
let optimalIterations = Round((PI() / 4.0) * Sqrt(IntAsDouble(N) / IntAsDouble(M))); | ||
|
||
// Perform Grover iterations for min or max | ||
for i in 1..optimalIterations { | ||
if (type == "min") { | ||
GroverIterationMin(list[candidateMin], inputQubits, auxQubit); | ||
} else { | ||
GroverIterationMax(list[candidateMin], inputQubits, auxQubit); | ||
} | ||
|
||
// Measure qubits and convert to an integer index | ||
mutable results = []; | ||
for qubit in inputQubits { | ||
let result = Measure([PauliZ], [qubit]); | ||
set results += [result]; | ||
|
||
// Reset qubit if it is in the |1⟩ state | ||
if (result == One) { | ||
X(qubit); | ||
} | ||
} | ||
|
||
let candidateIndex = BitsToInt(results); | ||
|
||
// Check if the new candidate is valid and within bounds | ||
if (candidateIndex >= 0 and candidateIndex < listSize) { | ||
let candidateValue = list[candidateIndex]; | ||
|
||
// Update the candidate if a better one is found | ||
if (type == "min" and candidateValue < list[candidateMin]) { | ||
OracleLessThan(list[candidateMin], inputQubits, auxQubit); // Mark the last candidate | ||
set candidateMin = candidateIndex; | ||
set betterCandidateFound = true; | ||
} elif (type == "max" and candidateValue > list[candidateMin]) { | ||
OracleMoreThan(list[candidateMin], inputQubits, auxQubit); // Mark the last candidate | ||
set candidateMin = candidateIndex; | ||
set betterCandidateFound = true; | ||
} | ||
set validIterations += 1; | ||
|
||
// Output intermediate results for debugging | ||
Message($"Iteration {validIterations}: Measured index = {candidateIndex}, Value = {candidateValue}"); | ||
} | ||
// Reset all qubits to |0⟩ before returning | ||
ResetAll(inputQubits + [auxQubit]); | ||
|
||
} | ||
|
||
} | ||
|
||
// Reset all qubits to |0⟩ before returning | ||
ResetAll(inputQubits + [auxQubit]); | ||
|
||
// Return the found minimum or maximum index | ||
return candidateMin; | ||
} | ||
} | ||
} | ||
export DurrHoyerAlgorithm; |