Skip to content

Commit 201f456

Browse files
DmitryVasilevskyDmitry Vasilevsky
and
Dmitry Vasilevsky
authored
Uniform superposition preparation moved to std (#2195)
Moved uniform superposition preparation into Std.StatePreparaion (simplified version based on df chemistry) Improved checks and updated doc comments Added tests --------- Co-authored-by: Dmitry Vasilevsky <[email protected]>
1 parent 15cf834 commit 201f456

File tree

6 files changed

+143
-263
lines changed

6 files changed

+143
-263
lines changed

library/chemistry/src/JordanWigner/JordanWignerOptimizedBlockEncoding.qs

+1-204
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@ export
88
MixedStatePreparation,
99
MixedStatePreparationRequirements,
1010
PurifiedMixedState,
11-
ObliviousAmplitudeAmplificationFromStatePreparation,
12-
ObliviousAmplitudeAmplificationFromPartialReflections,
13-
ApplyObliviousAmplitudeAmplification,
1411
PurifiedMixedStateRequirements,
1512
BlockEncodingByLCU,
1613
QuantumWalkByQubitization,
@@ -27,6 +24,7 @@ import Std.Math.*;
2724
import Std.Convert.IntAsDouble;
2825
import Std.Arithmetic.ApplyIfGreaterLE;
2926
import Std.StatePreparation.PreparePureStateD;
27+
import Std.StatePreparation.PrepareUniformSuperposition;
3028
import Std.Diagnostics.Fact;
3129
import Utils.GeneratorIndex;
3230
import Utils.GeneratorSystem;
@@ -628,207 +626,6 @@ operation PrepareQuantumROMState(
628626
}
629627
}
630628

