This repository has been archived by the owner on Aug 21, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Tasks.qs
258 lines (219 loc) · 12.3 KB
/
Tasks.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
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
namespace Quantum.Kata.DistinguishUnitaries {
open Microsoft.Quantum.Intrinsic;
//////////////////////////////////////////////////////////////////
// Welcome!
//////////////////////////////////////////////////////////////////
// "Distinguishing Unitaries" quantum kata is a series of exercises designed
// to help you learn to think about unitary transformations in a different way.
// It covers figuring out ways to distinguish several unitaries from the given list
// by performing experiments on them.
// Each task is wrapped in one operation preceded by the description of the task.
// Each task (except tasks in which you have to write a test) has a unit test associated with it,
// which initially fails. Your goal is to fill in the blank (marked with // ... comment)
// with some Q# code to make the failing test pass.
// The tasks are given in approximate order of increasing difficulty; harder ones are marked with asterisks.
//////////////////////////////////////////////////////////////////
// Part I. Single-Qubit Gates
//////////////////////////////////////////////////////////////////
// Task 1.1. Identity or Pauli X?
// Input: An operation that implements a single-qubit unitary transformation:
// either the identity (I gate)
// or the Pauli X gate (X gate).
// The operation will have Adjoint and Controlled variants defined.
// Output: 0 if the given operation is the I gate,
// 1 if the given operation is the X gate.
// You are allowed to apply the given operation and its adjoint/controlled variants exactly once.
operation DistinguishIfromX (unitary : (Qubit => Unit is Adj+Ctl)) : Int {
// ...
return -1;
}
// Task 1.2. Identity or Pauli Z?
// Input: An operation that implements a single-qubit unitary transformation:
// either the identity (I gate)
// or the Pauli Z gate (Z gate).
// The operation will have Adjoint and Controlled variants defined.
// Output: 0 if the given operation is the I gate,
// 1 if the given operation is the Z gate.
// You are allowed to apply the given operation and its adjoint/controlled variants exactly once.
operation DistinguishIfromZ (unitary : (Qubit => Unit is Adj+Ctl)) : Int {
// ...
return -1;
}
// Task 1.3. Z or S?
// Input: An operation that implements a single-qubit unitary transformation:
// either the Pauli Z gate
// or the S gate.
// The operation will have Adjoint and Controlled variants defined.
// Output: 0 if the given operation is the Z gate,
// 1 if the given operation is the S gate.
// You are allowed to apply the given operation and its adjoint/controlled variants at most twice.
operation DistinguishZfromS (unitary : (Qubit => Unit is Adj+Ctl)) : Int {
// ...
return -1;
}
// Task 1.4. Hadamard or Pauli X?
// Input: An operation that implements a single-qubit unitary transformation:
// either the Hadamard gate
// or the Pauli X gate.
// The operation will have Adjoint and Controlled variants defined.
// Output: 0 if the given operation is the H gate,
// 1 if the given operation is the X gate.
// You are allowed to apply the given operation and its adjoint/controlled variants at most twice.
operation DistinguishHfromX (unitary : (Qubit => Unit is Adj+Ctl)) : Int {
// ...
return -1;
}
// Task 1.5. Z or -Z?
// Input: An operation that implements a single-qubit unitary transformation:
// either the Pauli Z gate
// or the minus Pauli Z gate (i.e., a gate -|0〉〈0| + |1〉〈1|).
// The operation will have Adjoint and Controlled variants defined.
// Output: 0 if the given operation is the Z gate,
// 1 if the given operation is the -Z gate.
// You are allowed to apply the given operation and its adjoint/controlled variants exactly once.
operation DistinguishZfromMinusZ (unitary : (Qubit => Unit is Adj+Ctl)) : Int {
// ...
return -1;
}
// Task 1.6. Rz or R1 (arbitrary angle)?
// Input: An operation that implements a single-qubit unitary transformation:
// either the Rz gate
// or the R1 gate.
// This operation will take two parameters: the first parameter is the rotation angle, in radians,
// and the second parameter is the qubit to which the gate should be applied (matching normal Rz and R1 gates in Q#).
// The operation will have Adjoint and Controlled variants defined.
// Output: 0 if the given operation is the Rz gate,
// 1 if the given operation is the R1 gate.
// You are allowed to apply the given operation and its adjoint/controlled variants exactly once.
operation DistinguishRzFromR1 (unitary : ((Double, Qubit) => Unit is Adj+Ctl)) : Int {
// ...
return -1;
}
// Task 1.7. Y or XZ?
// Input: An operation that implements a single-qubit unitary transformation:
// either the Pauli Y gate
// or the sequence of Pauli Z and Pauli X gates (equivalent to applying the Z gate followed by the X gate).
// The operation will have Adjoint and Controlled variants defined.
// Output: 0 if the given operation is the Y gate,
// 1 if the given operation is the XZ gate.
// You are allowed to apply the given operation and its adjoint/controlled variants at most twice.
operation DistinguishYfromXZ (unitary : (Qubit => Unit is Adj+Ctl)) : Int {
// ...
return -1;
}
// Task 1.8. Y, XZ, -Y or -XZ?
// Input: An operation that implements a single-qubit unitary transformation:
// either the Pauli Y gate (possibly with an extra global phase of -1)
// or the sequence of Pauli Z and Pauli X gates (possibly with an extra global phase of -1).
// The operation will have Adjoint and Controlled variants defined.
// Output: 0 if the given operation is the Y gate,
// 1 if the given operation is the -XZ gate,
// 2 if the given operation is the -Y gate,
// 3 if the given operation is the XZ gate.
// You are allowed to apply the given operation and its adjoint/controlled variants at most three times.
operation DistinguishYfromXZWithPhases (unitary : (Qubit => Unit is Adj+Ctl)) : Int {
// ...
return -1;
}
// Task 1.9. Rz or Ry (fixed angle)?
// Inputs:
// 1) An angle θ ∊ [0.01π; 0.99π].
// 2) An operation that implements a single-qubit unitary transformation:
// either the Rz(θ) gate
// or the Ry(θ) gate.
// The operation will have Adjoint and Controlled variants defined.
// Output: 0 if the given operation is the Rz(θ) gate,
// 1 if the given operation is the Ry(θ) gate.
// You are allowed to apply the given operation and its adjoint/controlled variants any number of times.
operation DistinguishRzFromRy (theta : Double, unitary : (Qubit => Unit is Adj+Ctl)) : Int {
// ...
return -1;
}
// Task 1.10*. Rz or R1 (fixed angle)?
// Inputs:
// 1) An angle θ ∊ [0.01π; 0.99π].
// 2) An operation that implements a single-qubit unitary transformation:
// either the Rz(θ) gate
// or the R1(θ) gate.
// The operation will have Adjoint and Controlled variants defined.
// Output: 0 if the given operation is the Rz(θ) gate,
// 1 if the given operation is the R1(θ) gate.
// You are allowed to apply the given operation and its adjoint/controlled variants any number of times.
operation DistinguishRzFromR1WithAngle (theta : Double, unitary : (Qubit => Unit is Adj+Ctl)) : Int {
// ...
return -1;
}
// Task 1.11. Distinguish 4 Pauli unitaries
// Input: An operation that implements a single-qubit unitary transformation:
// either the identity (I gate) or one of the Pauli gates (X, Y or Z gate).
// The operation will have Adjoint and Controlled variants defined.
// Output: 0 if the given operation is the I gate,
// 1 if the given operation is the X gate,
// 2 if the given operation is the Y gate,
// 3 if the given operation is the Z gate,
// You are allowed to apply the given operation and its adjoint/controlled variants exactly once.
operation DistinguishPaulis (unitary : (Qubit => Unit is Adj+Ctl)) : Int {
// ...
return -1;
}
//////////////////////////////////////////////////////////////////
// Part II. Multi-Qubit Gates
//////////////////////////////////////////////////////////////////
// Task 2.1. I ⊗ X or CNOT?
// Input: An operation that implements a two-qubit unitary transformation:
// either I ⊗ X (the X gate applied to the second qubit)
// or the CNOT gate with the first qubit as control and the second qubit as target.
// The operation will accept an array of qubits as input, but it will fail if the array is empty or has one or more than two qubits.
// The operation will have Adjoint and Controlled variants defined.
// Output: 0 if the given operation is I ⊗ X,
// 1 if the given operation is the CNOT gate.
// You are allowed to apply the given operation and its adjoint/controlled variants exactly once.
operation DistinguishIXfromCNOT (unitary : (Qubit[] => Unit is Adj+Ctl)) : Int {
// ...
return -1;
}
// Task 2.2. Figure out the direction of CNOT
// Input: An operation that implements a two-qubit unitary transformation:
// either the CNOT gate with the first qubit as control and the second qubit as target (CNOT₁₂),
// or the CNOT gate with the second qubit as control and the first qubit as target (CNOT₂₁).
// The operation will accept an array of qubits as input, but it will fail if the array is empty or has one or more than two qubits.
// The operation will have Adjoint and Controlled variants defined.
// Output: 0 if the given operation is CNOT₁₂,
// 1 if the given operation is CNOT₂₁.
// You are allowed to apply the given operation and its adjoint/controlled variants exactly once.
operation CNOTDirection (unitary : (Qubit[] => Unit is Adj+Ctl)) : Int {
// ...
return -1;
}
// Task 2.3. CNOT₁₂ or SWAP?
// Input: An operation that implements a two-qubit unitary transformation:
// either the CNOT gate with the first qubit as control and the second qubit as target (CNOT₁₂)
// or the SWAP gate.
// The operation will accept an array of qubits as input, but it will fail if the array is empty or has one or more than two qubits.
// The operation will have Adjoint and Controlled variants defined.
// Output: 0 if the given operation is the CNOT₁₂ gate,
// 1 if the given operation is the SWAP gate.
// You are allowed to apply the given operation and its adjoint/controlled variants exactly once.
operation DistinguishCNOTfromSWAP (unitary : (Qubit[] => Unit is Adj+Ctl)) : Int {
// ...
return -1;
}
// Task 2.4. Identity, CNOTs or SWAP?
// Input: An operation that implements a two-qubit unitary transformation:
// either the identity (I ⊗ I gate),
// the CNOT gate with one of the qubits as control and the other qubit as a target,
// or the SWAP gate.
// The operation will accept an array of qubits as input, but it will fail if the array is empty or has one or more than two qubits.
// The operation will have Adjoint and Controlled variants defined.
// Output: 0 if the given operation is the I ⊗ I gate,
// 1 if the given operation is the CNOT₁₂ gate,
// 2 if the given operation is the CNOT₂₁ gate,
// 3 if the given operation is the SWAP gate.
// You are allowed to apply the given operation and its adjoint/controlled variants at most twice.
operation DistinguishTwoQubitUnitaries (unitary : (Qubit[] => Unit is Adj+Ctl)) : Int {
// ...
return -1;
}
}