Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
Qiskit_IO.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 squander.gates.qgd_Circuit import qgd_Circuit as Circuit
31 
32 
33 from squander.gates.gates_Wrapper import (
34  U1,
35  U2,
36  U3,
37  H,
38  X,
39  Y,
40  Z,
41  T,
42  Tdg,
43  R,
44  CH,
45  CNOT,
46  CZ,
47  RX,
48  RY,
49  RZ,
50  SX,
51  SYC,
52  CRY )
53 
54 
55 
56 
57 def scalar(param):
58  """Extract scalar value from array or return as is"""
59  return param.item() if hasattr(param, 'item') else param
60 
61 
62 
66 def get_Qiskit_Circuit( Squander_circuit, parameters ):
67 
68  from qiskit import QuantumCircuit
69 
70  # creating Qiskit quantum circuit
71  circuit = QuantumCircuit(Squander_circuit.get_Qbit_Num() )
72 
73  gates = Squander_circuit.get_Gates()
74 
75  # constructing quantum circuit
76  for gate in gates:
77 
78  if isinstance( gate, CNOT ):
79  # adding CNOT gate to the quantum circuit
80  circuit.cx( gate.get_Control_Qbit(), gate.get_Target_Qbit() )
81 
82  elif isinstance( gate, CRY ):
83  # adding CNOT gate to the quantum circuit
84  parameters_gate = gate.Extract_Parameters( parameters )
85  circuit.cry( parameters_gate[0], gate.get_Control_Qbit(), gate.get_Target_Qbit() )
86 
87  elif isinstance( gate, CZ ):
88  # adding CZ gate to the quantum circuit
89  circuit.cz( gate.get_Control_Qbit(), gate.get_Target_Qbit() )
90 
91  elif isinstance( gate, CH ):
92  # adding CZ gate to the quantum circuit
93  circuit.ch( gate.get_Control_Qbit(), gate.get_Target_Qbit() )
94 
95  elif isinstance( gate, SYC ):
96  # Sycamore gate
97  print("Unsupported gate in the circuit export: Sycamore gate")
98  return None
99 
100  elif isinstance( gate, U1 ):
101  # adding U1 gate to the quantum circuit
102  parameters_gate = gate.Extract_Parameters( parameters )
103  circuit.p( parameters_gate[0], gate.get_Target_Qbit() ) # U1 is equivalent to P gate
104 
105  elif isinstance( gate, U2 ):
106  # adding U2 gate to the quantum circuit
107  parameters_gate = gate.Extract_Parameters( parameters )
108  circuit.u( np.pi/2, parameters_gate[0], parameters_gate[1], gate.get_Target_Qbit() )
109 
110  elif isinstance( gate, U3 ):
111  # adding U3 gate to the quantum circuit
112  parameters_gate = gate.Extract_Parameters( parameters )
113  circuit.u( parameters_gate[0], parameters_gate[1], parameters_gate[2], gate.get_Target_Qbit() )
114 
115  elif isinstance( gate, RX ):
116  # RX gate
117  parameters_gate = gate.Extract_Parameters( parameters )
118  circuit.rx( parameters_gate[0], gate.get_Target_Qbit() )
119 
120  elif isinstance( gate, RY ):
121  # RY gate
122  parameters_gate = gate.Extract_Parameters( parameters )
123  circuit.ry( parameters_gate[0], gate.get_Target_Qbit() )
124 
125  elif isinstance( gate, RZ ):
126  # RZ gate
127  parameters_gate = gate.Extract_Parameters( parameters )
128  circuit.rz( parameters_gate[0], gate.get_Target_Qbit() )
129 
130  elif isinstance( gate, R ):
131  # R gate
132  parameters_gate = gate.Extract_Parameters( parameters )
133  circuit.r( parameters_gate[0],parameters_gate[1], gate.get_Target_Qbit() )
134  elif isinstance( gate, H ):
135  # Hadamard gate
136  circuit.h( gate.get_Target_Qbit() )
137 
138  elif isinstance( gate, X ):
139  # X gate
140  circuit.x( gate.get_Target_Qbit() )
141 
142  elif isinstance( gate, Y ):
143  # Y gate
144  circuit.y( gate.get_Target_Qbit() )
145 
146  elif isinstance( gate, Z ):
147  # Z gate
148  circuit.z( gate.get_Target_Qbit() )
149 
150  elif isinstance( gate, SX ):
151  # SX gate
152  circuit.sx( gate.get_Target_Qbit() )
153 
154  elif isinstance( gate, T ):
155  # T gate
156  circuit.t( gate.get_Target_Qbit() )
157 
158  elif isinstance( gate, Tdg ):
159  # T gate
160  circuit.tdg( gate.get_Target_Qbit() )
161 
162  elif isinstance( gate, Circuit ):
163  # Sub-circuit gate
164  raise ValueError("Qiskit export of circuits with subcircuit is not supported. Use Circuit::get_Flat_Circuit prior of exporting circuit.")
165 
166  else:
167  print(gate)
168  raise ValueError("Unsupported gate in the circuit export.")
169 
170  return( circuit )
171 
172 
173 
177 def get_Qiskit_Circuit_inverse( Squander_circuit, parameters ):
178 
179  from qiskit import QuantumCircuit
180 
181  # creating Qiskit quantum circuit
182  circuit = QuantumCircuit(Squander_circuit.get_Qbit_Num() )
183 
184  gates = Squander_circuit.get_Gates()
185 
186  # constructing quantum circuit
187  for idx in range(len(gates)-1, -1, -1):
188 
189  gate = gates[idx]
190 
191  if isinstance( gate, CNOT ):
192  # adding CNOT gate to the quantum circuit
193  circuit.cx( gate.get_Control_Qbit(), gate.get_Target_Qbit() )
194 
195  elif isinstance( gate, CRY ):
196  # adding CNOT gate to the quantum circuit
197  parameters_gate = [scalar(p) for p in gate.Extract_Parameters( parameters )]
198  circuit.cry( -parameters_gate[0], gate.get_Control_Qbit(), gate.get_Target_Qbit() )
199  elif isinstance( gate, R ):
200  # R gate
201  parameters_gate = gate.Extract_Parameters( parameters )
202  circuit.r( -parameters_gate[0],parameters_gate[1], gate.get_Target_Qbit() )
203  elif isinstance( gate, CZ ):
204  # adding CZ gate to the quantum circuit
205  circuit.cz( gate.get_Control_Qbit(), gate.get_Target_Qbit() )
206 
207  elif isinstance( gate, CH ):
208  # adding CZ gate to the quantum circuit
209  circuit.ch( gate.get_Control_Qbit(), gate.get_Target_Qbit() )
210 
211  elif isinstance( gate, SYC ):
212  # Sycamore gate
213  print("Unsupported gate in the circuit export: Sycamore gate")
214  return None
215 
216  elif isinstance( gate, U1 ):
217  # adding U1 gate to the quantum circuit
218  parameters_gate = [scalar(p) for p in gate.Extract_Parameters( parameters )]
219  circuit.p( -parameters_gate[0], gate.get_Target_Qbit() ) # U1 is equivalent to P gate
220 
221  elif isinstance( gate, U2 ):
222  # adding U2 gate to the quantum circuit
223  parameters_gate = [scalar(p) for p in gate.Extract_Parameters( parameters )]
224  circuit.u( -np.pi/2, -parameters_gate[0], -parameters_gate[1], gate.get_Target_Qbit() )
225 
226  elif isinstance( gate, U3 ):
227  # adding U3 gate to the quantum circuit
228  parameters_gate = [scalar(p) for p in gate.Extract_Parameters( parameters )]
229  circuit.u( -parameters_gate[0], -parameters_gate[2], -parameters_gate[1], gate.get_Target_Qbit() )
230 
231  elif isinstance( gate, RX ):
232  # RX gate
233  parameters_gate = [scalar(p) for p in gate.Extract_Parameters( parameters )]
234  circuit.rx( -parameters_gate[0], gate.get_Target_Qbit() )
235 
236  elif isinstance( gate, RY ):
237  # RY gate
238  parameters_gate = [scalar(p) for p in gate.Extract_Parameters( parameters )]
239  circuit.ry( -parameters_gate[0], gate.get_Target_Qbit() )
240 
241  elif isinstance( gate, RZ ):
242  # RZ gate
243  parameters_gate = [scalar(p) for p in gate.Extract_Parameters( parameters )]
244  circuit.rz( -parameters_gate[0], gate.get_Target_Qbit() )
245 
246  elif isinstance( gate, H ):
247  # Hadamard gate
248  circuit.h( gate.get_Target_Qbit() )
249 
250  elif isinstance( gate, X ):
251  # X gate
252  circuit.x( gate.get_Target_Qbit() )
253 
254  elif isinstance( gate, Y ):
255  # Y gate
256  circuit.y( gate.get_Target_Qbit() )
257 
258  elif isinstance( gate, Z ):
259  # Z gate
260  circuit.z( gate.get_Target_Qbit() )
261 
262  elif isinstance( gate, SX ):
263  # SX gate
264  circuit.sx( gate.get_Target_Qbit() )
265 
266  elif isinstance( gate, T ):
267  # T gate (inverse is Tdg)
268  circuit.tdg( gate.get_Target_Qbit() )
269 
270  elif isinstance( gate, Tdg ):
271  # Tdg gate (inverse is T)
272  circuit.t( gate.get_Target_Qbit() )
273 
274  elif isinstance( gate, Circuit ):
275  # Sub-circuit gate
276  raise ValueError("Qiskit export of circuits with subcircuit is not supported. Use Circuit::get_Flat_Circuit prior of exporting circuit.")
277 
278  else:
279  print(gate)
280  raise ValueError("Unsupported gate in the circuit export.")
281 
282 
283  return( circuit )
284 
285 
286 
290 
291  from qiskit import QuantumCircuit
292  from qiskit.circuit import ParameterExpression
293 
294 
295 
296 
297  # get the register of qubits
298  q_register = qc_in.qubits
299 
300  # get the size of the register
301  register_size = qc_in.num_qubits
302 
303  # construct the qgd gate structure
304  Circuit_Squander = Circuit(register_size)
305  parameters = list()
306 
307  for gate in qc_in.data:
308 
309  name = gate.operation.name
310  #print('Gate name in Qiskit: ', name )
311  if name == 'u1' or name == 'p':
312  # add U1 gate - lambda parameter used directly
313  qubits = gate.qubits
314  qubit = q_register.index( qubits[0] )
315 
316  params = gate.operation.params
317 
318  for param in params:
319  parameters = parameters + [float(param)]
320 
321  Circuit_Squander.add_U1( qubit )
322 
323  elif name == 'u2':
324  # add U2 gate - phi and lambda parameters used directly
325  qubits = gate.qubits
326  qubit = q_register.index( qubits[0] )
327 
328  params = gate.operation.params
329 
330  for param in params:
331  parameters = parameters + [float(param)]
332 
333  Circuit_Squander.add_U2( qubit )
334 
335  elif name == 'u3' or name == 'u':
336  # add U3 gate - theta/2 handled internally by U3 gate implementation
337  qubits = gate.qubits
338  qubit = q_register.index( qubits[0] )
339 
340  params = gate.operation.params
341  params[0] = params[0]/2 #SQUADER works with theta/2
342 
343  for param in params:
344  parameters = parameters + [float(param)]
345 
346  Circuit_Squander.add_U3( qubit )
347 
348  elif name == 'cx':
349  # add cx gate
350  qubits = gate.qubits
351  qubit0 = q_register.index( qubits[0] )
352  qubit1 = q_register.index( qubits[1] )
353  Circuit_Squander.add_CNOT( qubit1, qubit0 )
354 
355  elif name == "cry":
356 
357  qubits = gate.qubits
358  qubit0 = q_register.index( qubits[0] )
359  qubit1 = q_register.index( qubits[1] )
360 
361  params = gate.operation.params
362  params[0] = params[0]/2 #SQUADER works with theta/2
363 
364  for param in params:
365  parameters = parameters + [float(param)]
366 
367  Circuit_Squander.add_CRY( qubit1, qubit0 )
368 
369  elif name == "cz":
370  qubits = gate.qubits
371  qubit0 = q_register.index( qubits[0] )
372  qubit1 = q_register.index( qubits[1] )
373  Circuit_Squander.add_CZ( qubit1, qubit0 )
374 
375  elif name == "ch":
376  qubits = gate.qubits
377  qubit0 = q_register.index( qubits[0] )
378  qubit1 = q_register.index( qubits[1] )
379  Circuit_Squander.add_CH( qubit1, qubit0 )
380 
381  elif name == "rx":
382  qubits = gate.qubits
383  qubit = q_register.index( qubits[0] )
384 
385  params = gate.operation.params
386  params[0] = params[0]/2 #SQUADER works with theta/2
387 
388  for param in params:
389  parameters = parameters + [float(param)]
390 
391  Circuit_Squander.add_RX( qubit )
392 
393  elif name == "ry":
394  qubits = gate.qubits
395  qubit = q_register.index( qubits[0] )
396 
397  params = gate.operation.params
398  params[0] = params[0]/2 #SQUADER works with theta/2
399 
400  for param in params:
401  parameters = parameters + [float(param)]
402 
403  Circuit_Squander.add_RY( qubit )
404 
405  elif name == "rz" :
406  qubits = gate.qubits
407  qubit = q_register.index( qubits[0] )
408 
409  params = gate.operation.params
410  params[0] = params[0]/2 #SQUADER works with phi/2
411 
412  for param in params:
413  parameters = parameters + [float(param)]
414 
415  Circuit_Squander.add_RZ( qubit )
416 
417  elif name == "h":
418  qubits = gate.qubits
419  qubit = q_register.index( qubits[0] )
420 
421  Circuit_Squander.add_H( qubit )
422 
423  elif name == "x":
424  qubits = gate.qubits
425  qubit = q_register.index( qubits[0] )
426 
427  Circuit_Squander.add_X( qubit )
428 
429  elif name == "y":
430  qubits = gate.qubits
431  qubit = q_register.index( qubits[0] )
432 
433  Circuit_Squander.add_Y( qubit )
434 
435  elif name == "z":
436  qubits = gate.qubits
437  qubit = q_register.index( qubits[0] )
438 
439  Circuit_Squander.add_Z( qubit )
440 
441  elif name == "sx":
442  qubits = gate.qubits
443  qubit = q_register.index( qubits[0] )
444 
445  Circuit_Squander.add_SX( qubit )
446 
447  elif name == "t":
448  qubits = gate.qubits
449  qubit = q_register.index( qubits[0] )
450 
451  Circuit_Squander.add_T( qubit )
452 
453  elif name == "tdg":
454  qubits = gate.qubits
455  qubit = q_register.index( qubits[0] )
456 
457  Circuit_Squander.add_Tdg( qubit )
458 
459  elif name == "r":
460  qubits = gate.qubits
461  qubit = q_register.index( qubits[0] )
462 
463  params = gate.operation.params
464  params[0] = params[0]/2 #SQUADER works with theta/2
465 
466  for param in params:
467  parameters = parameters + [float(param)]
468 
469  Circuit_Squander.add_R( qubit )
470 
471  else:
472  print(f"convert_Qiskit_to_Squander: Unimplemented gate: {name}")
473 
474 
475  parameters = np.asarray(parameters, dtype=np.float64)
476 
477  return Circuit_Squander, parameters
478 
479 
480 
481 
def convert_Qiskit_to_Squander(qc_in)
Call to import initial quantum circuit in QISKIT format to be further comporessed.
Definition: Qiskit_IO.py:289
def get_Qiskit_Circuit_inverse(Squander_circuit, parameters)
Export the inverse of a Squsnder circuit into Qiskit circuit.
Definition: Qiskit_IO.py:177
def get_Qiskit_Circuit(Squander_circuit, parameters)
Export the unitary decomposition into Qiskit format.
Definition: Qiskit_IO.py:66