Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
example_heavy_hex_general_unitary.py
Go to the documentation of this file.
1 # -*- coding: utf-8 -*-
2 """
3 Created on Fri Jun 26 14:42:56 2020
4 Copyright 2020 Peter Rakyta, Ph.D.
5 
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9 
10  http://www.apache.org/licenses/LICENSE-2.0
11 
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 
18 @author: Peter Rakyta, Ph.D.
19 """
20 
22 
23 
24 
25 # cerate unitary q-bit matrix
26 from scipy.stats import unitary_group
27 from squander import utils
28 import numpy as np
29 
30 
31 
33  r"""
34  This method is called to create custom gate structure for the decomposition on IBM QX2
35 
36  """
37 
38  from squander import Circuit
39 
40  # creating an instance of the wrapper class Circuit
41  Circuit_ret = Circuit( qbit_num )
42 
43  disentangle_qubit = qbit_num - 1
44 
45 
46 
47  for qbit in range(0, disentangle_qubit ):
48 
49  # creating an instance of the wrapper class Circuit
50  Layer = Circuit( qbit_num )
51 
52 
53  if qbit == 0:
54 
55  # add U3 fate to the block
56  Theta = True
57  Phi = False
58  Lambda = True
59  Layer.add_U3( 0, Theta, Phi, Lambda )
60  Layer.add_U3( disentangle_qubit, Theta, Phi, Lambda )
61 
62  # add CNOT gate to the block
63  Layer.add_CNOT( 0, disentangle_qubit)
64 
65  elif qbit == 1:
66 
67  # add U3 fate to the block
68  Theta = True
69  Phi = False
70  Lambda = True
71  Layer.add_U3( 0, Theta, Phi, Lambda )
72  Layer.add_U3( 1, Theta, Phi, Lambda )
73 
74  # add CNOT gate to the block
75  Layer.add_CNOT( 0, 1)
76 
77 
78 
79  elif qbit == 2:
80 
81  # add U3 fate to the block
82  Theta = True
83  Phi = False
84  Lambda = True
85  Layer.add_U3( 2, Theta, Phi, Lambda )
86  Layer.add_U3( disentangle_qubit, Theta, Phi, Lambda )
87 
88  # add CNOT gate to the block
89  Layer.add_CNOT( disentangle_qubit, 2 )
90 
91 
92 
93  Circuit_ret.add_Circuit( Layer )
94 
95  return Circuit_ret
96 
97 
98 
99 
100 
102  r"""
103  This method is called to create custom gate structure for the decomposition on IBM QX2
104 
105  """
106 
107  from squander import Circuit
108 
109  # creating an instance of the wrapper class Circuit
110  Circuit_ret = Circuit( qbit_num )
111 
112  disentangle_qubit = qbit_num - 1
113 
114 
115 
116  for qbit in range(0, disentangle_qubit ):
117 
118  # creating an instance of the wrapper class Circuit
119  Layer = Circuit( qbit_num )
120 
121 
122  if qbit == 0:
123 
124  # add U3 fate to the block
125  Theta = True
126  Phi = False
127  Lambda = True
128  Layer.add_U3( 0, Theta, Phi, Lambda )
129  Layer.add_U3( disentangle_qubit, Theta, Phi, Lambda )
130 
131  # add CNOT gate to the block
132  Layer.add_CNOT( 0, disentangle_qubit)
133 
134  elif qbit == 1:
135 
136  # add U3 fate to the block
137  Theta = True
138  Phi = False
139  Lambda = True
140  Layer.add_U3( 0, Theta, Phi, Lambda )
141  Layer.add_U3( 1, Theta, Phi, Lambda )
142 
143  # add CNOT gate to the block
144  Layer.add_CNOT( 0, 1)
145 
146 
147 
148  elif qbit == 2:
149 
150  # add U3 fate to the block
151  Theta = True
152  Phi = False
153  Lambda = True
154  Layer.add_U3( 2, Theta, Phi, Lambda )
155  Layer.add_U3( 0, Theta, Phi, Lambda )
156 
157  # add CNOT gate to the block
158  Layer.add_CNOT( 0, 2)
159 
160 
161 
162  Circuit_ret.add_Circuit( Layer )
163 
164  return Circuit_ret
165 
166 
167 
168 from squander import N_Qubit_Decomposition
169 
170 # the number of qubits spanning the unitary
171 qbit_num = 4
172 
173 # determine the soze of the unitary to be decomposed
174 matrix_size = int(2**qbit_num)
175 
176 # creating a random unitary to be decomposed
177 Umtx = unitary_group.rvs(matrix_size)
178 
179 # creating an instance of the C++ class
180 decomp = N_Qubit_Decomposition( Umtx.conj().T )
181 
182 
183 # create custom gate structure
185 
186 
187 # adding custom gate structure to the decomposition
188 decomp.set_Gate_Structure( gate_structure )
189 
190 
191 # set the maximal number of layers in the decomposition
192 decomp.set_Max_Layer_Num( {4: 60, 3:16} )
193 
194 # set the number of block to be optimized in one shot
195 decomp.set_Optimization_Blocks( 20 )
196 
197 # starting the decomposition
198 decomp.Start_Decomposition()
199 
200 
201 # list the decomposing operations
202 decomp.List_Gates()
203 
204 # get the decomposing operations
205 quantum_circuit = decomp.get_Qiskit_Circuit()
206 
207 
208 import numpy.linalg as LA
209 
210 # the unitary matrix from the result object
211 decomposed_matrix = utils.get_unitary_from_qiskit_circuit( quantum_circuit )
212 product_matrix = np.dot(Umtx,decomposed_matrix.conj().T)
213 phase = np.angle(product_matrix[0,0])
214 product_matrix = product_matrix*np.exp(-1j*phase)
215 
216 product_matrix = np.eye(matrix_size)*2 - product_matrix - product_matrix.conj().T
217 # the error of the decomposition
218 decomposition_error = (np.real(np.trace(product_matrix)))/2
219 
220 print('The error of the decomposition is ' + str(decomposition_error))