631-
/// # Summary
632-
/// Creates a uniform superposition over states that encode 0 through `nIndices - 1`.
633-
///
634-
/// # Description
635-
///
636-
/// This operation can be described by a unitary matrix $U$ that creates
637-
/// a uniform superposition over all number states
638-
/// $0$ to $M-1$, given an input state $\ket{0\cdots 0}$. In other words,
639-
/// $$
640-
/// \begin{align}
641-
/// U \ket{0} = \frac{1}{\sqrt{M}} \sum_{j=0}^{M - 1} \ket{j}.
642-
/// \end{align}
643-
/// $$.
644-
///
645-
/// # Input
646-
/// ## nIndices
647-
/// The desired number of states $M$ in the uniform superposition.
648-
/// ## indexRegister
649-
/// The qubit register that stores the number states in `LittleEndian` format.
650-
/// This register must be able to store the number $M-1$, and is assumed to be
651-
/// initialized in the state $\ket{0\cdots 0}$.
652-
///
653-
/// # Remarks
654-
/// The operation is adjointable, but requires that `indexRegister` is in a uniform
655-
/// superposition over the first `nIndices` basis states in that case.
656-
///
657-
/// # Example
658-
/// The following example prepares the state $\frac{1}{\sqrt{6}}\sum_{j=0}^{5}\ket{j}$
659-
/// on $3$ qubits.
660-
/// ``` Q#
661-
/// let nIndices = 6;
662-
/// using(indexRegister = Qubit[3]) {
663-
/// PrepareUniformSuperposition(nIndices, LittleEndian(indexRegister));
664-
/// // ...
665-
/// }
666-
/// ```
667-
operation PrepareUniformSuperposition(nIndices : Int, indexRegister : Qubit[]) : Unit is Adj + Ctl {
668-
if nIndices == 0 {
669-
fail "Cannot prepare uniform superposition over 0 basis states.";
670-
} elif nIndices == 1 {
671-
// Superposition over one state, so do nothing.
672-
} elif nIndices == 2 {
673-
H(indexRegister[0]);
674-
} else {
675-
let nQubits = BitSizeI(nIndices - 1);
676-
if nQubits > Length(indexRegister) {
677-
fail $"Cannot prepare uniform superposition over {nIndices} states as it is larger than the qubit register.";
678-
}
679-
680-
use flagQubit = Qubit[3];
681-
let targetQubits = indexRegister[0..nQubits - 1];
682-
let qubits = flagQubit + targetQubits;
683-
let stateOracle = PrepareUniformSuperpositionOracle(nIndices, nQubits, 0, _);
684-
685-
let phases = ([0.0, PI()], [PI(), 0.0]);
686-
687-
ObliviousAmplitudeAmplificationFromStatePreparation(
688-
phases,
689-
stateOracle,
690-
(qs0, qs1) => I(qs0[0]),
691-
0
692-
)(qubits, []);
693-
694-
695-
ApplyToEachCA(X, flagQubit);
696-
}
697-
}
698-
699-
function ObliviousAmplitudeAmplificationFromStatePreparation(
700-
phases : (Double[], Double[]),
701-
startStateOracle : Qubit[] => Unit is Adj + Ctl,
702-
signalOracle : (Qubit[], Qubit[]) => Unit is Adj + Ctl,
703-
idxFlagQubit : Int
704-
) : (Qubit[], Qubit[]) => Unit is Adj + Ctl {
705-
let startStateReflection = (phase, qs) => {
706-
within {
707-
ApplyToEachCA(X, qs);
708-
} apply {
709-
Controlled R1(Rest(qs), (phase, qs[0]));
710-
}
711-
};
712-
let targetStateReflection = (phase, qs) => R1(phase, qs[idxFlagQubit]);
713-
let obliviousSignalOracle = (qs0, qs1) => { startStateOracle(qs0); signalOracle(qs0, qs1); };
714-
return ObliviousAmplitudeAmplificationFromPartialReflections(
715-
phases,
716-
startStateReflection,
717-
targetStateReflection,
718-
obliviousSignalOracle
719-
);
720-
}
721-
722-
function ObliviousAmplitudeAmplificationFromPartialReflections(
723-
phases : (Double[], Double[]),
724-
startStateReflection : (Double, Qubit[]) => Unit is Adj + Ctl,
725-
targetStateReflection : (Double, Qubit[]) => Unit is Adj + Ctl,
726-
signalOracle : (Qubit[], Qubit[]) => Unit is Adj + Ctl
727-
) : (Qubit[], Qubit[]) => Unit is Adj + Ctl {
728-
return ApplyObliviousAmplitudeAmplification(
729-
phases,
730-
startStateReflection,
731-
targetStateReflection,
732-
signalOracle,
733-
_,
734-
_
735-
);
736-
}
737-
738-
/// # Summary
739-
/// Oblivious amplitude amplification by specifying partial reflections.
740-
///
741-
/// # Input
742-
/// ## phases
743-
/// Phases of partial reflections
744-
/// ## startStateReflection
745-
/// Reflection operator about start state of auxiliary register
746-
/// ## targetStateReflection
747-
/// Reflection operator about target state of auxiliary register
748-
/// ## signalOracle
749-
/// Unitary oracle $O$ of type `ObliviousOracle` that acts jointly on the
750-
/// auxiliary and system registers.
751-
/// ## auxiliaryRegister
752-
/// Auxiliary register
753-
/// ## systemRegister
754-
/// System register
755-
///
756-
/// # Remarks
757-
/// Given a particular auxiliary start state $\ket{\text{start}}\_a$, a
758-
/// particular auxiliary target state $\ket{\text{target}}\_a$, and any
759-
/// system state $\ket{\psi}\_s$, suppose that
760-
/// \begin{align}
761-
/// O\ket{\text{start}}\_a\ket{\psi}\_s= \lambda\ket{\text{target}}\_a U \ket{\psi}\_s + \sqrt{1-|\lambda|^2}\ket{\text{target}^\perp}\_a\cdots
762-
/// \end{align}
763-
/// for some unitary $U$.
764-
/// By a sequence of reflections about the start and target states on the
765-
/// auxiliary register interleaved by applications of `signalOracle` and its
766-
/// adjoint, the success probability of applying $U$ may be altered.
767-
///
768-
/// In most cases, `auxiliaryRegister` is initialized in the state $\ket{\text{start}}\_a$.
769-
///
770-
/// # References
771-
/// - See [*D.W. Berry, A.M. Childs, R. Cleve, R. Kothari, R.D. Somma*](https://arxiv.org/abs/1312.1414)
772-
/// for the standard version.
773-
/// - See [*G.H. Low, I.L. Chuang*](https://arxiv.org/abs/1610.06546)
774-
/// for a generalization to partial reflections.
775-
operation ApplyObliviousAmplitudeAmplification(
776-
phases : (Double[], Double[]),
777-
startStateReflection : (Double, Qubit[]) => Unit is Adj + Ctl,
778-
targetStateReflection : (Double, Qubit[]) => Unit is Adj + Ctl,
779-
signalOracle : (Qubit[], Qubit[]) => Unit is Adj + Ctl,
780-
auxiliaryRegister : Qubit[],
781-
systemRegister : Qubit[]
782-
) : Unit is Adj + Ctl {
783-
let (aboutStart, aboutTarget) = phases;
784-
Fact(Length(aboutStart) == Length(aboutTarget), "number of phases about start and target state must be equal");
785-
let numPhases = Length(aboutStart);
786-
787-
for idx in 0..numPhases-1 {
788-
if aboutStart[idx] != 0.0 {
789-
startStateReflection(aboutStart[idx], auxiliaryRegister);
790-
}
791-
792-
if aboutTarget[idx] != 0.0 {
793-
// In the last iteration we do not need to apply `Adjoint signalOracle`
794-
if idx == numPhases - 1 {
795-
signalOracle(auxiliaryRegister, systemRegister);
796-
targetStateReflection(aboutTarget[idx], auxiliaryRegister);
797-
} else {
798-
within {
799-
signalOracle(auxiliaryRegister, systemRegister);
800-
} apply {
801-
targetStateReflection(aboutTarget[idx], auxiliaryRegister);
802-
}
803-
}
804-
}
805-
}
806-
807-
// We do need one more `signalOracle` call, if the last phase about the target state was 0.0
808-
if numPhases == 0 or aboutTarget[numPhases - 1] == 0.0 {
809-
signalOracle(auxiliaryRegister, systemRegister);
810-
}
811-
}
812-
813-
operation PrepareUniformSuperpositionOracle(nIndices : Int, nQubits : Int, idxFlag : Int, qubits : Qubit[]) : Unit is Adj + Ctl {
814-
let targetQubits = qubits[3...];
815-
let flagQubit = qubits[0];
816-
let auxillaryQubits = qubits[1..2];
817-
let theta = ArcSin(Sqrt(IntAsDouble(2^nQubits) / IntAsDouble(nIndices)) * Sin(PI() / 6.0));
818-
819-
ApplyToEachCA(H, targetQubits);
820-
use compareQubits = Qubit[nQubits] {
821-
within {
822-
ApplyXorInPlace(nIndices - 1, compareQubits);
823-
} apply {
824-
ApplyIfGreaterLE(X, targetQubits, compareQubits, auxillaryQubits[0]);
825-
X(auxillaryQubits[0]);
826-
}
827-
}
828-
Ry(2.0 * theta, auxillaryQubits[1]);
829-
(Controlled X)(auxillaryQubits, flagQubit);
830-
}
831-
832629
// Classical processing
833630
// This discretizes the coefficients such that
834631
// |coefficient[i] * oneNorm - discretizedCoefficient[i] * discretizedOneNorm| * nCoeffs <= 2^{1-bitsPrecision}.

