From 412e5a84b939a1d9181d3c26d0c5f6eb34e5fe50 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Mon, 26 Oct 2020 15:23:16 +0100 Subject: [PATCH 1/3] Refactor. --- Standard/src/Arithmetic/Integer.qs | 68 +++++++++++------------------- 1 file changed, 24 insertions(+), 44 deletions(-) diff --git a/Standard/src/Arithmetic/Integer.qs b/Standard/src/Arithmetic/Integer.qs index ad25bd2def1..b50d0318911 100644 --- a/Standard/src/Arithmetic/Integer.qs +++ b/Standard/src/Arithmetic/Integer.qs @@ -34,6 +34,8 @@ namespace Microsoft.Quantum.Arithmetic { /// Implements a compute carry gate using a temporary logical-AND construction. /// /// # Input + /// ## controls + /// Possible control lines. /// ## carryIn /// Carry-in qubit. /// ## summand1 @@ -43,40 +45,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 ApplyRippleCarryAddeDBlock(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); } @@ -136,7 +118,7 @@ namespace Microsoft.Quantum.Arithmetic { body (...) { Controlled RippleCarryAdderD(new Qubit[0], (xs, ys, carry)); } - controlled ( controls, ... ) { + controlled (controls, ... ) { let nQubits = Length(xs!); EqualityFactI( @@ -144,24 +126,22 @@ namespace Microsoft.Quantum.Arithmetic { "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( + ApplyRippleCarryAddeDBlock(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])); - } + 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])); } // 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])); } } } From b36fe9c50a35c42a66beb131932d38bc389b441a Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Mon, 26 Oct 2020 15:48:04 +0100 Subject: [PATCH 2/3] Save some operations. --- Standard/src/Arithmetic/Integer.qs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Standard/src/Arithmetic/Integer.qs b/Standard/src/Arithmetic/Integer.qs index b50d0318911..e6773fbdd92 100644 --- a/Standard/src/Arithmetic/Integer.qs +++ b/Standard/src/Arithmetic/Integer.qs @@ -25,9 +25,9 @@ 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 @@ -135,12 +135,20 @@ namespace Microsoft.Quantum.Arithmetic { ); } apply { - // 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])); + // 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])); } } From 8e1b491f3668e2a0712b9f938689287e7dfae1ec Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Thu, 5 Nov 2020 08:49:43 +0100 Subject: [PATCH 3/3] Apply suggestions from code review Co-authored-by: Guen P --- Standard/src/Arithmetic/Integer.qs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Standard/src/Arithmetic/Integer.qs b/Standard/src/Arithmetic/Integer.qs index e6773fbdd92..46218b6f9de 100644 --- a/Standard/src/Arithmetic/Integer.qs +++ b/Standard/src/Arithmetic/Integer.qs @@ -32,6 +32,8 @@ namespace Microsoft.Quantum.Arithmetic { /// # Summary /// Implements a compute carry gate using a temporary logical-AND construction. + /// 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 @@ -45,7 +47,7 @@ namespace Microsoft.Quantum.Arithmetic { /// `summand1` and `summand2`. /// ## carryOut /// Carry-out qubit, will be xored with the higher bit of the sum. - internal operation ApplyRippleCarryAddeDBlock(controls : Qubit[], (carryIn : Qubit, summand1 : Qubit, summand2 : Qubit, carryOut : Qubit)) + internal operation ApplyRippleCarryAdderDBlock(controls : Qubit[], (carryIn : Qubit, summand1 : Qubit, summand2 : Qubit, carryOut : Qubit)) : Unit is Adj { body (...) { @@ -130,7 +132,7 @@ namespace Microsoft.Quantum.Arithmetic { within { ApplyAnd(xs![0], ys![0], auxRegister[0]); ApplyToEachA( - ApplyRippleCarryAddeDBlock(controls, _), + ApplyRippleCarryAdderDBlock(controls, _), Zipped4(Most(auxRegister), xs![1..nQubits - 2], ys![1..nQubits - 2], Rest(auxRegister)) ); }