From 8e6095652c82f4a85b15dafcd28ef487afc6cb91 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Wed, 22 Jan 2020 17:28:05 -0800 Subject: [PATCH 01/17] Started work on code quality for M.Q.Preparation. --- Build/check_indents.py | 2 +- .../{StatePreparation.qs => Arbitrary.qs} | 144 ++++++++++++------ Standard/src/Preparation/Deprecated.qs | 10 ++ Standard/src/Preparation/Mixed.qs | 92 +++++++---- .../src/Preparation/UniformSuperposition.qs | 69 +++++---- 5 files changed, 208 insertions(+), 109 deletions(-) rename Standard/src/Preparation/{StatePreparation.qs => Arbitrary.qs} (65%) create mode 100644 Standard/src/Preparation/Deprecated.qs diff --git a/Build/check_indents.py b/Build/check_indents.py index 3e3d6202172..540db399215 100644 --- a/Build/check_indents.py +++ b/Build/check_indents.py @@ -24,7 +24,7 @@ def check_file(filename : str) -> bool: found_spaces = False found_tabs = False - with open(filename, 'r') as f: + with open(filename, 'r', encoding='utf8') as f: contents = list(f.readlines()) for line in contents: diff --git a/Standard/src/Preparation/StatePreparation.qs b/Standard/src/Preparation/Arbitrary.qs similarity index 65% rename from Standard/src/Preparation/StatePreparation.qs rename to Standard/src/Preparation/Arbitrary.qs index ec3f9a6d845..b9a79fdf48b 100644 --- a/Standard/src/Preparation/StatePreparation.qs +++ b/Standard/src/Preparation/Arbitrary.qs @@ -12,8 +12,8 @@ namespace Microsoft.Quantum.Preparation { // from the computational basis state $\ket{0...0}$. /// # Summary - /// Returns an operation that prepares the given quantum state. - /// + /// Returns an operation that prepares the given quantum state. + /// /// The returned operation $U$ prepares an arbitrary quantum /// state $\ket{\psi}$ with positive coefficients $\alpha_j\ge 0$ from /// the $n$-qubit computational basis state $\ket{0...0}$. @@ -61,8 +61,8 @@ namespace Microsoft.Quantum.Preparation { } /// # Summary - /// Returns an operation that prepares a specific quantum state. - /// + /// Returns an operation that prepares a specific quantum state. + /// /// The returned operation $U$ prepares an arbitrary quantum /// state $\ket{\psi}$ with complex coefficients $r_j e^{i t_j}$ from /// the $n$-qubit computational basis state $\ket{0...0}$. @@ -108,47 +108,82 @@ namespace Microsoft.Quantum.Preparation { function StatePreparationComplexCoefficients (coefficients : ComplexPolar[]) : (LittleEndian => Unit is Adj + Ctl) { return PrepareArbitraryState(coefficients, _); } - - + + /// # Summary - /// Returns an operation that prepares a given quantum state. - /// - /// The returned operation $U$ prepares an arbitrary quantum - /// state $\ket{\psi}$ with complex coefficients $r_j e^{i t_j}$ from - /// the $n$-qubit computational basis state $\ket{0...0}$. + /// Given an expansion of an abitrary state in the computational basis, + /// prepares that state on a register of qubits. /// + /// # Description + /// Given a register of qubits initially in the $n$-qubit + /// the $n$-qubit number state $\ket{0}$ (using a little-endian encoding), + /// prepares that register in the state /// $$ /// \begin{align} - /// U\ket{0...0}=\ket{\psi}=\frac{\sum_{j=0}^{2^n-1}r_j e^{i t_j}\ket{j}}{\sqrt{\sum_{j=0}^{2^n-1}|r_j|^2}}. + /// \ket{\psi} & = \frac{ + /// \sum_{j = 0}^{2^n - 1} r_j e^{i t_j} \ket{j} + /// }{ + /// \sqrt{\sum_{j = 0}^{2^n - 1} |r_j|^2} + /// }, /// \end{align} /// $$ + /// where $\{r_j e^{i t_j}\}_{j = 0}^{2^n - 1}$ is a list of complex + /// coefficients representing the state to be prepared. /// /// # Input /// ## coefficients - /// Array of up to $2^n$ complex coefficients represented by their - /// absolute value and phase $(r_j, t_j)$. The $j$th coefficient + /// An array of up to $2^n$ complex coefficients represented by their + /// magnitude and phase $(r_j, t_j)$. The $j$th coefficient /// indexes the number state $\ket{j}$ encoded in little-endian format. /// /// ## qubits /// Qubit register encoding number states in little-endian format. This is - /// expected to be initialized in the computational basis state - /// $\ket{0...0}$. + /// expected to be initialized in the number state $\ket{0}$. /// /// # Remarks /// Negative input coefficients $r_j < 0$ will be treated as though - /// positive with value $|r_j|$. `coefficients` will be padded with - /// elements $(r_j, t_j) = (0.0, 0.0)$ if fewer than $2^n$ are - /// specified. + /// positive with value $|r_j|$. If `coefficients` is shorter than $2^n$ + /// elements, this input will be padded with elements + /// $(r_j, t_j) = (0.0, 0.0)$ (that is, elements representing the coefficient + /// $0$). + /// + /// # Example + /// The following snippet prepares a new three-qubit register in the state + /// $\frac{1}{\sqrt{3}}\left( \sqrt{2} \ket{0} + e^{i \pi / 3} \ket{2} \right)$: + /// + /// ```Q# + /// // Represent 1 / √3 (√2 |0⟩ + e^{𝑖 π / 3} |2⟩) as an array of complex + /// // coefficients. + /// let coefficients = [ + /// ComplexPolar(Sqrt(2.0) / Sqrt(3.0), 0.0), + /// ComplexPolar(0.0, 0.0), + /// ComplexPolar(1.0 / Sqrt(3.0), PI() / 3.0) + /// ]; + /// + /// // Allocate a bare register of three qubits. + /// using (qs = Qubit[3]) { + /// // Use the bare register to create a new little-endian register. + /// // Note that in a little-endian encoding, the computational basis + /// // state |000⟩ encodes the number state |0⟩. + /// let register = LittleEndian(qs); + /// + /// // We can prepare the state represented by the coefficients array + /// // by calling PrepareArbitraryState. + /// PrepareArbitraryState(coefficients, register); + /// // ... + /// } + /// ``` /// /// # References /// - Synthesis of Quantum Logic Circuits /// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov /// https://arxiv.org/abs/quant-ph/0406176 - operation PrepareArbitraryState (coefficients : ComplexPolar[], qubits : LittleEndian) : Unit is Adj + Ctl { + operation PrepareArbitraryState(coefficients : ComplexPolar[], qubits : LittleEndian) + : Unit is Adj + Ctl { // pad coefficients at tail length to a power of 2. - let coefficientsPadded = Padded(-2 ^ Length(qubits!), ComplexPolar(0.0, 0.0), coefficients); + let paddedCoefficients = Padded(-2 ^ Length(qubits!), ComplexPolar(0.0, 0.0), coefficients); let target = (qubits!)[0]; - let op = (Adjoint _PrepareArbitraryState(coefficientsPadded, _, _))(_, target); + let op = (Adjoint _PrepareArbitraryState(paddedCoefficients, _, _))(_, target); op( // Determine what controls to apply to `op`. @@ -165,36 +200,41 @@ namespace Microsoft.Quantum.Preparation { /// # See Also /// - PrepareArbitraryState /// - Microsoft.Quantum.Canon.MultiplexPauli - operation _PrepareArbitraryState(coefficients : ComplexPolar[], control : LittleEndian, target : Qubit) : Unit is Adj + Ctl - { + operation _PrepareArbitraryState(coefficients : ComplexPolar[], control : LittleEndian, target : Qubit) + : Unit is Adj + Ctl { // For each 2D block, compute disentangling single-qubit rotation parameters let (disentanglingY, disentanglingZ, newCoefficients) = _StatePreparationSBMComputeCoefficients(coefficients); MultiplexPauli(disentanglingZ, PauliZ, control, target); MultiplexPauli(disentanglingY, PauliY, control, target); - + // target is now in |0> state up to the phase given by arg of newCoefficients. - + // Continue recursion while there are control qubits. - if (Length(control!) == 0) - { + if (Length(control!) == 0) { let (abs, arg) = newCoefficients[0]!; Exp([PauliI], -1.0 * arg, [target]); - } - else - { + } else { let newControl = LittleEndian((control!)[1 .. Length(control!) - 1]); let newTarget = (control!)[0]; _PrepareArbitraryState(newCoefficients, newControl, newTarget); } } - - + + /// # Summary - /// Computes the Bloch sphere coordinates for a single-qubit state. - /// - /// Given two complex numbers $a0, a1$ that represent the qubit state, computes coordinates - /// on the Bloch sphere such that - /// $a0 \ket{0} + a1 \ket{1} = r e^{it}(e^{-i \phi /2}\cos{(\theta/2)}\ket{0}+e^{i \phi /2}\sin{(\theta/2)}\ket{1})$. + /// Computes the Bloch sphere coordinates for a single-qubit state. + /// + /// # Description + /// Given two complex numbers $a_0$ and $a_1$ represent the single-qubit state, + /// $a_0 \ket{0} + a_1 \ket{1}$, returns coordinates $r$, $t$, $phi$, and + /// $\theta$ on the Bloch sphere such that + /// $$ + /// \begin{align} + /// a_0 \ket{0} + a_1 \ket{1} & = r e^_{i t} \left( + /// e^{-i \phi / 2} \cos(\theta / 2) \ket{0} + + /// e^{ i \phi / 2} \sin(\theta / 2) \ket{1} + /// \right). + /// \end{align} /// /// # Input /// ## a0 @@ -204,16 +244,24 @@ namespace Microsoft.Quantum.Preparation { /// /// # Output /// A tuple containing `(ComplexPolar(r, t), phi, theta)`. - function BlochSphereCoordinates (a0 : ComplexPolar, a1 : ComplexPolar) : (ComplexPolar, Double, Double) - { - let abs0 = AbsComplexPolar(a0); - let abs1 = AbsComplexPolar(a1); - let arg0 = ArgComplexPolar(a0); - let arg1 = ArgComplexPolar(a1); - let r = Sqrt(abs0 * abs0 + abs1 * abs1); - let t = 0.5 * (arg0 + arg1); - let phi = arg1 - arg0; - let theta = 2.0 * ArcTan2(abs1, abs0); + /// + /// # Example + /// ```Q# + /// let coefficients = ( + /// ComplexPolar(Sqrt(2.0) / Sqrt(3.0), 0.0), + /// ComplexPolar(1.0 / Sqrt(3.0), PI() / 3.0) + /// ); + /// let blochSphereCoordinates = BlochSphereCoordinates(coefficients); + /// Message($"{blochSphereCoordinates}"); + /// // Output: + /// // (ComplexPolar((1, 0.5235987755982988)), 1.0471975511965976, 1.2309594173407747) + /// ``` + function BlochSphereCoordinates (a0 : ComplexPolar, a1 : ComplexPolar) + : (ComplexPolar, Double, Double) { + let r = Sqrt(PowD(a0::Magnitude, 2.0) + PowD(a1::Magnitude, 2.0)); + let t = 0.5 * (a0::Argument + a1::Argument); + let phi = a0::Argument - a1::Argument; + let theta = 2.0 * ArcTan2(a0::Magnitude, a1::Magnitude); return (ComplexPolar(r, t), phi, theta); } diff --git a/Standard/src/Preparation/Deprecated.qs b/Standard/src/Preparation/Deprecated.qs new file mode 100644 index 00000000000..4f346636812 --- /dev/null +++ b/Standard/src/Preparation/Deprecated.qs @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Preparation { + + @Deprecated("Microsoft.Quantum.Preparation.PrepareSingleQubitPositivePauliEigenstate") + operation PrepareQubit (basis : Pauli, qubit : Qubit) : Unit { + PrepareSingleQubitPositivePauliEigenstate(basis, qubit); + } +} diff --git a/Standard/src/Preparation/Mixed.qs b/Standard/src/Preparation/Mixed.qs index c4bd4252788..aaf46f69a8c 100644 --- a/Standard/src/Preparation/Mixed.qs +++ b/Standard/src/Preparation/Mixed.qs @@ -7,12 +7,15 @@ namespace Microsoft.Quantum.Preparation { open Microsoft.Quantum.Math; /// # Summary - /// Prepares a qubit in the maximally mixed state. - /// - /// It prepares the given qubit in the $\boldone / 2$ state by applying the depolarizing channel + /// Prepares a qubit in the maximally mixed state. + /// + /// # Description + /// This operation prepares the given qubit in the $\boldone / 2$ state by applying the depolarizing channel /// $$ /// \begin{align} - /// \Omega(\rho) \mathrel{:=} \frac{1}{4} \sum_{\mu \in \{0, 1, 2, 3\}} \sigma\_{\mu} \rho \sigma\_{\mu}^{\dagger}, + /// \Omega(\rho) & \mathrel{:=} + /// \frac{1}{4} \sum_{\mu \in \{0, 1, 2, 3\}} + /// \sigma\_{\mu} \rho \sigma\_{\mu}^{\dagger}, /// \end{align} /// $$ /// where $\sigma\_i$ is the $i$th Pauli operator, and where @@ -31,60 +34,93 @@ namespace Microsoft.Quantum.Preparation { /// to pure states, but it acts as described in expectation. /// In particular, this operation can be used in process tomography /// to measure the *non-unital* components of a channel. + /// + /// As the mapping from an arbitrary density operator to the $\openone / 2$ + /// state is non-unitary, this operation is neither adjointable nor + /// controllable. operation PrepareSingleQubitIdentity(qubit : Qubit) : Unit { ApplyPauli([RandomSingleQubitPauli()], [qubit]); } /// # 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 - /// channel to each qubit, where $N$ is the length of the register. + /// + /// # Description + /// The register is prepared in the $\boldone / 2^N$ state by applying the + /// complete depolarizing channel to each qubit, where $N$ is the length of + /// the register. /// /// # Input /// ## register /// A register whose state is to be depolarized in the manner /// described above. /// + /// # Remarks + /// The mixed state $\boldone / 2^N$ describing the result of + /// applying this operation to a state implicitly describes + /// an expectation value over random choices made in this operation. + /// Thus, for any single application, this operation maps pure states + /// to pure states, but it acts as described in expectation. + /// In particular, this operation can be used in process tomography + /// to measure the *non-unital* components of a channel. + /// + /// As the mapping from an arbitrary density operator to the $\openone / 2^N$ + /// state is non-unitary, this operation is neither adjointable nor + /// controllable. + /// /// # See Also - /// - @"microsoft.quantum.canon.preparesinglequbitidentity" + /// - Microsoft.Quantum.Preparation.PrepareSingleQubitIdentity operation PrepareIdentity(register : Qubit[]) : Unit { ApplyToEach(PrepareSingleQubitIdentity, register); } /// # 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 positive eigenstate of the given Pauli operator. + /// If the identity operator is given, then the qubit is prepared in the maximally + /// mixed state. + /// + /// # Descrition /// 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 ). - /// - /// If the qubit was in a state other than $\ket{0}$, this operation applies the following gates: - /// $H$ for `PauliX`, $HS$ for `PauliY`, $I$ for `PauliZ` and - /// for `PauliI`. + /// in the maximally mixed state instead + /// (see ). /// /// # Input /// ## basis /// A Pauli operator $P$. /// ## qubit - /// A qubit to be prepared. - operation PrepareQubit (basis : Pauli, qubit : Qubit) : Unit { - if (basis == PauliI) - { + /// A qubit to be prepared in the given eigenstate. + /// + /// # Remarks + /// As an invariant of this operation, measuring the input qubit in the basis + /// given by `basis` will result in a `Zero` (corresponding to the $+1$ + /// eigenspace of that basis) immediately following preparation. + /// + /// For example: + /// ```Q# + /// PrepareSingleQubitPositivePauliEigenstate(PauliY, q); + /// EqualityFactR(Measure([PauliY], [q]), Zero, "Error in preparation."); + /// ``` + /// + /// # Example + /// To prepare the $\ket{+}$ state on a qubit `q` initially in the $\ket{0}$ + /// state: + /// ```Q# + /// PrepareSingleQubitPositivePauliEigenstate(PauliX, q); + /// ``` + operation PrepareSingleQubitPositivePauliEigenstate(basis : Pauli, qubit : Qubit) + : Unit { + if (basis == PauliI) { PrepareSingleQubitIdentity(qubit); - } - elif (basis == PauliX) - { + } elif (basis == PauliX) { H(qubit); - } - elif (basis == PauliY) - { + } elif (basis == PauliY) { H(qubit); S(qubit); } + // NB: Since the input qubit starts off in the |0⟩ state as a precondition, + // the preparation for PauliZ is a no-op, so we fall through in that + // case. } } diff --git a/Standard/src/Preparation/UniformSuperposition.qs b/Standard/src/Preparation/UniformSuperposition.qs index 177c43dcef9..727ccb4a954 100644 --- a/Standard/src/Preparation/UniformSuperposition.qs +++ b/Standard/src/Preparation/UniformSuperposition.qs @@ -11,32 +11,37 @@ namespace Microsoft.Quantum.Preparation { open Microsoft.Quantum.Math; /// # Summary - /// Creates a uniform superposition over states that encode 0 through `nIndices`. + /// Creates a uniform superposition over all integers less than a given + /// index. /// - /// That is, this unitary $U$ creates a uniform superposition over all number states - /// $0$ to $M-1$, given an input state $\ket{0\cdots 0}$. In other words, + /// # Description + /// Given a register of qubits representing a little-endian encoded integer + /// and initially in the state $\ket{0}$, this operation prepares the + /// register in the uniform superposition /// $$ /// \begin{align} - /// U\ket{0}=\frac{1}{\sqrt{M}}\sum_{j=0}^{M-1}\ket{j}. + /// \frac{1}{\sqrt{M}} \sum_{j = 0}^{M - 1} \ket{j} /// \end{align} - /// $$. + /// $$ + /// for a given integer $M$. /// /// # Input /// ## nIndices /// The desired number of states $M$ in the uniform superposition. /// ## indexRegister /// The qubit register that stores the number states in `LittleEndian` format. - /// This register must be able to store the number $M-1$, and is assumed to be - /// initialized in the state $\ket{0\cdots 0}$. + /// This register must be able to store the number $M - 1$, and is assumed to be + /// initialized in the state $\ket{0}$ (represented by the computational + /// basis state $\ket{0\cdots 0}). /// - /// # Remarks - /// ## Example + /// # Example /// The following example prepares the state $\frac{1}{\sqrt{6}}\sum_{j=0}^{5}\ket{j}$ - /// on $3$ qubits. + /// on $3$ qubits: /// ``` Q# /// let nIndices = 6; - /// using(indexRegister = Qubit[3]) { + /// using (indexRegister = Qubit[3]) { /// PrepareUniformSuperposition(nIndices, LittleEndian(indexRegister)); + /// // ... /// } /// ``` operation PrepareUniformSuperposition(nIndices: Int, indexRegister: LittleEndian) : Unit is Adj + Ctl { @@ -44,49 +49,49 @@ namespace Microsoft.Quantum.Preparation { fail $"Cannot prepare uniform superposition over {nIndices} 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!)){ + if (nQubits > Length(indexRegister!)) { fail $"Cannot prepare uniform superposition over {nIndices} states as it is larger than the qubit register."; } - using (flagQubit = Qubit[3]) { + using (flagQubits = Qubit[3]) { let targetQubits = indexRegister![0..nQubits - 1]; - let qubits = flagQubit + targetQubits; - let stateOracle = StateOracle(PrepareUniformSuperposition_(nIndices, nQubits, _, _)); + let qubits = flagQubits + targetQubits; + let stateOracle = StateOracle(_PrepareUniformSuperposition(nIndices, nQubits, _, _)); (StandardAmplitudeAmplification(1, stateOracle, 0))(qubits); - ApplyToEachCA(X, flagQubit); + ApplyToEachCA(X, flagQubits); } } } /// # 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; + operation _PrepareUniformSuperposition(nIndices : Int, nQubits : Int, idxFlag : Int, qubits : Qubit[]) + : Unit is Adj + Ctl { + 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) + ); - 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; + Exp([PauliY], -theta, [auxillaryQubits[1]]); + (Controlled X)(auxillaryQubits, flagQubit); } } From 88f219da6daabf8c2ed2ebbfa1531320b0e41020 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 23 Jan 2020 11:30:51 -0800 Subject: [PATCH 02/17] Various quality improvements to arbitrary state prep. --- Standard/src/Preparation/Arbitrary.qs | 51 +++++++++++++++------------ 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/Standard/src/Preparation/Arbitrary.qs b/Standard/src/Preparation/Arbitrary.qs index b9a79fdf48b..eddaf772aa3 100644 --- a/Standard/src/Preparation/Arbitrary.qs +++ b/Standard/src/Preparation/Arbitrary.qs @@ -8,9 +8,6 @@ namespace Microsoft.Quantum.Preparation { open Microsoft.Quantum.Math; open Microsoft.Quantum.Arrays; - // This library returns operations that prepare a specified quantum state - // from the computational basis state $\ket{0...0}$. - /// # Summary /// Returns an operation that prepares the given quantum state. /// @@ -49,7 +46,8 @@ namespace Microsoft.Quantum.Preparation { /// op(qubitsLE); /// } /// ``` - function StatePreparationPositiveCoefficients (coefficients : Double[]) : (LittleEndian => Unit is Adj + Ctl) { + function StatePreparationPositiveCoefficients (coefficients : Double[]) + : (LittleEndian => Unit is Adj + Ctl) { let nCoefficients = Length(coefficients); mutable coefficientsComplexPolar = new ComplexPolar[nCoefficients]; @@ -90,16 +88,14 @@ namespace Microsoft.Quantum.Preparation { /// specified. /// /// ## Example - /// The following snippet prepares the quantum state $\ket{\psi}=e^{i 0.1}\sqrt{1/8}\ket{0}+\sqrt{7/8}\ket{2}$ - /// in the qubit register `qubitsLE`. + /// The following snippet prepares the quantum state + /// $\ket{\psi} = e^{i 0.1} \sqrt{1 / 8} \ket{0} + \sqrt{7 / 8} \ket{2}$ + /// on the qubit register `qubitsLE`: /// ```qsharp /// let amplitudes = [Sqrt(0.125), 0.0, Sqrt(0.875), 0.0]; /// let phases = [0.1, 0.0, 0.0, 0.0]; - /// mutable complexNumbers = new ComplexPolar[4]; - /// for (idx in 0..3) { - /// set complexNumbers[idx] = ComplexPolar(amplitudes[idx], phases[idx]); - /// } - /// let op = StatePreparationComplexCoefficients(complexNumbers); + /// let coefficients = Mapped(ComplexPolar, Zip(amplitudes, phases)); + /// let op = StatePreparationComplexCoefficients(coefficients); /// using (qubits = Qubit[2]) { /// let qubitsLE = LittleEndian(qubits); /// op(qubitsLE); @@ -183,7 +179,7 @@ namespace Microsoft.Quantum.Preparation { // pad coefficients at tail length to a power of 2. let paddedCoefficients = Padded(-2 ^ Length(qubits!), ComplexPolar(0.0, 0.0), coefficients); let target = (qubits!)[0]; - let op = (Adjoint _PrepareArbitraryState(paddedCoefficients, _, _))(_, target); + let op = (Adjoint _UnprepareArbitraryState(paddedCoefficients, _, _))(_, target); op( // Determine what controls to apply to `op`. @@ -196,27 +192,36 @@ namespace Microsoft.Quantum.Preparation { /// # Summary /// Implementation step of arbitrary state preparation procedure. + /// As it is easier to implement an operation that maps the given state + /// to $\ket{0}$, we do that here in an adjointable manner, then take the + /// adjoint to get the desired preparation. /// /// # See Also /// - PrepareArbitraryState /// - Microsoft.Quantum.Canon.MultiplexPauli - operation _PrepareArbitraryState(coefficients : ComplexPolar[], control : LittleEndian, target : Qubit) + operation _UnprepareArbitraryState(coefficients : ComplexPolar[], control : LittleEndian, target : Qubit) : Unit is Adj + Ctl { - // For each 2D block, compute disentangling single-qubit rotation parameters + // For each 2D block, compute disentangling single-qubit rotation + // parameters. let (disentanglingY, disentanglingZ, newCoefficients) = _StatePreparationSBMComputeCoefficients(coefficients); MultiplexPauli(disentanglingZ, PauliZ, control, target); MultiplexPauli(disentanglingY, PauliY, control, target); - // target is now in |0> state up to the phase given by arg of newCoefficients. + // At this point, by having applied the disentanglers above, the target + // qubit is guaranteed to be in the |0⟩ state, up to a global phase + // given by the argument of newCoefficients[0]. + // Since this operation may be called in a controlled fashion, we need + // to correct that phase before recursing. // Continue recursion while there are control qubits. if (Length(control!) == 0) { - let (abs, arg) = newCoefficients[0]!; - Exp([PauliI], -1.0 * arg, [target]); + Exp([PauliI], -(Head(newCoefficients))::Argument, [target]); } else { - let newControl = LittleEndian((control!)[1 .. Length(control!) - 1]); - let newTarget = (control!)[0]; - _PrepareArbitraryState(newCoefficients, newControl, newTarget); + _UnprepareArbitraryState( + newCoefficients, + LittleEndian(Rest(control!)), + Head(control!) + ); } } @@ -267,9 +272,11 @@ namespace Microsoft.Quantum.Preparation { /// # Summary /// Implementation step of arbitrary state preparation procedure. + /// /// # See Also - /// - Microsoft.Quantum.Canon.PrepareArbitraryState - function _StatePreparationSBMComputeCoefficients (coefficients : ComplexPolar[]) : (Double[], Double[], ComplexPolar[]) { + /// - Microsoft.Quantum.Preparation.PrepareArbitraryState + 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]; From e628997b3ef52c2cea3ad4c045c5eff6e52865cf Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 23 Jan 2020 13:43:56 -0800 Subject: [PATCH 03/17] Started refactoring quantum ROM feature. --- Standard/src/Preparation/Deprecated.qs | 21 +- Standard/src/Preparation/QuantumROM.qs | 283 +++++++++++++------------ Standard/src/Preparation/Types.qs | 21 ++ 3 files changed, 194 insertions(+), 131 deletions(-) create mode 100644 Standard/src/Preparation/Types.qs diff --git a/Standard/src/Preparation/Deprecated.qs b/Standard/src/Preparation/Deprecated.qs index 4f346636812..9f7882712d1 100644 --- a/Standard/src/Preparation/Deprecated.qs +++ b/Standard/src/Preparation/Deprecated.qs @@ -3,8 +3,27 @@ namespace Microsoft.Quantum.Preparation { + open Microsoft.Quantum.Arithmetic; + + @Deprecated("Microsoft.Quantum.Preparation.PrepareSingleQubitPositivePauliEigenstate") - operation PrepareQubit (basis : Pauli, qubit : Qubit) : Unit { + operation PrepareQubit(basis : Pauli, qubit : Qubit) : Unit { PrepareSingleQubitPositivePauliEigenstate(basis, qubit); } + + @Deprecated("Microsoft.Quantum.Preparation.MixedStatePreparation") + function QuantumROM(targetError: Double, coefficients: Double[]) + : ((Int, (Int, Int)), Double, ((LittleEndian, Qubit[]) => Unit is Adj + Ctl)) { + let preparation = MixedStatePreparation(targetError, coefficients); + return ( + preparation::Requirements!, + preparation::Norm, + preparation::Prepare + ); + } + + function QuantumROMQubitCount(targetError: Double, nCoeffs: Int) + : (Int, (Int, Int)) { + return (MixedStatePreparationRequirements(targetError, nCoeffs))!; + } } diff --git a/Standard/src/Preparation/QuantumROM.qs b/Standard/src/Preparation/QuantumROM.qs index d2c984ba8fe..2d137c8aa82 100644 --- a/Standard/src/Preparation/QuantumROM.qs +++ b/Standard/src/Preparation/QuantumROM.qs @@ -10,49 +10,74 @@ namespace Microsoft.Quantum.Preparation { open Microsoft.Quantum.Arrays; /// # Summary - /// Uses the Quantum ROM technique to represent a given density matrix. - /// - /// Given a list of $N$ coefficients $\alpha_j$, this returns a unitary $U$ that uses the Quantum-ROM - /// technique to prepare - /// an approximation $\tilde\rho\sum_{j=0}^{N-1}p_j\ket{j}\bra{j}$ of the purification of the density matrix - /// $\rho=\sum_{j=0}^{N-1}\frac{|alpha_j|}{\sum_k |\alpha_k|}\ket{j}\bra{j}$. In this approximation, the - /// error $\epsilon$ is such that $|p_j-\frac{|alpha_j|}{\sum_k |\alpha_k|}|\le \epsilon / N$ and - /// $\|\tilde\rho - \rho\| \le \epsilon$. In other words, + /// Returns an operation that prepares a given mixed state. + /// + /// # Description + /// Uses the Quantum ROM technique to represent a given density matrix, + /// returning that representation as a state preparation operation. + /// + /// In particular, given a list of $N$ coefficients $\alpha_j$, this + /// function returns an operation that uses the Quantum ROM technique to + /// prepare an approximation /// $$ /// \begin{align} - /// U\ket{0}^{\lceil\log_2 N\rceil}\ket{0}^{m}=\sum_{j=0}^{N-1}\sqrt{p_j} \ket{j}\ket{\text{garbage}_j}. + /// \tilde\rho = \sum_{j = 0}^{N - 1} p_j \ket{j}\bra{j} /// \end{align} /// $$ + /// of the mixed state + /// $$ + /// \begin{align} + /// \rho = \sum_{j = 0}^{N-1}\ frac{|alpha_j|}{\sum_k |\alpha_k|} \ket{j}\bra{j}, + /// \end{align} + /// $$ + /// where each $p_j$ is an approximation to the given coefficient $\alpha_j$ + /// such that + /// $$ + /// \begin{align} + /// \left| p_j - \frac{ |\alpha_j| }{ \sum_k |\alpha_k| } \le \frac{\epsilon}{N} + /// \end{align} + /// $$ + /// for each $j$. + /// + /// When passed an index register and a register of garbage qubits, + /// initially in the state $\ket{0} \ket{00\cdots 0}, the returned operation + /// prepares both registers into the purification of $\tilde \rho$, + /// $$ + /// \begin{align} + /// \sum_{j=0}^{N-1} \sqrt{p_j} \ket{j}\ket{\text{garbage}_j}, + /// \end{align} + /// $$ + /// such that resetting and deallocating the garbage register enacts the + /// desired preparation to within the target error $\epsilon$. /// /// # Input /// ## targetError /// The target error $\epsilon$. /// ## coefficients - /// Array of $N$ coefficients specifying the probability of basis states. + /// Array of $N$ coefficients specifying the probability of basis states. /// Negative numbers $-\alpha_j$ will be treated as positive $|\alpha_j|$. /// /// # Output - /// ## First parameter - /// 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. - /// ## Second parameter - /// The one-norm $\sum_j |\alpha_j|$ of the coefficient array. - /// ## Third parameter - /// The unitary $U$. + /// An operation that prepares $\tilde \rho$ as a purification onto a joint + /// index and garbage register. /// /// # Remarks - /// ## Example - /// The following code snippet prepares an purification of the $3$-qubit state - /// $\rho=\sum_{j=0}^{4}\frac{|alpha_j|}{\sum_k |\alpha_k|}\ket{j}\bra{j}$, where - /// $\vec\alpha=(1.0,2.0,3.0,4.0,5.0)$, and the error is `1e-3`; - /// ```qsharp - /// let coefficients = [1.0,2.0,3.0,4.0,5.0]; + /// The coefficients provided to this operation are normalized following the + /// 1-norm, such that the coefficients are always considered to describe a + /// valid categorical probability distribution. + /// + /// # Example + /// The following code snippet prepares an purification of the $3$-qubit state + /// $\rho=\sum_{j=0}^{4}\frac{|alpha_j|}{\sum_k |\alpha_k|}\ket{j}\bra{j}$, where + /// $\vec\alpha=(1.0, 2.0, 3.0, 4.0, 5.0)$, and the target error is + /// $10^{-3}$: + /// ```Q# + /// let coefficients = [1.0, 2.0, 3.0, 4.0, 5.0]; /// let targetError = 1e-3; - /// let ((nTotalQubits, (nIndexQubits, nGarbageQubits)), oneNorm, op) = QuantumROM(targetError, coefficients); - /// using (indexRegister = Qubit[nIndexQubits]) { - /// using (garbageRegister = Qubit[nGarbageQubits]) { - /// op(LittleEndian(indexRegister), garbageRegister); + /// let preparation = MixedStatePreparation(targetError, coefficients); + /// using (indexRegister = Qubit[preparation::Requirements::NIndexQubits]) { + /// using (garbageRegister = Qubit[preparation::Requirements::NGarbageQubits]) { + /// preparation::Prepare(LittleEndian(indexRegister), garbageRegister); /// } /// } /// ``` @@ -61,53 +86,62 @@ 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 MixedStatePreparation(targetError : Double, coefficients : Double[]) + : MixedPreparationOperation { let nBitsPrecision = -Ceiling(Lg(0.5 * targetError)) + 1; let (oneNorm, keepCoeff, altIndex) = _QuantumROMDiscretization(nBitsPrecision, coefficients); let nCoeffs = Length(coefficients); let nBitsIndices = Ceiling(Lg(IntAsDouble(nCoeffs))); let op = _QuantumROMImpl(nBitsPrecision, nCoeffs, nBitsIndices, keepCoeff, altIndex, _, _); - let qubitCounts = QuantumROMQubitCount(targetError, nCoeffs); - return (qubitCounts, oneNorm, op); + let qubitCounts = MixedStatePreparationRequirements(targetError, nCoeffs); + return MixedPreparationOperation(qubitCounts, oneNorm, op); } /// # Summary /// Returns the total number of qubits that must be allocated - /// to the operation returned by `QuantumROM`. + /// to the operation returned by + /// @"microsoft.quantum.preparation.mixedstatepreparation". /// /// # Input /// ## targetError /// The target error $\epsilon$. - /// ## nCoeffs - /// Number of coefficients specified in `QuantumROM`. + /// ## nCoefficients + /// The number of coefficients to be specified in preparing a mixed state. /// /// # Output - /// ## First parameter - /// 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)) - { - let nBitsPrecision = -Ceiling(Lg(0.5*targetError))+1; - let nBitsIndices = Ceiling(Lg(IntAsDouble(nCoeffs))); - let nGarbageQubits = nBitsIndices + 2 * nBitsPrecision + 1; - let nTotal = nGarbageQubits + nBitsIndices; - return (nTotal, (nBitsIndices, nGarbageQubits)); + /// A description of how many qubits are required in total, and for each of + /// the index and garbage registers used by the + /// @"microsoft.quantum.preparation.mixedstatepreparation" function. + /// + /// # See Also + /// - Microsoft.Quantum.Preparation.MixedStatePreparation + function MixedStatePreparationRequirements(targetError : Double, nCoefficients : Int) + : MixedPreparationRequirements { + let nBitsPrecision = -Ceiling(Lg(0.5*targetError)) + 1; + let nIndexQubits = Ceiling(Lg(IntAsDouble(nCoefficients))); + let nGarbageQubits = nIndexQubits + 2 * nBitsPrecision + 1; + let nTotal = nGarbageQubits + nIndexQubits; + return MixedPreparationRequirements(nTotal, (nIndexQubits, 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]); + function _PartitionedForQuantumROM(targetError: Double, nCoeffs: Int, qubits: Qubit[]) + : ((LittleEndian, Qubit[]), Qubit[]) { + let requirements = MixedStatePreparationRequirements(targetError, nCoeffs); + let registers = Partitioned( + [requirements::NIndexQubits, requirements::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}. - function _QuantumROMDiscretization(bitsPrecision: Int, coefficients: Double[]) : (Double, Int[], Int[]) { + // |coefficient[i] * oneNorm - discretizedCoefficient[i] * discreizedOneNorm| * 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) { @@ -120,10 +154,13 @@ namespace Microsoft.Quantum.Preparation { fail $"State must have at least one coefficient > 0"; } - let barHeight = 2^bitsPrecision - 1; + let barHeight = 2 ^ bitsPrecision - 1; - mutable altIndex = RangeAsIntArray(0..nCoefficients-1); - mutable keepCoeff = Mapped(_QuantumROMDiscretizationRoundCoefficients(_, oneNorm, nCoefficients, barHeight), coefficients); + mutable altIndex = RangeAsIntArray(0..nCoefficients - 1); + mutable keepCoeff = Mapped( + _QuantumROMDiscretizationRoundCoefficients(_, oneNorm, nCoefficients, barHeight), + coefficients + ); // Calculate difference between number of discretized bars vs. maximum mutable bars = 0; @@ -133,117 +170,103 @@ namespace Microsoft.Quantum.Preparation { //Message($"Excess bars {bars}."); // Uniformly distribute excess bars across coefficients. for (idx in 0..AbsI(bars) - 1) { - if (bars > 0) { - set keepCoeff w/= idx <- keepCoeff[idx] - 1; - } else { - set keepCoeff w/= idx <- keepCoeff[idx] + 1; - } + set keepCoeff w/= idx <- keepCoeff[idx] + bars > 0 ? 1 | -1; } - mutable barSink = new Int[nCoefficients]; - mutable barSource = new Int[nCoefficients]; - mutable nBarSink = 0; - mutable nBarSource = 0; + mutable barSink = new Int[0]; + mutable barSource = new Int[0]; for (idxCoeff in IndexRange(keepCoeff)) { if (keepCoeff[idxCoeff] > barHeight) { - set barSource w/= nBarSource <- idxCoeff; - set nBarSource = nBarSource + 1; + set barSource += [idxCoeff]; } elif (keepCoeff[idxCoeff] < barHeight) { - set barSink w/= nBarSink <- idxCoeff; - set nBarSink = nBarSink + 1; + set barSink += [idxCoeff]; } } for (rep in 0..nCoefficients * 10) { - if (nBarSource > 0 and nBarSink > 0) { - let idxSink = barSink[nBarSink-1]; - let idxSource = barSource[nBarSource-1]; - set nBarSink = nBarSink - 1; - set nBarSource = nBarSource - 1; + if (Length(barSink) > 0 and Length(barSource) > 0) { + let idxSink = Tail(barSink); + let idxSource = Tail(barSource); + set barSink = Most(barSink); + set barSource = Most(barSource); set keepCoeff w/= idxSource <- keepCoeff[idxSource] - barHeight + keepCoeff[idxSink]; set altIndex w/= idxSink <- idxSource; - if (keepCoeff[idxSource] < barHeight) - { - set barSink w/= nBarSink <- idxSource; - set nBarSink = nBarSink + 1; - } - elif(keepCoeff[idxSource] > barHeight) - { - set barSource w/= nBarSource <- idxSource; - set nBarSource = nBarSource + 1; + if (keepCoeff[idxSource] < barHeight) { + set barSink += [idxSource]; + } elif (keepCoeff[idxSource] > barHeight) { + set barSource += [idxSource]; } - } - elif (nBarSource > 0) { + } elif (Length(barSource) > 0) { //Message($"rep: {rep}, nBarSource {nBarSource}."); - let idxSource = barSource[nBarSource-1]; - set nBarSource = nBarSource - 1; + let idxSource = Tail(barSource); + set barSource = Most(barSource); set keepCoeff w/= idxSource <- barHeight; } else { return (oneNorm, keepCoeff, altIndex); } } - + return (oneNorm, keepCoeff, altIndex); } - + // Used in QuantumROM implementation. function _QuantumROMDiscretizationRoundCoefficients(coefficient: Double, oneNorm: Double, nCoefficients: Int, barHeight: Int) : Int { return Round((AbsD(coefficient) / oneNorm) * IntAsDouble(nCoefficients) * IntAsDouble(barHeight)); } // Used in QuantumROM implementation. - operation _QuantumROMImpl(nBitsPrecision: Int, nCoeffs: Int, nBitsIndices: Int, keepCoeff: Int[], altIndex: Int[], indexRegister: LittleEndian, garbageRegister: Qubit[]) : Unit { - body (...) { - let unitaryGenerator = (nCoeffs, _QuantumROMWriteBitStringUnitary(_, keepCoeff, altIndex)); - let garbageIdx0 = nBitsIndices; - let garbageIdx1 = garbageIdx0 + nBitsPrecision; - let garbageIdx2 = garbageIdx1 + nBitsPrecision; - let garbageIdx3 = garbageIdx2 + 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]; - - // Create uniform superposition over index and alt coeff register. - PrepareUniformSuperposition(nCoeffs, indexRegister); - ApplyToEachCA(H, uniformKeepCoeffRegister!); - - // Write bitstrings to altIndex and keepCoeff register. - MultiplexOperationsFromGenerator(unitaryGenerator, indexRegister, (keepCoeffRegister, altIndexRegister)); - - // Perform comparison - CompareUsingRippleCarry(uniformKeepCoeffRegister, keepCoeffRegister, flagQubit); - - 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])); - } - } - adjoint auto; - controlled auto; - adjoint controlled auto; - } + operation _QuantumROMImpl( + nBitsPrecision: Int, nCoeffs: Int, nBitsIndices: Int, keepCoeff: Int[], + altIndex: Int[], indexRegister: LittleEndian, garbageRegister: Qubit[] + ) + : Unit is Adj + Ctl { + let unitaryGenerator = (nCoeffs, _QuantumROMWriteBitStringUnitary(_, keepCoeff, altIndex)); + let partitionedRegisters = Partitioned([nBitsIndices, nBitsPrecision, nBitsPrecision, 1], garbageRegister); + + let altIndexRegister = LittleEndian(partitionedRegisters[0]); + let keepCoeffRegister = LittleEndian(partitionedRegisters[1]); + let uniformKeepCoeffRegister = LittleEndian(partitionedRegisters[2]); + let flagQubit = partitionedRegisters[3][0]; + + // Create uniform superposition over index and alt coeff register. + PrepareUniformSuperposition(nCoeffs, indexRegister); + ApplyToEachCA(H, uniformKeepCoeffRegister!); + // Write bitstrings to altIndex and keepCoeff register. + MultiplexOperationsFromGenerator(unitaryGenerator, indexRegister, (keepCoeffRegister, altIndexRegister)); + + // Perform comparison + CompareUsingRippleCarry(uniformKeepCoeffRegister, keepCoeffRegister, flagQubit); + + // Swap in register based on comparison + Controlled ApplyToEachCA( + [flagQubit], + ( + SWAP, + Zip(Reversed(indexRegister!), altIndexRegister!) + ) + ); + // for (idx in 0..nBitsIndices - 1) { + // (Controlled SWAP)([flagQubit], (indexRegister![nBitsIndices - idx - 1], altIndexRegister![idx])); + // } + } // Used in QuantumROM implementation. - function _QuantumROMWriteBitStringUnitary(idx: Int, keepCoeff: Int[], altIndex: Int[]) : ((LittleEndian, LittleEndian) => Unit is Adj + Ctl) { + function _QuantumROMWriteBitStringUnitary(idx : Int, keepCoeff : Int[], altIndex : Int[]) + : ((LittleEndian, LittleEndian) => Unit is Adj + Ctl) { return _QuantumROMWriteBitString(idx, keepCoeff, altIndex, _, _); } // Used in QuantumROM implementation. - operation _QuantumROMWriteBitString(idx: Int, keepCoeff: Int[], altIndex: Int[], keepCoeffRegister: LittleEndian, altIndexRegister: LittleEndian) : Unit { - body (...) { - ApplyXorInPlace(keepCoeff[idx], keepCoeffRegister); - ApplyXorInPlace(altIndex[idx], altIndexRegister); - } - adjoint auto; - controlled auto; - adjoint controlled auto; + operation _QuantumROMWriteBitString( + idx: Int, keepCoeff: Int[], altIndex: Int[], + keepCoeffRegister: LittleEndian, altIndexRegister: LittleEndian + ) + : Unit is Adj + Ctl { + ApplyXorInPlace(keepCoeff[idx], keepCoeffRegister); + ApplyXorInPlace(altIndex[idx], altIndexRegister); } diff --git a/Standard/src/Preparation/Types.qs b/Standard/src/Preparation/Types.qs new file mode 100644 index 00000000000..dcb8aeb1369 --- /dev/null +++ b/Standard/src/Preparation/Types.qs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Preparation { + open Microsoft.Quantum.Arithmetic; + + newtype MixedPreparationOperation = ( + Requirements: MixedPreparationRequirements, + Norm: Double, + Prepare: ((LittleEndian, Qubit[]) => Unit is Adj + Ctl) + ); + + newtype MixedPreparationRequirements = ( + NTotalQubits: Int, + ( + NIndexQubits: Int, + NGarbageQubits: Int + ) + ); + +} From 7671cb81ef953cf709514937c1901adfb75d43c7 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 23 Jan 2020 14:01:52 -0800 Subject: [PATCH 04/17] Removed extraneous commented code. --- Standard/src/Preparation/QuantumROM.qs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Standard/src/Preparation/QuantumROM.qs b/Standard/src/Preparation/QuantumROM.qs index 2d137c8aa82..82e7fa43f72 100644 --- a/Standard/src/Preparation/QuantumROM.qs +++ b/Standard/src/Preparation/QuantumROM.qs @@ -249,9 +249,6 @@ namespace Microsoft.Quantum.Preparation { Zip(Reversed(indexRegister!), altIndexRegister!) ) ); - // for (idx in 0..nBitsIndices - 1) { - // (Controlled SWAP)([flagQubit], (indexRegister![nBitsIndices - idx - 1], altIndexRegister![idx])); - // } } // Used in QuantumROM implementation. function _QuantumROMWriteBitStringUnitary(idx : Int, keepCoeff : Int[], altIndex : Int[]) From 48daae980d353fc35b95800937ecd716e6a561c2 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 23 Jan 2020 14:54:31 -0800 Subject: [PATCH 05/17] Added description of preparation verb. --- .../Preparation/Properties/NamespaceInfo.qs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Standard/src/Preparation/Properties/NamespaceInfo.qs b/Standard/src/Preparation/Properties/NamespaceInfo.qs index e858cf88da3..7c15a5f056b 100644 --- a/Standard/src/Preparation/Properties/NamespaceInfo.qs +++ b/Standard/src/Preparation/Properties/NamespaceInfo.qs @@ -3,5 +3,21 @@ /// # Summary /// This namespace contains functions and operations for preparing qubits into -/// arbitrary initial states. +/// different states, given registers in specific initial states. +/// +/// # Description +/// This namespace provides operations for preparing different states, such as +/// entangled states, uniform superposition states, or arbitrary states +/// described by their coefficients in some basis. +/// +/// By contrast with reset operations, the state preparation +/// operations provided by this namespace in general assume that quantum +/// registers provided as input are in fixed initial states, such as +/// the all-zeros state $\ket{00 \cdots 0}$, and prepare desired states +/// accordingly. Thus, preparation operations are more likely to be adjointable, +/// representing "unpreparation," useful for returning returning qubits +/// to their initial state without using intermediate measurements. +/// +/// # See Also +/// - Microsoft.Quantum.Measurement namespace Microsoft.Quantum.Preparation {} From 0410446a1db79a9a78dbc26e8684bb1e8625ab1b Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Mon, 27 Jan 2020 14:14:46 -0800 Subject: [PATCH 06/17] Small improvements. --- Standard/src/Preparation/Arbitrary.qs | 4 ++-- Standard/src/Preparation/Deprecated.qs | 1 + Standard/src/Preparation/QuantumROM.qs | 2 +- Standard/src/Preparation/Reference.qs | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Standard/src/Preparation/Arbitrary.qs b/Standard/src/Preparation/Arbitrary.qs index eddaf772aa3..af010b5f66f 100644 --- a/Standard/src/Preparation/Arbitrary.qs +++ b/Standard/src/Preparation/Arbitrary.qs @@ -261,7 +261,7 @@ namespace Microsoft.Quantum.Preparation { /// // Output: /// // (ComplexPolar((1, 0.5235987755982988)), 1.0471975511965976, 1.2309594173407747) /// ``` - function BlochSphereCoordinates (a0 : ComplexPolar, a1 : ComplexPolar) + function BlochSphereCoordinates(a0 : ComplexPolar, a1 : ComplexPolar) : (ComplexPolar, Double, Double) { let r = Sqrt(PowD(a0::Magnitude, 2.0) + PowD(a1::Magnitude, 2.0)); let t = 0.5 * (a0::Argument + a1::Argument); @@ -275,7 +275,7 @@ namespace Microsoft.Quantum.Preparation { /// /// # See Also /// - Microsoft.Quantum.Preparation.PrepareArbitraryState - function _StatePreparationSBMComputeCoefficients (coefficients : ComplexPolar[]) + function _StatePreparationSBMComputeCoefficients(coefficients : ComplexPolar[]) : (Double[], Double[], ComplexPolar[]) { mutable disentanglingZ = new Double[Length(coefficients) / 2]; mutable disentanglingY = new Double[Length(coefficients) / 2]; diff --git a/Standard/src/Preparation/Deprecated.qs b/Standard/src/Preparation/Deprecated.qs index 9f7882712d1..dea37c7387f 100644 --- a/Standard/src/Preparation/Deprecated.qs +++ b/Standard/src/Preparation/Deprecated.qs @@ -22,6 +22,7 @@ namespace Microsoft.Quantum.Preparation { ); } + @Deprecated("Microsoft.Quantum.Preparation.MixedStatePreparationRequirements") function QuantumROMQubitCount(targetError: Double, nCoeffs: Int) : (Int, (Int, Int)) { return (MixedStatePreparationRequirements(targetError, nCoeffs))!; diff --git a/Standard/src/Preparation/QuantumROM.qs b/Standard/src/Preparation/QuantumROM.qs index 82e7fa43f72..7be3f47a958 100644 --- a/Standard/src/Preparation/QuantumROM.qs +++ b/Standard/src/Preparation/QuantumROM.qs @@ -100,7 +100,7 @@ namespace Microsoft.Quantum.Preparation { /// # Summary /// Returns the total number of qubits that must be allocated - /// to the operation returned by + /// in order to apply the operation returned by /// @"microsoft.quantum.preparation.mixedstatepreparation". /// /// # Input diff --git a/Standard/src/Preparation/Reference.qs b/Standard/src/Preparation/Reference.qs index 9203f0439ec..170fccdc557 100644 --- a/Standard/src/Preparation/Reference.qs +++ b/Standard/src/Preparation/Reference.qs @@ -63,7 +63,7 @@ namespace Microsoft.Quantum.Preparation { /// - PrepareChoiStateA /// - PrepareChoiStateC /// - PrepareChoiStateCA - operation PrepareChoiState (op : (Qubit[] => Unit), reference : Qubit[], target : Qubit[]) : Unit { + operation PrepareChoiState(op : (Qubit[] => Unit), reference : Qubit[], target : Qubit[]) : Unit { PrepareEntangledState(reference, target); op(target); } @@ -87,7 +87,7 @@ namespace Microsoft.Quantum.Preparation { /// /// # See Also /// - PrepareChoiState - operation PrepareChoiStateA (op : (Qubit[] => Unit is Adj), reference : Qubit[], target : Qubit[]) : Unit is Adj { + operation PrepareChoiStateA(op : (Qubit[] => Unit is Adj), reference : Qubit[], target : Qubit[]) : Unit is Adj { PrepareEntangledState(reference, target); op(target); } From e84decf7e27d7315d3915347f938e510850ef07e Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Mon, 27 Jan 2020 17:03:27 -0800 Subject: [PATCH 07/17] Applied a consistent set of names for quantum ROM operations / functions. --- Standard/src/Preparation/Deprecated.qs | 8 ++--- Standard/src/Preparation/QuantumROM.qs | 33 +++++++++++---------- Standard/src/Preparation/Types.qs | 41 ++++++++++++++++++++++++-- 3 files changed, 59 insertions(+), 23 deletions(-) diff --git a/Standard/src/Preparation/Deprecated.qs b/Standard/src/Preparation/Deprecated.qs index dea37c7387f..e9a690d9978 100644 --- a/Standard/src/Preparation/Deprecated.qs +++ b/Standard/src/Preparation/Deprecated.qs @@ -11,10 +11,10 @@ namespace Microsoft.Quantum.Preparation { PrepareSingleQubitPositivePauliEigenstate(basis, qubit); } - @Deprecated("Microsoft.Quantum.Preparation.MixedStatePreparation") + @Deprecated("Microsoft.Quantum.Preparation.PurifiedMixedState") function QuantumROM(targetError: Double, coefficients: Double[]) : ((Int, (Int, Int)), Double, ((LittleEndian, Qubit[]) => Unit is Adj + Ctl)) { - let preparation = MixedStatePreparation(targetError, coefficients); + let preparation = PurifiedMixedState(targetError, coefficients); return ( preparation::Requirements!, preparation::Norm, @@ -22,9 +22,9 @@ namespace Microsoft.Quantum.Preparation { ); } - @Deprecated("Microsoft.Quantum.Preparation.MixedStatePreparationRequirements") + @Deprecated("Microsoft.Quantum.Preparation.PurifiedMixedStateRequirements") function QuantumROMQubitCount(targetError: Double, nCoeffs: Int) : (Int, (Int, Int)) { - return (MixedStatePreparationRequirements(targetError, nCoeffs))!; + return (PurifiedMixedStateRequirements(targetError, nCoeffs))!; } } diff --git a/Standard/src/Preparation/QuantumROM.qs b/Standard/src/Preparation/QuantumROM.qs index 7be3f47a958..1b0e97020e2 100644 --- a/Standard/src/Preparation/QuantumROM.qs +++ b/Standard/src/Preparation/QuantumROM.qs @@ -10,7 +10,8 @@ namespace Microsoft.Quantum.Preparation { open Microsoft.Quantum.Arrays; /// # Summary - /// Returns an operation that prepares a given mixed state. + /// Returns an operation that prepares a a purification of a given mixed + /// state. /// /// # Description /// Uses the Quantum ROM technique to represent a given density matrix, @@ -74,10 +75,10 @@ namespace Microsoft.Quantum.Preparation { /// ```Q# /// let coefficients = [1.0, 2.0, 3.0, 4.0, 5.0]; /// let targetError = 1e-3; - /// let preparation = MixedStatePreparation(targetError, coefficients); - /// using (indexRegister = Qubit[preparation::Requirements::NIndexQubits]) { - /// using (garbageRegister = Qubit[preparation::Requirements::NGarbageQubits]) { - /// preparation::Prepare(LittleEndian(indexRegister), garbageRegister); + /// let purifiedState = PurifiedMixedState(targetError, coefficients); + /// using (indexRegister = Qubit[purifiedState::Requirements::NIndexQubits]) { + /// using (garbageRegister = Qubit[purifiedState::Requirements::NGarbageQubits]) { + /// purifiedState::Prepare(LittleEndian(indexRegister), garbageRegister); /// } /// } /// ``` @@ -86,22 +87,22 @@ 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 MixedStatePreparation(targetError : Double, coefficients : Double[]) - : MixedPreparationOperation { + function PurifiedMixedState(targetError : Double, coefficients : Double[]) + : MixedStatePreparation { let nBitsPrecision = -Ceiling(Lg(0.5 * targetError)) + 1; let (oneNorm, keepCoeff, altIndex) = _QuantumROMDiscretization(nBitsPrecision, coefficients); let nCoeffs = Length(coefficients); let nBitsIndices = Ceiling(Lg(IntAsDouble(nCoeffs))); let op = _QuantumROMImpl(nBitsPrecision, nCoeffs, nBitsIndices, keepCoeff, altIndex, _, _); - let qubitCounts = MixedStatePreparationRequirements(targetError, nCoeffs); - return MixedPreparationOperation(qubitCounts, oneNorm, op); + let qubitCounts = PurifiedMixedStateRequirements(targetError, nCoeffs); + return MixedStatePreparation(qubitCounts, oneNorm, op); } /// # Summary /// Returns the total number of qubits that must be allocated /// in order to apply the operation returned by - /// @"microsoft.quantum.preparation.mixedstatepreparation". + /// @"microsoft.quantum.preparation.purifiedmixedstate". /// /// # Input /// ## targetError @@ -112,24 +113,24 @@ namespace Microsoft.Quantum.Preparation { /// # Output /// A description of how many qubits are required in total, and for each of /// the index and garbage registers used by the - /// @"microsoft.quantum.preparation.mixedstatepreparation" function. + /// @"microsoft.quantum.preparation.purifiedmixedstate" function. /// /// # See Also - /// - Microsoft.Quantum.Preparation.MixedStatePreparation - function MixedStatePreparationRequirements(targetError : Double, nCoefficients : Int) - : MixedPreparationRequirements { + /// - Microsoft.Quantum.Preparation.PurifiedMixedState + function PurifiedMixedStateRequirements(targetError : Double, nCoefficients : Int) + : MixedStatePreparationRequirements { let nBitsPrecision = -Ceiling(Lg(0.5*targetError)) + 1; let nIndexQubits = Ceiling(Lg(IntAsDouble(nCoefficients))); let nGarbageQubits = nIndexQubits + 2 * nBitsPrecision + 1; let nTotal = nGarbageQubits + nIndexQubits; - return MixedPreparationRequirements(nTotal, (nIndexQubits, nGarbageQubits)); + return MixedStatePreparationRequirements(nTotal, (nIndexQubits, nGarbageQubits)); } // Implementation step of `QuantumROM`. This splits a single // qubit array into the subarrays required by the operation. function _PartitionedForQuantumROM(targetError: Double, nCoeffs: Int, qubits: Qubit[]) : ((LittleEndian, Qubit[]), Qubit[]) { - let requirements = MixedStatePreparationRequirements(targetError, nCoeffs); + let requirements = PurifiedMixedStateRequirements(targetError, nCoeffs); let registers = Partitioned( [requirements::NIndexQubits, requirements::NGarbageQubits], qubits diff --git a/Standard/src/Preparation/Types.qs b/Standard/src/Preparation/Types.qs index dcb8aeb1369..70c8392f605 100644 --- a/Standard/src/Preparation/Types.qs +++ b/Standard/src/Preparation/Types.qs @@ -4,13 +4,48 @@ namespace Microsoft.Quantum.Preparation { open Microsoft.Quantum.Arithmetic; - newtype MixedPreparationOperation = ( - Requirements: MixedPreparationRequirements, + /// # Summary + /// Represents a particular mixed state that can be prepared on an index + /// and a garbage register. + /// + /// # Input + /// ## Requirements + /// Specifies the size of the qubit registers required to prepare the + /// mixed state represented by this UDT value. + /// ## Norm + /// Specifies the 1-norm of the coefficients used to define this mixed + /// state. + /// ## Prepare + /// An operation that, given an index register and a garbage register initially + /// in the $\ket{0}$ and $\ket{00\cdots 0}$ states (respectively), + /// prepares the state represented by this UDT value on those registers. + /// + /// # See Also + /// - Microsoft.Quantum.PurifiedMixedState + newtype MixedStatePreparation = ( + Requirements: MixedStatePreparationRequirements, Norm: Double, Prepare: ((LittleEndian, Qubit[]) => Unit is Adj + Ctl) ); - newtype MixedPreparationRequirements = ( + /// # Summary + /// Represents the number of qubits required in order to prepare a given + /// mixed state. + /// + /// # Input + /// ## NTotalQubits + /// The total number of qubits required by the represented state preparation + /// operation. + /// ## NIndexQubits + /// The number of qubits required for the index register used by the + /// represented state preparation operation. + /// ## NGarbageQubits + /// The number of qubits required for the garbage register used by the + /// represented state preparation operation. + /// + /// # See Also + /// - Microsoft.Quantum.PurifiedMixedState + newtype MixedStatePreparationRequirements = ( NTotalQubits: Int, ( NIndexQubits: Int, From 3af5c57246f9d269a38fc2e46e0444bbffc30b16 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Mon, 27 Jan 2020 17:27:28 -0800 Subject: [PATCH 08/17] Workaround for private dependence. --- .../JordanWigner/JordanWignerOptimizedBlockEncoding.qs | 4 ++-- Standard/tests/QuantumROMTests.qs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Chemistry/src/Runtime/JordanWigner/JordanWignerOptimizedBlockEncoding.qs b/Chemistry/src/Runtime/JordanWigner/JordanWignerOptimizedBlockEncoding.qs index 887398988d2..e47834899ff 100644 --- a/Chemistry/src/Runtime/JordanWigner/JordanWignerOptimizedBlockEncoding.qs +++ b/Chemistry/src/Runtime/JordanWigner/JordanWignerOptimizedBlockEncoding.qs @@ -389,8 +389,8 @@ 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); + // FIXME: This is a dependency on a private function from a different assembly! + let ((qROMIdx, qROMGarbage), rest0) = _PartitionedForQuantumROM(targetError, nCoeffs, ctrlRegister); 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]); diff --git a/Standard/tests/QuantumROMTests.qs b/Standard/tests/QuantumROMTests.qs index 31528fb15ff..0977c39c3a9 100644 --- a/Standard/tests/QuantumROMTests.qs +++ b/Standard/tests/QuantumROMTests.qs @@ -86,7 +86,7 @@ namespace Microsoft.Quantum.Tests { Message($"Qubits used: {nGarbageQubits} + {nCoeffQubits}"); using(qubits = Qubit[nTotal]){ - let (register, rest) = _QuantumROMQubitManager(targetError, coeffs, qubits); + let (register, rest) = _PartitionedForQuantumROM(targetError, coeffs, qubits); let (coeffQubits, garbageQubits) = register; op(register); // Now check that probability of each number state in nCoeffQubits is as expected. From d9598676001e18b1583434e923180537395ad356 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Mon, 27 Jan 2020 17:51:02 -0800 Subject: [PATCH 09/17] Begin removing extraneous use of partial application. --- .../Runtime/JordanWigner/StatePreparation.qs | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/Chemistry/src/Runtime/JordanWigner/StatePreparation.qs b/Chemistry/src/Runtime/JordanWigner/StatePreparation.qs index 76269dad4f2..3622b6c20e3 100644 --- a/Chemistry/src/Runtime/JordanWigner/StatePreparation.qs +++ b/Chemistry/src/Runtime/JordanWigner/StatePreparation.qs @@ -38,12 +38,12 @@ namespace Microsoft.Quantum.Chemistry.JordanWigner { // The last term is the reference state. let referenceState = PrepareTrialState((2, [terms[nTerms-1]]), _); - + PrepareUnitaryCoupledClusterState(referenceState, terms[0..nTerms-2], trotterStepSize, qubits); } } - - + + /// # Summary /// Simple state preparation of trial state by occupying /// spin-orbitals @@ -54,23 +54,23 @@ namespace Microsoft.Quantum.Chemistry.JordanWigner { /// ## qubits /// Qubits of Hamiltonian. operation PrepareSingleConfigurationalStateSingleSiteOccupation (qubitIndices : Int[], qubits : Qubit[]) : Unit { - + body (...) { ApplyToEachCA(X, Subarray(qubitIndices, qubits)); } - + adjoint invert; controlled distribute; controlled adjoint distribute; } - - + + function _PrepareSingleConfigurationalStateSingleSiteOccupation (qubitIndices : Int[]) : (Qubit[] => Unit is Adj + Ctl) { - + return PrepareSingleConfigurationalStateSingleSiteOccupation(qubitIndices, _); } - - + + /// # Summary /// Sparse multi-configurational state preparation of trial state by adding excitations /// to initial trial state. @@ -85,34 +85,34 @@ namespace Microsoft.Quantum.Chemistry.JordanWigner { /// ## qubits /// Qubits of Hamiltonian. operation PrepareSparseMultiConfigurationalState (initialStatePreparation : (Qubit[] => Unit), excitations : JordanWignerInputState[], qubits : Qubit[]) : Unit { - + let nExcitations = Length(excitations); - + //FIXME compile error let coefficientsSqrtAbs = Mapped(Compose(Compose(Sqrt, Fst),Fst), excitations); mutable coefficientsSqrtAbs = new Double[nExcitations]; mutable coefficientsNewComplexPolar = new ComplexPolar[nExcitations]; mutable applyFlips = new Int[][nExcitations]; - + for (idx in 0 .. nExcitations - 1) { let (x, excitation) = excitations[idx]!; set coefficientsSqrtAbs w/= idx <- Sqrt(AbsComplexPolar(ComplexAsComplexPolar(Complex(x)))); set coefficientsNewComplexPolar w/= idx <- ComplexPolar(coefficientsSqrtAbs[idx], ArgComplexPolar(ComplexAsComplexPolar(Complex(x)))); set applyFlips w/= idx <- excitation; } - + let nBitsIndices = Ceiling(Lg(IntAsDouble(nExcitations))); - + repeat { mutable success = false; - + using (auxillary = Qubit[nBitsIndices + 1]) { using (flag = Qubit[1]) { let multiplexer = MultiplexerBruteForceFromGenerator(nExcitations, LookupFunction(Mapped(_PrepareSingleConfigurationalStateSingleSiteOccupation, applyFlips))); - (StatePreparationComplexCoefficients(coefficientsNewComplexPolar))(LittleEndian(auxillary)); + PrepareArbitraryState(coefficientsNewComplexPolar, LittleEndian(auxillary)); multiplexer(LittleEndian(auxillary), qubits); - (Adjoint (StatePreparationPositiveCoefficients(coefficientsSqrtAbs)))(LittleEndian(auxillary)); + Adjoint PrepareArbitraryState(coefficientsSqrtAbs, LittleEndian(auxillary)); (ControlledOnInt(0, X))(auxillary, flag[0]); - + // if measurement outcome one we prepared required state let outcome = Measure([PauliZ], flag); set success = outcome == One; @@ -126,9 +126,9 @@ namespace Microsoft.Quantum.Chemistry.JordanWigner { ResetAll(qubits); } } - + /// # Summary - /// Unitary coupled-cluster state preparation of trial state + /// Unitary coupled-cluster state preparation of trial state /// /// # Input /// ## initialStatePreparation From 32c4e05b1f2429e04993c3f69e5228e1d713d9e9 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Tue, 28 Jan 2020 11:17:20 -0800 Subject: [PATCH 10/17] Added type suffixes, focused on only operation form. --- .../Runtime/JordanWigner/StatePreparation.qs | 4 +- Standard/src/Math/Convert.qs | 18 ++ Standard/src/Preparation/Arbitrary.qs | 173 ++++++++---------- Standard/src/Preparation/Deprecated.qs | 27 ++- 4 files changed, 118 insertions(+), 104 deletions(-) diff --git a/Chemistry/src/Runtime/JordanWigner/StatePreparation.qs b/Chemistry/src/Runtime/JordanWigner/StatePreparation.qs index 3622b6c20e3..8c8e4911661 100644 --- a/Chemistry/src/Runtime/JordanWigner/StatePreparation.qs +++ b/Chemistry/src/Runtime/JordanWigner/StatePreparation.qs @@ -108,9 +108,9 @@ namespace Microsoft.Quantum.Chemistry.JordanWigner { using (auxillary = Qubit[nBitsIndices + 1]) { using (flag = Qubit[1]) { let multiplexer = MultiplexerBruteForceFromGenerator(nExcitations, LookupFunction(Mapped(_PrepareSingleConfigurationalStateSingleSiteOccupation, applyFlips))); - PrepareArbitraryState(coefficientsNewComplexPolar, LittleEndian(auxillary)); + PrepareArbitraryStateCP(coefficientsNewComplexPolar, LittleEndian(auxillary)); multiplexer(LittleEndian(auxillary), qubits); - Adjoint PrepareArbitraryState(coefficientsSqrtAbs, LittleEndian(auxillary)); + Adjoint PrepareArbitraryStateD(coefficientsSqrtAbs, LittleEndian(auxillary)); (ControlledOnInt(0, X))(auxillary, flag[0]); // if measurement outcome one we prepared required state diff --git a/Standard/src/Math/Convert.qs b/Standard/src/Math/Convert.qs index 947601cdc75..8353345dd79 100644 --- a/Standard/src/Math/Convert.qs +++ b/Standard/src/Math/Convert.qs @@ -3,6 +3,24 @@ namespace Microsoft.Quantum.Math { + /// # Summary + /// Converts a real floating-point number to a complex number in its polar + /// representation. + /// + /// # Input + /// ## input + /// The real number to be represented as a complex number. + /// + /// # Output + /// A complex number representing the given input in terms of polar + /// coordinates. + function DoubleAsComplexPolar(input : Double) : ComplexPolar { + return ComplexPolar( + AbsD(input), + input < 0.0 ? PI() | 0.0 + ); + } + /// # Summary /// Converts a complex number of type `ComplexPolar` to a complex /// number of type `Complex`. diff --git a/Standard/src/Preparation/Arbitrary.qs b/Standard/src/Preparation/Arbitrary.qs index af010b5f66f..9ccfd7ded49 100644 --- a/Standard/src/Preparation/Arbitrary.qs +++ b/Standard/src/Preparation/Arbitrary.qs @@ -8,104 +8,6 @@ namespace Microsoft.Quantum.Preparation { open Microsoft.Quantum.Math; open Microsoft.Quantum.Arrays; - /// # Summary - /// Returns an operation that prepares the given quantum state. - /// - /// The returned operation $U$ prepares an arbitrary quantum - /// state $\ket{\psi}$ with positive coefficients $\alpha_j\ge 0$ from - /// the $n$-qubit computational basis state $\ket{0...0}$. - /// - /// The action of U on a newly-allocated register is given by - /// $$ - /// \begin{align} - /// U \ket{0\cdots 0} = \ket{\psi} = \frac{\sum_{j=0}^{2^n-1}\alpha_j \ket{j}}{\sqrt{\sum_{j=0}^{2^n-1}|\alpha_j|^2}}. - /// \end{align} - /// $$ - /// - /// # Input - /// ## coefficients - /// Array of up to $2^n$ coefficients $\alpha_j$. The $j$th coefficient - /// indexes the number state $\ket{j}$ encoded in little-endian format. - /// - /// # Output - /// A state-preparation unitary operation $U$. - /// - /// # Remarks - /// Negative input coefficients $\alpha_j < 0$ will be treated as though - /// positive with value $|\alpha_j|$. `coefficients` will be padded with - /// elements $\alpha_j = 0.0$ if fewer than $2^n$ are specified. - /// - /// ## Example - /// The following snippet prepares the quantum state $\ket{\psi}=\sqrt{1/8}\ket{0}+\sqrt{7/8}\ket{2}$ - /// in the qubit register `qubitsLE`. - /// ```qsharp - /// let amplitudes = [Sqrt(0.125), 0.0, Sqrt(0.875), 0.0]; - /// let op = StatePreparationPositiveCoefficients(amplitudes); - /// using (qubits = Qubit[2]) { - /// let qubitsLE = LittleEndian(qubits); - /// 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); - } - - return PrepareArbitraryState(coefficientsComplexPolar, _); - } - - /// # Summary - /// Returns an operation that prepares a specific quantum state. - /// - /// The returned operation $U$ prepares an arbitrary quantum - /// state $\ket{\psi}$ with complex coefficients $r_j e^{i t_j}$ from - /// the $n$-qubit computational basis state $\ket{0...0}$. - /// - /// The action of U on a newly-allocated register is given by - /// $$ - /// \begin{align} - /// U\ket{0...0}=\ket{\psi}=\frac{\sum_{j=0}^{2^n-1}r_j e^{i t_j}\ket{j}}{\sqrt{\sum_{j=0}^{2^n-1}|r_j|^2}}. - /// \end{align} - /// $$ - /// - /// # Input - /// ## coefficients - /// Array of up to $2^n$ complex coefficients represented by their - /// absolute value and phase $(r_j, t_j)$. The $j$th coefficient - /// indexes the number state $\ket{j}$ encoded in little-endian format. - /// - /// # Output - /// A state-preparation unitary operation $U$. - /// - /// # Remarks - /// Negative input coefficients $r_j < 0$ will be treated as though - /// positive with value $|r_j|$. `coefficients` will be padded with - /// elements $(r_j, t_j) = (0.0, 0.0)$ if fewer than $2^n$ are - /// specified. - /// - /// ## Example - /// The following snippet prepares the quantum state - /// $\ket{\psi} = e^{i 0.1} \sqrt{1 / 8} \ket{0} + \sqrt{7 / 8} \ket{2}$ - /// on the qubit register `qubitsLE`: - /// ```qsharp - /// let amplitudes = [Sqrt(0.125), 0.0, Sqrt(0.875), 0.0]; - /// let phases = [0.1, 0.0, 0.0, 0.0]; - /// let coefficients = Mapped(ComplexPolar, Zip(amplitudes, phases)); - /// let op = StatePreparationComplexCoefficients(coefficients); - /// using (qubits = Qubit[2]) { - /// let qubitsLE = LittleEndian(qubits); - /// op(qubitsLE); - /// } - /// ``` - function StatePreparationComplexCoefficients (coefficients : ComplexPolar[]) : (LittleEndian => Unit is Adj + Ctl) { - return PrepareArbitraryState(coefficients, _); - } - - /// # Summary /// Given an expansion of an abitrary state in the computational basis, /// prepares that state on a register of qubits. @@ -165,7 +67,7 @@ namespace Microsoft.Quantum.Preparation { /// /// // We can prepare the state represented by the coefficients array /// // by calling PrepareArbitraryState. - /// PrepareArbitraryState(coefficients, register); + /// PrepareArbitraryStateCP(coefficients, register); /// // ... /// } /// ``` @@ -174,7 +76,7 @@ namespace Microsoft.Quantum.Preparation { /// - Synthesis of Quantum Logic Circuits /// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov /// https://arxiv.org/abs/quant-ph/0406176 - operation PrepareArbitraryState(coefficients : ComplexPolar[], qubits : LittleEndian) + operation PrepareArbitraryStateCP(coefficients : ComplexPolar[], qubits : LittleEndian) : Unit is Adj + Ctl { // pad coefficients at tail length to a power of 2. let paddedCoefficients = Padded(-2 ^ Length(qubits!), ComplexPolar(0.0, 0.0), coefficients); @@ -189,6 +91,77 @@ namespace Microsoft.Quantum.Preparation { ); } + /// # Summary + /// Given an expansion of an abitrary state in the computational basis, + /// prepares that state on a register of qubits. + /// + /// # Description + /// Given a register of qubits initially in the $n$-qubit + /// the $n$-qubit number state $\ket{0}$ (using a little-endian encoding), + /// prepares that register in the state + /// $$ + /// \begin{align} + /// \ket{\psi} & = \frac{ + /// \sum_{j = 0}^{2^n - 1} r_j e^{i t_j} \ket{j} + /// }{ + /// \sqrt{\sum_{j = 0}^{2^n - 1} |r_j|^2} + /// }, + /// \end{align} + /// $$ + /// where $\{r_j e^{i t_j}\}_{j = 0}^{2^n - 1}$ is a list of complex + /// coefficients representing the state to be prepared. + /// + /// # Input + /// ## coefficients + /// An array of up to $2^n$ coefficients. The $j$th coefficient + /// indexes the number state $\ket{j}$ encoded in little-endian format. + /// + /// ## qubits + /// Qubit register encoding number states in little-endian format. This is + /// expected to be initialized in the number state $\ket{0}$. + /// + /// # Remarks + /// If `coefficients` is shorter than $2^n$ elements, this input will be + /// padded with `0.0`. + /// + /// # Example + /// The following snippet prepares a new three-qubit register in the state + /// $\frac{1}{\sqrt{3}}\left( \sqrt{2} \ket{0} + \ket{2} \right)$: + /// + /// ```Q# + /// // Represent 1 / √3 (√2 |0⟩ + e^{𝑖 π / 3} |2⟩) as an array of complex + /// // coefficients. + /// let coefficients = [ + /// Sqrt(2.0) / Sqrt(3.0), + /// 0.0, + /// 1.0 / Sqrt(3.0) + /// ]; + /// + /// // Allocate a bare register of three qubits. + /// using (qs = Qubit[3]) { + /// // Use the bare register to create a new little-endian register. + /// // Note that in a little-endian encoding, the computational basis + /// // state |000⟩ encodes the number state |0⟩. + /// let register = LittleEndian(qs); + /// + /// // We can prepare the state represented by the coefficients array + /// // by calling PrepareArbitraryState. + /// PrepareArbitraryStateD(coefficients, register); + /// // ... + /// } + /// ``` + /// + /// # References + /// - Synthesis of Quantum Logic Circuits + /// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov + /// https://arxiv.org/abs/quant-ph/0406176 + operation PrepareArbitraryStateD(coefficients : Double[], qubits : LittleEndian) + : Unit is Adj + Ctl { + PrepareArbitraryStateCP( + Mapped(DoubleAsComplexPolar, coefficients), + qubits + ); + } /// # Summary /// Implementation step of arbitrary state preparation procedure. diff --git a/Standard/src/Preparation/Deprecated.qs b/Standard/src/Preparation/Deprecated.qs index e9a690d9978..ea970030de8 100644 --- a/Standard/src/Preparation/Deprecated.qs +++ b/Standard/src/Preparation/Deprecated.qs @@ -2,9 +2,8 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Preparation { - open Microsoft.Quantum.Arithmetic; - + open Microsoft.Quantum.Math; @Deprecated("Microsoft.Quantum.Preparation.PrepareSingleQubitPositivePauliEigenstate") operation PrepareQubit(basis : Pauli, qubit : Qubit) : Unit { @@ -27,4 +26,28 @@ namespace Microsoft.Quantum.Preparation { : (Int, (Int, Int)) { return (PurifiedMixedStateRequirements(targetError, nCoeffs))!; } + + @Deprecated("Microsoft.Quantum.Preparation.PrepareArbitraryStateCP") + operation PrepareArbitraryState(coefficients : ComplexPolar[], qubits : LittleEndian) + : Unit is Adj + Ctl { + PrepareArbitraryStateCP(coefficients, qubits); + } + + @Deprecated("Microsoft.Quantum.Preparation.PrepareArbitraryStateCP") + function StatePreparationComplexCoefficients (coefficients : ComplexPolar[]) : (LittleEndian => Unit is Adj + Ctl) { + return PrepareArbitraryStateCP(coefficients, _); + } + + @Deprecated("Microsoft.Quantum.Preparation.PrepareArbitraryStateD") + 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); + } + + return PrepareArbitraryState(coefficientsComplexPolar, _); + } } From 4f3de29dd8db843f1a48dc78d4a773e72319281f Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Tue, 28 Jan 2020 11:21:51 -0800 Subject: [PATCH 11/17] Added test for new conversion function. --- Standard/tests/Math/ConvertTests.qs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 Standard/tests/Math/ConvertTests.qs diff --git a/Standard/tests/Math/ConvertTests.qs b/Standard/tests/Math/ConvertTests.qs new file mode 100644 index 00000000000..2b790e24220 --- /dev/null +++ b/Standard/tests/Math/ConvertTests.qs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Math.Tests { + open Microsoft.Quantum.Math; + open Microsoft.Quantum.Diagnostics; + + @Test("QuantumSimulator") + function DoubleAsComplexPolarTest() : Unit { + EqualityFactCP(ComplexPolar(1.0, 0.0), DoubleAsComplexPolar(1.0), "Expected 1.0 == 1.0 exp(0)."); + EqualityFactCP(ComplexPolar(3.0, PI()), DoubleAsComplexPolar(-3.0), "Expected -3.0 == 3.0 exp(𝑖π)."); + } +} From f5c343f176e1199c9a64f4bd847a23c11c8ba160 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 30 Jan 2020 15:03:07 -0800 Subject: [PATCH 12/17] Typo fix. --- Standard/src/Preparation/Arbitrary.qs | 2 +- Standard/tests/StatePreparationTests.qs | 154 ++++++++++++------------ 2 files changed, 76 insertions(+), 80 deletions(-) diff --git a/Standard/src/Preparation/Arbitrary.qs b/Standard/src/Preparation/Arbitrary.qs index 9ccfd7ded49..82966c3e847 100644 --- a/Standard/src/Preparation/Arbitrary.qs +++ b/Standard/src/Preparation/Arbitrary.qs @@ -238,7 +238,7 @@ namespace Microsoft.Quantum.Preparation { : (ComplexPolar, Double, Double) { let r = Sqrt(PowD(a0::Magnitude, 2.0) + PowD(a1::Magnitude, 2.0)); let t = 0.5 * (a0::Argument + a1::Argument); - let phi = a0::Argument - a1::Argument; + let phi = a1::Argument - a0::Argument; let theta = 2.0 * ArcTan2(a0::Magnitude, a1::Magnitude); return (ComplexPolar(r, t), phi, theta); } diff --git a/Standard/tests/StatePreparationTests.qs b/Standard/tests/StatePreparationTests.qs index b0d03a1295f..fcbe0469a18 100644 --- a/Standard/tests/StatePreparationTests.qs +++ b/Standard/tests/StatePreparationTests.qs @@ -9,6 +9,7 @@ namespace Microsoft.Quantum.Tests { open Microsoft.Quantum.Math; open Microsoft.Quantum.Measurement; open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Diagnostics; // number of qubits, abs(amplitude), phase newtype StatePreparationTestCase = (Int, Double[], Double[]); @@ -19,7 +20,7 @@ namespace Microsoft.Quantum.Tests { 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; @@ -29,7 +30,7 @@ namespace Microsoft.Quantum.Tests { 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; @@ -39,70 +40,70 @@ namespace Microsoft.Quantum.Tests { 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; - + // Loop over multiple qubit tests for (idxTest in 0 .. nTests - 1) { let (nQubits, coefficientsAmplitude, coefficientsPhase) = testCases[idxTest]!; let nCoefficients = Length(coefficientsAmplitude); - + // 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) { let amp = normalizedCoefficients[idxCoeff]; let prob = amp * amp; AssertProbInt(idxCoeff, prob, qubitsLE, tolerance); } - + ResetAll(qubits); } } } - - + + // Test phase factor on 1-qubit uniform superposition. operation StatePreparationComplexCoefficientsQubitPhaseTest () : 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; - + // Loop over tests for (idxTest in 0 .. nTests - 1) { let (nQubits, coefficientsAmplitude, coefficientsPhase) = testCases[idxTest]!; Message($"Test case {idxTest}"); 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 normalizedCoefficients = PNormalized(2.0, coefficientsAmplitude); - + // Test phase factor on uniform superposition let phase = 0.5 * (coefficientsPhase[0] - coefficientsPhase[1]); let amp = normalizedCoefficients[0]; @@ -116,15 +117,16 @@ namespace Microsoft.Quantum.Tests { } } } - - + + // Test probabilities and phases factor of multi-qubit uniform superposition. + @Test("QuantumSimulator") operation StatePreparationComplexCoefficientsMultiQubitPhaseTest () : 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; @@ -136,46 +138,46 @@ namespace Microsoft.Quantum.Tests { 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; - + // Loop over tests for (idxTest in 0 .. nTests - 1) { let (nQubits, coefficientsAmplitude, coefficientsPhase) = testCases[idxTest]!; Message($"Test case {idxTest}"); 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 normalizedCoefficients = PNormalized(2.0, coefficientsAmplitude); - + // Test probability and phases of uniform superposition let op = StatePreparationComplexCoefficients(coefficients); - + using (control = Qubit[1]) { - + // Test probability H(control[0]); Controlled op(control, qubitsLE); X(control[0]); Controlled (ApplyToEachCA(H, _))(control, qubitsLE!); X(control[0]); - + for (idxCoeff in 0 .. nCoefficients - 1) { let amp = normalizedCoefficients[idxCoeff]; let prob = amp * amp; AssertProbInt(idxCoeff, prob, qubitsLE, tolerance); } - + ResetAll(control); ResetAll(qubits); - + //Test phase for (repeats in 0 .. nCoefficients / 2) { H(control[0]); @@ -194,73 +196,67 @@ namespace Microsoft.Quantum.Tests { } } } - - + + // Test probabilities and phases of arbitrary multi-qubit superposition. + @Test("QuantumSimulator") operation StatePreparationComplexCoefficientsArbitraryMultiQubitPhaseTest () : 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 ((idxTestCase, testCase) in Enumerated(testCases)) { + let (nQubits, coefficientsAmplitude, coefficientsPhase) = testCase!; + Message($"Test case {idxTestCase}"); 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); - - using (control = Qubit[1]) { - + let opReal = StatePreparationPositiveCoefficients(coefficientsAmplitude); + + using (control = Qubit()) { + // Test probability - H(control[0]); - Controlled opComplex(control, qubitsLE); - X(control[0]); - Controlled opReal(control, qubitsLE); - X(control[0]); - - for (idxCoeff in 0 .. nCoefficients - 1) { - let amp = normalizedCoefficients[idxCoeff]; - let prob = amp * amp; - AssertProbInt(idxCoeff, prob, qubitsLE, tolerance); + H(control); + Controlled opComplex([control], qubitsLE); + within { + X(control); + } apply { + Controlled opReal([control], qubitsLE); } - - ResetAll(control); + + for ((idxCoeff, coeff) in Enumerated(normalizedCoefficients)) { + AssertProbInt(idxCoeff, coeff * coeff, qubitsLE, tolerance); + } + + Reset(control); ResetAll(qubits); - + // Test phase for (repeats in 0 .. nCoefficients / 2) { - H(control[0]); - Controlled opComplex(control, qubitsLE); - X(control[0]); - Controlled opReal(control, qubitsLE); - X(control[0]); + H(control); + Controlled opComplex([control], qubitsLE); + within { + X(control); + } apply { + Controlled opReal([control], qubitsLE); + } let indexMeasuredInteger = MeasureInteger(qubitsLE); let phase = coefficientsPhase[indexMeasuredInteger]; Message($"StatePreparationComplexCoefficientsTest: expected phase = {phase}."); - AssertPhase(-0.5 * phase, control[0], tolerance); - ResetAll(control); + AssertPhase(-0.5 * phase, control, tolerance); + Reset(control); ResetAll(qubits); } } From abef2252d3dccd5ef75c7bbb79ee4c9f368002c8 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 30 Jan 2020 15:17:20 -0800 Subject: [PATCH 13/17] Add test coverage for BlochSphereCoordinates. --- Standard/src/Preparation/Arbitrary.qs | 2 +- Standard/tests/Preparation/ArbitraryTests.qs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 Standard/tests/Preparation/ArbitraryTests.qs diff --git a/Standard/src/Preparation/Arbitrary.qs b/Standard/src/Preparation/Arbitrary.qs index 82966c3e847..b3ea2a0694a 100644 --- a/Standard/src/Preparation/Arbitrary.qs +++ b/Standard/src/Preparation/Arbitrary.qs @@ -232,7 +232,7 @@ namespace Microsoft.Quantum.Preparation { /// let blochSphereCoordinates = BlochSphereCoordinates(coefficients); /// Message($"{blochSphereCoordinates}"); /// // Output: - /// // (ComplexPolar((1, 0.5235987755982988)), 1.0471975511965976, 1.2309594173407747) + /// // (ComplexPolar((1, 0.5235987755982988)), 1.0471975511965976, 1.9106332362490186) /// ``` function BlochSphereCoordinates(a0 : ComplexPolar, a1 : ComplexPolar) : (ComplexPolar, Double, Double) { diff --git a/Standard/tests/Preparation/ArbitraryTests.qs b/Standard/tests/Preparation/ArbitraryTests.qs new file mode 100644 index 00000000000..1ddc35ffade --- /dev/null +++ b/Standard/tests/Preparation/ArbitraryTests.qs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +namespace Microsoft.Quantum.Preparation.Tests { + open Microsoft.Quantum.Preparation; + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Math; + + @Test("QuantumSimulator") + function BlochSphereCoordinatesFact() : Unit { + let coefficients = ( + ComplexPolar(Sqrt(2.0) / Sqrt(3.0), 0.0), + ComplexPolar(1.0 / Sqrt(3.0), PI() / 3.0) + ); + let (prefactor, phi, theta) = BlochSphereCoordinates(coefficients); + NearEqualityFactCP(prefactor, ComplexPolar(1.0, 0.5235987755982988)); + NearEqualityFactD(phi, 1.0471975511965976); + NearEqualityFactD(theta, 1.9106332362490186); + } +} From 2bb0ae994aa272a38a9cdbc5bb64404a7387934f Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 30 Jan 2020 15:29:55 -0800 Subject: [PATCH 14/17] Improved test quality some. --- .../StatePreparationTests.qs | 75 ++++++++----------- 1 file changed, 32 insertions(+), 43 deletions(-) rename Standard/tests/{ => Preparation}/StatePreparationTests.qs (75%) diff --git a/Standard/tests/StatePreparationTests.qs b/Standard/tests/Preparation/StatePreparationTests.qs similarity index 75% rename from Standard/tests/StatePreparationTests.qs rename to Standard/tests/Preparation/StatePreparationTests.qs index fcbe0469a18..4777c02879e 100644 --- a/Standard/tests/StatePreparationTests.qs +++ b/Standard/tests/Preparation/StatePreparationTests.qs @@ -12,59 +12,47 @@ namespace Microsoft.Quantum.Tests { open Microsoft.Quantum.Diagnostics; // number of qubits, abs(amplitude), phase - newtype StatePreparationTestCase = (Int, Double[], Double[]); - + newtype StatePreparationTestCase = ( + NQubits: Int, + Magnitudes: Double[], + Phases: Double[] + ); + @Test("QuantumSimulator") operation StatePreparationPositiveCoefficientsTest () : 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]!; - let nCoefficients = Length(coefficientsAmplitude); + for ((idxTestCase, testCase) in Enumerated(testCases)) { // Test negative coefficients. Should give same results as positive coefficients. - using (qubits = Qubit[nQubits]) { + using (qubits = Qubit[testCase::NQubits]) { let qubitsLE = LittleEndian(qubits); - let op = StatePreparationPositiveCoefficients(coefficientsAmplitude); + let op = StatePreparationPositiveCoefficients(testCase::Magnitudes); op(qubitsLE); - let normalizedCoefficients = PNormalized(2.0, coefficientsAmplitude); + let normalizedCoefficients = PNormalized(2.0, testCase::Magnitudes); - for (idxCoeff in 0 .. nCoefficients - 1) { - let amp = normalizedCoefficients[idxCoeff]; - let prob = amp * amp; - AssertProbInt(idxCoeff, prob, qubitsLE, tolerance); + for ((idxCoefficient, coefficient) in Enumerated(normalizedCoefficients)) { + AssertProbInt(idxCoefficient, coefficient * coefficient, qubitsLE, tolerance); } ResetAll(qubits); @@ -74,6 +62,7 @@ namespace Microsoft.Quantum.Tests { // Test phase factor on 1-qubit uniform superposition. + @Test("QuantumSimulator") operation StatePreparationComplexCoefficientsQubitPhaseTest () : Unit { let tolerance = 1E-09; From 27ea3fd2098faea3c3f01d30efc9a670b81ba2f4 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Wed, 5 Feb 2020 16:24:37 -0800 Subject: [PATCH 15/17] Fixed a second typo. --- Standard/src/Preparation/Arbitrary.qs | 2 +- Standard/src/Preparation/Deprecated.qs | 2 +- Standard/tests/Preparation/StatePreparationTests.qs | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Standard/src/Preparation/Arbitrary.qs b/Standard/src/Preparation/Arbitrary.qs index b3ea2a0694a..1e04d4fa5cd 100644 --- a/Standard/src/Preparation/Arbitrary.qs +++ b/Standard/src/Preparation/Arbitrary.qs @@ -239,7 +239,7 @@ namespace Microsoft.Quantum.Preparation { let r = Sqrt(PowD(a0::Magnitude, 2.0) + PowD(a1::Magnitude, 2.0)); let t = 0.5 * (a0::Argument + a1::Argument); let phi = a1::Argument - a0::Argument; - let theta = 2.0 * ArcTan2(a0::Magnitude, a1::Magnitude); + let theta = 2.0 * ArcTan2(a1::Magnitude, a0::Magnitude); return (ComplexPolar(r, t), phi, theta); } diff --git a/Standard/src/Preparation/Deprecated.qs b/Standard/src/Preparation/Deprecated.qs index ea970030de8..90640d77e02 100644 --- a/Standard/src/Preparation/Deprecated.qs +++ b/Standard/src/Preparation/Deprecated.qs @@ -48,6 +48,6 @@ namespace Microsoft.Quantum.Preparation { set coefficientsComplexPolar w/= idx <- ComplexPolar(AbsD(coefficients[idx]), 0.0); } - return PrepareArbitraryState(coefficientsComplexPolar, _); + return PrepareArbitraryStateCP(coefficientsComplexPolar, _); } } diff --git a/Standard/tests/Preparation/StatePreparationTests.qs b/Standard/tests/Preparation/StatePreparationTests.qs index 4777c02879e..f8b1b0f284d 100644 --- a/Standard/tests/Preparation/StatePreparationTests.qs +++ b/Standard/tests/Preparation/StatePreparationTests.qs @@ -43,8 +43,6 @@ namespace Microsoft.Quantum.Tests { // Loop over multiple qubit tests for ((idxTestCase, testCase) in Enumerated(testCases)) { - - // Test negative coefficients. Should give same results as positive coefficients. using (qubits = Qubit[testCase::NQubits]) { let qubitsLE = LittleEndian(qubits); let op = StatePreparationPositiveCoefficients(testCase::Magnitudes); From da1e1edd20c82527bc8414e2d6ea100d1a556fff Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Thu, 6 Feb 2020 10:54:27 -0800 Subject: [PATCH 16/17] Slight test improvements. --- Standard/tests/QuantumROMTests.qs | 102 ++++++++++++++---------------- 1 file changed, 49 insertions(+), 53 deletions(-) diff --git a/Standard/tests/QuantumROMTests.qs b/Standard/tests/QuantumROMTests.qs index 0977c39c3a9..fbf273392a4 100644 --- a/Standard/tests/QuantumROMTests.qs +++ b/Standard/tests/QuantumROMTests.qs @@ -3,6 +3,8 @@ namespace Microsoft.Quantum.Tests { + open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Arithmetic; open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Canon; open Microsoft.Quantum.Preparation; @@ -11,93 +13,87 @@ namespace Microsoft.Quantum.Tests { open Microsoft.Quantum.Convert; // Tests the discretization algorithm + @Test("QuantumSimulator") operation _QuantumROMDiscretizationTest() : Unit { - for(rep in 0..20){ - let coeffs = RandomInt(5000)+2; - let bitsPrecision = RandomInt(30)+1; - let barHeight = 2^(bitsPrecision) - 1; - mutable coefficients = new Double[coeffs]; - Message($"Test case coeffs {coeffs}, bitsPrecision {bitsPrecision}"); - for (idx in 0..coeffs-1) - { - set coefficients w/= idx <- 1000.0 * RandomReal(2*bitsPrecision); + for (rep in 0..20) { + let nCoefficients = RandomInt(5000) + 2; + let nBitsPrecision = RandomInt(30) + 1; + let barHeight = 2 ^ nBitsPrecision - 1; + mutable coefficients = new Double[nCoefficients]; + Message($"Test case coeffs {nCoefficients}, bitsPrecision {nBitsPrecision}"); + for (idx in 0..nCoefficients - 1) { + set coefficients w/= idx <- 1000.0 * RandomReal(2 * nBitsPrecision); } // This avoids the case where coefficient are all zeros. - let rnd = RandomInt(coeffs); + let rnd = RandomInt(nCoefficients); set coefficients w/= rnd <- coefficients[rnd] + 1.0; - let (oneNorm, keepCoeff, altIndex) = _QuantumROMDiscretization(bitsPrecision, coefficients); + let (oneNorm, keepCoeff, altIndex) = _QuantumROMDiscretization(nBitsPrecision, coefficients); Message($"One-norm {oneNorm}"); // Reconstruct coefficients - mutable coefficientsOutInt = new Int[coeffs]; - for (idx in 0..coeffs-1) - { + mutable coefficientsOutInt = new Int[nCoefficients]; + for (idx in 0..nCoefficients - 1) { set coefficientsOutInt w/= idx <- coefficientsOutInt[idx] + keepCoeff[idx]; - if (altIndex[idx] >= 0) - { + if (altIndex[idx] >= 0) { set coefficientsOutInt w/= altIndex[idx] <- coefficientsOutInt[altIndex[idx]] + barHeight - keepCoeff[idx]; } } // Reconstruct coefficients - mutable coefficientsOut = new Double[coeffs]; - mutable errors = new Double[coeffs]; + mutable coefficientsOut = new Double[nCoefficients]; + mutable errors = new Double[nCoefficients]; mutable maxError = 0.0; - 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)); + for (i in 0..nCoefficients - 1) { + set coefficientsOut w/= i <- oneNorm * IntAsDouble(coefficientsOutInt[i]) / IntAsDouble(barHeight * nCoefficients); + let error = AbsD(coefficients[i] - coefficientsOut[i]) / oneNorm /( PowD(2.0, IntAsDouble(-nBitsPrecision)) / IntAsDouble(nCoefficients)); set errors w/= i <- error; - if(AbsD(error) > AbsD(maxError)){ - set maxError = error; - } + set maxError = MaxD(AbsD(error), maxError); } - Message($"coeffs {coeffs}, bitsPrecision {bitsPrecision}, maxError {maxError}"); - for(i in 0..coeffs-1){ - if(errors[i] < IntAsDouble(3)){ - // test passes - } - else{ + Message($"coeffs {nCoefficients}, bitsPrecision {nBitsPrecision}, maxError {maxError}"); + for (i in 0..nCoefficients - 1) { + if (errors[i] >= 3.0) { fail $"index {i} reconstructed coefficient incorrect. Error is {errors[i]}"; } } } } + @Test("QuantumSimulator") operation QuantumROMTest() : Unit { - for(coeffs in 2..7){ - for(nBitsPrecision in -1..-1..-2){ + for (coeffs in 2..7) { + for (nBitsPrecision in -1..-1..-2) { let targetError = PowD(2.0, IntAsDouble(nBitsPrecision)); let probtargetError = targetError / IntAsDouble(coeffs); - mutable coefficients = new Double[coeffs]; - for (idx in 0..coeffs-1) - { - set coefficients w/= idx <- RandomReal(2*32); - } - 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; + let coefficients = ForEach(Delay(RandomReal, 2 * 32, _), ConstantArray(coeffs, ())); + let preparation = PurifiedMixedState(targetError, coefficients); + Message($"Test case coeffs {coeffs}, bitsPrecision {preparation::Requirements::NIndexQubits}, global targetError {targetError}, probability error {probtargetError}."); + for (idx in 0..coeffs - 1) { + let tmp = AbsD(coefficients[idx]) / preparation::Norm; Message($"{idx} expected prob = {tmp}."); } - Message($"Qubits used: {nGarbageQubits} + {nCoeffQubits}"); - using(qubits = Qubit[nTotal]){ + Message($"Qubits used: {preparation::Requirements::NGarbageQubits} + {preparation::Requirements::NIndexQubits}"); + using (qubits = Qubit[preparation::Requirements::NTotalQubits]) { let (register, rest) = _PartitionedForQuantumROM(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)); + within { + preparation::Prepare(register); + } apply { + // Now check that probability of each number state in nCoeffQubits is as expected. + for (stateIndex in 0..coeffs - 1) { + let prob = AbsD(coefficients[stateIndex]) / preparation::Norm; + Message($"Testing probability {prob} on index {stateIndex}"); + AssertProbInt( + stateIndex, + prob, + coeffQubits, + targetError / IntAsDouble(coeffs) + ); + } } - (Adjoint op)(register); - } } } From e424747414bfecc4d7fb26b0755eb4bea20dc115 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Wed, 12 Feb 2020 15:37:49 -0800 Subject: [PATCH 17/17] Fix another typo. --- Standard/src/Preparation/QuantumROM.qs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Standard/src/Preparation/QuantumROM.qs b/Standard/src/Preparation/QuantumROM.qs index 1b0e97020e2..0a81c8cf268 100644 --- a/Standard/src/Preparation/QuantumROM.qs +++ b/Standard/src/Preparation/QuantumROM.qs @@ -171,7 +171,7 @@ namespace Microsoft.Quantum.Preparation { //Message($"Excess bars {bars}."); // Uniformly distribute excess bars across coefficients. for (idx in 0..AbsI(bars) - 1) { - set keepCoeff w/= idx <- keepCoeff[idx] + bars > 0 ? 1 | -1; + set keepCoeff w/= idx <- keepCoeff[idx] + (bars > 0 ? -1 | +1); } mutable barSink = new Int[0];