22import logging
33from copy import deepcopy as dp
44import random
5- import sys
65
76NONE = 0
87SINGLE_GATE = 1
1514ADD_MERGED_QUBITS_TO_DICT = 9
1615GIVE_STATEVECTOR = 10
1716DOUBLE_GATE = 11
17+ CONTROLLED_TWO_GATE = 12
1818
1919
2020class QubitThread (object ):
@@ -71,30 +71,36 @@ def give_statevector(self, channel):
7171 Sends the Qubit IDs and their state vectors over a channel.
7272
7373 Args:
74- channel(Queue): Channel to return the requested data to.
74+ channel (Queue): Channel to return the requested data to.
7575 """
7676 channel .put ((dp (self .qubits ), dp (self .qubit )))
7777
7878 def apply_controlled_gate (self , mat , q_id1 , q_id2 ):
7979 """
8080 Applies a controlled gate to q_id1
81+
82+ Args:
83+ mat (np.ndarray): The matrix to apply
84+ q_id1 (str): The target qubit id
85+ q_id2 (str): The control qubit id
8186 """
8287 first_mat = 1
8388 second_mat = 1
8489 nr1 = self .qubits .index (q_id1 )
8590 nr2 = self .qubits .index (q_id2 )
91+
8692 min_nr = min (nr1 , nr2 )
8793 max_nr = max (nr1 , nr2 )
88- if min_nr == nr1 :
89- # first_mat = mat
90- pass
94+
9195 total_amount = len (self .qubits )
9296 before = min_nr
9397 after = total_amount - max_nr - 1
9498 mid = total_amount - before - after - 2
99+
95100 if before > 0 :
96101 first_mat = np .eye (2 ** before )
97102 second_mat = np .eye (2 ** before )
103+
98104 # Apply first part of Matrix
99105 if min_nr == nr1 :
100106 first_mat = np .kron (first_mat , np .eye (2 ))
@@ -106,6 +112,7 @@ def apply_controlled_gate(self, mat, q_id1, q_id2):
106112 if mid > 0 :
107113 first_mat = np .kron (first_mat , np .eye (2 ** mid ))
108114 second_mat = np .kron (second_mat , np .eye (2 ** mid ))
115+
109116 # Apply second part of Matrix
110117 if min_nr == nr1 :
111118 first_mat = np .kron (first_mat , np .array ([[1 , 0 ], [0 , 0 ]]))
@@ -117,6 +124,7 @@ def apply_controlled_gate(self, mat, q_id1, q_id2):
117124 if after > 0 :
118125 first_mat = np .kron (first_mat , np .eye (2 ** after ))
119126 second_mat = np .kron (second_mat , np .eye (2 ** after ))
127+
120128 apply_mat = first_mat + second_mat
121129 self .qubit = np .dot (apply_mat , self .qubit )
122130
@@ -134,7 +142,7 @@ def merge_accept(self, channel):
134142 self .qubit = np .kron (self .qubit , vector )
135143 logging .debug ("Qubit Thread merged, new qubits are %r" , self .qubits )
136144
137- def merge_send (self , channel , chanel2 ):
145+ def merge_send (self , channel , channel2 ):
138146 """
139147 Send own process data to another process and suicide.
140148
@@ -145,20 +153,21 @@ def merge_send(self, channel, chanel2):
145153 """
146154 channel .put (dp (self .qubits ))
147155 channel .put (dp (self .qubit ))
148- chanel2 .put (dp (self .qubits ))
156+ channel2 .put (dp (self .qubits ))
149157 return
150158
151159 def swap_qubits (self , q_id1 , q_id2 ):
152160 """
153161 Swaps the position of qubit q_id1 with q_id2
154- in the statevector .
162+ in the state vector .
155163
156164 q_id1(String): Qubit id of one of the qubits to swap.
157165 q_id2(String): Qubit id of the other qubit to swap.
158166 """
159- def cnot (q_id1 , q_id2 ):
167+
168+ def cnot (_q_id1 , _q_id2 ):
160169 mat = np .asarray ([[0 , 1 ], [1 , 0 ]])
161- self .apply_controlled_gate (mat , q_id1 , q_id2 )
170+ self .apply_controlled_gate (mat , _q_id1 , _q_id2 )
162171
163172 # Check if they are the same ids
164173 if q_id1 == q_id2 :
@@ -173,9 +182,28 @@ def cnot(q_id1, q_id2):
173182 i2 = self .qubits .index (q_id2 )
174183 self .qubits [i1 ], self .qubits [i2 ] = self .qubits [i2 ], self .qubits [i1 ]
175184
185+ def apply_controlled_two_qubit_gate (self , mat , q_id1 , q_id2 , q_id3 ):
186+ """
187+ Applies a 3 qubit controlled gate
188+ Args:
189+ mat (np.ndarray): The 4x4 unitary gate to apply
190+ q_id1 (str): The control qubit
191+ q_id2 (str): A target qubit
192+ q_id3 (str): A target qubit
193+ """
194+ # Move the qubits to the correct position
195+ self .swap_qubits (q_id1 , self .qubits [0 ])
196+ self .swap_qubits (q_id2 , self .qubits [1 ])
197+ self .swap_qubits (q_id3 , self .qubits [2 ])
198+
199+ first_mat = np .block ([[np .eye (4 ), np .zeros ((4 , 4 ))], [np .zeros ((4 , 4 )), mat ]])
200+ total_mat = np .kron (first_mat , np .eye (2 ** (len (self .qubits ) - 3 )))
201+
202+ self .qubit = np .dot (total_mat , self .qubit )
203+
176204 def apply_two_qubit_gate (self , gate , q_id1 , q_id2 ):
177205 """
178- Applies a two qubit gate to the statevector .
206+ Applies a two qubit gate to the state vector .
179207
180208 Args:
181209 gate(np.ndarray): 4x4 unitary matrix
@@ -185,11 +213,12 @@ def apply_two_qubit_gate(self, gate, q_id1, q_id2):
185213 # Bring the qubits in the right order
186214 i2 = self .qubits .index (q_id2 )
187215 if i2 > 0 :
188- new_i1 = i2 - 1
216+ new_i1 = i2 - 1
189217 self .swap_qubits (q_id1 , self .qubits [new_i1 ])
190218 else :
191219 self .swap_qubits (q_id1 , self .qubits [0 ])
192220 self .swap_qubits (q_id2 , self .qubits [1 ])
221+
193222 apply_mat = gate
194223 nr1 = self .qubits .index (q_id1 )
195224 total_amount = len (self .qubits )
@@ -309,6 +338,8 @@ def run(self):
309338 self .apply_single_gate (item [1 ], item [2 ])
310339 elif item [0 ] == CONTROLLED_GATE :
311340 self .apply_controlled_gate (item [1 ], item [2 ], item [3 ])
341+ elif item [0 ] == CONTROLLED_TWO_GATE :
342+ self .apply_controlled_two_qubit_gate (item [1 ], item [2 ], item [3 ], item [4 ])
312343 elif item [0 ] == MEASURE :
313344 self .measure (item [1 ], item [2 ])
314345 # no qubit left, terminate
0 commit comments