Skip to content

Commit

Permalink
Added comparisons to Arithmetic namespace (#893)
Browse files Browse the repository at this point in the history
Added comparisons and tests.

---------

Co-authored-by: Dmitry Vasilevsky <[email protected]>
  • Loading branch information
DmitryVasilevsky and Dmitry Vasilevsky authored Dec 8, 2023
1 parent b24ad5a commit 353bd64
Show file tree
Hide file tree
Showing 5 changed files with 611 additions and 3 deletions.
34 changes: 32 additions & 2 deletions library/std/convert.qs
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@ namespace Microsoft.Quantum.Convert {
///
/// # Input
/// ## number
/// A non-negative integer to be converted to an array of boolean values.
/// A non-negative integer to be converted to an array of Boolean values.
/// ## bits
/// The number of bits in the binary representation of `number`.
///
/// # Output
/// An array of boolean values representing `number`.
/// An array of Boolean values representing `number`.
///
/// # Remarks
/// The input `bits` must be non-negative.
Expand All @@ -97,6 +97,36 @@ namespace Microsoft.Quantum.Convert {
result
}

/// # Summary
/// Produces a binary representation of a non-negative BigInt, using the
/// little-endian representation for the returned array.
///
/// # Input
/// ## number
/// A non-negative BigInt to be converted to an array of Boolean values.
/// ## bits
/// The number of bits in the binary representation of `number`.
///
/// # Output
/// An array of Boolean values representing `number`.
///
/// # Remarks
/// The input `bits` must be non-negative.
/// The input `number` must be between 0 and 2^bits - 1.
function BigIntAsBoolArray(number : BigInt, bits : Int) : Bool[] {
Fact(bits >= 0, "Requested number of bits must be non-negative.");
Fact(number >= 0L, "Number must be non-negative.");
mutable runningValue = number;
mutable result = [];
for _ in 1..bits {
set result += [ (runningValue &&& 1L) != 0L ];
set runningValue >>>= 1;
}
Fact(runningValue == 0L, $"`number`={number} is too large to fit into {bits} bits.");

result
}

/// # Summary
/// Produces a non-negative integer from a string of Results in little-endian format.
///
Expand Down
223 changes: 222 additions & 1 deletion library/std/unstable_arithmetic.qs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic {
open Microsoft.Quantum.Arrays;
open Microsoft.Quantum.Diagnostics;
open Microsoft.Quantum.Math;
open Microsoft.Quantum.Convert;

/// # Summary
/// This applies the in-place majority operation to 3 qubits.
Expand Down Expand Up @@ -511,4 +512,224 @@ namespace Microsoft.Quantum.Unstable.Arithmetic {
}
}

}
//
// Compare BigInt and qubit register in a little-endian format
//
// target ^= c < x | InvertIfLessL
// target ^= c <= x | InvertIfLessOrEqualL
// target ^= c == x | InvertIfEqualL
// target ^= c >= x | InvertIfGreaterOrEqualL
// target ^= c > x | InvertIfGreaterL
//

/// # Summary
/// Computes `target ^= (c < x)`, that is, inverts `target`
/// if a BigInt value `c` is less than the little-endian qubit register `x`
operation InvertIfLessL (c : BigInt, x : Qubit[], target : Qubit) : Unit is Adj + Ctl {
ApplyActionIfGreaterThanOrEqualConstant(false, X, c + 1L, x, target);
}

/// # Summary
/// Computes `target ^= (c <= x)`, that is, inverts `target`
/// if a BigInt value `c` is less or equal to the little-endian qubit register `x`
operation InvertIfLessOrEqualL (c : BigInt, x : Qubit[], target : Qubit) : Unit is Adj + Ctl {
ApplyActionIfGreaterThanOrEqualConstant(false, X, c, x, target);
}

/// # Summary
/// Computes `target ^= (c == x)`, that is, inverts `target`
/// if a BigInt value `c` is equal to the little-endian qubit register `x`
operation InvertIfEqualL (c : BigInt, xs : Qubit[], target : Qubit) : Unit is Adj + Ctl {
let cBitSize = BitSizeL(c);
let xLen = Length(xs);
if (cBitSize <= xLen) {
let bits = BigIntAsBoolArray(c, Length(xs));
within {
ApplyPauliFromBitString(PauliX, false, bits, xs);
} apply {
Controlled X(xs, target);
}
}
}

/// # Summary
/// Computes `target ^= (c >= x)`, that is, inverts `target`
/// if a BigInt value `c` is greater or equal to the little-endian qubit register `x`
operation InvertIfGreaterOrEqualL (c : BigInt, x : Qubit[], target : Qubit) : Unit is Adj + Ctl {
ApplyActionIfGreaterThanOrEqualConstant(true, X, c + 1L, x, target);
}

/// # Summary
/// Computes `target ^= (c > x)`, that is, inverts `target`
/// if a BigInt value `c` is greater than the little-endian qubit register `x`
operation InvertIfGreaterL (c : BigInt, x : Qubit[], target : Qubit) : Unit is Adj + Ctl {
ApplyActionIfGreaterThanOrEqualConstant(true, X, c, x, target);
}

//
// Compare two qubit registers in a little-endian format
//
// target ^= x < y | InvertIfLessLE
// target ^= x <= y | InvertIfLessOrEqualLE
// target ^= x == y | InvertIfEqualLE
// target ^= x >= y | InvertIfGreaterOrEqualLE
// target ^= x > y | InvertIfGreaterLE
//

/// # Summary
/// Computes `target ^= (x < y)`, that is, inverts `target`
/// if register `x` is less than the register `y`.
/// Both qubit registers should be in a little-endian format.
operation InvertIfLessLE (x : Qubit[], y : Qubit[], target : Qubit) : Unit is Adj + Ctl {
InvertIfGreaterLE(y, x, target);
}

/// # Summary
/// Computes `target ^= (x <= y)`, that is, inverts `target`
/// if register `x` is less or equal to the register `y`.
/// Both qubit registers should be in a little-endian format.
operation InvertIfLessOrEqualLE (x : Qubit[], y : Qubit[], target : Qubit) : Unit is Adj + Ctl {
Fact(Length(x) > 0, "Bitwidth must be at least 1");

within {
ApplyToEachA(X, x);
} apply {
ApplyActionIfSumOverflows(X, x, y, false, target);
}
}

/// # Summary
/// Computes `target ^= (x == y)`, that is, inverts `target`
/// if register `x` is equal to the register `y`.
/// Both qubit registers should be in a little-endian format.
operation InvertIfEqualLE (x : Qubit[], y : Qubit[], target : Qubit) : Unit is Adj + Ctl {
Fact(Length(x) == Length(y), "x and y must be of same length");

within {
for i in IndexRange(x) {
CNOT(x[i], y[i]);
X(y[i]);
}
} apply {
Controlled X(y, target);
}
}

/// # Summary
/// Computes `target ^= (x >= y)`, that is, inverts `target`
/// if register `x` is greater or equal to the register `y`.
/// Both qubit registers should be in a little-endian format.
operation InvertIfGreaterOrEqualLE (x : Qubit[], y : Qubit[], target : Qubit) : Unit is Adj + Ctl {
InvertIfLessOrEqualLE(y, x, target);
}

/// # Summary
/// Computes `target ^= (x > y)`, that is, inverts `target`
/// if register `x` is greater than the register `y`.
/// Both qubit registers should be in a little-endian format.
operation InvertIfGreaterLE (x : Qubit[], y : Qubit[], target : Qubit) : Unit is Adj + Ctl {
Fact(Length(x) > 0, "Bitwidth must be at least 1");

within {
ApplyToEachA(X, x);
} apply {
ApplyActionIfSumOverflows(X, x, y, true, target);
}
}

//
// Compare two qubit registers in a little-endian format and apply action
//
// if x < y { action(target) } | ApplyIfLessLE
// if x <= y { action(target) } | ApplyIfLessOrEqualLE
// if x == y { action(target) } | ApplyIfEqualLE
// if x >= y { action(target) } | ApplyIfGreaterOrEqualLE
// if x > y { action(target) } | ApplyIfGreaterLE
//

/// # Summary
/// Computes `if x < y { action(target) }`, that is, applies `action` to `target`
/// if register `x` is less than the register `y`.
/// Both qubit registers should be in a little-endian format.
operation ApplyIfLessLE<'T> (
action : 'T => Unit is Adj + Ctl,
x : Qubit[],
y : Qubit[],
target : 'T) : Unit is Adj + Ctl {

ApplyIfGreaterLE(action, y, x, target);
}

