-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathBell.qs
115 lines (102 loc) · 5.95 KB
/
Bell.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
// File name: Bell.qs
// Source: https://docs.microsoft.com/en-us/quantum/quantum-writeaquantumprogram?view=qsharp-preview&tabs=tabid-vscode
// Written and Edited by: Anton Karazeev <[email protected]>
//
// This file is part of Quantum Computing Seminars project (https://github.com/RQC-QApp/Seminars)
namespace Bell
{
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Primitive;
// Создание операции `Set` со следующей сигнатурой:
// * `desired` - первый аргумент типа `Result`,
// * `q1` - второй аргумент типа `Qubit`.
//
// Метод ничего не возвращает - следовательно после `:` стоят
// пустые скобки (аналог `void` в С/С++).
operation Set (desired: Result, q1: Qubit) : ()
{
body
{
// Объявление immutable-переменной `current`,
// которая инициализируется измеренным значением
// кубита `q1` (т.е. Zero или One).
let current = M(q1);
// Если измеренное состояние не совпадает с заданным
// ранее, то флипаем (меняем на противоположное значение: |0>
// -> |1>, |1> -> |0>) кубит `q1`.
if (desired != current)
{
// Применение X-гейта (операции NOT) к кубиту `q1`.
X(q1);
}
}
}
// Аргументами выступают количество экспериментов `count` и начальное
// состояние кубита `initial`.
//
// Метод возвращает кортеж (tuple) из трёх целых чисел.
operation BellTest (count: Int, initial: Result) : (Int, Int, Int)
{
body
{
// Значения этих переменных можно изменять с помощью
// метода `set`.
//
// Количество испытаний, в которых измерение нулевого кубита
// дало единицу (|1>).
mutable numOnes = 0;
// Число измерений, в которых состояния кубитов совпадают.
// Под такими состояниями понимаются |00> и |11> (в нашем двухкубитном случае).
mutable agree = 0;
// Объявление массива из двух элементов типа `Qubit`.
// После выхода из блока `using` - память, выделенная под массив,
// освобождается.
using (qubits = Qubit[2])
{
// Цикл `for` - итерирование по значениям от 1 до `count`
// переменной `test`.
for (test in 1..count)
{
// Используем написанную ранее операцию `Set` для
// инициализации кубитов заданными значениями.
Set(initial, qubits[0]);
Set(Zero, qubits[1]);
// Применение гейта Адамара к нулевому кубиту.
H(qubits[0]);
// Применение управляющего отрицания к нулевому и первому
// гейтам.
//
// Как раз с помощью этого гейта мы можем сделать запутанность
// (entaglement) между нулевым и первым кубитами.
//
// v-- управляющий v-- таргет.
CNOT(qubits[0], qubits[1]);
// Проводим измерение нулевого кубита.
let res = M(qubits[0]);
// Если получили единицу, то увеличиваем счётчик единиц
// на один.
if (res == One)
{
set numOnes = numOnes + 1;
}
// Если измеренное состояние первого кубита совпадает с
// измеренным состояние нулевого кубита, то увеличиваем
// счётчик измерений с одинаковыми состояниями на один.
if (M(qubits[1]) == res)
{
set agree = agree + 1;
}
}
// Сбрасываем состояния кубитов.
// Это можно сделать и через цикл по `i` для `qubits[i]`.
Set(Zero, qubits[0]);
Set(Zero, qubits[1]);
}
// Возвращаем кортеж (tuple) из:
// * количество испытаний с результатом |0> для нулевого кубита,
// * количество испытаний с результатом |1> для нулевого кубита,
// * количество испытаний с одинаковыми результатами для нулевого и первого кубитов.
return (count - numOnes, numOnes, agree);
}
}
}