library/chemistry/src/Tests.qs

-15
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import Std.StatePreparation.ApproximatelyPreparePureStateCP;
22
// Copyright (c) Microsoft Corporation. All rights reserved.
33
// Licensed under the MIT License.
44

5-
import JordanWigner.JordanWignerOptimizedBlockEncoding.PrepareUniformSuperposition;
65
import JordanWigner.JordanWignerClusterOperatorEvolutionSet.JordanWignerClusterOperatorPQRSTermSigns;
76
import JordanWigner.OptimizedBEOperator.OptimizedBEXY;
87
import JordanWigner.OptimizedBEOperator.SelectZ;
@@ -23,20 +22,6 @@ import Std.Math.Lg;
2322
import Std.Arrays.Reversed;
2423
import Std.Math.Sqrt;
2524

26-
@Config(Unrestricted)
27-
@Test()
28-
operation PrepareUniformSuperpositionTest() : Unit {
29-
let NBits = 4;
30-
use qs = Qubit[NBits];
31-
for NStates in 1..2^NBits-1 {
32-
PrepareUniformSuperposition(NStates, qs);
33-
let t = Std.Math.Sqrt(1.0 / IntAsDouble(NStates));
34-
Adjoint Std.StatePreparation.PreparePureStateD(Repeated(t, NStates), Reversed(qs));
35-
Fact(CheckAllZero(qs), "All Z");
36-
ResetAll(qs);
37-
}
38-
}
39-
4025
@Config(Unrestricted)
4126
@Test()
4227
operation PrepareSparseMultiConfigurationalState0Test() : Unit {

library/src/tests/resources/src/state_preparation.qs

+18
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,22 @@ namespace Test {
106106
}
107107
}
108108