/// # Summary
/// Computes `if x <= y { action(target) }`, that is, applies `action` to `target`
/// if register `x` is less or equal to the register `y`.
/// Both qubit registers should be in a little-endian format.
operation ApplyIfLessOrEqualLE<'T> (
action : 'T => Unit is Adj + Ctl,
x : Qubit[],
y : Qubit[],
target : 'T) : Unit is Adj + Ctl {

Fact(Length(x) > 0, "Bitwidth must be at least 1");
within {
ApplyToEachA(X, x);
} apply {
// control is not inverted
ApplyActionIfSumOverflows(action, x, y, false, target);
}
}

/// # Summary
/// Computes `x == y { action(target) }`, that is, applies `action` to `target`
/// if register `x` is equal to the register `y`.
/// Both qubit registers should be in a little-endian format.
operation ApplyIfEqualLE<'T> (
action : 'T => Unit is Adj + Ctl,
x : Qubit[],
y : Qubit[],
target : 'T) : Unit is Adj + Ctl {

Fact(Length(x) == Length(y), "x and y must be of same length");
within {
for i in IndexRange(x) {
CNOT(x[i], y[i]);
X(y[i]);
}
} apply {
Controlled action(y, target);
}
}

/// # Summary
/// Computes `if x >= y { action(target) }`, that is, applies `action` to `target`
/// if register `x` is greater or equal to the register `y`.
/// Both qubit registers should be in a little-endian format.
operation ApplyIfGreaterOrEqualLE<'T> (
action : 'T => Unit is Adj + Ctl,
x : Qubit[],
y : Qubit[],
target : 'T) : Unit is Adj + Ctl {

ApplyIfLessOrEqualLE(action, y, x, target);
}

/// # Summary
/// Computes `if x > y { action(target) }`, that is, applies `action` to `target`
/// if register `x` is greater than the register `y`.
/// Both qubit registers should be in a little-endian format.
operation ApplyIfGreaterLE<'T> (
action : 'T => Unit is Adj + Ctl,
x : Qubit[],
y : Qubit[],
target : 'T) : Unit is Adj + Ctl {

Fact(Length(x) > 0, "Bitwidth must be at least 1");
within {
ApplyToEachA(X, x);
} apply {
// control is inverted
ApplyActionIfSumOverflows(action, x, y, true, target);
}
}

}
Loading

0 comments on commit 353bd64

Please sign in to comment.