From f15a2df49c9e2cec68830bece354d3e89d943050 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Tue, 10 Dec 2019 08:21:26 +0100 Subject: [PATCH 01/23] Two AND gate implementations. --- Standard/src/Canon/And.qs | 96 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 Standard/src/Canon/And.qs diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs new file mode 100644 index 00000000000..b2e3ca380c8 --- /dev/null +++ b/Standard/src/Canon/And.qs @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Canon { + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Measurement; + + /// # Summary + /// 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. + /// + /// # Inputs + /// ## control1 + /// First control qubit + /// ## control2 + /// Second control qubit + /// ## target + /// Target ancilla qubit; must be in state 0 + /// + /// # References + /// - Craig Gidney: "Halving the cost of quantum addition", Quantum 2, page + /// 74, 2018 + /// https://arxiv.org/abs/1709.06648 + operation AND(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { + body (...) { + 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); + } + HY(target); + } + adjoint (...) { + H(target); + AssertProb([PauliZ], [target], One, 0.5, "Probability of the measurement must be 0.5", 1e-10); + if (IsResultOne(MResetZ(target))) { + CZ(control1, control2); + } + } + } + + /// # Summary + /// 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 1 and + /// requires one 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, and no helper qubit. + /// + /// # Inputs + /// ## control1 + /// First control qubit + /// ## control2 + /// Second control qubit + /// ## target + /// Target ancilla qubit; must be in state 0 + /// + /// # References + /// - Craig Gidney: "Halving the cost of quantum addition", Quantum 2, page + /// 74, 2018 + /// https://arxiv.org/abs/1709.06648 + /// - Cody Jones: "Novel constructions for the fault-tolerant Toffoli gate", + /// Phys. Rev. A 87, 022328, 2013 + /// https://arxiv.org/abs/1212.5069 + operation ANDLowDepth(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { + body (...) { + using (helper = Qubit()) { + H(target); + within { + CNOT(control1, helper); + CNOT(control2, helper); + CNOT(target, control1); + CNOT(target, control2); + } apply { + Adjoint T(control1); + Adjoint T(control2); + T(target); + T(helper); + } + HY(target); + } + } + adjoint (...) { + Adjoint AND(control1, control2, target); + } + } +} From 5778c1daeacd6e93bb323c81474aaf41a7b3b90f Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Tue, 10 Dec 2019 14:43:04 +0100 Subject: [PATCH 02/23] Added test case. --- Standard/tests/ANDTests.qs | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 Standard/tests/ANDTests.qs diff --git a/Standard/tests/ANDTests.qs b/Standard/tests/ANDTests.qs new file mode 100644 index 00000000000..618bdb6d51a --- /dev/null +++ b/Standard/tests/ANDTests.qs @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +namespace Microsoft.Quantum.Tests { + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Convert; + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Measurement; + + operation ANDTestHelper(polarity1 : Bool, polarity2 : Bool, gate : CCNOTop) : Unit { + using ((control1, control2, target, output) = (Qubit(), Qubit(), Qubit(), Qubit())) { + within { + ApplyPauliFromBitString(PauliX, true, [polarity1, polarity2], [control1, control2]); + gate!(control1, control2, target); + } + apply { + CNOT(target, output); + } + let expected = BoolAsResult(polarity1 and polarity2); + if (MResetZ(output) != expected) { + fail $"Expected output register to be {expected}"; + } + if (IsResultOne(M(control1))) { + fail "Expected first control register to be 0"; + } + if (IsResultOne(M(control2))) { + fail "Expected second control register to be 0"; + } + if (IsResultOne(M(target))) { + fail "Expected target register to be 0"; + } + } + } + + operation ANDTest() : Unit + { + for (p1 in [false, true]) { + for (p2 in [false, true]) { + for (op in [AND, ANDLowDepth]) { + ANDTestHelper(p1, p2, CCNOTop(op)); + } + } + } + } +} + + From a59a3dab261592de7fbc0922deac5e93ea78a8e3 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Tue, 10 Dec 2019 14:46:13 +0100 Subject: [PATCH 03/23] Formatting. --- Standard/src/Canon/And.qs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs index b2e3ca380c8..0602b9e01c9 100644 --- a/Standard/src/Canon/And.qs +++ b/Standard/src/Canon/And.qs @@ -33,7 +33,8 @@ namespace Microsoft.Quantum.Canon { within { CNOT(target, control1); CNOT(target, control2); - } apply { + } + apply { Adjoint T(control1); Adjoint T(control2); T(target); @@ -80,7 +81,8 @@ namespace Microsoft.Quantum.Canon { CNOT(control2, helper); CNOT(target, control1); CNOT(target, control2); - } apply { + } + apply { Adjoint T(control1); Adjoint T(control2); T(target); From 27c9adb68eb5f8b81fc2c1f61751ae52eb577733 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Wed, 11 Dec 2019 15:51:01 +0100 Subject: [PATCH 04/23] Code formatting. --- Standard/tests/ANDTests.qs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Standard/tests/ANDTests.qs b/Standard/tests/ANDTests.qs index 618bdb6d51a..195d0331c07 100644 --- a/Standard/tests/ANDTests.qs +++ b/Standard/tests/ANDTests.qs @@ -31,8 +31,7 @@ namespace Microsoft.Quantum.Tests { } } - operation ANDTest() : Unit - { + operation ANDTest() : Unit { for (p1 in [false, true]) { for (p2 in [false, true]) { for (op in [AND, ANDLowDepth]) { From 697bda486a12ef40c3e1d38f33346aec998adc66 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Fri, 13 Dec 2019 16:11:35 +0100 Subject: [PATCH 05/23] Update Standard/src/Canon/And.qs Co-Authored-By: Chris Granade --- Standard/src/Canon/And.qs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs index 0602b9e01c9..39c0302da57 100644 --- a/Standard/src/Canon/And.qs +++ b/Standard/src/Canon/And.qs @@ -6,6 +6,10 @@ namespace Microsoft.Quantum.Canon { open Microsoft.Quantum.Measurement; /// # Summary + /// Inverts a given target qubit if and only if both control qubits are in the 1 state, + /// using measurement to perform the adjoint operation. + /// + /// # 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 From e7f05cdccb04af5ebe2703671414b98e15cd1231 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Fri, 13 Dec 2019 16:13:00 +0100 Subject: [PATCH 06/23] Assertion for 0-target. --- Standard/src/Canon/And.qs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs index 0602b9e01c9..f30a39e4f23 100644 --- a/Standard/src/Canon/And.qs +++ b/Standard/src/Canon/And.qs @@ -26,6 +26,7 @@ namespace Microsoft.Quantum.Canon { /// https://arxiv.org/abs/1709.06648 operation AND(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { body (...) { + AssertProb([PauliZ], [target], Zero, 1.0, "Target qubit must be in 0 state", 0.0); H(target); T(target); CNOT(control1, target); @@ -75,6 +76,7 @@ namespace Microsoft.Quantum.Canon { operation ANDLowDepth(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { body (...) { using (helper = Qubit()) { + AssertProb([PauliZ], [target], Zero, 1.0, "Target qubit must be in 0 state", 0.0); H(target); within { CNOT(control1, helper); From cfb5a856ebd943f239b7099afcf49f7c23b4fa17 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Fri, 13 Dec 2019 16:15:33 +0100 Subject: [PATCH 07/23] Added DOI to references. --- Standard/src/Canon/And.qs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs index 0db84f4ed1f..d2da51616a0 100644 --- a/Standard/src/Canon/And.qs +++ b/Standard/src/Canon/And.qs @@ -28,6 +28,7 @@ namespace Microsoft.Quantum.Canon { /// - Craig Gidney: "Halving the cost of quantum addition", Quantum 2, page /// 74, 2018 /// https://arxiv.org/abs/1709.06648 + /// doi:10.1103/PhysRevA.85.044302 operation AND(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { body (...) { AssertProb([PauliZ], [target], Zero, 1.0, "Target qubit must be in 0 state", 0.0); @@ -74,9 +75,11 @@ namespace Microsoft.Quantum.Canon { /// - Craig Gidney: "Halving the cost of quantum addition", Quantum 2, page /// 74, 2018 /// https://arxiv.org/abs/1709.06648 + /// doi:10.1103/PhysRevA.85.044302 /// - Cody Jones: "Novel constructions for the fault-tolerant Toffoli gate", /// Phys. Rev. A 87, 022328, 2013 /// https://arxiv.org/abs/1212.5069 + /// doi:10.1103/PhysRevA.87.022328 operation ANDLowDepth(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { body (...) { using (helper = Qubit()) { From 5380e88872e1c30cb93d605c9a05c6995133a45a Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Mon, 16 Dec 2019 11:38:04 +0100 Subject: [PATCH 08/23] Named application for CCNOTop. --- Standard/src/Canon/Combinators/ApplyMultiControlled.qs | 6 +++--- Standard/tests/ANDTests.qs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Standard/src/Canon/Combinators/ApplyMultiControlled.qs b/Standard/src/Canon/Combinators/ApplyMultiControlled.qs index 89bddccafab..ab207594dff 100644 --- a/Standard/src/Canon/Combinators/ApplyMultiControlled.qs +++ b/Standard/src/Canon/Combinators/ApplyMultiControlled.qs @@ -11,7 +11,7 @@ namespace Microsoft.Quantum.Canon { /// # Summary /// The signature type of CCNOT gate. - newtype CCNOTop = ((Qubit, Qubit, Qubit) => Unit is Adj); + newtype CCNOTop = (Apply : ((Qubit, Qubit, Qubit) => Unit is Adj)); /// # Summary @@ -170,10 +170,10 @@ namespace Microsoft.Quantum.Canon { operation AndLadder (ccnot : CCNOTop, controls : Qubit[], targets : Qubit[]) : Unit is Adj { EqualityFactI(Length(controls), Length(targets) + 1, $"Length(controls) must be equal to Length(target) + 1"); Fact(Length(controls) >= 2, $"The operation is not defined for less than 2 controls"); - ccnot!(controls[0], controls[1], targets[0]); + ccnot::Apply(controls[0], controls[1], targets[0]); for (k in 1 .. Length(targets) - 1) { - ccnot!(controls[k + 1], targets[k - 1], targets[k]); + ccnot::Apply(controls[k + 1], targets[k - 1], targets[k]); } } diff --git a/Standard/tests/ANDTests.qs b/Standard/tests/ANDTests.qs index 195d0331c07..d55e291d445 100644 --- a/Standard/tests/ANDTests.qs +++ b/Standard/tests/ANDTests.qs @@ -10,7 +10,7 @@ namespace Microsoft.Quantum.Tests { using ((control1, control2, target, output) = (Qubit(), Qubit(), Qubit(), Qubit())) { within { ApplyPauliFromBitString(PauliX, true, [polarity1, polarity2], [control1, control2]); - gate!(control1, control2, target); + gate::Apply(control1, control2, target); } apply { CNOT(target, output); From b9d3388f8ecacfe1c51b31f183716fd5e8e4472c Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Mon, 16 Dec 2019 11:44:36 +0100 Subject: [PATCH 09/23] Rename operations. --- Standard/src/Canon/And.qs | 6 +++--- Standard/tests/ANDTests.qs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs index d2da51616a0..9eee82d8bd5 100644 --- a/Standard/src/Canon/And.qs +++ b/Standard/src/Canon/And.qs @@ -29,7 +29,7 @@ namespace Microsoft.Quantum.Canon { /// 74, 2018 /// https://arxiv.org/abs/1709.06648 /// doi:10.1103/PhysRevA.85.044302 - operation AND(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { + operation ApplyAND(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { body (...) { AssertProb([PauliZ], [target], Zero, 1.0, "Target qubit must be in 0 state", 0.0); H(target); @@ -80,7 +80,7 @@ namespace Microsoft.Quantum.Canon { /// Phys. Rev. A 87, 022328, 2013 /// https://arxiv.org/abs/1212.5069 /// doi:10.1103/PhysRevA.87.022328 - operation ANDLowDepth(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { + operation ApplyANDLowDepth(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { body (...) { using (helper = Qubit()) { AssertProb([PauliZ], [target], Zero, 1.0, "Target qubit must be in 0 state", 0.0); @@ -101,7 +101,7 @@ namespace Microsoft.Quantum.Canon { } } adjoint (...) { - Adjoint AND(control1, control2, target); + Adjoint ApplyAND(control1, control2, target); } } } diff --git a/Standard/tests/ANDTests.qs b/Standard/tests/ANDTests.qs index d55e291d445..79fb150c65f 100644 --- a/Standard/tests/ANDTests.qs +++ b/Standard/tests/ANDTests.qs @@ -31,10 +31,10 @@ namespace Microsoft.Quantum.Tests { } } - operation ANDTest() : Unit { + operation ApplyANDTest() : Unit { for (p1 in [false, true]) { for (p2 in [false, true]) { - for (op in [AND, ANDLowDepth]) { + for (op in [ApplyAND, ApplyANDLowDepth]) { ANDTestHelper(p1, p2, CCNOTop(op)); } } From fc85ea22fe3b0526bfa4f0167b40c71726c1a446 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Tue, 17 Dec 2019 11:09:45 +0100 Subject: [PATCH 10/23] Add Test attribute. --- Standard/tests/ANDTests.qs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Standard/tests/ANDTests.qs b/Standard/tests/ANDTests.qs index 79fb150c65f..95c489210ae 100644 --- a/Standard/tests/ANDTests.qs +++ b/Standard/tests/ANDTests.qs @@ -3,6 +3,7 @@ namespace Microsoft.Quantum.Tests { open Microsoft.Quantum.Canon; open Microsoft.Quantum.Convert; + open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Measurement; @@ -31,6 +32,7 @@ namespace Microsoft.Quantum.Tests { } } + @Test("QuantumSimulator") operation ApplyANDTest() : Unit { for (p1 in [false, true]) { for (p2 in [false, true]) { From 78b19006323b0b27bab8142a74850a4888eaa16c Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Tue, 17 Dec 2019 11:11:50 +0100 Subject: [PATCH 11/23] Add links to arXiv. --- Standard/src/Canon/And.qs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs index 9eee82d8bd5..03b5d766787 100644 --- a/Standard/src/Canon/And.qs +++ b/Standard/src/Canon/And.qs @@ -27,7 +27,7 @@ namespace Microsoft.Quantum.Canon { /// # References /// - Craig Gidney: "Halving the cost of quantum addition", Quantum 2, page /// 74, 2018 - /// https://arxiv.org/abs/1709.06648 + /// [arXiv:1709.06648](https://arxiv.org/abs/1709.06648) /// doi:10.1103/PhysRevA.85.044302 operation ApplyAND(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { body (...) { @@ -74,11 +74,11 @@ namespace Microsoft.Quantum.Canon { /// # References /// - Craig Gidney: "Halving the cost of quantum addition", Quantum 2, page /// 74, 2018 - /// https://arxiv.org/abs/1709.06648 + /// [arXiv:1709.06648](https://arxiv.org/abs/1709.06648) /// doi:10.1103/PhysRevA.85.044302 /// - Cody Jones: "Novel constructions for the fault-tolerant Toffoli gate", /// Phys. Rev. A 87, 022328, 2013 - /// https://arxiv.org/abs/1212.5069 + /// [arXiv:1212.5069](https://arxiv.org/abs/1212.5069) /// doi:10.1103/PhysRevA.87.022328 operation ApplyANDLowDepth(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { body (...) { From b06ddf4753bea12c8cf6a0c1abe8d36d354cdf91 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Tue, 17 Dec 2019 11:18:07 +0100 Subject: [PATCH 12/23] Rename operations. --- Standard/src/Canon/And.qs | 6 +++--- Standard/tests/ANDTests.qs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs index 03b5d766787..a066be862b1 100644 --- a/Standard/src/Canon/And.qs +++ b/Standard/src/Canon/And.qs @@ -29,7 +29,7 @@ namespace Microsoft.Quantum.Canon { /// 74, 2018 /// [arXiv:1709.06648](https://arxiv.org/abs/1709.06648) /// doi:10.1103/PhysRevA.85.044302 - operation ApplyAND(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { + operation ApplyAnd(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { body (...) { AssertProb([PauliZ], [target], Zero, 1.0, "Target qubit must be in 0 state", 0.0); H(target); @@ -80,7 +80,7 @@ namespace Microsoft.Quantum.Canon { /// Phys. Rev. A 87, 022328, 2013 /// [arXiv:1212.5069](https://arxiv.org/abs/1212.5069) /// doi:10.1103/PhysRevA.87.022328 - operation ApplyANDLowDepth(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { + operation ApplyLowDepthAnd(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { body (...) { using (helper = Qubit()) { AssertProb([PauliZ], [target], Zero, 1.0, "Target qubit must be in 0 state", 0.0); @@ -101,7 +101,7 @@ namespace Microsoft.Quantum.Canon { } } adjoint (...) { - Adjoint ApplyAND(control1, control2, target); + Adjoint ApplyAnd(control1, control2, target); } } } diff --git a/Standard/tests/ANDTests.qs b/Standard/tests/ANDTests.qs index 95c489210ae..27cd9726476 100644 --- a/Standard/tests/ANDTests.qs +++ b/Standard/tests/ANDTests.qs @@ -33,10 +33,10 @@ namespace Microsoft.Quantum.Tests { } @Test("QuantumSimulator") - operation ApplyANDTest() : Unit { + operation ApplyAndTest() : Unit { for (p1 in [false, true]) { for (p2 in [false, true]) { - for (op in [ApplyAND, ApplyANDLowDepth]) { + for (op in [ApplyAnd, ApplyLowDepthAnd]) { ANDTestHelper(p1, p2, CCNOTop(op)); } } From 5639cf60e6d9336b8f90bca17355013c6537e1e4 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Tue, 17 Dec 2019 11:52:33 +0100 Subject: [PATCH 13/23] Better assertion for 0-target. --- Standard/src/Canon/And.qs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs index a066be862b1..876aad47c9c 100644 --- a/Standard/src/Canon/And.qs +++ b/Standard/src/Canon/And.qs @@ -2,6 +2,7 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Canon { + open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Measurement; @@ -31,7 +32,7 @@ namespace Microsoft.Quantum.Canon { /// doi:10.1103/PhysRevA.85.044302 operation ApplyAnd(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { body (...) { - AssertProb([PauliZ], [target], Zero, 1.0, "Target qubit must be in 0 state", 0.0); + AssertAllZero([target]); H(target); T(target); CNOT(control1, target); @@ -83,7 +84,7 @@ namespace Microsoft.Quantum.Canon { operation ApplyLowDepthAnd(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { body (...) { using (helper = Qubit()) { - AssertProb([PauliZ], [target], Zero, 1.0, "Target qubit must be in 0 state", 0.0); + AssertAllZero([target]); H(target); within { CNOT(control1, helper); From 4af583bd2abf31e6e1c62f8998756ae891571077 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Tue, 17 Dec 2019 14:48:19 +0100 Subject: [PATCH 14/23] Fix bug in LowDepthAnd. --- Standard/src/Canon/And.qs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs index 876aad47c9c..4f967cbe44b 100644 --- a/Standard/src/Canon/And.qs +++ b/Standard/src/Canon/And.qs @@ -87,9 +87,9 @@ namespace Microsoft.Quantum.Canon { AssertAllZero([target]); H(target); within { + CNOT(target, control1); CNOT(control1, helper); CNOT(control2, helper); - CNOT(target, control1); CNOT(target, control2); } apply { From fb3d6a600115841571260693dc6ca74c66b70b41 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Tue, 17 Dec 2019 14:50:23 +0100 Subject: [PATCH 15/23] Docs. --- Standard/src/Canon/And.qs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs index 4f967cbe44b..8c12047321d 100644 --- a/Standard/src/Canon/And.qs +++ b/Standard/src/Canon/And.qs @@ -58,6 +58,11 @@ namespace Microsoft.Quantum.Canon { } /// # Summary + /// Inverts a given target qubit if and only if both control qubits are in + /// the 1 state, with T-depth 1, using measurement to perform the adjoint + /// operation. + /// + /// # 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 1 and /// requires one helper qubit, and may therefore be preferable to a CCNOT From 678421cc6b1c8a9be2c0bce4a8234e3c02e28d43 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Tue, 17 Dec 2019 15:07:15 +0100 Subject: [PATCH 16/23] Doc string convention. --- Standard/src/Canon/And.qs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs index 8c12047321d..6425d363e98 100644 --- a/Standard/src/Canon/And.qs +++ b/Standard/src/Canon/And.qs @@ -17,7 +17,7 @@ namespace Microsoft.Quantum.Canon { /// operation, if `target` is known to be 0. The adjoint of this operation /// is measurement based and requires no T gates. /// - /// # Inputs + /// # Input /// ## control1 /// First control qubit /// ## control2 @@ -69,7 +69,7 @@ namespace Microsoft.Quantum.Canon { /// operation, if `target` is known to be 0. The adjoint of this operation /// is measurement based and requires no T gates, and no helper qubit. /// - /// # Inputs + /// # Input /// ## control1 /// First control qubit /// ## control2 From 0f7f9ee8d8f245c61eaff16be40cb78c1024db6c Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Tue, 17 Dec 2019 15:20:11 +0100 Subject: [PATCH 17/23] Controlled variant for `ApplyAnd`. --- Standard/src/Canon/And.qs | 146 +++++++++++++++++++++++++++++++++++++ Standard/tests/ANDTests.qs | 37 ++++++++-- 2 files changed, 175 insertions(+), 8 deletions(-) diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs index 6425d363e98..4acd1d23ab8 100644 --- a/Standard/src/Canon/And.qs +++ b/Standard/src/Canon/And.qs @@ -2,8 +2,11 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Canon { + open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Convert; open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Math; open Microsoft.Quantum.Measurement; /// # Summary @@ -17,6 +20,13 @@ namespace Microsoft.Quantum.Canon { /// operation, if `target` is known to be 0. The adjoint of this operation /// is measurement based and requires no T gates. /// + /// The controlled application of this operation requires no helper qubit, + /// `2^c` `Rz` gates and is not optimized for depth, where `c` is the number + /// of overall control qubits including the two controls from the `ApplyAnd` + /// operation. The adjoint controlled application requires `2^c - 1` `Rz` + /// gates (with an angle twice the size of the non-adjoint operation), no + /// helper qubit and is not optimized for depth. + /// /// # Input /// ## control1 /// First control qubit @@ -55,6 +65,12 @@ namespace Microsoft.Quantum.Canon { CZ(control1, control2); } } + controlled (controls, ...) { + _ApplyMultipleControlledAnd(controls + [control1, control2], target); + } + adjoint controlled (controls, ...) { + Adjoint _ApplyMultipleControlledAnd(controls + [control1, control2], target); + } } /// # Summary @@ -110,4 +126,134 @@ namespace Microsoft.Quantum.Canon { Adjoint ApplyAnd(control1, control2, target); } } + + /// # Summary + /// Creates Gray code sequences + /// + /// # Input + /// ## n + /// Number of bits + /// + /// # Output + /// Array of tuples. First value in tuple is value in GrayCode sequence + /// Second value in tuple is position to change in current value to get + /// next one. + /// + /// # Example + /// ```Q# + /// GrayCode(2); // [(0, 0);(1, 1);(3, 0);(2, 1)] + /// ``` + function _GrayCode(n : Int) : (Int, Int)[] { + let N = 1 <<< n; + + mutable res = new (Int, Int)[N]; + mutable j = 0; + mutable current = IntAsBoolArray(0, n); + + for (i in 0..N - 1) { + if (i % 2 == 0) { + set j = 0; + } else { + let e = Zip(current, RangeAsIntArray(0..N - 1)); + set j = Snd(Head(Filtered(Fst, e))) + 1; + } + + set j = MaxI(0, Min([j, n - 1])); + set res w/= i <- (BoolArrayAsInt(current), j); + if (j < n) { + set current w/= j <- not current[j]; + } + } + + return res; + } + + /// # Summary + /// Computes the Hamming weight of an integer, i.e., the number of 1s in its + /// binary expansion. + /// + /// # Input + /// ## number + /// Number to compute Hamming weight + /// # Output + /// Hamming weight of the number + function _HammingWeightI(number : Int) : Int { + mutable cnt = number; + set cnt = (cnt &&& 0x5555555555555555) + ((cnt >>> 1) &&& 0x5555555555555555); + set cnt = (cnt &&& 0x3333333333333333) + ((cnt >>> 2) &&& 0x3333333333333333); + set cnt = (cnt &&& 0x0f0f0f0f0f0f0f0f) + ((cnt >>> 4) &&& 0x0f0f0f0f0f0f0f0f); + set cnt = (cnt &&& 0x00ff00ff00ff00ff) + ((cnt >>> 8) &&& 0x00ff00ff00ff00ff); + set cnt = (cnt &&& 0x0000ffff0000ffff) + ((cnt >>> 16) &&& 0x0000ffff0000ffff); + set cnt = (cnt &&& 0x00000000ffffffff) + ((cnt >>> 32) &&& 0x00000000ffffffff); + return cnt; + } + + /// # Summary + /// Returns the coefficient of the Rademacher-Walsh spectrum of the + /// n-variable AND function for a given assignment + /// + /// # Input + /// ## numVars + /// Number of variables in the AND function + /// ## index + /// Input assignment as integer (from 0 to 2^n - 1) + /// + /// # Output + /// Coefficient of the Rademacher-Walsh spectrum for given assignment + function _AndSpectrum(numVars : Int, index : Int) : Int { + if (index == 0) { + return 2^numVars - 2; + } else { + return _HammingWeightI(index) % 2 == 1 ? 2 | -2; + } + } + + /// # Summary + /// Implements a multiple-controlled Toffoli gate, assuming that target + /// qubit is initialized 0. The adjoint operation assumes that the target + /// qubit will be released to 0. + /// + /// # Input + /// ## controls + /// Control qubits + /// ## target + /// Target qubit + operation _ApplyMultipleControlledAnd(controls : Qubit[], target : Qubit) : Unit { + body (...) { + let vars = Length(controls); + + AssertAllZero([target]); + + HY(target); + + let code = _GrayCode(vars); + for (j in 0..Length(code) - 1) { + let (offset, ctrl) = code[j]; + RFrac(PauliZ, _AndSpectrum(vars, offset), vars + 2, target); + CNOT(controls[ctrl], target); + } + + H(target); + } + adjoint (...) { + let vars = Length(controls); + + H(target); + AssertProb([PauliZ], [target], One, 0.5, "Probability of the measurement must be 0.5", 1e-10); + if (IsResultOne(M(target))) { + for (i in 0..vars - 1) { + let start = 1 <<< i; + let code = _GrayCode(i); + for (j in 0..Length(code) - 1) { + let (offset, ctrl) = code[j]; + RFrac(PauliZ, -_AndSpectrum(vars, start + offset), vars + 1, controls[i]); + if (i != 0) { + CNOT(controls[ctrl], controls[i]); + } + } + } + Reset(target); + } + } + } } diff --git a/Standard/tests/ANDTests.qs b/Standard/tests/ANDTests.qs index 27cd9726476..6c62fec5d67 100644 --- a/Standard/tests/ANDTests.qs +++ b/Standard/tests/ANDTests.qs @@ -1,13 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. namespace Microsoft.Quantum.Tests { + open Microsoft.Quantum.Arrays; open Microsoft.Quantum.Canon; open Microsoft.Quantum.Convert; open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Logical; open Microsoft.Quantum.Measurement; - operation ANDTestHelper(polarity1 : Bool, polarity2 : Bool, gate : CCNOTop) : Unit { + operation AndTestHelper(polarity1 : Bool, polarity2 : Bool, gate : CCNOTop) : Unit { using ((control1, control2, target, output) = (Qubit(), Qubit(), Qubit(), Qubit())) { within { ApplyPauliFromBitString(PauliX, true, [polarity1, polarity2], [control1, control2]); @@ -20,15 +22,25 @@ namespace Microsoft.Quantum.Tests { if (MResetZ(output) != expected) { fail $"Expected output register to be {expected}"; } - if (IsResultOne(M(control1))) { - fail "Expected first control register to be 0"; + AssertAllZero([control1, control2, target]); + } + } + + operation ControlledAndTestHelper(polarities : Bool[]) : Unit { + let numControls = Length(polarities); + using ((controls, target, output) = (Qubit[numControls], Qubit(), Qubit())) { + within { + ApplyPauliFromBitString(PauliX, true, polarities, controls); + Controlled ApplyAnd(controls[0..numControls - 3], (controls[numControls - 2], controls[numControls - 1], target)); } - if (IsResultOne(M(control2))) { - fail "Expected second control register to be 0"; + apply { + CNOT(target, output); } - if (IsResultOne(M(target))) { - fail "Expected target register to be 0"; + let expected = BoolAsResult(All(EqualB(true, _), polarities)); + if (MResetZ(output) != expected) { + fail $"Expected output register to be {expected}"; } + AssertAllZero(controls + [target]); } } @@ -37,11 +49,20 @@ namespace Microsoft.Quantum.Tests { for (p1 in [false, true]) { for (p2 in [false, true]) { for (op in [ApplyAnd, ApplyLowDepthAnd]) { - ANDTestHelper(p1, p2, CCNOTop(op)); + AndTestHelper(p1, p2, CCNOTop(op)); } } } } + + @Test("QuantumSimulator") + operation ControlledApplyAndTest() : Unit { + for (numControls in 3..5) { + for (assignment in 0..2^numControls - 1) { + ControlledAndTestHelper(IntAsBoolArray(assignment, numControls)); + } + } + } } From 8b6198a9ee078c3799dec9e5c231cbe9bef5e5ce Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Wed, 18 Dec 2019 09:05:30 +0100 Subject: [PATCH 18/23] Controlled AndLowDepth. --- Standard/src/Canon/And.qs | 81 +++++++++++++++++++++++++++++++++++++- Standard/tests/ANDTests.qs | 11 ++++-- 2 files changed, 88 insertions(+), 4 deletions(-) diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs index 4acd1d23ab8..0a8739a86ac 100644 --- a/Standard/src/Canon/And.qs +++ b/Standard/src/Canon/And.qs @@ -125,6 +125,12 @@ namespace Microsoft.Quantum.Canon { adjoint (...) { Adjoint ApplyAnd(control1, control2, target); } + controlled (controls, ...) { + _ApplyMultipleControlledLowDepthAnd(controls + [control1, control2], target); + } + adjoint controlled (controls, ...) { + Adjoint _ApplyMultipleControlledAnd(controls + [control1, control2], target); + } } /// # Summary @@ -141,7 +147,7 @@ namespace Microsoft.Quantum.Canon { /// /// # Example /// ```Q# - /// GrayCode(2); // [(0, 0);(1, 1);(3, 0);(2, 1)] + /// _GrayCode(2); // [(0, 0);(1, 1);(3, 0);(2, 1)] /// ``` function _GrayCode(n : Int) : (Int, Int)[] { let N = 1 <<< n; @@ -256,4 +262,77 @@ namespace Microsoft.Quantum.Canon { } } } + + /// # Summary + /// Arrange control, target, and helper qubits according to an index + /// + /// # Description + /// Returns a Qubit array with target at index 0, and control i at index + /// 2^i. The helper qubits are inserted to all other positions in the + /// array. + function _ArrangeQubits(controls : Qubit[], target : Qubit, helper : Qubit[]) : Qubit[] { + let numControls = Length(controls); + mutable qs = new Qubit[2^numControls]; + set qs w/= 0 <- target; + mutable cntC = 0; + mutable cntH = 0; + for (i in 1..2^numControls - 1) { + if (i == (i &&& -i)) { + set qs w/= i <- controls[cntC]; + set cntC += 1; + } else { + set qs w/= i <- helper[cntH]; + set cntH += 1; + } + } + return qs; + } + + /// # Summary + /// Implements a multiple-controlled Toffoli gate, assuming that target + /// qubit is initialized 0. The adjoint operation assumes that the target + /// qubit will be released to 0. Requires a Rz depth of 1, while the number + /// of helper qubits are exponential in the number of qubits. + /// + /// # Input + /// ## controls + /// Control qubits + /// ## target + /// Target qubit + operation _ApplyMultipleControlledLowDepthAnd(controls : Qubit[], target : Qubit) : Unit { + body (...) { + let vars = Length(controls); + using (helper = Qubit[2^vars - vars - 1]) { + let qs = _ArrangeQubits(controls, target, helper); + + AssertAllZero([target]); + HY(target); + + within { + // initialize helper lines with control lines based on LSB + for (i in 3..2^vars - 1) { + let lsb = i &&& -i; + if (i != lsb) { // i is power of 2 + CNOT(qs[lsb], qs[i]); + } + } + // target to control + ApplyToEachA(CNOT(target, _), controls); + // copy remainder (without LSB) + for (i in 3..2^vars - 1) { + let lsb = i &&& -i; + if (i != lsb) { + CNOT(qs[i - lsb], qs[i]); + } + } + } apply { + for (i in IndexRange(qs)) { + RFrac(PauliZ, _AndSpectrum(vars, i), vars + 2, qs[i]); + } + } + + H(target); + } + } + } } diff --git a/Standard/tests/ANDTests.qs b/Standard/tests/ANDTests.qs index 6c62fec5d67..4cefc1304f3 100644 --- a/Standard/tests/ANDTests.qs +++ b/Standard/tests/ANDTests.qs @@ -26,12 +26,12 @@ namespace Microsoft.Quantum.Tests { } } - operation ControlledAndTestHelper(polarities : Bool[]) : Unit { + operation ControlledAndTestHelper(polarities : Bool[], gate : ((Qubit, Qubit, Qubit) => Unit is Adj+Ctl)) : Unit { let numControls = Length(polarities); using ((controls, target, output) = (Qubit[numControls], Qubit(), Qubit())) { within { ApplyPauliFromBitString(PauliX, true, polarities, controls); - Controlled ApplyAnd(controls[0..numControls - 3], (controls[numControls - 2], controls[numControls - 1], target)); + Controlled gate(controls[0..numControls - 3], (controls[numControls - 2], controls[numControls - 1], target)); } apply { CNOT(target, output); @@ -59,7 +59,12 @@ namespace Microsoft.Quantum.Tests { operation ControlledApplyAndTest() : Unit { for (numControls in 3..5) { for (assignment in 0..2^numControls - 1) { - ControlledAndTestHelper(IntAsBoolArray(assignment, numControls)); + ControlledAndTestHelper(IntAsBoolArray(assignment, numControls), ApplyAnd); + } + } + for (numControls in 3..4) { + for (assignment in 0..2^numControls - 1) { + ControlledAndTestHelper(IntAsBoolArray(assignment, numControls), ApplyLowDepthAnd); } } } From 21c95b091b99849a98c45e900897dbc00742cb94 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Wed, 18 Dec 2019 09:22:00 +0100 Subject: [PATCH 19/23] Adjoint Controlled LowDepthAnd. --- Standard/src/Canon/And.qs | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs index 0a8739a86ac..30ab2adaf7a 100644 --- a/Standard/src/Canon/And.qs +++ b/Standard/src/Canon/And.qs @@ -129,7 +129,7 @@ namespace Microsoft.Quantum.Canon { _ApplyMultipleControlledLowDepthAnd(controls + [control1, control2], target); } adjoint controlled (controls, ...) { - Adjoint _ApplyMultipleControlledAnd(controls + [control1, control2], target); + Adjoint _ApplyMultipleControlledLowDepthAnd(controls + [control1, control2], target); } } @@ -246,7 +246,7 @@ namespace Microsoft.Quantum.Canon { H(target); AssertProb([PauliZ], [target], One, 0.5, "Probability of the measurement must be 0.5", 1e-10); - if (IsResultOne(M(target))) { + if (IsResultOne(MResetZ(target))) { for (i in 0..vars - 1) { let start = 1 <<< i; let code = _GrayCode(i); @@ -258,7 +258,6 @@ namespace Microsoft.Quantum.Canon { } } } - Reset(target); } } } @@ -334,5 +333,33 @@ namespace Microsoft.Quantum.Canon { H(target); } } + adjoint (...) { + let vars = Length(controls); + + H(target); + AssertProb([PauliZ], [target], One, 0.5, "Probability of the measurement must be 0.5", 1e-10); + if (IsResultOne(MResetZ(target))) { + using (helper = Qubit[2^vars - vars - 1]) { + let qs = _ArrangeQubits(controls, target, helper); + within { + // this is a bit easier than in the compute part, since + // the target qubit does not have to be copied over to + // the control lines. Therefore, the two LSB CNOT parts + // can be merged into a single loop. + for (i in 3..2^vars - 1) { + let lsb = i &&& -i; + if (i != lsb) { + CNOT(qs[lsb], qs[i]); + CNOT(qs[i - lsb], qs[i]); + } + } + } apply { + for (i in 1..2^vars - 1) { + RFrac(PauliZ, -_AndSpectrum(vars, i), vars + 1, qs[i]); + } + } + } + } + } } } From fecfd550a48fa85dca2ee67a9b872a8eb47a0dc3 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Wed, 18 Dec 2019 16:41:03 +0100 Subject: [PATCH 20/23] References. --- Standard/src/Canon/And.qs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs index 30ab2adaf7a..7eb2e5d7335 100644 --- a/Standard/src/Canon/And.qs +++ b/Standard/src/Canon/And.qs @@ -36,10 +36,17 @@ namespace Microsoft.Quantum.Canon { /// Target ancilla qubit; must be in state 0 /// /// # 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 /// - Craig Gidney: "Halving the cost of quantum addition", Quantum 2, page /// 74, 2018 /// [arXiv:1709.06648](https://arxiv.org/abs/1709.06648) /// doi:10.1103/PhysRevA.85.044302 + /// - Mathias Soeken: "Quantum Oracle Circuits and the Christmas Tree Pattern", + /// [Blog article from Decemer 19, 2019](https://msoeken.github.io/blog_qac.html) + /// (note: explains the multiple controlled construction) operation ApplyAnd(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { body (...) { AssertAllZero([target]); @@ -94,14 +101,14 @@ namespace Microsoft.Quantum.Canon { /// Target ancilla qubit; must be in state 0 /// /// # References - /// - Craig Gidney: "Halving the cost of quantum addition", Quantum 2, page - /// 74, 2018 - /// [arXiv:1709.06648](https://arxiv.org/abs/1709.06648) - /// doi:10.1103/PhysRevA.85.044302 /// - 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 + /// - Peter Selinger: "Quantum circuits of T-depth one", + /// Phys. Rev. A 87, 042302, 2013 + /// [arXiv:1210.0974](https://arxiv.org/abs/1210.0974) + /// doi:10.1103/PhysRevA.87.042302 operation ApplyLowDepthAnd(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { body (...) { using (helper = Qubit()) { From dbd958ac64cd7956fb5bc316ec7498f8109144ca Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Wed, 18 Dec 2019 18:17:45 +0100 Subject: [PATCH 21/23] Simplify code. --- Standard/src/Canon/And.qs | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs index 7eb2e5d7335..8f45014013a 100644 --- a/Standard/src/Canon/And.qs +++ b/Standard/src/Canon/And.qs @@ -202,23 +202,19 @@ namespace Microsoft.Quantum.Canon { } /// # Summary - /// Returns the coefficient of the Rademacher-Walsh spectrum of the - /// n-variable AND function for a given assignment + /// Returns 1, if `index` has an odd number of 1s and -1, if `index` has an + /// even number of 1s. + /// + /// # Description + /// Value corresponds to the sign of the coefficient of the Rademacher-Walsh + /// spectrum of the n-variable AND function for a given assignment that + /// decides the angle of the rotation. /// /// # Input - /// ## numVars - /// Number of variables in the AND function /// ## index /// Input assignment as integer (from 0 to 2^n - 1) - /// - /// # Output - /// Coefficient of the Rademacher-Walsh spectrum for given assignment - function _AndSpectrum(numVars : Int, index : Int) : Int { - if (index == 0) { - return 2^numVars - 2; - } else { - return _HammingWeightI(index) % 2 == 1 ? 2 | -2; - } + function _Angle(index : Int) : Int { + return _HammingWeightI(index) % 2 == 1 ? 1 | -1; } /// # Summary @@ -237,16 +233,16 @@ namespace Microsoft.Quantum.Canon { AssertAllZero([target]); - HY(target); + H(target); let code = _GrayCode(vars); for (j in 0..Length(code) - 1) { let (offset, ctrl) = code[j]; - RFrac(PauliZ, _AndSpectrum(vars, offset), vars + 2, target); + RFrac(PauliZ, _Angle(offset), vars + 1, target); CNOT(controls[ctrl], target); } - H(target); + HY(target); } adjoint (...) { let vars = Length(controls); @@ -259,7 +255,7 @@ namespace Microsoft.Quantum.Canon { let code = _GrayCode(i); for (j in 0..Length(code) - 1) { let (offset, ctrl) = code[j]; - RFrac(PauliZ, -_AndSpectrum(vars, start + offset), vars + 1, controls[i]); + RFrac(PauliZ, -_Angle(start + offset), vars, controls[i]); if (i != 0) { CNOT(controls[ctrl], controls[i]); } @@ -312,7 +308,7 @@ namespace Microsoft.Quantum.Canon { let qs = _ArrangeQubits(controls, target, helper); AssertAllZero([target]); - HY(target); + H(target); within { // initialize helper lines with control lines based on LSB @@ -333,11 +329,11 @@ namespace Microsoft.Quantum.Canon { } } apply { for (i in IndexRange(qs)) { - RFrac(PauliZ, _AndSpectrum(vars, i), vars + 2, qs[i]); + RFrac(PauliZ, _Angle(i), vars + 1, qs[i]); } } - H(target); + HY(target); } } adjoint (...) { @@ -362,7 +358,7 @@ namespace Microsoft.Quantum.Canon { } } apply { for (i in 1..2^vars - 1) { - RFrac(PauliZ, -_AndSpectrum(vars, i), vars + 1, qs[i]); + RFrac(PauliZ, -_Angle(i), vars, qs[i]); } } } From 9f8bdf317f6d926206c262910851011ac064a682 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Wed, 18 Dec 2019 23:26:36 +0100 Subject: [PATCH 22/23] Apply suggestions from code review Co-Authored-By: Chris Granade --- Standard/src/Canon/And.qs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs index 8f45014013a..e6b89c67a71 100644 --- a/Standard/src/Canon/And.qs +++ b/Standard/src/Canon/And.qs @@ -33,7 +33,7 @@ namespace Microsoft.Quantum.Canon { /// ## control2 /// Second control qubit /// ## target - /// Target ancilla qubit; must be in state 0 + /// Target auxillary qubit; must be in state 0 /// /// # References /// - Cody Jones: "Novel constructions for the fault-tolerant Toffoli gate", @@ -98,7 +98,7 @@ namespace Microsoft.Quantum.Canon { /// ## control2 /// Second control qubit /// ## target - /// Target ancilla qubit; must be in state 0 + /// Target auxillary qubit; must be in state 0 /// /// # References /// - Cody Jones: "Novel constructions for the fault-tolerant Toffoli gate", @@ -154,7 +154,7 @@ namespace Microsoft.Quantum.Canon { /// /// # Example /// ```Q# - /// _GrayCode(2); // [(0, 0);(1, 1);(3, 0);(2, 1)] + /// _GrayCode(2); // [(0, 0),(1, 1),(3, 0),(2, 1)] /// ``` function _GrayCode(n : Int) : (Int, Int)[] { let N = 1 <<< n; From c099b7e31e94f93f47442d69556b77fa0577bae2 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Wed, 18 Dec 2019 23:30:07 +0100 Subject: [PATCH 23/23] Integrate comment. --- Standard/src/Canon/And.qs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs index e6b89c67a71..c1c3eec25d2 100644 --- a/Standard/src/Canon/And.qs +++ b/Standard/src/Canon/And.qs @@ -274,8 +274,7 @@ namespace Microsoft.Quantum.Canon { /// array. function _ArrangeQubits(controls : Qubit[], target : Qubit, helper : Qubit[]) : Qubit[] { let numControls = Length(controls); - mutable qs = new Qubit[2^numControls]; - set qs w/= 0 <- target; + mutable qs = new Qubit[2^numControls] w/ 0 <- target; mutable cntC = 0; mutable cntH = 0; for (i in 1..2^numControls - 1) {