-
Notifications
You must be signed in to change notification settings - Fork 31
/
Copy pathquantum.py
executable file
·100 lines (87 loc) · 3.43 KB
/
quantum.py
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
#!/usr/bin/env python
# encoding: utf-8
from cmath import exp, pi, sqrt
from random import random
class Psi:
def __init__(self, n_qubits):
"""
set up a quantum system with the given number of qubits
initialized to the "zero" qubit.
"""
self.n_qubits = n_qubits
# in this classical simulation, we use 2^n_qubits complex numbers
self.amplitudes = [0] * (1 << n_qubits)
self.amplitudes[0] = 1
def collapse(self):
"""
collapse the system (i.e. measure it) and return a tuple
of the bits.
"""
weights = [abs(amp) ** 2 for amp in self.amplitudes]
choice = random() * sum(weights)
for i, w in enumerate(weights):
choice -= w
if choice < 0:
self.amplitudes = [0] * (1 << self.n_qubits)
self.amplitudes[i] = 1
return tuple((i >> bit) % 2 for bit in range(self.n_qubits))
## gates
def pi_over_eight(self, qubit):
"""
applies a π/8 gate to the given qubit
"""
# has to be a valid qubit
if qubit > self.n_qubits:
raise ValueError()
# go through each amplitude
for i in range(1 << self.n_qubits):
# find out whether that amplitude corresponds to the qubit being
# zero or one
if (i >> qubit) % 2 == 0: # if zero
self.amplitudes[i] *= exp(-1j * pi / 8)
else: # if one
self.amplitudes[i] *= exp(1j * pi / 8)
def controlled_not(self, qubit1, qubit2):
"""
applies a controlled-not gate using the first given qubit as the
control of the permutation of the second.
"""
# the two quibits have to valid and different
if qubit1 > self.n_qubits or qubit2 > self.n_qubits or qubit1 == qubit2:
raise ValueError()
# make a copy of amplitudes as they update simultaneously
old_amplitudes = self.amplitudes[:]
# go through each amplitude
for i in range(1 << self.n_qubits):
# permutate qubit2 based on value of qubit1
self.amplitudes[i ^ (((i >> qubit1) % 2) << qubit2)] = old_amplitudes[i]
def hadamard(self, qubit):
"""
applies a Hadamard gate to the given qubit.
"""
# has to be a valid qubit
if qubit > self.n_qubits:
raise ValueError()
# make a copy of amplitudes as they update simultaneously
old_amplitudes = self.amplitudes[:]
# go through each amplitude
for i in range(1 << self.n_qubits):
# find out whether that amplitude corresponds to the qubit being
# zero or one
if (i >> qubit) % 2 == 0: # if zero
self.amplitudes[i] = (old_amplitudes[i] - old_amplitudes[i + (1 << qubit)]) / sqrt(2)
else: # if one
self.amplitudes[i] = (old_amplitudes[i - (1 << qubit)] - old_amplitudes[i]) / sqrt(2)
if __name__ == "__main__":
# set up a system with 3 qubits
psi = Psi(3)
# apply Hadamard gate to qubit 1 (second qubit)
psi.hadamard(1)
# apply Hadamard gate to qubit 2 (third qubit)
psi.hadamard(2)
# apply π/8 gate to qubit 1
psi.pi_over_eight(1)
# apply controlled-not gate with qubit 1 controlling qubit 0 (first qubit)
psi.controlled_not(1, 0)
# collapse and print the result (a tuple of 3 classical bits)
print(psi.collapse())