Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ jobs:
- name: Install requirements
run: |
pip install pytest
pip install qsharp==1.19.0
pip install qdk==1.29.1
- name: Run tests
run: pytest
1 change: 1 addition & 0 deletions lib/qsharp.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"src/QuantumArithmetic/DM2004.qs",
"src/QuantumArithmetic/GKDKH2021.qs",
"src/QuantumArithmetic/JHHA2016.qs",
"src/QuantumArithmetic/LAInc.qs",
"src/QuantumArithmetic/LYTZW2013.qs",
"src/QuantumArithmetic/LYY2021.qs",
"src/QuantumArithmetic/MCT2017.qs",
Expand Down
17 changes: 15 additions & 2 deletions lib/src/EstimateUtils.qs
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
/// Runs operation on the given number of qubits.
operation RunUnaryOp(n : Int, op : (Qubit[]) => Unit) : Unit {
use a = Qubit[n];
op(a);
}

/// Runs controlled operation on the given number of qubits.
operation RunUnaryOpCtl(n : Int, op : (Qubit[]) => Unit is Ctl) : Unit {
use ctrl = Qubit[1];
use a = Qubit[n];
Controlled op(ctrl, (a));
}

operation BinaryOpExtraOut(n : Int, x_val : Int, y_val : Int, op : (Qubit[], Qubit[], Qubit[], Qubit) => Unit) : Int {
use x = Qubit[n];
use y = Qubit[n];
Expand Down Expand Up @@ -53,14 +66,14 @@ operation RunModExp(n : Int, op : (Qubit[], Qubit[], BigInt, BigInt) => Unit) :
op(x_qubits, ans, a, N);
}

