This repository was archived by the owner on Jan 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 925
/
Copy pathHiddenShift.qs
196 lines (168 loc) Β· 8.62 KB
/
HiddenShift.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
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Samples {
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Measurement;
open Microsoft.Quantum.Arrays;
open Microsoft.Quantum.Convert;
// We consider a particular family of problems known as hidden
// shift problems, in which one is given two Boolean functions π and π
// with the promise that they satisfy the relation
//
// π(π₯) = π(π₯ β π ) for all π₯,
//
// where π is a hidden bitstring that we would like to find.
// Good quantum algorithms exist for several different families of
// pairs of Boolean functions. In particular, here we consider the case
// in which both π and π are bent functions. We say that a Boolean
// function is bent if it is as far from linear as possible. In
// particular, bent functions have flat Fourier spectra, such that each
// Fourier coefficient is equal in absolute value.
// In this case, the Roetteler algorithm (see References, below) uses
// black-box oracles for π^* and π, where π^* is the dual bent function
// to π (defined in more detail below), and computes the hidden shift π
// between π and π.
/// # Summary
/// Correlation-based algorithm to solve the hidden shift problem for bent functions.
/// The problem is to identify an unknown shift π of the arguments of two Boolean functions
/// π and π that are promised to satisfy the relation π(π₯) = π(π₯ β π ) for all π₯.
/// Note that the promise about the functions π and π to be bent functions is assumed,
/// i.e., they both have a flat Fourier (WalshβHadamard) spectra. Input to this algorithm
/// are implementations π_g of the Boolean function π and π_f^*, an implementation of
/// dual bent function of the function π. Both functions are given via phase encoding.
///
/// # Input
/// ## Ufstar
/// A quantum operation that implements $U_f^*:\ket{x}\mapsto (-1)^{f^*(x)} \ket{x}$,
/// where $f^*$ is a Boolean function, $x$ is an $n$ bit register and $y$ is a single qubit.
/// ## Ug
/// A quantum operation that implements $U_g:\ket{x}\mapsto (-1)^{g(x)} \ket{x}$,
/// where $g$ is a Boolean function that is shifted by unknown $s$ from $f$, and $x$ is
/// an $n$ bit register.
/// ## n
/// The number of bits of the input register |π₯βͺ.
///
/// # Output
/// An array of type `Bool[]` which encodes the bit representation of the hidden shift.
///
/// # References
/// - [*Martin Roetteler*,
/// Proc. SODA 2010, ACM, pp. 448-457, 2010](https://doi.org/10.1137/1.9781611973075.37)
operation HiddenShiftBentCorrelation (Ufstar : (Qubit[] => Unit), Ug : (Qubit[] => Unit), n : Int)
: Result[] {
// now, we allocate n clean qubits. Note that the function Ufstar and Ug are
// unitary operations on n qubits defined via phase encoding.
use qubits = Qubit[n];
// first, a Hadamard transform is applied to each of the qubits.
ApplyToEach(H, qubits);
// we now apply the shifted function Ug to the n qubits, computing
// |xβͺ -> (-1)^{g(x)} |xβͺ.
Ug(qubits);
within {
// now, a Hadamard transform is applied to each of the n qubits.
ApplyToEachA(H, qubits);
} apply {
// we now apply the dual function of the unshifted function, i.e., Ufstar,
// to the n qubits, computing |xβͺ -> (-1)^{fstar(x)} |xβͺ.
Ufstar(qubits);
}
// the following for-loop measures the n qubits and resets them to
// zero so that they can be safely returned at the end of the
// using-block.
return ForEach(MResetZ, qubits);
}
// We demonstrate this algorithm by defining an operation which implements
// an oracle for a bent function constructed from the inner product of
// Boolean functions.
// In particular, the operation `InnerProductBentFunctionImpl` defines the Boolean
// function IP(x_0, ..., x_{n-1}) which is computed into the phase, i.e.,
// a diagonal operator that maps |xβͺ -> (-1)^{IP(x)} |xβͺ, where x stands for
// x = (x_0, ..., x_{n-1}) and all the x_i are binary. The IP function is
// defined as IP(y, z) = y_0 z_0 + y_1 z_1 + ... y_{u-1} z_{u-1} where
// y = (y_0, ..., y_{u-1}) and z = (z_0, ..., z_{u-1}) are two bit
// vectors of length u. Notice that the function IP is a Boolean function
// on n = 2u bits. IP is a special case of a so-called 'bent' function.
// These are functions for which the Walsh-Hadamard transform is perfectly
// flat (in absolute value). Because of this flatness, the Walsh-Hadamard
// spectrum of any bent function defines a +1/-1 function, i.e., gives
// rise to another Boolean function, called the 'dual bent function'.
// What is more, for the case of the IP function it can be shown that IP
// is equal to its own dual bent function, a fact that is exploited in
// the present test case.
// Notice that a diagonal operator implementing IP between 2 variables
// y_0 and z_0 is nothing but the AND function between those variables, i.e.,
// in phase encoding it is computed by a Controlled-Z gate. Extending this
// to an XOR of the AND of more variables, as required in the definition of
// the IP function can then be accomplished by applying several Controlled-Z
// gates between the respective inputs.
internal operation ApplyInnerProductBentFunction(u : Int, qs : Qubit[]) : Unit {
if Length(qs) != 2 * u {
fail "Length of qs must be twice the value of u";
}
let xs = qs[0 .. u - 1];
let ys = qs[u .. 2 * u - 1];
for idx in 0 .. u - 1 {
Controlled Z([xs[idx]], ys[idx]);
}
}
// Again, using partial application we create a function which for a given bit
// size u constructs the IP Boolean function on 2u qubits, computed into the phase.
function InnerProductBentFunction(u : Int) : (Qubit[] => Unit) {
return ApplyInnerProductBentFunction(u, _);
}
// To instantiate the hidden shift problem we need another function g which is
// related to IP via g(x) = IP(x + s), i.e., we have to shift the argument of
// the IP function by a given shift. Notice that the '+' operation here is the
// Boolean addition, i.e., a bit-wise operation. Notice further, that in
// general a diagonal operation |xβͺ -> (-1)^{f(x)} can be turned into a shifted
// version by applying a bit flip to the |xβͺ register first, then applying the
// diagonal operation, and then undoing the bit flips to the |xβͺ register. We
// use this principle to define shifted versions of the IP operation.
internal operation ApplyShiftedInnerProductBentFunction(shift : Bool[], u : Int, qs : Qubit[]) : Unit {
let n = 2 * u;
if Length(shift) != n or Length(qs) != n {
fail "Length of shift and qs must be twice the value of u";
}
within {
// the following loop flips the bits in shift
for (shiftBit, target) in Zipped(shift, qs) {
if shiftBit {
X(target);
}
}
} apply {
// now we compute the IP function into the phase
InnerProductBentFunction(u)(qs);
}
}
// Again, using partial application we construct a function that produces the
// operations that are used to instantiate a particular hidden shift problem
// and are then passed to the quantum algorithm `HiddenShiftBentCorrelation`
// which computes the hidden shift.
function ShiftedInnerProductBentFunction(shift : Bool[], u : Int) : (Qubit[] => Unit) {
return ApplyShiftedInnerProductBentFunction(shift, u, _);
}
/// # Summary
/// Runs the hidden shift program.
///
/// # Input
/// ## patternInt
/// Pattern to be used, represented as an integer.
/// ## registerSize
/// Qubit register size
///
/// # Output
/// An array of the qubit measurement results
@EntryPoint()
operation RunHiddenShift(patternInt : Int, registerSize : Int) : Result[] {
let nQubits = 2 * registerSize;
// Convert the integer pattern to a bit string.
let pattern = IntAsBoolArray(patternInt, nQubits);
return HiddenShiftBentCorrelation(
InnerProductBentFunction(registerSize),
ShiftedInnerProductBentFunction(pattern, registerSize),
nQubits
);
}
}