diff --git a/Chemistry/src/Runtime/JordanWigner/JordanWignerClusterOperatorEvolutionSet.qs b/Chemistry/src/Runtime/JordanWigner/JordanWignerClusterOperatorEvolutionSet.qs index 3489b204..660b48b4 100644 --- a/Chemistry/src/Runtime/JordanWigner/JordanWignerClusterOperatorEvolutionSet.qs +++ b/Chemistry/src/Runtime/JordanWigner/JordanWignerClusterOperatorEvolutionSet.qs @@ -10,7 +10,7 @@ namespace Microsoft.Quantum.Chemistry.JordanWigner { open Microsoft.Quantum.Arrays; /// # Summary - /// Computes Z component of Jordan–Wigner string between + /// Computes Z component of Jordan–Wigner string between /// fermion indices in a fermionic operator with an even /// number of creation / annihilation operators. /// @@ -89,7 +89,7 @@ namespace Microsoft.Quantum.Chemistry.JordanWigner { let ops = [[PauliX, PauliY], [PauliY, PauliX]]; let signs = [+1.0, -1.0]; - for ((op, sign) in Zip(ops, signs)) { + for ((op, sign) in Zipped(ops, signs)) { let pauliString = _ComputeJordanWignerPauliString(Length(qubits), idxFermions, op); Exp(pauliString, sign * angle, qubits); } @@ -124,7 +124,7 @@ namespace Microsoft.Quantum.Chemistry.JordanWigner { let ops = [[y,y,x,y],[x,x,x,y],[x,y,y,y],[y,x,y,y],[x,y,x,x],[y,x,x,x],[y,y,y,x],[x,x,y,x]]; let (sortedIndices, signs, globalSign) = _JordanWignerClusterOperatorPQRSTermSigns([p,q,r,s]); - for ((op, sign) in Zip(ops, signs)) { + for ((op, sign) in Zipped(ops, signs)) { let pauliString = _ComputeJordanWignerPauliString(Length(qubits), sortedIndices, op); Exp(pauliString, globalSign * sign * angle, qubits); } @@ -272,4 +272,3 @@ namespace Microsoft.Quantum.Chemistry.JordanWigner { } - diff --git a/Chemistry/src/Runtime/JordanWigner/JordanWignerEvolutionSet.qs b/Chemistry/src/Runtime/JordanWigner/JordanWignerEvolutionSet.qs index 969a7222..d9890ef3 100644 --- a/Chemistry/src/Runtime/JordanWigner/JordanWignerEvolutionSet.qs +++ b/Chemistry/src/Runtime/JordanWigner/JordanWignerEvolutionSet.qs @@ -8,7 +8,7 @@ namespace Microsoft.Quantum.Chemistry.JordanWigner { open Microsoft.Quantum.Chemistry; open Microsoft.Quantum.Arrays; - // This evolution set runs off data optimized for a Jordan–Wigner encoding. + // This evolution set runs off data optimized for a Jordan–Wigner encoding. // This collects terms Z, ZZ, PQandPQQR, hpqrs separately. // This only apples the needed hpqrs XXXX XXYY terms. // Operations here are expressed in terms of Exp([...]) @@ -134,7 +134,7 @@ namespace Microsoft.Quantum.Chemistry.JordanWigner { if (idxFermions[0] < qubitQidx and qubitQidx < idxFermions[3]) { let termPR1 = GeneratorIndex((idxTermType, [1.0]), [idxFermions[0], idxFermions[3] - 1]); - _ApplyJordanWignerPQTerm_(termPR1, angle, new Qubit[0], Exclude([qubitQidx], qubits)); + _ApplyJordanWignerPQTerm_(termPR1, angle, new Qubit[0], Excluding([qubitQidx], qubits)); } else { let termPR1 = GeneratorIndex((idxTermType, [1.0]), [0, idxFermions[3] - idxFermions[0]]); @@ -280,4 +280,3 @@ namespace Microsoft.Quantum.Chemistry.JordanWigner { } - diff --git a/Chemistry/src/Runtime/JordanWigner/JordanWignerVQE.qs b/Chemistry/src/Runtime/JordanWigner/JordanWignerVQE.qs index ba605577..41e68812 100644 --- a/Chemistry/src/Runtime/JordanWigner/JordanWignerVQE.qs +++ b/Chemistry/src/Runtime/JordanWigner/JordanWignerVQE.qs @@ -39,7 +39,7 @@ namespace Microsoft.Quantum.Chemistry.JordanWigner.VQE { mutable jwTermEnergy = 0.; - for ((coeff, op) in Zip(coeffs, ops)) { + for ((coeff, op) in Zipped(coeffs, ops)) { // Only perform computation if the coefficient is significant enough if (AbsD(coeff) >= 1e-10) { // Compute expectation value using the fast frequency estimator, add contribution to Jordan-Wigner term energy @@ -95,7 +95,7 @@ namespace Microsoft.Quantum.Chemistry.JordanWigner.VQE { mutable compactOp = compactOps[iOp]; mutable op = ConstantArray(nQubits, PauliI); - for ((idx, pauli) in Zip(indices, compactOp)) { + for ((idx, pauli) in Zipped(indices, compactOp)) { set op w/= idx <- pauli; } for (i in indices[0]+1..indices[1]-1) { diff --git a/MachineLearning/src/Private.qs b/MachineLearning/src/Private.qs index 33a9ffa9..98d59544 100644 --- a/MachineLearning/src/Private.qs +++ b/MachineLearning/src/Private.qs @@ -6,7 +6,7 @@ namespace Microsoft.Quantum.MachineLearning { open Microsoft.Quantum.Math; function _AllNearlyEqualD(v1 : Double[], v2 : Double[]) : Bool { - return Length(v1) == Length(v2) and All(NearlyEqualD, Zip(v1, v2)); + return Length(v1) == Length(v2) and All(NearlyEqualD, Zipped(v1, v2)); } function _TailMeasurement(nQubits : Int) : (Qubit[] => Result) { diff --git a/MachineLearning/src/Structure.qs b/MachineLearning/src/Structure.qs index a3a80c5a..760e94ea 100644 --- a/MachineLearning/src/Structure.qs +++ b/MachineLearning/src/Structure.qs @@ -63,7 +63,7 @@ namespace Microsoft.Quantum.MachineLearning { } function _UncontrolledSpanSequence(idxsQubits : Int[]) : (Int, Int[])[] { - return Zip( + return Zipped( idxsQubits, ConstantArray(Length(idxsQubits), new Int[0]) ); @@ -210,4 +210,4 @@ namespace Microsoft.Quantum.MachineLearning { return combined; } -} \ No newline at end of file +} diff --git a/MachineLearning/src/Training.qs b/MachineLearning/src/Training.qs index 9eda6e6a..0944b3ed 100644 --- a/MachineLearning/src/Training.qs +++ b/MachineLearning/src/Training.qs @@ -160,9 +160,9 @@ namespace Microsoft.Quantum.MachineLearning { // size of the step taken during the move. We can find this size // as the squared norm of the gradient. SquaredNorm(batchGradient), - // To actually apply the step, we can use Mapped(PlusD, Zip(...)) + // To actually apply the step, we can use Mapped(PlusD, Zipped(...)) // to represent element-wise vector summation. - model w/ Parameters <- Mapped(PlusD, Zip(model::Parameters, batchGradient)) + model w/ Parameters <- Mapped(PlusD, Zipped(model::Parameters, batchGradient)) ); } @@ -239,7 +239,7 @@ namespace Microsoft.Quantum.MachineLearning { features, options::NMeasurements ); let updatedBias = _UpdatedBias( - Zip(probabilities, actualLabels), model::Bias, options::Tolerance + Zipped(probabilities, actualLabels), model::Bias, options::Tolerance ); let updatedLabels = InferredLabels( updatedBias, probabilities @@ -330,7 +330,7 @@ namespace Microsoft.Quantum.MachineLearning { ); // Find the best bias for the new classification parameters. let localBias = _UpdatedBias( - Zip(probabilities, Sampled(validationSchedule, labels)), + Zipped(probabilities, Sampled(validationSchedule, labels)), 0.0, options::Tolerance ); @@ -359,7 +359,7 @@ namespace Microsoft.Quantum.MachineLearning { ); mutable bestSoFar = model w/ Bias <- _UpdatedBias( - Zip(probabilities, actualLabels), + Zipped(probabilities, actualLabels), model::Bias, options::Tolerance ); let inferredLabels = InferredLabels( diff --git a/MachineLearning/src/Validation.qs b/MachineLearning/src/Validation.qs index 532c8c53..da28961b 100644 --- a/MachineLearning/src/Validation.qs +++ b/MachineLearning/src/Validation.qs @@ -27,7 +27,7 @@ namespace Microsoft.Quantum.MachineLearning { : Int[] { return Where( NotEqualI, - Zip(inferredLabels, actualLabels) + Zipped(inferredLabels, actualLabels) ); } diff --git a/MachineLearning/tests/StructureTests.qs b/MachineLearning/tests/StructureTests.qs index e9ee25a2..d77108ed 100644 --- a/MachineLearning/tests/StructureTests.qs +++ b/MachineLearning/tests/StructureTests.qs @@ -53,14 +53,14 @@ namespace Microsoft.Quantum.MachineLearning.Tests { function EqualCR(x : ML.ControlledRotation, y : ML.ControlledRotation) : Bool { return x::Axis == y::Axis and - All(EqualI, Zip(x::ControlIndices, y::ControlIndices)) and + All(EqualI, Zipped(x::ControlIndices, y::ControlIndices)) and x::TargetIndex == y::TargetIndex and x::ParameterIndex == y::ParameterIndex; } @Test("QuantumSimulator") function LocalRotationsLayerFact() : Unit { - Fact(All(EqualCR, Zip( + Fact(All(EqualCR, Zipped( ML.LocalRotationsLayer(3, PauliY), [ Default() @@ -86,7 +86,7 @@ namespace Microsoft.Quantum.MachineLearning.Tests { @Test("QuantumSimulator") function PartialRotationsLayerFact() : Unit { - Fact(All(EqualCR, Zip( + Fact(All(EqualCR, Zipped( ML.PartialRotationsLayer([4, 5, 6], PauliY), [ Default() @@ -112,7 +112,7 @@ namespace Microsoft.Quantum.MachineLearning.Tests { @Test("QuantumSimulator") function CyclicEntanglingLayerFact() : Unit { - Fact(All(EqualCR, Zip( + Fact(All(EqualCR, Zipped( ML.CyclicEntanglingLayer(3, PauliX, 2), [ Default() @@ -160,7 +160,7 @@ namespace Microsoft.Quantum.MachineLearning.Tests { w/ ParameterIndex <- 0 ] ]); - Fact(All(EqualCR, Zip( + Fact(All(EqualCR, Zipped( combined, [ Default() diff --git a/Numerics/src/FixedPoint/Multiplication.qs b/Numerics/src/FixedPoint/Multiplication.qs index 837f0d7a..3629d647 100644 --- a/Numerics/src/FixedPoint/Multiplication.qs +++ b/Numerics/src/FixedPoint/Multiplication.qs @@ -43,7 +43,7 @@ namespace Microsoft.Quantum.Arithmetic { MultiplySI(xsInt, ysInt, tmpResultInt); (Controlled ApplyToEachCA)(controls, (CNOT, - Zip(tmpResult[n-px..2*n-px-1], zs))); + Zipped(tmpResult[n-px..2*n-px-1], zs))); (Adjoint MultiplySI)(xsInt, ysInt, tmpResultInt); } } @@ -77,7 +77,7 @@ namespace Microsoft.Quantum.Arithmetic { SquareSI(xsInt, tmpResultInt); (Controlled ApplyToEachCA)(controls, (CNOT, - Zip(tmpResult[n-px..2*n-px-1], ys))); + Zipped(tmpResult[n-px..2*n-px-1], ys))); (Adjoint SquareSI)(xsInt, tmpResultInt); } } diff --git a/Numerics/src/FixedPoint/Reciprocal.qs b/Numerics/src/FixedPoint/Reciprocal.qs index 0da13f03..33521863 100644 --- a/Numerics/src/FixedPoint/Reciprocal.qs +++ b/Numerics/src/FixedPoint/Reciprocal.qs @@ -32,7 +32,7 @@ namespace Microsoft.Quantum.Arithmetic { ([sign], SignedLittleEndian(LittleEndian(xs))); ComputeReciprocalI(LittleEndian(xs), LittleEndian(tmpRes)); (Controlled ApplyToEachCA)(controls, - (CNOT, Zip(tmpRes[p+pRes-1+n-Length(rs)..Min([n+p+pRes, 2*n-1])], rs))); + (CNOT, Zipped(tmpRes[p+pRes-1+n-Length(rs)..Min([n+p+pRes, 2*n-1])], rs))); (Controlled Invert2sSI)([sign], SignedLittleEndian(LittleEndian(rs))); (Adjoint ComputeReciprocalI)(LittleEndian(xs), LittleEndian(tmpRes)); (Controlled Adjoint Invert2sSI) diff --git a/Standard/src/AmplitudeAmplification/AmplitudeAmplification.qs b/Standard/src/AmplitudeAmplification/AmplitudeAmplification.qs index dde60e11..646943ef 100644 --- a/Standard/src/AmplitudeAmplification/AmplitudeAmplification.qs +++ b/Standard/src/AmplitudeAmplification/AmplitudeAmplification.qs @@ -57,7 +57,7 @@ namespace Microsoft.Quantum.AmplitudeAmplification { systemRegister : Qubit[] ) : Unit is Adj + Ctl { - for ((startPhase, targetPhase) in Zip(phases!)) { + for ((startPhase, targetPhase) in Zipped(phases!)) { if (startPhase != 0.0) { startStateReflection::ApplyReflection( startPhase, auxiliaryRegister diff --git a/Standard/src/Arithmetic/Arithmetic.qs b/Standard/src/Arithmetic/Arithmetic.qs index 189d0e79..abab5bed 100644 --- a/Standard/src/Arithmetic/Arithmetic.qs +++ b/Standard/src/Arithmetic/Arithmetic.qs @@ -28,7 +28,7 @@ namespace Microsoft.Quantum.Arithmetic { : Unit is Adj + Ctl { ApplyToEachCA( CControlledCA(X), - Zip(IntAsBoolArray(value, Length(target!)), target!) + Zipped(IntAsBoolArray(value, Length(target!)), target!) ); } diff --git a/Standard/src/Arithmetic/Integer.qs b/Standard/src/Arithmetic/Integer.qs index 6599c7c6..03e4fd1f 100644 --- a/Standard/src/Arithmetic/Integer.qs +++ b/Standard/src/Arithmetic/Integer.qs @@ -182,7 +182,7 @@ namespace Microsoft.Quantum.Arithmetic { CCNOT(xs![nQubits - 2], ys![nQubits - 1], carry); ApplyToEachCA(X, Most(Rest(ys!))); // X on ys[1..(nQubits-2)] CNOT(ancilla, ys![1]) ; - ApplyToEachCA(CNOT, Zip(Rest(Most(xs!)), Rest(Rest(ys!)))); + ApplyToEachCA(CNOT, Zipped(Rest(Most(xs!)), Rest(Rest(ys!)))); } /// # Summary @@ -222,7 +222,7 @@ namespace Microsoft.Quantum.Arithmetic { using (auxiliary = Qubit()) { within { - ApplyToEachCA(CNOT, Zip(Rest(xs!), Rest(ys!))); + ApplyToEachCA(CNOT, Zipped(Rest(xs!), Rest(ys!))); CNOT(xs![1], auxiliary); CCNOT(xs![0], ys![0], auxiliary); ApplyOuterCDKMAdder(xs, ys, auxiliary); @@ -309,7 +309,7 @@ namespace Microsoft.Quantum.Arithmetic { "Input registers must have the same number of qubits." ); - ApplyToEachCA(CNOT, Zip(Rest(xs!), Rest(ys!))); + ApplyToEachCA(CNOT, Zipped(Rest(xs!), Rest(ys!))); Adjoint ApplyCNOTChain(Rest(xs!)); } @@ -492,7 +492,7 @@ namespace Microsoft.Quantum.Arithmetic { else { within { ApplyToEachCA(X, ys!); - ApplyToEachCA(CNOT, Zip(Rest(xs!), Rest(ys!))); + ApplyToEachCA(CNOT, Zipped(Rest(xs!), Rest(ys!))); } apply { within { (Adjoint ApplyCNOTChain) (Rest(xs!)); diff --git a/Standard/src/Arithmetic/Modular.qs b/Standard/src/Arithmetic/Modular.qs index b4c94a58..f9b91b6a 100644 --- a/Standard/src/Arithmetic/Modular.qs +++ b/Standard/src/Arithmetic/Modular.qs @@ -245,7 +245,7 @@ namespace Microsoft.Quantum.Arithmetic { MultiplyAndAddByModularInteger(constMultiplier, modulus, multiplier, summandLE); // now the joint state is |x⟩|xâ‹…a(mod N)⟩ - ApplyToEachCA(SWAP, Zip(summandLE!, multiplier!)); + ApplyToEachCA(SWAP, Zipped(summandLE!, multiplier!)); // now the joint state is |xâ‹…a(mod N)⟩|x⟩ let inverseMod = InverseModI(constMultiplier, modulus); diff --git a/Standard/src/Arithmetic/Reflections.qs b/Standard/src/Arithmetic/Reflections.qs index eece6613..fdd459d1 100644 --- a/Standard/src/Arithmetic/Reflections.qs +++ b/Standard/src/Arithmetic/Reflections.qs @@ -31,7 +31,7 @@ namespace Microsoft.Quantum.Arithmetic { // of X instructions that flip all the zeros in our index. ApplyToEachCA( CControlledCA(X), - Zip(Mapped(Not, IntAsBoolArray(index, Length(reg!))), reg!) + Zipped(Mapped(Not, IntAsBoolArray(index, Length(reg!))), reg!) ); } apply { Controlled Z(Most(reg!), Tail(reg!)); diff --git a/Standard/src/Arrays/Arrays.qs b/Standard/src/Arrays/Arrays.qs index 32e5ef99..c24f1632 100644 --- a/Standard/src/Arrays/Arrays.qs +++ b/Standard/src/Arrays/Arrays.qs @@ -63,10 +63,6 @@ namespace Microsoft.Quantum.Arrays { return array[0 .. Length(array) - 2]; } - internal function Lookup<'T> (array : 'T[], index : Int) : 'T { - return array[index]; - } - /// # Summary /// Given an array, returns a function which returns elements of that /// array. @@ -90,7 +86,7 @@ namespace Microsoft.Quantum.Arrays { /// where functions are used to avoid the need to record an entire array /// in memory. function LookupFunction<'T> (array : 'T[]) : (Int -> 'T) { - return Lookup(array, _); + return ElementAt(_, array); } /// # Summary @@ -129,6 +125,40 @@ namespace Microsoft.Quantum.Arrays { return array[0]; } + /// # Summary + /// Returns a tuple of first and all remaining elements of the array. + /// + /// # Type Parameters + /// ## 'A + /// The type of the array elements. + /// + /// # Input + /// ## array + /// An array with at least one element. + /// + /// # Output + /// A tuple of first and all remaining elements of the array. + function HeadAndRest<'A>(array : 'A[]) : ('A, 'A[]) { + return (Head(array), Rest(array)); + } + + /// # Summary + /// Returns a tuple of all but one and the last element of the array. + /// + /// # Type Parameters + /// ## 'A + /// The type of the array elements. + /// + /// # Input + /// ## array + /// An array with at least one element. + /// + /// # Output + /// A tuple of all but one and the last element of the array. + function MostAndTail<'A>(array : 'A[]) : ('A[], 'A) { + return (Most(array), Tail(array)); + } + /// # Summary /// Creates an array of given length with all elements equal to given value. /// @@ -182,9 +212,9 @@ namespace Microsoft.Quantum.Arrays { /// ```qsharp /// let array = [10, 11, 12, 13, 14, 15]; /// // The following line returns [10, 12, 15]. - /// let subarray = Exclude([1, 3, 4], array); + /// let subarray = Excluding([1, 3, 4], array); /// ``` - function Exclude<'T> (remove : Int[], array : 'T[]) : 'T[] { + function Excluding<'T>(remove : Int[], array : 'T[]) : 'T[] { let nSliced = Length(remove); let nElements = Length(array); diff --git a/Standard/src/Arrays/Deprecated.qs b/Standard/src/Arrays/Deprecated.qs new file mode 100644 index 00000000..c90700a9 --- /dev/null +++ b/Standard/src/Arrays/Deprecated.qs @@ -0,0 +1,151 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Arrays { + open Microsoft.Quantum.Arithmetic; + open Microsoft.Quantum.Logical; + + /// # Summary + /// Given two arrays, returns a new array of pairs such that each pair + /// contains an element from each original array. + /// + /// # Type Parameters + /// ## 'T + /// The type of the left array elements. + /// ## 'U + /// The type of the right array elements. + /// + /// # Input + /// ## left + /// An array containing values for the first element of each tuple. + /// ## right + /// An array containing values for the second element of each tuple. + /// + /// # Output + /// An array containing pairs of the form `(left[idx], right[idx])` for + /// each `idx`. If the two arrays are not of equal length, the output will + /// be as long as the shorter of the inputs. + /// + /// # Remarks + /// ## Example + /// ```qsharp + /// let left = [1, 3, 71]; + /// let right = [false, true]; + /// let pairs = Zip(left, right); // [(1, false), (3, true)] + /// ``` + /// + /// # See Also + /// - Zip3 + /// - Zip4 + /// - Unzipped + @Deprecated("Microsoft.Quantum.Arrays.Zipped") + function Zip<'T, 'U> (left : 'T[], right : 'U[]) : ('T, 'U)[] { + return Zipped(left, right); + } + + /// # Summary + /// Given three arrays, returns a new array of 3-tuples such that each 3-tuple + /// contains an element from each original array. + /// + /// # Type Parameters + /// ## 'T1 + /// The type of the first array elements. + /// ## 'T2 + /// The type of the second array elements. + /// ## 'T3 + /// The type of the third array elements. + /// + /// # Input + /// ## first + /// An array containing values for the first element of each tuple. + /// ## second + /// An array containing values for the second element of each tuple. + /// ## third + /// An array containing values for the third element of each tuple. + /// + /// # Output + /// An array containing 3-tuples of the form `(first[idx], second[idx], third[idx])` for + /// each `idx`. If the three arrays are not of equal length, the output will + /// be as long as the shorter of the inputs. + /// + /// # See Also + /// - Zip + /// - Zip4 + @Deprecated("Microsoft.Quantum.Arrays.Zipped3") + function Zip3<'T1, 'T2, 'T3> (first : 'T1[], second : 'T2[], third : 'T3[]) : ('T1, 'T2, 'T3)[] { + return Zipped3(first, second, third); + } + + + /// # Summary + /// Given four arrays, returns a new array of 4-tuples such that each 4-tuple + /// contains an element from each original array. + /// + /// # Type Parameters + /// ## 'T1 + /// The type of the first array elements. + /// ## 'T2 + /// The type of the second array elements. + /// ## 'T3 + /// The type of the third array elements. + /// ## 'T4 + /// The type of the fourth array elements. + /// + /// # Input + /// ## first + /// An array containing values for the first element of each tuple. + /// ## second + /// An array containing values for the second element of each tuple. + /// ## third + /// An array containing values for the third element of each tuple. + /// ## fourth + /// An array containing values for the fourth element of each tuple. + /// + /// # Output + /// An array containing 4-tuples of the form `(first[idx], second[idx], third[idx], fourth[idx])` for + /// each `idx`. If the four arrays are not of equal length, the output will + /// be as long as the shorter of the inputs. + /// + /// # See Also + /// - Zip + /// - Zip3 + @Deprecated("Microsoft.Quantum.Arrays.Zipped4") + function Zip4<'T1, 'T2, 'T3, 'T4> (first : 'T1[], second : 'T2[], third : 'T3[], fourth : 'T4[]) : ('T1, 'T2, 'T3, 'T4)[] { + return Zipped4(first, second, third, fourth); + } + + + + /// # Summary + /// Returns an array containing the elements of another array, + /// excluding elements at a given list of indices. + /// + /// # Type Parameters + /// ## 'T + /// The type of the array elements. + /// + /// # Input + /// ## remove + /// An array of indices denoting which elements should be excluded + /// from the output. + /// ## array + /// Array of which the values in the output array are taken. + /// + /// # Output + /// An array `output` such that `output[0]` is the first element + /// of `array` whose index does not appear in `remove`, + /// such that `output[1]` is the second such element, and so + /// forth. + /// + /// # Remarks + /// ## Example + /// ```qsharp + /// let array = [10, 11, 12, 13, 14, 15]; + /// // The following line returns [10, 12, 15]. + /// let subarray = Exclude([1, 3, 4], array); + /// ``` + function Exclude<'T>(remove : Int[], array : 'T[]) : 'T[] { + return Excluding(remove, array); + } + +} diff --git a/Standard/src/Arrays/EqualA.qs b/Standard/src/Arrays/EqualA.qs index 960db42b..eb3cfc41 100644 --- a/Standard/src/Arrays/EqualA.qs +++ b/Standard/src/Arrays/EqualA.qs @@ -51,7 +51,7 @@ namespace Microsoft.Quantum.Arrays { if (Length(array1) != Length(array2)) { return false; } - return All(equal, Zip(array1, array2)); + return All(equal, Zipped(array1, array2)); } } diff --git a/Standard/src/Arrays/Filter.qs b/Standard/src/Arrays/Filter.qs index f03605ef..38a7c463 100644 --- a/Standard/src/Arrays/Filter.qs +++ b/Standard/src/Arrays/Filter.qs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Microsoft.Quantum.Arrays { @@ -40,7 +40,7 @@ namespace Microsoft.Quantum.Arrays { /// } /// ``` /// The outcome one should expect from this example will be an array of numbers greater than 5. - function Filtered<'T> (predicate : ('T -> Bool), array : 'T[]) : 'T[] { + function Filtered<'T>(predicate : ('T -> Bool), array : 'T[]) : 'T[] { mutable totalFound = 0; mutable idxArray = new Int[Length(array)]; @@ -80,4 +80,45 @@ namespace Microsoft.Quantum.Arrays { ); } + /// # Summary + /// Given an array and a predicate that is defined + /// for the elements of the array, returns the number of elements + /// an array that consists of those elements that satisfy the predicate. + /// + /// # Remarks + /// The function is defined for generic types, i.e., whenever we have + /// an array `'T[]` and a predicate `'T -> Bool` we can filter elements. + /// + /// # Type Parameters + /// ## 'T + /// The type of `array` elements. + /// + /// # Input + /// ## predicate + /// A function from `'T` to Boolean that is used to filter elements. + /// ## array + /// An array of elements over `'T`. + /// + /// # Output + /// The number of elements in `array` that satisfy the predicate. + /// + /// # Example + /// The following code demonstrates the "Count" function. + /// A predicate is defined using the @"microsoft.quantum.logical.greaterthani" function: + /// ```Q# + /// let predicate = GreaterThanI(_, 5); + /// let count = Count(predicate, [2, 5, 9, 1, 8]); + /// // count = 2 + /// ``` + function Count<'T>(predicate : ('T -> Bool), array : 'T[]) : Int { + mutable totalFound = 0; + + for (element in array) { + if (predicate(element)) { + set totalFound += 1; + } + } + + return totalFound; + } } diff --git a/Standard/src/Arrays/Interleaved.qs b/Standard/src/Arrays/Interleaved.qs new file mode 100644 index 00000000..05cbc93b --- /dev/null +++ b/Standard/src/Arrays/Interleaved.qs @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Arrays { + open Microsoft.Quantum.Diagnostics; + + /// # Summary + /// Interleaves two arrays of (almost) same size. + /// + /// # Description + /// This function returns the interleaving of two arrays, starting + /// with the first element from the first array, then the first + /// element from the second array, and so on. + /// + /// The first array must either be + /// of the same length as the second one, or can have one more element. + /// + /// # Type Parameters + /// ## 'T + /// The type of each element of `first` and `second`. + /// + /// # Input + /// ## first + /// The first array to be interleaved. + /// + /// ## second + /// The second array to be interleaved. + /// + /// # Output + /// Interleaved array + /// + /// # Example + /// ```Q# + /// // same as int1 = [1, -1, 2, -2, 3, -3] + /// let int1 = Interleaved([1, 2, 3], [-1, -2, -3]) + /// + /// // same as int2 = [false, true, false, true, false] + /// let int2 = Interleaved(ConstantArray(3, false), ConstantArray(2, true)); + /// ``` + function Interleaved<'T>(first : 'T[], second : 'T[]) : 'T[] { + let lFirst = Length(first); + let lSecond = Length(second); + + Fact(lFirst >= lSecond and lFirst - lSecond <= 1, "Array `first` is either of same size as `second`, or has one more element"); + + return new 'T[lFirst + lSecond] + w/ 0..2..(lFirst + lSecond - 1) <- first + w/ 1..2..(lFirst + lSecond - 1) <- second; + } +} diff --git a/Standard/src/Arrays/Map.qs b/Standard/src/Arrays/Map.qs index e6e28337..b541190a 100644 --- a/Standard/src/Arrays/Map.qs +++ b/Standard/src/Arrays/Map.qs @@ -2,6 +2,7 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Arrays { + open Microsoft.Quantum.Math; /// # Summary /// Given an array and a function that is defined @@ -86,6 +87,109 @@ namespace Microsoft.Quantum.Arrays { return resultArray; } + /// # Summary + /// Given a range and a function that takes an integer as input, + /// returns a new array that consists + /// of the images of the range values under the function. + /// + /// # Remarks + /// The function is defined for generic types, i.e., whenever we have + /// a function `mapper: Int -> 'T` we can map the values + /// of the range and produce an array of type `'T[]`. + /// + /// # Type Parameters + /// ## 'T + /// The result type of the `mapper` function. + /// + /// # Input + /// ## mapper + /// A function from `Int` to `'T` that is used to map range values. + /// ## range + /// A range of integers. + /// + /// # Output + /// An array `'T[]` of elements that are mapped by the `mapper` function. + /// + /// # Example + /// This example adds 1 to a range of even numbers: + /// ```Q# + /// let numbers = MappedOverRange(PlusI(1, _), 0..2..10); + /// // numbers = [1, 3, 5, 7, 9, 11] + /// ``` + /// + /// # See Also + /// - Microsoft.Quantum.Arrays.Mapped + function MappedOverRange<'T> (mapper : (Int -> 'T), range : Range) : 'T[] { + let start = RangeStart(range); + let step = RangeStep(range); + let end = RangeEnd(range); + if ((end - start) / step >= 0) { + let nTerms = (end - start) / step + 1; + mutable resultArray = new 'T[nTerms]; + mutable idxElement = 0; + for (elem in range) { + set resultArray w/= idxElement <- mapper(elem); + set idxElement += 1; + } + return resultArray; + } else { + return new 'T[0]; + } + } + + /// # Summary + /// Given an array and a function that maps an array element to some output + /// array, returns the concatenated output arrays for each array element. + /// + /// # Type Parameters + /// ## 'TInput + /// The type of `array` elements. + /// ## 'TOutput + /// The `mapper` function returns arrays of this type. + /// + /// # Input + /// ## mapper + /// A function from `'TInput` to `'TOutput[]` that is used to map array elements. + /// ## array + /// An array of elements. + /// + /// # Output + /// An array of `'TOutput[]` which is the concatenation of all arrays generated by + /// the mapping function. + /// + /// # Example + /// ```Q# + /// let Numbers = SequenceI(1, _); // generates numbers starting from 1 + /// let values = FlatMapped(Numbers, [1, 2, 3]); + /// // values = [1, 1, 2, 1, 2, 3] + /// ``` + function FlatMapped<'TInput, 'TOutput>(mapper : ('TInput -> 'TOutput[]), array : 'TInput[]) : 'TOutput[] { + return Fold(PlusA<'TOutput>, new 'TOutput[0], Mapped(mapper, array)); + } + + /// # Summary + /// Given an array of arrays, returns the concatenation of all arrays. + /// + /// # Type Parameters + /// ## 'T + /// The type of `array` elements. + /// + /// # Input + /// ## arrays + /// Array of arrays. + /// + /// # Output + /// Concatenation of all arrays. + /// + /// # Example + /// ```Q# + /// let flattened = Flattened([[1, 2], [3], [4, 5, 6]]); + /// // flattened = [1, 2, 3, 4, 5, 6] + /// ``` + function Flattened<'T>(arrays : 'T[][]): 'T[] { + return Fold(PlusA<'T>, new 'T[0], arrays); + } + /// # Summary /// Given an array and an operation that is defined /// for the elements of the array, returns a new array that consists diff --git a/Standard/src/Arrays/Multidimensional.qs b/Standard/src/Arrays/Multidimensional.qs new file mode 100644 index 00000000..7e210258 --- /dev/null +++ b/Standard/src/Arrays/Multidimensional.qs @@ -0,0 +1,276 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Arrays { + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Convert; + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Logical; + open Microsoft.Quantum.Math; + + /// # Summary + /// Returns the transpose of a matrix represented as an array + /// of arrays. + /// + /// # Description + /// Input as an $r \times c$ matrix with $r$ rows and $c$ columns. The matrix + /// is row-based, i.e., `matrix[i][j]` accesses the element at row $i$ and column $j$. + /// + /// This function returns the $c \times r$ matrix that is the transpose of the + /// input matrix. + /// + /// # Type Parameters + /// ## 'T + /// The type of each element of `matrix`. + /// + /// # Input + /// ## matrix + /// Row-based $r \times c$ matrix + /// + /// # Output + /// Transposed $c \times r$ matrix + /// + /// # Example + /// ```Q# + /// // same as [[1, 4], [2, 5], [3, 6]] + /// let transposed = Transposed([[1, 2, 3], [4, 5, 6]]); + /// ``` + function Transposed<'T>(matrix : 'T[][]) : 'T[][] { + let numRows = Length(matrix); + Fact(numRows > 0, "Matrix must have at least 1 row"); + let numColumns = Length(Head(matrix)); + Fact(numColumns > 0, "Matrix must have at least 1 column"); + RectangularArrayFact(matrix, "Matrix is not a rectangular array"); + + return Mapped(ColumnAtUnchecked(_, matrix), SequenceI(0, numColumns - 1)); + } + + /// # Summary + /// Returns the at the given index of an array. + /// + /// # Type Parameters + /// ## 'T + /// The type of each element of `array`. + /// + /// # Input + /// ## index + /// Index of element + /// ## array + /// The array being indexed. + /// + /// # Remark + /// This function is more general than `LookupFunction`, since + /// it can also be used for partial application on a fixed index. + /// Note that the type parameter must explicitly be provided in + /// this case as it cannot be deduced automatically. + /// + /// # Example + /// Get the third number in four famous integer sequences. (note + /// that the 0 index corresponds to the _first_ value of the sequence.) + /// ```Q# + /// let lucas = [2, 1, 3, 4, 7, 11, 18, 29, 47, 76]; + /// let prime = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]; + /// let fibonacci = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]; + /// let catalan = [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862]; + /// let famous2 = Mapped(ElementAt(2, _), [lucas, prime, fibonacci, catalan]); + /// // same as: famous2 = [3, 5, 1, 2] + /// ``` + /// + /// # See Also + /// - Microsoft.Quantum.Arrays.LookupFunction + /// - Microsoft.Quantum.Arrays.ElementsAt + function ElementAt<'T>(index : Int, array : 'T[]) : 'T { + Fact(index >= 0 and index < Length(array), "Index is out of bound"); + return array[index]; + } + + /// # Summary + /// Returns the array's elements at a given range + /// of indices. + /// + /// # Type Parameters + /// ## 'T + /// The type of each element of `array`. + /// + /// # Input + /// ## range + /// Range of array indexes + /// ## array + /// Array + /// + /// # Example + /// Get the odd indexes in famous integer sequences. (note + /// that the 0 index corresponds to the _first_ value of the sequence.) + /// ```Q# + /// let lucas = [2, 1, 3, 4, 7, 11, 18, 29, 47, 76]; + /// let prime = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]; + /// let fibonacci = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]; + /// let catalan = [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862]; + /// let famousOdd = Mapped(ElementsAt(0..2..9, _), [lucas, prime, fibonacci, catalan]); + /// // same as: famousOdd = [[2, 3, 7, 18, 47], [2, 5, 11, 17, 23], [0, 1, 3, 8, 21], [1, 2, 14, 132, 1430]] + /// ``` + /// + /// # See Also + /// - Microsoft.Quantum.Arrays.ElementAt + /// - Microsoft.Quantum.Arrays.LookupFunction + function ElementsAt<'T>(range : Range, array : 'T[]) : 'T[] { + return array[range]; + } + + /// # Summary + /// Extracts a column from a matrix. + /// + /// # Description + /// This function extracts a column in a matrix in row-wise order. + /// Extracting a row corrsponds to element access of the first index + /// and therefore requires no further treatment. + /// + /// # Type Parameters + /// ## 'T + /// The type of each element of `matrix`. + /// + /// # Input + /// ## column + /// Column of the matrix + /// ## matrix + /// 2-dimensional matrix in row-wise order + /// + /// # Example + /// ```Q# + /// let matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; + /// let column = ColumnAt(0, matrix); + /// // same as: column = [1, 4, 7] + /// ``` + /// + /// # See Also + /// - Microsoft.Quantum.Arrays.Transposed + /// - Microsoft.Quantum.Arrays.Diagonal + function ColumnAt<'T>(column : Int, matrix : 'T[][]) : 'T[] { + RectangularArrayFact(matrix, "Matrix is not a rectangular array"); + return ColumnAtUnchecked(column, matrix); + } + + /// # Summary + /// This function does not check for matrix shape + /// + /// # Description + /// This function can be used in other multidimensional functions, + /// which already check the input matrix for a valid rectangular shape. + internal function ColumnAtUnchecked<'T>(column : Int, matrix : 'T[][]) : 'T[] { + return Mapped( + Compose( + ElementAt<'T>(column, _), + LookupFunction(matrix) + ), RangeAsIntArray(IndexRange(matrix))); + } + + /// # Summary + /// Returns an array of diagonal elements of a 2-dimensional array + /// + /// # Description + /// If the 2-dimensional array has not a square shape, the diagonal over + /// the minimum over the number of rows and columns will be returned. + /// + /// # Type Parameters + /// ## 'T + /// The type of each element of `matrix`. + /// + /// # Input + /// ## matrix + /// 2-dimensional matrix in row-wise order + /// + /// # Example + /// ```Q# + /// let matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; + /// let diagonal = Diagonal(matrix); + /// // same as: column = [1, 5, 9] + /// ``` + /// + /// # See Also + /// - Microsoft.Quantum.Arrays.Transposed + function Diagonal<'T>(matrix : 'T[][]) : 'T[] { + RectangularArrayFact(matrix, "Matrix is not a rectangular array"); + + let numRows = Length(matrix); + let numColumns = numRows == 0 ? 0 | Length(Head(matrix)); + + return MappedOverRange(ElementAtDiagonal(_, matrix), 0..(MinI(numRows, numColumns) - 1)); + } + + internal function ElementAtDiagonal<'T>(index : Int, matrix : 'T[][]) : 'T { + return matrix[index][index]; + } + + /// # Summary + /// Represents a condition that a 2-dimensional array has a rectangular shape + /// + /// # Description + /// This function asserts that each row in an array has the same length. + /// + /// # Type Parameters + /// ## 'T + /// The type of each element of `array`. + /// + /// # Input + /// ## array + /// A 2-dimensional array of elements + /// ## message + /// A message to be printed if the array is not a rectangular array + /// + /// # Example + /// ```Q# + /// RectangularArrayFact([[1, 2], [3, 4]], "Array is not rectangular"); // okay + /// RectangularArrayFact([[1, 2, 3], [4, 5, 6]], "Array is not rectangular"); // okay + /// RectangularArrayFact([[1, 2], [3, 4, 5]], "Array is not rectangular"); // will fail + /// ``` + /// + /// # See Also + /// - Microsoft.Quantum.Arrays.SquareArrayFact + function RectangularArrayFact<'T>(array : 'T[][], message : String) : Unit { + if (Length(array) == 0) { + return (); + } else { + let numColumns = Length(Head(array)); + if (Any(Compose(NotEqualI(numColumns, _), Length<'T>), Rest(array))) { + fail message; + } + } + } + + /// # Summary + /// Represents a condition that a 2-dimensional array has a square shape + /// + /// # Description + /// This function asserts that each row in an array has + /// as many elements as there are rows (elements) in the array. + /// + /// # Type Parameters + /// ## 'T + /// The type of each element of `array`. + /// + /// # Input + /// ## array + /// A 2-dimensional array of elements + /// ## message + /// A message to be printed if the array is not a square array + /// + /// # Example + /// ```Q# + /// SquareArrayFact([[1, 2], [3, 4]], "Array is not a square"); // okay + /// SquareArrayFact([[1, 2, 3], [4, 5, 6]], "Array is not a square"); // will fail + /// SquareArrayFact([[1, 2], [3, 4, 5]], "Array is not a square"); // will fail + /// ``` + /// + /// # See Also + /// - Microsoft.Quantum.Arrays.RectangularArrayFact + function SquareArrayFact<'T>(array : 'T[][], message : String) : Unit { + if (Length(array) == 0) { + return (); + } else { + let numColumns = Length(array); + if (Any(Compose(NotEqualI(numColumns, _), Length<'T>), array)) { + fail message; + } + } + } +} diff --git a/Standard/src/Arrays/Reductions.qs b/Standard/src/Arrays/Reductions.qs new file mode 100644 index 00000000..201c45b4 --- /dev/null +++ b/Standard/src/Arrays/Reductions.qs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Arrays { + + /// # Summary + /// Combines Mapped and Fold into a single function + /// + /// # Description + /// This function iterates the `fn` function through the array, starting from + /// an initial state `state` and returns all intermediate values, not including + /// the inital state. + /// + /// # Type Parameters + /// ## 'State + /// The type of states that the `fn` function operates on, i.e., accepts as its first + /// input and returns. + /// ## 'T + /// The type of `array` elements. + /// + /// # Input + /// ## fn + /// A function to be folded over the array + /// + /// ## state + /// The initial state to be folded + /// + /// ## array + /// An array of values to be folded over + /// + /// # Output + /// All intermediate states, including the final state, but not the initial state. + /// The length of the output array is of the same length as `array`. + /// + /// # Remark + /// This function generalizes `Fold` since + /// `Tail(CumulativeFolded(fn, state, array))` is the same as `Fold(fn, state, array)`. + /// + /// # Example + /// ```Q# + /// // same as sums = [1, 3, 6, 10, 15] + /// let sums = CumulativeFolded(PlusI, 0, SequenceI(1, 5)); + /// ``` + function CumulativeFolded<'State, 'T>(fn : (('State, 'T) -> 'State), state : 'State, array : 'T[]) : 'State[] { + mutable current = state; + mutable result = new 'State[Length(array)]; + + for ((i, elem) in Enumerated(array)) { + set current = fn(current, elem); + set result w/= i <- current; + } + + return result; + } +} diff --git a/Standard/src/Arrays/Sorted.qs b/Standard/src/Arrays/Sorted.qs new file mode 100644 index 00000000..7cb3b15b --- /dev/null +++ b/Standard/src/Arrays/Sorted.qs @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Arrays { + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Canon; + + /// # Summary + /// Given two sorted arrays, returns a single array containing the + /// elements of both in sorted order. Used internally by merge sort. + internal function Merged<'T>(comparison : (('T, 'T) -> Bool), left : 'T[], right : 'T[]) : 'T[] { + mutable result = new 'T[0]; + mutable l = left; + mutable r = right; + while ((not IsEmpty(l)) and (not IsEmpty(r))) { + if (comparison(Head(l), Head(r))) { + set result += [Head(l)]; + set l = Rest(l); + } else { + set result += [Head(r)]; + set r = Rest(r); + } + } + + // Note that at this point, either or both of l and r are empty, + // such that we can simply append both to our result to get the + // whole merged array. + return result + l + r; + } + + /// # Summary + /// Given an array, returns whether that array is sorted as defined by + /// a given comparison function. + /// + /// # Type Parameters + /// ## 'T + /// The type of each element of `array`. + /// + /// # Input + /// ## comparison + /// A function that compares two elements such that `a` is considered to + /// be less than or equal to `b` if `comparison(a, b)` is `true`. + /// ## array + /// The array to be checked. + /// + /// # Output + /// `true` if and only if for each pair of elements `a` and `b` of + /// `array` occuring in that order, `comparison(a, b)` is `true`. + /// + /// # Remarks + /// The function `comparison` is assumed to be transitive, such that + /// if `comparison(a, b)` and `comparison(b, c)`, then `comparison(a, c)` + /// is assumed. If this property does not hold, then the output of this + /// function may be incorrect. + function IsSorted<'T>(comparison : (('T, 'T) -> Bool), array : 'T[]) : Bool { + return All( + comparison, + Zipped(Most(array), Rest(array)) + ); + } + + /// # Summary + /// Given an array, returns the elements of that array sorted by a given + /// comparison function. + /// + /// # Type Parameters + /// ## 'T + /// The type of each element of `array`. + /// + /// # Input + /// ## comparison + /// A function that compares two elements such that `a` is considered to + /// be less than or equal to `b` if `comparison(a, b)` is `true`. + /// ## array + /// The array to be sorted. + /// + /// # Ouput + /// An array containing the same elements as `array`, such that for all + /// elements `a` occuring earlier than elements `b`, `comparison(a, b)` + /// is `true`. + /// + /// # Example + /// The following snippet sorts an array of integers to occur in ascending + /// order: + /// ```Q# + /// let sortedArray = Sorted(LessThanOrEqualI, [3, 17, 11, -201, -11]); + /// ``` + /// + /// # Remarks + /// The function `comparison` is assumed to be transitive, such that + /// if `comparison(a, b)` and `comparison(b, c)`, then `comparison(a, c)` + /// is assumed. If this property does not hold, then the output of this + /// function may be incorrect. + /// + /// As this is a function, the results are completely determinstic, even + /// when two elements are considered equal under `comparison`; + /// that is, when `comparison(a, b)` and `comparison(b, a)` are both `true`. + /// In particular, the sort performed by this function is guaranteed to be + /// stable, so that if two elements `a` and `b` occur in that order within + /// `array` and are considered equal under `comparison`, then `a` will also + /// appear before `b` in the output. + /// + /// For example: + /// ```Q# + /// function LastDigitLessThanOrEqual(left : Int, right : Int) : Bool { + /// return LessThanOrEqualI( + /// left % 10, right % 10 + /// ); + /// } + /// + /// function SortedByLastDigit() : Int[] { + /// return Sorted(LastDigitLessThanOrEqual, [3, 37, 11, 17]); + /// } + /// // returns [11, 3, 37, 17]. + /// ``` + function Sorted<'T>(comparison : (('T, 'T) -> Bool), array : 'T[]) : 'T[] { + if (Length(array) <= 1) { + return array; + } else { + let idxPivot = Length(array) / 2; + let left = array[...idxPivot - 1]; + let right = array[idxPivot...]; + + // Sort each sublist, then merge them back into a single combined + // list and return. + return Merged<'T>( + comparison, + Sorted(comparison, left), + Sorted(comparison, right) + ); + } + } + +} diff --git a/Standard/src/Arrays/Unique.qs b/Standard/src/Arrays/Unique.qs new file mode 100644 index 00000000..ea588a39 --- /dev/null +++ b/Standard/src/Arrays/Unique.qs @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Arrays { + /// # Summary + /// Returns a new array that has no equal adjacent elements. + /// + /// # Description + /// Given some array of elements and a function to test equality, this + /// function returns a new array in which the relative order of elements + /// is kept, but all adjacent elements which are equal are filtered to + /// just a single element. + /// + /// # Type Parameters + /// ## 'T + /// The type of each element of `array`. + /// + /// # Input + /// ## equal + /// A function that compares two elements such that `a` is considered to + /// be equal to `b` if `equal(a, b)` is `true`. + /// ## array + /// The array to be filtered for unique elements. + /// + /// # Output + /// Array with no equal adjacent elements. + /// + /// # Remarks + /// If there are multiple elements that are equal but not next to each other, + /// there will be multiple occurrences in the output array. Use this function + /// together with `Sorted` to get an array with overall unique elements. + /// + /// # Example + /// ```Q# + /// let unique1 = Unique(EqualI, [1, 1, 3, 3, 2, 5, 5, 5, 7]); + /// // same as [1, 3, 2, 5, 7] + /// let unique2 = Unique(EqualI, [2, 2, 1, 1, 2, 2, 1, 1]); + /// // same as [2, 1, 2, 1]; + /// let unique3 = Unique(EqualI, Sorted(LessThanOrEqualI, [2, 2, 1, 1, 2, 2, 1, 1])); + /// // same as [1, 2]; + /// ``` + function Unique<'T>(equal : (('T, 'T) -> Bool), array : 'T[]) : 'T[] { + if (Length(array) == 0) { + return new 'T[0]; + } + + mutable unique = ConstantArray(Length(array), Head(array)); + mutable count = 1; + + for (elem in Rest(array)) { + if (not equal(elem, unique[count - 1])) { + set unique w/= count <- elem; + set count += 1; + } + } + + return unique[0..count - 1]; + } +} diff --git a/Standard/src/Arrays/Windows.qs b/Standard/src/Arrays/Windows.qs new file mode 100644 index 00000000..bcad5c35 --- /dev/null +++ b/Standard/src/Arrays/Windows.qs @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Arrays { + + /// # Summary + /// Returns all consecutive subarrays of length `size`. + /// + /// # Description + /// This function returns all `n - size + 1` subarrays of + /// length `size` in order, where `n` is the length of `arr`. + /// The first subarrays are `arr[0..size - 1], arr[1..size], arr[2..size + 1]` + /// until the last subarray `arr[n - size..n - 1]`. + /// + /// If `size <= 0` or `size > n`, an empty array is returned. + /// + /// # Type Parameters + /// ## 'T + /// The type of `array` elements. + /// + /// # Input + /// ## size + /// Length of the subarrays. + /// + /// ## array + /// An array of elements. + /// + /// # Example + /// ```Q# + /// // same as [[1, 2, 3], [2, 3, 4], [3, 4, 5]] + /// let windows = Windows(3, [1, 2, 3, 4, 5]); + /// ``` + function Windows<'T>(size : Int, array : 'T[]) : 'T[][] { + let n = Length(array); + + if (size <= 0 or size > n) { + return new 'T[][0]; + } + + mutable result = new 'T[][n + 1 - size]; + + for (i in 0..n - size) { + set result w/= i <- array[i..i + size - 1]; + } + + return result; + } + + /// # Summary + /// Given an array, returns all its prefixes. + /// + /// # Description + /// Returns an array of all prefixes, starting with an array that only + /// has the first element until the complete array. + /// + /// # Type Parameters + /// ## 'T + /// The type of `array` elements. + /// + /// # Input + /// ## array + /// An array of elements. + /// + /// # Example + /// ```Q# + /// let prefixes = Prefixes([23, 42, 144]); + /// // prefixes = [[23], [23, 42], [23, 42, 144]] + /// ``` + function Prefixes<'T>(array : 'T[]) : 'T[][] { + return MappedOverRange(Prefix(_, array), IndexRange(array)); + } + + internal function Prefix<'T>(to : Int, array : 'T[]) : 'T[] { + return array[0..to]; + } +} diff --git a/Standard/src/Arrays/Zip.qs b/Standard/src/Arrays/Zip.qs index caa785a2..2b164f22 100644 --- a/Standard/src/Arrays/Zip.qs +++ b/Standard/src/Arrays/Zip.qs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Microsoft.Quantum.Arrays { @@ -30,13 +30,14 @@ namespace Microsoft.Quantum.Arrays { /// ```qsharp /// let left = [1, 3, 71]; /// let right = [false, true]; - /// let pairs = Zip(left, right); // [(1, false), (3, true)] + /// let pairs = Zipped(left, right); // [(1, false), (3, true)] /// ``` /// /// # See Also - /// - Zip3 - /// - Zip4 - function Zip<'T, 'U> (left : 'T[], right : 'U[]) : ('T, 'U)[] { + /// - Microsoft.Quantum.Arrays.Zipped3 + /// - Microsoft.Quantum.Arrays.Zipped4 + /// - Microsoft.Quantum.Arrays.Unzipped + function Zipped<'T, 'U>(left : 'T[], right : 'U[]) : ('T, 'U)[] { let nElements = Length(left) < Length(right) ? Length(left) | Length(right); @@ -75,9 +76,9 @@ namespace Microsoft.Quantum.Arrays { /// be as long as the shorter of the inputs. /// /// # See Also - /// - Zip - /// - Zip4 - function Zip3<'T1, 'T2, 'T3> (first : 'T1[], second : 'T2[], third : 'T3[]) : ('T1, 'T2, 'T3)[] { + /// - Microsoft.Quantum.Arrays.Zipped + /// - Microsoft.Quantum.Arrays.Zipped4 + function Zipped3<'T1, 'T2, 'T3> (first : 'T1[], second : 'T2[], third : 'T3[]) : ('T1, 'T2, 'T3)[] { let nElements = Min([Length(first), Length(second), Length(third)]); mutable output = new ('T1, 'T2, 'T3)[nElements]; @@ -118,9 +119,9 @@ namespace Microsoft.Quantum.Arrays { /// be as long as the shorter of the inputs. /// /// # See Also - /// - Zip - /// - Zip3 - function Zip4<'T1, 'T2, 'T3, 'T4> (first : 'T1[], second : 'T2[], third : 'T3[], fourth : 'T4[]) : ('T1, 'T2, 'T3, 'T4)[] { + /// - Microsoft.Quantum.Arrays.Zipped + /// - Microsoft.Quantum.Arrays.Zipped3 + function Zipped4<'T1, 'T2, 'T3, 'T4> (first : 'T1[], second : 'T2[], third : 'T3[], fourth : 'T4[]) : ('T1, 'T2, 'T3, 'T4)[] { let nElements = Min([Length(first), Length(second), Length(third), Length(fourth)]); mutable output = new ('T1, 'T2, 'T3, 'T4)[nElements]; @@ -131,6 +132,46 @@ namespace Microsoft.Quantum.Arrays { return output; } + /// # Summary + /// Given an array of 2-tuples, returns a tuple of two arrays, each containing + /// the elements of the tuples of the input array. + /// + /// # Type Parameters + /// ## 'T + /// The type of the first element in each tuple + /// ## 'U + /// The type of the second element in each tuple + /// + /// # Input + /// ## arr + /// An array containing 2-tuples + /// + /// # Output + /// Two arrays, the first one containing all first elements of the input + /// tuples, the second one containing all second elements of the input tuples. + /// + /// # Example + /// ```Q# + /// // split is same as ([6, 5, 5, 3, 2, 1], [true, false, false, false, true, false]) + /// let split = Unzipped([(6, true), (5, false), (5, false), (3, false), (2, true), (1, false)]); + /// ``` + /// + /// # Remark + /// This function is equivalent to `(Mapped(Fst<'T, 'U>, arr), Mapped(Snd<'T, 'U>, arr))`. + /// + /// # See Also + /// - Microsoft.Quantum.Arrays.Zipped + function Unzipped<'T, 'U>(arr : ('T, 'U)[]) : ('T[], 'U[]) { + let nElements = Length(arr); + mutable first = new 'T[nElements]; + mutable second = new 'U[nElements]; + for (idxElement in 0 .. nElements - 1) { + let (left, right) = arr[idxElement]; + set first w/= idxElement <- left; + set second w/= idxElement <- right; + } + return (first, second); + } } diff --git a/Standard/src/Canon/And.qs b/Standard/src/Canon/And.qs index 7cfaf579..3b8452f3 100644 --- a/Standard/src/Canon/And.qs +++ b/Standard/src/Canon/And.qs @@ -167,7 +167,7 @@ namespace Microsoft.Quantum.Canon { if (i % 2 == 0) { set j = 0; } else { - let e = Zip(current, RangeAsIntArray(0..N - 1)); + let e = Zipped(current, RangeAsIntArray(0..N - 1)); set j = Snd(Head(Filtered(Fst, e))) + 1; } diff --git a/Standard/src/Canon/Combinators/ApplyIf.qs b/Standard/src/Canon/Combinators/ApplyIf.qs index 69dfc6c4..8cb6d8b7 100644 --- a/Standard/src/Canon/Combinators/ApplyIf.qs +++ b/Standard/src/Canon/Combinators/ApplyIf.qs @@ -34,7 +34,7 @@ namespace Microsoft.Quantum.Canon { /// ```Q# /// let bitstring = [true, false, true]; /// using (register = Qubit(3)) { - /// ApplyToEach(ApplyIf(X, _, _), Zip(bitstring, register)); + /// ApplyToEach(ApplyIf(X, _, _), Zipped(bitstring, register)); /// // register should now be in the state |101⟩. /// ... /// } @@ -77,7 +77,7 @@ namespace Microsoft.Quantum.Canon { /// ```Q# /// let bitstring = [true, false, true]; /// using (register = Qubit(3)) { - /// ApplyToEach(ApplyIf(X, _, _), Zip(bitstring, register)); + /// ApplyToEach(ApplyIf(X, _, _), Zipped(bitstring, register)); /// // register should now be in the state |101⟩. /// ... /// } @@ -120,7 +120,7 @@ namespace Microsoft.Quantum.Canon { /// ```Q# /// let bitstring = [true, false, true]; /// using (register = Qubit(3)) { - /// ApplyToEach(ApplyIf(X, _, _), Zip(bitstring, register)); + /// ApplyToEach(ApplyIf(X, _, _), Zipped(bitstring, register)); /// // register should now be in the state |101⟩. /// ... /// } @@ -164,7 +164,7 @@ namespace Microsoft.Quantum.Canon { /// ```Q# /// let bitstring = [true, false, true]; /// using (register = Qubit(3)) { - /// ApplyToEach(ApplyIf(X, _, _), Zip(bitstring, register)); + /// ApplyToEach(ApplyIf(X, _, _), Zipped(bitstring, register)); /// // register should now be in the state |101⟩. /// ... /// } diff --git a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs index 7db8042d..26cdd7c7 100644 --- a/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs +++ b/Standard/src/Canon/Combinators/ApplyRepeatedOver.qs @@ -35,7 +35,7 @@ namespace Microsoft.Quantum.Canon { if (Length(listOfOps) != Length(targets)) { fail "The number of ops and number of targets do not match!"; } - for ((op, targetIndices) in Zip(listOfOps, targets)) { + for ((op, targetIndices) in Zipped(listOfOps, targets)) { if (Length(targetIndices) > Length(register)) { fail "There are too many targets!"; } @@ -69,7 +69,7 @@ namespace Microsoft.Quantum.Canon { if (Length(listOfOps) != Length(targets)) { fail "The number of ops and number of targets do not match!"; } - for ((op, targetIndices) in Zip(listOfOps, targets)) { + for ((op, targetIndices) in Zipped(listOfOps, targets)) { if (Length(targetIndices) > Length(register)) { fail "There are too many targets!"; } @@ -103,7 +103,7 @@ namespace Microsoft.Quantum.Canon { if (Length(listOfOps) != Length(targets)) { fail "The number of ops and number of targets do not match!"; } - for ((op, targetIndices) in Zip(listOfOps, targets)) { + for ((op, targetIndices) in Zipped(listOfOps, targets)) { if (Length(targetIndices) > Length(register)) { fail "There are too many targets!"; } @@ -137,7 +137,7 @@ namespace Microsoft.Quantum.Canon { if (Length(listOfOps) != Length(targets)) { fail "The number of ops and number of targets do not match!"; } - for ((op, targetIndices) in Zip(listOfOps, targets)) { + for ((op, targetIndices) in Zipped(listOfOps, targets)) { if (Length(targetIndices) > Length(register)) { fail "There are too many targets!"; } diff --git a/Standard/src/Canon/Combinators/ApplyToArray.qs b/Standard/src/Canon/Combinators/ApplyToArray.qs new file mode 100644 index 00000000..1d364e82 --- /dev/null +++ b/Standard/src/Canon/Combinators/ApplyToArray.qs @@ -0,0 +1,434 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Canon { + open Microsoft.Quantum.Arrays; + + /// # Summary + /// Applies an operation to the first element of an array. + /// + /// # Description + /// Given an operation `op` and an array of targets `targets`, + /// applies `op(Head(targets))`. + /// + /// # Input + /// ## op + /// An operation to be applied. + /// ## target + /// An array of targets, of which the first will be applied to `op`. + /// + /// # Type Parameters + /// ## 'T + /// The input type of the operation to be applied. + /// + /// # Example + /// The following Q# snippets are equivalent: + /// ```Q# + /// ApplyToHead(H, register); + /// H(Head(register)); + /// ``` + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyToHeadA + /// - Microsoft.Quantum.Canon.ApplyToHeadC + /// - Microsoft.Quantum.Canon.ApplyToHeadCA + operation ApplyToHead<'T>(op : ('T => Unit), targets : 'T[]) : Unit { + op(Head(targets)); + } + + /// # Summary + /// Applies an operation to the first element of an array. + /// + /// # Description + /// Given an operation `op` and an array of targets `targets`, + /// applies `op(Head(targets))`. + /// + /// # Input + /// ## op + /// An operation to be applied. + /// ## target + /// An array of targets, of which the first will be applied to `op`. + /// + /// # Type Parameters + /// ## 'T + /// The input type of the operation to be applied. + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyToHead + /// - Microsoft.Quantum.Canon.ApplyToHeadC + /// - Microsoft.Quantum.Canon.ApplyToHeadCA + operation ApplyToHeadA<'T>(op : ('T => Unit is Adj), targets : 'T[]) : Unit is Adj { + op(Head(targets)); + } + + /// # Summary + /// Applies an operation to the first element of an array. + /// + /// # Description + /// Given an operation `op` and an array of targets `targets`, + /// applies `op(Head(targets))`. + /// + /// # Input + /// ## op + /// An operation to be applied. + /// ## target + /// An array of targets, of which the first will be applied to `op`. + /// + /// # Type Parameters + /// ## 'T + /// The input type of the operation to be applied. + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyToHead + /// - Microsoft.Quantum.Canon.ApplyToHeadA + /// - Microsoft.Quantum.Canon.ApplyToHeadCA + operation ApplyToHeadC<'T>(op : ('T => Unit is Ctl), targets : 'T[]) : Unit is Ctl { + op(Head(targets)); + } + + /// # Summary + /// Applies an operation to the first element of an array. + /// + /// # Description + /// Given an operation `op` and an array of targets `targets`, + /// applies `op(Head(targets))`. + /// + /// # Input + /// ## op + /// An operation to be applied. + /// ## target + /// An array of targets, of which the first will be applied to `op`. + /// + /// # Type Parameters + /// ## 'T + /// The input type of the operation to be applied. + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyToHead + /// - Microsoft.Quantum.Canon.ApplyToHeadA + /// - Microsoft.Quantum.Canon.ApplyToHeadC + operation ApplyToHeadCA<'T>(op : ('T => Unit is Adj+Ctl), targets : 'T[]) : Unit is Adj+Ctl { + op(Head(targets)); + } + + /// # Summary + /// Applies an operation to all but the first element of an array. + /// + /// # Description + /// Given an operation `op` and an array of targets `targets`, + /// applies `op(Rest(targets))`. + /// + /// # Input + /// ## op + /// An operation to be applied. + /// ## target + /// An array of targets, of which all but the first will be applied to `op`. + /// + /// # Type Parameters + /// ## 'T + /// The input type of the operation to be applied. + /// + /// # Example + /// The following Q# snippets are equivalent: + /// ```Q# + /// ApplyToRest(ApplyCNOTChain, register); + /// ApplyCNOTChain(Rest(register)); + /// ``` + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyToRestA + /// - Microsoft.Quantum.Canon.ApplyToRestC + /// - Microsoft.Quantum.Canon.ApplyToRestCA + operation ApplyToRest<'T>(op : ('T[] => Unit), targets : 'T[]) : Unit { + op(Rest(targets)); + } + + /// # Summary + /// Applies an operation to all but the first element of an array. + /// + /// # Description + /// Given an operation `op` and an array of targets `targets`, + /// applies `op(Rest(targets))`. + /// + /// # Input + /// ## op + /// An operation to be applied. + /// ## target + /// An array of targets, of which all but the first will be applied to `op`. + /// + /// # Type Parameters + /// ## 'T + /// The input type of the operation to be applied. + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyToRest + /// - Microsoft.Quantum.Canon.ApplyToRestC + /// - Microsoft.Quantum.Canon.ApplyToRestCA + operation ApplyToRestA<'T>(op : ('T[] => Unit is Adj), targets : 'T[]) : Unit is Adj { + op(Rest(targets)); + } + + /// # Summary + /// Applies an operation to all but the first element of an array. + /// + /// # Description + /// Given an operation `op` and an array of targets `targets`, + /// applies `op(Rest(targets))`. + /// + /// # Input + /// ## op + /// An operation to be applied. + /// ## target + /// An array of targets, of which all but the first will be applied to `op`. + /// + /// # Type Parameters + /// ## 'T + /// The input type of the operation to be applied. + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyToRest + /// - Microsoft.Quantum.Canon.ApplyToRestA + /// - Microsoft.Quantum.Canon.ApplyToRestCA + operation ApplyToRestC<'T>(op : ('T[] => Unit is Ctl), targets : 'T[]) : Unit is Ctl { + op(Rest(targets)); + } + + /// # Summary + /// Applies an operation to all but the first element of an array. + /// + /// # Description + /// Given an operation `op` and an array of targets `targets`, + /// applies `op(Rest(targets))`. + /// + /// # Input + /// ## op + /// An operation to be applied. + /// ## target + /// An array of targets, of which all but the first will be applied to `op`. + /// + /// # Type Parameters + /// ## 'T + /// The input type of the operation to be applied. + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyToRest + /// - Microsoft.Quantum.Canon.ApplyToRestA + /// - Microsoft.Quantum.Canon.ApplyToRestC + operation ApplyToRestCA<'T>(op : ('T[] => Unit is Adj+Ctl), targets : 'T[]) : Unit is Adj+Ctl { + op(Rest(targets)); + } + + /// # Summary + /// Applies an operation to the last element of an array. + /// + /// # Description + /// Given an operation `op` and an array of targets `targets`, + /// applies `op(Tail(targets))`. + /// + /// # Input + /// ## op + /// An operation to be applied. + /// ## target + /// An array of targets, of which the last will be applied to `op`. + /// + /// # Type Parameters + /// ## 'T + /// The input type of the operation to be applied. + /// + /// # Example + /// The following Q# snippets are equivalent: + /// ```Q# + /// ApplyToTail(H, register); + /// H(Tail(register)); + /// ``` + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyToTailA + /// - Microsoft.Quantum.Canon.ApplyToTailC + /// - Microsoft.Quantum.Canon.ApplyToTailCA + operation ApplyToTail<'T>(op : ('T => Unit), targets : 'T[]) : Unit { + op(Tail(targets)); + } + + /// # Summary + /// Applies an operation to the last element of an array. + /// + /// # Description + /// Given an operation `op` and an array of targets `targets`, + /// applies `op(Tail(targets))`. + /// + /// # Input + /// ## op + /// An operation to be applied. + /// ## target + /// An array of targets, of which the last will be applied to `op`. + /// + /// # Type Parameters + /// ## 'T + /// The input type of the operation to be applied. + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyToTail + /// - Microsoft.Quantum.Canon.ApplyToTailC + /// - Microsoft.Quantum.Canon.ApplyToTailCA + operation ApplyToTailA<'T>(op : ('T => Unit is Adj), targets : 'T[]) : Unit is Adj { + op(Tail(targets)); + } + + /// # Summary + /// Applies an operation to the last element of an array. + /// + /// # Description + /// Given an operation `op` and an array of targets `targets`, + /// applies `op(Tail(targets))`. + /// + /// # Input + /// ## op + /// An operation to be applied. + /// ## target + /// An array of targets, of which the last will be applied to `op`. + /// + /// # Type Parameters + /// ## 'T + /// The input type of the operation to be applied. + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyToTail + /// - Microsoft.Quantum.Canon.ApplyToTailA + /// - Microsoft.Quantum.Canon.ApplyToTailCA + operation ApplyToTailC<'T>(op : ('T => Unit is Ctl), targets : 'T[]) : Unit is Ctl { + op(Tail(targets)); + } + + /// # Summary + /// Applies an operation to the last element of an array. + /// + /// # Description + /// Given an operation `op` and an array of targets `targets`, + /// applies `op(Tail(targets))`. + /// + /// # Input + /// ## op + /// An operation to be applied. + /// ## target + /// An array of targets, of which the last will be applied to `op`. + /// + /// # Type Parameters + /// ## 'T + /// The input type of the operation to be applied. + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyToTail + /// - Microsoft.Quantum.Canon.ApplyToTailA + /// - Microsoft.Quantum.Canon.ApplyToTailC + operation ApplyToTailCA<'T>(op : ('T => Unit is Adj+Ctl), targets : 'T[]) : Unit is Adj+Ctl { + op(Tail(targets)); + } + + /// # Summary + /// Applies an operation to all but the last element of an array. + /// + /// # Description + /// Given an operation `op` and an array of targets `targets`, + /// applies `op(Most(targets))`. + /// + /// # Input + /// ## op + /// An operation to be applied. + /// ## target + /// An array of targets, of which all but the last will be applied to `op`. + /// + /// # Type Parameters + /// ## 'T + /// The input type of the operation to be applied. + /// + /// # Example + /// The following Q# snippets are equivalent: + /// ```Q# + /// ApplyToMost(ApplyCNOTChain, register); + /// ApplyCNOTChain(Most(register)); + /// ``` + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyToMostA + /// - Microsoft.Quantum.Canon.ApplyToMostC + /// - Microsoft.Quantum.Canon.ApplyToMostCA + operation ApplyToMost<'T>(op : ('T[] => Unit), targets : 'T[]) : Unit { + op(Most(targets)); + } + + /// # Summary + /// Applies an operation to all but the last element of an array. + /// + /// # Description + /// Given an operation `op` and an array of targets `targets`, + /// applies `op(Most(targets))`. + /// + /// # Input + /// ## op + /// An operation to be applied. + /// ## target + /// An array of targets, of which all but the last will be applied to `op`. + /// + /// # Type Parameters + /// ## 'T + /// The input type of the operation to be applied. + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyToMost + /// - Microsoft.Quantum.Canon.ApplyToMostC + /// - Microsoft.Quantum.Canon.ApplyToMostCA + operation ApplyToMostA<'T>(op : ('T[] => Unit is Adj), targets : 'T[]) : Unit is Adj { + op(Most(targets)); + } + + /// # Summary + /// Applies an operation to all but the last element of an array. + /// + /// # Description + /// Given an operation `op` and an array of targets `targets`, + /// applies `op(Most(targets))`. + /// + /// # Input + /// ## op + /// An operation to be applied. + /// ## target + /// An array of targets, of which all but the last will be applied to `op`. + /// + /// # Type Parameters + /// ## 'T + /// The input type of the operation to be applied. + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyToMost + /// - Microsoft.Quantum.Canon.ApplyToMostA + /// - Microsoft.Quantum.Canon.ApplyToMostCA + operation ApplyToMostC<'T>(op : ('T[] => Unit is Ctl), targets : 'T[]) : Unit is Ctl { + op(Most(targets)); + } + + /// # Summary + /// Applies an operation to all but the last element of an array. + /// + /// # Description + /// Given an operation `op` and an array of targets `targets`, + /// applies `op(Most(targets))`. + /// + /// # Input + /// ## op + /// An operation to be applied. + /// ## target + /// An array of targets, of which all but the last will be applied to `op`. + /// + /// # Type Parameters + /// ## 'T + /// The input type of the operation to be applied. + /// + /// # See Also + /// - Microsoft.Quantum.Canon.ApplyToMost + /// - Microsoft.Quantum.Canon.ApplyToMostA + /// - Microsoft.Quantum.Canon.ApplyToMostC + operation ApplyToMostCA<'T>(op : ('T[] => Unit is Adj+Ctl), targets : 'T[]) : Unit is Adj+Ctl { + op(Most(targets)); + } +} diff --git a/Standard/src/Canon/Parity.qs b/Standard/src/Canon/Parity.qs index c0f0ced3..74e32a9b 100644 --- a/Standard/src/Canon/Parity.qs +++ b/Standard/src/Canon/Parity.qs @@ -23,7 +23,7 @@ namespace Microsoft.Quantum.Canon { /// ## qubits /// Array of qubits whose parity is to be computed and stored. operation ApplyCNOTChain(qubits : Qubit[]) : Unit is Adj + Ctl { - ApplyToEachCA(CNOT, Zip(Most(qubits), Rest(qubits))); + ApplyToEachCA(CNOT, Zipped(Most(qubits), Rest(qubits))); } /// # Summary diff --git a/Standard/src/Characterization/Distinguishability.qs b/Standard/src/Characterization/Distinguishability.qs index 6387314e..3c7b733c 100644 --- a/Standard/src/Characterization/Distinguishability.qs +++ b/Standard/src/Characterization/Distinguishability.qs @@ -206,7 +206,7 @@ namespace Microsoft.Quantum.Characterization { } apply { preparation1(target1); preparation2(target2); - ApplyToEachCA(Controlled SWAP([control], _), Zip(target1, target2)); + ApplyToEachCA(Controlled SWAP([control], _), Zipped(target1, target2)); } } diff --git a/Standard/src/Diagnostics/Facts.qs b/Standard/src/Diagnostics/Facts.qs index eaa4461c..f947a677 100644 --- a/Standard/src/Diagnostics/Facts.qs +++ b/Standard/src/Diagnostics/Facts.qs @@ -207,7 +207,7 @@ namespace Microsoft.Quantum.Diagnostics { FormattedFailure(actual, expected, message); } - Ignore(Mapped(EqualityFactB(_, _, message), Zip(actual, expected))); + Ignore(Mapped(EqualityFactB(_, _, message), Zipped(actual, expected))); } /// # Summary @@ -229,7 +229,7 @@ namespace Microsoft.Quantum.Diagnostics { FormattedFailure(actual, expected, message); } - Ignore(Mapped(EqualityFactI(_, _, message), Zip(actual, expected))); + Ignore(Mapped(EqualityFactI(_, _, message), Zipped(actual, expected))); } } diff --git a/Standard/src/Logical/Comparisons.qs b/Standard/src/Logical/Comparisons.qs new file mode 100644 index 00000000..d0e4a153 --- /dev/null +++ b/Standard/src/Logical/Comparisons.qs @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Logical { + open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Canon; + + /// # Summary + /// Given a comparison function, returns a new function that + /// lexographically compares two arrays. + /// + /// # Type Parameters + /// ## 'T + /// The type of the elements of the arrays being compared. + /// + /// # Input + /// ## elementComparison + /// A function that compares two elements `x` and `y` and returns if + /// `x` is less than or equal to `y`. + /// + /// # Output + /// A function that compares two arrays `xs` and `ys` and returns if + /// `xs` occurs before or equal to `ys` in lexographical ordering. + /// + /// # Remarks + /// The lexographic comparison between two arrays `xs` and `ys` is defined + /// by the following procedure. We say that two elements `x` and `y` + /// are equivalent if `elementComparison(x, y)` and `elementComparison(y, x)` + /// are both true. + /// + /// - Both arrays are compared element-by-element until the first pair of + /// elements that are not equivalent. The array containing the element + /// that occurs first according to `elementComparison` is said to occur + /// first in lexographical ordering. + /// - If no inequivalent elements are found, and one array is longer than + /// the other, the shorter array is said to occur first. + /// + /// # Examples + /// ```Q# + /// let arrayComparison = LexographicComparison(LessThanOrEqualD); + /// let data = [ + /// [1.1, 2.2, 3.3], + /// [1.1, 2.2], + /// [0.2, 2.2], + /// [1.1, 2.7] + /// ]; + /// let sorted = Sorted(arrayComparison, data); + /// // sorted: + /// // [ + /// // [0.2, 2.2], + /// // [1.1, 2.2], + /// // [1.1, 2.2, 3.3], + /// // [1.1, 2.7] + /// // ]; + /// ``` + /// + /// # See Also + /// - Microsoft.Quantum.Arrays.Sorted + function LexographicComparison<'T>(elementComparison : (('T, 'T) -> Bool)) : (('T[], 'T[]) -> Bool) { + return LessThanLexographic(elementComparison, _, _); + } + + /// # Summary + /// Used to implement `LexographicComparison`. + internal function LessThanLexographic<'T>(comparison : (('T, 'T) -> Bool), left : 'T[], right : 'T[]) : Bool { + for ((l, r) in Zipped(left, right)) { + let lessThanOrEqual = comparison(l, r); + let greaterThanOrEqual = comparison(r, l); + let equal = lessThanOrEqual and greaterThanOrEqual; + if (lessThanOrEqual and not equal) { + return true; + } elif (greaterThanOrEqual and not equal) { + return false; + } + } + + // At this point, all items in the common prefix of both arrays + // are equal to each other under comparison (l ≤ r and r ≤ l). + // Thus, if left is shorter than or equal to right, then left occurs + // at or before right in lexographical ordering. + return Length(left) <= Length(right); + } + +} diff --git a/Standard/src/Preparation/Reference.qs b/Standard/src/Preparation/Reference.qs index 9203f043..74564a6c 100644 --- a/Standard/src/Preparation/Reference.qs +++ b/Standard/src/Preparation/Reference.qs @@ -22,7 +22,7 @@ namespace Microsoft.Quantum.Preparation { fail $"Left and right registers must be the same length."; } - for ((leftQubit, rightQubit) in Zip(left, right)) { + for ((leftQubit, rightQubit) in Zipped(left, right)) { H(leftQubit); Controlled X([leftQubit], rightQubit); } diff --git a/Standard/src/Synthesis/DecompositionBased.qs b/Standard/src/Synthesis/DecompositionBased.qs index 3ad114f4..26a55f05 100644 --- a/Standard/src/Synthesis/DecompositionBased.qs +++ b/Standard/src/Synthesis/DecompositionBased.qs @@ -279,7 +279,7 @@ namespace Microsoft.Quantum.Synthesis { let register = qubits!; for ((func, target) in TruthTablesFromPermutation(perm, variableOrder)) { - ApplyXControlledOnTruthTable(func, Exclude([target], register), register[target]); + ApplyXControlledOnTruthTable(func, Excluding([target], register), register[target]); } } } diff --git a/Standard/src/Synthesis/Transposition.qs b/Standard/src/Synthesis/Transposition.qs index 9f7c1a81..08c93b6f 100644 --- a/Standard/src/Synthesis/Transposition.qs +++ b/Standard/src/Synthesis/Transposition.qs @@ -54,11 +54,11 @@ namespace Microsoft.Quantum.Synthesis { within { for (target in Most(diff)) { - (BitControlledX(bbits[...target - 1] + abits[target + 1...]))(Exclude([target], qs), qs[target]); + (BitControlledX(bbits[...target - 1] + abits[target + 1...]))(Excluding([target], qs), qs[target]); } } apply { let target = Tail(diff); - (BitControlledX(bbits[...target - 1] + abits[target + 1...]))(Exclude([target], qs), qs[target]); + (BitControlledX(bbits[...target - 1] + abits[target + 1...]))(Excluding([target], qs), qs[target]); } } } diff --git a/Standard/tests/ArrayTests.qs b/Standard/tests/ArrayTests.qs index 5dbadf4d..3aa1b38b 100644 --- a/Standard/tests/ArrayTests.qs +++ b/Standard/tests/ArrayTests.qs @@ -1,18 +1,19 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Microsoft.Quantum.Tests { - open Microsoft.Quantum.Logical; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Canon; - open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Logical; + open Microsoft.Quantum.Math; @Test("QuantumSimulator") - function ZipTest() : Unit { + function TestZipped() : Unit { let left = [1, 2, 101]; let right = [PauliY, PauliI]; - let zipped = Zip(left, right); + let zipped = Zipped(left, right); let (leftActual1, rightActual1) = zipped[0]; if (leftActual1 != 1 or rightActual1 != PauliY) { @@ -26,9 +27,19 @@ namespace Microsoft.Quantum.Tests { } } + @Test("QuantumSimulator") + function TestUnzipped() : Unit { + let first = [6, 5, 5, 3, 2, 1]; + let second = [true, false, false, false, true, false]; + + let (first2, second2) = Unzipped(Zipped(first, second)); + AllEqualityFactI(first2, first, "Unexpected array of integers"); + AllEqualityFactB(second2, second, "Unexpected array of Booleans"); + } + @Test("QuantumSimulator") - function LookupTest () : Unit { + function TestLookup() : Unit { let array = [1, 12, 71, 103]; let fn = LookupFunction(array); @@ -41,21 +52,21 @@ namespace Microsoft.Quantum.Tests { } internal function AllEqualI(expected : Int[], actual : Int[]) : Bool { - return All(EqualI, Zip(expected, actual)); + return All(EqualI, Zipped(expected, actual)); } @Test("QuantumSimulator") - function ChunksTest() : Unit { + function TestChunks() : Unit { let data = [10, 11, 12, 13, 14, 15]; // 2 × 3 case. - Fact(All(AllEqualI, Zip( + Fact(All(AllEqualI, Zipped( [[10, 11], [12, 13], [14, 15]], Chunks(2, data) )), "Wrong chunks in 2x3 case."); // Case with some leftovers. - Fact(All(AllEqualI, Zip( + Fact(All(AllEqualI, Zipped( [[10, 11, 12, 13], [14, 15]], Chunks(4, data) )), "Wrong chunks in case with leftover elements."); @@ -65,13 +76,15 @@ namespace Microsoft.Quantum.Tests { return x * x; } - - function ConstantArrayTest () : Unit { - + @Test("QuantumSimulator") + function ConstantArrayOfDoublesIsCorrect() : Unit { let dblArray = ConstantArray(71, 2.17); EqualityFactI(Length(dblArray), 71, $"ConstantArray(Int, Double) had the wrong length."); let ignore = Mapped(NearEqualityFactD(_, 2.17), dblArray); + } + @Test("QuantumSimulator") + function ConstantArrayOfFunctionsIsCorrect() : Unit { // Stress test by making an array of Int -> Int. let fnArray = ConstantArray(7, Squared); EqualityFactI(Length(fnArray), 7, $"ConstantArray(Int, Int -> Int) had the wrong length."); @@ -80,36 +93,40 @@ namespace Microsoft.Quantum.Tests { function SubarrayTest () : Unit { - let array0 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let subarrayOdd = Subarray([1, 3, 5, 7, 9], array0); let subarrayEven = Subarray([0, 2, 4, 6, 8, 10], array0); Fact(All(IsEven, subarrayEven), $"the even elements of [1..10] were not correctly sliced."); Fact(not Any(IsEven, subarrayOdd), $"the odd elements of [1..10] were not correctly sliced."); let array1 = [10, 11, 12, 13]; - Ignore(Mapped(EqualityFactI(_, _, $"Subarray failed: subpermutation case."), Zip([12, 11], Subarray([2, 1], array1)))); + Ignore(Mapped(EqualityFactI(_, _, $"Subarray failed: subpermutation case."), Zipped([12, 11], Subarray([2, 1], array1)))); } - - function FilterTest () : Unit { - + @Test("QuantumSimulator") + function FilteredIsEvenHasNoOdds() : Unit { let array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let evenArray = Filtered(IsEven, array); - EqualityFactB(All(IsEven, evenArray), true, $"the even elements of [1..10] were not correctly filtered."); + Fact(All(IsEven, evenArray), $"the even elements of [1..10] were not correctly filtered."); + } + + @Test("QuantumSimulator") + function CountOfIsEvenIsCorrect() : Unit { + let array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let countEvens = Count(IsEven, array); + EqualityFactI(countEvens, 5, $"the even elements of [1..10] were not correctly counted."); } function ReverseTest () : Unit { let array = [1, 2, 3]; - Ignore(Mapped(EqualityFactI(_, _, $"Reversed failed."), Zip([3, 2, 1], Reversed(array)))); + Ignore(Mapped(EqualityFactI(_, _, $"Reversed failed."), Zipped([3, 2, 1], Reversed(array)))); } - function ExcludeTest () : Unit { - + function ExcludingTest () : Unit { let array = [10, 11, 12, 13, 14, 15]; - Ignore(Mapped(EqualityFactI(_, _, $"Exclude failed."), Zip([10, 11, 13, 14], Exclude([2, 5], array)))); + Ignore(Mapped(EqualityFactI(_, _, $"Excluding failed."), Zipped([10, 11, 13, 14], Excluding([2, 5], array)))); } @@ -120,7 +137,7 @@ namespace Microsoft.Quantum.Tests { for (idxTest in IndexRange(arrayTestCase)) { let (nElementsTotal, defaultElement, inputArray, outputArray) = arrayTestCase[idxTest]; let paddedArray = Padded(nElementsTotal, defaultElement, inputArray); - Ignore(Mapped(EqualityFactI(_, _, $"Padded failed."), Zip(outputArray, paddedArray))); + Ignore(Mapped(EqualityFactI(_, _, $"Padded failed."), Zipped(outputArray, paddedArray))); } } @@ -129,7 +146,7 @@ namespace Microsoft.Quantum.Tests { let expected = [(0, 37), (1, 12)]; let actual = Enumerated(example); - for ((actualElement, expectedElement) in Zip(actual, expected)) { + for ((actualElement, expectedElement) in Zipped(actual, expected)) { EqualityFactI(Fst(actualElement), Fst(expectedElement), "Indices did not match."); EqualityFactI(Snd(actualElement), Snd(expectedElement), "Elements did not match."); } @@ -140,9 +157,9 @@ namespace Microsoft.Quantum.Tests { let expected = [[0, 1, 2, 3], [23, 24, 25, 26, 27, 28, 29], [-5, -4, -3, -2]]; let actual = Mapped(SequenceI, example); - for ((exp, act) in Zip(expected, actual)) { + for ((exp, act) in Zipped(expected, actual)) { EqualityFactI(Length(exp), Length(act), "Lengths of arrays did not match."); - for ((i, j) in Zip(exp, act)) { + for ((i, j) in Zipped(exp, act)) { EqualityFactI(i, j, "Elements did not match."); } } @@ -153,9 +170,9 @@ namespace Microsoft.Quantum.Tests { let expected = [[0L, 1L, 2L, 3L], [23L, 24L, 25L, 26L, 27L, 28L, 29L], [-5L, -4L, -3L, -2L]]; let actual = Mapped(SequenceL, example); - for ((exp, act) in Zip(expected, actual)) { + for ((exp, act) in Zipped(expected, actual)) { EqualityFactI(Length(exp), Length(act), "Lengths of arrays did not match."); - for ((i, j) in Zip(exp, act)) { + for ((i, j) in Zipped(exp, act)) { EqualityFactL(i, j, "Elements did not match."); } } @@ -166,9 +183,9 @@ namespace Microsoft.Quantum.Tests { let expected = [[0, 1, 2, 3], [0, 1, 2, 3, 4, 5], [0]]; let actual = Mapped(SequenceI(0, _), example); - for ((exp, act) in Zip(expected, actual)) { + for ((exp, act) in Zipped(expected, actual)) { EqualityFactI(Length(exp), Length(act), "Lengths of arrays did not match."); - for ((i, j) in Zip(exp, act)) { + for ((i, j) in Zipped(exp, act)) { EqualityFactI(i, j, "Elements did not match."); } } @@ -188,7 +205,7 @@ namespace Microsoft.Quantum.Tests { let actual = _SwapOrderToPermuteArray(newOrder); EqualityFactI(Length(expected), Length(actual), "Number of swaps does not match"); - for ((exp, act) in Zip(expected, actual)) { + for ((exp, act) in Zipped(expected, actual)) { let (leftExp, rightExp) = exp; let (leftAct, rightAct) = act; @@ -205,7 +222,7 @@ namespace Microsoft.Quantum.Tests { let newArray = Swapped(leftIndex, rightIndex, example); EqualityFactI(Length(expected), Length(newArray), "Swapped array is a different size than original"); - for ((exp, act) in Zip(expected, newArray)) { + for ((exp, act) in Zipped(expected, newArray)) { EqualityFactI(exp, act, "Elements did not match"); } } @@ -216,8 +233,8 @@ namespace Microsoft.Quantum.Tests { 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)) { + for ((exp, act) in Zipped(expected, actual)) { + for ((elementExp, elementAct) in Zipped(exp, act)) { EqualityFactI(elementExp, elementAct, "Elements did not match"); } } @@ -237,6 +254,109 @@ namespace Microsoft.Quantum.Tests { let differentElements = EqualA(EqualR, [One, Zero], [One, One]); Fact(not differentElements, "Arrays with different elements were reported as equal"); } + + @Test("QuantumSimulator") + operation TestInterleaved() : Unit { + AllEqualityFactI(Interleaved([1, 2, 3], [-1, -2, -3]), [1, -1, 2, -2, 3, -3], "Interleaving failed"); + AllEqualityFactB(Interleaved(ConstantArray(3, false), ConstantArray(2, true)), [false, true, false, true, false], "Interleaving failed"); + } + + @Test("QuantumSimulator") + operation TestCumulativeFolded() : Unit { + AllEqualityFactI(CumulativeFolded(PlusI, 0, SequenceI(1, 5)), [1, 3, 6, 10, 15], "CumulativeFolded failed"); + } + + @Test("QuantumSimulator") + operation TestTransposed() : Unit { + for ((actual, expected) in Zipped(Transposed([[1, 2, 3], [4, 5, 6]]), [[1, 4], [2, 5], [3, 6]])) { + AllEqualityFactI(actual, expected, "Transposed failed"); + } + } + + @Test("QuantumSimulator") + operation TestColumnAt() : Unit { + let matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; + AllEqualityFactI(ColumnAt(0, matrix), [1, 4, 7], "ColumnAt failed"); + AllEqualityFactI(ColumnAt(1, matrix), [2, 5, 8], "ColumnAt failed"); + AllEqualityFactI(ColumnAt(2, matrix), [3, 6, 9], "ColumnAt failed"); + } + + @Test("QuantumSimulator") + operation TestElementAt() : Unit { + let lucas = [2, 1, 3, 4, 7, 11, 18, 29, 47, 76]; + let prime = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]; + let fibonacci = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]; + let catalan = [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862]; + let famous2 = Mapped(ElementAt(2, _), [lucas, prime, fibonacci, catalan]); + AllEqualityFactI(famous2, [3, 5, 1, 2], "ElementAt failed"); + } + + @Test("QuantumSimulator") + operation TestElementsAt() : Unit { + let lucas = [2, 1, 3, 4, 7, 11, 18, 29, 47, 76]; + let prime = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]; + let fibonacci = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]; + let catalan = [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862]; + let famousOdd = Mapped(ElementsAt(0..2..9, _), [lucas, prime, fibonacci, catalan]); + for ((actual, expected) in Zipped(famousOdd, [[2, 3, 7, 18, 47], [2, 5, 11, 17, 23], [0, 1, 3, 8, 21], [1, 2, 14, 132, 1430]])) { + AllEqualityFactI(actual, expected, "ElementsAt failed"); + } + } + + @Test("QuantumSimulator") + operation TestDiagonal() : Unit { + AllEqualityFactI(Diagonal([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), [1, 5, 9], "Diagonal failed"); + AllEqualityFactI(Diagonal([[1, 2, 3], [4, 5, 6]]), [1, 5], "Diagonal failed"); + AllEqualityFactI(Diagonal([[1, 2], [4, 5], [7, 8]]), [1, 5], "Diagonal failed"); + } + + @Test("QuantumSimulator") + operation TestWindows() : Unit { + let EqualIntA = EqualA(EqualI, _, _); + let EqualIntAA = EqualA(EqualIntA, _, _); + + Fact(EqualIntAA(Windows(-1, [1, 2, 3]), new Int[][0]), "unexpected windows"); + Fact(EqualIntAA(Windows(0, [1, 2, 3]), new Int[][0]), "unexpected windows"); + Fact(EqualIntAA(Windows(1, [1, 2, 3]), [[1], [2], [3]]), "unexpected windows"); + Fact(EqualIntAA(Windows(2, [1, 2, 3]), [[1, 2], [2, 3]]), "unexpected windows"); + Fact(EqualIntAA(Windows(3, [1, 2, 3]), [[1, 2, 3]]), "unexpected windows"); + Fact(EqualIntAA(Windows(4, [1, 2, 3]), new Int[][0]), "unexpected windows"); + } + + @Test("QuantumSimulator") + operation TestPrefixes() : Unit { + let array = [0, 1, 1, 2, 3, 5]; + let prefixes = Prefixes(array); + + EqualityFactI(Length(prefixes), Length(array), "unexpected length for prefixes"); + AllEqualityFactI(prefixes[0], [0], "unexpected prefix"); + AllEqualityFactI(prefixes[1], [0, 1], "unexpected prefix"); + AllEqualityFactI(prefixes[2], [0, 1, 1], "unexpected prefix"); + AllEqualityFactI(prefixes[3], [0, 1, 1, 2], "unexpected prefix"); + AllEqualityFactI(prefixes[4], [0, 1, 1, 2, 3], "unexpected prefix"); + AllEqualityFactI(prefixes[5], [0, 1, 1, 2, 3, 5], "unexpected prefix"); + } + + @Test("QuantumSimulator") + operation TestSuccessfulRectangularFact() : Unit { + RectangularArrayFact([[1, 2], [3, 4]], "Array is not rectangular"); + RectangularArrayFact([[1, 2, 3], [4, 5, 6]], "Array is not rectangular"); + } + + operation RectangularFactTestShouldFail() : Unit { + RectangularArrayFact([[1, 2], [3, 4, 5]], "Array is not rectangular"); + } + + @Test("QuantumSimulator") + operation TestSuccessfulSquareFact() : Unit { + SquareArrayFact([[1, 2], [3, 4]], "Array is not a square"); + } + + operation SquareFact1TestShouldFail() : Unit { + SquareArrayFact([[1, 2, 3], [4, 5, 6]], "Array is not a square"); + } + + operation SquareFact2TestShouldFail() : Unit { + SquareArrayFact([[1, 2], [3, 4, 5]], "Array is not a square"); + } } - - diff --git a/Standard/tests/Arrays/SortedTests.qs b/Standard/tests/Arrays/SortedTests.qs new file mode 100644 index 00000000..a0dbc5fd --- /dev/null +++ b/Standard/tests/Arrays/SortedTests.qs @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Arrays { + open Microsoft.Quantum.Random; + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Logical; + + @Test("QuantumSimulator") + function IntsAreSorted() : Unit { + Fact(IsSorted(LessThanOrEqualI, [1, 10, 100]), "[1, 10, 100] was marked as unsorted."); + } + + @Test("QuantumSimulator") + function DoublesAreSorted() : Unit { + Fact(IsSorted(LessThanOrEqualD, [1.0, 10.1, 100.2]), "[1.0, 10.1, 100.2] was marked as unsorted."); + } + + @Test("QuantumSimulator") + function IntsAreNotSorted() : Unit { + Contradiction(IsSorted(LessThanOrEqualI, [100, 10, 3]), "[100, 10, 3] was marked as sorted."); + } + + @Test("QuantumSimulator") + function SortedIntsAreSorted() : Unit { + Fact(IsSorted(LessThanOrEqualI, + Sorted(LessThanOrEqualI, [100, 10, 3])), + "Sorted(<=, [100, 10, 3]) was marked as unsorted." + ); + } + + @Test("QuantumSimulator") + function SortedDoublesAreSorted() : Unit { + Fact(IsSorted(LessThanOrEqualD, + Sorted(LessThanOrEqualD, [100.0, 10.1, 3.14])), + "Sorted(<=, [100.0, 10.1, 3.14]) was marked as unsorted." + ); + } + + @Test("QuantumSimulator") + operation CheckRandomArraysAreSortedWhenSorted() : Unit { + let nItems = 100; + let nTrials = 10; + let maxItem = 1000; + for (_ in 0..nTrials - 1) { + let data = DrawMany((DiscreteUniformDistribution(0, maxItem))::Sample, nItems, ()); + Fact(IsSorted(LessThanOrEqualI, Sorted(LessThanOrEqualI, data)), $"{data} was not sorted after running Sorted."); + } + } + + @Test("QuantumSimulator") + function LexographicSortIsCorrect() : Unit { + let arrayComparison = LexographicComparison(LessThanOrEqualI); + let data = [ + [1, 2, 3], + [1, 2], + [0, 2], + [1, 3] + ]; + let sorted = Sorted(arrayComparison, data); + + AllEqualityFactI( + sorted[0], [0, 2], "0th item was not correct." + ); + AllEqualityFactI( + sorted[1], [1, 2], "1st item was not correct." + ); + AllEqualityFactI( + sorted[2], [1, 2, 3], "2nd item was not correct." + ); + AllEqualityFactI( + sorted[3], [1, 3], "3rd item was not correct." + ); + } + +} diff --git a/Standard/tests/Arrays/UniqueTests.qs b/Standard/tests/Arrays/UniqueTests.qs new file mode 100644 index 00000000..4309359b --- /dev/null +++ b/Standard/tests/Arrays/UniqueTests.qs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Arrays { + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Logical; + + @Test("QuantumSimulator") + operation UniqueInts() : Unit { + AllEqualityFactI(Unique(EqualI, [0, 0, 1, 2, 2, 3, 4, 5, 5, 8, 42, 42, 39]), [0, 1, 2, 3, 4, 5, 8, 42, 39], "Data is not unique"); + AllEqualityFactI(Unique(EqualI, [0, 1, 1, 0, 0, 1, 1, 0]), [0, 1, 0, 1, 0], "Data is not unique"); + AllEqualityFactI(Unique(EqualI, Sorted(LessThanOrEqualI, [2, 2, 1, 1, 2, 2, 1, 1])), [1, 2], "Sorted data is not unique"); + } + + @Test("QuantumSimulator") + operation UniqueDoubles() : Unit { + let unique = Unique(EqualD, [1.1, 1.1, 2.2, 2.2, 2.2, 3.3, 0.5, 42.0]); + EqualityFactI(Length(unique), 5, "Unexpected length of unique data"); + Fact(unique[0] == 1.1, "Unexpected element in unique data"); + Fact(unique[1] == 2.2, "Unexpected element in unique data"); + Fact(unique[2] == 3.3, "Unexpected element in unique data"); + Fact(unique[3] == 0.5, "Unexpected element in unique data"); + Fact(unique[4] == 42.0, "Unexpected element in unique data"); + } +} diff --git a/Standard/tests/CombinatorTests.qs b/Standard/tests/CombinatorTests.qs index 9834abae..ad06f180 100644 --- a/Standard/tests/CombinatorTests.qs +++ b/Standard/tests/CombinatorTests.qs @@ -134,14 +134,14 @@ namespace Microsoft.Quantum.Tests { operation CControlledActual (op : (Qubit => Unit), target : Qubit[]) : Unit { - ApplyToEach(CControlled(op), Zip([true, false, true], target)); + ApplyToEach(CControlled(op), Zipped([true, false, true], target)); } operation CControlledActualC (op : (Qubit => Unit is Ctl), target : Qubit[]) : Unit { body (...) { - ApplyToEachC(CControlledC(op), Zip([true, false, true], target)); + ApplyToEachC(CControlledC(op), Zipped([true, false, true], target)); } controlled distribute; @@ -151,7 +151,7 @@ namespace Microsoft.Quantum.Tests { operation CControlledActualA (op : (Qubit => Unit is Adj), target : Qubit[]) : Unit { body (...) { - ApplyToEachA(CControlledA(op), Zip([true, false, true], target)); + ApplyToEachA(CControlledA(op), Zipped([true, false, true], target)); } adjoint invert; @@ -161,7 +161,7 @@ namespace Microsoft.Quantum.Tests { operation CControlledActualCA (op : (Qubit => Unit is Adj + Ctl), target : Qubit[]) : Unit { body (...) { - ApplyToEachCA(CControlledCA(op), Zip([true, false, true], target)); + ApplyToEachCA(CControlledCA(op), Zipped([true, false, true], target)); } adjoint invert; diff --git a/Standard/tests/EnumerationTests.qs b/Standard/tests/EnumerationTests.qs index 48e23694..5e9db499 100644 --- a/Standard/tests/EnumerationTests.qs +++ b/Standard/tests/EnumerationTests.qs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Microsoft.Quantum.Tests { open Microsoft.Quantum.Math; @@ -59,6 +59,33 @@ namespace Microsoft.Quantum.Tests { EqualityFactI(Fold(Add, 0, squaredArray), 30, $"the sum of the squares of [1, 2, 3, 4] was not found to be 30."); } + @Test("QuantumSimulator") + function TestMappedOverNonEmptyRange() : Unit { + AllEqualityFactI(MappedOverRange(PlusI(_, 2), 1..5), [3, 4, 5, 6, 7], "MappedOverRange failed."); + } + + @Test("QuantumSimulator") + function TestMappedOverReversedRange() : Unit { + AllEqualityFactI(MappedOverRange(TimesI(_, 2), 4..-2..-4), [8, 4, 0, -4, -8], "MappedOverRange failed."); + } + + @Test("QuantumSimulator") + function TestMappedOverEmpty() : Unit { + AllEqualityFactI(MappedOverRange(TimesI(_, 2), 1..-1..2), new Int[0], "MappedOverRange failed."); + } + + @Test("QuantumSimulator") + function TestFlatMapped() : Unit { + let numbers = FlatMapped(SequenceI(1, _), SequenceI(1, 5)); + AllEqualityFactI(numbers, [1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5], "FlatMapped failed"); + } + + @Test("QuantumSimulator") + function TestFlattened() : Unit { + let numbers = Flattened(ConstantArray(3, SequenceI(1, 3))); + AllEqualityFactI(numbers, [1, 2, 3, 1, 2, 3, 1, 2, 3], "Flattened failed"); + } + function ExtremaTest () : Unit { let array = [-10, 10, 7, 0]; EqualityFactI(-10, Min(array), $"Min failed."); diff --git a/Standard/tests/Logical/ComparisonTests.qs b/Standard/tests/Logical/ComparisonTests.qs new file mode 100644 index 00000000..9afd776c --- /dev/null +++ b/Standard/tests/Logical/ComparisonTests.qs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Tests { + open Microsoft.Quantum.Logical; + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Math; + open Microsoft.Quantum.Arrays; + + function LexographicComparisonIsCorrect() : Unit { + let lexographicComparison = LexographicComparison(LessThanOrEqualD); + Fact( + lexographicComparison( + [1.1, 2.2], [1.1, 2.2, 3.3] + ), + "Shorter array should have occured first." + ); + Fact( + lexographicComparison( + [0.7, 2.2], [1.1, 2.2] + ), + "Array with smaller first element should have occured first." + ); + Fact( + lexographicComparison( + [1.1, 2.2], [1.1, 2.2] + ), + "Identical arrays should be marked as less than or equal." + ); + Contradiction( + lexographicComparison( + [1.1, 2.7], [1.1, 2.2, 3.3] + ), + "Array with larger second element should have occured second." + ); + } + +} diff --git a/Standard/tests/QubitizationTests.qs b/Standard/tests/QubitizationTests.qs index ef418797..ff3f330e 100644 --- a/Standard/tests/QubitizationTests.qs +++ b/Standard/tests/QubitizationTests.qs @@ -145,7 +145,7 @@ namespace Microsoft.Quantum.Tests { for (idxTest in IndexRange(testCases)) { let (expected, range) = testCases[idxTest]; let output = RangeAsIntArray(range); - Ignore(Mapped(EqualityFactI(_, _, "Padded failed."), Zip(output, expected))); + Ignore(Mapped(EqualityFactI(_, _, "Padded failed."), Zipped(output, expected))); } }