Skip to content

Commit

Permalink
Replaced custom ApplyAndAssuming0Target with AND from std (#2123)
Browse files Browse the repository at this point in the history
We used to have custom implementation for AND before we added it to the
standard library. Now that we have it in std, this PR removes custom
ApplyAndAssuming0Target and replaces it with AND. This standard
implementation is via PhaseCCX, and has the same T-count of 4, T-depth
of 2, but uses fewer gates overall.

Previous custom implementation:
![Screenshot 2025-01-23
124923](https://github.com/user-attachments/assets/4e480670-40f2-4d50-af4e-0d6ec2fb4797)

Implementation from the standard library:
![Screenshot 2025-01-23
124952](https://github.com/user-attachments/assets/d4c6a90d-95f1-4d17-a7ea-fb08d3dbacef)

This new implementation results in different sequence of gates in Shor's
sample, which, in turn, changes its behavior on the specific test we
have for it. As randomness is removed from tests, that scenario results
in guessing factorization, which isn't great. So this PR changes the
default sample for Shor.

Co-authored-by: Dmitry Vasilevsky <[email protected]>
  • Loading branch information
DmitryVasilevsky and Dmitry Vasilevsky authored Jan 24, 2025
1 parent 6d83547 commit 3ff4980
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 107 deletions.
4 changes: 2 additions & 2 deletions library/std/src/Std/Arithmetic.qs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ operation RippleCarryCGIncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl {
} else {
use carries = Qubit[xsLen];
within {
ApplyAndAssuming0Target(xs[0], ys[0], carries[0]);
AND(xs[0], ys[0], carries[0]);
} apply {
for i in 1..xsLen - 2 {
CarryForInc(carries[i - 1], xs[i], ys[i], carries[i]);
Expand Down Expand Up @@ -307,7 +307,7 @@ operation LookAheadDKRSAddLE(xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is
// with carry-out
// compute initial generate values
for k in 0..xsLen - 1 {
ApplyAndAssuming0Target(xs[k], ys[k], zs[k + 1]);
AND(xs[k], ys[k], zs[k + 1]);
}

within {
Expand Down
100 changes: 16 additions & 84 deletions library/std/src/Std/ArithmeticUtils.qs
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,9 @@ operation HalfAdderForInc(x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj
use helper = Qubit();

within {
ApplyAndAssuming0Target(x, y, helper);
AND(x, y, helper);
} apply {
ApplyAndAssuming0Target(ctl, helper, carryOut);
AND(ctl, helper, carryOut);
}
CCNOT(ctl, x, y);
}
Expand Down Expand Up @@ -178,7 +178,7 @@ operation FullAdderForInc(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubi
operation FullAdder(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj {
CNOT(x, y);
CNOT(x, carryIn);
ApplyAndAssuming0Target(y, carryIn, carryOut);
AND(y, carryIn, carryOut);
CNOT(x, y);
CNOT(x, carryOut);
CNOT(y, carryIn);
Expand All @@ -190,7 +190,7 @@ operation CarryForInc(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) :
body (...) {
CNOT(carryIn, x);
CNOT(carryIn, y);
ApplyAndAssuming0Target(x, y, carryOut);
AND(x, y, carryOut);
CNOT(carryIn, carryOut);
}
adjoint auto;
Expand All @@ -209,7 +209,7 @@ operation CarryForInc(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) :
operation UncarryForInc(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj + Ctl {
body (...) {
CNOT(carryIn, carryOut);
Adjoint ApplyAndAssuming0Target(x, y, carryOut);
Adjoint AND(x, y, carryOut);
CNOT(carryIn, x);
CNOT(x, y);
}
Expand All @@ -220,92 +220,24 @@ operation UncarryForInc(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit)
let ctl = ctls[0];

CNOT(carryIn, carryOut);
Adjoint ApplyAndAssuming0Target(x, y, carryOut);
Adjoint AND(x, y, carryOut);
CCNOT(ctl, x, y); // Controlled X(ctls + [x], y);
CNOT(carryIn, x);
CNOT(carryIn, y);
}
controlled adjoint auto;
}

/// # Summary
/// Applies AND gate between `control1` and `control2` and stores the result
/// in `target` assuming `target` is in |0> state.
///
/// # Description
/// Inverts `target` if and only if both controls are 1, but assumes that
/// `target` is in state 0. The operation has T-count 4, T-depth 2 and
/// requires no helper qubit, and may therefore be preferable to a CCNOT
/// operation, if `target` is known to be 0.
/// The adjoint of this operation is measurement based and requires no T
/// gates (but requires target to support branching on measurements).
/// Although the Toffoli gate (CCNOT) will perform faster in simulations,
/// this version has lower T gate requirements.
/// # References
/// - Cody Jones: "Novel constructions for the fault-tolerant Toffoli gate",
/// Phys. Rev. A 87, 022328, 2013
/// [arXiv:1212.5069](https://arxiv.org/abs/1212.5069)
/// doi:10.1103/PhysRevA.87.022328
@Config(Adaptive)
operation ApplyAndAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj {
// NOTE: Eventually this operation will be public and intrinsic.
body (...) {
CCNOT(control1, control2, target);
}
adjoint (...) {
H(target);
if M(target) == One {
Reset(target);
CZ(control1, control2);
}
}
}

operation ApplyOrAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj {
within {
X(control1);
X(control2);
} apply {
ApplyAndAssuming0Target(control1, control2, target);
AND(control1, control2, target);
X(target);
}
}

/// # Summary
/// Applies AND gate between `control1` and `control2` and stores the result
/// in `target` assuming `target` is in |0> state.
///
/// # Description
/// Inverts `target` if and only if both controls are 1, but assumes that
/// `target` is in state 0. The operation has T-count 4, T-depth 2 and
/// requires no helper qubit, and may therefore be preferable to a CCNOT
/// operation, if `target` is known to be 0.
/// This version is suitable for Base profile.
/// Although the Toffoli gate (CCNOT) will perform faster in simulations,
/// this version has lower T gate requirements.
/// # References
/// - Cody Jones: "Novel constructions for the fault-tolerant Toffoli gate",
/// Phys. Rev. A 87, 022328, 2013
/// [arXiv:1212.5069](https://arxiv.org/abs/1212.5069)
/// doi:10.1103/PhysRevA.87.022328
@Config(not Adaptive)
operation ApplyAndAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj {
H(target);
T(target);
CNOT(control1, target);
CNOT(control2, target);
within {
CNOT(target, control1);
CNOT(target, control2);
} apply {
Adjoint T(control1);
Adjoint T(control2);
T(target);
}
H(target);
S(target);
}

/// # Summary
/// Computes carries for the look-ahead adder
operation ComputeCarries(ps : Qubit[], gs : Qubit[]) : Unit is Adj {
Expand All @@ -318,8 +250,8 @@ operation ComputeCarries(ps : Qubit[], gs : Qubit[]) : Unit is Adj {
let registerPartition = MappedOverRange(t -> Floor(IntAsDouble(n) / IntAsDouble(2^t)) - 1, 1..T - 1);
let pWorkspace = [ps] + Partitioned(registerPartition, qs);

// Note that we cannot use ApplyAndAssuming0Target targeting gs[0]
// as it may not be in the 0 state. We use regular CCNOT in GRounds and CRounds.
// Note that we cannot use AND gate targeting gs[0] as it may not be in the 0 state.
// We use regular CCNOT in GRounds and CRounds.
within {
PRounds(pWorkspace);
} apply {
Expand Down Expand Up @@ -354,7 +286,7 @@ operation PRounds(pWorkspace : Qubit[][]) : Unit is Adj {
let (current, next) = (Rest(ws[0]), ws[1]);

for m in IndexRange(next) {
ApplyAndAssuming0Target(current[2 * m], current[2 * m + 1], next[m]);
AND(current[2 * m], current[2 * m + 1], next[m]);
}
}
}
Expand Down Expand Up @@ -447,7 +379,7 @@ operation ApplyActionIfGreaterThanOrEqualConstant<'T>(

within {
for i in 0..Length(cs1) - 1 {
let op = cNormalized &&& (1L <<< (i + 1)) != 0L ? ApplyAndAssuming0Target | ApplyOrAssuming0Target;
let op = cNormalized &&& (1L <<< (i + 1)) != 0L ? AND | ApplyOrAssuming0Target;
op(cs1[i], xNormalized[i + 1], qs[i]);
}
} apply {
Expand Down Expand Up @@ -510,7 +442,7 @@ operation CarryWith1CarryIn(
body (...) {
X(x);
X(y);
ApplyAndAssuming0Target(x, y, carryOut);
AND(x, y, carryOut);
X(carryOut);
}

Expand Down Expand Up @@ -568,10 +500,10 @@ operation LogDepthAndChain(ctls : Qubit[], tgts : Qubit[]) : Unit is Adj {
Fact(lc == lt + 1, $"There must be exactly one more control qubit than target qubits (got {lc}, {lt})");

if lt == 1 {
ApplyAndAssuming0Target(ctls[0], ctls[1], tgts[0]);
AND(ctls[0], ctls[1], tgts[0]);
} elif lt == 2 {
ApplyAndAssuming0Target(ctls[0], ctls[1], tgts[0]);
ApplyAndAssuming0Target(ctls[2], tgts[0], tgts[1]);
AND(ctls[0], ctls[1], tgts[0]);
AND(ctls[2], tgts[0], tgts[1]);
} else {
let left = lc / 2;
let right = lc - left;
Expand All @@ -584,6 +516,6 @@ operation LogDepthAndChain(ctls : Qubit[], tgts : Qubit[]) : Unit is Adj {

LogDepthAndChain(ctlsLeft, tgtsLeft);
LogDepthAndChain(ctlsRight, tgtsRight);
ApplyAndAssuming0Target(Tail(tgtsLeft), Tail(tgtsRight), Tail(tgts));
AND(Tail(tgtsLeft), Tail(tgtsRight), Tail(tgts));
}
}
11 changes: 5 additions & 6 deletions library/std/src/Std/TableLookup.qs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ import
Std.Convert.IntAsDouble,
Std.Arrays.*,
Std.ResourceEstimation.BeginEstimateCaching,
Std.ResourceEstimation.EndEstimateCaching,
Std.ArithmeticUtils.ApplyAndAssuming0Target;
Std.ResourceEstimation.EndEstimateCaching;

/// # Summary
/// Performs table lookup using a SELECT network
Expand Down Expand Up @@ -123,7 +122,7 @@ operation SinglyControlledSelect(
within {
X(tail);
} apply {
ApplyAndAssuming0Target(ctl, tail, helper);
AND(ctl, tail, helper);
}

SinglyControlledSelect(helper, parts[0], most, target);
Expand All @@ -132,7 +131,7 @@ operation SinglyControlledSelect(

SinglyControlledSelect(helper, parts[1], most, target);

Adjoint ApplyAndAssuming0Target(ctl, tail, helper);
Adjoint AND(ctl, tail, helper);
}

EndEstimateCaching();
Expand Down Expand Up @@ -240,7 +239,7 @@ operation EncodeUnary(
// targets are the first and second 2^i qubits of the target register
let split = Partitioned([2^i, 2^i], target);
for j in IndexRange(split[0]) {
ApplyAndAssuming0Target(input[i], split[0][j], split[1][j]);
AND(input[i], split[0][j], split[1][j]);
CNOT(split[1][j], split[0][j]);
}
}
Expand Down Expand Up @@ -275,7 +274,7 @@ operation AndChainOperation(ctls : Qubit[], helper : Qubit[], target : Qubit) :
let tgts = helper + [target];

for idx in IndexRange(tgts) {
ApplyAndAssuming0Target(ctls1[idx], ctls2[idx], tgts[idx]);
AND(ctls1[idx], ctls2[idx], tgts[idx]);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion samples/algorithms/Shor.qs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Std.Arithmetic.*;
import Std.Arrays.*;

operation Main() : (Int, Int) {
let n = 143; // 11*13;
let n = 187; // 11*17;
// You can try these other examples for a lengthier computation.
// let n = 16837; // = 113*149
// let n = 22499; // = 149*151
Expand Down
28 changes: 14 additions & 14 deletions samples_test/src/tests/algorithms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,23 +237,23 @@ pub const QUANTUMHELLOWORLD_EXPECT_DEBUG: Expect = expect![[r#"
pub const RANDOMBIT_EXPECT: Expect = expect!["Zero"];
pub const RANDOMBIT_EXPECT_DEBUG: Expect = expect!["Zero"];
pub const SHOR_EXPECT: Expect = expect![[r#"
*** Factorizing 143, attempt 1.
Estimating period of 139.
*** Factorizing 187, attempt 1.
Estimating period of 182.
Estimating frequency with bitsPrecision=17.
Estimated frequency=30583
Found period=30
Found factor=13
Found factorization 143 = 13 * 11
(13, 11)"#]];
Estimated frequency=126158
Found period=80
Found factor=17
Found factorization 187 = 17 * 11
(17, 11)"#]];
pub const SHOR_EXPECT_DEBUG: Expect = expect![[r#"
*** Factorizing 143, attempt 1.
Estimating period of 139.
*** Factorizing 187, attempt 1.
Estimating period of 182.
Estimating frequency with bitsPrecision=17.
Estimated frequency=30583
Found period=30
Found factor=13
Found factorization 143 = 13 * 11
(13, 11)"#]];
Estimated frequency=126158
Found period=80
Found factor=17
Found factorization 187 = 17 * 11
(17, 11)"#]];
pub const SIMPLEISING_EXPECT: Expect =
expect!["[Zero, Zero, Zero, One, One, Zero, One, One, Zero]"];
pub const SIMPLEISING_EXPECT_DEBUG: Expect =
Expand Down

0 comments on commit 3ff4980

Please sign in to comment.