forked from microsoft/Quantum
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Operations.qs
171 lines (143 loc) · 6.77 KB
/
Operations.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
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Quantum.Samples.OracleEmulation
{
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Arithmetic;
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Diagnostics;
open Microsoft.Quantum.Extensions.Oracles;
//////////////////////////////////////////////////////////////////////////
// Defining and using simple emulated oracles ////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Declare an oracle to be implemented in C#. See the
// `PermutationOracle.Register` call in the driver for its implementation.
operation HalfAnswer(x: Qubit[], y: Qubit[]) : Unit {
// Since we are here only interested in the emulation feature, we do not
// provide a native Q# implementation. In general, providing a Q#
// implementation is encouraged because it allows for resource counting
// and running on target machines without emulation capabilities.
body (...) {
fail "not implemented";
}
adjoint auto;
}
// Define a simple permutation function that is used below to create
// another oracle.
function DoubleAnswerFunc(x: Int, y: Int) : Int {
return 84 ^^^ y;
}
// Measure and print the result.
operation MeasureAndDisplay(message: String, register: Qubit[]) : Unit {
let answer = MeasureInteger(LittleEndian(register));
Message($"{message}{answer}.");
}
// # Summary
// Here we demonstrate the use of three simple oracles. Each oracle ignores
// the content of the first register and XOR's a constant number into the
// second register.
//
// # Input
// ## oracle
// A quantum operation that implements an oracle
// $$
// \begin{align}
// O: \ket{x}\ket{y} \rightarrow \ket{x}\ket{f(x, y)}.
// \end{align}
// $$
operation RunConstantOracles (oracle: ((Qubit[], Qubit[]) => Unit)) : Unit {
Message("Querying the oracles...");
// Prepare a one-qubit register `flag` and an eight-qubit register
// `result`. Since all the oracles here ignore the flag, its length and
// state do not matter.
use flag = Qubit();
use result = Qubit[8];
H(flag);
// Apply an oracle that was passed explicitly by the C# driver.
oracle([flag], result);
MeasureAndDisplay("The answer is ", result);
// Apply an oracle that was declared above and implemented in the C#
// driver.
HalfAnswer([flag], result);
MeasureAndDisplay("Half the answer is ", result);
// Apply an oracle defined in terms of a Q# permutation function.
PermutationOracle(DoubleAnswerFunc, [flag], result);
MeasureAndDisplay("Twice the answer is ", result);
// Apply an oracle to a superposition in result.
for _ in 1..5 {
H(result[7]);
// Before the oracle is queried, the state of the result register is
// $\ket{y} = \ket{0} + \ket{128}$.
// The oracle will map this to
// $\ket{y'} = \ket{42 \oplus 0} + \ket{42 \oplus 128} = \ket{42} + \ket{170}$.
oracle([flag], result);
MeasureAndDisplay("The answer might be ", result);
}
Reset(flag);
}
//////////////////////////////////////////////////////////////////////////
// Emulated arithmetic operations ////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Prepare two `LittleEndian` registers in a computational basis state.
operation PrepareSummands(numbers: (Int, Int), registers: (Qubit[], Qubit[])) : (LittleEndian, LittleEndian) {
let x = LittleEndian(Fst(registers));
let y = LittleEndian(Snd(registers));
ApplyXorInPlace(Fst(numbers), x);
ApplyXorInPlace(Snd(numbers), y);
return (x, y);
}
// Measure and check that M(x) + y_init == M(y).
operation MeasureAndCheckAddResult(y_init: Int, x: LittleEndian, y: LittleEndian): (Int, Int) {
let mx = MeasureInteger(x);
let my = MeasureInteger(y);
Message($"Computed {mx} + {y_init} = {my} mod {2^8}");
EqualityFactI((mx + y_init) % 2^8, my, "sum is wrong");
return (mx, my);
}
// Modular addition of 8-bit integers.
function ModAdd8(x: Int, y: Int) : Int {
return (x + y) % (1 <<< 8);
}
// Here we demonstrate how to define and use emulated arithmetic operations.
// Our example is modular addition of 8-bit integers as implemented by the
// one-line function above. This defines already a permutation function on
// the computational basis states of two 8-qubit registers:
// $\ket{m}\ket{n} \rightarrow \ket{m}\ket{m + n \mod 8}$.
// We can hence directly turn this function into an emulated oracle.
operation RunAddOracle() : Unit {
Message("Running emulated addition...");
// Turn the permutation function into an oracle operation acting on two
// quantum registers.
let adder = PermutationOracle(ModAdd8, _, _);
let width = 8;
// Two integers to initialize the registers.
let numbers = (123, 234);
// Write the numbers into registers and add them.
use registers = (Qubit[width], Qubit[width]) {
// Prepare two `LittleEndian` registers, initialized to the values
// in `numbers`.
let (x, y) = PrepareSummands(numbers, registers);
// Apply the add oracle. Note that the oracle expects two plain
// `Qubit[]` registers, so the `LittleEndian` variables `x`, `y`
// need to be unwrapped with the `!` operator.
adder(x!, y!);
// Measure the registers. Check that the addition was performed and
// the input register `x` has not been changed.
let (mx, my) = MeasureAndCheckAddResult(Snd(numbers), x, y);
EqualityFactI(mx, Fst(numbers), "x changed!");
}
// Now do two additions in superposition.
for _ in 1..5 {
use registers = (Qubit[width], Qubit[width]);
// Prepare x in the superposition $\ket{x} = \ket{123} + \ket{251}$.
let (x, y) = PrepareSummands(numbers, registers);
H(x![7]);
// Apply the add oracle.
adder(x!, y!);
// Measure the registers. Check that the addition was performed and
// the input register `x` has collapsed into either 123 or 251.
let (mx, my) = MeasureAndCheckAddResult(Snd(numbers), x, y);
Fact(mx == Fst(numbers) or mx == (Fst(numbers) + 2^7) % 2^width, "x changed!");
}
}
}