From b94ec8c2dcc26b9afe763e2961218b15a1e7cac3 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Tue, 25 Aug 2020 15:56:26 +0200 Subject: [PATCH 01/11] Cleanup QuantumROM. --- Standard/src/Preparation/QuantumROM.qs | 8 ------ Standard/tests/QuantumROMTests.qs | 36 ++++++++++++++------------ 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/Standard/src/Preparation/QuantumROM.qs b/Standard/src/Preparation/QuantumROM.qs index 96108141b5a..d0f3623aa25 100644 --- a/Standard/src/Preparation/QuantumROM.qs +++ b/Standard/src/Preparation/QuantumROM.qs @@ -95,14 +95,6 @@ namespace Microsoft.Quantum.Preparation { return (nTotal, (nBitsIndices, nGarbageQubits)); } - // Implementation step of `QuantumROM`. This splits a single - // qubit array into the subarrays required by the operation. - function _QuantumROMQubitManager(targetError: Double, nCoeffs: Int, qubits: Qubit[]) : ((LittleEndian, Qubit[]), Qubit[]) { - let (nTotal, (nIndexRegister, nGarbageQubits)) = QuantumROMQubitCount(targetError, nCoeffs); - let registers = Partitioned([nIndexRegister, nGarbageQubits], qubits); - return((LittleEndian(registers[0]), registers[1]), registers[2]); - } - // Classical processing // This discretizes the coefficients such that // |coefficient[i] * oneNorm - discretizedCoefficient[i] * discreizedOneNorm| * nCoeffs <= 2^{1-bitsPrecision}. diff --git a/Standard/tests/QuantumROMTests.qs b/Standard/tests/QuantumROMTests.qs index 2768277ea53..4a1da7ebdad 100644 --- a/Standard/tests/QuantumROMTests.qs +++ b/Standard/tests/QuantumROMTests.qs @@ -3,6 +3,7 @@ namespace Microsoft.Quantum.Tests { + open Microsoft.Quantum.Arithmetic; open Microsoft.Quantum.Arrays; open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Canon; @@ -64,34 +65,37 @@ namespace Microsoft.Quantum.Tests { } } - operation QuantumROMTest() : Unit { + @Test("QuantumSimulator") + operation TestQuantumROM() : Unit { for(coeffs in 2..7){ for(nBitsPrecision in -1..-1..-2){ let targetError = PowD(2.0, IntAsDouble(nBitsPrecision)); let probtargetError = targetError / IntAsDouble(coeffs); let coefficients = DrawMany(DrawRandomDouble, coeffs, (0.0, 1.0)); let ((nTotal, (nCoeffQubits, nGarbageQubits)), oneNorm, op) = QuantumROM(targetError, coefficients); + Message($"Test case coeffs {coeffs}, bitsPrecision {nCoeffQubits}, global targetError {targetError}, probability error {probtargetError}."); - for (idx in 0..coeffs-1) - { - let tmp = AbsD(coefficients[idx]) / oneNorm; + for ((idx, coefficient) in Enumerated(coefficients)) { + let tmp = AbsD(coefficient) / oneNorm; Message($"{idx} expected prob = {tmp}."); } Message($"Qubits used: {nGarbageQubits} + {nCoeffQubits}"); - using(qubits = Qubit[nTotal]){ - let (register, rest) = _QuantumROMQubitManager(targetError, coeffs, qubits); - let (coeffQubits, garbageQubits) = register; - op(register); - // Now check that probability of each number state in nCoeffQubits is as expected. - for(stateIndex in 0..coeffs-1){ - let prob = AbsD(coefficients[stateIndex]) / oneNorm; - Message($"Testing probability {prob} on index {stateIndex}"); - //BAssertProbIntBE(stateIndex, AbsD(coefficients[stateIndex]) / oneNorm, BigEndian(coeffQubits), targetError / IntAsDouble(coeffs)); - } - - (Adjoint op)(register); + using ((coeffRegister, garbageQubits) = (Qubit[nCoeffQubits], Qubit[nGarbageQubits])) { + let coeffQubits = LittleEndian(coeffRegister); + // Check that probability of each number state in nCoeffQubits is as expected. + within { + op(coeffQubits, garbageQubits); + } apply { + for (stateIndex in 0..coeffs - 1) { + let prob = AbsD(coefficients[stateIndex]) / oneNorm; + // FIXME: this only works for stateIndex == 0; why? + if (stateIndex == 0) { + AssertProbInt(stateIndex, prob, coeffQubits, probtargetError); + } + } + } } } } From 860c0ab12a0fac8a1d053bd6118897761bc547fa Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Wed, 26 Aug 2020 09:21:21 +0200 Subject: [PATCH 02/11] Cleanup uniform superposition. --- .../src/Preparation/UniformSuperposition.qs | 44 ++++++++-------- .../UniformSuperpositionPreparationTests.qs | 51 ++++++------------- 2 files changed, 37 insertions(+), 58 deletions(-) diff --git a/Standard/src/Preparation/UniformSuperposition.qs b/Standard/src/Preparation/UniformSuperposition.qs index 177c43dcef9..a4d3773cd49 100644 --- a/Standard/src/Preparation/UniformSuperposition.qs +++ b/Standard/src/Preparation/UniformSuperposition.qs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Microsoft.Quantum.Preparation { @@ -39,23 +39,24 @@ namespace Microsoft.Quantum.Preparation { /// PrepareUniformSuperposition(nIndices, LittleEndian(indexRegister)); /// } /// ``` - operation PrepareUniformSuperposition(nIndices: Int, indexRegister: LittleEndian) : Unit is Adj + Ctl { - if(nIndices == 0) { - fail $"Cannot prepare uniform superposition over {nIndices} state."; + operation PrepareUniformSuperposition(nIndices: Int, indexRegister: LittleEndian) + : Unit is Adj+Ctl { + if (nIndices == 0) { + fail "Cannot prepare uniform superposition over 0 state."; } elif (nIndices == 1) { // Superposition over one state, so do nothing. - } elif (nIndices == 2){ + } elif (nIndices == 2) { H(indexRegister![0]); } else { - let nQubits = Ceiling(Lg(IntAsDouble(nIndices))); - if (nQubits > Length(indexRegister!)){ + let nQubits = BitSizeI(nIndices - 1); + if (nQubits > Length(indexRegister!)) { fail $"Cannot prepare uniform superposition over {nIndices} states as it is larger than the qubit register."; } using (flagQubit = Qubit[3]) { let targetQubits = indexRegister![0..nQubits - 1]; let qubits = flagQubit + targetQubits; - let stateOracle = StateOracle(PrepareUniformSuperposition_(nIndices, nQubits, _, _)); + let stateOracle = StateOracle(PrepareUniformSuperpositionOracle(nIndices, nQubits, _, _)); (StandardAmplitudeAmplification(1, stateOracle, 0))(qubits); @@ -66,27 +67,24 @@ namespace Microsoft.Quantum.Preparation { /// # Summary /// Implementation step of - operation PrepareUniformSuperposition_(nIndices: Int, nQubits: Int, idxFlag: Int, qubits: Qubit[]) : Unit { - body (...) { - let targetQubits = qubits[3..3 + nQubits-1]; - let flagQubit = qubits[0]; - let auxillaryQubits = qubits[1..2]; - let theta = ArcSin(Sqrt(IntAsDouble(2^nQubits)/IntAsDouble(nIndices)) * Sin(PI() / 6.0)); - //let theta = PI() * 0.5; + internal operation PrepareUniformSuperpositionOracle(nIndices: Int, nQubits: Int, idxFlag: Int, qubits: Qubit[]) + : Unit is Adj+Ctl { + let targetQubits = qubits[3...]; + let flagQubit = qubits[0]; + let auxillaryQubits = qubits[1..2]; + let theta = ArcSin(Sqrt(IntAsDouble(2^nQubits) / IntAsDouble(nIndices)) * Sin(PI() / 6.0)); - ApplyToEachCA(H, targetQubits); - using(compareQubits = Qubit[nQubits]) { + ApplyToEachCA(H, targetQubits); + using (compareQubits = Qubit[nQubits]) { + within { ApplyXorInPlace(nIndices - 1, LittleEndian(compareQubits)); + } apply { CompareUsingRippleCarry(LittleEndian(targetQubits), LittleEndian(compareQubits), auxillaryQubits[0]); X(auxillaryQubits[0]); - ApplyXorInPlace(nIndices - 1, LittleEndian(compareQubits)); } - Exp([PauliY], -theta, [auxillaryQubits[1]]); - (Controlled X)(auxillaryQubits, flagQubit); } - adjoint auto; - controlled auto; - adjoint controlled auto; + Ry(2.0 * theta, auxillaryQubits[1]); + (Controlled X)(auxillaryQubits, flagQubit); } } diff --git a/Standard/tests/UniformSuperpositionPreparationTests.qs b/Standard/tests/UniformSuperpositionPreparationTests.qs index bebb308de36..306ee5f7d40 100644 --- a/Standard/tests/UniformSuperpositionPreparationTests.qs +++ b/Standard/tests/UniformSuperpositionPreparationTests.qs @@ -1,48 +1,29 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Microsoft.Quantum.Tests { - open Microsoft.Quantum.Preparation; open Microsoft.Quantum.Arithmetic; - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Canon; open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Measurement; - open Microsoft.Quantum.Arrays; - - - operation PrepareUniformSuperpositionTest() : Unit { - body (...) { - let nQubits = 5; - using(qubits = Qubit[nQubits]) { - for(nIndices in 1..2^nQubits) - { - Message($"Testing nIndices {nIndices} on {nQubits} qubits"); - PrepareUniformSuperposition(nIndices, LittleEndian(qubits)); - - ApplyToEachCA(H,qubits); - - using(flag = Qubit[1]) - { - (ControlledOnInt(0, X))(qubits, flag[0]); - AssertProb([PauliZ], flag, One, IntAsDouble(nIndices)/IntAsDouble(2^nQubits), "", 1e-10); - (ControlledOnInt(0, X))(qubits, flag[0]); - ApplyToEachCA(H,qubits); + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Preparation; - let measuredInt = MeasureInteger(LittleEndian(qubits)); - if(measuredInt >= nIndices){ - fail $"Measured integer {measuredInt} which is bigger than expected of number state {nIndices}."; - } + @Test("QuantumSimulator") + operation TestPrepareUniformSuperposition() : Unit { + let nQubits = 5; + using(qubits = Qubit[nQubits]) { + for(nIndices in 1..2^nQubits) { + Message($"Testing nIndices {nIndices} on {nQubits} qubits"); + PrepareUniformSuperposition(nIndices, LittleEndian(qubits)); - ResetAll(flag); - } - ResetAll(qubits); + let prob = 1.0 / IntAsDouble(nIndices); + for (stateIndex in 0..2^nQubits - 1) { + AssertProbInt(stateIndex, stateIndex < nIndices ? prob | 0.0, LittleEndian(qubits), 1e-10); } + + ResetAll(qubits); } } } } - - From e8076f770f3fe4fdba7c17cd176443abcd9aac98 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Wed, 26 Aug 2020 09:31:17 +0200 Subject: [PATCH 03/11] Cleanup quantum ROM. --- Standard/src/Preparation/QuantumROM.qs | 43 +++++++++++++------------- Standard/tests/QuantumROMTests.qs | 19 +++++------- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/Standard/src/Preparation/QuantumROM.qs b/Standard/src/Preparation/QuantumROM.qs index d0f3623aa25..813cfd8a075 100644 --- a/Standard/src/Preparation/QuantumROM.qs +++ b/Standard/src/Preparation/QuantumROM.qs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Microsoft.Quantum.Preparation { @@ -61,7 +61,8 @@ namespace Microsoft.Quantum.Preparation { /// - Encoding Electronic Spectra in Quantum Circuits with Linear T Complexity /// Ryan Babbush, Craig Gidney, Dominic W. Berry, Nathan Wiebe, Jarrod McClean, Alexandru Paler, Austin Fowler, Hartmut Neven /// https://arxiv.org/abs/1805.03662 - function QuantumROM(targetError: Double, coefficients: Double[]) : ((Int, (Int, Int)), Double, ((LittleEndian, Qubit[]) => Unit is Adj + Ctl)) { + function QuantumROM(targetError: Double, coefficients: Double[]) + : ((Int, (Int, Int)), Double, ((LittleEndian, Qubit[]) => Unit is Adj + Ctl)) { let nBitsPrecision = -Ceiling(Lg(0.5 * targetError)) + 1; let (oneNorm, keepCoeff, altIndex) = _QuantumROMDiscretization(nBitsPrecision, coefficients); let nCoeffs = Length(coefficients); @@ -87,7 +88,8 @@ namespace Microsoft.Quantum.Preparation { /// A tuple `(x,(y,z))` where `x = y + z` is the total number of qubits allocated, /// `y` is the number of qubits for the `LittleEndian` register, and `z` is the Number /// of garbage qubits. - function QuantumROMQubitCount(targetError: Double, nCoeffs: Int) : (Int, (Int, Int)) { + function QuantumROMQubitCount(targetError: Double, nCoeffs: Int) + : (Int, (Int, Int)) { let nBitsPrecision = -Ceiling(Lg(0.5*targetError))+1; let nBitsIndices = Ceiling(Lg(IntAsDouble(nCoeffs))); let nGarbageQubits = nBitsIndices + 2 * nBitsPrecision + 1; @@ -97,23 +99,24 @@ namespace Microsoft.Quantum.Preparation { // Classical processing // This discretizes the coefficients such that - // |coefficient[i] * oneNorm - discretizedCoefficient[i] * discreizedOneNorm| * nCoeffs <= 2^{1-bitsPrecision}. - function _QuantumROMDiscretization(bitsPrecision: Int, coefficients: Double[]) : (Double, Int[], Int[]) { + // |coefficient[i] * oneNorm - discretizedCoefficient[i] * discretizedOneNorm| * nCoeffs <= 2^{1-bitsPrecision}. + function _QuantumROMDiscretization(bitsPrecision: Int, coefficients: Double[]) + : (Double, Int[], Int[]) { let oneNorm = PNorm(1.0, coefficients); let nCoefficients = Length(coefficients); if (bitsPrecision > 31) { fail $"Bits of precision {bitsPrecision} unsupported. Max is 31."; } if (nCoefficients <= 1) { - fail $"Cannot prepare state with less than 2 coefficients."; + fail "Cannot prepare state with less than 2 coefficients."; } if (oneNorm == 0.0) { - fail $"State must have at least one coefficient > 0"; + fail "State must have at least one coefficient > 0"; } let barHeight = 2^bitsPrecision - 1; - mutable altIndex = RangeAsIntArray(0..nCoefficients-1); + mutable altIndex = RangeAsIntArray(0..nCoefficients - 1); mutable keepCoeff = Mapped(RoundedDiscretizationCoefficients(_, oneNorm, nCoefficients, barHeight), coefficients); // Calculate difference between number of discretized bars vs. maximum @@ -121,7 +124,7 @@ namespace Microsoft.Quantum.Preparation { for (idxCoeff in IndexRange(keepCoeff)) { set bars += keepCoeff[idxCoeff] - barHeight; } - //Message($"Excess bars {bars}."); + // Uniformly distribute excess bars across coefficients. for (idx in 0..AbsI(bars) - 1) { if (bars > 0) { @@ -148,28 +151,24 @@ namespace Microsoft.Quantum.Preparation { for (rep in 0..nCoefficients * 10) { if (nBarSource > 0 and nBarSink > 0) { - let idxSink = barSink[nBarSink-1]; - let idxSource = barSource[nBarSource-1]; + let idxSink = barSink[nBarSink - 1]; + let idxSource = barSource[nBarSource - 1]; set nBarSink = nBarSink - 1; set nBarSource = nBarSource - 1; set keepCoeff w/= idxSource <- keepCoeff[idxSource] - barHeight + keepCoeff[idxSink]; set altIndex w/= idxSink <- idxSource; - if (keepCoeff[idxSource] < barHeight) - { + if (keepCoeff[idxSource] < barHeight) { set barSink w/= nBarSink <- idxSource; set nBarSink = nBarSink + 1; - } - elif(keepCoeff[idxSource] > barHeight) - { + } elif(keepCoeff[idxSource] > barHeight) { set barSource w/= nBarSource <- idxSource; set nBarSource = nBarSource + 1; } } elif (nBarSource > 0) { - //Message($"rep: {rep}, nBarSource {nBarSource}."); - let idxSource = barSource[nBarSource-1]; + let idxSource = barSource[nBarSource - 1]; set nBarSource = nBarSource - 1; set keepCoeff w/= idxSource <- barHeight; } else { @@ -181,7 +180,8 @@ namespace Microsoft.Quantum.Preparation { } // Used in QuantumROM implementation. - internal function RoundedDiscretizationCoefficients(coefficient: Double, oneNorm: Double, nCoefficients: Int, barHeight: Int) : Int { + internal function RoundedDiscretizationCoefficients(coefficient: Double, oneNorm: Double, nCoefficients: Int, barHeight: Int) + : Int { return Round((AbsD(coefficient) / oneNorm) * IntAsDouble(nCoefficients) * IntAsDouble(barHeight)); } @@ -194,7 +194,7 @@ namespace Microsoft.Quantum.Preparation { let garbageIdx2 = garbageIdx1 + nBitsPrecision; let garbageIdx3 = garbageIdx2 + 1; - let altIndexRegister = LittleEndian(garbageRegister[0..garbageIdx0-1]); + let altIndexRegister = LittleEndian(garbageRegister[0..garbageIdx0 - 1]); let keepCoeffRegister = LittleEndian(garbageRegister[garbageIdx0..garbageIdx1 - 1]); let uniformKeepCoeffRegister = LittleEndian(garbageRegister[garbageIdx1..garbageIdx2 - 1]); let flagQubit = garbageRegister[garbageIdx3 - 1]; @@ -218,7 +218,8 @@ namespace Microsoft.Quantum.Preparation { } // Used in QuantumROM implementation. - internal function QuantumROMBitStringWriterByIndex(idx : Int, keepCoeff : Int[], altIndex : Int[]) : ((LittleEndian, LittleEndian) => Unit is Adj + Ctl) { + internal function QuantumROMBitStringWriterByIndex(idx : Int, keepCoeff : Int[], altIndex : Int[]) + : ((LittleEndian, LittleEndian) => Unit is Adj + Ctl) { return WriteQuantumROMBitString(idx, keepCoeff, altIndex, _, _); } diff --git a/Standard/tests/QuantumROMTests.qs b/Standard/tests/QuantumROMTests.qs index 4a1da7ebdad..72f149a472f 100644 --- a/Standard/tests/QuantumROMTests.qs +++ b/Standard/tests/QuantumROMTests.qs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. @@ -14,7 +14,8 @@ namespace Microsoft.Quantum.Tests { open Microsoft.Quantum.Random; // Tests the discretization algorithm - operation QuantumROMDiscretizationTest() : Unit { + @Test("QuantumSimulator") + operation TestQuantumROMDiscretization() : Unit { for(rep in 0..20){ let coeffs = DrawRandomInt(2, 5002); let bitsPrecision = DrawRandomInt(1, 31); @@ -31,7 +32,7 @@ namespace Microsoft.Quantum.Tests { // Reconstruct coefficients mutable coefficientsOutInt = new Int[coeffs]; - for (idx in 0..coeffs-1) + for (idx in 0..coeffs - 1) { set coefficientsOutInt w/= idx <- coefficientsOutInt[idx] + keepCoeff[idx]; if (altIndex[idx] >= 0) @@ -44,21 +45,17 @@ namespace Microsoft.Quantum.Tests { mutable coefficientsOut = new Double[coeffs]; mutable errors = new Double[coeffs]; mutable maxError = 0.0; - for (i in 0..coeffs-1) - { + for (i in 0..coeffs - 1) { set coefficientsOut w/= i <- oneNorm * IntAsDouble(coefficientsOutInt[i]) / IntAsDouble(barHeight * coeffs); let error = AbsD(coefficients[i] - coefficientsOut[i]) / oneNorm /( PowD(2.0, IntAsDouble(-bitsPrecision)) / IntAsDouble(coeffs)); set errors w/= i <- error; - if(AbsD(error) > AbsD(maxError)){ + if (AbsD(error) > AbsD(maxError)) { set maxError = error; } } Message($"coeffs {coeffs}, bitsPrecision {bitsPrecision}, maxError {maxError}"); - for(i in 0..coeffs-1){ - if(errors[i] < IntAsDouble(3)){ - // test passes - } - else{ + for (i in 0..coeffs - 1) { + if (errors[i] >= IntAsDouble(3)) { fail $"index {i} reconstructed coefficient incorrect. Error is {errors[i]}"; } } From b35222ab855c85c8bab699b0a489af089f811d12 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Thu, 27 Aug 2020 11:54:33 +0200 Subject: [PATCH 04/11] Clean-up arbitrary state preparation. --- Standard/src/Preparation/Arbitrary.qs | 43 ++---- Standard/tests/StatePreparationTests.qs | 196 +++++++++--------------- 2 files changed, 93 insertions(+), 146 deletions(-) diff --git a/Standard/src/Preparation/Arbitrary.qs b/Standard/src/Preparation/Arbitrary.qs index 2eed1e0b8e5..0fbdeb72ee3 100644 --- a/Standard/src/Preparation/Arbitrary.qs +++ b/Standard/src/Preparation/Arbitrary.qs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Microsoft.Quantum.Preparation { @@ -49,14 +49,8 @@ namespace Microsoft.Quantum.Preparation { /// op(qubitsLE); /// } /// ``` - function StatePreparationPositiveCoefficients (coefficients : Double[]) : (LittleEndian => Unit is Adj + Ctl) { - let nCoefficients = Length(coefficients); - mutable coefficientsComplexPolar = new ComplexPolar[nCoefficients]; - - for (idx in 0 .. nCoefficients - 1) { - set coefficientsComplexPolar w/= idx <- ComplexPolar(AbsD(coefficients[idx]), 0.0); - } - + function StatePreparationPositiveCoefficients(coefficients : Double[]) : (LittleEndian => Unit is Adj + Ctl) { + let coefficientsComplexPolar = Mapped(Compose(ComplexPolar(_, 0.0), AbsD), coefficients); return PrepareArbitraryState(coefficientsComplexPolar, _); } @@ -218,7 +212,7 @@ namespace Microsoft.Quantum.Preparation { qubits : LittleEndian ) : Unit is Adj + Ctl { - (_CompileApproximateArbitraryStatePreparation(tolerance, coefficients, Length(qubits!)))(qubits); + (CompileApproximateArbitraryStatePreparation(tolerance, coefficients, Length(qubits!)))(qubits); } /// # Summary @@ -234,7 +228,7 @@ namespace Microsoft.Quantum.Preparation { // NB: This is currently not marked as internal, as the QML library // currently uses this function. Please see the relevant GitHub issue // at https://github.com/microsoft/QuantumLibraries/issues/239. - function _CompileApproximateArbitraryStatePreparation( + internal function CompileApproximateArbitraryStatePreparation( tolerance : Double, coefficients : ComplexPolar[], nQubits : Int @@ -248,7 +242,7 @@ namespace Microsoft.Quantum.Preparation { nQubits > 1 ? (1 .. (nQubits - 1)) | (1..0); - let plan = _ApproximatelyUnprepareArbitraryStatePlan( + let plan = ApproximatelyUnprepareArbitraryStatePlan( tolerance, coefficientsPadded, (rngControl, idxTarget) ); let unprepare = BoundCA(plan); @@ -265,12 +259,11 @@ namespace Microsoft.Quantum.Preparation { ApproximatelyMultiplexPauli(tolerance, disentangling, axis, actualControl, register[idxTarget]); } - internal function RangeLength(rng : Range) : Int { - mutable len = 0; + internal function IsRangeEmpty(rng : Range) : Bool { for (idx in rng) { - set len += 1; + return false; } - return len; + return true; } internal operation ApplyGlobalRotationStep( @@ -285,7 +278,7 @@ namespace Microsoft.Quantum.Preparation { /// # See Also /// - PrepareArbitraryState /// - Microsoft.Quantum.Canon.MultiplexPauli - function _ApproximatelyUnprepareArbitraryStatePlan( + internal function ApproximatelyUnprepareArbitraryStatePlan( tolerance : Double, coefficients : ComplexPolar[], (rngControl : Range, idxTarget : Int) ) @@ -293,7 +286,7 @@ namespace Microsoft.Quantum.Preparation { mutable plan = new (Qubit[] => Unit is Adj + Ctl)[0]; // For each 2D block, compute disentangling single-qubit rotation parameters - let (disentanglingY, disentanglingZ, newCoefficients) = _StatePreparationSBMComputeCoefficients(coefficients); + let (disentanglingY, disentanglingZ, newCoefficients) = StatePreparationSBMComputeCoefficients(coefficients); if (AnyOutsideToleranceD(tolerance, disentanglingZ)) { set plan += [ApplyMultiplexStep(tolerance, disentanglingZ, PauliZ, (rngControl, idxTarget), _)]; } @@ -304,17 +297,15 @@ namespace Microsoft.Quantum.Preparation { // target is now in |0> state up to the phase given by arg of newCoefficients. // Continue recursion while there are control qubits. - if (RangeLength(rngControl) == 0) { + if (IsRangeEmpty(rngControl)) { let (abs, arg) = newCoefficients[0]!; if (AbsD(arg) > tolerance) { set plan += [ApplyGlobalRotationStep(-1.0 * arg, idxTarget, _)]; } - } else { - if (AnyOutsideToleranceCP(tolerance, newCoefficients)) { - let newControl = (RangeStart(rngControl) + 1)..RangeStep(rngControl)..RangeEnd(rngControl); - let newTarget = RangeStart(rngControl); - set plan += _ApproximatelyUnprepareArbitraryStatePlan(tolerance, newCoefficients, (newControl, newTarget)); - } + } elif (AnyOutsideToleranceCP(tolerance, newCoefficients)) { + let newControl = (RangeStart(rngControl) + 1)..RangeStep(rngControl)..RangeEnd(rngControl); + let newTarget = RangeStart(rngControl); + set plan += ApproximatelyUnprepareArbitraryStatePlan(tolerance, newCoefficients, (newControl, newTarget)); } return plan; @@ -352,7 +343,7 @@ namespace Microsoft.Quantum.Preparation { /// Implementation step of arbitrary state preparation procedure. /// # See Also /// - Microsoft.Quantum.Canon.PrepareArbitraryState - function _StatePreparationSBMComputeCoefficients (coefficients : ComplexPolar[]) : (Double[], Double[], ComplexPolar[]) { + internal function StatePreparationSBMComputeCoefficients (coefficients : ComplexPolar[]) : (Double[], Double[], ComplexPolar[]) { mutable disentanglingZ = new Double[Length(coefficients) / 2]; mutable disentanglingY = new Double[Length(coefficients) / 2]; mutable newCoefficients = new ComplexPolar[Length(coefficients) / 2]; diff --git a/Standard/tests/StatePreparationTests.qs b/Standard/tests/StatePreparationTests.qs index b0d03a1295f..85ce82dff17 100644 --- a/Standard/tests/StatePreparationTests.qs +++ b/Standard/tests/StatePreparationTests.qs @@ -1,66 +1,58 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Microsoft.Quantum.Tests { - open Microsoft.Quantum.Preparation; open Microsoft.Quantum.Arithmetic; + open Microsoft.Quantum.Arrays; open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Canon; open Microsoft.Quantum.Convert; + open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Math; open Microsoft.Quantum.Measurement; - open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Preparation; // number of qubits, abs(amplitude), phase newtype StatePreparationTestCase = (Int, Double[], Double[]); - operation StatePreparationPositiveCoefficientsTest () : Unit { + @Test("QuantumSimulator") + operation TestStatePreparationPositiveCoefficients() : Unit { let tolerance = 1E-09; - mutable testCases = new StatePreparationTestCase[100]; - mutable nTests = 0; - - // Test positive coefficients. - set testCases w/= nTests <- StatePreparationTestCase(1, [0.773761, 0.633478], [0.0, 0.0]); - set nTests = nTests + 1; - set testCases w/= nTests <- StatePreparationTestCase(2, [0.183017, 0.406973, 0.604925, 0.659502], [0.0, 0.0, 0.0, 0.0]); - set nTests = nTests + 1; - set testCases w/= nTests <- StatePreparationTestCase(3, [0.0986553, 0.359005, 0.465689, 0.467395, 0.419893, 0.118445, 0.461883, 0.149609], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]); - set nTests = nTests + 1; - set testCases w/= nTests <- StatePreparationTestCase(4, [0.271471, 0.0583654, 0.11639, 0.36112, 0.307383, 0.193371, 0.274151, 0.332542, 0.130172, 0.222546, 0.314879, 0.210704, 0.212429, 0.245518, 0.30666, 0.22773], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]); - set nTests = nTests + 1; - - // Test negative coefficients. Should give same probabilities as positive coefficients. - set testCases w/= nTests <- StatePreparationTestCase(1, [-0.773761, 0.633478], [0.0, 0.0]); - set nTests = nTests + 1; - set testCases w/= nTests <- StatePreparationTestCase(2, [0.183017, -0.406973, 0.604925, 0.659502], [0.0, 0.0, 0.0, 0.0]); - set nTests = nTests + 1; - set testCases w/= nTests <- StatePreparationTestCase(3, [0.0986553, -0.359005, 0.465689, -0.467395, 0.419893, 0.118445, -0.461883, 0.149609], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]); - set nTests = nTests + 1; - set testCases w/= nTests <- StatePreparationTestCase(4, [-0.271471, 0.0583654, 0.11639, 0.36112, -0.307383, 0.193371, -0.274151, 0.332542, 0.130172, 0.222546, 0.314879, -0.210704, 0.212429, 0.245518, -0.30666, -0.22773], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]); - set nTests = nTests + 1; - - // Test unnormalized coefficients - set testCases w/= nTests <- StatePreparationTestCase(3, [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445, 0.461883, 0.149609], new Double[0]); - set nTests = nTests + 1; - - // Test missing coefficients - set testCases w/= nTests <- StatePreparationTestCase(3, [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445], new Double[0]); - set nTests = nTests + 1; + + let testCases = [ + // Test positive coefficients + StatePreparationTestCase(1, [0.773761, 0.633478], [0.0, 0.0]), + StatePreparationTestCase(2, [0.183017, 0.406973, 0.604925, 0.659502], [0.0, 0.0, 0.0, 0.0]), + StatePreparationTestCase(3, [0.0986553, 0.359005, 0.465689, 0.467395, 0.419893, 0.118445, 0.461883, 0.149609], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), + StatePreparationTestCase(4, [0.271471, 0.0583654, 0.11639, 0.36112, 0.307383, 0.193371, 0.274151, 0.332542, 0.130172, 0.222546, 0.314879, 0.210704, 0.212429, 0.245518, 0.30666, 0.22773], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), + + // Test negative coefficients; should give same probabilities as positive coefficients + StatePreparationTestCase(1, [-0.773761, 0.633478], [0.0, 0.0]), + StatePreparationTestCase(2, [0.183017, -0.406973, 0.604925, 0.659502], [0.0, 0.0, 0.0, 0.0]), + StatePreparationTestCase(3, [0.0986553, -0.359005, 0.465689, -0.467395, 0.419893, 0.118445, -0.461883, 0.149609], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), + StatePreparationTestCase(4, [-0.271471, 0.0583654, 0.11639, 0.36112, -0.307383, 0.193371, -0.274151, 0.332542, 0.130172, 0.222546, 0.314879, -0.210704, 0.212429, 0.245518, -0.30666, -0.22773], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), + + // Test unnormalized coefficients + StatePreparationTestCase(3, [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445, 0.461883, 0.149609], new Double[0]), + + // Test missing coefficients + StatePreparationTestCase(3, [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445], new Double[0]) + ]; // Loop over multiple qubit tests - for (idxTest in 0 .. nTests - 1) { - let (nQubits, coefficientsAmplitude, coefficientsPhase) = testCases[idxTest]!; + for (testCase in testCases) { + let (nQubits, coefficientsAmplitude, coefficientsPhase) = testCase!; let nCoefficients = Length(coefficientsAmplitude); - // Test negative coefficients. Should give same results as positive coefficients. + // Test negative coefficients. Should give same results as positive coefficients using (qubits = Qubit[nQubits]) { let qubitsLE = LittleEndian(qubits); let op = StatePreparationPositiveCoefficients(coefficientsAmplitude); op(qubitsLE); let normalizedCoefficients = PNormalized(2.0, coefficientsAmplitude); - for (idxCoeff in 0 .. nCoefficients - 1) { + for (idxCoeff in IndexRange(coefficientsAmplitude)) { let amp = normalizedCoefficients[idxCoeff]; let prob = amp * amp; AssertProbInt(idxCoeff, prob, qubitsLE, tolerance); @@ -73,34 +65,25 @@ namespace Microsoft.Quantum.Tests { // Test phase factor on 1-qubit uniform superposition. - operation StatePreparationComplexCoefficientsQubitPhaseTest () : Unit { + @Test("QuantumSimulator") + operation TestStatePreparationComplexCoefficientsQubitPhase() : Unit { let tolerance = 1E-09; - mutable testCases = new StatePreparationTestCase[10]; - mutable nTests = 0; - - // Test phase factor on uniform superposition. - set testCases w/= nTests <- StatePreparationTestCase(1, [1.0, 1.0], [0.01, -0.01]); - set nTests = nTests + 1; - set testCases w/= nTests <- StatePreparationTestCase(1, [1.0, 1.0], [0.01, -0.05]); - set nTests = nTests + 1; + + let testCases = [ + // Test phase factor on uniform superposition + StatePreparationTestCase(1, [1.0, 1.0], [0.01, -0.01]), + StatePreparationTestCase(1, [1.0, 1.0], [0.01, -0.05]) + ]; // Loop over tests - for (idxTest in 0 .. nTests - 1) { - let (nQubits, coefficientsAmplitude, coefficientsPhase) = testCases[idxTest]!; - Message($"Test case {idxTest}"); + for (testCase in testCases) { + let (nQubits, coefficientsAmplitude, coefficientsPhase) = testCase!; let nCoefficients = Length(coefficientsAmplitude); using (qubits = Qubit[nQubits]) { let qubitsLE = LittleEndian(qubits); - mutable coefficients = new ComplexPolar[nCoefficients]; - mutable coefficientsPositive = new Double[nCoefficients]; - - for (idxCoeff in 0 .. nCoefficients - 1) { - set coefficients w/= idxCoeff <- ComplexPolar(coefficientsAmplitude[idxCoeff], coefficientsPhase[idxCoeff]); - set coefficientsPositive w/= idxCoeff <- coefficientsAmplitude[idxCoeff]; - } - + let coefficients = Mapped(ComplexPolar, Zip(coefficientsAmplitude, coefficientsPhase)); let normalizedCoefficients = PNormalized(2.0, coefficientsAmplitude); // Test phase factor on uniform superposition @@ -111,7 +94,7 @@ namespace Microsoft.Quantum.Tests { op(qubitsLE); AssertProbInt(0, prob, qubitsLE, tolerance); AssertProbInt(1, prob, qubitsLE, tolerance); - AssertPhase(phase, (qubitsLE!)[0], tolerance); + Microsoft.Quantum.Diagnostics.AssertPhase(phase, (qubitsLE!)[0], tolerance); ResetAll(qubits); } } @@ -119,40 +102,28 @@ namespace Microsoft.Quantum.Tests { // Test probabilities and phases factor of multi-qubit uniform superposition. - operation StatePreparationComplexCoefficientsMultiQubitPhaseTest () : Unit { + @Test("QuantumSimulator") + operation TestStatePreparationComplexCoefficientsMultiQubitPhase() : Unit { let tolerance = 1E-09; - mutable testCases = new StatePreparationTestCase[10]; - mutable nTests = 0; - - // Test probability and phases of uniform superposition. - set testCases w/= nTests <- StatePreparationTestCase(1, [1.0, 1.0], [0.01, -0.01]); - set nTests = nTests + 1; - set testCases w/= nTests <- StatePreparationTestCase(3, [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]); - set nTests = nTests + 1; - set testCases w/= nTests <- StatePreparationTestCase(3, [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], ConstantArray(8, PI())); - set nTests = nTests + 1; - set testCases w/= nTests <- StatePreparationTestCase(3, [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01]); - set nTests = nTests + 1; - set testCases w/= nTests <- StatePreparationTestCase(3, [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445, 0.461883, 0.149609]); - set nTests = nTests + 1; + + let testCases = [ + // Test probability and phases of uniform superposition + StatePreparationTestCase(1, [1.0, 1.0], [0.01, -0.01]), + StatePreparationTestCase(3, [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), + StatePreparationTestCase(3, [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], ConstantArray(8, PI())), + StatePreparationTestCase(3, [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01]), + StatePreparationTestCase(3, [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445, 0.461883, 0.149609]) + ]; // Loop over tests - for (idxTest in 0 .. nTests - 1) { - let (nQubits, coefficientsAmplitude, coefficientsPhase) = testCases[idxTest]!; - Message($"Test case {idxTest}"); + for (testCase in testCases) { + let (nQubits, coefficientsAmplitude, coefficientsPhase) = testCase!; let nCoefficients = Length(coefficientsAmplitude); using (qubits = Qubit[nQubits]) { let qubitsLE = LittleEndian(qubits); - mutable coefficients = new ComplexPolar[nCoefficients]; - mutable coefficientsPositive = new Double[nCoefficients]; - - for (idxCoeff in 0 .. nCoefficients - 1) { - set coefficients w/= idxCoeff <- ComplexPolar(coefficientsAmplitude[idxCoeff], coefficientsPhase[idxCoeff]); - set coefficientsPositive w/= idxCoeff <- coefficientsAmplitude[idxCoeff]; - } - + let coefficients = Mapped(ComplexPolar, Zip(coefficientsAmplitude, coefficientsPhase)); let normalizedCoefficients = PNormalized(2.0, coefficientsAmplitude); // Test probability and phases of uniform superposition @@ -167,14 +138,12 @@ namespace Microsoft.Quantum.Tests { Controlled (ApplyToEachCA(H, _))(control, qubitsLE!); X(control[0]); - for (idxCoeff in 0 .. nCoefficients - 1) { - let amp = normalizedCoefficients[idxCoeff]; + for ((idxCoeff, amp) in Enumerated(normalizedCoefficients)) { let prob = amp * amp; AssertProbInt(idxCoeff, prob, qubitsLE, tolerance); } - ResetAll(control); - ResetAll(qubits); + ResetAll(control + qubits); //Test phase for (repeats in 0 .. nCoefficients / 2) { @@ -186,9 +155,8 @@ namespace Microsoft.Quantum.Tests { let indexMeasuredInteger = MeasureInteger(qubitsLE); let phase = coefficientsPhase[indexMeasuredInteger]; Message($"StatePreparationComplexCoefficientsTest: expected phase = {phase}."); - AssertPhase(-0.5 * phase, control[0], tolerance); - ResetAll(control); - ResetAll(qubits); + Microsoft.Quantum.Diagnostics.AssertPhase(-0.5 * phase, control[0], tolerance); + ResetAll(control + qubits); } } } @@ -197,39 +165,30 @@ namespace Microsoft.Quantum.Tests { // Test probabilities and phases of arbitrary multi-qubit superposition. - operation StatePreparationComplexCoefficientsArbitraryMultiQubitPhaseTest () : Unit { + @Test("QuantumSimulator") + operation TestStatePreparationComplexCoefficientsArbitraryMultiQubitPhase() : Unit { let tolerance = 1E-09; - mutable testCases = new StatePreparationTestCase[10]; - mutable nTests = 0; - set testCases w/= nTests <- StatePreparationTestCase(1, [1.0986553, 0.359005], [0.419893, 0.118445]); - set nTests = nTests + 1; - set testCases w/= nTests <- StatePreparationTestCase(2, [1.0986553, 0.359005, -0.123, 9.238], [0.419893, 0.118445, -0.467395, 0.419893]); - set nTests = nTests + 1; - set testCases w/= nTests <- StatePreparationTestCase(3, [1.0986553, 0.359005, 0.465689, 0.467395, 0.419893, 0.118445, 0.123, 9.238], [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445, 0.461883, 0.149609]); - set nTests = nTests + 1; + + let testCases = [ + StatePreparationTestCase(1, [1.0986553, 0.359005], [0.419893, 0.118445]), + StatePreparationTestCase(2, [1.0986553, 0.359005, -0.123, 9.238], [0.419893, 0.118445, -0.467395, 0.419893]), + StatePreparationTestCase(3, [1.0986553, 0.359005, 0.465689, 0.467395, 0.419893, 0.118445, 0.123, 9.238], [1.0986553, 0.359005, 0.465689, -0.467395, 0.419893, 0.118445, 0.461883, 0.149609]) + ]; // Loop over tests - for (idxTest in 0 .. nTests - 1) { - let (nQubits, coefficientsAmplitude, coefficientsPhase) = testCases[idxTest]!; - Message($"Test case {idxTest}"); + for (testCase in testCases) { + let (nQubits, coefficientsAmplitude, coefficientsPhase) = testCase!; let nCoefficients = Length(coefficientsAmplitude); using (qubits = Qubit[nQubits]) { let qubitsLE = LittleEndian(qubits); - mutable coefficients = new ComplexPolar[nCoefficients]; - mutable coefficientsPositive = new Double[nCoefficients]; - - for (idxCoeff in 0 .. nCoefficients - 1) { - set coefficients w/= idxCoeff <- ComplexPolar(coefficientsAmplitude[idxCoeff], coefficientsPhase[idxCoeff]); - set coefficientsPositive w/= idxCoeff <- coefficientsAmplitude[idxCoeff]; - } - + let coefficients = Mapped(ComplexPolar, Zip(coefficientsAmplitude, coefficientsPhase)); let normalizedCoefficients = PNormalized(2.0, coefficientsAmplitude); // Test probability and phases of arbitrary superposition let opComplex = StatePreparationComplexCoefficients(coefficients); - let opReal = StatePreparationPositiveCoefficients(coefficientsPositive); + let opReal = StatePreparationPositiveCoefficients(coefficientsAmplitude); using (control = Qubit[1]) { @@ -240,14 +199,12 @@ namespace Microsoft.Quantum.Tests { Controlled opReal(control, qubitsLE); X(control[0]); - for (idxCoeff in 0 .. nCoefficients - 1) { - let amp = normalizedCoefficients[idxCoeff]; + for ((idxCoeff, amp) in Enumerated(normalizedCoefficients)) { let prob = amp * amp; AssertProbInt(idxCoeff, prob, qubitsLE, tolerance); } - ResetAll(control); - ResetAll(qubits); + ResetAll(control + qubits); // Test phase for (repeats in 0 .. nCoefficients / 2) { @@ -259,9 +216,8 @@ namespace Microsoft.Quantum.Tests { let indexMeasuredInteger = MeasureInteger(qubitsLE); let phase = coefficientsPhase[indexMeasuredInteger]; Message($"StatePreparationComplexCoefficientsTest: expected phase = {phase}."); - AssertPhase(-0.5 * phase, control[0], tolerance); - ResetAll(control); - ResetAll(qubits); + Microsoft.Quantum.Diagnostics.AssertPhase(-0.5 * phase, control[0], tolerance); + ResetAll(control + qubits); } } } From 58d428ed6476d096fe5678dbc04f6e95b19e0d1f Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Thu, 27 Aug 2020 11:59:12 +0200 Subject: [PATCH 05/11] Cleanup remaining files. --- Standard/src/Preparation/Mixed.qs | 29 +++++++++++---------------- Standard/src/Preparation/Reference.qs | 18 ++++++++--------- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/Standard/src/Preparation/Mixed.qs b/Standard/src/Preparation/Mixed.qs index 6d6eddcf75e..7de63073113 100644 --- a/Standard/src/Preparation/Mixed.qs +++ b/Standard/src/Preparation/Mixed.qs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Microsoft.Quantum.Preparation { @@ -8,8 +8,8 @@ namespace Microsoft.Quantum.Preparation { open Microsoft.Quantum.Random; /// # Summary - /// Prepares a qubit in the maximally mixed state. - /// + /// Prepares a qubit in the maximally mixed state. + /// /// It prepares the given qubit in the $\boldone / 2$ state by applying the depolarizing channel /// $$ /// \begin{align} @@ -38,9 +38,9 @@ namespace Microsoft.Quantum.Preparation { /// # Summary /// Given a register, prepares that register in the maximally mixed state. - /// + /// /// The register is prepared in the $\boldone / 2^N$ state by applying the - /// complete depolarizing + /// complete depolarizing /// channel to each qubit, where $N$ is the length of the register. /// /// # Input @@ -55,10 +55,10 @@ namespace Microsoft.Quantum.Preparation { } /// # Summary - /// Prepares a qubit in the +1 (`Zero`) eigenstate of the given Pauli operator. - /// If the identity operator is given, then the qubit is prepared in the maximally - /// mixed state. - /// + /// Prepares a qubit in the +1 (`Zero`) eigenstate of the given Pauli operator. + /// If the identity operator is given, then the qubit is prepared in the maximally + /// mixed state. + /// /// If the qubit was initially in the $\ket{0}$ state, this operation prepares the /// qubit in the $+1$ eigenstate of a given Pauli operator, or, for `PauliI`, /// in the maximally mixed state instead (see ). @@ -73,16 +73,11 @@ namespace Microsoft.Quantum.Preparation { /// ## qubit /// A qubit to be prepared. operation PrepareQubit (basis : Pauli, qubit : Qubit) : Unit { - if (basis == PauliI) - { + if (basis == PauliI) { PrepareSingleQubitIdentity(qubit); - } - elif (basis == PauliX) - { + } elif (basis == PauliX) { H(qubit); - } - elif (basis == PauliY) - { + } elif (basis == PauliY) { H(qubit); S(qubit); } diff --git a/Standard/src/Preparation/Reference.qs b/Standard/src/Preparation/Reference.qs index 9203f0439ec..a03b94672a7 100644 --- a/Standard/src/Preparation/Reference.qs +++ b/Standard/src/Preparation/Reference.qs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Microsoft.Quantum.Preparation { @@ -6,8 +6,8 @@ namespace Microsoft.Quantum.Preparation { open Microsoft.Quantum.Arrays; /// # Summary - /// Pairwise entangles two qubit registers. - /// + /// Pairwise entangles two qubit registers. + /// /// That is, given two registers, prepares the maximally entangled state /// $\frac{1}{\sqrt{2}} \left(\ket{00} + \ket{11} \right)$ between each pair of qubits on the respective registers, /// assuming that each register starts in the $\ket{0\cdots 0}$ state. @@ -24,17 +24,17 @@ namespace Microsoft.Quantum.Preparation { for ((leftQubit, rightQubit) in Zip(left, right)) { H(leftQubit); - Controlled X([leftQubit], rightQubit); + CNOT(leftQubit, rightQubit); } } /// # Summary - /// Prepares the Choi–Jamiłkowski state for a given operation onto given reference + /// Prepares the Choi–Jamiołkowski state for a given operation onto given reference /// and target registers. /// /// # Input /// ## op - /// Operation $\Lambda$ whose Choi–Jamiłkowski state $J(\Lambda) / 2^N$ + /// Operation $\Lambda$ whose Choi–Jamiołkowski state $J(\Lambda) / 2^N$ /// is to be prepared, where $N$ is the number of qubits on which /// `op` acts. /// ## reference @@ -70,7 +70,7 @@ namespace Microsoft.Quantum.Preparation { /// # Summary - /// Prepares the Choi–Jamiłkowski state for a given operation with a controlled variant onto given reference + /// Prepares the Choi–Jamiołkowski state for a given operation with a controlled variant onto given reference /// and target registers. /// /// # See Also @@ -82,7 +82,7 @@ namespace Microsoft.Quantum.Preparation { /// # Summary - /// Prepares the Choi–Jamiłkowski state for a given operation with an adjoint variant onto given reference + /// Prepares the Choi–Jamiołkowski state for a given operation with an adjoint variant onto given reference /// and target registers. /// /// # See Also @@ -94,7 +94,7 @@ namespace Microsoft.Quantum.Preparation { /// # Summary - /// Prepares the Choi–Jamiłkowski state for a given operation with both controlled and adjoint variants onto given reference + /// Prepares the Choi–Jamiołkowski state for a given operation with both controlled and adjoint variants onto given reference /// and target registers. /// /// # See Also From 984156791d29db5190698ba0b17d3e4733c7f9af Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Mon, 31 Aug 2020 10:41:17 +0200 Subject: [PATCH 06/11] Fix bug in QuantumROM. --- Standard/src/Preparation/QuantumROM.qs | 4 +--- Standard/tests/QuantumROMTests.qs | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Standard/src/Preparation/QuantumROM.qs b/Standard/src/Preparation/QuantumROM.qs index 813cfd8a075..9e49dae3d9d 100644 --- a/Standard/src/Preparation/QuantumROM.qs +++ b/Standard/src/Preparation/QuantumROM.qs @@ -212,9 +212,7 @@ namespace Microsoft.Quantum.Preparation { let indexRegisterSize = Length(indexRegister!); // Swap in register based on comparison - for (idx in 0..nBitsIndices - 1) { - (Controlled SWAP)([flagQubit], (indexRegister![nBitsIndices - idx - 1], altIndexRegister![idx])); - } + ApplyToEachCA((Controlled SWAP)([flagQubit], _), Zip(indexRegister!, altIndexRegister!)); } // Used in QuantumROM implementation. diff --git a/Standard/tests/QuantumROMTests.qs b/Standard/tests/QuantumROMTests.qs index 72f149a472f..301b25ea71d 100644 --- a/Standard/tests/QuantumROMTests.qs +++ b/Standard/tests/QuantumROMTests.qs @@ -87,10 +87,7 @@ namespace Microsoft.Quantum.Tests { } apply { for (stateIndex in 0..coeffs - 1) { let prob = AbsD(coefficients[stateIndex]) / oneNorm; - // FIXME: this only works for stateIndex == 0; why? - if (stateIndex == 0) { - AssertProbInt(stateIndex, prob, coeffQubits, probtargetError); - } + AssertProbInt(stateIndex, prob, coeffQubits, probtargetError); } } } From cb77faa3854d3c3b7b32938585ddb4596d8d84c2 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Mon, 31 Aug 2020 16:46:12 +0200 Subject: [PATCH 07/11] Fix error. --- .../JordanWigner/JordanWignerOptimizedBlockEncoding.qs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Chemistry/src/Runtime/JordanWigner/JordanWignerOptimizedBlockEncoding.qs b/Chemistry/src/Runtime/JordanWigner/JordanWignerOptimizedBlockEncoding.qs index 887398988d2..e325737b0b3 100644 --- a/Chemistry/src/Runtime/JordanWigner/JordanWignerOptimizedBlockEncoding.qs +++ b/Chemistry/src/Runtime/JordanWigner/JordanWignerOptimizedBlockEncoding.qs @@ -389,8 +389,9 @@ namespace Microsoft.Quantum.Chemistry.JordanWigner { function _JordanWignerOptimizedBlockEncodingQubitManager_ (targetError : Double, nCoeffs : Int, nZ : Int, nMaj : Int, nIdxRegQubits : Int, ctrlRegister : Qubit[]) : ((LittleEndian, Qubit[], Qubit, Qubit[], Qubit[], Qubit[], LittleEndian, LittleEndian[]), (Qubit, Qubit[], Qubit[], Qubit[], LittleEndian[]), Qubit[]) { - - let ((qROMIdx, qROMGarbage), rest0) = _QuantumROMQubitManager(targetError, nCoeffs, ctrlRegister); + let (_, (nIndexRegister, nGarbageQubits)) = QuantumROMQubitCount(targetError, nCoeffs); + let parts = Partitioned([nIndexRegister, nGarbageQubits], ctrlRegister); + let ((qROMIdx, qROMGarbage), rest0) = ((LittleEndian(parts[0]), parts[1]), parts[2]); let ((signQubit, selectZControlRegisters, optimizedBEControlRegisters, pauliBases, indexRegisters, tmp), rest1) = _JordanWignerSelectQubitManager_(nZ, nMaj, nIdxRegQubits, rest0, new Qubit[0]); let registers = Partitioned([3], rest1); let pauliBasesIdx = LittleEndian(registers[0]); From 540fbe8503deba6c87b895aa47c31262287d8df4 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Mon, 31 Aug 2020 21:47:04 +0200 Subject: [PATCH 08/11] Revert name due to #239. --- Standard/src/Preparation/Arbitrary.qs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Standard/src/Preparation/Arbitrary.qs b/Standard/src/Preparation/Arbitrary.qs index 0fbdeb72ee3..fb5afec4a83 100644 --- a/Standard/src/Preparation/Arbitrary.qs +++ b/Standard/src/Preparation/Arbitrary.qs @@ -212,7 +212,7 @@ namespace Microsoft.Quantum.Preparation { qubits : LittleEndian ) : Unit is Adj + Ctl { - (CompileApproximateArbitraryStatePreparation(tolerance, coefficients, Length(qubits!)))(qubits); + (_CompileApproximateArbitraryStatePreparation(tolerance, coefficients, Length(qubits!)))(qubits); } /// # Summary @@ -228,7 +228,7 @@ namespace Microsoft.Quantum.Preparation { // NB: This is currently not marked as internal, as the QML library // currently uses this function. Please see the relevant GitHub issue // at https://github.com/microsoft/QuantumLibraries/issues/239. - internal function CompileApproximateArbitraryStatePreparation( + function _CompileApproximateArbitraryStatePreparation( tolerance : Double, coefficients : ComplexPolar[], nQubits : Int From d065ca6270c1193521e9c01d351110dec702ef4e Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Wed, 2 Sep 2020 13:03:22 +0200 Subject: [PATCH 09/11] Apply suggestions from code review Co-authored-by: Chris Granade --- Standard/src/Preparation/UniformSuperposition.qs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Standard/src/Preparation/UniformSuperposition.qs b/Standard/src/Preparation/UniformSuperposition.qs index a4d3773cd49..56d51dca2ad 100644 --- a/Standard/src/Preparation/UniformSuperposition.qs +++ b/Standard/src/Preparation/UniformSuperposition.qs @@ -42,7 +42,7 @@ namespace Microsoft.Quantum.Preparation { operation PrepareUniformSuperposition(nIndices: Int, indexRegister: LittleEndian) : Unit is Adj+Ctl { if (nIndices == 0) { - fail "Cannot prepare uniform superposition over 0 state."; + fail "Cannot prepare uniform superposition over 0 basis states."; } elif (nIndices == 1) { // Superposition over one state, so do nothing. } elif (nIndices == 2) { From f66d5bae0995dabfedfaabd4f49e779497f7be14 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Wed, 2 Sep 2020 13:03:33 +0200 Subject: [PATCH 10/11] Addressing reviewer comments. --- Standard/src/Canon/Range.qs | 18 ++++++++++++++++++ Standard/src/Preparation/Arbitrary.qs | 7 ------- 2 files changed, 18 insertions(+), 7 deletions(-) create mode 100644 Standard/src/Canon/Range.qs diff --git a/Standard/src/Canon/Range.qs b/Standard/src/Canon/Range.qs new file mode 100644 index 00000000000..9e9b395dc8e --- /dev/null +++ b/Standard/src/Canon/Range.qs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Canon { + + /// # Summary + /// Returns true if and only if input range is empty. + /// + /// # Remark + /// This function needs to check at most one range index + /// to determine whether the range is empty. + function IsRangeEmpty(rng : Range) : Bool { + for (idx in rng) { + return false; + } + return true; + } +} diff --git a/Standard/src/Preparation/Arbitrary.qs b/Standard/src/Preparation/Arbitrary.qs index fb5afec4a83..575d88eb528 100644 --- a/Standard/src/Preparation/Arbitrary.qs +++ b/Standard/src/Preparation/Arbitrary.qs @@ -259,13 +259,6 @@ namespace Microsoft.Quantum.Preparation { ApproximatelyMultiplexPauli(tolerance, disentangling, axis, actualControl, register[idxTarget]); } - internal function IsRangeEmpty(rng : Range) : Bool { - for (idx in rng) { - return false; - } - return true; - } - internal operation ApplyGlobalRotationStep( angle : Double, idxTarget : Int, register : Qubit[] ) : Unit is Adj + Ctl { From dd51f63dbd4c5ab1cee2d98974f570fc8ff689a4 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Thu, 3 Sep 2020 10:16:50 +0200 Subject: [PATCH 11/11] Docs. --- Standard/src/Canon/Range.qs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Standard/src/Canon/Range.qs b/Standard/src/Canon/Range.qs index 9e9b395dc8e..f920483b7e9 100644 --- a/Standard/src/Canon/Range.qs +++ b/Standard/src/Canon/Range.qs @@ -6,6 +6,13 @@ namespace Microsoft.Quantum.Canon { /// # Summary /// Returns true if and only if input range is empty. /// + /// # Input + /// ## rng + /// Any range + /// + /// # Output + /// True, if and only if `rng` is empty + /// /// # Remark /// This function needs to check at most one range index /// to determine whether the range is empty.