forked from microsoft/QuantumKatas
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ReferenceImplementation.qs
243 lines (196 loc) · 9.33 KB
/
ReferenceImplementation.qs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
//////////////////////////////////////////////////////////////////////
// This file contains reference solutions to all tasks.
// The tasks themselves can be found in Tasks.qs file.
// We recommend that you try to solve the tasks yourself first,
// but feel free to look up the solution if you get stuck.
//////////////////////////////////////////////////////////////////////
namespace Quantum.Kata.QFT {
open Microsoft.Quantum.Measurement;
open Microsoft.Quantum.Arrays;
open Microsoft.Quantum.Arithmetic;
open Microsoft.Quantum.Convert;
open Microsoft.Quantum.Math;
open Microsoft.Quantum.Diagnostics;
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Canon;
//////////////////////////////////////////////////////////////////
// Part I. Implementing Quantum Fourier Transform
//////////////////////////////////////////////////////////////////
// Task 1.1. 1-qubit QFT
operation OneQubitQFT_Reference (q : Qubit) : Unit is Adj+Ctl {
H(q);
}
// Task 1.2. Rotation gate
operation Rotation_Reference (q : Qubit, k : Int) : Unit is Adj+Ctl {
R1Frac(2, k, q);
}
// Task 1.3. Prepare binary fraction exponent (classical input)
// Inputs:
// 1) A qubit in state |ψ⟩ = α |0⟩ + β |1⟩
// 2) An array of bits [j₁, j₂, ..., jₙ], stored as Int[] (jₖ ∈ {0, 1}).
// Goal: Change the state of the qubit to α |0⟩ + β · exp(2πi · 0.j₁j₂...jₙ) |1⟩,
// where 0.j₁j₂...jₙ is a binary fraction, similar to decimal fractions:
// 0.j₁j₂...jₙ = j₁ / 2¹ + j₂ / 2² + ... + jₙ / 2ⁿ.
operation BinaryFractionClassical_Reference (q : Qubit, j : Int[]) : Unit is Adj+Ctl {
for ind in 0 .. Length(j) - 1 {
if j[ind] == 1 {
Rotation_Reference(q, ind + 1);
}
}
}
function IntArrayAsInt (j : Int[]) : Int {
mutable n = 0;
for ind in 0 .. Length(j) - 1 {
set n = n * 2 + j[ind];
}
return n;
}
operation BinaryFractionClassical_Alternative (q : Qubit, j : Int[]) : Unit is Adj+Ctl {
// alternatively, we can convert the number to an integer and apply a single R1 rotation
let num = IntArrayAsInt(j);
R1(2.0 * PI() * IntAsDouble(num) / IntAsDouble(1 <<< Length(j)), q);
}
// Task 1.4. Prepare binary fraction exponent (quantum input)
// Inputs:
// 1) A qubit in state |ψ⟩ = α |0⟩ + β |1⟩
// 2) A register of qubits in state |j₁j₂...jₙ⟩
// Goal: Change the state of the input
// from (α |0⟩ + β |1⟩) ⊗ |j₁j₂...jₙ⟩
// to (α |0⟩ + β · exp(2πi · 0.j₁j₂...jₙ) |1⟩) ⊗ |j₁j₂...jₙ⟩,
// where 0.j₁j₂...jₙ is a binary fraction corresponding to the basis state j₁j₂...jₙ of the register.
operation BinaryFractionQuantum_Reference (q : Qubit, jRegister : Qubit[]) : Unit is Adj+Ctl {
for ind in 0 .. Length(jRegister) - 1 {
Controlled Rotation_Reference([jRegister[ind]], (q, ind + 1));
}
}
// Task 1.5. Prepare binary fraction exponent in place (quantum input)
// Input: A register of qubits in state |j₁j₂...jₙ⟩
// Goal: Change the state of the register
// from |j₁⟩ ⊗ |j₂...jₙ⟩
// to 1/sqrt(2) (|0⟩ + exp(2πi · 0.j₁j₂...jₙ) |1⟩) ⊗ |j₂...jₙ⟩.
operation BinaryFractionQuantumInPlace_Reference (register : Qubit[]) : Unit is Adj+Ctl {
OneQubitQFT_Reference(register[0]);
for ind in 1 .. Length(register) - 1 {
Controlled Rotation_Reference([register[ind]], (register[0], ind + 1));
}
}
// Task 1.6. Reverse the order of qubits
// Input: A register of qubits in state |x₁x₂...xₙ⟩
// Goal: Reverse the order of qubits, i.e., convert the state of the register to |xₙ...x₂x₁⟩.
operation ReverseRegister_Reference (register : Qubit[]) : Unit is Adj+Ctl {
let N = Length(register);
for ind in 0 .. N / 2 - 1 {
SWAP(register[ind], register[N - 1 - ind]);
}
}
// Task 1.7. Quantum Fourier transform
// Input: A register of qubits in state |j₁j₂...jₙ⟩
// Goal: Apply quantum Fourier transform to the input register, i.e.,
// transform it to a state
// 1/sqrt(2) (|0⟩ + exp(2πi · 0.jₙ) |1⟩) ⊗
// 1/sqrt(2) (|0⟩ + exp(2πi · 0.jₙ₋₁jₙ) |1⟩) ⊗ ... ⊗
// 1/sqrt(2) (|0⟩ + exp(2πi · 0.j₁j₂...jₙ₋₁jₙ) |1⟩) ⊗
operation QuantumFourierTransform_Reference (register : Qubit[]) : Unit is Adj+Ctl {
let n = Length(register);
for i in 0 .. n - 1 {
BinaryFractionQuantumInPlace_Reference(register[i ...]);
}
ReverseRegister_Reference(register);
}
// Task 1.8. Inverse QFT
operation InverseQFT_Reference (register : Qubit[]) : Unit is Adj+Ctl {
Adjoint QuantumFourierTransform_Reference(register);
}
//////////////////////////////////////////////////////////////////
// Part II. Using the Quantum Fourier Transform
//////////////////////////////////////////////////////////////////
// Task 2.1. Prepare an equal superposition of all basis states
operation PrepareEqualSuperposition_Reference (register : Qubit[]) : Unit is Adj+Ctl {
// We get equal superposition of all basis states
// if we apply QFT to the |0...0⟩ state
QFT(BigEndian(register));
}
// Task 2.2. Prepare a periodic state
// 1 / sqrt(2ⁿ) Σₖ exp(2πi Fk/2ⁿ) |k⟩
operation PreparePeriodicState_Reference (register : Qubit[], F : Int) : Unit is Adj+Ctl {
// Prepare state |F⟩ (in big endian notation)
// IntAsBoolArray gets bits in little endian notation, so need to reverse
let bitsBE = Reversed(IntAsBoolArray(F, Length(register)));
ApplyPauliFromBitString(PauliX, true, bitsBE, register);
QFT(BigEndian(register));
}
// Task 2.3. Prepare a periodic state with alternating 1 and -1 amplitudes
// 1 / sqrt(2ⁿ) (|0⟩ - |1⟩ + |2⟩ - |3⟩ + ... - |2ⁿ-1⟩).
operation PrepareAlternatingState_Reference (register : Qubit[]) : Unit is Adj+Ctl {
// Prepare state |2ⁿ⁻¹⟩ = |10...0⟩
// which corresponds to 1 / sqrt(2ⁿ) Σₖ exp(2πi k/2) |k⟩, amplitudes +1 for even k and -1 for odd k
X(Head(register));
QFT(BigEndian(register));
}
// Task 2.4. Prepare an equal superposition of all even basis states
// 1/sqrt(2ⁿ⁻¹) (|0⟩ + |2⟩ + ... + |2ⁿ-2⟩).
operation PrepareEqualSuperpositionOfEvenStates_Reference (register : Qubit[]) : Unit is Adj+Ctl {
// Prepare superposition |0⟩ + |2ⁿ⁻¹⟩ = |0...00⟩ + |0..01⟩
H(Head(register));
QFT(BigEndian(register));
}
// Task 2.5*. Prepare a square-wave signal
// 1/sqrt(2ⁿ) (|0⟩ + |1⟩ - |2⟩ - |3⟩ + ... - |2ⁿ-2⟩ - |2ⁿ-1⟩).
operation PrepareSquareWaveSignal_Reference (register : Qubit[]) : Unit is Adj+Ctl {
// Following https://oreilly-qc.github.io?p=7-3
// Prepare superposition exp(-iπ/4)|2ⁿ⁻²⟩ + exp(iπ/4)|-2ⁿ⁻²⟩
let n = Length(register);
X(register[1]);
// |010...0⟩
H(register[0]);
// |010...0⟩ + |110...0⟩
T(register[0]);
within { X(register[0]); }
apply { Adjoint T(register[0]); }
QFT(BigEndian(register));
}
// Task 2.6. Get the frequency of a signal
// Input: A register of n ≥ 2 qubits in state 1/sqrt(2ⁿ) Σₖ exp(2πikF/2ⁿ) |k⟩, 0 ≤ F ≤ 2ⁿ - 1.
// Goal: Return the frequency F of the "signal" encoded in this state.
operation Frequency_Reference (register : Qubit[]) : Int {
Adjoint QFT(BigEndian(register));
let bitsBE = MultiM(register);
return ResultArrayAsInt(Reversed(bitsBE));
}
//////////////////////////////////////////////////////////////////
// Part III. Powers and roots of the QFT
//////////////////////////////////////////////////////////////////
// Task 3.1. Implement powers of the QFT
operation QFTPower_Reference (P : Int, inputRegister : Qubit[]) : Unit is Adj+Ctl {
// Use the fact that QFT⁴ = I
for _ in 1 .. (P % 4) {
QuantumFourierTransform_Reference(inputRegister);
}
}
// Task 3.2. Implement roots of the QFT
// Follow p.16 of https://arxiv.org/pdf/quant-ph/0309121.pdf
internal operation Circ (qs : LittleEndian, alpha : Double) : Unit is Adj + Ctl {
within {
Adjoint QFTLE(qs);
} apply {
ApplyDiagonalUnitary(
[0.0, -alpha, -2.0*alpha, alpha],
qs
);
}
}
operation QFTRoot_Reference (P : Int, inputRegister : Qubit[]) : Unit is Adj+Ctl {
use aux = Qubit[2];
let Q = QuantumFourierTransform_Reference;
let Q2 = OperationPowCA(Q, 2);
within {
ApplyToEachCA(H, aux);
Controlled Adjoint Q([aux[0]], inputRegister);
Controlled Adjoint Q2([aux[1]], inputRegister);
} apply {
Circ(LittleEndian(aux), PI() / (2.0 * IntAsDouble(P)));
}
}
}