Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
qgd_Circuit.py
Go to the documentation of this file.
1 
3 """
4 Created on Tue Jun 30 15:44:26 2020
5 Copyright 2020 Peter Rakyta, Ph.D.
6 
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10 
11  http://www.apache.org/licenses/LICENSE-2.0
12 
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see http://www.gnu.org/licenses/.
21 
22 @author: Peter Rakyta, Ph.D.
23 """
24 
25 
27 
28 
29 import numpy as np
30 from os import path
31 from squander.gates.qgd_Circuit_Wrapper import qgd_Circuit_Wrapper
32 
33 
34 from squander.gates.gates_Wrapper import (
35  U1,
36  U2,
37  U3,
38  H,
39  X,
40  Y,
41  Z,
42  T,
43  Tdg,
44  CH,
45  CNOT,
46  CZ,
47  R,
48  RX,
49  RY,
50  RZ,
51  SX,
52  SYC,
53  CRY,
54  CR,
55  CROT )
56 
57 
58 
60 class qgd_Circuit(qgd_Circuit_Wrapper):
61 
62 
63 
67 
68  def __init__( self, qbit_num ):
69 
70  # call the constructor of the wrapper class
71  super().__init__( qbit_num )
72 
73  """
74  def __getstate__(self):
75  # Return a dictionary of the object's state
76 
77  return super().__getstate__()
78 
79  def __setstate__(self, state):
80 
81  print( state )
82  super().__setstate__( state )
83 
84 
85  def __new__(cls, *args, **kwargs):
86 
87  print( "NEEEEEEEEEEEEEW", args)
88  return super().__new__(cls, *args, **kwargs)
89  """
90 
91 #@brief Call to add a U1 gate to the front of the gate structure.
92 #@param self A pointer pointing to an instance of the class qgd_Circuit.
93 #@param Input argument: target_qbit (int)
94 
95  def add_U1( self, target_qbit):
96 
97  # call the C wrapper function
98  super().add_U1(target_qbit)
99 
100 #@brief Call to add a U2 gate to the front of the gate structure.
101 #@param self A pointer pointing to an instance of the class qgd_Circuit.
102 #@param Input argument: target_qbit (int)
103 
104  def add_U2( self, target_qbit):
105 
106  # call the C wrapper function
107  super().add_U2(target_qbit)
108 
109 #@brief Call to add a U3 gate to the front of the gate structure.
110 #@param self A pointer pointing to an instance of the class qgd_Circuit.
111 #@param Input argument: target_qbit (int)
112 
113  def add_U3( self, target_qbit):
114 
115  # call the C wrapper function
116  super().add_U3(target_qbit)
117 
118 #@brief Call to add a RX gate to the front of the gate structure.
119 #@param self A pointer pointing to an instance of the class qgd_Circuit.
120 #@param Input arguments: target_qbit (int).
121 
122  def add_RX( self, target_qbit):
123 
124  # call the C wrapper function
125  super().add_RX(target_qbit)
126 
127 #@brief Call to add a R gate to the front of the gate structure.
128 #@param self A pointer pointing to an instance of the class qgd_Circuit.
129 #@param Input arguments: target_qbit (int).
130  def add_R( self, target_qbit):
131 
132  # call the C wrapper function
133  super().add_R(target_qbit)
134 
135 #@brief Call to add a RY gate to the front of the gate structure.
136 #@param self A pointer pointing to an instance of the class qgd_Circuit.
137 #@param Input arguments: target_qbit (int).
138 
139  def add_RY( self, target_qbit):
140 
141  # call the C wrapper function
142  super().add_RY(target_qbit)
143 
144 #@brief Call to add a RZ gate to the front of the gate structure.
145 #@param self A pointer pointing to an instance of the class qgd_Circuit.
146 #@param Input arguments: target_qbit (int).
147 
148  def add_RZ( self, target_qbit):
149 
150  # call the C wrapper function
151  super().add_RZ(target_qbit)
152 
153 #@brief Call to add a CNOT gate to the front of the gate structure.
154 #@param self A pointer pointing to an instance of the class qgd_Circuit.
155 #@param Input arguments: target_qbit (int), control_qbit (int).
156 
157  def add_CNOT( self, target_qbit, control_qbit):
158 
159  # call the C wrapper function
160  super().add_CNOT(target_qbit, control_qbit)
161 
162 #@brief Call to add a CZ gate to the front of the gate structure.
163 #@param self A pointer pointing to an instance of the class qgd_Circuit.
164 #@param Input arguments: target_qbit (int), control_qbit (int).
165 
166  def add_CZ( self, target_qbit, control_qbit):
167 
168  # call the C wrapper function
169  super().add_CZ(target_qbit, control_qbit)
170 
171 #@brief Call to add a CH gate to the front of the gate structure.
172 #@param self A pointer pointing to an instance of the class qgd_Circuit.
173 #@param Input arguments: target_qbit (int), control_qbit (int).
174 
175  def add_CH( self, target_qbit, control_qbit):
176 
177  # call the C wrapper function
178  super().add_CH(target_qbit, control_qbit)
179 
180 #@brief Call to add a SYC gate to the front of the gate structure.
181 #@param self A pointer pointing to an instance of the class qgd_Circuit.
182 #@param Input arguments: target_qbit (int), control_qbit (int).
183 
184  def add_SYC( self, target_qbit, control_qbit):
185 
186  # call the C wrapper function
187  super().add_SYC(target_qbit, control_qbit)
188 
189 
190 #@brief Call to add a Hadamard gate to the front of the gate structure.
191 #@param self A pointer pointing to an instance of the class qgd_Circuit.
192 #@param Input arguments: target_qbit (int)
193 
194  def add_H( self, target_qbit):
195 
196  # call the C wrapper function
197  super().add_H(target_qbit)
198 
199 #@brief Call to add a X gate to the front of the gate structure.
200 #@param self A pointer pointing to an instance of the class qgd_Circuit.
201 #@param Input arguments: target_qbit (int)
202 
203  def add_X( self, target_qbit):
204 
205  # call the C wrapper function
206  super().add_X(target_qbit)
207 
208 #@brief Call to add a Y gate to the front of the gate structure.
209 #@param self A pointer pointing to an instance of the class qgd_Circuit.
210 #@param Input arguments: target_qbit (int).
211 
212  def add_Y( self, target_qbit):
213 
214  # call the C wrapper function
215  super().add_Y(target_qbit)
216 
217 #@brief Call to add a Z gate to the front of the gate structure.
218 #@param self A pointer pointing to an instance of the class qgd_Circuit.
219 #@param Input arguments: target_qbit (int).
220 
221  def add_Z( self, target_qbit):
222 
223  # call the C wrapper function
224  super().add_Z(target_qbit)
225 
226 #@brief Call to add a SX gate to the front of the gate structure.
227 #@param self A pointer pointing to an instance of the class qgd_Circuit.
228 #@param Input arguments: target_qbit (int).
229 
230  def add_SX( self, target_qbit):
231 
232  # call the C wrapper function
233  super().add_SX(target_qbit)
234 
235 #@brief Call to add a T gate to the front of the gate structure.
236 #@param self A pointer pointing to an instance of the class qgd_Circuit.
237 #@param Input arguments: target_qbit (int).
238 
239  def add_T( self, target_qbit):
240 
241  # call the C wrapper function
242  super().add_T(target_qbit)
243 
244 #@brief Call to add a T gate to the front of the gate structure.
245 #@param self A pointer pointing to an instance of the class qgd_Circuit.
246 #@param Input arguments: target_qbit (int).
247 
248  def add_Tdg( self, target_qbit):
249 
250  # call the C wrapper function
251  super().add_Tdg(target_qbit)
252 
253 #@brief Call to add adaptive gate to the front of the gate structure.
254 #@param self A pointer pointing to an instance of the class qgd_Circuit.
255 #@param Input arguments: target_qbit (int), control_qbit (int).
256 
257  def add_adaptive( self, target_qbit, control_qbit):
258 
259  # call the C wrapper function
260  super().add_adaptive(target_qbit, control_qbit)
261 
262 #@brief Call to add a CROT gate to the front of the gate structure.
263 #@param self A pointer pointing to an instance of the class qgd_Circuit.
264 #@param Input arguments: target_qbit (int).
265 
266  def add_CROT( self, target_qbit, control_qbit):
267 
268  # call the C wrapper function
269  super(qgd_Circuit, self).add_CROT(target_qbit, control_qbit)
270 
271 #@brief Call to add a CR gate to the front of the gate structure.
272 #@param self A pointer pointing to an instance of the class qgd_Circuit.
273 #@param Input arguments: target_qbit (int), control_qbit (int).
274 
275  def add_CR( self, target_qbit, control_qbit):
276 
277  # call the C wrapper function
278  super(qgd_Circuit, self).add_CR(target_qbit, control_qbit)
279 
280 #@brief Call to add adaptive gate to the front of the gate structure.
281 #@param self A pointer pointing to an instance of the class qgd_Circuit.
282 #@param Input arguments: target_qbit (int), control_qbit (int).
283 
284  def add_Circuit( self, gate):
285 
286  # call the C wrapper function
287  super().add_Circuit(gate)
288 
289 #@brief Call to retrieve the matrix of the operation.
290 #@param self A pointer pointing to an instance of the class qgd_Circuit.
291 #@param Input arguments: parameters_mtx.
292 
293  def get_Matrix( self, parameters_mtx):
294 
295  # call the C wrapper function
296  return super().get_Matrix(parameters_mtx)
297 
298 
299 #@brief Call to get the parameters of the matrices.
300 #@param self A pointer pointing to an instance of the class qgd_Circuit.
301 
302  def get_Parameter_Num( self):
303 
304  # call the C wrapper function
305  return super().get_Parameter_Num()
306 
307 
308 
309 #@brief Call to apply the gate operation on the input matrix
310 #@param Input arguments: parameters_mtx, unitary_mtx.
311  def apply_to( self, parameters_mtx, unitary_mtx, parallel=1):
312 
313  # call the C wrapper function
314  super().apply_to( parameters_mtx, unitary_mtx, parallel=parallel )
315 
316 
317 
318 
324  def get_Second_Renyi_Entropy(self, parameters=None, input_state=None, qubit_list=None ):
325 
326  # validate input parameters
327 
328  qbit_num = self.get_Qbit_Num()
329 
330  qubit_list_validated = list()
331  if isinstance(qubit_list, list) or isinstance(qubit_list, tuple):
332  for item in qubit_list:
333  if isinstance(item, int):
334  qubit_list_validated.append(item)
335  qubit_list_validated = list(set(qubit_list_validated))
336  else:
337  print("Elements of qbit_list should be integers")
338  return
339  elif qubit_list == None:
340  qubit_list_validated = [ x for x in range(qbit_num) ]
341 
342  else:
343  print("Elements of qbit_list should be integers")
344  return
345 
346 
347  if parameters is None:
348  print( "get_Second_Renyi_entropy: array of input parameters is None")
349  return None
350 
351 
352  if input_state is None:
353  matrix_size = 1 << qbit_num
354  input_state = np.zeros( (matrix_size,1), dtype=np.complex128 )
355  input_state[0] = 1
356 
357  # evaluate the entropy
358  entropy = super().get_Second_Renyi_Entropy( parameters, input_state, qubit_list_validated)
359 
360 
361  return entropy
362 
363 
364 
365 
368  def get_Qbit_Num(self):
369 
370  return super().get_Qbit_Num()
371 
372 
373 
376  def get_Qbits(self):
377 
378  return super().get_Qbits()
379 
380 
381 
384  def get_Gates(self):
385 
386  return super().get_Gates()
387 
388 
389 
392  def get_Gate_Nums(self):
393 
394  return super().get_Gate_Nums()
395 
396 
397 
402  def Remap_Qbits(self, qbit_map, qbit_num=None):
403 
404  if qbit_num == None:
405  qbit_num = self.get_Qbit_Num()
406 
407 
408  return super().Remap_Qbits( qbit_map, qbit_num)
409 
410 
411 
412 
413 #@brief Call to get the starting index of the parameters in the parameter array corresponding to the circuit in which the current gate is incorporated.
415 
416  # call the C wrapper function
417  return super().get_Parameter_Start_Index()
418 
419 
420 #@brief Method to get the list of parent gate indices. Then the parent gates can be obtained from the list of gates involved in the circuit.
421  def get_Parents( self, gate):
422 
423  # call the C wrapper function
424  return super().get_Parents( gate )
425 
426 
427 #@brief Method to get the list of child gate indices. Then the children gates can be obtained from the list of gates involved in the circuit.
428  def get_Children( self, gate):
429 
430  # call the C wrapper function
431  return super().get_Children( gate )
432 
433 
434 #@brief Add a generic gate to the circuit
435  def add_Gate(self,qgd_gate):
436 
437 
438  if isinstance(qgd_gate,H):
439  self.add_H(qgd_gate.get_Target_Qbit())
440  elif isinstance(qgd_gate,X):
441  self.add_X(qgd_gate.get_Target_Qbit())
442  elif isinstance(qgd_gate,Y):
443  self.add_Y(qgd_gate.get_Target_Qbit())
444  elif isinstance(qgd_gate,Z):
445  self.add_Z(qgd_gate.get_Target_Qbit())
446  elif isinstance(qgd_gate,CH):
447  self.add_CH(qgd_gate.get_Target_Qbit(),qgd_gate.get_Control_Qbit())
448  elif isinstance(qgd_gate,CZ):
449  self.add_CZ(qgd_gate.get_Target_Qbit(),qgd_gate.get_Control_Qbit())
450  elif isinstance(qgd_gate,RX):
451  self.add_RX(qgd_gate.get_Target_Qbit())
452  elif isinstance(qgd_gate,RY):
453  self.add_RY(qgd_gate.get_Target_Qbit())
454  elif isinstance(qgd_gate,RZ):
455  self.add_RZ(qgd_gate.get_Target_Qbit())
456  elif isinstance(qgd_gate,SX):
457  self.add_SX(qgd_gate.get_Target_Qbit())
458  elif isinstance(qgd_gate,U1):
459  self.add_U1(qgd_gate.get_Target_Qbit())
460  elif isinstance(qgd_gate,U2):
461  self.add_U2(qgd_gate.get_Target_Qbit())
462  elif isinstance(qgd_gate,U3):
463  self.add_U3(qgd_gate.get_Target_Qbit())
464  elif isinstance(qgd_gate,CRY):
465  self.add_CRY(qgd_gate.get_Target_Qbit(),qgd_gate.get_Control_Qbit())
466  elif isinstance(qgd_gate,CNOT):
467  self.add_CNOT(qgd_gate.get_Target_Qbit(),qgd_gate.get_Control_Qbit())
468  elif isinstance(qgd_gate,T):
469  self.add_T(qgd_gate.get_Target_Qbit())
470  elif isinstance(qgd_gate,Tdg):
471  self.add_Tdg(qgd_gate.get_Target_Qbit())
472  elif isinstance(qgd_gate,R):
473  self.add_R(qgd_gate.get_Target_Qbit())
474  elif isinstance(qgd_gate,CROT):
475  self.add_CROT(qgd_gate.get_Target_Qbit(),qgd_gate.get_Control_Qbit())
476  elif isinstance(qgd_gate,CR):
477  self.add_CR(qgd_gate.get_Target_Qbit(),qgd_gate.get_Control_Qbit())
478  else:
479  raise Exception("Cannot add gate: unimplemented gate type")
def add_Y(self, target_qbit)
Definition: qgd_Circuit.py:212
def get_Parameter_Start_Index(self)
Definition: qgd_Circuit.py:414
def add_CNOT(self, target_qbit, control_qbit)
Definition: qgd_Circuit.py:157
def get_Qbit_Num(self)
Call to get the number of qubits in the circuit.
Definition: qgd_Circuit.py:368
def add_SX(self, target_qbit)
Definition: qgd_Circuit.py:230
A QGD Python interface class for the Gates_Block.
Definition: qgd_Circuit.py:60
def add_SYC(self, target_qbit, control_qbit)
Definition: qgd_Circuit.py:184
def add_T(self, target_qbit)
Definition: qgd_Circuit.py:239
def get_Second_Renyi_Entropy(self, parameters=None, input_state=None, qubit_list=None)
Call to get the second Rényi entropy.
Definition: qgd_Circuit.py:324
def add_CH(self, target_qbit, control_qbit)
Definition: qgd_Circuit.py:175
def add_X(self, target_qbit)
Definition: qgd_Circuit.py:203
def get_Gates(self)
Call to get the list of gates (or subcircuits) in the circuit.
Definition: qgd_Circuit.py:384
def get_Gate_Nums(self)
Call to get statisctics on the gate counts in the circuit.
Definition: qgd_Circuit.py:392
def add_RY(self, target_qbit)
Definition: qgd_Circuit.py:139
def add_R(self, target_qbit)
Definition: qgd_Circuit.py:130
def add_RZ(self, target_qbit)
Definition: qgd_Circuit.py:148
def add_CROT(self, target_qbit, control_qbit)
Definition: qgd_Circuit.py:266
def Remap_Qbits(self, qbit_map, qbit_num=None)
Call to remap the qubits in the circuit.
Definition: qgd_Circuit.py:402
def get_Matrix(self, parameters_mtx)
Definition: qgd_Circuit.py:293
def add_CZ(self, target_qbit, control_qbit)
Definition: qgd_Circuit.py:166
def add_H(self, target_qbit)
Definition: qgd_Circuit.py:194
def add_RX(self, target_qbit)
Definition: qgd_Circuit.py:122
def add_adaptive(self, target_qbit, control_qbit)
Definition: qgd_Circuit.py:257
def add_CR(self, target_qbit, control_qbit)
Definition: qgd_Circuit.py:275
def apply_to(self, parameters_mtx, unitary_mtx, parallel=1)
Definition: qgd_Circuit.py:311
def add_Tdg(self, target_qbit)
Definition: qgd_Circuit.py:248
def get_Parents(self, gate)
Definition: qgd_Circuit.py:421
def __init__(self, qbit_num)
Constructor of the class.
Definition: qgd_Circuit.py:68
def get_Qbits(self)
Call to get the list of qubits involved in the circuit.
Definition: qgd_Circuit.py:376
def get_Children(self, gate)
Definition: qgd_Circuit.py:428
def add_U1(self, target_qbit)
Definition: qgd_Circuit.py:95
def add_U3(self, target_qbit)
Definition: qgd_Circuit.py:113
def add_Circuit(self, gate)
Definition: qgd_Circuit.py:284
def add_U2(self, target_qbit)
Definition: qgd_Circuit.py:104
def add_Z(self, target_qbit)
Definition: qgd_Circuit.py:221
def add_Gate(self, qgd_gate)
Definition: qgd_Circuit.py:435