Skip to content
This repository has been archived by the owner on Jan 12, 2024. It is now read-only.

Refactoring improved adder implementation #359

Open
wants to merge 3 commits into
base: feature/adder
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
86 changes: 38 additions & 48 deletions Standard/src/Arithmetic/Integer.qs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,19 @@ namespace Microsoft.Quantum.Arithmetic {
/// Carry-out qubit, will be xored with the higher bit of the sum.
operation Carry(carryIn: Qubit, summand1: Qubit, summand2: Qubit, carryOut: Qubit)
: Unit is Adj + Ctl {
CCNOT (summand1, summand2, carryOut);
CNOT (summand1, summand2);
CCNOT (carryIn, summand2, carryOut);
CCNOT(summand1, summand2, carryOut);
CNOT(summand1, summand2);
CCNOT(carryIn, summand2, carryOut);
}

/// # Summary
/// Implements a compute carry gate using a temporary logical-AND construction.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this related to figure 1 in this paper (https://arxiv.org/pdf/1709.06648.pdf)? If yes could we link it here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This operation is not related to that paper. It has been used in the previous implementation, and only remains in the code, because it has been exposed as public API. It basically computes the majority-of-three function out-of-place into carryOut, but also changes the state of summand2.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok thanks! Is there another reference we can link here?

msoeken marked this conversation as resolved.
Show resolved Hide resolved
/// The input parameters `(carryIn, summand1, summand2, carryOut)` are passed together as a tuple
/// to have a more natural call to `ApplyToEachA` in the calling function.
///
/// # Input
/// ## controls
/// Possible control lines.
/// ## carryIn
msoeken marked this conversation as resolved.
Show resolved Hide resolved
/// Carry-in qubit.
/// ## summand1
Expand All @@ -43,40 +47,20 @@ namespace Microsoft.Quantum.Arithmetic {
/// `summand1` and `summand2`.
/// ## carryOut
/// Carry-out qubit, will be xored with the higher bit of the sum.
internal operation ComputeTemporaryCarry(carryIn: Qubit, summand1: Qubit, summand2: Qubit, carryOut: Qubit)
: Unit is Adj{
CNOT(carryIn, summand2);
CNOT(carryIn, summand1);
ApplyAnd(summand1, summand2, carryOut);
CNOT(carryIn, carryOut);
}

/// # Summary
/// Implements a erase carry gate by uncomputing the logical-AND.
///
/// # Input
/// ## carryIn
/// Carry-in qubit.
/// ## summand1
/// First summand qubit.
/// ## summand2
/// Second summand qubit, is replaced with the lower bit of the sum of
/// `summand1` and `summand2`.
/// ## carryOut
/// Carry-out qubit, will be erased
internal operation EraseTemporaryCarry(carryIn: Qubit, summand1: Qubit, summand2: Qubit, carryOut: Qubit)
: Unit is Adj + Ctl{
body (...){
CNOT (carryIn, carryOut);
(Adjoint ApplyAnd) (summand1, summand2, carryOut);
CNOT (summand1, summand2);
CNOT(carryIn, summand1);
internal operation ApplyRippleCarryAdderDBlock(controls : Qubit[], (carryIn : Qubit, summand1 : Qubit, summand2 : Qubit, carryOut : Qubit))
: Unit is Adj
{
body (...) {
CNOT(carryIn, summand2);
CNOT(carryIn, summand1);
ApplyAnd(summand1, summand2, carryOut);
CNOT(carryIn, carryOut);
}
controlled (controls, ...) {

adjoint (...) {
CNOT (carryIn, carryOut);
(Adjoint ApplyAnd) (summand1, summand2, carryOut);
(Controlled CNOT) (controls, (summand1, summand2));
Adjoint ApplyAnd(summand1, summand2, carryOut);
Controlled CNOT(controls, (summand1, summand2));
CNOT(carryIn, summand1);
CNOT(carryIn, summand2);
}
Expand Down Expand Up @@ -136,32 +120,38 @@ namespace Microsoft.Quantum.Arithmetic {
body (...) {
Controlled RippleCarryAdderD(new Qubit[0], (xs, ys, carry));
}
controlled ( controls, ... ) {
controlled (controls, ... ) {
let nQubits = Length(xs!);

EqualityFactI(
nQubits, Length(ys!),
"Input registers must have the same number of qubits."
);

using (auxRegister = Qubit[nQubits-1]) {
using (auxRegister = Qubit[nQubits - 1]) {
within {
ApplyAnd (xs![0], ys![0], auxRegister[0]);
ApplyAnd(xs![0], ys![0], auxRegister[0]);
ApplyToEachA(
ApplyRippleCarryAdderDBlock(controls, _),
Zipped4(Most(auxRegister), xs![1..nQubits - 2], ys![1..nQubits - 2], Rest(auxRegister))
);
}
apply {
for (idx in 1..(nQubits-2)) {
ComputeTemporaryCarry(auxRegister[idx-1], xs![idx], ys![idx], auxRegister[idx]);
}
// carry out is computed using Carry and Sum since using temporary Logical-AND construction erases the carry bit
(Controlled Carry) (controls, (auxRegister[nQubits-2], xs![nQubits-1], ys![nQubits-1], carry));
(Controlled CNOT) (controls, (xs![nQubits-1], ys![nQubits-1]));
(Controlled Sum) (controls, (auxRegister[nQubits-2], xs![nQubits-1], ys![nQubits-1]));
for (idx in (nQubits-2)..-1..1) {
(Controlled EraseTemporaryCarry) (controls, (auxRegister[idx-1], xs![idx], ys![idx], auxRegister[idx]));
// carry out is computed using a majority-of-three operation
within {
CNOT(Tail(auxRegister), Tail(xs!));
CNOT(Tail(auxRegister), Tail(ys!));
} apply {
Controlled ApplyAnd(controls, (Tail(xs!), Tail(ys!), carry));
Controlled CNOT(controls, (Tail(auxRegister), carry));
}

// final sum
Controlled CNOT(controls, (Tail(auxRegister), Tail(ys!)));
Controlled CNOT(controls, (Tail(xs!), Tail(ys!)));
}
// low bit output computation is simplified since CarryIn is always |0>
(Controlled CNOT) (controls, (xs![0], ys![0]));

Controlled CNOT(controls, (xs![0], ys![0]));
}
}
}
Expand Down