microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
copilot/fix-circuit-panel-error-message

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

samples/estimation/df-chemistry/src/Prepare.qs

178lines · modecode

1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT License.
3import Std.Arrays.*;
4import Std.Convert.*;
5import Std.Diagnostics.*;
6import Std.Intrinsic.*;
7import Std.Math.*;
8import Std.Arithmetic.*;
9import Std.TableLookup.*;
10import Std.StatePreparation.PrepareUniformSuperposition;
11
12// ------------------------------------- //
13// State preparation (public operations) //
14// ------------------------------------- //
15
16operation PrepareSingleQubit(p0 : Double, p1 : Double, target : Qubit) : Unit is Adj + Ctl {
17 let oneNorm = p0 + p1;
18 let alpha = ArcCos(Sqrt(p0 / oneNorm));
19
20 Ry(2.0 * alpha, target);
21}
22
23struct PrepareArbitrarySuperposition {
24 NIndexQubits : Int,
25 NGarbageQubits : Int,
26 Prepare : (Qubit[], Qubit[], Qubit[]) => Unit is Adj + Ctl,
27 PrepareWithSelect : ((Bool[][], Qubit[], Qubit[]) => Unit is Adj + Ctl, Qubit[], Qubit[], Qubit[]) => Unit is Adj + Ctl
28}
29
30function MakePrepareArbitrarySuperposition(targetError : Double, coefficients : Double[]) : PrepareArbitrarySuperposition {
31 let nBitsPrecision = -Ceiling(Lg(0.5 * targetError)) + 1;
32 let positiveCoefficients = Mapped(AbsD, coefficients);
33 let (keepCoeff, altIndex) = DiscretizedProbabilityDistribution(nBitsPrecision, positiveCoefficients);
34 let nCoeffs = Length(positiveCoefficients);
35 let nBitsIndices = Ceiling(Lg(IntAsDouble(nCoeffs)));
36
37 let op = PrepareQuantumROMState(nBitsPrecision, nCoeffs, nBitsIndices, keepCoeff, altIndex, [], Select, _, _, _);
38 let opWithSelect = PrepareQuantumROMState(nBitsPrecision, nCoeffs, nBitsIndices, keepCoeff, altIndex, [], _, _, _, _);
39 let (nIndexQubits, nGarbageQubits) = ArbitrarySuperpositionRegisterLengths(targetError, nCoeffs);
40 return new PrepareArbitrarySuperposition { NIndexQubits = nIndexQubits, NGarbageQubits = nGarbageQubits, Prepare = op, PrepareWithSelect = opWithSelect };
41}
42
43function MakePrepareArbitrarySuperpositionWithData(targetError : Double, coefficients : Double[], data : Bool[][]) : PrepareArbitrarySuperposition {
44 let nBitsPrecision = -Ceiling(Lg(0.5 * targetError)) + 1;
45 let positiveCoefficients = Mapped(AbsD, coefficients);
46 let (keepCoeff, altIndex) = DiscretizedProbabilityDistribution(nBitsPrecision, positiveCoefficients);
47 let nCoeffs = Length(positiveCoefficients);
48 let nBitsIndices = Ceiling(Lg(IntAsDouble(nCoeffs)));
49
50 let op = PrepareQuantumROMState(nBitsPrecision, nCoeffs, nBitsIndices, keepCoeff, altIndex, data, Select, _, _, _);
51 let opWithSelect = PrepareQuantumROMState(nBitsPrecision, nCoeffs, nBitsIndices, keepCoeff, altIndex, data, _, _, _, _);
52 let (nIndexQubits, nGarbageQubits) = ArbitrarySuperpositionRegisterLengths(targetError, nCoeffs);
53 return new PrepareArbitrarySuperposition { NIndexQubits = nIndexQubits, NGarbageQubits = nGarbageQubits + Length(data[0]), Prepare = op, PrepareWithSelect = opWithSelect };
54}
55
56// -------------------------------------- //
57// State preparation (private operations) //
58// -------------------------------------- //
59
60internal function ArbitrarySuperpositionRegisterLengths(targetError : Double, nCoefficients : Int) : (Int, Int) {
61 Fact(targetError > 0.0, "targetError must be positive");
62 Fact(nCoefficients > 0, "nCoefficients must be positive");
63
64 let nBitsPrecision = -Ceiling(Lg(0.5 * targetError)) + 1;
65 let nIndexQubits = Ceiling(Lg(IntAsDouble(nCoefficients)));
66 let nGarbageQubits = nIndexQubits + 2 * nBitsPrecision + 1;
67 (nIndexQubits, nGarbageQubits)
68}
69
70// Computes discretized probability distribution as described in Section 3
71// and Fig. 13 in [arXiv:1805.03662](https://arxiv.org/pdf/1805.03662.pdf)
72internal function DiscretizedProbabilityDistribution(bitsPrecision : Int, coefficients : Double[]) : (Int[], Int[]) {
73 let oneNorm = PNorm(1.0, coefficients);
74 let nCoefficients = Length(coefficients);
75 Fact(bitsPrecision <= 31, $"Bits of precision {bitsPrecision} unsupported. Max is 31.");
76 Fact(nCoefficients > 1, "Cannot prepare state with less than 2 coefficients.");
77 Fact(AbsD(oneNorm) > 0.0, "State must have at least one coefficient > 0");
78
79 let barHeight = 2^bitsPrecision - 1;
80
81 mutable altIndex = SequenceI(0, nCoefficients - 1);
82 mutable keepCoeff = Mapped(
83 coefficient -> Round((AbsD(coefficient) / oneNorm) * IntAsDouble(nCoefficients) * IntAsDouble(barHeight)),
84 coefficients
85 );
86
87 // Calculate difference between number of discretized bars vs. maximum
88 let bars = Fold((state, value) -> state + value - barHeight, 0, keepCoeff);
89
90 // Uniformly distribute excess bars across coefficients.
91 for idx in 0..AbsI(bars) - 1 {
92 set keepCoeff w/= idx <- keepCoeff[idx] + (bars > 0 ? -1 | + 1);
93 }
94
95 mutable barSink = [];
96 mutable barSource = [];
97
98 for idxCoeff in IndexRange(keepCoeff) {
99 if keepCoeff[idxCoeff] > barHeight {
100 set barSource += [idxCoeff];
101 } elif keepCoeff[idxCoeff] < barHeight {
102 set barSink += [idxCoeff];
103 }
104 }
105
106 for rep in 0..nCoefficients * 10 {
107 if Length(barSink) > 0 and Length(barSource) > 0 {
108 let idxSink = Tail(barSink);
109 let idxSource = Tail(barSource);
110 set barSink = Most(barSink);
111 set barSource = Most(barSource);
112
113 set keepCoeff w/= idxSource <- keepCoeff[idxSource] - barHeight + keepCoeff[idxSink];
114 set altIndex w/= idxSink <- idxSource;
115
116 if keepCoeff[idxSource] < barHeight {
117 set barSink += [idxSource];
118 } elif keepCoeff[idxSource] > barHeight {
119 set barSource += [idxSource];
120 }
121 } elif Length(barSource) > 0 {
122 let idxSource = Tail(barSource);
123 set barSource = Most(barSource);
124 set keepCoeff w/= idxSource <- barHeight;
125 } else {
126 return (keepCoeff, altIndex);
127 }
128 }
129
130 return (keepCoeff, altIndex);
131}
132
133// Used in QuantumROM implementation.
134internal operation PrepareQuantumROMState(
135 nBitsPrecision : Int,
136 nCoeffs : Int,
137 nBitsIndices : Int,
138 keepCoeff : Int[],
139 altIndex : Int[],
140 data : Bool[][],
141 selectOperation : (Bool[][], Qubit[], Qubit[]) => Unit is Adj + Ctl,
142 indexRegister : Qubit[],
143 dataQubits : Qubit[],
144 garbageRegister : Qubit[]
145) : Unit is Adj + Ctl {
146 let garbageIdx0 = nBitsIndices;
147 let garbageIdx1 = garbageIdx0 + nBitsPrecision;
148 let garbageIdx2 = garbageIdx1 + nBitsPrecision;
149 let garbageIdx3 = garbageIdx2 + 1;
150
151 let altIndexRegister = garbageRegister[0..garbageIdx0 - 1];
152 let keepCoeffRegister = garbageRegister[garbageIdx0..garbageIdx1 - 1];
153 let uniformKeepCoeffRegister = garbageRegister[garbageIdx1..garbageIdx2 - 1];
154 let flagQubit = garbageRegister[garbageIdx3 - 1];
155 let dataRegister = dataQubits;
156 let altDataRegister = garbageRegister[garbageIdx3...];
157
158 // Create uniform superposition over index and alt coeff register.
159 PrepareUniformSuperposition(nCoeffs, indexRegister);
160 ApplyToEachCA(H, uniformKeepCoeffRegister);
161
162 // Write bitstrings to altIndex and keepCoeff register.
163 let target = keepCoeffRegister + altIndexRegister + dataRegister + altDataRegister;
164 let selectData = MappedOverRange(idx -> IntAsBoolArray(keepCoeff[idx], Length(keepCoeffRegister)) + IntAsBoolArray(altIndex[idx], Length(altIndexRegister)) + (IsEmpty(data) ? [] | data[idx] + data[altIndex[idx]]), 0..nCoeffs - 1);
165 selectOperation(selectData, indexRegister, target);
166
167 // Perform comparison
168 ApplyIfGreaterLE(X, uniformKeepCoeffRegister, keepCoeffRegister, flagQubit);
169
170 let indexRegisterSize = Length(indexRegister);
171
172 // Swap in register based on comparison
173 let lhs = indexRegister + dataRegister;
174 let rhs = altIndexRegister + altDataRegister;
175 for i in IndexRange(lhs) {
176 Controlled SWAP([flagQubit], (lhs[i], rhs[i]));
177 }
178}
179