From 9d10dec1a3a032721f68023c875a39ad1e666dc8 Mon Sep 17 00:00:00 2001 From: Christopher Kang Date: Wed, 28 Aug 2019 10:14:09 -0700 Subject: [PATCH 01/20] Drafted new apply ops --- .../Canon/Combinators/ApplyRepeatedOver.qs | 313 ++++++++++++++++++ 1 file changed, 313 insertions(+) create mode 100644 Standard/src/Canon/Combinators/ApplyRepeatedOver.qs diff --git a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs new file mode 100644 index 00000000000..7e9100d1ad7 --- /dev/null +++ b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs @@ -0,0 +1,313 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Canon { + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Arrays; + + /////////////////////////////////////////////////////////////////////////////////////////////// + // Helpers to repeatedly apply functions over qubit arrays + /////////////////////////////////////////////////////////////////////////////////////////////// + + operation ApplySeriesOfOps(listOfOps : (Qubit[] => Unit)[], targets : Int[][], register : Qubit[]) : Unit { + // + if (Length(listOfOps) != Length(targets)) { + fail "The number of ops and number of targets do not match!"; + } + for (index in 0..Length(listOfOps) - 1) { + if (Length(targets[index]) > Length(register)) { + fail "There are too many targets!"; + } + let opToApply = listOfOps[index]; + let qubitTargets = Subarray(targets[index, register]); + opToApply(qubitTargets); + } + } + + /// # Summary + /// Applies a multiply controlled version of a singly controlled + /// operation. + /// The modifier `C` indicates that the single-qubit operation is controllable. + /// + /// # Input + /// ## op + /// An operation to be applied multiple times on the qubit register + /// ## ccnot + /// The controlled-controlled-NOT gate to use for the construction. + /// ## controls + /// The qubits that `singlyControlledOp` is to be controlled on. + /// The length of `controls` must be at least 1. + /// ## targets + /// The target qubits that `singlyControlledOp` acts upon. + /// + /// # Remarks + /// This operation uses only clean ancilla qubits. + /// + /// For the explanation and circuit diagram see Figure 4.10, Section 4.3 in Nielsen & Chuang + /// + /// # References + /// - [ *Michael A. Nielsen , Isaac L. Chuang*, + /// Quantum Computation and Quantum Information ](http://doi.org/10.1017/CBO9780511976667) + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyMultiControlledCA + operation ApplyOpRepeatedlyOver(op : (Qubit[] => Unit), targets : Int[][], register : Qubit[]) : Unit + { + for (index in 0..Length(targets) - 1) + { + if (Length(targets[index]) > Length(register)) + { + fail "Too many targets!"; + } + let opTargets = Subarray(targets[index], register); + op(opTargets); + } + } + + operation ApplyOpRepeatedlyOverA(op : (Qubit[] => Unit is Adj), targets : Int[][], register : Qubit[]) : Unit is Adj + { + for (index in 0..Length(targets) - 1) + { + if (Length(targets[index]) > Length(register)) + { + fail "Too many targets!"; + } + let opTargets = Subarray(targets[index], register); + op(opTargets); + } + } + + operation ApplyOpRepeatedlyOverC(op : (Qubit[] => Unit is Ctl), targets : Int[][], register : Qubit[]) : Unit is Ctl + { + for (index in 0..Length(targets) - 1) + { + if (Length(targets[index]) > Length(register)) + { + fail "Too many targets!"; + } + let opTargets = Subarray(targets[index], register); + op(opTargets); + } + } + + + operation ApplyOpRepeatedlyOverCA(op : (Qubit[] => Unit is Adj+Ctl), targets : Int[][], register : Qubit[]) : Unit is Adj+Ctl + { + for (index in 0..Length(targets) - 1) + { + if (Length(targets[index]) > Length(register)) + { + fail "Too many targets!"; + } + let opTargets = Subarray(targets[index], register); + op(opTargets); + } + } + + /// # Summary + /// Applies a multiply controlled version of a singly controlled + /// operation. + /// The modifier `C` indicates that the single-qubit operation is controllable. + /// + /// # Input + /// ## singlyControlledOp + /// An operation controlled on a single qubit. + /// The first qubit in the argument of the operation is + /// assumed to be a control and the rest are assumed to be target qubits. + /// `ApplyMultiControlled` always calls `singlyControlledOp` with an argument of + /// length at least 1. + /// ## ccnot + /// The controlled-controlled-NOT gate to use for the construction. + /// ## controls + /// The qubits that `singlyControlledOp` is to be controlled on. + /// The length of `controls` must be at least 1. + /// ## targets + /// The target qubits that `singlyControlledOp` acts upon. + /// + /// # Remarks + /// This operation uses only clean ancilla qubits. + /// + /// For the explanation and circuit diagram see Figure 4.10, Section 4.3 in Nielsen & Chuang + /// + /// # References + /// - [ *Michael A. Nielsen , Isaac L. Chuang*, + /// Quantum Computation and Quantum Information ](http://doi.org/10.1017/CBO9780511976667) + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyMultiControlledCA + operation PermuteQubits(targets : Int[][], register : Qubit[]) : Unit { + ApplyOpRepeatedlyOverCA(ApplyToFirstTwoQubits(SWAP, _), targets, register); + } + + + + + /// # Summary + /// The signature type of CCNOT gate. + newtype CCNOTop = ((Qubit, Qubit, Qubit) => Unit is Adj); + + + /// # Summary + /// Applies a multiply controlled version of a singly controlled + /// operation. + /// The modifier `C` indicates that the single-qubit operation is controllable. + /// + /// # Input + /// ## singlyControlledOp + /// An operation controlled on a single qubit. + /// The first qubit in the argument of the operation is + /// assumed to be a control and the rest are assumed to be target qubits. + /// `ApplyMultiControlled` always calls `singlyControlledOp` with an argument of + /// length at least 1. + /// ## ccnot + /// The controlled-controlled-NOT gate to use for the construction. + /// ## controls + /// The qubits that `singlyControlledOp` is to be controlled on. + /// The length of `controls` must be at least 1. + /// ## targets + /// The target qubits that `singlyControlledOp` acts upon. + /// + /// # Remarks + /// This operation uses only clean ancilla qubits. + /// + /// For the explanation and circuit diagram see Figure 4.10, Section 4.3 in Nielsen & Chuang + /// + /// # References + /// - [ *Michael A. Nielsen , Isaac L. Chuang*, + /// Quantum Computation and Quantum Information ](http://doi.org/10.1017/CBO9780511976667) + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyMultiControlledCA + operation ApplyMultiControlledC (singlyControlledOp : (Qubit[] => Unit), ccnot : CCNOTop, controls : Qubit[], targets : Qubit[]) : Unit + { + body (...) + { + EqualityFactB(Length(controls) >= 1, true, $"Length of controls must be at least 1"); + + if (Length(controls) == 1) + { + singlyControlledOp(controls + targets); + } + else + { + using (ancillas = Qubit[Length(controls) - 1]) + { + AndLadder(ccnot, controls, ancillas); + singlyControlledOp([Tail(ancillas)] + targets); + Adjoint AndLadder(ccnot, controls, ancillas); + } + } + } + + controlled (extraControls, ...) + { + ApplyMultiControlledC(singlyControlledOp, ccnot, extraControls + controls, targets); + } + } + + + /// # Summary + /// Applies a multiply controlled version of a singly controlled + /// operation. + /// The modifier `CA` indicates that the single-qubit operation is controllable + /// and adjointable. + /// + /// # Input + /// ## singlyControlledOp + /// An operation controlled on a single qubit. + /// The first qubit in the argument of the operation + /// assumed to be a control and the rest are assumed to be target qubits. + /// `ApplyMultiControlled` always calls `singlyControlledOp` with an argument of + /// length at least 1. + /// ## ccnot + /// The controlled-controlled-NOT gate to use for the construction. + /// ## controls + /// The qubits that `singlyControlledOp` is to be controlled on. + /// The length of `controls` must be at least 1. + /// ## targets + /// The target qubits that `singlyControlledOp` acts upon. + /// + /// # Remarks + /// This operation uses only clean ancilla qubits. + /// + /// For the explanation and circuit diagram see Figure 4.10, Section 4.3 in Nielsen & Chuang + /// + /// # References + /// - [ *Michael A. Nielsen , Isaac L. Chuang*, + /// Quantum Computation and Quantum Information ](http://doi.org/10.1017/CBO9780511976667) + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyMultiControlledC + operation ApplyMultiControlledCA (singlyControlledOp : (Qubit[] => Unit is Adj), ccnot : CCNOTop, controls : Qubit[], targets : Qubit[]) : Unit { + body (...) { + Fact(Length(controls) >= 1, $"Length of controls must be at least 1"); + + if (Length(controls) == 1) { + singlyControlledOp(controls + targets); + } else { + using (ladderRegister = Qubit[Length(controls) - 1]) { + AndLadder(ccnot, controls, ladderRegister); + singlyControlledOp([Tail(ladderRegister)] + targets); + Adjoint AndLadder(ccnot, controls, ladderRegister); + } + } + } + + adjoint invert; + + controlled (extraControls, ...) { + ApplyMultiControlledCA(singlyControlledOp, ccnot, extraControls + controls, targets); + } + + controlled adjoint invert; + } + + + /// # Summary + /// Performs a controlled 'AND ladder' on the target qubits. + /// + /// This applies a unitary given by the following map on computational basis vectors: + /// $$ + /// \begin{align} + /// \ket{x\_1, \dots, x\_n} \ket{y\_1, \dots, y\_{n - 1}} \mapsto + /// \ket{x\_1, \dots, x\_n} \ket{ + /// y\_1 \oplus (x\_1 \land x\_2), \dots, y\_{n - 1} \oplus (x\_1 \land x\_2 \land \cdots \land x\_{n - 1} + /// }, + /// \end{align} + /// $$ + /// where $\ket{x\_1, \dots, x\_n}$ refers to the computational basis + /// states of `controls`, and where $\ket{y\_1, \dots, y\_{n - 1}}$ + /// refers to the computational basis states of `targets`. + /// + /// # Input + /// ## ccnot + /// The CCNOT gate to use for the construction. + /// ## controls + /// A register of qubits to be used as controls for the and ladder. + /// This operation leaves computational basis states of `controls` + /// invariant. + /// The length of `controls` must be at least 2, and must + /// be equal to one plus the length of `targets`. + /// ## targets + /// The length of `targets` must be at least 1 and equal to the length + /// of `controls` minus one. + /// + /// # References + /// - [ *Michael A. Nielsen , Isaac L. Chuang*, + /// Quantum Computation and Quantum Information ](http://doi.org/10.1017/CBO9780511976667) + /// + /// # Remarks + /// - Used as a part of + /// and . + /// - For the explanation and circuit diagram see Figure 4.10, Section 4.3 in Nielsen & Chuang. + 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]); + + for (k in 1 .. Length(targets) - 1) { + ccnot!(controls[k + 1], targets[k - 1], targets[k]); + } + } + +} \ No newline at end of file From 2e61df931e7527f22806e4007555ede6c58ad3ea Mon Sep 17 00:00:00 2001 From: Christopher Kang Date: Wed, 28 Aug 2019 10:16:54 -0700 Subject: [PATCH 02/20] Fixed docs --- .../Canon/Combinators/ApplyRepeatedOver.qs | 225 +----------------- 1 file changed, 5 insertions(+), 220 deletions(-) diff --git a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs index 7e9100d1ad7..51f96ff29d3 100644 --- a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs +++ b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs @@ -10,7 +10,6 @@ namespace Microsoft.Quantum.Canon { /////////////////////////////////////////////////////////////////////////////////////////////// operation ApplySeriesOfOps(listOfOps : (Qubit[] => Unit)[], targets : Int[][], register : Qubit[]) : Unit { - // if (Length(listOfOps) != Length(targets)) { fail "The number of ops and number of targets do not match!"; } @@ -32,25 +31,14 @@ namespace Microsoft.Quantum.Canon { /// # Input /// ## op /// An operation to be applied multiple times on the qubit register - /// ## ccnot - /// The controlled-controlled-NOT gate to use for the construction. - /// ## controls - /// The qubits that `singlyControlledOp` is to be controlled on. - /// The length of `controls` must be at least 1. /// ## targets - /// The target qubits that `singlyControlledOp` acts upon. - /// - /// # Remarks - /// This operation uses only clean ancilla qubits. - /// - /// For the explanation and circuit diagram see Figure 4.10, Section 4.3 in Nielsen & Chuang - /// - /// # References - /// - [ *Michael A. Nielsen , Isaac L. Chuang*, - /// Quantum Computation and Quantum Information ](http://doi.org/10.1017/CBO9780511976667) + /// Nested arrays describing the targets of the op. Each array should contain a list of ints describing + /// the qubits to be used. + /// ## register + /// Qubit register to be acted upon. /// /// # See Also - /// - Microsoft.Quantum.Canon.ApplyMultiControlledCA + /// - Microsoft.Quantum.Canon.ApplySeriesOfOps operation ApplyOpRepeatedlyOver(op : (Qubit[] => Unit), targets : Int[][], register : Qubit[]) : Unit { for (index in 0..Length(targets) - 1) @@ -90,7 +78,6 @@ namespace Microsoft.Quantum.Canon { } } - operation ApplyOpRepeatedlyOverCA(op : (Qubit[] => Unit is Adj+Ctl), targets : Int[][], register : Qubit[]) : Unit is Adj+Ctl { for (index in 0..Length(targets) - 1) @@ -104,210 +91,8 @@ namespace Microsoft.Quantum.Canon { } } - /// # Summary - /// Applies a multiply controlled version of a singly controlled - /// operation. - /// The modifier `C` indicates that the single-qubit operation is controllable. - /// - /// # Input - /// ## singlyControlledOp - /// An operation controlled on a single qubit. - /// The first qubit in the argument of the operation is - /// assumed to be a control and the rest are assumed to be target qubits. - /// `ApplyMultiControlled` always calls `singlyControlledOp` with an argument of - /// length at least 1. - /// ## ccnot - /// The controlled-controlled-NOT gate to use for the construction. - /// ## controls - /// The qubits that `singlyControlledOp` is to be controlled on. - /// The length of `controls` must be at least 1. - /// ## targets - /// The target qubits that `singlyControlledOp` acts upon. - /// - /// # Remarks - /// This operation uses only clean ancilla qubits. - /// - /// For the explanation and circuit diagram see Figure 4.10, Section 4.3 in Nielsen & Chuang - /// - /// # References - /// - [ *Michael A. Nielsen , Isaac L. Chuang*, - /// Quantum Computation and Quantum Information ](http://doi.org/10.1017/CBO9780511976667) - /// - /// # See Also - /// - Microsoft.Quantum.Canon.ApplyMultiControlledCA operation PermuteQubits(targets : Int[][], register : Qubit[]) : Unit { ApplyOpRepeatedlyOverCA(ApplyToFirstTwoQubits(SWAP, _), targets, register); } - - - - /// # Summary - /// The signature type of CCNOT gate. - newtype CCNOTop = ((Qubit, Qubit, Qubit) => Unit is Adj); - - - /// # Summary - /// Applies a multiply controlled version of a singly controlled - /// operation. - /// The modifier `C` indicates that the single-qubit operation is controllable. - /// - /// # Input - /// ## singlyControlledOp - /// An operation controlled on a single qubit. - /// The first qubit in the argument of the operation is - /// assumed to be a control and the rest are assumed to be target qubits. - /// `ApplyMultiControlled` always calls `singlyControlledOp` with an argument of - /// length at least 1. - /// ## ccnot - /// The controlled-controlled-NOT gate to use for the construction. - /// ## controls - /// The qubits that `singlyControlledOp` is to be controlled on. - /// The length of `controls` must be at least 1. - /// ## targets - /// The target qubits that `singlyControlledOp` acts upon. - /// - /// # Remarks - /// This operation uses only clean ancilla qubits. - /// - /// For the explanation and circuit diagram see Figure 4.10, Section 4.3 in Nielsen & Chuang - /// - /// # References - /// - [ *Michael A. Nielsen , Isaac L. Chuang*, - /// Quantum Computation and Quantum Information ](http://doi.org/10.1017/CBO9780511976667) - /// - /// # See Also - /// - Microsoft.Quantum.Canon.ApplyMultiControlledCA - operation ApplyMultiControlledC (singlyControlledOp : (Qubit[] => Unit), ccnot : CCNOTop, controls : Qubit[], targets : Qubit[]) : Unit - { - body (...) - { - EqualityFactB(Length(controls) >= 1, true, $"Length of controls must be at least 1"); - - if (Length(controls) == 1) - { - singlyControlledOp(controls + targets); - } - else - { - using (ancillas = Qubit[Length(controls) - 1]) - { - AndLadder(ccnot, controls, ancillas); - singlyControlledOp([Tail(ancillas)] + targets); - Adjoint AndLadder(ccnot, controls, ancillas); - } - } - } - - controlled (extraControls, ...) - { - ApplyMultiControlledC(singlyControlledOp, ccnot, extraControls + controls, targets); - } - } - - - /// # Summary - /// Applies a multiply controlled version of a singly controlled - /// operation. - /// The modifier `CA` indicates that the single-qubit operation is controllable - /// and adjointable. - /// - /// # Input - /// ## singlyControlledOp - /// An operation controlled on a single qubit. - /// The first qubit in the argument of the operation - /// assumed to be a control and the rest are assumed to be target qubits. - /// `ApplyMultiControlled` always calls `singlyControlledOp` with an argument of - /// length at least 1. - /// ## ccnot - /// The controlled-controlled-NOT gate to use for the construction. - /// ## controls - /// The qubits that `singlyControlledOp` is to be controlled on. - /// The length of `controls` must be at least 1. - /// ## targets - /// The target qubits that `singlyControlledOp` acts upon. - /// - /// # Remarks - /// This operation uses only clean ancilla qubits. - /// - /// For the explanation and circuit diagram see Figure 4.10, Section 4.3 in Nielsen & Chuang - /// - /// # References - /// - [ *Michael A. Nielsen , Isaac L. Chuang*, - /// Quantum Computation and Quantum Information ](http://doi.org/10.1017/CBO9780511976667) - /// - /// # See Also - /// - Microsoft.Quantum.Canon.ApplyMultiControlledC - operation ApplyMultiControlledCA (singlyControlledOp : (Qubit[] => Unit is Adj), ccnot : CCNOTop, controls : Qubit[], targets : Qubit[]) : Unit { - body (...) { - Fact(Length(controls) >= 1, $"Length of controls must be at least 1"); - - if (Length(controls) == 1) { - singlyControlledOp(controls + targets); - } else { - using (ladderRegister = Qubit[Length(controls) - 1]) { - AndLadder(ccnot, controls, ladderRegister); - singlyControlledOp([Tail(ladderRegister)] + targets); - Adjoint AndLadder(ccnot, controls, ladderRegister); - } - } - } - - adjoint invert; - - controlled (extraControls, ...) { - ApplyMultiControlledCA(singlyControlledOp, ccnot, extraControls + controls, targets); - } - - controlled adjoint invert; - } - - - /// # Summary - /// Performs a controlled 'AND ladder' on the target qubits. - /// - /// This applies a unitary given by the following map on computational basis vectors: - /// $$ - /// \begin{align} - /// \ket{x\_1, \dots, x\_n} \ket{y\_1, \dots, y\_{n - 1}} \mapsto - /// \ket{x\_1, \dots, x\_n} \ket{ - /// y\_1 \oplus (x\_1 \land x\_2), \dots, y\_{n - 1} \oplus (x\_1 \land x\_2 \land \cdots \land x\_{n - 1} - /// }, - /// \end{align} - /// $$ - /// where $\ket{x\_1, \dots, x\_n}$ refers to the computational basis - /// states of `controls`, and where $\ket{y\_1, \dots, y\_{n - 1}}$ - /// refers to the computational basis states of `targets`. - /// - /// # Input - /// ## ccnot - /// The CCNOT gate to use for the construction. - /// ## controls - /// A register of qubits to be used as controls for the and ladder. - /// This operation leaves computational basis states of `controls` - /// invariant. - /// The length of `controls` must be at least 2, and must - /// be equal to one plus the length of `targets`. - /// ## targets - /// The length of `targets` must be at least 1 and equal to the length - /// of `controls` minus one. - /// - /// # References - /// - [ *Michael A. Nielsen , Isaac L. Chuang*, - /// Quantum Computation and Quantum Information ](http://doi.org/10.1017/CBO9780511976667) - /// - /// # Remarks - /// - Used as a part of - /// and . - /// - For the explanation and circuit diagram see Figure 4.10, Section 4.3 in Nielsen & Chuang. - 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]); - - for (k in 1 .. Length(targets) - 1) { - ccnot!(controls[k + 1], targets[k - 1], targets[k]); - } - } - } \ No newline at end of file From f76cf3e442a12a24ed6ce59502b5629bef11c2c7 Mon Sep 17 00:00:00 2001 From: Christopher Kang Date: Wed, 28 Aug 2019 10:27:12 -0700 Subject: [PATCH 03/20] Fixed minor bugs --- Standard/src/Canon/Combinators/ApplyRepeatedOver.qs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs index 51f96ff29d3..ce775cd858e 100644 --- a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs +++ b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs @@ -18,7 +18,7 @@ namespace Microsoft.Quantum.Canon { fail "There are too many targets!"; } let opToApply = listOfOps[index]; - let qubitTargets = Subarray(targets[index, register]); + let qubitTargets = Subarray(targets[index], register); opToApply(qubitTargets); } } @@ -92,7 +92,7 @@ namespace Microsoft.Quantum.Canon { } operation PermuteQubits(targets : Int[][], register : Qubit[]) : Unit { - ApplyOpRepeatedlyOverCA(ApplyToFirstTwoQubits(SWAP, _), targets, register); + ApplyOpRepeatedlyOver(ApplyToFirstTwoQubits(SWAP, _), targets, register); } } \ No newline at end of file From ba39745daee3e28e0963c1f889e5c9e3c726567f Mon Sep 17 00:00:00 2001 From: Christopher Kang Date: Thu, 29 Aug 2019 12:24:57 -0700 Subject: [PATCH 04/20] Added Permutation function + helper Arrays + Claim functions --- Standard/src/Arrays/Arrays.qs | 102 +++++++++++ .../Canon/Combinators/ApplyRepeatedOver.qs | 173 +++++++++++++++++- Standard/src/Diagnostics/Claims.qs | 27 +++ Standard/src/Standard.csproj | 2 +- Standard/tests/ApplyRepeatedOverTests.qs | 35 ++++ 5 files changed, 333 insertions(+), 6 deletions(-) create mode 100644 Standard/src/Diagnostics/Claims.qs create mode 100644 Standard/tests/ApplyRepeatedOverTests.qs diff --git a/Standard/src/Arrays/Arrays.qs b/Standard/src/Arrays/Arrays.qs index 064375e5512..28a76e48fef 100644 --- a/Standard/src/Arrays/Arrays.qs +++ b/Standard/src/Arrays/Arrays.qs @@ -280,6 +280,108 @@ namespace Microsoft.Quantum.Arrays { return output; } + /// # Summary + /// Returns the order elements in an array need to be swapped to produce an ordered array. + /// Assumes swaps occur in place. + /// + /// # Input + /// ## newOrder + /// Array with the permutation of the indices of the new array. There should be n elements, + /// each being a unique integer from 0 to n-1. + /// + /// # Output + /// The tuple represents the two indices to be swapped. The swaps begin at the lowest index. + /// + /// # Remarks + /// ## Example + /// ```qsharp + /// // The following returns [(0, 5),(0, 4),(0, 1),(0, 3)]; + /// let swapOrder = SwapOrderToPermuteArray([5, 3, 2, 0, 1, 4]); + /// ``` + /// + /// ## Psuedocode + /// for (index in 0..Length(newOrder) - 1) + /// { + /// while newOrder[index] != index + /// { + /// Switch newOrder[index] with newOrder[newOrder[index]] + /// } + /// } + function SwapOrderToPermuteArray(newOrder : Int[]) : (Int, Int)[] { + // Check to verify the new ordering actually is a permutation of the indices + for (index in 0..Length(newOrder) - 1) { + if (IndexOf(ClaimEqualInt(index, _), newOrder) == -1) { + fail "The new ordering is not a permuation of the arrays indices"; + } + } + + // The maximum number of swaps is n - 1 + let maxSwaps = Length(newOrder) - 1; + mutable leftSwap = new Int[maxSwaps]; + mutable rightSwap = new Int[maxSwaps]; + mutable order = newOrder; + mutable swapIndex = 0; + + for (index in 0..Length(order) - 1) { + while (not ClaimEqualInt(order[index], index)) + { + set leftSwap w/= swapIndex <- index; + set rightSwap w/= swapIndex <- order[index]; + set order = Swapped(order[index], index, order); + set swapIndex = swapIndex + 1; + } + } + + // Remove (0, 0) swaps at the end + while ((leftSwap[Length(leftSwap) - 1] == 0) and (rightSwap[Length(rightSwap) - 1] == 0)) { + set leftSwap = Most(leftSwap); + set rightSwap = Most(rightSwap); + } + + return Zip(leftSwap, rightSwap); + } + + /// # Summary + /// Applies an in-place swap of two elements in an array. + /// + /// # Input + /// ## firstIndex + /// Index of the first element to be swapped. + /// + /// ## secondIndex + /// Index of the second element to be swapped. + /// + /// ## arr + /// Array with elements to be swapped. + /// + /// # Output + /// The array with the in place swapp applied. + function Swapped<'T>(firstIndex: Int, secondIndex: Int, arr: 'T[]) : 'T[] { + mutable newArray = arr; + let firstIndexVal = arr[firstIndex]; + set newArray w/= firstIndex <- newArray[secondIndex]; + set newArray w/= secondIndex <- firstIndexVal; + return newArray; + } + + /// # Summary + /// Turns a list of 2-tuples into a nested array. + /// + /// # Input + /// ## tupleList + /// List of 2-tuples to be turned into a nested array. + /// + /// # Output + /// A nested array with length matching the tupleList. + function TupleListToNestedArray<'T>(tupleList : ('T, 'T)[]) : 'T[][] { + mutable newArray = new 'T[][Length(tupleList)]; + for (idx in IndexRange(tupleList)) { + let (tupleLeft, tupleRight) = tupleList[idx]; + set newArray w/= idx <- [tupleLeft, tupleRight]; + } + return newArray; + } + } diff --git a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs index ce775cd858e..29afdffcdc2 100644 --- a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs +++ b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs @@ -4,11 +4,26 @@ namespace Microsoft.Quantum.Canon { open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Intrinsic; /////////////////////////////////////////////////////////////////////////////////////////////// // Helpers to repeatedly apply functions over qubit arrays /////////////////////////////////////////////////////////////////////////////////////////////// + /// # Summary + /// Applies a list of ops and their targets sequentially on a qubit array. + /// + /// # Input + /// ## listOfOps + /// List of ops, each taking a qubit array, to be applied. They are applied sequentially, lowest index first. + /// ## targets + /// Nested arrays describing the targets of the op. Each array should contain a list of ints describing + /// the qubits to be used. + /// ## register + /// Qubit register to be acted upon. + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyOpRepeatedlyOver operation ApplySeriesOfOps(listOfOps : (Qubit[] => Unit)[], targets : Int[][], register : Qubit[]) : Unit { if (Length(listOfOps) != Length(targets)) { fail "The number of ops and number of targets do not match!"; @@ -24,9 +39,94 @@ namespace Microsoft.Quantum.Canon { } /// # Summary - /// Applies a multiply controlled version of a singly controlled - /// operation. - /// The modifier `C` indicates that the single-qubit operation is controllable. + /// Applies a list of ops and their targets sequentially on a qubit array. (Adjoint) + /// + /// # Input + /// ## listOfOps + /// List of ops, each taking a qubit array, to be applied. They are applied sequentially, lowest index first. + /// Each must have a Adjoint functor. + /// ## targets + /// Nested arrays describing the targets of the op. Each array should contain a list of ints describing + /// the qubits to be used. + /// ## register + /// Qubit register to be acted upon. + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyOpRepeatedlyOver + operation ApplySeriesOfOpsA(listOfOps : (Qubit[] => Unit is Adj)[], targets : Int[][], register : Qubit[]) : Unit is Adj{ + if (Length(listOfOps) != Length(targets)) { + fail "The number of ops and number of targets do not match!"; + } + for (index in 0..Length(listOfOps) - 1) { + if (Length(targets[index]) > Length(register)) { + fail "There are too many targets!"; + } + let opToApply = listOfOps[index]; + let qubitTargets = Subarray(targets[index], register); + opToApply(qubitTargets); + } + } + + /// # Summary + /// Applies a list of ops and their targets sequentially on a qubit array. (Controlled) + /// + /// # Input + /// ## listOfOps + /// List of ops, each taking a qubit array, to be applied. They are applied sequentially, lowest index first. + /// Each must have a Controlled functor. + /// ## targets + /// Nested arrays describing the targets of the op. Each array should contain a list of ints describing + /// the qubits to be used. + /// ## register + /// Qubit register to be acted upon. + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyOpRepeatedlyOver + operation ApplySeriesOfOpsC(listOfOps : (Qubit[] => Unit is Ctl)[], targets : Int[][], register : Qubit[]) : Unit is Ctl { + if (Length(listOfOps) != Length(targets)) { + fail "The number of ops and number of targets do not match!"; + } + for (index in 0..Length(listOfOps) - 1) { + if (Length(targets[index]) > Length(register)) { + fail "There are too many targets!"; + } + let opToApply = listOfOps[index]; + let qubitTargets = Subarray(targets[index], register); + opToApply(qubitTargets); + } + } + + /// # Summary + /// Applies a list of ops and their targets sequentially on a qubit array. (Adjoint + Controlled) + /// + /// # Input + /// ## listOfOps + /// List of ops, each taking a qubit array, to be applied. They are applied sequentially, lowest index first. + /// Each must have both a Adjoint and Controlled functor. + /// ## targets + /// Nested arrays describing the targets of the op. Each array should contain a list of ints describing + /// the qubits to be used. + /// ## register + /// Qubit register to be acted upon. + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyOpRepeatedlyOver + operation ApplySeriesOfOpsCA(listOfOps : (Qubit[] => Unit is Adj + Ctl)[], targets : Int[][], register : Qubit[]) : Unit is Adj + Ctl { + if (Length(listOfOps) != Length(targets)) { + fail "The number of ops and number of targets do not match!"; + } + for (index in 0..Length(listOfOps) - 1) { + if (Length(targets[index]) > Length(register)) { + fail "There are too many targets!"; + } + let opToApply = listOfOps[index]; + let qubitTargets = Subarray(targets[index], register); + opToApply(qubitTargets); + } + } + + /// # Summary + /// Applies the same op over a qubit register multiple times. /// /// # Input /// ## op @@ -52,6 +152,20 @@ namespace Microsoft.Quantum.Canon { } } + /// # Summary + /// Applies the same op over a qubit register multiple times. + /// + /// # Input + /// ## op + /// An operation to be applied multiple times on the qubit register + /// ## targets + /// Nested arrays describing the targets of the op. Each array should contain a list of ints describing + /// the qubits to be used. + /// ## register + /// Qubit register to be acted upon. + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplySeriesOfOps operation ApplyOpRepeatedlyOverA(op : (Qubit[] => Unit is Adj), targets : Int[][], register : Qubit[]) : Unit is Adj { for (index in 0..Length(targets) - 1) @@ -65,6 +179,20 @@ namespace Microsoft.Quantum.Canon { } } + /// # Summary + /// Applies the same op over a qubit register multiple times. + /// + /// # Input + /// ## op + /// An operation to be applied multiple times on the qubit register + /// ## targets + /// Nested arrays describing the targets of the op. Each array should contain a list of ints describing + /// the qubits to be used. + /// ## register + /// Qubit register to be acted upon. + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplySeriesOfOps operation ApplyOpRepeatedlyOverC(op : (Qubit[] => Unit is Ctl), targets : Int[][], register : Qubit[]) : Unit is Ctl { for (index in 0..Length(targets) - 1) @@ -78,6 +206,20 @@ namespace Microsoft.Quantum.Canon { } } + /// # Summary + /// Applies the same op over a qubit register multiple times. + /// + /// # Input + /// ## op + /// An operation to be applied multiple times on the qubit register + /// ## targets + /// Nested arrays describing the targets of the op. Each array should contain a list of ints describing + /// the qubits to be used. + /// ## register + /// Qubit register to be acted upon. + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplySeriesOfOps operation ApplyOpRepeatedlyOverCA(op : (Qubit[] => Unit is Adj+Ctl), targets : Int[][], register : Qubit[]) : Unit is Adj+Ctl { for (index in 0..Length(targets) - 1) @@ -91,8 +233,29 @@ namespace Microsoft.Quantum.Canon { } } - operation PermuteQubits(targets : Int[][], register : Qubit[]) : Unit { - ApplyOpRepeatedlyOver(ApplyToFirstTwoQubits(SWAP, _), targets, register); + // operation PermuteQubits(targets : Int[][], register : Qubit[]) : Unit { + // ApplyOpRepeatedlyOver(ApplyToFirstTwoQubits(SWAP, _), targets, register); + // } + + /// # Summary + /// Permutes qubits by using the SWAP operator. + /// + /// # Input + /// ## ordering + /// Describes the new ordering of the qubits, where the qubit at index i will now be at ordering[i]. + /// ## register + /// Qubit register to be acted upon. + operation PermuteQubits(ordering : Int[], register : Qubit[]) : Unit { + // Do something! + if (Length(ordering) != Length(register)) { + fail "The new ordering array has an incorrect number of elements"; + } + + let swapOrder = SwapOrderToPermuteArray(ordering); + let swapTargets = TupleListToNestedArray(swapOrder); + + let SwapOp = ApplyToFirstTwoQubitsCA(SWAP, _); + ApplyOpRepeatedlyOverCA(SwapOp, swapTargets, register); } } \ No newline at end of file diff --git a/Standard/src/Diagnostics/Claims.qs b/Standard/src/Diagnostics/Claims.qs new file mode 100644 index 00000000000..ecc1eefa9fb --- /dev/null +++ b/Standard/src/Diagnostics/Claims.qs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Diagnostics { + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Canon; + + /// # Summary + /// Checks whether two ints are equal + /// + /// # Input + /// ## first + /// First int to check + /// + /// ## second + /// Second int to check + /// + /// # Output + /// True if the ints are equal, False if the ints differ. + function ClaimEqualInt(first : Int, second : Int) : Bool { + if (first == second) { + return true; + } + return false; + } + +} diff --git a/Standard/src/Standard.csproj b/Standard/src/Standard.csproj index b874e7d6fec..6331a9bd3e8 100644 --- a/Standard/src/Standard.csproj +++ b/Standard/src/Standard.csproj @@ -7,7 +7,7 @@ 0162 - True + False Microsoft Microsoft's Quantum standard libraries. © Microsoft Corporation. All rights reserved. diff --git a/Standard/tests/ApplyRepeatedOverTests.qs b/Standard/tests/ApplyRepeatedOverTests.qs new file mode 100644 index 00000000000..80eefdba2fe --- /dev/null +++ b/Standard/tests/ApplyRepeatedOverTests.qs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +namespace Microsoft.Quantum.Tests { + + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Diagnostics; + + + operation ApplySeriesOfOpsTest() : Unit { + // + } + + /// # Summary + /// Tests multiply controlled not implementation that uses + /// ApplyMultiControlledCA against multiply controlled version of + /// the Microsoft.Quantum.Intrinsic.X + operation ApplyRepeatedOpTest() : Unit { + // + let op = ???; + using (register = Qubit[]) { + // + } + } + + operation PermuteQubitsTest() : Unit { + // + using (register = Qubit[]) { + // + + // maybe verify this using the Subarray function? + } + } + +} \ No newline at end of file From e2282b875e60b197f00886343be0b77256831bdd Mon Sep 17 00:00:00 2001 From: Christopher Kang Date: Thu, 29 Aug 2019 12:26:25 -0700 Subject: [PATCH 05/20] Added Adj + Ctl and set csproj back to generating docs --- Standard/src/Canon/Combinators/ApplyRepeatedOver.qs | 2 +- Standard/src/Standard.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs index 29afdffcdc2..af8fed73807 100644 --- a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs +++ b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs @@ -245,7 +245,7 @@ namespace Microsoft.Quantum.Canon { /// Describes the new ordering of the qubits, where the qubit at index i will now be at ordering[i]. /// ## register /// Qubit register to be acted upon. - operation PermuteQubits(ordering : Int[], register : Qubit[]) : Unit { + operation PermuteQubits(ordering : Int[], register : Qubit[]) : Unit is Adj+Ctl { // Do something! if (Length(ordering) != Length(register)) { fail "The new ordering array has an incorrect number of elements"; diff --git a/Standard/src/Standard.csproj b/Standard/src/Standard.csproj index 6331a9bd3e8..b874e7d6fec 100644 --- a/Standard/src/Standard.csproj +++ b/Standard/src/Standard.csproj @@ -7,7 +7,7 @@ 0162 - False + True Microsoft Microsoft's Quantum standard libraries. © Microsoft Corporation. All rights reserved. From 8580eeefb6b8be1f23387f23476839ad95503eb2 Mon Sep 17 00:00:00 2001 From: Christopher Kang Date: Thu, 29 Aug 2019 15:46:12 -0700 Subject: [PATCH 06/20] Added tests --- Standard/tests/ApplyRepeatedOverTests.qs | 66 ++++++++++++++++++------ Standard/tests/ArrayTests.qs | 27 ++++++++++ Standard/tests/ClaimTests.qs | 18 +++++++ 3 files changed, 94 insertions(+), 17 deletions(-) create mode 100644 Standard/tests/ClaimTests.qs diff --git a/Standard/tests/ApplyRepeatedOverTests.qs b/Standard/tests/ApplyRepeatedOverTests.qs index 80eefdba2fe..0e1da1f08dc 100644 --- a/Standard/tests/ApplyRepeatedOverTests.qs +++ b/Standard/tests/ApplyRepeatedOverTests.qs @@ -1,35 +1,67 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. + namespace Microsoft.Quantum.Tests { open Microsoft.Quantum.Canon; open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Diagnostics; - + open Microsoft.Quantum.Arrays; + operation ApplySeriesOfOpsTest() : Unit { - // + // create the sample ops + their targets here + let op1 = ApplyToFirstQubit(X, _); + let op2 = ApplyToFirstTwoQubits(CNOT, _); + let op3 = Exp([PauliX, PauliZ, PauliY], 0.2002, _); + let op4 = ApplyToEachA(H, _); + let target1 = [0]; + let target2 = [0, 4]; + let target3 = [2, 3, 5]; + let target4 = [1, 2, 3, 4]; + + let listOfOps = [op1, op2, op3, op4]; + let listOfTargets = [target1, target2, target3, target4]; + AssertOperationsEqualReferenced(6, ApplySeriesOfOps(listOfOps, listOfTargets, _), _SampleApplySeriesOfOps(_)); + } + + // Helper method for ApplySeriesOfOpsTest + operation _SampleApplySeriesOfOps(register : Qubit[]) : Unit is Adj + Ctl { + // replicate those ops implemented here + X(register[0]); + CNOT(register[0], register[4]); + Exp([PauliX, PauliZ, PauliY], 0.2002, Subarray([2, 3, 5], register)); + ApplyToEachA(H, Subarray([1, 2, 3, 4], register)); } - /// # Summary - /// Tests multiply controlled not implementation that uses - /// ApplyMultiControlledCA against multiply controlled version of - /// the Microsoft.Quantum.Intrinsic.X operation ApplyRepeatedOpTest() : Unit { - // - let op = ???; - using (register = Qubit[]) { - // - } + let op = ApplyToFirstThreeQubits(CCNOT, _); + let targets = [[0, 1, 2], [2, 1, 0], [3, 4, 5], [2, 4, 0], [5, 3, 1]]; + AssertOperationsEqualReferenced(6, ApplyOpRepeatedlyOver(op, targets, _), _SampleApplyRepeatedOp(_)); + } + + // Helper method for ApplyRepeatedOpTest + operation _SampleApplyRepeatedOp(register : Qubit[]) : Unit is Adj + Ctl { + CCNOT(register[0], register[1], register[2]); + CCNOT(register[2], register[1], register[0]); + CCNOT(register[3], register[4], register[5]); + CCNOT(register[2], register[4], register[0]); + CCNOT(register[5], register[3], register[1]); } operation PermuteQubitsTest() : Unit { - // - using (register = Qubit[]) { - // - - // maybe verify this using the Subarray function? - } + let sampleOrder = [5, 3, 2, 0, 1, 4]; + AssertOperationsEqualReferenced(6, PermuteQubits(sampleOrder, _) , _SamplePermuteQubits); } + + // Helper method for PermuteQubitsTest + operation _SamplePermuteQubits(register : Qubit[]) : Unit is Adj + Ctl { + // assumes the order to be swapped is [(0, 5),(0, 4),(0, 1),(0, 3)] + // (Order is [5, 3, 2, 0, 1, 4]) + SWAP(register[0], register[5]); + SWAP(register[0], register[4]); + SWAP(register[0], register[1]); + SWAP(register[0], register[3]); + } } \ No newline at end of file diff --git a/Standard/tests/ArrayTests.qs b/Standard/tests/ArrayTests.qs index 9ce3d6d9c16..e1523645870 100644 --- a/Standard/tests/ArrayTests.qs +++ b/Standard/tests/ArrayTests.qs @@ -153,6 +153,33 @@ namespace Microsoft.Quantum.Tests { } } + function SwappedTest() : Unit { + let example = [2, 4, 6, 8, 10]; + let expected = [2, 8, 6, 4, 10]; + let leftIndex = 1; + let rightIndex = 3; + let newArray = Swapped(leftIndex, rightIndex, example); + + EqualityFactI(Length(expected), Length(actual)); + for ((exp, act) in Zip(expected, actual)) { + EqualityFactI(exp, act, "Elements did not match"); + } + } + + function TupleListToNestedArray() : Unit { + let example = [(0, 1), (2, 3), (4, 5), (6, 7)]; + let expected = [[0, 1], [2, 3], [4, 5], [6, 7]]; + + let actual = TupleListToNestedArray(example); + EqualityFactI(Length(expected), Length(actual)); + for ((exp, act) in Zip(expected, actual)) { + for ((elementExp, elementAct) in Zip(exp, act)) { + EqualityFactI(elementExp, elementAct, "Elements did not match"); + } + } + + } + } diff --git a/Standard/tests/ClaimTests.qs b/Standard/tests/ClaimTests.qs new file mode 100644 index 00000000000..858ba4fd0d9 --- /dev/null +++ b/Standard/tests/ClaimTests.qs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Tests { + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Diagnostics; + + + operation ClaimEqualIntTest() : Unit { + let int1 = 10; + let int2 = 24; + + EqualityFactB(ClaimEqualInt(int1, int1), true, "ClaimEqualInt says two ints are different when they are the same"); + EqualityFactB(ClaimEqualInt(int1, int2), false, "ClaimEqualInt says two ints are the same when they are different"); + } + +} From 09f543518999db4eaa0d119b2bedfd6e471e15ab Mon Sep 17 00:00:00 2001 From: Christopher Kang Date: Fri, 30 Aug 2019 09:23:56 -0700 Subject: [PATCH 07/20] Fixed test errors --- Standard/tests/ApplyRepeatedOverTests.qs | 2 +- Standard/tests/ArrayTests.qs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Standard/tests/ApplyRepeatedOverTests.qs b/Standard/tests/ApplyRepeatedOverTests.qs index 0e1da1f08dc..ff72f39ce93 100644 --- a/Standard/tests/ApplyRepeatedOverTests.qs +++ b/Standard/tests/ApplyRepeatedOverTests.qs @@ -31,7 +31,7 @@ namespace Microsoft.Quantum.Tests { X(register[0]); CNOT(register[0], register[4]); Exp([PauliX, PauliZ, PauliY], 0.2002, Subarray([2, 3, 5], register)); - ApplyToEachA(H, Subarray([1, 2, 3, 4], register)); + ApplyToEachCA(H, Subarray([1, 2, 3, 4], register)); } operation ApplyRepeatedOpTest() : Unit { diff --git a/Standard/tests/ArrayTests.qs b/Standard/tests/ArrayTests.qs index e1523645870..8e18c67d492 100644 --- a/Standard/tests/ArrayTests.qs +++ b/Standard/tests/ArrayTests.qs @@ -160,18 +160,18 @@ namespace Microsoft.Quantum.Tests { let rightIndex = 3; let newArray = Swapped(leftIndex, rightIndex, example); - EqualityFactI(Length(expected), Length(actual)); - for ((exp, act) in Zip(expected, actual)) { + EqualityFactI(Length(expected), Length(newArray), "Swapped array is a different size than original"); + for ((exp, act) in Zip(expected, newArray)) { EqualityFactI(exp, act, "Elements did not match"); } } - function TupleListToNestedArray() : Unit { + function TupleListToNestedArrayTest() : Unit { let example = [(0, 1), (2, 3), (4, 5), (6, 7)]; let expected = [[0, 1], [2, 3], [4, 5], [6, 7]]; let actual = TupleListToNestedArray(example); - EqualityFactI(Length(expected), Length(actual)); + EqualityFactI(Length(expected), Length(actual), "Arrays are of different sizes"); for ((exp, act) in Zip(expected, actual)) { for ((elementExp, elementAct) in Zip(exp, act)) { EqualityFactI(elementExp, elementAct, "Elements did not match"); From 72c76bfa58fe9adb7b840a527bac36ff36520272 Mon Sep 17 00:00:00 2001 From: Christopher Kang Date: Sun, 1 Sep 2019 17:55:46 -0700 Subject: [PATCH 08/20] Updated code from comments; moved PermuteQubits to CommonGates --- Standard/src/Arrays/Arrays.qs | 31 +++++++++---------- .../Canon/Combinators/ApplyRepeatedOver.qs | 25 --------------- Standard/src/Canon/CommonGates.qs | 16 ++++++++++ Standard/src/Diagnostics/Claims.qs | 9 ++++++ Standard/src/Standard.csproj | 2 +- 5 files changed, 41 insertions(+), 42 deletions(-) diff --git a/Standard/src/Arrays/Arrays.qs b/Standard/src/Arrays/Arrays.qs index 28a76e48fef..57ffcf433d1 100644 --- a/Standard/src/Arrays/Arrays.qs +++ b/Standard/src/Arrays/Arrays.qs @@ -2,7 +2,9 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Arrays { + open Microsoft.Quantum.Convert; open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Math; /// # Summary @@ -280,6 +282,15 @@ namespace Microsoft.Quantum.Arrays { return output; } + function _IsPermutationPred(permutation : Int[], value : Int) : Bool { + let index = IndexOf(ClaimEqualInt(value, _), permutation); + return index != -1; + } + + function _IsPermutation(permuation : Int[]) : Bool { + return All(_IsPermutationPred(permuation, _), RangeAsIntArray(IndexRange(permuation))); + } + /// # Summary /// Returns the order elements in an array need to be swapped to produce an ordered array. /// Assumes swaps occur in place. @@ -309,36 +320,24 @@ namespace Microsoft.Quantum.Arrays { /// } function SwapOrderToPermuteArray(newOrder : Int[]) : (Int, Int)[] { // Check to verify the new ordering actually is a permutation of the indices - for (index in 0..Length(newOrder) - 1) { - if (IndexOf(ClaimEqualInt(index, _), newOrder) == -1) { - fail "The new ordering is not a permuation of the arrays indices"; - } - } + Fact(_IsPermutation(newOrder), $"The new ordering is not a permutation"); // The maximum number of swaps is n - 1 - let maxSwaps = Length(newOrder) - 1; - mutable leftSwap = new Int[maxSwaps]; - mutable rightSwap = new Int[maxSwaps]; + mutable swaps = new (Int, Int)[Length(newOrder) - 1]; mutable order = newOrder; mutable swapIndex = 0; for (index in 0..Length(order) - 1) { while (not ClaimEqualInt(order[index], index)) { - set leftSwap w/= swapIndex <- index; - set rightSwap w/= swapIndex <- order[index]; + set swaps w/= swapIndex <- (index, order[index]); set order = Swapped(order[index], index, order); set swapIndex = swapIndex + 1; } } // Remove (0, 0) swaps at the end - while ((leftSwap[Length(leftSwap) - 1] == 0) and (rightSwap[Length(rightSwap) - 1] == 0)) { - set leftSwap = Most(leftSwap); - set rightSwap = Most(rightSwap); - } - - return Zip(leftSwap, rightSwap); + return Filtered(ClaimDifferentInt, swaps); } /// # Summary diff --git a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs index af8fed73807..a64074b0f63 100644 --- a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs +++ b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs @@ -233,29 +233,4 @@ namespace Microsoft.Quantum.Canon { } } - // operation PermuteQubits(targets : Int[][], register : Qubit[]) : Unit { - // ApplyOpRepeatedlyOver(ApplyToFirstTwoQubits(SWAP, _), targets, register); - // } - - /// # Summary - /// Permutes qubits by using the SWAP operator. - /// - /// # Input - /// ## ordering - /// Describes the new ordering of the qubits, where the qubit at index i will now be at ordering[i]. - /// ## register - /// Qubit register to be acted upon. - operation PermuteQubits(ordering : Int[], register : Qubit[]) : Unit is Adj+Ctl { - // Do something! - if (Length(ordering) != Length(register)) { - fail "The new ordering array has an incorrect number of elements"; - } - - let swapOrder = SwapOrderToPermuteArray(ordering); - let swapTargets = TupleListToNestedArray(swapOrder); - - let SwapOp = ApplyToFirstTwoQubitsCA(SWAP, _); - ApplyOpRepeatedlyOverCA(SwapOp, swapTargets, register); - } - } \ No newline at end of file diff --git a/Standard/src/Canon/CommonGates.qs b/Standard/src/Canon/CommonGates.qs index e3f74f10a2c..1f82ea4ec86 100644 --- a/Standard/src/Canon/CommonGates.qs +++ b/Standard/src/Canon/CommonGates.qs @@ -272,4 +272,20 @@ namespace Microsoft.Quantum.Canon { CZ(qubit1, qubit2); } + /// # Summary + /// Permutes qubits by using the SWAP operator. + /// + /// # Input + /// ## ordering + /// Describes the new ordering of the qubits, where the qubit at index i will now be at ordering[i]. + /// ## register + /// Qubit register to be acted upon. + operation PermuteQubits(ordering : Int[], register : Qubit[]) : Unit is Adj+Ctl { + EqualityFactI(Length(ordering), Length(register), "The new ordering has an incorrect number of elements"); + + for ((left, right) in SwapOrderToPermuteArray(ordering)) { + SWAP(register[left], register[right]); + } + } + } diff --git a/Standard/src/Diagnostics/Claims.qs b/Standard/src/Diagnostics/Claims.qs index ecc1eefa9fb..869dd04bede 100644 --- a/Standard/src/Diagnostics/Claims.qs +++ b/Standard/src/Diagnostics/Claims.qs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +// !! PLACEHOLDER METHODS !! +// Waiting until Microsoft.Quantum.Logical is PR'd namespace Microsoft.Quantum.Diagnostics { open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Canon; @@ -24,4 +26,11 @@ namespace Microsoft.Quantum.Diagnostics { return false; } + function ClaimDifferentInt(first : Int, second : Int) : Bool { + if (first != second) { + return true; + } + return false; + } + } diff --git a/Standard/src/Standard.csproj b/Standard/src/Standard.csproj index b874e7d6fec..6331a9bd3e8 100644 --- a/Standard/src/Standard.csproj +++ b/Standard/src/Standard.csproj @@ -7,7 +7,7 @@ 0162 - True + False Microsoft Microsoft's Quantum standard libraries. © Microsoft Corporation. All rights reserved. From 9afaa7144cb47e04bc6b1d5d88af5d0167ea2957 Mon Sep 17 00:00:00 2001 From: Christopher Kang Date: Tue, 3 Sep 2019 09:00:34 -0700 Subject: [PATCH 09/20] Fixed minor bugs --- Standard/src/Canon/CommonGates.qs | 2 ++ Standard/tests/ApplyRepeatedOverTests.qs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Standard/src/Canon/CommonGates.qs b/Standard/src/Canon/CommonGates.qs index 1f82ea4ec86..eb3ef89cce6 100644 --- a/Standard/src/Canon/CommonGates.qs +++ b/Standard/src/Canon/CommonGates.qs @@ -4,6 +4,8 @@ namespace Microsoft.Quantum.Canon { open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Arithmetic; + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Arrays; /// # Summary /// Applies the controlled-X (CX) gate to a pair of qubits. diff --git a/Standard/tests/ApplyRepeatedOverTests.qs b/Standard/tests/ApplyRepeatedOverTests.qs index ff72f39ce93..59c0f043e89 100644 --- a/Standard/tests/ApplyRepeatedOverTests.qs +++ b/Standard/tests/ApplyRepeatedOverTests.qs @@ -62,6 +62,6 @@ namespace Microsoft.Quantum.Tests { SWAP(register[0], register[4]); SWAP(register[0], register[1]); SWAP(register[0], register[3]); - } + } } \ No newline at end of file From f305f58fa4698345d8159d9cf51d709660bbfe2c Mon Sep 17 00:00:00 2001 From: Christopher Kang <42285636+christopherkang@users.noreply.github.com> Date: Tue, 3 Sep 2019 10:15:29 -0700 Subject: [PATCH 10/20] Apply suggestions from code review Co-Authored-By: Chris Granade --- Standard/src/Arrays/Arrays.qs | 4 +++- Standard/src/Canon/Combinators/ApplyRepeatedOver.qs | 8 ++++---- Standard/src/Canon/CommonGates.qs | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Standard/src/Arrays/Arrays.qs b/Standard/src/Arrays/Arrays.qs index 57ffcf433d1..a924126dd77 100644 --- a/Standard/src/Arrays/Arrays.qs +++ b/Standard/src/Arrays/Arrays.qs @@ -357,7 +357,9 @@ namespace Microsoft.Quantum.Arrays { /// The array with the in place swapp applied. function Swapped<'T>(firstIndex: Int, secondIndex: Int, arr: 'T[]) : 'T[] { mutable newArray = arr; - let firstIndexVal = arr[firstIndex]; + return arr + w/ firstIndex <- arr[secondIndex] + w/ secondIndex <- arr[firstIndex]; set newArray w/= firstIndex <- newArray[secondIndex]; set newArray w/= secondIndex <- firstIndexVal; return newArray; diff --git a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs index a64074b0f63..416263593a6 100644 --- a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs +++ b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs @@ -7,7 +7,7 @@ namespace Microsoft.Quantum.Canon { open Microsoft.Quantum.Intrinsic; /////////////////////////////////////////////////////////////////////////////////////////////// - // Helpers to repeatedly apply functions over qubit arrays + // Helpers to repeatedly apply operations over qubit arrays /////////////////////////////////////////////////////////////////////////////////////////////// /// # Summary @@ -24,11 +24,11 @@ namespace Microsoft.Quantum.Canon { /// /// # See Also /// - Microsoft.Quantum.Canon.ApplyOpRepeatedlyOver - operation ApplySeriesOfOps(listOfOps : (Qubit[] => Unit)[], targets : Int[][], register : Qubit[]) : Unit { + operation ApplySeriesOfOps<'T>(listOfOps : ('T[] => Unit)[], targets : Int[][], register : 'T[]) : Unit { if (Length(listOfOps) != Length(targets)) { fail "The number of ops and number of targets do not match!"; } - for (index in 0..Length(listOfOps) - 1) { + for ((op, targetIndices) in Zip(listOfOps, targets)) { if (Length(targets[index]) > Length(register)) { fail "There are too many targets!"; } @@ -233,4 +233,4 @@ namespace Microsoft.Quantum.Canon { } } -} \ No newline at end of file +} diff --git a/Standard/src/Canon/CommonGates.qs b/Standard/src/Canon/CommonGates.qs index eb3ef89cce6..5c09ad55b96 100644 --- a/Standard/src/Canon/CommonGates.qs +++ b/Standard/src/Canon/CommonGates.qs @@ -275,7 +275,7 @@ namespace Microsoft.Quantum.Canon { } /// # Summary - /// Permutes qubits by using the SWAP operator. + /// Permutes qubits by using the SWAP operation. /// /// # Input /// ## ordering From 781312d52e3b139c0224ba0424cc7a60856617a9 Mon Sep 17 00:00:00 2001 From: Christopher Kang Date: Tue, 3 Sep 2019 10:29:09 -0700 Subject: [PATCH 11/20] Added some fixes from changes --- Standard/src/Arrays/Arrays.qs | 9 +++------ Standard/src/Canon/Combinators/ApplyRepeatedOver.qs | 6 ++---- Standard/src/Canon/CommonGates.qs | 4 ++++ 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Standard/src/Arrays/Arrays.qs b/Standard/src/Arrays/Arrays.qs index a924126dd77..5b7cc74c74d 100644 --- a/Standard/src/Arrays/Arrays.qs +++ b/Standard/src/Arrays/Arrays.qs @@ -297,8 +297,8 @@ namespace Microsoft.Quantum.Arrays { /// /// # Input /// ## newOrder - /// Array with the permutation of the indices of the new array. There should be n elements, - /// each being a unique integer from 0 to n-1. + /// Array with the permutation of the indices of the new array. There should be $n$ elements, + /// each being a unique integer from $0$ to $n-1$. /// /// # Output /// The tuple represents the two indices to be swapped. The swaps begin at the lowest index. @@ -341,7 +341,7 @@ namespace Microsoft.Quantum.Arrays { } /// # Summary - /// Applies an in-place swap of two elements in an array. + /// Applies a swap of two elements in an array. /// /// # Input /// ## firstIndex @@ -360,9 +360,6 @@ namespace Microsoft.Quantum.Arrays { return arr w/ firstIndex <- arr[secondIndex] w/ secondIndex <- arr[firstIndex]; - set newArray w/= firstIndex <- newArray[secondIndex]; - set newArray w/= secondIndex <- firstIndexVal; - return newArray; } /// # Summary diff --git a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs index 416263593a6..162db4ce6f7 100644 --- a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs +++ b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs @@ -29,12 +29,10 @@ namespace Microsoft.Quantum.Canon { fail "The number of ops and number of targets do not match!"; } for ((op, targetIndices) in Zip(listOfOps, targets)) { - if (Length(targets[index]) > Length(register)) { + if (Length(targetIndices) > Length(register)) { fail "There are too many targets!"; } - let opToApply = listOfOps[index]; - let qubitTargets = Subarray(targets[index], register); - opToApply(qubitTargets); + op(Subarray(targetIndices, register)); } } diff --git a/Standard/src/Canon/CommonGates.qs b/Standard/src/Canon/CommonGates.qs index 5c09ad55b96..5f4aa28810e 100644 --- a/Standard/src/Canon/CommonGates.qs +++ b/Standard/src/Canon/CommonGates.qs @@ -282,6 +282,10 @@ namespace Microsoft.Quantum.Canon { /// Describes the new ordering of the qubits, where the qubit at index i will now be at ordering[i]. /// ## register /// Qubit register to be acted upon. + /// + /// # Example + /// Given ordering = [2, 1, 0] and register $\ket{\alpha_0} \ket{\alpha_1} \ket{\alpha_2}$, PermuteQubits + /// changes the register into $\ket{\alpha_2} \ket{\alpha_1} \ket{\alpha_0}$ operation PermuteQubits(ordering : Int[], register : Qubit[]) : Unit is Adj+Ctl { EqualityFactI(Length(ordering), Length(register), "The new ordering has an incorrect number of elements"); From 0172ccba6cafdcde53c26aa9a02b78612a3b3ce7 Mon Sep 17 00:00:00 2001 From: Christopher Kang Date: Tue, 3 Sep 2019 16:03:15 -0700 Subject: [PATCH 12/20] Added most recommendations from Mathias --- Standard/src/Arrays/Arrays.qs | 17 +++++++---- Standard/src/Diagnostics/Claims.qs | 36 ------------------------ Standard/tests/ApplyRepeatedOverTests.qs | 2 +- Standard/tests/ClaimTests.qs | 18 ------------ 4 files changed, 13 insertions(+), 60 deletions(-) delete mode 100644 Standard/src/Diagnostics/Claims.qs delete mode 100644 Standard/tests/ClaimTests.qs diff --git a/Standard/src/Arrays/Arrays.qs b/Standard/src/Arrays/Arrays.qs index 5b7cc74c74d..316c22d79cb 100644 --- a/Standard/src/Arrays/Arrays.qs +++ b/Standard/src/Arrays/Arrays.qs @@ -6,6 +6,7 @@ namespace Microsoft.Quantum.Arrays { open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Math; + open Microsoft.Quantum.Logical; /// # Summary /// Create an array that contains the same elements as an input array but in Reversed @@ -283,7 +284,7 @@ namespace Microsoft.Quantum.Arrays { } function _IsPermutationPred(permutation : Int[], value : Int) : Bool { - let index = IndexOf(ClaimEqualInt(value, _), permutation); + let index = IndexOf(EqualI(value, _), permutation); return index != -1; } @@ -328,7 +329,7 @@ namespace Microsoft.Quantum.Arrays { mutable swapIndex = 0; for (index in 0..Length(order) - 1) { - while (not ClaimEqualInt(order[index], index)) + while (not EqualI(order[index], index)) { set swaps w/= swapIndex <- (index, order[index]); set order = Swapped(order[index], index, order); @@ -337,7 +338,7 @@ namespace Microsoft.Quantum.Arrays { } // Remove (0, 0) swaps at the end - return Filtered(ClaimDifferentInt, swaps); + return Filtered(NotEqualI, swaps); } /// # Summary @@ -355,6 +356,10 @@ namespace Microsoft.Quantum.Arrays { /// /// # Output /// The array with the in place swapp applied. + /// + /// # Example + /// Given an array [0, 1, 2, 3, 4], and two indices 1, 3 + /// Returns [0, 3, 2, 1, 4] function Swapped<'T>(firstIndex: Int, secondIndex: Int, arr: 'T[]) : 'T[] { mutable newArray = arr; return arr @@ -371,6 +376,10 @@ namespace Microsoft.Quantum.Arrays { /// /// # Output /// A nested array with length matching the tupleList. + /// + /// # Example + /// Given [(2, 3), (4, 5)], TupleListToNestedArray will output + /// [[2, 3], [4, 5]] function TupleListToNestedArray<'T>(tupleList : ('T, 'T)[]) : 'T[][] { mutable newArray = new 'T[][Length(tupleList)]; for (idx in IndexRange(tupleList)) { @@ -381,5 +390,3 @@ namespace Microsoft.Quantum.Arrays { } } - - diff --git a/Standard/src/Diagnostics/Claims.qs b/Standard/src/Diagnostics/Claims.qs deleted file mode 100644 index 869dd04bede..00000000000 --- a/Standard/src/Diagnostics/Claims.qs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// !! PLACEHOLDER METHODS !! -// Waiting until Microsoft.Quantum.Logical is PR'd -namespace Microsoft.Quantum.Diagnostics { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Canon; - - /// # Summary - /// Checks whether two ints are equal - /// - /// # Input - /// ## first - /// First int to check - /// - /// ## second - /// Second int to check - /// - /// # Output - /// True if the ints are equal, False if the ints differ. - function ClaimEqualInt(first : Int, second : Int) : Bool { - if (first == second) { - return true; - } - return false; - } - - function ClaimDifferentInt(first : Int, second : Int) : Bool { - if (first != second) { - return true; - } - return false; - } - -} diff --git a/Standard/tests/ApplyRepeatedOverTests.qs b/Standard/tests/ApplyRepeatedOverTests.qs index 59c0f043e89..31cdc1ca0fb 100644 --- a/Standard/tests/ApplyRepeatedOverTests.qs +++ b/Standard/tests/ApplyRepeatedOverTests.qs @@ -64,4 +64,4 @@ namespace Microsoft.Quantum.Tests { SWAP(register[0], register[3]); } -} \ No newline at end of file +} diff --git a/Standard/tests/ClaimTests.qs b/Standard/tests/ClaimTests.qs deleted file mode 100644 index 858ba4fd0d9..00000000000 --- a/Standard/tests/ClaimTests.qs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Tests { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Canon; - open Microsoft.Quantum.Diagnostics; - - - operation ClaimEqualIntTest() : Unit { - let int1 = 10; - let int2 = 24; - - EqualityFactB(ClaimEqualInt(int1, int1), true, "ClaimEqualInt says two ints are different when they are the same"); - EqualityFactB(ClaimEqualInt(int1, int2), false, "ClaimEqualInt says two ints are the same when they are different"); - } - -} From d7673ec0bfcde4f980b96456ac9dbc2ab8cbd960 Mon Sep 17 00:00:00 2001 From: Christopher Kang Date: Tue, 3 Sep 2019 16:25:28 -0700 Subject: [PATCH 13/20] Added example to ApplySeriesOfOps --- Standard/src/Canon/Combinators/ApplyRepeatedOver.qs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs index 162db4ce6f7..3fcaf289fb7 100644 --- a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs +++ b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs @@ -22,6 +22,11 @@ namespace Microsoft.Quantum.Canon { /// ## register /// Qubit register to be acted upon. /// + /// # Example + /// Given a list of ops ([Exp([PauliX, PauliY], 0.5, _), ApplyToFirstQubit(X, _)]) and the indices of their targets + /// in the register ([[0, 1], [2]]), ApplySeriesOfOps will apply Exp([PauliX, PauliY], 0.5) to qubits 0, 1 and then + /// X to qubit 2. + /// /// # See Also /// - Microsoft.Quantum.Canon.ApplyOpRepeatedlyOver operation ApplySeriesOfOps<'T>(listOfOps : ('T[] => Unit)[], targets : Int[][], register : 'T[]) : Unit { From b74e2118bcd9f83e0c7e98d2f8cff543cf4d7ee5 Mon Sep 17 00:00:00 2001 From: Christopher Kang Date: Tue, 3 Sep 2019 16:36:42 -0700 Subject: [PATCH 14/20] Added new examples --- Standard/src/Arrays/Arrays.qs | 15 +++++++++------ .../src/Canon/Combinators/ApplyRepeatedOver.qs | 10 ++++++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Standard/src/Arrays/Arrays.qs b/Standard/src/Arrays/Arrays.qs index 316c22d79cb..f14d03d152d 100644 --- a/Standard/src/Arrays/Arrays.qs +++ b/Standard/src/Arrays/Arrays.qs @@ -357,9 +357,10 @@ namespace Microsoft.Quantum.Arrays { /// # Output /// The array with the in place swapp applied. /// - /// # Example - /// Given an array [0, 1, 2, 3, 4], and two indices 1, 3 - /// Returns [0, 3, 2, 1, 4] + /// ## Example + /// ```qsharp + /// // The following returns [0, 3, 2, 1, 4] + /// Swapped(1, 3, [0, 1, 2, 3, 4]); function Swapped<'T>(firstIndex: Int, secondIndex: Int, arr: 'T[]) : 'T[] { mutable newArray = arr; return arr @@ -377,9 +378,11 @@ namespace Microsoft.Quantum.Arrays { /// # Output /// A nested array with length matching the tupleList. /// - /// # Example - /// Given [(2, 3), (4, 5)], TupleListToNestedArray will output - /// [[2, 3], [4, 5]] + /// ## Example + /// ```qsharp + /// // The following returns [[2, 3], [4, 5]] + /// TupleListToNestedArray([(2, 3), (4, 5)]); + /// ``` function TupleListToNestedArray<'T>(tupleList : ('T, 'T)[]) : 'T[][] { mutable newArray = new 'T[][Length(tupleList)]; for (idx in IndexRange(tupleList)) { diff --git a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs index 3fcaf289fb7..2af40ed0641 100644 --- a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs +++ b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs @@ -22,10 +22,12 @@ namespace Microsoft.Quantum.Canon { /// ## register /// Qubit register to be acted upon. /// - /// # Example - /// Given a list of ops ([Exp([PauliX, PauliY], 0.5, _), ApplyToFirstQubit(X, _)]) and the indices of their targets - /// in the register ([[0, 1], [2]]), ApplySeriesOfOps will apply Exp([PauliX, PauliY], 0.5) to qubits 0, 1 and then - /// X to qubit 2. + /// ## Example + /// // The following applies Exp([PauliX, PauliY], 0.5) to qubits 0, 1 + /// // then X to qubit 2 + /// let ops = [Exp([PauliX, PauliY], 0.5, _), ApplyToFirstQubit(X, _)]; + /// let indices = [[0, 1], [2]]; + /// ApplySeriesOfOps(ops, indices, qubitArray); /// /// # See Also /// - Microsoft.Quantum.Canon.ApplyOpRepeatedlyOver From 58236ba0e4c2dc0016f4f23912da520b637016e8 Mon Sep 17 00:00:00 2001 From: Christopher Kang Date: Wed, 4 Sep 2019 08:28:17 -0700 Subject: [PATCH 15/20] Added PermuteQubits example --- Standard/src/Canon/CommonGates.qs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Standard/src/Canon/CommonGates.qs b/Standard/src/Canon/CommonGates.qs index 5f4aa28810e..0c5656d4080 100644 --- a/Standard/src/Canon/CommonGates.qs +++ b/Standard/src/Canon/CommonGates.qs @@ -286,6 +286,12 @@ namespace Microsoft.Quantum.Canon { /// # Example /// Given ordering = [2, 1, 0] and register $\ket{\alpha_0} \ket{\alpha_1} \ket{\alpha_2}$, PermuteQubits /// changes the register into $\ket{\alpha_2} \ket{\alpha_1} \ket{\alpha_0}$ + /// + /// ```qsharp + /// // The following two lines are equivalent + /// PermuteQubits([2, 1, 0], register); + /// SWAP(register[0], register[2]); + /// ``` operation PermuteQubits(ordering : Int[], register : Qubit[]) : Unit is Adj+Ctl { EqualityFactI(Length(ordering), Length(register), "The new ordering has an incorrect number of elements"); From 68e0da46081a35d2b9a9c79e8bfe34b301f2d071 Mon Sep 17 00:00:00 2001 From: Christopher Kang Date: Wed, 4 Sep 2019 08:53:11 -0700 Subject: [PATCH 16/20] Changed Swap Order to be appending to an array, added test for it --- Standard/src/Arrays/Arrays.qs | 7 +++---- Standard/tests/ArrayTests.qs | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Standard/src/Arrays/Arrays.qs b/Standard/src/Arrays/Arrays.qs index f14d03d152d..3a8cb827cfc 100644 --- a/Standard/src/Arrays/Arrays.qs +++ b/Standard/src/Arrays/Arrays.qs @@ -324,21 +324,20 @@ namespace Microsoft.Quantum.Arrays { Fact(_IsPermutation(newOrder), $"The new ordering is not a permutation"); // The maximum number of swaps is n - 1 - mutable swaps = new (Int, Int)[Length(newOrder) - 1]; + mutable swaps = new (Int, Int)[0]; mutable order = newOrder; mutable swapIndex = 0; for (index in 0..Length(order) - 1) { while (not EqualI(order[index], index)) { - set swaps w/= swapIndex <- (index, order[index]); + set swaps += [(index, order[index])]; set order = Swapped(order[index], index, order); - set swapIndex = swapIndex + 1; } } // Remove (0, 0) swaps at the end - return Filtered(NotEqualI, swaps); + return swaps; } /// # Summary diff --git a/Standard/tests/ArrayTests.qs b/Standard/tests/ArrayTests.qs index 26fb5eb3072..84c44a7bb55 100644 --- a/Standard/tests/ArrayTests.qs +++ b/Standard/tests/ArrayTests.qs @@ -153,6 +153,21 @@ namespace Microsoft.Quantum.Tests { } } + function SwapOrderToPermuteArrayTest() : Unit { + let newOrder = [0, 4, 2, 1, 3]; + let expected = [(1, 4), (1, 3)]; + let actual = SwapOrderToPermuteArray(newOrder); + + EqualityFactI(Length(expected), Length(actual), "Number of swaps does not match"); + for ((exp, act) in Zip(expected, actual)) { + let (leftExp, rightExp) = exp; + let (leftAct, rightAct) = act; + + EqualityFactI(leftExp, leftAct, "SWAP doesn't match"); + EqualityFactI(rightExp, rightAct, "SWAP doesn't match"); + } + } + function SwappedTest() : Unit { let example = [2, 4, 6, 8, 10]; let expected = [2, 8, 6, 4, 10]; From 53ac666bf3ef73f6449e7940497ab50f6876e8ae Mon Sep 17 00:00:00 2001 From: Christopher Kang Date: Wed, 4 Sep 2019 12:32:59 -0700 Subject: [PATCH 17/20] Updated ApplyOpRepeatedlyOver Docs --- Standard/src/Arrays/Arrays.qs | 4 +- .../Canon/Combinators/ApplyRepeatedOver.qs | 81 +++++++++++-------- 2 files changed, 49 insertions(+), 36 deletions(-) diff --git a/Standard/src/Arrays/Arrays.qs b/Standard/src/Arrays/Arrays.qs index 3a8cb827cfc..db1d9f6decf 100644 --- a/Standard/src/Arrays/Arrays.qs +++ b/Standard/src/Arrays/Arrays.qs @@ -323,11 +323,10 @@ namespace Microsoft.Quantum.Arrays { // Check to verify the new ordering actually is a permutation of the indices Fact(_IsPermutation(newOrder), $"The new ordering is not a permutation"); - // The maximum number of swaps is n - 1 mutable swaps = new (Int, Int)[0]; mutable order = newOrder; - mutable swapIndex = 0; + // for each value, whenever the index and value don't match, swap until it does for (index in 0..Length(order) - 1) { while (not EqualI(order[index], index)) { @@ -336,7 +335,6 @@ namespace Microsoft.Quantum.Arrays { } } - // Remove (0, 0) swaps at the end return swaps; } diff --git a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs index 2af40ed0641..5aaf10c2d2b 100644 --- a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs +++ b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs @@ -11,14 +11,14 @@ namespace Microsoft.Quantum.Canon { /////////////////////////////////////////////////////////////////////////////////////////////// /// # Summary - /// Applies a list of ops and their targets sequentially on a qubit array. + /// Applies a list of ops and their targets sequentially on an array. /// /// # Input /// ## listOfOps - /// List of ops, each taking a qubit array, to be applied. They are applied sequentially, lowest index first. + /// List of ops, each taking a 'T array, to be applied. They are applied sequentially, lowest index first. /// ## targets /// Nested arrays describing the targets of the op. Each array should contain a list of ints describing - /// the qubits to be used. + /// the indices to be used. /// ## register /// Qubit register to be acted upon. /// @@ -44,89 +44,104 @@ namespace Microsoft.Quantum.Canon { } /// # Summary - /// Applies a list of ops and their targets sequentially on a qubit array. (Adjoint) + /// Applies a list of ops and their targets sequentially on an array. (Adjoint) /// /// # Input /// ## listOfOps - /// List of ops, each taking a qubit array, to be applied. They are applied sequentially, lowest index first. - /// Each must have a Adjoint functor. + /// List of ops, each taking a 'T array, to be applied. They are applied sequentially, lowest index first. + /// Each must have an adjoint functor /// ## targets /// Nested arrays describing the targets of the op. Each array should contain a list of ints describing - /// the qubits to be used. + /// the indices to be used. /// ## register /// Qubit register to be acted upon. /// + /// ## Example + /// // The following applies Exp([PauliX, PauliY], 0.5) to qubits 0, 1 + /// // then X to qubit 2 + /// let ops = [Exp([PauliX, PauliY], 0.5, _), ApplyToFirstQubitA(X, _)]; + /// let indices = [[0, 1], [2]]; + /// ApplySeriesOfOpsA(ops, indices, qubitArray); + /// /// # See Also /// - Microsoft.Quantum.Canon.ApplyOpRepeatedlyOver - operation ApplySeriesOfOpsA(listOfOps : (Qubit[] => Unit is Adj)[], targets : Int[][], register : Qubit[]) : Unit is Adj{ + operation ApplySeriesOfOpsA<'T>(listOfOps : ('T[] => Unit is Adj)[], targets : Int[][], register : 'T[]) : Unit is Adj{ if (Length(listOfOps) != Length(targets)) { fail "The number of ops and number of targets do not match!"; } - for (index in 0..Length(listOfOps) - 1) { - if (Length(targets[index]) > Length(register)) { + for ((op, targetIndices) in Zip(listOfOps, targets)) { + if (Length(targetIndices) > Length(register)) { fail "There are too many targets!"; } - let opToApply = listOfOps[index]; - let qubitTargets = Subarray(targets[index], register); - opToApply(qubitTargets); + op(Subarray(targetIndices, register)); } } /// # Summary - /// Applies a list of ops and their targets sequentially on a qubit array. (Controlled) + /// Applies a list of ops and their targets sequentially on an array. (Controlled) /// /// # Input /// ## listOfOps - /// List of ops, each taking a qubit array, to be applied. They are applied sequentially, lowest index first. - /// Each must have a Controlled functor. + /// List of ops, each taking a 'T array, to be applied. They are applied sequentially, lowest index first. + /// Each must have a Controlled functor /// ## targets /// Nested arrays describing the targets of the op. Each array should contain a list of ints describing - /// the qubits to be used. + /// the indices to be used. /// ## register /// Qubit register to be acted upon. /// + /// ## Example + /// // The following applies Exp([PauliX, PauliY], 0.5) to qubits 0, 1 + /// // then X to qubit 2 + /// let ops = [Exp([PauliX, PauliY], 0.5, _), ApplyToFirstQubitC(X, _)]; + /// let indices = [[0, 1], [2]]; + /// ApplySeriesOfOpsC(ops, indices, qubitArray); + /// /// # See Also /// - Microsoft.Quantum.Canon.ApplyOpRepeatedlyOver - operation ApplySeriesOfOpsC(listOfOps : (Qubit[] => Unit is Ctl)[], targets : Int[][], register : Qubit[]) : Unit is Ctl { + operation ApplySeriesOfOpsC<'T>(listOfOps : ('T[] => Unit is Ctl)[], targets : Int[][], register : 'T[]) : Unit is Ctl{ if (Length(listOfOps) != Length(targets)) { fail "The number of ops and number of targets do not match!"; } - for (index in 0..Length(listOfOps) - 1) { - if (Length(targets[index]) > Length(register)) { + for ((op, targetIndices) in Zip(listOfOps, targets)) { + if (Length(targetIndices) > Length(register)) { fail "There are too many targets!"; } - let opToApply = listOfOps[index]; - let qubitTargets = Subarray(targets[index], register); - opToApply(qubitTargets); + op(Subarray(targetIndices, register)); } } /// # Summary - /// Applies a list of ops and their targets sequentially on a qubit array. (Adjoint + Controlled) + /// Applies a list of ops and their targets sequentially on an array. (Adjoint + Controlled) /// /// # Input /// ## listOfOps - /// List of ops, each taking a qubit array, to be applied. They are applied sequentially, lowest index first. - /// Each must have both a Adjoint and Controlled functor. + /// List of ops, each taking a 'T array, to be applied. They are applied sequentially, lowest index first. + /// Each must have both an Adjoint and Controlled functor. /// ## targets /// Nested arrays describing the targets of the op. Each array should contain a list of ints describing - /// the qubits to be used. + /// the indices to be used. /// ## register /// Qubit register to be acted upon. /// + /// ## Example + /// // The following applies Exp([PauliX, PauliY], 0.5) to qubits 0, 1 + /// // then X to qubit 2 + /// let ops = [Exp([PauliX, PauliY], 0.5, _), ApplyToFirstQubitCA(X, _)]; + /// let indices = [[0, 1], [2]]; + /// ApplySeriesOfOpsCA(ops, indices, qubitArray); + /// /// # See Also /// - Microsoft.Quantum.Canon.ApplyOpRepeatedlyOver - operation ApplySeriesOfOpsCA(listOfOps : (Qubit[] => Unit is Adj + Ctl)[], targets : Int[][], register : Qubit[]) : Unit is Adj + Ctl { + operation ApplySeriesOfOpsCA<'T>(listOfOps : ('T[] => Unit is Adj + Ctl)[], targets : Int[][], register : 'T[]) : Unit is Adj + Ctl{ if (Length(listOfOps) != Length(targets)) { fail "The number of ops and number of targets do not match!"; } - for (index in 0..Length(listOfOps) - 1) { - if (Length(targets[index]) > Length(register)) { + for ((op, targetIndices) in Zip(listOfOps, targets)) { + if (Length(targetIndices) > Length(register)) { fail "There are too many targets!"; } - let opToApply = listOfOps[index]; - let qubitTargets = Subarray(targets[index], register); - opToApply(qubitTargets); + op(Subarray(targetIndices, register)); } } From cf53aca997c7a8f2657cddfe2a109154a7b703f6 Mon Sep 17 00:00:00 2001 From: Christopher Kang Date: Thu, 5 Sep 2019 08:42:15 -0700 Subject: [PATCH 18/20] Added Mathias' comments --- Standard/src/Arrays/Arrays.qs | 7 +++--- .../Canon/Combinators/ApplyRepeatedOver.qs | 24 +++++++++---------- Standard/src/Canon/CommonGates.qs | 2 +- Standard/tests/ArrayTests.qs | 4 ++-- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/Standard/src/Arrays/Arrays.qs b/Standard/src/Arrays/Arrays.qs index db1d9f6decf..66fee6e5574 100644 --- a/Standard/src/Arrays/Arrays.qs +++ b/Standard/src/Arrays/Arrays.qs @@ -308,7 +308,7 @@ namespace Microsoft.Quantum.Arrays { /// ## Example /// ```qsharp /// // The following returns [(0, 5),(0, 4),(0, 1),(0, 3)]; - /// let swapOrder = SwapOrderToPermuteArray([5, 3, 2, 0, 1, 4]); + /// let swapOrder = _SwapOrderToPermuteArray([5, 3, 2, 0, 1, 4]); /// ``` /// /// ## Psuedocode @@ -319,7 +319,7 @@ namespace Microsoft.Quantum.Arrays { /// Switch newOrder[index] with newOrder[newOrder[index]] /// } /// } - function SwapOrderToPermuteArray(newOrder : Int[]) : (Int, Int)[] { + function _SwapOrderToPermuteArray(newOrder : Int[]) : (Int, Int)[] { // Check to verify the new ordering actually is a permutation of the indices Fact(_IsPermutation(newOrder), $"The new ordering is not a permutation"); @@ -327,7 +327,7 @@ namespace Microsoft.Quantum.Arrays { mutable order = newOrder; // for each value, whenever the index and value don't match, swap until it does - for (index in 0..Length(order) - 1) { + for (index in IndexRange(order)) { while (not EqualI(order[index], index)) { set swaps += [(index, order[index])]; @@ -359,7 +359,6 @@ namespace Microsoft.Quantum.Arrays { /// // The following returns [0, 3, 2, 1, 4] /// Swapped(1, 3, [0, 1, 2, 3, 4]); function Swapped<'T>(firstIndex: Int, secondIndex: Int, arr: 'T[]) : 'T[] { - mutable newArray = arr; return arr w/ firstIndex <- arr[secondIndex] w/ secondIndex <- arr[firstIndex]; diff --git a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs index 5aaf10c2d2b..7db8042d35e 100644 --- a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs +++ b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs @@ -161,13 +161,13 @@ namespace Microsoft.Quantum.Canon { /// - Microsoft.Quantum.Canon.ApplySeriesOfOps operation ApplyOpRepeatedlyOver(op : (Qubit[] => Unit), targets : Int[][], register : Qubit[]) : Unit { - for (index in 0..Length(targets) - 1) + for (target in targets) { - if (Length(targets[index]) > Length(register)) + if (Length(target) > Length(register)) { fail "Too many targets!"; } - let opTargets = Subarray(targets[index], register); + let opTargets = Subarray(target, register); op(opTargets); } } @@ -188,13 +188,13 @@ namespace Microsoft.Quantum.Canon { /// - Microsoft.Quantum.Canon.ApplySeriesOfOps operation ApplyOpRepeatedlyOverA(op : (Qubit[] => Unit is Adj), targets : Int[][], register : Qubit[]) : Unit is Adj { - for (index in 0..Length(targets) - 1) + for (target in targets) { - if (Length(targets[index]) > Length(register)) + if (Length(target) > Length(register)) { fail "Too many targets!"; } - let opTargets = Subarray(targets[index], register); + let opTargets = Subarray(target, register); op(opTargets); } } @@ -215,13 +215,13 @@ namespace Microsoft.Quantum.Canon { /// - Microsoft.Quantum.Canon.ApplySeriesOfOps operation ApplyOpRepeatedlyOverC(op : (Qubit[] => Unit is Ctl), targets : Int[][], register : Qubit[]) : Unit is Ctl { - for (index in 0..Length(targets) - 1) + for (target in targets) { - if (Length(targets[index]) > Length(register)) + if (Length(target) > Length(register)) { fail "Too many targets!"; } - let opTargets = Subarray(targets[index], register); + let opTargets = Subarray(target, register); op(opTargets); } } @@ -242,13 +242,13 @@ namespace Microsoft.Quantum.Canon { /// - Microsoft.Quantum.Canon.ApplySeriesOfOps operation ApplyOpRepeatedlyOverCA(op : (Qubit[] => Unit is Adj+Ctl), targets : Int[][], register : Qubit[]) : Unit is Adj+Ctl { - for (index in 0..Length(targets) - 1) + for (target in targets) { - if (Length(targets[index]) > Length(register)) + if (Length(target) > Length(register)) { fail "Too many targets!"; } - let opTargets = Subarray(targets[index], register); + let opTargets = Subarray(target, register); op(opTargets); } } diff --git a/Standard/src/Canon/CommonGates.qs b/Standard/src/Canon/CommonGates.qs index 0c5656d4080..fafc2dcd31f 100644 --- a/Standard/src/Canon/CommonGates.qs +++ b/Standard/src/Canon/CommonGates.qs @@ -295,7 +295,7 @@ namespace Microsoft.Quantum.Canon { operation PermuteQubits(ordering : Int[], register : Qubit[]) : Unit is Adj+Ctl { EqualityFactI(Length(ordering), Length(register), "The new ordering has an incorrect number of elements"); - for ((left, right) in SwapOrderToPermuteArray(ordering)) { + for ((left, right) in _SwapOrderToPermuteArray(ordering)) { SWAP(register[left], register[right]); } } diff --git a/Standard/tests/ArrayTests.qs b/Standard/tests/ArrayTests.qs index 84c44a7bb55..55847ca7cd8 100644 --- a/Standard/tests/ArrayTests.qs +++ b/Standard/tests/ArrayTests.qs @@ -153,10 +153,10 @@ namespace Microsoft.Quantum.Tests { } } - function SwapOrderToPermuteArrayTest() : Unit { + function _SwapOrderToPermuteArrayTest() : Unit { let newOrder = [0, 4, 2, 1, 3]; let expected = [(1, 4), (1, 3)]; - let actual = SwapOrderToPermuteArray(newOrder); + let actual = _SwapOrderToPermuteArray(newOrder); EqualityFactI(Length(expected), Length(actual), "Number of swaps does not match"); for ((exp, act) in Zip(expected, actual)) { From ec17ec32dce111588e006831c9a2fb71c2047447 Mon Sep 17 00:00:00 2001 From: Christopher Kang Date: Sat, 21 Sep 2019 18:48:15 -0700 Subject: [PATCH 19/20] Reverted csproj file --- Standard/src/Standard.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Standard/src/Standard.csproj b/Standard/src/Standard.csproj index 6331a9bd3e8..b874e7d6fec 100644 --- a/Standard/src/Standard.csproj +++ b/Standard/src/Standard.csproj @@ -7,7 +7,7 @@ 0162 - False + True Microsoft Microsoft's Quantum standard libraries. © Microsoft Corporation. All rights reserved. From 4e75b08cd181402cbc2ff9acd8c167c90a516e82 Mon Sep 17 00:00:00 2001 From: Christopher Kang Date: Sat, 28 Sep 2019 11:04:18 -0700 Subject: [PATCH 20/20] Renamed TupleArrayAsNestedArray --- Standard/src/Arrays/Arrays.qs | 4 ++-- Standard/tests/ArrayTests.qs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Standard/src/Arrays/Arrays.qs b/Standard/src/Arrays/Arrays.qs index 66fee6e5574..740b4f195b4 100644 --- a/Standard/src/Arrays/Arrays.qs +++ b/Standard/src/Arrays/Arrays.qs @@ -377,9 +377,9 @@ namespace Microsoft.Quantum.Arrays { /// ## Example /// ```qsharp /// // The following returns [[2, 3], [4, 5]] - /// TupleListToNestedArray([(2, 3), (4, 5)]); + /// TupleArrayAsNestedArray([(2, 3), (4, 5)]); /// ``` - function TupleListToNestedArray<'T>(tupleList : ('T, 'T)[]) : 'T[][] { + function TupleArrayAsNestedArray<'T>(tupleList : ('T, 'T)[]) : 'T[][] { mutable newArray = new 'T[][Length(tupleList)]; for (idx in IndexRange(tupleList)) { let (tupleLeft, tupleRight) = tupleList[idx]; diff --git a/Standard/tests/ArrayTests.qs b/Standard/tests/ArrayTests.qs index 55847ca7cd8..0d45adec9fc 100644 --- a/Standard/tests/ArrayTests.qs +++ b/Standard/tests/ArrayTests.qs @@ -181,11 +181,11 @@ namespace Microsoft.Quantum.Tests { } } - function TupleListToNestedArrayTest() : Unit { + function TupleArrayAsNestedArrayTest() : Unit { let example = [(0, 1), (2, 3), (4, 5), (6, 7)]; let expected = [[0, 1], [2, 3], [4, 5], [6, 7]]; - let actual = TupleListToNestedArray(example); + let actual = TupleArrayAsNestedArray(example); EqualityFactI(Length(expected), Length(actual), "Arrays are of different sizes"); for ((exp, act) in Zip(expected, actual)) { for ((elementExp, elementAct) in Zip(exp, act)) {