Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port signed integer math to modern QDK #1841

Merged
merged 16 commits into from
Aug 22, 2024
2 changes: 2 additions & 0 deletions library/signed/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Signed
The `signed` library defines signed quantum integer primitives and operations.
21 changes: 21 additions & 0 deletions library/signed/qsharp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"author": "Microsoft",
"license": "MIT",
"dependencies": {
"Unstable": {
"github": {
"owner": "Microsoft",
"repo": "qsharp",
"ref": "d1fb2a1",
"path": "library/unstable"
}
}
},
"files": [
"src/Comparison.qs",
"src/Measurement.qs",
"src/Operations.qs",
"src/Tests.qs",
"src/Utils.qs"
]
}
104 changes: 104 additions & 0 deletions library/signed/src/Comparison.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import Std.Arrays.Tail, Std.Arrays.Zipped, Std.Arrays.Most, Std.Arrays.Rest;
import Utils.ApplyCCNOTChain;

/// # Summary
/// Wrapper for signed integer comparison: `result = xs > ys`.
///
/// # Input
/// ## xs
/// First $n$-bit number
/// ## ys
/// Second $n$-bit number
/// ## result
/// Will be flipped if $xs > ys$
operation CompareGTSI(xs : Qubit[], ys : Qubit[], result : Qubit) : Unit is Adj + Ctl {
sezna marked this conversation as resolved.
Show resolved Hide resolved
use tmp = Qubit();
CNOT(Tail(xs), tmp);
CNOT(Tail(ys), tmp);
X(tmp);
Controlled CompareGTI([tmp], (xs, ys, result));
X(tmp);
CCNOT(tmp, Tail(ys), result);
CNOT(Tail(xs), tmp);
CNOT(Tail(ys), tmp);
sezna marked this conversation as resolved.
Show resolved Hide resolved
}


/// # Summary
/// Wrapper for integer comparison: `result = x > y`.
///
/// # Input
/// ## xs
/// First $n$-bit number
/// ## ys
/// Second $n$-bit number
/// ## result
/// Will be flipped if $x > y$
operation CompareGTI(xs : Qubit[], ys : Qubit[], result : Qubit) : Unit is Adj + Ctl {
sezna marked this conversation as resolved.
Show resolved Hide resolved
GreaterThan(xs, ys, result);
}

/// # Summary
/// Applies a greater-than comparison between two integers encoded into
sezna marked this conversation as resolved.
Show resolved Hide resolved
/// qubit registers, flipping a target qubit based on the result of the
/// comparison.
///
/// # Description
/// Carries out a strictly greater than comparison of two integers $x$ and $y$, encoded
/// in qubit registers xs and ys. If $x > y$, then the result qubit will be flipped,
/// otherwise the result qubit will retain its state.
///
/// # Input
/// ## xs
/// LittleEndian qubit register encoding the first integer $x$.
/// ## ys
/// LittleEndian qubit register encoding the second integer $y$.
/// ## result
/// Single qubit that will be flipped if $x > y$.
///
/// # References
/// - Steven A. Cuccaro, Thomas G. Draper, Samuel A. Kutin, David
/// Petrie Moulton: "A new quantum ripple-carry addition circuit", 2004.
/// https://arxiv.org/abs/quant-ph/0410184v1
///
/// - Thomas Haener, Martin Roetteler, Krysta M. Svore: "Factoring using 2n+2 qubits
/// with Toffoli based modular multiplication", 2016
/// https://arxiv.org/abs/1611.07995
///
/// # Remarks
/// Uses the trick that $x - y = (x'+y)'$, where ' denotes the one's complement.
operation GreaterThan(xs : Qubit[], ys : Qubit[], result : Qubit) : Unit is Adj + Ctl {
body (...) {
(Controlled GreaterThan)([], (xs, ys, result));
}
controlled (controls, ...) {
let nQubits = Length(xs);
sezna marked this conversation as resolved.
Show resolved Hide resolved

if (nQubits == 1) {
X(ys[0]);
(Controlled CCNOT)(controls, (xs[0], ys[0], result));
X(ys[0]);
} else {
within {
ApplyToEachCA(X, ys);
ApplyToEachCA(CNOT, Zipped(Rest(xs), Rest(ys)));
} apply {
within {
(Adjoint ApplyCNOTChain)(Rest(xs));
ApplyCCNOTChain(Most(ys), xs);
} apply {
(Controlled CCNOT)(controls, (xs[nQubits-1], ys[nQubits-1], result));
}
(Controlled CNOT)(controls, (xs[nQubits-1], result));
}
}
}
}

export
CompareGTSI,
CompareGTI,
GreaterThan;
49 changes: 49 additions & 0 deletions library/signed/src/Measurement.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import Std.Diagnostics.Fact;
import Operations.Invert2sSI;

/// # Summary
/// Measures a signed integer of a given width.
/// If the width is 4, the qubit register will be measured as a 4-bit signed integer.
/// This means that bit n is the sign bit, and bits n-1 to 0 are the integer value.
/// If fewer than `width` qubits are provided, the remaining bits are assumed to be 0.
/// For example, if qubit register `[q1, q2, q3]` is passed in, but the width is 5,
/// the integer value will be measured as `[0, 0, q1, q2, q3]`, with the first 0 being
/// the sign bit (positive). This is in contrast to the standard library `MeasureInteger`,
/// which always measures unsigned integers up to and including 63 qubits in width.
/// If the length of the qubit register passed in is greater than the width, this operation
/// will throw an error.
///
/// # Input
/// ## target
/// A qubit register representing the signed integer to be measured.
///
/// ## width
/// The width of the signed integer to be measured.
operation MeasureSignedInteger(target : Qubit[], width : Int) : Int {
sezna marked this conversation as resolved.
Show resolved Hide resolved
let nBits = Length(target);
Fact(nBits <= 64, $"`Length(target)` must be less than or equal to 64, but was {nBits}.");
Fact(nBits <= width, $"`Length(target)` must be less than or equal to `width`, but was {nBits}.");

mutable coefficient = 1;
let signBit = MResetZ(target[nBits - 1]);
cesarzc marked this conversation as resolved.
Show resolved Hide resolved
if (signBit == One) {
Operations.Invert2sSI(target);
set coefficient = -1;
}

mutable number = 0;
for i in 0..nBits - 2 {
if (MResetZ(target[i]) == One) {
set number |||= 1 <<< i;
}
}

ResetAll(target);

number * coefficient
}

export MeasureSignedInteger;
Loading
Loading