Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
test_heavy_hex.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 You should have received a copy of the GNU General Public License
19 along with this program. If not, see http://www.gnu.org/licenses/.
20 
21 @author: Peter Rakyta, Ph.D.
22 """
23 
25 
26 
27 
28 # cerate unitary q-bit matrix
29 from scipy.stats import unitary_group
30 import numpy as np
31 from squander import utils
32 
33 try:
34  from mpi4py import MPI
35  MPI_imported = True
36 except ModuleNotFoundError:
37  MPI_imported = False
38 
39 
41  """This is a test class of the python iterface to the decompsition classes of the QGD package"""
42 
44  r"""
45  This method is called by pytest.
46  Test to define custom gate structure in the decomposition
47 
48  """
49 
50  from squander import N_Qubit_Decomposition
51 
52  # the number of qubits spanning the unitary
53  qbit_num = 4
54 
55  # determine the soze of the unitary to be decomposed
56  matrix_size = int(2**qbit_num)
57 
58  # creating a random unitary to be decomposed
59  Umtx = unitary_group.rvs(matrix_size)
60 
61  # creating an instance of the C++ class
62  decomp = N_Qubit_Decomposition( Umtx.conj().T)
63 
64 
65  # create custom gate structure
67 
68 
69  # adding custom gate structure to the decomposition
70  decomp.set_Gate_Structure( gate_structure )
71 
72 
73  # set the maximal number of layers in the decomposition
74  decomp.set_Max_Layer_Num( {4: 60, 3:16} )
75 
76  # set the number of block to be optimized in one shot
77  decomp.set_Optimization_Blocks( 20 )
78 
79  # starting the decomposition
80  decomp.Start_Decomposition()
81 
82 
83  # list the decomposing operations
84  decomp.List_Gates()
85 
86  # get the decomposing operations
87  quantum_circuit = decomp.get_Qiskit_Circuit()
88 
89  import numpy.linalg as LA
90 
91 
92  # the unitary matrix from the result object
93  decomposed_matrix = np.asarray( utils.get_unitary_from_qiskit_circuit( quantum_circuit ) )
94  product_matrix = np.dot(Umtx,decomposed_matrix.conj().T)
95  phase = np.angle(product_matrix[0,0])
96  product_matrix = product_matrix*np.exp(-1j*phase)
97 
98  product_matrix = np.eye(matrix_size)*2 - product_matrix - product_matrix.conj().T
99  # the error of the decomposition
100  decomposition_error = (np.real(np.trace(product_matrix)))/2
101 
102  print('The error of the decomposition is ' + str(decomposition_error))
103 
104  assert( decomposition_error < 1e-3 )
105 
106 
107 
108 
110  r"""
111  This method is called to create custom gate structure for the decomposition on IBM QX2
112 
113  """
114 
115  from squander import Circuit
116 
117  # creating an instance of the wrapper class Circuit
118  Circuit_ret = Circuit( qbit_num )
119 
120  disentangle_qubit = qbit_num - 1
121 
122 
123 
124  for qbit in range(0, disentangle_qubit ):
125 
126  # creating an instance of the wrapper class Circuit
127  Layer = Circuit( qbit_num )
128 
129 
130  if qbit == 0:
131 
132  # add U3 fate to the block
133  Theta = True
134  Phi = False
135  Lambda = True
136  Layer.add_U3( 0 )
137  Layer.add_U3( disentangle_qubit )
138 
139  # add CNOT gate to the block
140  Layer.add_CNOT( 0, disentangle_qubit)
141 
142  elif qbit == 1:
143 
144  # add U3 fate to the block
145  Theta = True
146  Phi = False
147  Lambda = True
148  Layer.add_U3( 0 )
149  Layer.add_U3( 1 )
150 
151  # add CNOT gate to the block
152  Layer.add_CNOT( 0, 1)
153 
154 
155 
156  elif qbit == 2:
157 
158  # add U3 fate to the block
159  Theta = True
160  Phi = False
161  Lambda = True
162  Layer.add_U3( 2 )
163  Layer.add_U3( disentangle_qubit )
164 
165  # add CNOT gate to the block
166  Layer.add_CNOT( disentangle_qubit, 2 )
167 
168 
169 
170  Circuit_ret.add_Circuit( Layer )
171 
172  return Circuit_ret
173 
174 
175 
176 
177 
179  r"""
180  This method is called to create custom gate structure for the decomposition on IBM QX2
181 
182  """
183 
184  from squander import Circuit
185 
186  # creating an instance of the wrapper class Circuit
187  Circuit_ret = Circuit( qbit_num )
188 
189  disentangle_qubit = qbit_num - 1
190 
191 
192 
193  for qbit in range(0, disentangle_qubit ):
194 
195  # creating an instance of the wrapper class Circuit
196  Layer = Circuit( qbit_num )
197 
198 
199  if qbit == 0:
200 
201  # add U3 fate to the block
202  Theta = True
203  Phi = False
204  Lambda = True
205  Layer.add_U3( 0 )
206  Layer.add_U3( disentangle_qubit )
207 
208  # add CNOT gate to the block
209  Layer.add_CNOT( 0, disentangle_qubit)
210 
211  elif qbit == 1:
212 
213  # add U3 fate to the block
214  Theta = True
215  Phi = False
216  Lambda = True
217  Layer.add_U3( 0 )
218  Layer.add_U3( 1 )
219 
220  # add CNOT gate to the block
221  Layer.add_CNOT( 0, 1)
222 
223 
224 
225  elif qbit == 2:
226 
227  # add U3 fate to the block
228  Theta = True
229  Phi = False
230  Lambda = True
231  Layer.add_U3( 2 )
232  Layer.add_U3( 0 )
233 
234  # add CNOT gate to the block
235  Layer.add_CNOT( 0, 2)
236 
237 
238 
239  Circuit_ret.add_Circuit( Layer )
240 
241  return Circuit_ret
242 
A base class to determine the decomposition of an N-qubit unitary into a sequence of CNOT and U3 gate...