operation RunRadix(n: Int, radix: Int, op : (Qubit[], Qubit[], Qubit[], Int, (Qubit[], Qubit[], Qubit[]) => Unit is Adj) => Unit is Adj, adder_op: (Qubit[], Qubit[], Qubit[]) => Unit is Adj) : Unit {
operation RunRadix(n : Int, radix : Int, op : (Qubit[], Qubit[], Qubit[], Int, (Qubit[], Qubit[], Qubit[]) => Unit is Adj) => Unit is Adj, adder_op : (Qubit[], Qubit[], Qubit[]) => Unit is Adj) : Unit {
use a = Qubit[n];
use b = Qubit[n];
use c = Qubit[n];
op(a, b, c, radix, adder_op);
}

operation RunRadixCarry(n: Int, radix: Int, op : (Qubit[], Qubit[], Qubit[], Int, (Qubit[], Qubit[], Qubit[], Qubit) => Unit is Adj) => Unit is Adj, adder_op: (Qubit[], Qubit[], Qubit[], Qubit) => Unit is Adj) : Unit {
operation RunRadixCarry(n : Int, radix : Int, op : (Qubit[], Qubit[], Qubit[], Int, (Qubit[], Qubit[], Qubit[], Qubit) => Unit is Adj) => Unit is Adj, adder_op : (Qubit[], Qubit[], Qubit[], Qubit) => Unit is Adj) : Unit {
use a = Qubit[n];
use b = Qubit[n];
use c = Qubit[n];
Expand Down
154 changes: 154 additions & 0 deletions lib/src/QuantumArithmetic/LAInc.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/// Low-ancilla incrementer circuit.


function Log2(x : Int) : Double {
return Std.Math.Log(Std.Convert.IntAsDouble(x)) / Std.Math.LogOf2();
}

/// Computes ans := CTO(x), where CTO(x) is number of trailing (least
/// significant) "1" bits in register x before first zero bit. CTO(0)=0.
/// ans must be prepared in zero state.
operation CountTrailingOnes(x : Qubit[], ans : Qubit[]) : Unit is Ctl + Adj {
body (...) {
Controlled CountTrailingOnes([], (x, ans));
}
controlled (ctrl, ...) {
let x_len = Length(x);
let ctrl_len = Length(ctrl);
if ctrl_len >= 2 {
use anc = Qubit();
within {
AND(ctrl[0], ctrl[1], anc);
} apply {
Controlled CountTrailingOnes([anc] + ctrl[2..ctrl_len-1], (x, ans));
}
} elif (x_len == 1 and ctrl_len == 0) {
CNOT(x[0], ans[0]);
} elif (x_len == 1 and ctrl_len == 1) {
CCNOT(ctrl[0], x[0], ans[0]);
} elif (x_len == 2 and ctrl_len == 0) {
X(x[1]);
CCNOT(x[0], x[1], ans[0]);
X(x[1]);
CCNOT(x[0], x[1], ans[1]);
} elif (x_len == 2 and ctrl_len == 1) {
use x0 = Qubit();
within {
AND(ctrl[0], x[0], x0);
} apply {
X(x[1]);
CCNOT(x0, x[1], ans[0]);
X(x[1]);
CCNOT(x0, x[1], ans[1]);
}
} else {
let n : Int = Std.Math.Ceiling(Log2(x_len));
let x_low = x[0..(1 <<< (n - 1))-1];
let x_high = x[(1 <<< (n - 1))..x_len-1];
if (x_len == 1 <<< n) {
Std.Diagnostics.Fact(Length(ans) >= n + 1, "ans too small");
Controlled CountTrailingOnes(ctrl, (x_low, ans[0..n-1]));
Controlled CountTrailingOnes(ctrl + [ans[n-1]], (x_high, ans[0..n-2] + [ans[n]]));
Controlled CNOT(ctrl, (ans[n], ans[n-1]));
} else {
Std.Diagnostics.Fact(Length(ans) >= n, "ans too small");
Controlled CountTrailingOnes(ctrl, (x_low, ans[0..n-1]));
Controlled CountTrailingOnes(ctrl + [ans[n-1]], (x_high, ans[0..n-2]));
}
}
}
}

/// Flips first `ctr` bits in `target`.
/// If `ctr==0`, does nothing.
/// If `ctr==Length(target)`, flips all bits.
/// If `ctr>Length(target)`, behavior is undefined.
operation FlipFirst(target : Qubit[], ctr : Qubit[]) : Unit is Ctl + Adj {
body (...) {
Controlled FlipFirst([], (target, ctr));
}
controlled (ctrl, ...) {
let target_len = Length(target);
let ctr_len = Length(ctr);
let n = Std.Math.Floor(Log2(target_len)) + 1;
let ctrl_len = Length(ctrl);
if ctrl_len >= 2 {
use anc = Qubit();
within {
AND(ctrl[0], ctrl[1], anc);
} apply {
Controlled FlipFirst([anc] + ctrl[2..ctrl_len-1], (target, ctr));
}
} elif (ctr_len > n) {
// Counter too large, ignore highest qubits.
Controlled FlipFirst(ctrl, (target, ctr[0..n-1]));
} elif (ctr_len < n) {
// Counter too small, can only affect prefix of target.
Controlled FlipFirst(ctrl, (target[0..(1 <<< ctr_len)-2], ctr));
} elif (target_len == 1 and ctrl_len == 0) {
CNOT(ctr[0], target[0]);
} elif (target_len == 1 and ctrl_len == 1) {
CCNOT(ctrl[0], ctr[0], target[0]);
} elif (target_len == 2 and ctrl_len == 0) {
CNOT(ctr[0], target[0]);
CNOT(ctr[1], target[0]);
CNOT(ctr[1], target[1]);
} elif (target_len == 2 and ctrl_len == 1) {
CCNOT(ctrl[0], ctr[0], target[0]);
CCNOT(ctrl[0], ctr[1], target[0]);
CCNOT(ctrl[0], ctr[1], target[1]);
} else {
Std.Diagnostics.Fact(ctr_len == n, "");
Std.Diagnostics.Fact(target_len >= (1 <<< (n - 1)), "");
let target_low : Qubit[] = target[0..(1 <<< (n - 1))-1];
let target_high : Qubit[] = target[(1 <<< (n - 1))..target_len-1];

Controlled ApplyToEachCA(ctrl + [ctr[n-1]], (X, target_low));
if (Length(target_high) > 0) {
Controlled FlipFirst(ctrl + [ctr[n-1]], (target_high, ctr[0..n-2]));
}
if (Length(target_low) > 1) {
Controlled X(ctrl, (ctr[n-1]));
Controlled FlipFirst(ctrl + [ctr[n-1]], (target_low[0..Length(target_low)-2], ctr[0..n-2]));
Controlled X(ctrl, (ctr[n-1]));
}
}
}
}

/// Flips target iff x==y.
operation FlipIfEqual(x : Qubit[], y : BigInt, target : Qubit) : Unit is Ctl + Adj {
let y_bits = Std.Convert.BigIntAsBoolArray(y, Length(x));
within {
ApplyPauliFromBitString(PauliX, false, y_bits, x);
} apply {
Controlled X(x, (target));
}
}

/// Computes x = (x+1)%(2^n), where n=Length(x).
operation IncrementByFlip(x : Qubit[]) : Unit is Adj {
body (...) {
Controlled IncrementByFlip([], (x));
}
controlled (ctrl, ...) {
use ctr = Qubit[Std.Math.Floor(Log2(Length(x) + 1)) + 1];
use carry = Qubit();
CountTrailingOnes(x, ctr);
QuantumArithmetic.ConstAdder.AddConstant(1L, ctr);
Controlled FlipFirst(ctrl, (x + [carry], ctr));
QuantumArithmetic.ConstAdder.AddConstant(-1L, ctr);

// Uncompute carry.
// We know that carry=1 iff ctr=Length(x).
let x_len = Std.Convert.IntAsBigInt(Length(x));
Controlled FlipIfEqual(ctrl, (ctr, x_len, carry));

// Uncompute ctr.
within {
Controlled ApplyToEachCA(ctrl, (X, x));
} apply {
Adjoint CountTrailingOnes(x, ctr);
}
}
}
33 changes: 33 additions & 0 deletions lib/src/TestUtils.qs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,39 @@ operation MeasureBigInt(reg : Qubit[]) : BigInt {
return ans;
}

/// Tests artihemtic operation that acts on array of qubit registers.
/// Numbers are unsigned little-endian integers.
operation TestArithmeticOp(
op : (Qubit[][]) => Unit,
sizes : Int[],
vals : BigInt[]
) : BigInt[] {
Fact(Length(sizes) == Length(vals), "sizes and vals must have the same length.");
let n = Length(sizes);
mutable total = 0;
for sz in sizes {
set total += sz;
}
use allQubits = Qubit[total];
mutable regs : Qubit[][] = [];
mutable offset = 0;
for sz in sizes {
set regs += [allQubits[offset..offset + sz - 1]];
set offset += sz;
}
for i in 0..n - 1 {
ApplyBigInt(vals[i], regs[i]);
}

op(regs);

mutable results : BigInt[] = [];
for i in 0..n - 1 {
set results += [MeasureBigInt(regs[i])];
}
return results;
}

// Applies binary operation on quantum integers.
// 1. Creates qubit register x of size n, populates it with integer x_val.
// 2. Creates qubit register y of size n, populates it with integer y_val.
Expand Down
Loading
Loading