From daa310ccd639e60986e8056284e27ebad4ef5d09 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Thu, 10 Feb 2022 16:39:07 +0100 Subject: [PATCH 1/5] Optimization and formatting. --- .../AmplitudeAmplification.qs | 48 +++++++++++-------- Standard/src/Oracles/Types.qs | 12 ++--- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/Standard/src/AmplitudeAmplification/AmplitudeAmplification.qs b/Standard/src/AmplitudeAmplification/AmplitudeAmplification.qs index 6d600414da3..dffd3047e1b 100644 --- a/Standard/src/AmplitudeAmplification/AmplitudeAmplification.qs +++ b/Standard/src/AmplitudeAmplification/AmplitudeAmplification.qs @@ -5,6 +5,7 @@ namespace Microsoft.Quantum.AmplitudeAmplification { open Microsoft.Quantum.Arrays; open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Convert; + open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Math; open Microsoft.Quantum.Canon; open Microsoft.Quantum.Oracles; @@ -37,16 +38,14 @@ namespace Microsoft.Quantum.AmplitudeAmplification { /// for some unitary $U$. /// By a sequence of reflections about the start and target states on the /// auxiliary register interleaved by applications of `signalOracle` and its - /// adjoint, the success probability of applying U may be altered. + /// adjoint, the success probability of applying U$$ may be altered. /// /// In most cases, `auxiliaryRegister` is initialized in the state $\ket{\text{start}}\_a$. /// /// # References - /// See - /// - [ *D.W. Berry, A.M. Childs, R. Cleve, R. Kothari, R.D. Somma* ](https://arxiv.org/abs/1312.1414) + /// - See [*D.W. Berry, A.M. Childs, R. Cleve, R. Kothari, R.D. Somma*](https://arxiv.org/abs/1312.1414) /// for the standard version. - /// See - /// - [ *G.H. Low, I.L. Chuang* ](https://arxiv.org/abs/1610.06546) + /// - See [*G.H. Low, I.L. Chuang*](https://arxiv.org/abs/1610.06546) /// for a generalization to partial reflections. operation ApplyObliviousAmplitudeAmplification( phases : ReflectionPhases, @@ -57,24 +56,33 @@ namespace Microsoft.Quantum.AmplitudeAmplification { systemRegister : Qubit[] ) : Unit is Adj + Ctl { - for (startPhase, targetPhase) in Zipped(phases!) { + EqualityFactI(Length(phases::AboutStart), Length(phases::AboutTarget), "number of phases about start and target state must be equal"); + let numPhases = Length(phases::AboutStart); + + for (idx, (startPhase, targetPhase)) in Enumerated(Zipped(phases!)) { if startPhase != 0.0 { - startStateReflection::ApplyReflection( - startPhase, auxiliaryRegister - ); + startStateReflection::ApplyReflection(startPhase, auxiliaryRegister); } if targetPhase != 0.0 { - within { + // In the last iteration we do not need to apply `Adjoint signalOracle` + if idx == numPhases - 1 { signalOracle!(auxiliaryRegister, systemRegister); - } apply { - targetStateReflection!(targetPhase, auxiliaryRegister); + targetStateReflection::ApplyReflection(targetPhase, auxiliaryRegister); + } else { + within { + signalOracle!(auxiliaryRegister, systemRegister); + } apply { + targetStateReflection::ApplyReflection(targetPhase, auxiliaryRegister); + } } } } - // This gives us one extra application of Adjoint signalOracle!, so we - // apply the forward direction at the end. - signalOracle!(auxiliaryRegister, systemRegister); + + // We do need one more `signalOracle` call, if the last phase about the target state was 0.0 + if numPhases == 0 or phases::AboutTarget[numPhases - 1] == 0.0 { + signalOracle!(auxiliaryRegister, systemRegister); + } } @@ -90,7 +98,7 @@ namespace Microsoft.Quantum.AmplitudeAmplification { targetStateReflection : ReflectionOracle, signalOracle : ObliviousOracle ) - : ((Qubit[], Qubit[]) => Unit is Adj + Ctl) { + : (Qubit[], Qubit[]) => Unit is Adj + Ctl { return ApplyObliviousAmplitudeAmplification( phases, startStateReflection, targetStateReflection, signalOracle, _, _ @@ -243,9 +251,9 @@ namespace Microsoft.Quantum.AmplitudeAmplification { let systemRegister = []; let signalOracle = ObliviousOracle(NoOp); let startStateOracle = DeterministicStateOracleFromStateOracle(idxFlagQubit, stateOracle); - return (ObliviousAmplitudeAmplificationFromStatePreparation( + return ObliviousAmplitudeAmplificationFromStatePreparation( phases, startStateOracle, signalOracle, idxFlagQubit - ))(_, systemRegister); + )(_, systemRegister); } @@ -324,9 +332,9 @@ namespace Microsoft.Quantum.AmplitudeAmplification { repeat { let queries = 2 ^ exponentCurrent; let phases = FixedPointReflectionPhases(queries, successMin); - (AmplitudeAmplificationFromStatePreparation(phases, statePrepOracle, idxFlagQubit))(qubits); + AmplitudeAmplificationFromStatePreparation(phases, statePrepOracle, idxFlagQubit)(qubits); set finished = M(flagQubit); - set exponentCurrent = exponentCurrent + 1; + set exponentCurrent += 1; } until finished == One or exponentCurrent > exponentMax fixup { diff --git a/Standard/src/Oracles/Types.qs b/Standard/src/Oracles/Types.qs index 24dc04a6085..cb6079325ce 100644 --- a/Standard/src/Oracles/Types.qs +++ b/Standard/src/Oracles/Types.qs @@ -17,7 +17,7 @@ namespace Microsoft.Quantum.Oracles { /// performs a partial reflection by a phase $\phi$ about a single pure state /// $\ket{\psi}$. newtype ReflectionOracle = ( - ApplyReflection: ((Double, Qubit[]) => Unit is Adj + Ctl) + ApplyReflection: (Double, Qubit[]) => Unit is Adj + Ctl ); // This oracle O|s>_a|ψ>_s = λ |t>_a U |ψ>_s + ... acts on the ancilla state |s>_a to implement the unitary U on any system state |ψ>_s with amplitude λ in the |t>_a basis. @@ -37,7 +37,7 @@ namespace Microsoft.Quantum.Oracles { /// $$ /// acts on the ancilla state $\ket{s}\_a$ to implement the unitary $U$ on any system state $\ket{\psi}\_s$ with amplitude $\lambda$ in the basis flagged by $\ket{t}\_a$. /// The first parameter is the qubit register of $\ket{s}\_a$. The second parameter is the qubit register of $\ket{\psi}\_s$. - newtype ObliviousOracle = ((Qubit[], Qubit[]) => Unit is Adj + Ctl); + newtype ObliviousOracle = (Qubit[], Qubit[]) => Unit is Adj + Ctl; /// # Summary /// Represents an oracle for state preparation. @@ -54,7 +54,7 @@ namespace Microsoft.Quantum.Oracles { /// $$ /// acts on the on computational basis state $\ket{0}\_{f}\ket{0}\_s$ to create the target state $\ket{\psi}\_s$ with amplitude $\lambda$ in the basis flagged by $\ket{1}\_f$. /// The first parameter is an index to the qubit register of $\ket{0}\_f$. The second parameter encompassed both registers. - newtype StateOracle = ((Int, Qubit[]) => Unit is Adj + Ctl); + newtype StateOracle = (Int, Qubit[]) => Unit is Adj + Ctl; /// # Summary /// Represents an oracle for deterministic state preparation. @@ -66,7 +66,7 @@ namespace Microsoft.Quantum.Oracles { /// # Remarks /// This oracle defined by $O\ket{0}=\ket{\psi}$ acts on the on computational basis state $\ket{0}$ to create the state $\ket{\psi}$. /// The first parameter is the qubit register of $\ket{\psi}$. - newtype DeterministicStateOracle = (Qubit[] => Unit is Adj + Ctl); + newtype DeterministicStateOracle = Qubit[] => Unit is Adj + Ctl; /// # Summary @@ -75,7 +75,7 @@ namespace Microsoft.Quantum.Oracles { /// # Description /// This is an oracle that implements $U^m$ for a fixed operation $U$ /// and a non-negative integer $m$. - newtype DiscreteOracle = ((Int, Qubit[]) => Unit is Adj + Ctl); + newtype DiscreteOracle = (Int, Qubit[]) => Unit is Adj + Ctl; /// # Summary /// Represents a continuous-time oracle. @@ -85,7 +85,7 @@ namespace Microsoft.Quantum.Oracles { /// $U(\delta t) : \ket{\psi(t)} \mapsto \ket{\psi(t + \delta t)}$ /// for all times $t$, where $U$ is a fixed operation, and where /// $\delta t$ is a non-negative real number. - newtype ContinuousOracle = ((Double, Qubit[]) => Unit is Adj + Ctl); + newtype ContinuousOracle = (Double, Qubit[]) => Unit is Adj + Ctl; } From b5274c72171762dbf0db7ce3646e0b5824ab91f4 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Thu, 10 Feb 2022 17:01:28 +0100 Subject: [PATCH 2/5] Use array API. --- Standard/src/Canon/CommonGates.qs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Standard/src/Canon/CommonGates.qs b/Standard/src/Canon/CommonGates.qs index 4f8a4b29871..ea9886be141 100644 --- a/Standard/src/Canon/CommonGates.qs +++ b/Standard/src/Canon/CommonGates.qs @@ -179,9 +179,7 @@ namespace Microsoft.Quantum.Canon { /// The register whose state is to be rotated by $R$. operation RAll1 (phase : Double, qubits : Qubit[]) : Unit { body (...) { - let nQubits = Length(qubits); - let flagQubit = qubits[0]; - let systemRegister = qubits[1 .. nQubits - 1]; + let (flagQubit, systemRegister) = HeadAndRest(qubits); Controlled (R1(phase, _))(systemRegister, flagQubit); } From d2916d3a5daad016d665c8bfad2ee027321fb95d Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Wed, 16 Feb 2022 13:52:52 +0100 Subject: [PATCH 3/5] Fix errors and add comments with refs to paper. --- .../StandardAlgorithms.qs | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/Standard/src/AmplitudeAmplification/StandardAlgorithms.qs b/Standard/src/AmplitudeAmplification/StandardAlgorithms.qs index 8b92e3a013c..b2ea3633e6d 100644 --- a/Standard/src/AmplitudeAmplification/StandardAlgorithms.qs +++ b/Standard/src/AmplitudeAmplification/StandardAlgorithms.qs @@ -2,8 +2,9 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.AmplitudeAmplification { - open Microsoft.Quantum.Convert; open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Convert; + open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Math; /// # Summary @@ -52,13 +53,27 @@ namespace Microsoft.Quantum.AmplitudeAmplification { /// for phases in the `RotationPhases` format. function FixedPointReflectionPhases(nQueries : Int, successMin : Double) : ReflectionPhases { - let twoPi = 2.0 * PI(); + // In this implementation `nQueries` corresponds to $L$ in + // arXiv:1409.3305. + Fact(nQueries % 2 == 1, "nQueries must be odd"); + + // Initializes L rotation phases, this also initializes the first + // rotation phase with 0.0. mutable phasesRot = [0.0, size = nQueries]; let nQueriesDouble = IntAsDouble(nQueries); - set phasesRot w/= 0 <- 0.0; - let beta = Cosh((1.0 / nQueriesDouble) * ArcCosh(Sqrt(successMin))); - let alpha = Sqrt(1.0 - beta * beta); + // The success probability `successMin` is $1 - \delta^2$ in + // arXiv:1409.3305. Variable `beta` corresponds to $\gamma^{-1}$ in + // arXiv:1409.3305, right below Eq. (11) + let beta = Cosh((1.0 / nQueriesDouble) * ArcCosh(Sqrt(1.0 / (1.0 - successMin)))); + + // `alpha` is $\sqrt(1 - \gamma^2)$ in Eq. (11) in arXiv:1409.3305, + // therefore it is $\sqrt(1 - (1 / \beta^2))$ + let alpha = Sqrt(1.0 - 1.0 / (beta * beta)); + + // Iterative computation of rotation phases is described in Eq. (30) in + // arXiv:1603.03996. In there, we can set $j = 1$. + let twoPi = 2.0 * PI(); for idxPhases in 1 .. nQueries - 1 { set phasesRot w/= idxPhases <- phasesRot[idxPhases - 1] + From 93f4a6382bcc117dfaffd6a8a25061e90e2891a5 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Wed, 16 Feb 2022 13:53:10 +0100 Subject: [PATCH 4/5] Add corner case in conversion of rotation phases. --- Standard/src/AmplitudeAmplification/Convert.qs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Standard/src/AmplitudeAmplification/Convert.qs b/Standard/src/AmplitudeAmplification/Convert.qs index 70c5ace858c..f86be6d0585 100644 --- a/Standard/src/AmplitudeAmplification/Convert.qs +++ b/Standard/src/AmplitudeAmplification/Convert.qs @@ -31,6 +31,11 @@ namespace Microsoft.Quantum.AmplitudeAmplification { mutable phasesTarget = [0.0, size = nPhasesRef]; mutable phasesStart = [0.0, size = nPhasesRef]; + + if nPhasesRot == 1 { + return ReflectionPhases(phasesStart, phasesTarget); + } + set phasesTarget w/= 0 <- ((rotPhases!)[0] - (rotPhases!)[1]) - PI(); set phasesStart w/= 0 <- -(rotPhases!)[0] + 0.5 * PI(); From 0583a46714e3b4b6f426dcb236c87b067bd6bd30 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Tue, 8 Mar 2022 12:09:53 +0100 Subject: [PATCH 5/5] Add test case. --- Standard/tests/AmplitudeAmplificationTests.qs | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/Standard/tests/AmplitudeAmplificationTests.qs b/Standard/tests/AmplitudeAmplificationTests.qs index 16d6dcdc4e6..07f6ce32f6d 100644 --- a/Standard/tests/AmplitudeAmplificationTests.qs +++ b/Standard/tests/AmplitudeAmplificationTests.qs @@ -2,13 +2,15 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Tests { - open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.AmplitudeAmplification; + open Microsoft.Quantum.Arrays; open Microsoft.Quantum.Canon; open Microsoft.Quantum.Convert; open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.AmplitudeAmplification; - open Microsoft.Quantum.Oracles; + open Microsoft.Quantum.Intrinsic; + open Microsoft.Quantum.Logical; open Microsoft.Quantum.Math; + open Microsoft.Quantum.Oracles; ///Here we consider the smallest example of amplitude amplification ///Suppose we have a single-qubit oracle that prepares the state @@ -94,6 +96,18 @@ namespace Microsoft.Quantum.Tests { } } + @Test("QuantumSimulator") + operation TestRotationPhasesAsReflectionPhases() : Unit { + let rotationPhases = RotationPhases([0.1, 0.2, 0.3, 0.4, 0.5]); + let reflectionPhases = RotationPhasesAsReflectionPhases(rotationPhases); + + EqualityFactI(Length(reflectionPhases::AboutStart), 3, "Unexpected length of reflection phases"); + EqualityFactI(Length(reflectionPhases::AboutTarget), 3, "Unexpected length of reflection phases"); + + Fact(All(NearlyEqualD, Zipped(reflectionPhases::AboutStart, [1.4707963267948965,3.041592653589793,3.041592653589793])), "Unexpected reflection phases"); + Fact(All(NearlyEqualD, Zipped(reflectionPhases::AboutTarget, [-3.241592653589793,-3.241592653589793,-1.0707963267948966])), "Unexpected reflection phases"); + } + }