microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
billt/revert-mimalloc

Branches

Tags

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

Clone

HTTPS

Download ZIP

samples/algorithms/DeutschJozsa.qs

146lines · modecode

1/// # Sample
2/// Deutsch–Jozsa algorithm
3///
4/// # Description
5/// Deutsch–Jozsa is a quantum algorithm that determines whether a given Boolean
6/// function 𝑓 is constant (0 on all inputs or 1 on all inputs) or balanced
7/// (1 for exactly half of the input domain and 0 for the other half).
8///
9/// This Q# program implements the Deutsch–Jozsa algorithm.
10namespace Sample {
11 open Microsoft.Quantum.Diagnostics;
12 open Microsoft.Quantum.Math;
13 open Microsoft.Quantum.Measurement;
14
15 @EntryPoint()
16 operation Main() : (String, Bool)[] {
17 // A Boolean function is a function that maps bitstrings to a bit:
18 // 𝑓 : {0, 1}^n → {0, 1}.
19
20 // We say that 𝑓 is constant if 𝑓(𝑥⃗) = 𝑓(𝑦⃗) for all bitstrings 𝑥⃗ and
21 // 𝑦⃗, and that 𝑓 is balanced if 𝑓 evaluates to true for exactly half of
22 // its inputs.
23
24 // If we are given a function 𝑓 as a quantum operation 𝑈 |𝑥〉|𝑦〉 =
25 // |𝑥〉|𝑦 ⊕ 𝑓(𝑥)〉, and are promised that 𝑓 is either constant or is
26 // balanced, then the Deutsch–Jozsa algorithm decides between these
27 // cases with a single application of 𝑈.
28
29 // Here, we demonstrate the use of the Deutsch-Jozsa algorithm by
30 // determining the type (constant or balanced) of various functions.
31 let nameFunctionTypeTuples = [
32 ("SimpleConstantBoolF", SimpleConstantBoolF, true),
33 ("SimpleBalancedBoolF", SimpleBalancedBoolF, false),
34 ("ConstantBoolF", ConstantBoolF, true),
35 ("BalancedBoolF", BalancedBoolF, false)
36 ];
37
38 mutable results = [];
39 for (name, fn, shouldBeConstant) in nameFunctionTypeTuples {
40 let isConstant = DeutschJozsa(fn, 5);
41 if (isConstant != shouldBeConstant) {
42 let shouldBeConstantStr = shouldBeConstant ?
43 "constant" |
44 "balanced";
45 fail $"{name} should be detected as {shouldBeConstantStr}";
46 }
47
48 let isConstantStr = isConstant ? "constant" | "balanced";
49 Message($"{name} is {isConstantStr}");
50 set results += [(name, isConstant)];
51 }
52
53 return results;
54 }
55
56 /// # Summary
57 /// This operation implements the DeutschJozsa algorithm.
58 /// It returns the Boolean value `true` if the function is constant and
59 /// `false` if it is not.
60 /// It is assumed that the function is either constant or balanced.
61 ///
62 /// # Input
63 /// ## Uf
64 /// A quantum operation that implements |𝑥〉|𝑦〉 ↦ |𝑥〉|𝑦 ⊕ 𝑓(𝑥)〉, where 𝑓 is a
65 /// Boolean function, 𝑥 is an 𝑛 bit register and 𝑦 is a single qubit.
66 /// ## n
67 /// The number of bits in the input register |𝑥〉.
68 ///
69 /// # Output
70 /// A boolean value `true` that indicates that the function is constant and
71 /// `false` that indicates that the function is balanced.
72 ///
73 /// # See Also
74 /// - For details see Section 1.4.3 of Nielsen & Chuang.
75 ///
76 /// # References
77 /// - [ *Michael A. Nielsen , Isaac L. Chuang*,
78 /// Quantum Computation and Quantum Information ]
79 /// (http://doi.org/10.1017/CBO9780511976667)
80 operation DeutschJozsa(Uf : ((Qubit[], Qubit) => Unit), n : Int) : Bool {
81 // We allocate n + 1 clean qubits. Note that the function `Uf` is defined
82 // on inputs of the form (x, y), where x has n bits and y has 1 bit.
83 use queryRegister = Qubit[n];
84 use target = Qubit();
85
86 // The last qubit needs to be flipped so that the function will actually
87 // be computed into the phase when Uf is applied.
88 X(target);
89
90 // Now, a Hadamard transform is applied to each of the qubits.
91 H(target);
92 // We use a within-apply block to ensure that the Hadamard transform is
93 // correctly inverted on the |𝑥〉 register.
94 within {
95 for q in queryRegister {
96 H(q);
97 }
98 } apply {
99 // We apply Uf to the n+1 qubits, computing |𝑥, 𝑦〉 ↦ |𝑥, 𝑦 ⊕ 𝑓(𝑥)〉.
100 Uf(queryRegister, target);
101 }
102
103 // The following for-loop measures all qubits and resets them to the |0〉
104 // state so that they can be safely deallocated at the end of the block.
105 // The loop also sets `result` to `true` if all measurement results are
106 // `Zero`, i.e. if the function is a constant function, and sets
107 // `result` to `false` if not, which according to the assumption on 𝑓
108 // means that it must be balanced.
109 mutable result = true;
110 for q in queryRegister {
111 if MResetZ(q) == One {
112 set result = false;
113 }
114 }
115
116 // Finally, the last qubit, which held the 𝑦-register, is reset.
117 Reset(target);
118 return result;
119 }
120
121 // Simple constant Boolean function
122 operation SimpleConstantBoolF(args : Qubit[], target : Qubit) : Unit {
123 X(target);
124 }
125
126 // Simple balanced Boolean function
127 operation SimpleBalancedBoolF(args : Qubit[], target : Qubit) : Unit {
128 CX(args[0], target);
129 }
130
131 // A more complex constant Boolean function.
132 // It applies X to every input basis vector.
133 operation ConstantBoolF(args : Qubit[], target : Qubit) : Unit {
134 for i in 0..(2^Length(args))-1 {
135 ApplyControlledOnInt(i, X, args, target);
136 }
137 }
138
139 // A more complex balanced Boolean function.
140 // It applies X to half of the input basis vectors.
141 operation BalancedBoolF(args : Qubit[], target : Qubit) : Unit {
142 for i in 0..2..(2^Length(args))-1 {
143 ApplyControlledOnInt(i, X, args, target);
144 }
145 }
146}
147