1+ import numpy as np
2+
3+ class One_qubit :
4+ def __init__ (self ):
5+ self .state = np .zeros (2 , dtype = np .complex_ )
6+ self .I = np .eye (2 )
7+ self .Z = np .array ([[1 , 0 ], [0 , - 1 ]])
8+ self .X = np .array ([[0 , 1 ], [1 , 0 ]])
9+ self .Y = np .array ([[0 , - 1j ], [1j , 0 ]])
10+ self .H = np .array ([[1 , 1 ], [1 , - 1 ]]) / np .sqrt (2 )
11+ self .S = np .array ([[1 , 0 ], [0 , 1j ]])
12+
13+ def set_state (self , state ):
14+ if abs (np .linalg .norm (state ) - 1 ) > 1e-10 :
15+ raise ValueError ("The state vector must be normalized." )
16+ self .state = state
17+
18+ def apply_hadamard (self ):
19+ self .state = np .dot (self .H , self .state )
20+ return self .state
21+
22+ def apply_x (self ):
23+ self .state = np .dot (self .X , self .state )
24+ return self .state
25+
26+ def apply_y (self ):
27+ self .state = np .dot (self .Y , self .state )
28+ return self .state
29+
30+ def apply_z (self ):
31+ self .state = np .dot (self .Z , self .state )
32+ return self .state
33+
34+ def measure (self , num_shots = 1 ):
35+ prob = np .abs (self .state )** 2
36+ possible = np .arange (len (self .state )) #possible measurement outcomes
37+ outcome = np .random .choice (possible , p = prob , size = num_shots ) #measurement outcome
38+ self .state = np .zeros_like (self .state ) #set state to the measurement outcome
39+ self .state [outcome [- 1 ]] = 1
40+ return outcome
41+
42+ def rotate_x (self , theta ):
43+ # implement rotation around x axis
44+ Rx = np .cos (theta / 2 ) * self .I - 1j * np .sin (theta / 2 ) * self .X
45+ self .state = np .dot (Rx , self .state )
46+
47+ def rotate_y (self , phi ):
48+ # implement rotation around y axis
49+ Ry = np .cos (phi / 2 ) * self .I - 1j * np .sin (phi / 2 ) * self .Y
50+ self .state = np .dot (Ry , self .state )
51+
52+ class Two_qubit (One_qubit ):
53+ def __init__ (self ):
54+ super ().__init__ ()
55+ self .state = np .zeros (4 , dtype = np .complex_ )
56+ self .CNOT01 = np .array ([[1 , 0 , 0 , 0 ], [0 , 1 , 0 , 0 ], [0 , 0 , 0 , 1 ], [0 , 0 , 1 , 0 ]])
57+ self .CNOT10 = np .array ([[1 , 0 , 0 , 0 ], [0 , 0 , 0 , 1 ], [0 , 0 , 1 , 0 ], [0 , 1 , 0 , 0 ]])
58+ self .SWAP = np .array ([[1 , 0 , 0 , 0 ], [0 , 0 , 1 , 0 ], [0 , 1 , 0 , 0 ], [0 , 0 , 0 , 1 ]])
59+
60+ # np.random.seed(0)
61+
62+ def apply_cnot01 (self ):
63+ self .state = np .dot (self .CNOT01 , self .state )
64+ return self .state
65+
66+ def apply_cnot10 (self ):
67+ self .state = np .dot (self .CNOT10 , self .state )
68+ return self .state
69+
70+ def apply_swap (self ):
71+ self .state = np .dot (self .SWAP , self .state )
72+ return self .state
73+
74+ def apply_hadamard (self , qubit ):
75+ if qubit == 0 :
76+ self .state = np .kron (self .H , self .I ).dot (self .state )
77+ elif qubit == 1 :
78+ self .state = np .kron (self .I , self .H ).dot (self .state )
79+ return self .state
80+
81+ def apply_sdag (self , qubit ):
82+ if qubit == 0 :
83+ self .state = np .kron (self .S .conj ().T , self .I ).dot (self .state )
84+ elif qubit == 1 :
85+ self .state = np .kron (self .I , self .S .conj ().T ).dot (self .state )
86+ return self .state
87+
88+ def apply_x (self , qubit ):
89+ if qubit == 0 :
90+ self .state = np .kron (self .X , self .I ).dot (self .state )
91+ elif qubit == 1 :
92+ self .state = np .kron (self .I , self .X ).dot (self .state )
93+ return self .state
94+
95+ def apply_y (self , qubit ):
96+ if qubit == 0 :
97+ self .state = np .kron (self .Y , self .I ).dot (self .state )
98+ elif qubit == 1 :
99+ self .state = np .kron (self .I , self .Y ).dot (self .state )
100+ return self .state
101+
102+ def apply_z (self , qubit ):
103+ if qubit == 0 :
104+ self .state = np .kron (self .Z , self .I ).dot (self .state )
105+ elif qubit == 1 :
106+ self .state = np .kron (self .I , self .Z ).dot (self .state )
107+ return self .state
108+
109+ def rotate_x (self , theta , qubit ):
110+ Rx = np .cos (theta / 2 ) * self .I - 1j * np .sin (theta / 2 ) * self .X
111+ if qubit == 0 :
112+ self .state = np .kron (Rx , self .I ).dot (self .state )
113+ elif qubit == 1 :
114+ self .state = np .kron (self .I , Rx ).dot (self .state )
115+ return self .state
116+
117+ def rotate_y (self , phi , qubit ):
118+ # implement rotation around y axis
119+ Ry = np .cos (phi / 2 ) * self .I - 1j * np .sin (phi / 2 ) * self .Y
120+ if qubit == 0 :
121+ self .state = np .kron (Ry , self .I ).dot (self .state )
122+ elif qubit == 1 :
123+ self .state = np .kron (self .I , Ry ).dot (self .state )
124+ return self .state
125+
126+ class Four_qubit (Two_qubit ):
127+ #This is based on the two qubit class since the Lipkin model at most acts on two qubits at the time
128+ def __init__ (self ):
129+ super ().__init__ ()
130+ self .state = np .zeros (16 , dtype = np .complex_ )
131+
132+ def apply_cnot10 (self , qubit1 ):
133+ # can only be applied for adjecent qubits
134+ if qubit1 == 0 :
135+ op = np .kron (self .CNOT10 , np .kron (self .I , self .I ))
136+ return np .dot (op , self .state )
137+ elif qubit1 == 1 :
138+ op = np .kron (self .I , np .kron (self .CNOT10 , self .I ))
139+ return np .dot (op , self .state )
140+ elif qubit1 == 2 :
141+ op = np .kron (self .I , np .kron (self .I , self .CNOT10 ))
142+ return np .dot (op , self .state )
143+ else :
144+ print ('qubit1 must be 0, 1, or 2' )
145+
146+ def apply_cnot01 (self , qubit1 ):
147+ # can only be applied for adjecent qubits
148+ if qubit1 == 0 :
149+ op = np .kron (self .CNOT01 , np .kron (self .I , self .I ))
150+ return np .dot (op , self .state )
151+ elif qubit1 == 1 :
152+ op = np .kron (self .I , np .kron (self .CNOT01 , self .I ))
153+ return np .dot (op , self .state )
154+ elif qubit1 == 2 :
155+ op = np .kron (self .I , np .kron (self .I , self .CNOT01 ))
156+ return np .dot (op , self .state )
157+ else :
158+ print ('qubit1 must be 0, 1, or 2' )
159+
160+ def apply_swap (self , qubit1 ):
161+ # can only be applied for adjecent qubits
162+ if qubit1 == 0 :
163+ op = np .kron (self .SWAP , np .kron (self .I , self .I ))
164+ return np .dot (op , self .state )
165+ elif qubit1 == 1 :
166+ op = np .kron (self .I , np .kron (self .SWAP , self .I ))
167+ return np .dot (op , self .state )
168+ elif qubit1 == 2 :
169+ op = np .kron (self .I , np .kron (self .I , self .SWAP ))
170+ return np .dot (op , self .state )
171+ else :
172+ print ('qubit1 must be 0, 1, or 2' )
173+
174+ def apply_hadamard (self , qubit ):
175+ if qubit == 0 :
176+ self .state = np .kron (self .H , np .kron (self .I , np .kron (self .I , self .I ))).dot (self .state )
177+ elif qubit == 1 :
178+ self .state = np .kron (self .I , np .kron (self .H , np .kron (self .I , self .I ))).dot (self .state )
179+ elif qubit == 2 :
180+ self .state = np .kron (self .I , np .kron (self .I , np .kron (self .H , self .I ))).dot (self .state )
181+ elif qubit == 3 :
182+ self .state = np .kron (self .I , np .kron (self .I , np .kron (self .I , self .H ))).dot (self .state )
183+ return self .state
184+
185+ def apply_sdag (self , qubit ):
186+ if qubit == 0 :
187+ self .state = np .kron (self .S .conj ().T , np .kron (self .I , np .kron (self .I , self .I ))).dot (self .state )
188+ elif qubit == 1 :
189+ self .state = np .kron (self .I , np .kron (self .S .conj ().T , np .kron (self .I , self .I ))).dot (self .state )
190+ elif qubit == 2 :
191+ self .state = np .kron (self .I , np .kron (self .I , np .kron (self .S .conj ().T , self .I ))).dot (self .state )
192+ elif qubit == 3 :
193+ self .state = np .kron (self .I , np .kron (self .I , np .kron (self .I , self .S .conj ().T ))).dot (self .state )
194+ return self .state
0 commit comments