109+
operation TestPrepareUniformSuperposition(nStates : Int) : Unit {
110+
use qs = Qubit[10];
111+
PrepareUniformSuperposition(nStates, qs);
112+
DumpMachine();
113+
ResetAll(qs);
114+
}
115+
116+
operation TestPrepareUniformSuperpositionExhaustive() : Unit {
117+
let NBits = 4;
118+
for NStates in 1..2^NBits-1 {
119+
use qs = Qubit[NBits];
120+
PrepareUniformSuperposition(NStates, qs);
121+
let t = Std.Math.Sqrt(1.0 / IntAsDouble(NStates));
122+
Adjoint Std.StatePreparation.PreparePureStateD(Repeated(t, NStates), Reversed(qs));
123+
Fact(CheckAllZero(qs), "All qubits must be in zero state.");
124+
}
125+
}
126+
109127
}

library/src/tests/state_preparation.rs

+53
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT License.
33

44
use super::test_expression;
5+
use super::test_expression_fails;
56
use super::test_expression_with_lib;
67
use expect_test::expect;
78
use qsc::interpret::Value;
@@ -254,3 +255,55 @@ fn check_preparation_doc_sample() {
254255
"#]]
255256
.assert_eq(&out);
256257
}
258+
259+
#[test]
260+
fn check_uniform_superposition_preparation() {
261+
let out = test_expression_with_lib(
262+
"Test.TestPrepareUniformSuperposition(5)",
263+
STATE_PREPARATION_TEST_LIB,
264+
&Value::Tuple(vec![].into()),
265+
);
266+
267+
expect![[r#"
268+
STATE:
269+
|0000000000⟩: 0.4472+0.0000𝑖
270+
|0010000000⟩: 0.4472+0.0000𝑖
271+
|0100000000⟩: 0.4472+0.0000𝑖
272+
|1000000000⟩: 0.4472+0.0000𝑖
273+
|1100000000⟩: 0.4472+0.0000𝑖
274+
"#]]
275+
.assert_eq(&out);
276+
}
277+
278+
#[test]
279+
fn check_uniform_superposition_preparation_exhaustive() {
280+
let _ = test_expression_with_lib(
281+
"Test.TestPrepareUniformSuperpositionExhaustive()",
282+
STATE_PREPARATION_TEST_LIB,
283+
&Value::Tuple(vec![].into()),
284+
);
285+
}
286+
287+
#[test]
288+
fn check_uniform_superposition_short_array() {
289+
let out = test_expression_fails(
290+
"{
291+
use qs=Qubit[2];
292+
Std.StatePreparation.PrepareUniformSuperposition(5, qs);
293+
}",
294+
);
295+
296+
expect!["program failed: Qubit register is too short to prepare 5 states."].assert_eq(&out);
297+
}
298+
299+
#[test]
300+
fn check_uniform_superposition_invalid_state_count() {
301+
let out = test_expression_fails(
302+
"{
303+
use qs=Qubit[2];
304+
Std.StatePreparation.PrepareUniformSuperposition(0, qs);
305+
}",
306+
);
307+
308+
expect!["program failed: Number of basis states must be positive."].assert_eq(&out);
309+
}

0 commit comments

Comments
 (0)