diff --git a/Standard/src/Arithmetic/Asserts.qs b/Standard/src/Arithmetic/Asserts.qs index 3673af4cefc..9b8326c5447 100644 --- a/Standard/src/Arithmetic/Asserts.qs +++ b/Standard/src/Arithmetic/Asserts.qs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Microsoft.Quantum.Arithmetic { @@ -32,14 +32,15 @@ namespace Microsoft.Quantum.Arithmetic { /// ## tolerance /// Absolute tolerance on the difference between actual and expected. /// - /// # Remarks - /// ## Example + /// # Example /// Suppose that the `qubits` register encodes a 3-qubit quantum state /// $\ket{\psi}=\sqrt{1/8}\ket{0}+\sqrt{7/8}\ket{6}$ in little-endian format. /// This means that the number states $\ket{0}\equiv\ket{0}\ket{0}\ket{0}$ /// and $\ket{6}\equiv\ket{0}\ket{1}\ket{1}$. Then the following asserts succeed: - /// - `AssertProbInt(0,0.125,qubits,10e-10);` - /// - `AssertProbInt(6,0.875,qubits,10e-10);` + /// ```qsharp + /// AssertProbInt(0, 0.125, qubits, 10e-10); + /// AssertProbInt(6, 0.875, qubits, 10e-10); + /// ``` operation AssertProbInt(stateIndex : Int, expected : Double, qubits : LittleEndian, tolerance : Double) : Unit { using (flag = Qubit()) { within { @@ -50,17 +51,6 @@ namespace Microsoft.Quantum.Arithmetic { } } - operation AssertSignedProbInt(stateIndex : Int, expected : Double, sign : Qubit, qubits : LittleEndian, tolerance : Double) : Unit { - using (flag = Qubit()) { - let signOffset = expected < 0.0 ? 1 <<< Length(qubits!) | 0; - within { - (ControlledOnInt(stateIndex + signOffset, X))(qubits! + [sign], flag); - } apply { - AssertMeasurementProbability([PauliZ], [flag], One, AbsD(expected), $"AssertSignedProbInt failed on stateIndex {stateIndex}, expected probability {expected}.", tolerance); - } - } - } - /// # Summary /// Asserts that the most significant qubit of a qubit register /// representing an unsigned integer is in a particular state. diff --git a/Standard/src/Preparation/Arbitrary.qs b/Standard/src/Preparation/Arbitrary.qs index 307e67dd094..48e4ed93878 100644 --- a/Standard/src/Preparation/Arbitrary.qs +++ b/Standard/src/Preparation/Arbitrary.qs @@ -12,70 +12,88 @@ namespace Microsoft.Quantum.Preparation { // from the computational basis state $\ket{0...0}$. /// # Summary - /// Returns an operation that prepares the given quantum state. + /// Given a set of coefficients and a little-endian encoded quantum register, + /// prepares an state on that register described by the given coefficients. /// - /// 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}$. + /// # Description + /// This operation 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 \cdots 0}$. + /// In particular, the action of this operation can be simulated by the + /// a unitary transformation $U$ which acts on the all-zeros state as /// - /// 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}}. + /// 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$ coefficients $\alpha_j$. The $j$th coefficient + /// 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$. + /// ## qubits + /// Qubit register encoding number states in little-endian format. This is + /// expected to be initialized in the computational basis state + /// $\ket{0...0}$. /// /// # 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 coefficientsComplexPolar = Mapped(Compose(ComplexPolar(_, 0.0), AbsD), coefficients); - return PrepareArbitraryState(coefficientsComplexPolar, _); + /// 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. + /// + /// # References + /// - Synthesis of Quantum Logic Circuits + /// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov + /// https://arxiv.org/abs/quant-ph/0406176 + /// + /// # See Also + /// - Microsoft.Quantum.Preparation.ApproximatelyPrepareArbitraryState + operation PrepareArbitraryStateCP(coefficients : ComplexPolar[], qubits : LittleEndian) : Unit is Adj + Ctl { + ApproximatelyPrepareArbitraryStateCP(0.0, coefficients, qubits); } /// # Summary - /// Returns an operation that prepares a specific quantum state. + /// Given a set of coefficients and a little-endian encoded quantum register, + /// prepares an state on that register described by the given coefficients. /// - /// The returned operation $U$ prepares an arbitrary quantum + /// # Description + /// This operation 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 $n$-qubit computational basis state $\ket{0 \cdots 0}$. + /// In particular, the action of this operation can be simulated by the + /// a unitary transformation $U$ that acts on the all-zeros state as /// - /// 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}}. + /// 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 + /// Array of up to $2^n$ real coefficients. The $j$th coefficient /// indexes the number state $\ket{j}$ encoded in little-endian format. /// - /// # Output - /// A state-preparation unitary operation $U$. + /// ## qubits + /// Qubit register encoding number states in little-endian format. This is + /// expected to be initialized in the computational basis state + /// $\ket{0...0}$. /// /// # Remarks /// Negative input coefficients $r_j < 0$ will be treated as though @@ -83,30 +101,21 @@ namespace Microsoft.Quantum.Preparation { /// 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}$ - /// in 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); - /// using (qubits = Qubit[2]) { - /// let qubitsLE = LittleEndian(qubits); - /// op(qubitsLE); - /// } - /// ``` - function StatePreparationComplexCoefficients (coefficients : ComplexPolar[]) : (LittleEndian => Unit is Adj + Ctl) { - return PrepareArbitraryState(coefficients, _); + /// # References + /// - Synthesis of Quantum Logic Circuits + /// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov + /// https://arxiv.org/abs/quant-ph/0406176 + /// + /// # See Also + /// - Microsoft.Quantum.Preparation.ApproximatelyPrepareArbitraryState + operation PrepareArbitraryStateD(coefficients : Double[], qubits : LittleEndian) : Unit is Adj + Ctl { + ApproximatelyPrepareArbitraryStateD(0.0, coefficients, qubits); } - /// # Summary /// Given a set of coefficients and a little-endian encoded quantum register, - /// prepares an state on that register described by the given coefficients. + /// prepares an state on that register described by the given coefficients, + /// up to a given approximation tolerance. /// /// # Description /// This operation prepares an arbitrary quantum @@ -128,6 +137,9 @@ namespace Microsoft.Quantum.Preparation { /// $$ /// /// # Input + /// ## tolerance + /// The approximation tolerance to be used when preparing the given state. + /// /// ## coefficients /// Array of up to $2^n$ complex coefficients represented by their /// absolute value and phase $(r_j, t_j)$. The $j$th coefficient @@ -148,11 +160,13 @@ 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 - /// - /// # See Also - /// - Microsoft.Quantum.Preparation.ApproximatelyPrepareArbitraryState - operation PrepareArbitraryState(coefficients : ComplexPolar[], qubits : LittleEndian) : Unit is Adj + Ctl { - ApproximatelyPrepareArbitraryState(0.0, coefficients, qubits); + operation ApproximatelyPrepareArbitraryStateCP( + tolerance : Double, + coefficients : ComplexPolar[], + qubits : LittleEndian + ) + : Unit is Adj + Ctl { + (_CompileApproximateArbitraryStatePreparation(tolerance, coefficients, Length(qubits!)))(qubits); } /// # Summary @@ -184,8 +198,7 @@ namespace Microsoft.Quantum.Preparation { /// The approximation tolerance to be used when preparing the given state. /// /// ## coefficients - /// Array of up to $2^n$ complex coefficients represented by their - /// absolute value and phase $(r_j, t_j)$. The $j$th coefficient + /// Array of up to $2^n$ real coefficients. The $j$th coefficient /// indexes the number state $\ket{j}$ encoded in little-endian format. /// /// ## qubits @@ -203,16 +216,14 @@ 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 - /// - /// # See Also - /// - Microsoft.Quantum.Preparation.ApproximatelyPrepareArbitraryState - operation ApproximatelyPrepareArbitraryState( + operation ApproximatelyPrepareArbitraryStateD( tolerance : Double, - coefficients : ComplexPolar[], + coefficients : Double[], qubits : LittleEndian ) : Unit is Adj + Ctl { - (_CompileApproximateArbitraryStatePreparation(tolerance, coefficients, Length(qubits!)))(qubits); + let coefficientsAsComplexPolar = Mapped(Compose(ComplexPolar(_, 0.0), AbsD), coefficients); + ApproximatelyPrepareArbitraryStateCP(tolerance, coefficientsAsComplexPolar, qubits); } /// # Summary @@ -353,4 +364,3 @@ namespace Microsoft.Quantum.Preparation { } - diff --git a/Standard/src/Preparation/Deprecated.qs b/Standard/src/Preparation/Deprecated.qs index 4fdb28a5d35..e9bf3e7cfba 100644 --- a/Standard/src/Preparation/Deprecated.qs +++ b/Standard/src/Preparation/Deprecated.qs @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. - // Licensed under the MIT License. +// Licensed under the MIT License. namespace Microsoft.Quantum.Preparation { - + open Microsoft.Quantum.Math; open Microsoft.Quantum.Arithmetic; /// # Summary @@ -92,4 +92,236 @@ namespace Microsoft.Quantum.Preparation { : (Int, (Int, Int)) { return (PurifiedMixedStateRequirements(targetError, nCoeffs))!; } + + /// # 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. + /// + /// 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`. + /// + /// # Input + /// ## basis + /// A Pauli operator $P$. + /// ## qubit + /// A qubit to be prepared. + @Deprecated("Microsoft.Quantum.Preparation.PreparePauliEigenstate") + operation PrepareQubit(basis : Pauli, qubit : Qubit) : Unit { + PreparePauliEigenstate(basis, qubit); + } + + /// # Summary + /// Given a set of coefficients and a little-endian encoded quantum register, + /// prepares an state on that register described by the given coefficients. + /// + /// # Description + /// This operation 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 \cdots 0}$. + /// In particular, the action of this operation can be simulated by the + /// a unitary transformation $U$ which acts on the all-zeros state as + /// + /// $$ + /// \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. + /// + /// ## qubits + /// Qubit register encoding number states in little-endian format. This is + /// expected to be initialized in the computational basis state + /// $\ket{0...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. + /// + /// # References + /// - Synthesis of Quantum Logic Circuits + /// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov + /// https://arxiv.org/abs/quant-ph/0406176 + /// + /// # See Also + /// - Microsoft.Quantum.Preparation.ApproximatelyPrepareArbitraryState + @Deprecated("Microsoft.Quantum.Preparation.PrepareArbitraryStateCP") + operation PrepareArbitraryState(coefficients : ComplexPolar[], qubits : LittleEndian) : Unit is Adj + Ctl { + PrepareArbitraryStateCP(coefficients, qubits); + } + + + /// # 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}$ + /// in 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); + /// using (qubits = Qubit[2]) { + /// let qubitsLE = LittleEndian(qubits); + /// op(qubitsLE); + /// } + /// ``` + @Deprecated("Microsoft.Quantum.Preparation.PrepareArbitraryStateCP") + function StatePreparationComplexCoefficients(coefficients : ComplexPolar[]) : (LittleEndian => Unit is Adj + Ctl) { + return PrepareArbitraryStateCP(coefficients, _); + } + + + /// # 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); + /// } + /// ``` + @Deprecated("Microsoft.Quantum.Preparation.PrepareArbitraryStateD") + function StatePreparationPositiveCoefficients(coefficients : Double[]) : (LittleEndian => Unit is Adj + Ctl) { + return PrepareArbitraryStateD(coefficients, _); + } + + + /// # Summary + /// Given a set of coefficients and a little-endian encoded quantum register, + /// prepares an state on that register described by the given coefficients, + /// up to a given approximation tolerance. + /// + /// # Description + /// This operation 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 \cdots 0}$. + /// In particular, the action of this operation can be simulated by the + /// a unitary transformation $U$ which acts on the all-zeros state as + /// + /// $$ + /// \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 + /// ## tolerance + /// The approximation tolerance to be used when preparing the given state. + /// + /// ## 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. + /// + /// ## qubits + /// Qubit register encoding number states in little-endian format. This is + /// expected to be initialized in the computational basis state + /// $\ket{0...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. + /// + /// # References + /// - Synthesis of Quantum Logic Circuits + /// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov + /// https://arxiv.org/abs/quant-ph/0406176 + /// + /// # See Also + /// - Microsoft.Quantum.Preparation.ApproximatelyPrepareArbitraryState + @Deprecated("Microsoft.Quantum.Preparation.ApproximatelyPrepareArbitraryStateCP") + operation ApproximatelyPrepareArbitraryState( + tolerance : Double, + coefficients : ComplexPolar[], + qubits : LittleEndian + ) + : Unit is Adj + Ctl { + ApproximatelyPrepareArbitraryStateCP(tolerance, coefficients, qubits); + } } diff --git a/Standard/src/Preparation/Mixed.qs b/Standard/src/Preparation/Mixed.qs index e23fe4d3588..a13e7390812 100644 --- a/Standard/src/Preparation/Mixed.qs +++ b/Standard/src/Preparation/Mixed.qs @@ -55,10 +55,11 @@ namespace Microsoft.Quantum.Preparation { } /// # Summary - /// Prepares a qubit in the +1 (`Zero`) eigenstate of the given Pauli operator. + /// Prepares a qubit in the positive eigenstate of a given Pauli operator. /// If the identity operator is given, then the qubit is prepared in the maximally /// mixed state. /// + /// # Description /// 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 ). @@ -72,7 +73,17 @@ namespace Microsoft.Quantum.Preparation { /// A Pauli operator $P$. /// ## qubit /// A qubit to be prepared. - operation PrepareQubit (basis : Pauli, qubit : Qubit) : Unit { + /// + /// # Example + /// To prepare a qubit in the $\ket{+}$ state: + /// + /// ```qsharp + /// using (q = Qubit()) { + /// PreparePauliEigenstate(PauliX, qubit); + /// // ... + /// } + /// ``` + operation PreparePauliEigenstate(basis : Pauli, qubit : Qubit) : Unit { if (basis == PauliI) { PrepareSingleQubitIdentity(qubit); } elif (basis == PauliX) { diff --git a/Standard/src/Preparation/QuantumROM.qs b/Standard/src/Preparation/QuantumROM.qs index a5f04748782..599e196090c 100644 --- a/Standard/src/Preparation/QuantumROM.qs +++ b/Standard/src/Preparation/QuantumROM.qs @@ -87,6 +87,9 @@ 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 + /// + /// # See Also + /// - Microsoft.Quantum.Preparation.PurifiedMixedStateWithData function PurifiedMixedState(targetError : Double, coefficients : Double[]) : MixedStatePreparation { let nBitsPrecision = -Ceiling(Lg(0.5 * targetError)) + 1; @@ -95,7 +98,7 @@ namespace Microsoft.Quantum.Preparation { let nCoeffs = Length(positiveCoefficients); let nBitsIndices = Ceiling(Lg(IntAsDouble(nCoeffs))); - let op = PrepareQuantumROMState(nBitsPrecision, nCoeffs, nBitsIndices, keepCoeff, altIndex, new Int[0], _, _, _); + let op = PrepareQuantumROMState(nBitsPrecision, nCoeffs, nBitsIndices, keepCoeff, altIndex, EmptyArray(), _, _, _); let qubitCounts = PurifiedMixedStateRequirements(targetError, nCoeffs); return MixedStatePreparation(qubitCounts, oneNorm, op); } @@ -105,17 +108,56 @@ namespace Microsoft.Quantum.Preparation { } /// # Summary - /// Same as @"microsoft.quantum.preparation.purifiedmixedstate" but - /// also prepares sign of the coefficient on an extra qubit. + /// Returns an operation that prepares a a purification of a given mixed + /// state, entangled with a register representing a given collection of + /// data. + /// + /// # 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$, and a + /// bitstring $\vec{x}_j$ associated with each coefficient, this + /// function returns an operation that uses the Quantum ROM technique to + /// prepare an approximation + /// $$ + /// \begin{align} + /// \tilde\rho = \sum_{j = 0}^{N - 1} p_j \ket{j}\bra{j} \otimes \ket{\vec{x}_j}\bra{\vec{x}_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} \otimes \ket{\vec{x}_j}\bra{\vec{x}_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{\vec{x}_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. - /// Negative numbers $-\alpha_j$ will be treated as positive $|\alpha_j|$, - /// but the sign of a negative number will be prepared on a separate data - /// qubit. + /// Array of $N$ coefficients specifying the probability of basis states, + /// along with the bitstring $\vec{x}_j$ associated with each coefficient. + /// Negative numbers $-\alpha_j$ will be treated as positive $|\alpha_j|$. /// /// # Output /// An operation that prepares $\tilde \rho$ as a purification onto a joint @@ -126,33 +168,23 @@ namespace Microsoft.Quantum.Preparation { /// 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 purifiedState = PurifiedMixedStateAndSign(targetError, coefficients); - /// using ((indexRegister, sign) = (Qubit[purifiedState::Requirements::NIndexQubits], Qubit())) { - /// using (garbageRegister = Qubit[purifiedState::Requirements::NGarbageQubits]) { - /// purifiedState::Prepare(LittleEndian(indexRegister), [sign], garbageRegister); - /// } - /// } - /// ``` + /// # References + /// - 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 /// /// # See Also - /// - PurifiedMixedState - function PurifiedMixedStateAndSign(targetError : Double, coefficients : Double[]) - : MixedStatePreparation { + /// - Microsoft.Quantum.Preparation.PurifiedMixedState + function PurifiedMixedStateWithData(targetError : Double, coefficients : (Double, Bool[])[]) : MixedStatePreparation { + let nBitsPrecision = -Ceiling(Lg(0.5 * targetError)) + 1; - let (positiveCoefficients, signs) = Unzipped(Mapped(SplitSign, coefficients)); + let positiveCoefficients = Mapped(AbsD, Mapped(Fst, coefficients)); + let data = Mapped(Snd, coefficients); let (oneNorm, keepCoeff, altIndex) = _QuantumROMDiscretization(nBitsPrecision, positiveCoefficients); let nCoeffs = Length(positiveCoefficients); let nBitsIndices = Ceiling(Lg(IntAsDouble(nCoeffs))); - let op = PrepareQuantumROMState(nBitsPrecision, nCoeffs, nBitsIndices, keepCoeff, altIndex, signs, _, _, _); + let op = PrepareQuantumROMState(nBitsPrecision, nCoeffs, nBitsIndices, keepCoeff, altIndex, data, _, _, _); let qubitCounts = PurifiedMixedStateRequirements(targetError, nCoeffs); return MixedStatePreparation(qubitCounts w/ NGarbageQubits <- qubitCounts::NGarbageQubits + 1, oneNorm, op); } @@ -265,7 +297,11 @@ namespace Microsoft.Quantum.Preparation { } // Used in QuantumROM implementation. - internal operation PrepareQuantumROMState(nBitsPrecision: Int, nCoeffs: Int, nBitsIndices: Int, keepCoeff: Int[], altIndex: Int[], data : Int[], indexRegister: LittleEndian, dataQubits : Qubit[], garbageRegister: Qubit[]) + internal operation PrepareQuantumROMState( + nBitsPrecision: Int, nCoeffs: Int, nBitsIndices: Int, + keepCoeff: Int[], altIndex: Int[], data : Bool[][], + indexRegister: LittleEndian, dataQubits : Qubit[], garbageRegister: Qubit[] + ) : Unit is Adj + Ctl { let garbageIdx0 = nBitsIndices; let garbageIdx1 = garbageIdx0 + nBitsPrecision; @@ -276,8 +312,8 @@ namespace Microsoft.Quantum.Preparation { let keepCoeffRegister = LittleEndian(garbageRegister[garbageIdx0..garbageIdx1 - 1]); let uniformKeepCoeffRegister = LittleEndian(garbageRegister[garbageIdx1..garbageIdx2 - 1]); let flagQubit = garbageRegister[garbageIdx3 - 1]; - let dataRegister = LittleEndian(dataQubits); - let altDataRegister = LittleEndian(garbageRegister[garbageIdx3...]); + let dataRegister = dataQubits; + let altDataRegister = garbageRegister[garbageIdx3...]; // Create uniform superposition over index and alt coeff register. PrepareUniformSuperposition(nCoeffs, indexRegister); @@ -293,23 +329,23 @@ namespace Microsoft.Quantum.Preparation { let indexRegisterSize = Length(indexRegister!); // Swap in register based on comparison - ApplyToEachCA((Controlled SWAP)([flagQubit], _), Zip(indexRegister! + dataRegister!, altIndexRegister! + altDataRegister!)); + ApplyToEachCA((Controlled SWAP)([flagQubit], _), Zipped(indexRegister! + dataRegister, altIndexRegister! + altDataRegister)); } // Used in QuantumROM implementation. - internal function QuantumROMBitStringWriterByIndex(idx : Int, keepCoeff : Int[], altIndex : Int[], data : Int[]) - : ((LittleEndian, LittleEndian, LittleEndian, LittleEndian) => Unit is Adj + Ctl) { + internal function QuantumROMBitStringWriterByIndex(idx : Int, keepCoeff : Int[], altIndex : Int[], data : Bool[][]) + : ((LittleEndian, LittleEndian, Qubit[], Qubit[]) => Unit is Adj + Ctl) { return WriteQuantumROMBitString(idx, keepCoeff, altIndex, data, _, _, _, _); } // Used in QuantumROM implementation. - internal operation WriteQuantumROMBitString(idx: Int, keepCoeff: Int[], altIndex: Int[], data : Int[], keepCoeffRegister: LittleEndian, altIndexRegister: LittleEndian, dataRegister : LittleEndian, altDataRegister : LittleEndian) + internal operation WriteQuantumROMBitString(idx: Int, keepCoeff: Int[], altIndex: Int[], data : Bool[][], keepCoeffRegister: LittleEndian, altIndexRegister: LittleEndian, dataRegister : Qubit[], altDataRegister : Qubit[]) : Unit is Adj + Ctl { ApplyXorInPlace(keepCoeff[idx], keepCoeffRegister); ApplyXorInPlace(altIndex[idx], altIndexRegister); - if (Length(dataRegister!) > 0) { - ApplyXorInPlace(data[idx], dataRegister); - ApplyXorInPlace(data[altIndex[idx]], altDataRegister); + if (Length(dataRegister) > 0) { + ApplyToEachCA(CControlledCA(X), Zipped(data[idx], dataRegister)); + ApplyToEachCA(CControlledCA(X), Zipped(data[altIndex[idx]], altDataRegister)); } } diff --git a/Standard/tests/QuantumROMTests.qs b/Standard/tests/QuantumROMTests.qs index 2de16c86543..e1d4d33ad11 100644 --- a/Standard/tests/QuantumROMTests.qs +++ b/Standard/tests/QuantumROMTests.qs @@ -3,6 +3,7 @@ namespace Microsoft.Quantum.Tests { + open Microsoft.Quantum.Logical; open Microsoft.Quantum.Arithmetic; open Microsoft.Quantum.Arrays; open Microsoft.Quantum.Intrinsic; @@ -70,38 +71,59 @@ namespace Microsoft.Quantum.Tests { let probtargetError = targetError / IntAsDouble(coeffs); let coefficients = DrawMany(DrawRandomDouble, coeffs, (-1.0, 1.0)); - if (true) { // quantum ROM without sign - let purifiedState = PurifiedMixedState(targetError, coefficients); + let purifiedState = PurifiedMixedState(targetError, coefficients); - using ((coeffRegister, garbageQubits) = (Qubit[purifiedState::Requirements::NIndexQubits], Qubit[purifiedState::Requirements::NGarbageQubits])) { - let coeffQubits = LittleEndian(coeffRegister); + using ((coeffRegister, garbageQubits) = (Qubit[purifiedState::Requirements::NIndexQubits], Qubit[purifiedState::Requirements::NGarbageQubits])) { + let coeffQubits = LittleEndian(coeffRegister); - // Check that probability of each number state in nCoeffQubits is as expected. - within { - purifiedState::Prepare(coeffQubits, new Qubit[0], garbageQubits); - } apply { - for (stateIndex in 0..coeffs - 1) { - let prob = AbsD(coefficients[stateIndex]) / purifiedState::Norm; - AssertProbInt(stateIndex, prob, coeffQubits, probtargetError); - } + // Check that probability of each number state in nCoeffQubits is as expected. + within { + purifiedState::Prepare(coeffQubits, new Qubit[0], garbageQubits); + } apply { + for (stateIndex in 0..coeffs - 1) { + let prob = AbsD(coefficients[stateIndex]) / purifiedState::Norm; + AssertProbInt(stateIndex, prob, coeffQubits, probtargetError); } } } + } + } + } + + // NB: We should consider making this a public operation, perhaps part + // of the improvements in https://github.com/microsoft/QuantumLibraries/issues/337. + internal operation AssertSignedProbInt(stateIndex : Int, expected : Double, sign : Qubit, qubits : LittleEndian, tolerance : Double) : Unit { + using (flag = Qubit()) { + let signOffset = expected < 0.0 ? 1 <<< Length(qubits!) | 0; + within { + (ControlledOnInt(stateIndex + signOffset, X))(qubits! + [sign], flag); + } apply { + AssertMeasurementProbability([PauliZ], [flag], One, AbsD(expected), $"AssertSignedProbInt failed on stateIndex {stateIndex}, expected probability {expected}.", tolerance); + } + } + } + + @Test("QuantumSimulator") + operation TestQuantumROMWithData() : Unit { + for(coeffs in 2..7){ + for(nBitsPrecision in -1..-1..-2){ + let targetError = PowD(2.0, IntAsDouble(nBitsPrecision)); + let probtargetError = targetError / IntAsDouble(coeffs); + let coefficients = DrawMany(DrawRandomDouble, coeffs, (-1.0, 1.0)); + let signs = Mapped(Compose(ConstantArray(1, _), LessThanD(_, 0.0)), coefficients); - if (true) { // quantum ROM with sign - let purifiedState = PurifiedMixedStateAndSign(targetError, coefficients); + let purifiedState = PurifiedMixedStateWithData(targetError, Zipped(coefficients, signs)); - using ((coeffRegister, signQubit, garbageQubits) = (Qubit[purifiedState::Requirements::NIndexQubits], Qubit(), Qubit[purifiedState::Requirements::NGarbageQubits])) { - let coeffQubits = LittleEndian(coeffRegister); + using ((coeffRegister, signQubit, garbageQubits) = (Qubit[purifiedState::Requirements::NIndexQubits], Qubit(), Qubit[purifiedState::Requirements::NGarbageQubits])) { + let coeffQubits = LittleEndian(coeffRegister); - // Check that probability of each number state in nCoeffQubits is as expected. - within { - purifiedState::Prepare(coeffQubits, [signQubit], garbageQubits); - } apply { - for (stateIndex in 0..coeffs - 1) { - let prob = coefficients[stateIndex] / purifiedState::Norm; - AssertSignedProbInt(stateIndex, prob, signQubit, coeffQubits, probtargetError); - } + // Check that probability of each number state in nCoeffQubits is as expected. + within { + purifiedState::Prepare(coeffQubits, [signQubit], garbageQubits); + } apply { + for (stateIndex in 0..coeffs - 1) { + let prob = coefficients[stateIndex] / purifiedState::Norm; + AssertSignedProbInt(stateIndex, prob, signQubit, coeffQubits, probtargetError); } } }