From dca41b508ce92e1fcb636a9b945e454c2cc89301 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Wed, 4 Dec 2019 11:24:18 -0800 Subject: [PATCH 1/8] Consolidated exact and approximate MultiplexZ. --- .../src/Runtime/SpecialMultiplexor.qs | 96 +-------- MachineLearning/src/Runtime/SpecialSP.qs | 4 +- Standard/src/Canon/Utils/Multiplexer.qs | 190 +++++++++--------- 3 files changed, 95 insertions(+), 195 deletions(-) diff --git a/MachineLearning/src/Runtime/SpecialMultiplexor.qs b/MachineLearning/src/Runtime/SpecialMultiplexor.qs index a95ea0f58ec..53716dff73b 100644 --- a/MachineLearning/src/Runtime/SpecialMultiplexor.qs +++ b/MachineLearning/src/Runtime/SpecialMultiplexor.qs @@ -6,7 +6,7 @@ namespace Microsoft.Quantum.Canon { open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Arrays; open Microsoft.Quantum.Math; - + /// # Summary /// Applies a Pauli rotation conditioned on an array of qubits. /// @@ -42,7 +42,7 @@ namespace Microsoft.Quantum.Canon { { if (pauli == PauliZ) { - let op = NoisyMultiplexZ(tolerance, coefficients, control, _); + let op = ApproximatelyMultiplexZ(tolerance, coefficients, control, _); op(target); } elif (pauli == PauliX) @@ -69,97 +69,7 @@ namespace Microsoft.Quantum.Canon { controlled distribute; controlled adjoint distribute; } - - function significantReal(tol: Double, rg:Double[]):Bool - { - for(j in 0..(Length(rg)-1)) - { - if (AbsD(rg[j])>tol) - { - return true; - } - } - return false; - } - - /// # Summary - /// Applies a Pauli Z rotation conditioned on an array of qubits. - /// - /// This applies the multiply-controlled unitary operation $U$ that performs - /// rotations by angle $\theta_j$ about single-qubit Pauli operator $Z$ - /// when controlled by the $n$-qubit number state $\ket{j}$. - /// - /// $U = \sum^{2^n-1}_{j=0}\ket{j}\bra{j}\otimes e^{i Z \theta_j}$. - /// - /// # Input - /// ## coefficients - /// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient - /// indexes the number state $\ket{j}$ encoded in little-endian format. - /// - /// ## control - /// $n$-qubit control register that encodes number states $\ket{j}$ in - /// little-endian format. - /// - /// ## target - /// Single qubit register that is rotated by $e^{i P \theta_j}$. - /// - /// # Remarks - /// `coefficients` will be padded with elements $\theta_j = 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 - operation NoisyMultiplexZ (tolerance: Double, coefficients : Double[], control : LittleEndian, target : Qubit) : Unit - { - body (...) - { - // pad coefficients length at tail to a power of 2. - let coefficientsPadded = Padded(-2 ^ Length(control!), 0.0, coefficients); - - if (Length(coefficientsPadded) == 1) - { - // Termination case - if (AbsD(coefficientsPadded[0])> tolerance) - { - Exp([PauliZ], coefficientsPadded[0], [target]); - } - } - else - { - // Compute new coefficients. - let (coefficients0, coefficients1) = specialMultiplexZComputeCoefficients_(coefficientsPadded); - NoisyMultiplexZ(tolerance,coefficients0, LittleEndian((control!)[0 .. Length(control!) - 2]), target); - if (significantReal(tolerance,coefficients1)) - { - CNOT((control!)[Length(control!) - 1], target); - NoisyMultiplexZ(tolerance,coefficients1, LittleEndian((control!)[0 .. Length(control!) - 2]), target); - CNOT((control!)[Length(control!) - 1], target); - } - } - } - - adjoint invert; - - controlled (controlRegister, ...) - { - // pad coefficients length to a power of 2. - let coefficientsPadded = Padded(2 ^ (Length(control!) + 1), 0.0, Padded(-2 ^ Length(control!), 0.0, coefficients)); - let (coefficients0, coefficients1) = specialMultiplexZComputeCoefficients_(coefficientsPadded); - NoisyMultiplexZ(tolerance,coefficients0, control, target); - if (significantReal(tolerance,coefficients1)) - { - Controlled X(controlRegister, target); - NoisyMultiplexZ(tolerance,coefficients1, control, target); - Controlled X(controlRegister, target); - } - } - - controlled adjoint invert; - } - /// # Summary /// Applies an array of complex phases to numeric basis states of a register of qubits. @@ -202,7 +112,7 @@ namespace Microsoft.Quantum.Canon { // Compute new coefficients. let (coefficients0, coefficients1) = specialMultiplexZComputeCoefficients_(coefficientsPadded); - NoisyMultiplexZ(tolerance,coefficients1, LittleEndian((qubits!)[0 .. Length(qubits!) - 2]), (qubits!)[Length(qubits!) - 1]); + ApproximatelyMultiplexZ(tolerance,coefficients1, LittleEndian((qubits!)[0 .. Length(qubits!) - 2]), (qubits!)[Length(qubits!) - 1]); if (Length(coefficientsPadded) == 2) { diff --git a/MachineLearning/src/Runtime/SpecialSP.qs b/MachineLearning/src/Runtime/SpecialSP.qs index 620e108feff..18568a2a164 100644 --- a/MachineLearning/src/Runtime/SpecialSP.qs +++ b/MachineLearning/src/Runtime/SpecialSP.qs @@ -172,10 +172,10 @@ namespace Microsoft.Quantum.MachineLearning { operation _NoisyPrepareArbitraryState(tolerance: Double, coefficients : ComplexPolar[], control : LittleEndian, target : Qubit) : Unit is Adj + Ctl { // For each 2D block, compute disentangling single-qubit rotation parameters let (disentanglingY, disentanglingZ, newCoefficients) = _NoisyStatePreparationSBMComputeCoefficients(coefficients); - if (significantReal(tolerance,disentanglingZ)) { + if (_AnyOutsideTolerance(tolerance,disentanglingZ)) { NoisyMultiplexPauli(tolerance,disentanglingZ, PauliZ, control, target); } - if (significantReal(tolerance,disentanglingY)) { + if (_AnyOutsideTolerance(tolerance,disentanglingY)) { NoisyMultiplexPauli(tolerance,disentanglingY, PauliY, control, target); } // target is now in |0> state up to the phase given by arg of newCoefficients. diff --git a/Standard/src/Canon/Utils/Multiplexer.qs b/Standard/src/Canon/Utils/Multiplexer.qs index f6cfce0f835..eb577004ecc 100644 --- a/Standard/src/Canon/Utils/Multiplexer.qs +++ b/Standard/src/Canon/Utils/Multiplexer.qs @@ -10,6 +10,7 @@ namespace Microsoft.Quantum.Canon { /// # Summary /// Applies a Pauli rotation conditioned on an array of qubits. /// + /// # Description /// This applies the multiply-controlled unitary operation $U$ that performs /// rotations by angle $\theta_j$ about single-qubit Pauli operator $P$ /// when controlled by the $n$-qubit number state $\ket{j}$. @@ -34,44 +35,27 @@ namespace Microsoft.Quantum.Canon { /// # Remarks /// `coefficients` will be padded with elements $\theta_j = 0.0$ if /// fewer than $2^n$ are specified. - operation MultiplexPauli (coefficients : Double[], pauli : Pauli, control : LittleEndian, target : Qubit) : Unit - { - body (...) - { - if (pauli == PauliZ) - { - let op = MultiplexZ(coefficients, control, _); - op(target); - } - elif (pauli == PauliX) - { - let op = MultiplexPauli(coefficients, PauliZ, control, _); - ApplyWithCA(H, op, target); - } - elif (pauli == PauliY) - { - let op = MultiplexPauli(coefficients, PauliX, control, _); - ApplyWithCA(Adjoint S, op, target); - } - elif (pauli == PauliI) - { - ApplyDiagonalUnitary(coefficients, control); - } - else - { - fail $"MultiplexPauli failed. Invalid pauli {pauli}."; - } + operation MultiplexPauli (coefficients : Double[], pauli : Pauli, control : LittleEndian, target : Qubit) + : Unit is Adj + Ctl { + if (pauli == PauliZ) { + let op = MultiplexZ(coefficients, control, _); + op(target); + } elif (pauli == PauliX) { + let op = MultiplexPauli(coefficients, PauliZ, control, _); + ApplyWithCA(H, op, target); + } elif (pauli == PauliY) { + let op = MultiplexPauli(coefficients, PauliX, control, _); + ApplyWithCA(Adjoint S, op, target); + } elif (pauli == PauliI) { + ApplyDiagonalUnitary(coefficients, control); + } else { + fail $"MultiplexPauli failed. Invalid pauli {pauli}."; } - - adjoint invert; - controlled distribute; - controlled adjoint distribute; } - - + /// # Summary /// Applies a Pauli Z rotation conditioned on an array of qubits. - /// + /// /// This applies the multiply-controlled unitary operation $U$ that performs /// rotations by angle $\theta_j$ about single-qubit Pauli operator $Z$ /// when controlled by the $n$-qubit number state $\ket{j}$. @@ -98,46 +82,65 @@ namespace Microsoft.Quantum.Canon { /// - Synthesis of Quantum Logic Circuits /// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov /// https://arxiv.org/abs/quant-ph/0406176 - operation MultiplexZ (coefficients : Double[], control : LittleEndian, target : Qubit) : Unit - { - body (...) - { - // pad coefficients length at tail to a power of 2. - let coefficientsPadded = Padded(-2 ^ Length(control!), 0.0, coefficients); - - if (Length(coefficientsPadded) == 1) - { - // Termination case - Exp([PauliZ], coefficientsPadded[0], [target]); - } - else - { - // Compute new coefficients. - let (coefficients0, coefficients1) = MultiplexZComputeCoefficients_(coefficientsPadded); - MultiplexZ(coefficients0, LittleEndian((control!)[0 .. Length(control!) - 2]), target); - CNOT((control!)[Length(control!) - 1], target); - MultiplexZ(coefficients1, LittleEndian((control!)[0 .. Length(control!) - 2]), target); - CNOT((control!)[Length(control!) - 1], target); + operation MultiplexZ(coefficients : Double[], control : LittleEndian, target : Qubit) + : Unit is Adj + Ctl { + ApproximatelyMultiplexZ(0.0, coefficients, control, target); + } + + function _AnyOutsideTolerance(tolerance : Double, coefficients : Double[]) : Bool { + // NB: We don't currently use Any / Mapped for this, as we want to be + // able to short-circuit. That should be implied by immutable + // semantics, but that's not yet the case. + for (coefficient in coefficients) { + if (AbsD(coefficient) >= tolerance) { + return true; } } - - adjoint invert; - - controlled (controlRegister, ...) - { - // pad coefficients length to a power of 2. - let coefficientsPadded = Padded(2 ^ (Length(control!) + 1), 0.0, Padded(-2 ^ Length(control!), 0.0, coefficients)); - let (coefficients0, coefficients1) = MultiplexZComputeCoefficients_(coefficientsPadded); - MultiplexZ(coefficients0, control, target); - Controlled X(controlRegister, target); - MultiplexZ(coefficients1, control, target); - Controlled X(controlRegister, target); - } - - controlled adjoint invert; + return false; } - - + + /// TODO + operation ApproximatelyMultiplexZ(tolerance : Double, coefficients : Double[], control : LittleEndian, target : Qubit) : Unit is Adj + Ctl { + body (...) { + // pad coefficients length at tail to a power of 2. + let coefficientsPadded = Padded(-2 ^ Length(control!), 0.0, coefficients); + + if (Length(coefficientsPadded) == 1) { + // Termination case + if (AbsD(coefficientsPadded[0])> tolerance) { + Exp([PauliZ], coefficientsPadded[0], [target]); + } + } + else + { + // Compute new coefficients. + let (coefficients0, coefficients1) = _MultiplexZCoefficients(coefficientsPadded); + ApproximatelyMultiplexZ(tolerance,coefficients0, LittleEndian((control!)[0 .. Length(control!) - 2]), target); + if (_AnyOutsideTolerance(tolerance, coefficients1)) { + within { + CNOT((control!)[Length(control!) - 1], target); + } apply { + ApproximatelyMultiplexZ(tolerance,coefficients1, LittleEndian((control!)[0 .. Length(control!) - 2]), target); + } + } + } + } + + controlled (controlRegister, ...) { + // pad coefficients length to a power of 2. + let coefficientsPadded = Padded(2 ^ (Length(control!) + 1), 0.0, Padded(-2 ^ Length(control!), 0.0, coefficients)); + let (coefficients0, coefficients1) = _MultiplexZCoefficients(coefficientsPadded); + ApproximatelyMultiplexZ(tolerance,coefficients0, control, target); + if (_AnyOutsideTolerance(tolerance,coefficients1)) { + within { + Controlled X(controlRegister, target); + } apply { + ApproximatelyMultiplexZ(tolerance,coefficients1, control, target); + } + } + } + } + /// # Summary /// Applies an array of complex phases to numeric basis states of a register of qubits. /// @@ -176,7 +179,7 @@ namespace Microsoft.Quantum.Canon { let coefficientsPadded = Padded(-2 ^ Length(qubits!), 0.0, coefficients); // Compute new coefficients. - let (coefficients0, coefficients1) = MultiplexZComputeCoefficients_(coefficientsPadded); + let (coefficients0, coefficients1) = _MultiplexZCoefficients(coefficientsPadded); MultiplexZ(coefficients1, LittleEndian((qubits!)[0 .. Length(qubits!) - 2]), (qubits!)[Length(qubits!) - 1]); if (Length(coefficientsPadded) == 2) @@ -200,22 +203,19 @@ namespace Microsoft.Quantum.Canon { /// Implementation step of multiply-controlled Z rotations. /// # See Also /// - Microsoft.Quantum.Canon.MultiplexZ - function MultiplexZComputeCoefficients_ (coefficients : Double[]) : (Double[], Double[]) - { + function _MultiplexZCoefficients(coefficients : Double[]) : (Double[], Double[]) { let newCoefficientsLength = Length(coefficients) / 2; mutable coefficients0 = new Double[newCoefficientsLength]; mutable coefficients1 = new Double[newCoefficientsLength]; - - for (idxCoeff in 0 .. newCoefficientsLength - 1) - { + + for (idxCoeff in 0 .. newCoefficientsLength - 1) { set coefficients0 w/= idxCoeff <- 0.5 * (coefficients[idxCoeff] + coefficients[idxCoeff + newCoefficientsLength]); set coefficients1 w/= idxCoeff <- 0.5 * (coefficients[idxCoeff] - coefficients[idxCoeff + newCoefficientsLength]); } - + return (coefficients0, coefficients1); } - - + /// # Summary /// Applies an array of operations controlled by an array of number states. /// @@ -245,28 +245,18 @@ namespace Microsoft.Quantum.Canon { /// - Toward the first quantum simulation with quantum speedup /// Andrew M. Childs, Dmitri Maslov, Yunseong Nam, Neil J. Ross, Yuan Su /// https://arxiv.org/abs/1711.10980 - operation MultiplexOperations<'T> (unitaries : ('T => Unit is Adj + Ctl)[], index : LittleEndian, target : 'T) : Unit - { - body (...) - { - if (Length(index!) == 0) - { - fail $"MultiplexOperations failed. Number of index qubits must be greater than 0."; - } - - if (Length(unitaries) > 0) - { - let ancilla = new Qubit[0]; - _MultiplexOperations(unitaries, ancilla, index, target); - } + operation MultiplexOperations<'T> (unitaries : ('T => Unit is Adj + Ctl)[], index : LittleEndian, target : 'T) + : Unit is Adj + Ctl { + if (Length(index!) == 0) { + fail $"MultiplexOperations failed. Number of index qubits must be greater than 0."; + } + + if (Length(unitaries) > 0) { + let ancilla = new Qubit[0]; + _MultiplexOperations(unitaries, ancilla, index, target); } - - adjoint invert; - controlled distribute; - controlled adjoint distribute; } - - + /// # Summary /// Implementation step of MultiplexOperations. /// # See Also From 8c9153a11ee8325010d9a257254f65429c0d72c3 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Wed, 4 Dec 2019 11:29:48 -0800 Subject: [PATCH 2/8] Consolidate exact and approx ApplyDiagonalUnitary --- .../src/Runtime/SpecialMultiplexor.qs | 67 +------------------ Standard/src/Canon/Utils/Multiplexer.qs | 59 +++++++--------- 2 files changed, 27 insertions(+), 99 deletions(-) diff --git a/MachineLearning/src/Runtime/SpecialMultiplexor.qs b/MachineLearning/src/Runtime/SpecialMultiplexor.qs index 53716dff73b..e535f307a95 100644 --- a/MachineLearning/src/Runtime/SpecialMultiplexor.qs +++ b/MachineLearning/src/Runtime/SpecialMultiplexor.qs @@ -57,7 +57,7 @@ namespace Microsoft.Quantum.Canon { } elif (pauli == PauliI) { - NoisyApplyDiagonalUnitary(tolerance,coefficients, control); + ApproximatelyApplyDiagonalUnitary(tolerance, coefficients, control); } else { @@ -69,71 +69,6 @@ namespace Microsoft.Quantum.Canon { controlled distribute; controlled adjoint distribute; } - - - /// # Summary - /// Applies an array of complex phases to numeric basis states of a register of qubits. - /// - /// That is, this implements the diagonal unitary operation $U$ that applies a complex phase - /// $e^{i \theta_j}$ on the $n$-qubit number state $\ket{j}$. - /// - /// $U = \sum^{2^n-1}_{j=0}e^{i\theta_j}\ket{j}\bra{j}$. - /// - /// TODO: REIMPLEMENT THIS along the Welch et Bocharov lines - /// # Input - /// ## tolerance - /// Coefficients under this tolerance level should be ignored - /// ## coefficients - /// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient - /// indexes the number state $\ket{j}$ encoded in little-endian format. - /// - /// ## control - /// $n$-qubit control register that encodes number states $\ket{j}$ in - /// little-endian format. - /// - /// # Remarks - /// `coefficients` will be padded with elements $\theta_j = 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 - operation NoisyApplyDiagonalUnitary (tolerance: Double, coefficients : Double[], qubits : LittleEndian) : Unit - { - body (...) - { - if (IsEmpty(qubits!)) { - fail "operation ApplyDiagonalUnitary -- Number of qubits must be greater than 0."; - } - - // pad coefficients length at tail to a power of 2. - let coefficientsPadded = Padded(-2 ^ Length(qubits!), 0.0, coefficients); - - // Compute new coefficients. - let (coefficients0, coefficients1) = specialMultiplexZComputeCoefficients_(coefficientsPadded); - ApproximatelyMultiplexZ(tolerance,coefficients1, LittleEndian((qubits!)[0 .. Length(qubits!) - 2]), (qubits!)[Length(qubits!) - 1]); - - if (Length(coefficientsPadded) == 2) - { - - // Termination case - if (AbsD(coefficients0[0])>tolerance) - { - Exp([PauliI], 1.0 * coefficients0[0], qubits!); - } - } - else - { - NoisyApplyDiagonalUnitary(tolerance,coefficients0, LittleEndian((qubits!)[0 .. Length(qubits!) - 2])); - } - } - - adjoint invert; - controlled distribute; - controlled adjoint distribute; - } - /// # Summary /// Implementation step of multiply-controlled Z rotations. diff --git a/Standard/src/Canon/Utils/Multiplexer.qs b/Standard/src/Canon/Utils/Multiplexer.qs index eb577004ecc..b0bc60f3070 100644 --- a/Standard/src/Canon/Utils/Multiplexer.qs +++ b/Standard/src/Canon/Utils/Multiplexer.qs @@ -107,12 +107,10 @@ namespace Microsoft.Quantum.Canon { if (Length(coefficientsPadded) == 1) { // Termination case - if (AbsD(coefficientsPadded[0])> tolerance) { + if (AbsD(coefficientsPadded[0]) > tolerance) { Exp([PauliZ], coefficientsPadded[0], [target]); } - } - else - { + } else { // Compute new coefficients. let (coefficients0, coefficients1) = _MultiplexZCoefficients(coefficientsPadded); ApproximatelyMultiplexZ(tolerance,coefficients0, LittleEndian((control!)[0 .. Length(control!) - 2]), target); @@ -166,39 +164,34 @@ namespace Microsoft.Quantum.Canon { /// - Synthesis of Quantum Logic Circuits /// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov /// https://arxiv.org/abs/quant-ph/0406176 - operation ApplyDiagonalUnitary (coefficients : Double[], qubits : LittleEndian) : Unit - { - body (...) - { - if (Length(qubits!) == 0) - { - fail $"operation ApplyDiagonalUnitary -- Number of qubits must be greater than 0."; - } - - // pad coefficients length at tail to a power of 2. - let coefficientsPadded = Padded(-2 ^ Length(qubits!), 0.0, coefficients); - - // Compute new coefficients. - let (coefficients0, coefficients1) = _MultiplexZCoefficients(coefficientsPadded); - MultiplexZ(coefficients1, LittleEndian((qubits!)[0 .. Length(qubits!) - 2]), (qubits!)[Length(qubits!) - 1]); - - if (Length(coefficientsPadded) == 2) - { - // Termination case + operation ApplyDiagonalUnitary (coefficients : Double[], qubits : LittleEndian) : Unit is Adj + Ctl { + ApproximatelyApplyDiagonalUnitary(0.0, coefficients, qubits); + } + + /// # TODO + operation ApproximatelyApplyDiagonalUnitary(tolerance : Double, coefficients : Double[], qubits : LittleEndian) + : Unit is Adj + Ctl { + if (IsEmpty(qubits!)) { + fail "operation ApplyDiagonalUnitary -- Number of qubits must be greater than 0."; + } + + // pad coefficients length at tail to a power of 2. + let coefficientsPadded = Padded(-2 ^ Length(qubits!), 0.0, coefficients); + + // Compute new coefficients. + let (coefficients0, coefficients1) = _MultiplexZCoefficients(coefficientsPadded); + ApproximatelyMultiplexZ(tolerance,coefficients1, LittleEndian((qubits!)[0 .. Length(qubits!) - 2]), (qubits!)[Length(qubits!) - 1]); + + if (Length(coefficientsPadded) == 2) { + // Termination case + if (AbsD(coefficients0[0]) > tolerance) { Exp([PauliI], 1.0 * coefficients0[0], qubits!); } - else - { - ApplyDiagonalUnitary(coefficients0, LittleEndian((qubits!)[0 .. Length(qubits!) - 2])); - } + } else { + ApproximatelyApplyDiagonalUnitary(tolerance, coefficients0, LittleEndian(Most(qubits!))); } - - adjoint invert; - controlled distribute; - controlled adjoint distribute; } - - + /// # Summary /// Implementation step of multiply-controlled Z rotations. /// # See Also From 29f8878de4535f5582b421729a6a000f8489d5a7 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Wed, 4 Dec 2019 11:36:12 -0800 Subject: [PATCH 3/8] Finished consolidating multiplexers. --- .../src/Runtime/SpecialMultiplexor.qs | 97 ------------------- MachineLearning/src/Runtime/SpecialSP.qs | 4 +- Standard/src/Canon/Utils/Multiplexer.qs | 16 ++- 3 files changed, 13 insertions(+), 104 deletions(-) delete mode 100644 MachineLearning/src/Runtime/SpecialMultiplexor.qs diff --git a/MachineLearning/src/Runtime/SpecialMultiplexor.qs b/MachineLearning/src/Runtime/SpecialMultiplexor.qs deleted file mode 100644 index e535f307a95..00000000000 --- a/MachineLearning/src/Runtime/SpecialMultiplexor.qs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Canon { - open Microsoft.Quantum.Arithmetic; - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Math; - - /// # Summary - /// Applies a Pauli rotation conditioned on an array of qubits. - /// - /// This applies the multiply-controlled unitary operation $U$ that performs - /// rotations by angle $\theta_j$ about single-qubit Pauli operator $P$ - /// when controlled by the $n$-qubit number state $\ket{j}$. - /// - /// $U = \sum^{2^n-1}_{j=0}\ket{j}\bra{j}\otimes e^{i P \theta_j}$. - /// - /// # Input - /// ## tolerance - /// Coefficients under this tolerance level should be ignored - /// ## coefficients - /// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient - /// indexes the number state $\ket{j}$ encoded in little-endian format. - /// - /// ## pauli - /// Pauli operator $P$ that determines axis of rotation. - /// - /// ## control - /// $n$-qubit control register that encodes number states $\ket{j}$ in - /// little-endian format. - /// - /// ## target - /// Single qubit register that is rotated by $e^{i P \theta_j}$. - /// - /// # Remarks - /// `coefficients` will be padded with elements $\theta_j = 0.0$ if - /// fewer than $2^n$ are specified. - operation NoisyMultiplexPauli (tolerance: Double,coefficients : Double[], pauli : Pauli, control : LittleEndian, target : Qubit) : Unit - { - body (...) - { - if (pauli == PauliZ) - { - let op = ApproximatelyMultiplexZ(tolerance, coefficients, control, _); - op(target); - } - elif (pauli == PauliX) - { - let op = NoisyMultiplexPauli(tolerance,coefficients, PauliZ, control, _); - ApplyWithCA(H, op, target); - } - elif (pauli == PauliY) - { - let op = NoisyMultiplexPauli(tolerance,coefficients, PauliX, control, _); - ApplyWithCA(Adjoint S, op, target); - } - elif (pauli == PauliI) - { - ApproximatelyApplyDiagonalUnitary(tolerance, coefficients, control); - } - else - { - fail $"MultiplexPauli failed. Invalid pauli {pauli}."; - } - } - - adjoint invert; - controlled distribute; - controlled adjoint distribute; - } - - /// # Summary - /// Implementation step of multiply-controlled Z rotations. - /// # See Also - /// - Microsoft.Quantum.Canon.MultiplexZ - function specialMultiplexZComputeCoefficients_ (coefficients : Double[]) : (Double[], Double[]) - { - let newCoefficientsLength = Length(coefficients) / 2; - mutable coefficients0 = new Double[newCoefficientsLength]; - mutable coefficients1 = new Double[newCoefficientsLength]; - - for (idxCoeff in 0 .. newCoefficientsLength - 1) - { - set coefficients0 w/= idxCoeff <- 0.5 * (coefficients[idxCoeff] + coefficients[idxCoeff + newCoefficientsLength]); - set coefficients1 w/= idxCoeff <- 0.5 * (coefficients[idxCoeff] - coefficients[idxCoeff + newCoefficientsLength]); - } - - return (coefficients0, coefficients1); - } - - - - -} - - diff --git a/MachineLearning/src/Runtime/SpecialSP.qs b/MachineLearning/src/Runtime/SpecialSP.qs index 18568a2a164..6bd16a83971 100644 --- a/MachineLearning/src/Runtime/SpecialSP.qs +++ b/MachineLearning/src/Runtime/SpecialSP.qs @@ -173,10 +173,10 @@ namespace Microsoft.Quantum.MachineLearning { // For each 2D block, compute disentangling single-qubit rotation parameters let (disentanglingY, disentanglingZ, newCoefficients) = _NoisyStatePreparationSBMComputeCoefficients(coefficients); if (_AnyOutsideTolerance(tolerance,disentanglingZ)) { - NoisyMultiplexPauli(tolerance,disentanglingZ, PauliZ, control, target); + ApproximatelyMultiplexPauli(tolerance, disentanglingZ, PauliZ, control, target); } if (_AnyOutsideTolerance(tolerance,disentanglingY)) { - NoisyMultiplexPauli(tolerance,disentanglingY, PauliY, control, target); + ApproximatelyMultiplexPauli(tolerance, disentanglingY, PauliY, control, target); } // target is now in |0> state up to the phase given by arg of newCoefficients. diff --git a/Standard/src/Canon/Utils/Multiplexer.qs b/Standard/src/Canon/Utils/Multiplexer.qs index b0bc60f3070..71b1fe38f9a 100644 --- a/Standard/src/Canon/Utils/Multiplexer.qs +++ b/Standard/src/Canon/Utils/Multiplexer.qs @@ -36,18 +36,24 @@ namespace Microsoft.Quantum.Canon { /// `coefficients` will be padded with elements $\theta_j = 0.0$ if /// fewer than $2^n$ are specified. operation MultiplexPauli (coefficients : Double[], pauli : Pauli, control : LittleEndian, target : Qubit) + : Unit is Adj + Ctl { + ApproximatelyMultiplexPauli(0.0, coefficients, pauli, control, target); + } + + /// TODO + operation ApproximatelyMultiplexPauli(tolerance : Double, coefficients : Double[], pauli : Pauli, control : LittleEndian, target : Qubit) : Unit is Adj + Ctl { if (pauli == PauliZ) { - let op = MultiplexZ(coefficients, control, _); + let op = ApproximatelyMultiplexZ(tolerance, coefficients, control, _); op(target); } elif (pauli == PauliX) { - let op = MultiplexPauli(coefficients, PauliZ, control, _); + let op = ApproximatelyMultiplexPauli(tolerance, coefficients, PauliZ, control, _); ApplyWithCA(H, op, target); } elif (pauli == PauliY) { - let op = MultiplexPauli(coefficients, PauliX, control, _); + let op = ApproximatelyMultiplexPauli(tolerance, coefficients, PauliX, control, _); ApplyWithCA(Adjoint S, op, target); } elif (pauli == PauliI) { - ApplyDiagonalUnitary(coefficients, control); + ApproximatelyApplyDiagonalUnitary(tolerance, coefficients, control); } else { fail $"MultiplexPauli failed. Invalid pauli {pauli}."; } @@ -141,7 +147,7 @@ namespace Microsoft.Quantum.Canon { /// # Summary /// Applies an array of complex phases to numeric basis states of a register of qubits. - /// + /// /// That is, this implements the diagonal unitary operation $U$ that applies a complex phase /// $e^{i \theta_j}$ on the $n$-qubit number state $\ket{j}$. /// From c38d2d93c5d6c0799e75a9c7f5c85a080e8c3e7a Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Wed, 4 Dec 2019 12:31:00 -0800 Subject: [PATCH 4/8] Code cleanup, inclusive language. --- Standard/src/Canon/Utils/Multiplexer.qs | 97 ++++++++++++------------- 1 file changed, 45 insertions(+), 52 deletions(-) diff --git a/Standard/src/Canon/Utils/Multiplexer.qs b/Standard/src/Canon/Utils/Multiplexer.qs index 71b1fe38f9a..1c764ecc442 100644 --- a/Standard/src/Canon/Utils/Multiplexer.qs +++ b/Standard/src/Canon/Utils/Multiplexer.qs @@ -217,7 +217,7 @@ namespace Microsoft.Quantum.Canon { /// # Summary /// Applies an array of operations controlled by an array of number states. - /// + /// /// That is, applies Multiply-controlled unitary operation $U$ that applies a /// unitary $V_j$ when controlled by $n$-qubit number state $\ket{j}$. /// @@ -238,7 +238,7 @@ namespace Microsoft.Quantum.Canon { /// # Remarks /// `coefficients` will be padded with identity elements if /// fewer than $2^n$ are specified. This implementation uses - /// $n-1$ ancilla qubits. + /// $n - 1$ auxillary qubits. /// /// # References /// - Toward the first quantum simulation with quantum speedup @@ -251,8 +251,8 @@ namespace Microsoft.Quantum.Canon { } if (Length(unitaries) > 0) { - let ancilla = new Qubit[0]; - _MultiplexOperations(unitaries, ancilla, index, target); + let auxillaryRegister = new Qubit[0]; + _MultiplexOperations(unitaries, auxillaryRegister, index, target); } } @@ -260,10 +260,14 @@ namespace Microsoft.Quantum.Canon { /// Implementation step of MultiplexOperations. /// # See Also /// - Microsoft.Quantum.Canon.MultiplexOperations - operation _MultiplexOperations<'T>(unitaries : ('T => Unit is Adj + Ctl)[], ancilla : Qubit[], index : LittleEndian, target : 'T) : Unit - { - body (...) - { + operation _MultiplexOperations<'T>( + unitaries : ('T => Unit is Adj + Ctl)[], + auxillaryRegister : Qubit[], + index : LittleEndian, + target : 'T + ) + : Unit is Adj + Ctl { + body (...) { let nIndex = Length(index!); let nStates = 2 ^ nIndex; let nUnitaries = Length(unitaries); @@ -272,59 +276,48 @@ namespace Microsoft.Quantum.Canon { let rightUnitaries = unitaries[0 .. nUnitariesRight - 1]; let leftUnitaries = unitaries[nUnitariesRight .. nUnitariesLeft - 1]; let newControls = LittleEndian((index!)[0 .. nIndex - 2]); - - if (nUnitaries > 0) - { - if (Length(ancilla) == 1 and nIndex == 0) - { + + if (nUnitaries > 0) { + if (Length(auxillaryRegister) == 1 and nIndex == 0) { // Termination case - Controlled unitaries[0](ancilla, target); - } - elif (Length(ancilla) == 0 and nIndex >= 1) - { + Controlled unitaries[0](auxillaryRegister, target); + } elif (Length(auxillaryRegister) == 0 and nIndex >= 1) { // Start case - let newAncilla = [(index!)[Length(index!) - 1]]; - - if (nUnitariesLeft > 0) - { - _MultiplexOperations(leftUnitaries, newAncilla, newControls, target); + let newAuxQubit = Tail(index!); + + if (nUnitariesLeft > 0) { + _MultiplexOperations(leftUnitaries, [newAuxQubit], newControls, target); } - - X(newAncilla[0]); - _MultiplexOperations(rightUnitaries, newAncilla, newControls, target); - X(newAncilla[0]); - } - else - { - // Recursion that reduces nIndex by 1 & sets Length(ancilla) to 1. - using (newAncilla = Qubit[1]) - { - Controlled X(ancilla + [(index!)[Length(index!) - 1]], newAncilla[0]); - - if (nUnitariesLeft > 0) - { - _MultiplexOperations(leftUnitaries, newAncilla, newControls, target); + + within { + X(newAuxQubit); + } apply { + _MultiplexOperations(rightUnitaries, [newAuxQubit], newControls, target); + } + } else { + // Recursion that reduces nIndex by 1 & sets Length(auxillaryRegister) to 1. + using (newAuxQubit = Qubit()) { + within { + Controlled X(auxillaryRegister + [(index!)[Length(index!) - 1]], newAuxQubit); + } apply { + if (nUnitariesLeft > 0) { + _MultiplexOperations(leftUnitaries, [newAuxQubit], newControls, target); + } + + within { + Controlled X(auxillaryRegister, newAuxQubit); + } apply { + _MultiplexOperations(rightUnitaries, [newAuxQubit], newControls, target); + } } - - Controlled X(ancilla, newAncilla[0]); - _MultiplexOperations(rightUnitaries, newAncilla, newControls, target); - Controlled X(ancilla, newAncilla[0]); - Controlled X(ancilla + [(index!)[Length(index!) - 1]], newAncilla[0]); } } } } - - adjoint invert; - - controlled (controlRegister, ...) - { + + controlled (controlRegister, ...) { _MultiplexOperations(unitaries, controlRegister, index, target); } - - controlled adjoint invert; } - -} - +} From b60346cbc6930431a173f9bbe1661e1a96991161 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Wed, 4 Dec 2019 12:53:13 -0800 Subject: [PATCH 5/8] Whitespace fix and name clarification. --- .../{StatePreparation.qs => Arbitrary.qs} | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) rename Standard/src/Preparation/{StatePreparation.qs => Arbitrary.qs} (96%) diff --git a/Standard/src/Preparation/StatePreparation.qs b/Standard/src/Preparation/Arbitrary.qs similarity index 96% rename from Standard/src/Preparation/StatePreparation.qs rename to Standard/src/Preparation/Arbitrary.qs index ec3f9a6d845..efaca9835ae 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,11 +108,11 @@ 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. - /// + /// 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}$. @@ -171,9 +171,9 @@ namespace Microsoft.Quantum.Preparation { 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) { @@ -187,11 +187,11 @@ namespace Microsoft.Quantum.Preparation { _PrepareArbitraryState(newCoefficients, newControl, newTarget); } } - - + + /// # Summary - /// Computes the Bloch sphere coordinates for a single-qubit state. - /// + /// 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})$. From 97b2415d6fc6ccd8180f736c5b537701a3db1104 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Wed, 4 Dec 2019 13:24:01 -0800 Subject: [PATCH 6/8] Consolidated arbitrary state preparation. --- MachineLearning/src/Runtime/InputEncoding.qs | 167 ++++++------- MachineLearning/src/Runtime/SpecialSP.qs | 242 ------------------- Standard/src/Canon/Utils/Multiplexer.qs | 83 ++++--- Standard/src/Preparation/Arbitrary.qs | 46 ++-- 4 files changed, 156 insertions(+), 382 deletions(-) delete mode 100644 MachineLearning/src/Runtime/SpecialSP.qs diff --git a/MachineLearning/src/Runtime/InputEncoding.qs b/MachineLearning/src/Runtime/InputEncoding.qs index cf243f2a3c2..cd0119d4bdc 100644 --- a/MachineLearning/src/Runtime/InputEncoding.qs +++ b/MachineLearning/src/Runtime/InputEncoding.qs @@ -2,113 +2,114 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.MachineLearning { + open Microsoft.Quantum.Preparation; open Microsoft.Quantum.Convert; open Microsoft.Quantum.Math; open Microsoft.Quantum.Arithmetic; open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Canon; - function _CanApplyTwoQubitCase(datum: Double[]) : Bool { - return((Length(datum)==4) and (Microsoft.Quantum.Math.AbsD(datum[0]*datum[3]-datum[1]*datum[2])< 1E-12) and (Microsoft.Quantum.Math.AbsD(datum[0])> 1E-4)); - } + function _CanApplyTwoQubitCase(datum: Double[]) : Bool { + return((Length(datum)==4) and (Microsoft.Quantum.Math.AbsD(datum[0]*datum[3]-datum[1]*datum[2])< 1E-12) and (Microsoft.Quantum.Math.AbsD(datum[0])> 1E-4)); + } - operation _ApplyTwoQubitCase(datum: Double[], reg: LittleEndian) : Unit is Adj + Ctl { - let x = datum[1]/datum[0]; - let y = datum[2]/datum[0]; - // we now encoding [1,x,y,x*y] - let ax = 2.0 * ArcTan(x); - let ay = 2.0 * ArcTan(y); - R(PauliY, ay, (reg!)[1]); - R(PauliY, ax, (reg!)[0]); - } + operation _ApplyTwoQubitCase(datum: Double[], reg: LittleEndian) : Unit is Adj + Ctl { + let x = datum[1]/datum[0]; + let y = datum[2]/datum[0]; + // we now encoding [1,x,y,x*y] + let ax = 2.0 * ArcTan(x); + let ay = 2.0 * ArcTan(y); + R(PauliY, ay, (reg!)[1]); + R(PauliY, ax, (reg!)[0]); + } - function _Unnegate(negLocs: Int[], coefficients : ComplexPolar[]) : ComplexPolar[] { - mutable ret = coefficients; - for (idxNegative in negLocs) { - if (idxNegative >= Length(coefficients)) { - fail $"Cannot set the phase at index {idxNegative}, only {Length(coefficients)} coefficients were provided."; - } - let coefficient = coefficients[idxNegative]; - set ret w/= idxNegative <- ComplexPolar(coefficient::Magnitude, 0.0); - } - return ret; - } + function _Unnegate(negLocs: Int[], coefficients : ComplexPolar[]) : ComplexPolar[] { + mutable ret = coefficients; + for (idxNegative in negLocs) { + if (idxNegative >= Length(coefficients)) { + fail $"Cannot set the phase at index {idxNegative}, only {Length(coefficients)} coefficients were provided."; + } + let coefficient = coefficients[idxNegative]; + set ret w/= idxNegative <- ComplexPolar(coefficient::Magnitude, 0.0); + } + return ret; + } - /// Do special processing on the first cNegative entries - operation _EncodeSparseNegativeInput(cNegative: Int, tolerance: Double,coefficients : ComplexPolar[], reg: LittleEndian): Unit is Adj + Ctl - { - let negLocs = collectNegativeLocs(cNegative, coefficients); - // Prepare the state disregarding the sign of negative components. - NoisyPrepareArbitraryState(tolerance, _Unnegate(negLocs, coefficients), reg); - // Reflect about the negative coefficients to apply the negative signs - // at the end. - for (ineg in 0..(cNegative - 1)) { - let jx = negLocs[ineg]; - if (jx > -1) { - ReflectAboutInteger(jx, reg); //TODO:REVIEW: this assumes that 2^Length(reg) is the minimal pad to Length(coefficients) - } - } - } + /// Do special processing on the first cNegative entries + operation _EncodeSparseNegativeInput(cNegative: Int, tolerance: Double,coefficients : ComplexPolar[], reg: LittleEndian): Unit is Adj + Ctl + { + let negLocs = collectNegativeLocs(cNegative, coefficients); + // Prepare the state disregarding the sign of negative components. + ApproximatelyPrepareArbitraryState(tolerance, _Unnegate(negLocs, coefficients), reg); + // Reflect about the negative coefficients to apply the negative signs + // at the end. + for (ineg in 0..(cNegative - 1)) { + let jx = negLocs[ineg]; + if (jx > -1) { + ReflectAboutInteger(jx, reg); //TODO:REVIEW: this assumes that 2^Length(reg) is the minimal pad to Length(coefficients) + } + } + } - function NoisyInputEncoder(tolerance: Double,coefficients : Double[]) : (LittleEndian => Unit is Adj + Ctl) { - //First quantize the coefficients: for a coef x find such y*tolerance, where y is integer and |x-y*tolerance| \neq tolerance/2 - let nCoefficients = Length(coefficients); + function NoisyInputEncoder(tolerance: Double,coefficients : Double[]) : (LittleEndian => Unit is Adj + Ctl) { + //First quantize the coefficients: for a coef x find such y*tolerance, where y is integer and |x-y*tolerance| \neq tolerance/2 + let nCoefficients = Length(coefficients); mutable coefficientsComplexPolar = new ComplexPolar[nCoefficients]; mutable cNegative = 0; for (idx in 0 .. nCoefficients - 1) { - mutable coef = coefficients[idx]; - if (tolerance > 1E-9) { - set coef = tolerance * IntAsDouble(Round(coefficients[idx] / tolerance)); //quantization - } - mutable ang = 0.0; - if (coef < 0.0) { - set cNegative += 1; - set coef = -coef; - set ang = PI(); - } + mutable coef = coefficients[idx]; + if (tolerance > 1E-9) { + set coef = tolerance * IntAsDouble(Round(coefficients[idx] / tolerance)); //quantization + } + mutable ang = 0.0; + if (coef < 0.0) { + set cNegative += 1; + set coef = -coef; + set ang = PI(); + } set coefficientsComplexPolar w/= idx <- ComplexPolar(coef, ang); } - // Check if we can apply the explicit two-qubit case. + // Check if we can apply the explicit two-qubit case. if (_CanApplyTwoQubitCase(coefficients)) { - return _ApplyTwoQubitCase(coefficients, _); - } - // If not, we may be able to use a special protocol in the case that - // there are only a few negative coefficients. - // Here, by a "few," we mean fewer than the number of qubits required - // to encode features. - if ((cNegative > 0) and (IntAsDouble(cNegative) < Lg(IntAsDouble(Length(coefficients))) + 1.0)) { - return _EncodeSparseNegativeInput(cNegative, tolerance, coefficientsComplexPolar, _); //TODO:MORE:ACCEPTANCE ("Wines" passing soi far) - } - - // Finally, we fall back to arbitrary state preparation. - return NoisyPrepareArbitraryState(tolerance, coefficientsComplexPolar, _); - } //EncodeNoisyInput + return _ApplyTwoQubitCase(coefficients, _); + } + // If not, we may be able to use a special protocol in the case that + // there are only a few negative coefficients. + // Here, by a "few," we mean fewer than the number of qubits required + // to encode features. + if ((cNegative > 0) and (IntAsDouble(cNegative) < Lg(IntAsDouble(Length(coefficients))) + 1.0)) { + return _EncodeSparseNegativeInput(cNegative, tolerance, coefficientsComplexPolar, _); //TODO:MORE:ACCEPTANCE ("Wines" passing soi far) + } + + // Finally, we fall back to arbitrary state preparation. + return ApproximatelyPrepareArbitraryState(tolerance, coefficientsComplexPolar, _); + } //EncodeNoisyInput - //TODO:REVIEW: Design consideration! The implicit qubit count must be read off from the state encoder, NOT from the gate sequence! + //TODO:REVIEW: Design consideration! The implicit qubit count must be read off from the state encoder, NOT from the gate sequence! - /// Create amplitude encoding of an array of real-valued coefficients - /// The vector of 'coefficients' does not have to be unitary - function InputEncoder(coefficients : Double[]): (LittleEndian => Unit is Adj + Ctl) { - //default implementation, does not respect sparcity - let nCoefficients = Length(coefficients); + /// Create amplitude encoding of an array of real-valued coefficients + /// The vector of 'coefficients' does not have to be unitary + function InputEncoder(coefficients : Double[]): (LittleEndian => Unit is Adj + Ctl) { + //default implementation, does not respect sparcity + let nCoefficients = Length(coefficients); mutable coefficientsComplexPolar = new ComplexPolar[nCoefficients]; mutable allPositive = true; for (idx in 0 .. nCoefficients - 1) { - mutable coef = coefficients[idx]; - mutable ang = 0.0; - if (coef < 0.0) - { - set allPositive = false; - set coef = -coef; - set ang =Microsoft.Quantum.Math.PI(); - } + mutable coef = coefficients[idx]; + mutable ang = 0.0; + if (coef < 0.0) + { + set allPositive = false; + set coef = -coef; + set ang =Microsoft.Quantum.Math.PI(); + } set coefficientsComplexPolar w/= idx<-ComplexPolar(coef,ang); } if (_CanApplyTwoQubitCase(coefficients)) { - return _ApplyTwoQubitCase(coefficients,_); - } - return NoisyPrepareArbitraryState(1E-12, coefficientsComplexPolar, _); //this is preparing the state almost exactly so far - } + return _ApplyTwoQubitCase(coefficients,_); + } + return ApproximatelyPrepareArbitraryState(1E-12, coefficientsComplexPolar, _); //this is preparing the state almost exactly so far + } } \ No newline at end of file diff --git a/MachineLearning/src/Runtime/SpecialSP.qs b/MachineLearning/src/Runtime/SpecialSP.qs deleted file mode 100644 index 6bd16a83971..00000000000 --- a/MachineLearning/src/Runtime/SpecialSP.qs +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -namespace Microsoft.Quantum.MachineLearning { - open Microsoft.Quantum.Canon; - open Microsoft.Quantum.Arithmetic; - open Microsoft.Quantum.Intrinsic; - 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. - /// - /// 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 NoisyStatePreparationPositiveCoefficients (tolerance: Double, 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 NoisyPrepareArbitraryState(tolerance, 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}$ - /// 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 NoisyStatePreparationComplexCoefficients (tolerance: Double, coefficients : ComplexPolar[]) : (LittleEndian => Unit is Adj + Ctl) { - return NoisyPrepareArbitraryState(tolerance, 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}$. - /// - /// $$ - /// \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 - operation NoisyPrepareArbitraryState (tolerance:Double, 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 target = (qubits!)[0]; - let op = (Adjoint _NoisyPrepareArbitraryState(tolerance,coefficientsPadded, _, _))(_, target); - op( - // Determine what controls to apply to `op`. - Length(qubits!) > 1 - ? LittleEndian((qubits!)[1 .. Length(qubits!) - 1]) - | LittleEndian(new Qubit[0]) - ); - } - - - function significantComplex(tol: Double, rg:ComplexPolar[]):Bool { - for (j in 0..(Length(rg)-1)) { - if (AbsComplexPolar(rg[j])>tol) { - return true; - } - } - return false; - } - - /// # Summary - /// Implementation step of arbitrary state preparation procedure. - /// - /// # See Also - /// - PrepareArbitraryState - /// - Microsoft.Quantum.Canon.MultiplexPauli - operation _NoisyPrepareArbitraryState(tolerance: Double, coefficients : ComplexPolar[], control : LittleEndian, target : Qubit) : Unit is Adj + Ctl { - // For each 2D block, compute disentangling single-qubit rotation parameters - let (disentanglingY, disentanglingZ, newCoefficients) = _NoisyStatePreparationSBMComputeCoefficients(coefficients); - if (_AnyOutsideTolerance(tolerance,disentanglingZ)) { - ApproximatelyMultiplexPauli(tolerance, disentanglingZ, PauliZ, control, target); - } - if (_AnyOutsideTolerance(tolerance,disentanglingY)) { - ApproximatelyMultiplexPauli(tolerance, 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) { - let (abs, arg) = newCoefficients[0]!; - if (AbsD(arg)> tolerance) - { - Exp([PauliI], -1.0 * arg, [target]); - } - } else { - if (significantComplex(tolerance,newCoefficients)) { - let newControl = LittleEndian((control!)[1 .. Length(control!) - 1]); - let newTarget = (control!)[0]; - _NoisyPrepareArbitraryState(tolerance,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})$. - /// - /// # Input - /// ## a0 - /// Complex coefficient of state $\ket{0}$. - /// ## a1 - /// Complex coefficient of state $\ket{1}$. - /// - /// # Output - /// A tuple containing `(ComplexPolar(r, t), phi, theta)`. - function NoisyBlochSphereCoordinates (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); - return (ComplexPolar(r, t), phi, theta); - } - - /// # Summary - /// Implementation step of arbitrary state preparation procedure. - /// # See Also - /// - Microsoft.Quantum.Canon.PrepareArbitraryState - function _NoisyStatePreparationSBMComputeCoefficients (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]; - for (idxCoeff in 0 .. 2 .. Length(coefficients) - 1) { - let (rt, phi, theta) = NoisyBlochSphereCoordinates(coefficients[idxCoeff], coefficients[idxCoeff + 1]); - set disentanglingZ w/= idxCoeff / 2 <- 0.5 * phi; - set disentanglingY w/= idxCoeff / 2 <- 0.5 * theta; - set newCoefficients w/= idxCoeff / 2 <- rt; - } - return (disentanglingY, disentanglingZ, newCoefficients); - } -} \ No newline at end of file diff --git a/Standard/src/Canon/Utils/Multiplexer.qs b/Standard/src/Canon/Utils/Multiplexer.qs index 1c764ecc442..d82c7fe9902 100644 --- a/Standard/src/Canon/Utils/Multiplexer.qs +++ b/Standard/src/Canon/Utils/Multiplexer.qs @@ -8,8 +8,8 @@ namespace Microsoft.Quantum.Canon { open Microsoft.Quantum.Math; /// # Summary - /// Applies a Pauli rotation conditioned on an array of qubits. - /// + /// Applies a Pauli rotation conditioned on an array of qubits. + /// /// # Description /// This applies the multiply-controlled unitary operation $U$ that performs /// rotations by angle $\theta_j$ about single-qubit Pauli operator $P$ @@ -60,8 +60,8 @@ namespace Microsoft.Quantum.Canon { } /// # Summary - /// Applies a Pauli Z rotation conditioned on an array of qubits. - /// + /// Applies a Pauli Z rotation conditioned on an array of qubits. + /// /// This applies the multiply-controlled unitary operation $U$ that performs /// rotations by angle $\theta_j$ about single-qubit Pauli operator $Z$ /// when controlled by the $n$-qubit number state $\ket{j}$. @@ -93,7 +93,7 @@ namespace Microsoft.Quantum.Canon { ApproximatelyMultiplexZ(0.0, coefficients, control, target); } - function _AnyOutsideTolerance(tolerance : Double, coefficients : Double[]) : Bool { + function _AnyOutsideToleranceD(tolerance : Double, coefficients : Double[]) : Bool { // NB: We don't currently use Any / Mapped for this, as we want to be // able to short-circuit. That should be implied by immutable // semantics, but that's not yet the case. @@ -105,49 +105,58 @@ namespace Microsoft.Quantum.Canon { return false; } + function _AnyOutsideToleranceCP(tolerance : Double, coefficients : ComplexPolar[]) : Bool { + for (coefficient in coefficients) { + if (AbsComplexPolar(coefficient) > tolerance) { + return true; + } + } + return false; + } + /// TODO operation ApproximatelyMultiplexZ(tolerance : Double, coefficients : Double[], control : LittleEndian, target : Qubit) : Unit is Adj + Ctl { - body (...) { - // pad coefficients length at tail to a power of 2. - let coefficientsPadded = Padded(-2 ^ Length(control!), 0.0, coefficients); + body (...) { + // pad coefficients length at tail to a power of 2. + let coefficientsPadded = Padded(-2 ^ Length(control!), 0.0, coefficients); - if (Length(coefficientsPadded) == 1) { - // Termination case - if (AbsD(coefficientsPadded[0]) > tolerance) { - Exp([PauliZ], coefficientsPadded[0], [target]); - } - } else { - // Compute new coefficients. - let (coefficients0, coefficients1) = _MultiplexZCoefficients(coefficientsPadded); - ApproximatelyMultiplexZ(tolerance,coefficients0, LittleEndian((control!)[0 .. Length(control!) - 2]), target); - if (_AnyOutsideTolerance(tolerance, coefficients1)) { + if (Length(coefficientsPadded) == 1) { + // Termination case + if (AbsD(coefficientsPadded[0]) > tolerance) { + Exp([PauliZ], coefficientsPadded[0], [target]); + } + } else { + // Compute new coefficients. + let (coefficients0, coefficients1) = _MultiplexZCoefficients(coefficientsPadded); + ApproximatelyMultiplexZ(tolerance,coefficients0, LittleEndian((control!)[0 .. Length(control!) - 2]), target); + if (_AnyOutsideToleranceD(tolerance, coefficients1)) { within { - CNOT((control!)[Length(control!) - 1], target); + CNOT((control!)[Length(control!) - 1], target); } apply { - ApproximatelyMultiplexZ(tolerance,coefficients1, LittleEndian((control!)[0 .. Length(control!) - 2]), target); + ApproximatelyMultiplexZ(tolerance,coefficients1, LittleEndian((control!)[0 .. Length(control!) - 2]), target); } - } - } - } + } + } + } - controlled (controlRegister, ...) { - // pad coefficients length to a power of 2. - let coefficientsPadded = Padded(2 ^ (Length(control!) + 1), 0.0, Padded(-2 ^ Length(control!), 0.0, coefficients)); - let (coefficients0, coefficients1) = _MultiplexZCoefficients(coefficientsPadded); - ApproximatelyMultiplexZ(tolerance,coefficients0, control, target); - if (_AnyOutsideTolerance(tolerance,coefficients1)) { - within { + controlled (controlRegister, ...) { + // pad coefficients length to a power of 2. + let coefficientsPadded = Padded(2 ^ (Length(control!) + 1), 0.0, Padded(-2 ^ Length(control!), 0.0, coefficients)); + let (coefficients0, coefficients1) = _MultiplexZCoefficients(coefficientsPadded); + ApproximatelyMultiplexZ(tolerance,coefficients0, control, target); + if (_AnyOutsideToleranceD(tolerance,coefficients1)) { + within { Controlled X(controlRegister, target); } apply { - ApproximatelyMultiplexZ(tolerance,coefficients1, control, target); + ApproximatelyMultiplexZ(tolerance,coefficients1, control, target); } - } - } + } + } } /// # Summary - /// Applies an array of complex phases to numeric basis states of a register of qubits. - /// + /// Applies an array of complex phases to numeric basis states of a register of qubits. + /// /// That is, this implements the diagonal unitary operation $U$ that applies a complex phase /// $e^{i \theta_j}$ on the $n$-qubit number state $\ket{j}$. /// @@ -216,8 +225,8 @@ namespace Microsoft.Quantum.Canon { } /// # Summary - /// Applies an array of operations controlled by an array of number states. - /// + /// Applies an array of operations controlled by an array of number states. + /// /// That is, applies Multiply-controlled unitary operation $U$ that applies a /// unitary $V_j$ when controlled by $n$-qubit number state $\ket{j}$. /// diff --git a/Standard/src/Preparation/Arbitrary.qs b/Standard/src/Preparation/Arbitrary.qs index efaca9835ae..8b12642d855 100644 --- a/Standard/src/Preparation/Arbitrary.qs +++ b/Standard/src/Preparation/Arbitrary.qs @@ -144,12 +144,16 @@ 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) : Unit is Adj + Ctl { + operation PrepareArbitraryState(coefficients : ComplexPolar[], qubits : LittleEndian) : Unit is Adj + Ctl { + ApproximatelyPrepareArbitraryState(0.0, coefficients, qubits); + } + + /// TODO + operation ApproximatelyPrepareArbitraryState(tolerance : Double, 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 target = (qubits!)[0]; - let op = (Adjoint _PrepareArbitraryState(coefficientsPadded, _, _))(_, target); - + let op = (Adjoint _ApproximatelyPrepareArbitraryState(tolerance, coefficientsPadded, _, _))(_, target); op( // Determine what controls to apply to `op`. Length(qubits!) > 1 @@ -158,33 +162,36 @@ namespace Microsoft.Quantum.Preparation { ); } - /// # Summary /// Implementation step of arbitrary state preparation procedure. /// /// # See Also /// - PrepareArbitraryState /// - Microsoft.Quantum.Canon.MultiplexPauli - operation _PrepareArbitraryState(coefficients : ComplexPolar[], control : LittleEndian, target : Qubit) : Unit is Adj + Ctl - { + operation _ApproximatelyPrepareArbitraryState(tolerance: Double, 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); - + if (_AnyOutsideToleranceD(tolerance, disentanglingZ)) { + ApproximatelyMultiplexPauli(tolerance, disentanglingZ, PauliZ, control, target); + } + if (_AnyOutsideToleranceD(tolerance, disentanglingY)) { + ApproximatelyMultiplexPauli(tolerance, 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 - { - let newControl = LittleEndian((control!)[1 .. Length(control!) - 1]); - let newTarget = (control!)[0]; - _PrepareArbitraryState(newCoefficients, newControl, newTarget); + if (AbsD(arg) > tolerance) { + Exp([PauliI], -1.0 * arg, [target]); + } + } else { + if (_AnyOutsideToleranceCP(tolerance, newCoefficients)) { + let newControl = LittleEndian((control!)[1 .. Length(control!) - 1]); + let newTarget = (control!)[0]; + _ApproximatelyPrepareArbitraryState(tolerance,newCoefficients, newControl, newTarget); + } } } @@ -204,8 +211,7 @@ namespace Microsoft.Quantum.Preparation { /// /// # Output /// A tuple containing `(ComplexPolar(r, t), phi, theta)`. - function BlochSphereCoordinates (a0 : ComplexPolar, a1 : ComplexPolar) : (ComplexPolar, Double, Double) - { + function BlochSphereCoordinates (a0 : ComplexPolar, a1 : ComplexPolar) : (ComplexPolar, Double, Double) { let abs0 = AbsComplexPolar(a0); let abs1 = AbsComplexPolar(a1); let arg0 = ArgComplexPolar(a0); From 91cae612a5165d948ed9d4e01bd2bf730dffa7cb Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Wed, 4 Dec 2019 13:25:34 -0800 Subject: [PATCH 7/8] Slight cleanup. --- MachineLearning/src/Runtime/InputEncoding.qs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/MachineLearning/src/Runtime/InputEncoding.qs b/MachineLearning/src/Runtime/InputEncoding.qs index cd0119d4bdc..201b1d5e3be 100644 --- a/MachineLearning/src/Runtime/InputEncoding.qs +++ b/MachineLearning/src/Runtime/InputEncoding.qs @@ -98,16 +98,15 @@ namespace Microsoft.Quantum.MachineLearning { for (idx in 0 .. nCoefficients - 1) { mutable coef = coefficients[idx]; mutable ang = 0.0; - if (coef < 0.0) - { + if (coef < 0.0) { set allPositive = false; set coef = -coef; - set ang =Microsoft.Quantum.Math.PI(); + set ang = PI(); } set coefficientsComplexPolar w/= idx<-ComplexPolar(coef,ang); } if (_CanApplyTwoQubitCase(coefficients)) { - return _ApplyTwoQubitCase(coefficients,_); + return _ApplyTwoQubitCase(coefficients, _); } return ApproximatelyPrepareArbitraryState(1E-12, coefficientsComplexPolar, _); //this is preparing the state almost exactly so far } From 165373d9ec06c976a5caeae186b6d147c880b1e2 Mon Sep 17 00:00:00 2001 From: Christopher Granade Date: Wed, 4 Dec 2019 15:24:54 -0800 Subject: [PATCH 8/8] API documentation comments. --- Standard/src/Canon/Utils/Multiplexer.qs | 171 ++++++++++++++++++++++-- 1 file changed, 159 insertions(+), 12 deletions(-) diff --git a/Standard/src/Canon/Utils/Multiplexer.qs b/Standard/src/Canon/Utils/Multiplexer.qs index d82c7fe9902..0b4a2901e31 100644 --- a/Standard/src/Canon/Utils/Multiplexer.qs +++ b/Standard/src/Canon/Utils/Multiplexer.qs @@ -11,11 +11,17 @@ namespace Microsoft.Quantum.Canon { /// Applies a Pauli rotation conditioned on an array of qubits. /// /// # Description - /// This applies the multiply-controlled unitary operation $U$ that performs + /// This applies a multiply controlled unitary operation that performs /// rotations by angle $\theta_j$ about single-qubit Pauli operator $P$ /// when controlled by the $n$-qubit number state $\ket{j}$. + /// In particular, the action of this operation is represented by the + /// unitary /// - /// $U = \sum^{2^n-1}_{j=0}\ket{j}\bra{j}\otimes e^{i P \theta_j}$. + /// $$ + /// \begin{align} + /// U = \sum^{2^n - 1}_{j=0} \ket{j}\bra{j} \otimes e^{i P \theta_j}. + /// \end{align} + /// ## /// /// # Input /// ## coefficients @@ -35,12 +41,55 @@ namespace Microsoft.Quantum.Canon { /// # Remarks /// `coefficients` will be padded with elements $\theta_j = 0.0$ if /// fewer than $2^n$ are specified. - operation MultiplexPauli (coefficients : Double[], pauli : Pauli, control : LittleEndian, target : Qubit) + /// + /// # See Also + /// - ApproximatelyMultiplexPauli + operation MultiplexPauli(coefficients : Double[], pauli : Pauli, control : LittleEndian, target : Qubit) : Unit is Adj + Ctl { ApproximatelyMultiplexPauli(0.0, coefficients, pauli, control, target); } - /// TODO + /// # Summary + /// Applies a Pauli rotation conditioned on an array of qubits, truncating + /// small rotation angles according to a given tolerance. + /// + /// # Description + /// This applies a multiply controlled unitary operation that performs + /// rotations by angle $\theta_j$ about single-qubit Pauli operator $P$ + /// when controlled by the $n$-qubit number state $\ket{j}$. + /// In particular, the action of this operation is represented by the + /// unitary + /// + /// $$ + /// \begin{align} + /// U = \sum^{2^n - 1}_{j=0} \ket{j}\bra{j} \otimes e^{i P \theta_j}. + /// \end{align} + /// ## + /// + /// # Input + /// ## tolerance + /// A tolerance below which small coefficients are truncated. + /// + /// ## coefficients + /// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient + /// indexes the number state $\ket{j}$ encoded in little-endian format. + /// + /// ## pauli + /// Pauli operator $P$ that determines axis of rotation. + /// + /// ## control + /// $n$-qubit control register that encodes number states $\ket{j}$ in + /// little-endian format. + /// + /// ## target + /// Single qubit register that is rotated by $e^{i P \theta_j}$. + /// + /// # Remarks + /// `coefficients` will be padded with elements $\theta_j = 0.0$ if + /// fewer than $2^n$ are specified. + /// + /// # See Also + /// - MultiplexPauli operation ApproximatelyMultiplexPauli(tolerance : Double, coefficients : Double[], pauli : Pauli, control : LittleEndian, target : Qubit) : Unit is Adj + Ctl { if (pauli == PauliZ) { @@ -62,11 +111,17 @@ namespace Microsoft.Quantum.Canon { /// # Summary /// Applies a Pauli Z rotation conditioned on an array of qubits. /// - /// This applies the multiply-controlled unitary operation $U$ that performs + /// # Description + /// This applies the multiply controlled unitary operation that performs /// rotations by angle $\theta_j$ about single-qubit Pauli operator $Z$ /// when controlled by the $n$-qubit number state $\ket{j}$. + /// In particular, this operation can be represented by the unitary /// - /// $U = \sum^{2^n-1}_{j=0}\ket{j}\bra{j}\otimes e^{i Z \theta_j}$. + /// $$ + /// \begin{align} + /// U = \sum^{2^n-1}_{j=0} \ket{j}\bra{j} \otimes e^{i Z \theta_j}. + /// \end{align} + /// $$ /// /// # Input /// ## coefficients @@ -88,6 +143,9 @@ namespace Microsoft.Quantum.Canon { /// - Synthesis of Quantum Logic Circuits /// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov /// https://arxiv.org/abs/quant-ph/0406176 + /// + /// # See Also + /// - ApproximatelyMultiplexZ operation MultiplexZ(coefficients : Double[], control : LittleEndian, target : Qubit) : Unit is Adj + Ctl { ApproximatelyMultiplexZ(0.0, coefficients, control, target); @@ -114,7 +172,48 @@ namespace Microsoft.Quantum.Canon { return false; } - /// TODO + /// # Summary + /// Applies a Pauli Z rotation conditioned on an array of qubits, truncating + /// small rotation angles according to a given tolerance. + /// + /// # Description + /// This applies the multiply controlled unitary operation that performs + /// rotations by angle $\theta_j$ about single-qubit Pauli operator $Z$ + /// when controlled by the $n$-qubit number state $\ket{j}$. + /// In particular, this operation can be represented by the unitary + /// + /// $$ + /// \begin{align} + /// U = \sum^{2^n-1}_{j=0} \ket{j}\bra{j} \otimes e^{i Z \theta_j}. + /// \end{align} + /// $$ + /// + /// # Input + /// ## tolerance + /// A tolerance below which small coefficients are truncated. + /// + /// ## coefficients + /// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient + /// indexes the number state $\ket{j}$ encoded in little-endian format. + /// + /// ## control + /// $n$-qubit control register that encodes number states $\ket{j}$ in + /// little-endian format. + /// + /// ## target + /// Single qubit register that is rotated by $e^{i P \theta_j}$. + /// + /// # Remarks + /// `coefficients` will be padded with elements $\theta_j = 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 + /// - MultiplexZ operation ApproximatelyMultiplexZ(tolerance : Double, coefficients : Double[], control : LittleEndian, target : Qubit) : Unit is Adj + Ctl { body (...) { // pad coefficients length at tail to a power of 2. @@ -155,12 +254,19 @@ namespace Microsoft.Quantum.Canon { } /// # Summary - /// Applies an array of complex phases to numeric basis states of a register of qubits. + /// Applies an array of complex phases to numeric basis states of a register + /// of qubits. /// - /// That is, this implements the diagonal unitary operation $U$ that applies a complex phase + /// # Description + /// This operation implements a diagonal unitary that applies a complex phase /// $e^{i \theta_j}$ on the $n$-qubit number state $\ket{j}$. + /// In particular, this operation can be represented by the unitary /// - /// $U = \sum^{2^n-1}_{j=0}e^{i\theta_j}\ket{j}\bra{j}$. + /// $$ + /// \begin{align} + /// U = \sum^{2^n-1}_{j=0}e^{i\theta_j}\ket{j}\bra{j}. + /// \end{align} + /// $$ /// /// # Input /// ## coefficients @@ -179,11 +285,52 @@ namespace Microsoft.Quantum.Canon { /// - Synthesis of Quantum Logic Circuits /// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov /// https://arxiv.org/abs/quant-ph/0406176 - operation ApplyDiagonalUnitary (coefficients : Double[], qubits : LittleEndian) : Unit is Adj + Ctl { + /// + /// # See Also + /// - ApproximatelyApplyDiagonalUnitary + operation ApplyDiagonalUnitary(coefficients : Double[], qubits : LittleEndian) : Unit is Adj + Ctl { ApproximatelyApplyDiagonalUnitary(0.0, coefficients, qubits); } - /// # TODO + /// # Summary + /// Applies an array of complex phases to numeric basis states of a register + /// of qubits, truncating small rotation angles according to a given + /// tolerance. + /// + /// # Description + /// This operation implements a diagonal unitary that applies a complex phase + /// $e^{i \theta_j}$ on the $n$-qubit number state $\ket{j}$. + /// In particular, this operation can be represented by the unitary + /// + /// $$ + /// \begin{align} + /// U = \sum^{2^n-1}_{j=0}e^{i\theta_j}\ket{j}\bra{j}. + /// \end{align} + /// $$ + /// + /// # Input + /// ## tolerance + /// A tolerance below which small coefficients are truncated. + /// + /// ## coefficients + /// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient + /// indexes the number state $\ket{j}$ encoded in little-endian format. + /// + /// ## control + /// $n$-qubit control register that encodes number states $\ket{j}$ in + /// little-endian format. + /// + /// # Remarks + /// `coefficients` will be padded with elements $\theta_j = 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 + /// - ApplyDiagonalUnitary operation ApproximatelyApplyDiagonalUnitary(tolerance : Double, coefficients : Double[], qubits : LittleEndian) : Unit is Adj + Ctl { if (IsEmpty(qubits!)) {