-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSingle_Qubit_Mapping.py
More file actions
227 lines (188 loc) · 7 KB
/
Single_Qubit_Mapping.py
File metadata and controls
227 lines (188 loc) · 7 KB
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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
"""
Code to visualize the affect of random unitaries composed of fundamental
gate sets on different initial states, with the goal of understanding
universality, and magic states/gates.
Code Written by Andrew Projansky
and Joseph Gibson
Project Start Date: 7/18/2022
"""
import numpy as np
import matplotlib.pyplot as plt
import random
"""
Defines all gates used
"""
H = np.array([[1 / np.sqrt(2), 1 / np.sqrt(2)], [1 / np.sqrt(2), -1 / np.sqrt(2)]])
S = np.array([[1, 0], [0, 1j]])
Z = np.array([[1, 0], [0, -1]])
X = np.array([[0, 1], [1, 0]])
Y = np.array([[0, -1j], [1j, 0]])
T = np.array([[np.exp(-1j * np.pi / 8), 0], [0, np.exp(1j * np.pi / 8)]])
univ_rot = np.matmul(T, np.matmul(H, np.matmul(T, H)))
"""
Defines the dictionaries of different gate sets: currently,
the hadamard, the one dimensional clifford group, the hadamard and t gate,
the one dimensional clifford plus T, and the clifford plus the pauli matrices
currently for testing we have a gate set that is just a single matrix,
THTH - the irrational rotation
"""
C0 = {1: H}
C1 = {1: H, 2: S}
C2 = {1: H, 2: T}
C3 = {1: H, 2: S, 3: T}
CP1 = {1: H, 2: S, 3: Z, 4: X, 5: Y, 6: T}
test = {1: univ_rot}
"""
Circuit_Run: class for defining a trial
gate_num: number of gates to be randomly chosen
gate_set: set of gates to be randomly chosen from
state: inital state
runs: number of data points for given number of gates and inital state
"""
#%%
class Experiment:
"""
Parameters
----------
gate_set : dict, optional
set of gates to use. The default is CP2.
num_steps : int, optional
total number of gates. The default is 1.
num_sites : int, optional
number of independent state positions. The default is None.
init_states : list, optional
initial position. The default is None.
gate_list : list, optional
List of gates to be applied, if not suppplied will generate random
gates from gate set. The default is None.
Attributes
----------
angles : list
angles from states Used for plotting
"""
def __init__(
self,
gate_set: dict = C2,
num_steps: int = 1,
num_sites: int = None,
init_states: list = None,
gate_list: list = None,
):
self.num_steps = num_steps
self.gate_set = gate_set
if num_sites == None and init_states == None:
self.states = [np.array([0, 1])]
self.num_sites = 1
elif init_states == None:
"""TODO make random init positions"""
self.states = [np.array([0, 1]) for x in range(num_sites)]
self.num_sites = num_sites
elif num_sites == None:
self.states = [np.array(x) for x in init_states]
self.num_sites = len(init_states)
if gate_list == None:
self.gate_list = self.__gen_gate_list()
else:
self.num_steps = len(gate_list)
self.gate_list = gate_list
# self.gate_list.insert(0, np.identity(2))
self.angles = []
# self.final_unitary = self.__gen_final_unitary()
def __gen_gate_list(self):
vals = list(self.gate_set.values())
return [random.choice(vals) for x in range(self.num_steps)]
################# run functions ##################################
def run_stepwise(self):
self.intermediate_states = self.__gen_intermediate_states()
self.angles = self.__gen_angles()
def run_multiple(self, num_runs: int):
self.angles = [[self.__get_angle(state)] for state in self.states]
for i in range(num_runs):
self.gate_list = self.__gen_gate_list()
self.final_unitary = self.__gen_final_unitary()
f_state = self.__gen_final_state()
new_angles = [self.__get_angle(state) for state in f_state]
for i in range(self.num_sites):
self.angles[i].append(new_angles[i])
def __gen_intermediate_states(self):
inter_gate_list = self.gen_intermediate_unitaries()
return [[np.matmul(y, x) for y in inter_gate_list] for x in self.states]
def gen_intermediate_unitaries(self):
unitary_arr = [np.identity(2)]
for i in range(1, self.num_steps):
unitary_arr.append(np.matmul(unitary_arr[i - 1], self.gate_list[i]))
return unitary_arr
def __gen_final_unitary(self):
"""
performs matrix mutiplication to compose total unitary
from multiplcation of randomly selected gates
varibials-
"""
gate_step_i = self.gate_list[0]
for i in range(1, self.num_steps):
gate_step_j = self.gate_list[i]
gate_step_i = np.matmul(gate_step_j, gate_step_i)
return gate_step_i
def __gen_final_state(self):
return [np.matmul(self.final_unitary, x) for x in self.states]
def __gen_angles(self):
return [
[self.__get_angle(state) for state in x] for x in self.intermediate_states
]
def __get_angle(self, state):
"""
get an angle for a single state
"""
first_mag = np.sqrt(np.real(state[0]) ** 2 + np.imag(state[0]) ** 2)
second_mag = np.sqrt(np.real(state[1]) ** 2 + np.imag(state[1]) ** 2)
first_phi = np.arctan2(np.imag(state[0]), np.real(state[0]))
second_phi = np.arctan2(np.imag(state[1]), np.real(state[1]))
phi = second_phi - first_phi
theta = 2 * np.arccos(np.real(state[0] * np.exp(-1j * first_phi)))
return [theta, phi]
##############plot functions ########################
def plot(self):
states_xyz = [self.__gen_xyz_points(x) for x in self.angles]
print(np.shape(states_xyz))
fig = plt.figure()
ax = fig.add_subplot(projection="3d")
u, v = np.mgrid[0 : 2 * np.pi : 50j, 0 : np.pi : 50j]
xs = np.cos(u) * np.sin(v)
ys = np.sin(u) * np.sin(v)
zs = np.cos(v)
ax.plot_surface(xs, ys, zs, color="lightgrey", alpha=0.3)
for x in states_xyz:
ax.scatter(x[0], x[1], x[2], marker="o", alpha=0.9)
# ax.scatter(xin, yin, zin, marker="o", color="red")
plt.show()
def __gen_xyz_points(self, angle_arr):
"""
Parameters
----------
angle_arr : list
list of the form [[theta1,phi1],[theta2,phi2] ...].
"""
x = np.array([])
y = np.array([])
z = np.array([])
for i in angle_arr:
x = np.append(x, self.__get_x(i[0], i[1]))
y = np.append(y, self.__get_y(i[0], i[1]))
z = np.append(z, self.__get_z(i[0], i[1]))
return x, y, z
def __get_x(self, theta, phi):
return np.cos(phi) * np.sin(theta)
def __get_y(self, theta, phi):
return np.sin(phi) * np.sin(theta)
def __get_z(self, theta, phi):
return np.cos(theta)
#%%
n = np.sqrt(1 / 2)
init_state = [[1, 0], [0, 1], [n, n]]
exp = Experiment(init_states=init_state, num_steps=500)
exp.run_stepwise()
exp.plot()
#%%
exp = Experiment(num_steps=100)
exp.run_multiple(num_runs=500)
exp.plot()