Sequential Quantum Gate Decomposer  v1.9.6
Powerful decomposition of general unitarias into one- and two-qubit gates gates
test_Compression.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 
34 try:
35  from mpi4py import MPI
36  MPI_imported = True
37 except ModuleNotFoundError:
38  MPI_imported = False
39 
40 
41 
42 
44  """This is a test class of the python iterface to the decompsition classes of the QGD package"""
45 
47  r"""
48  This method is called by pytest.
49  Test to decompose a 4-qubit unitary of the IBM chellenge
50 
51  """
52 
53  from squander import N_Qubit_Decomposition_adaptive
54  from scipy.io import loadmat
55 
56  # load the unitary from file
57  data = loadmat('data/Umtx.mat')
58  # The unitary to be decomposed
59  Umtx = data['Umtx']
60 
61  # generate config structure
62  config = { 'max_outer_iterations': 10,
63  'max_inner_iterations': 300000,
64  'max_inner_iterations_compression': 10000,
65  'max_inner_iterations_final': 1000,
66  'randomized_adaptive_layers': 1,
67  'export_circuit_2_binary': 1,
68  'optimization_tolerance': 1e-8 }
69 
70 
71 
72 
73  # creating a class to decompose the unitary
74  cDecompose = N_Qubit_Decomposition_adaptive( Umtx.conj().T, config=config )
75 
76 
77  # setting the verbosity of the decomposition
78  cDecompose.set_Verbose( 3 )
79 
80  # adding decomposing layers to the gate structure
81  levels = 2
82  for idx in range(levels):
83  cDecompose.add_Adaptive_Layers()
84 
85  cDecompose.add_Finalyzing_Layer_To_Gate_Structure()
86 
87  # set initial parameters
88  rng = np.random.default_rng( 42 )
89  num_of_parameters = cDecompose.get_Parameter_Num()
90  parameters = rng.random(num_of_parameters)*2*np.pi
91 
92  cDecompose.set_Optimized_Parameters( parameters )
93 
94 
95  # starting the decomposition
96  cDecompose.get_Initial_Circuit()
97 
98  # compress the initial gate structure
99  cDecompose.Compress_Circuit()
100 
101  # finalize the gate structur (replace CRY gates with CNOT gates)
102  cDecompose.Finalize_Circuit()
103 
104  # list the decomposing operations
105  cDecompose.List_Gates()
106 
107  # get the decomposing operations
108  quantum_circuit = cDecompose.get_Qiskit_Circuit()
109 
110  # print the quantum circuit
111  print(quantum_circuit)
112 
113  import numpy.linalg as LA
114 
115  # the unitary matrix from the result object
116  decomposed_matrix = utils.get_unitary_from_qiskit_circuit( quantum_circuit )
117  product_matrix = np.dot(Umtx,decomposed_matrix.conj().T)
118  phase = np.angle(product_matrix[0,0])
119  product_matrix = product_matrix*np.exp(-1j*phase)
120 
121  product_matrix = np.eye(16)*2 - product_matrix - product_matrix.conj().T
122  # the error of the decomposition
123  decomposition_error = (np.real(np.trace(product_matrix)))/2
124 
125  print('The error of the decomposition is ' + str(decomposition_error))
126 
127  assert( decomposition_error < 1e-3 )
128 
129 
131  r"""
132  This method is called by pytest.
133  Test to decompose a 4-qubit unitary of the IBM chellenge
134 
135  """
136 
137  from squander import N_Qubit_Decomposition_adaptive
138  from scipy.io import loadmat
139 
140  # load the unitary from file
141  data = loadmat('data/Umtx.mat')
142  # The unitary to be decomposed
143  Umtx = data['Umtx']
144 
145  # generate config structure
146  config = { 'max_outer_iterations': 10,
147  'max_inner_iterations': 300000,
148  'max_inner_iterations_compression': 10000,
149  'max_inner_iterations_final': 1000,
150  'randomized_adaptive_layers': 1,
151  'export_circuit_2_binary': 1,
152  'optimization_tolerance': 1e-8 }
153 
154 
155  # creating a class to decompose the unitary
156  cDecompose = N_Qubit_Decomposition_adaptive( Umtx.conj().T, config=config )
157 
158 
159  # setting the verbosity of the decomposition
160  cDecompose.set_Verbose( 3 )
161 
162 
163  # adding decomposing layers to the gate structure
164  levels = 3
165  for idx in range(levels):
166  cDecompose.add_Adaptive_Layers()
167 
168  cDecompose.add_Finalyzing_Layer_To_Gate_Structure()
169 
170 
171  # set initial parameters
172  rng = np.random.default_rng( 42 )
173  num_of_parameters = cDecompose.get_Parameter_Num()
174  parameters = rng.random(num_of_parameters)*2*np.pi
175 
176  cDecompose.set_Optimized_Parameters( parameters )
177 
178  # starting the decomposition
179  cDecompose.get_Initial_Circuit()
180 
181  # finalize the gate structur (replace CRY gates with CNOT gates)
182  cDecompose.Finalize_Circuit()
183 
184  # list the decomposing operations
185  cDecompose.List_Gates()
186 
187  # get the decomposing operations
188  quantum_circuit = cDecompose.get_Qiskit_Circuit()
189 
190  # print the quantum circuit
191  print(quantum_circuit)
192 
193  import numpy.linalg as LA
194 
195  # the unitary matrix from the result object
196  decomposed_matrix = utils.get_unitary_from_qiskit_circuit( quantum_circuit )
197  product_matrix = np.dot(Umtx,decomposed_matrix.conj().T)
198  phase = np.angle(product_matrix[0,0])
199  product_matrix = product_matrix*np.exp(-1j*phase)
200 
201  product_matrix = np.eye(16)*2 - product_matrix - product_matrix.conj().T
202  # the error of the decomposition
203  decomposition_error = (np.real(np.trace(product_matrix)))/2
204 
205  print('The error of the decomposition is ' + str(decomposition_error))
206 
207  assert( decomposition_error < 1e-3 )
208 
209 
211  r"""
212  This method is called by pytest.
213  Test to decompose a 4-qubit unitary of the IBM chellenge
214 
215  """
216 
217  from squander import N_Qubit_Decomposition_adaptive
218  from scipy.io import loadmat
219 
220  # load the unitary from file
221  data = loadmat('data/Umtx.mat')
222  # The unitary to be decomposed
223  Umtx = data['Umtx']
224 
225 
226  # generate config structure
227  config = { 'max_outer_iterations': 10,
228  'max_inner_iterations': 300000,
229  'max_inner_iterations_compression': 10000,
230  'max_inner_iterations_final': 1000,
231  'randomized_adaptive_layers': 1,
232  'export_circuit_2_binary': 1,
233  'optimization_tolerance': 1e-8 }
234 
235 
236  # creating a class to decompose the unitary
237  cDecompose = N_Qubit_Decomposition_adaptive( Umtx.conj().T, config=config )
238 
239 
240  # setting the verbosity of the decomposition
241  cDecompose.set_Verbose( 3 )
242 
243 
244 
245  # importing circuit from a binary
246  cDecompose.set_Gate_Structure_From_Binary("circuit_squander.binary")
247 
248  # starting compression iterations
249  cDecompose.Compress_Circuit()
250 
251  # finalize the gate structur (replace CRY gates with CNOT gates)
252  cDecompose.Finalize_Circuit()
253 
254  # list the decomposing operations
255  cDecompose.List_Gates()
256 
257  # get the decomposing operations
258  quantum_circuit = cDecompose.get_Qiskit_Circuit()
259 
260  # print the quantum circuit
261  print(quantum_circuit)
262 
263  import numpy.linalg as LA
264 
265  # the unitary matrix from the result object
266  decomposed_matrix = utils.get_unitary_from_qiskit_circuit( quantum_circuit )
267  product_matrix = np.dot(Umtx,decomposed_matrix.conj().T)
268  phase = np.angle(product_matrix[0,0])
269  product_matrix = product_matrix*np.exp(-1j*phase)
270 
271  product_matrix = np.eye(16)*2 - product_matrix - product_matrix.conj().T
272  # the error of the decomposition
273  decomposition_error = (np.real(np.trace(product_matrix)))/2
274 
275  print('The error of the decomposition is ' + str(decomposition_error))
276 
277  assert( decomposition_error < 1e-3 )
278 
279 
281  r"""
282  This method is called by pytest.
283  Test to decompose a 4-qubit unitary of the IBM chellenge
284 
285  """
286 
287  from squander import N_Qubit_Decomposition_adaptive
288  from scipy.io import loadmat
289 
290  # load the unitary from file
291  data = loadmat('data/Umtx.mat')
292  # The unitary to be decomposed
293  Umtx = data['Umtx']
294  config = { 'max_outer_iterations': 1,
295  'max_inner_iterations_agent': 25000,
296  'max_inner_iterations_compression': 10000,
297  'max_inner_iterations' : 500,
298  'max_inner_iterations_final': 5000,
299  'Randomized_Radius': 0.3,
300  'randomized_adaptive_layers': 1,
301  'optimization_tolerance_agent': 1e-4,
302  'optimization_tolerance': 1e-5,
303  'agent_num': 10}
304 
305  # creating a class to decompose the unitary
306  cDecompose = N_Qubit_Decomposition_adaptive( Umtx.conj().T, config=config )
307 
308 
309  # setting the verbosity of the decomposition
310  cDecompose.set_Verbose( 3 )
311 
312 
313  # adding decomposing layers to the gate structure
314  levels = 2
315  for idx in range(levels):
316  cDecompose.add_Adaptive_Layers()
317 
318  cDecompose.add_Finalyzing_Layer_To_Gate_Structure()
319 
320 
321 
322  # set initial parameters
323  rng = np.random.default_rng( 42 )
324  num_of_parameters = cDecompose.get_Parameter_Num()
325  parameters = rng.random(num_of_parameters)*2*np.pi
326 
327  cDecompose.set_Optimized_Parameters( parameters )
328 
329  # setting optimizer
330  cDecompose.set_Optimizer("AGENTS")
331 
332  # starting the decomposition
333  cDecompose.get_Initial_Circuit()
334 
335  # setting optimizer
336  cDecompose.set_Optimizer("BFGS")
337 
338  # continue the decomposition with a second optimizer method
339  cDecompose.get_Initial_Circuit()
340 
341  # starting compression iterations
342  cDecompose.Compress_Circuit()
343 
344  # finalize the gate structur (replace CRY gates with CNOT gates)
345  cDecompose.Finalize_Circuit()
346 
347  # list the decomposing operations
348  cDecompose.List_Gates()
349 
350  # get the decomposing operations
351  quantum_circuit = cDecompose.get_Qiskit_Circuit()
352 
353  # print the quantum circuit
354  print(quantum_circuit)
355 
356  import numpy.linalg as LA
357 
358  # the unitary matrix from the result object
359  decomposed_matrix = utils.get_unitary_from_qiskit_circuit( quantum_circuit )
360  product_matrix = np.dot(Umtx,decomposed_matrix.conj().T)
361  phase = np.angle(product_matrix[0,0])
362  product_matrix = product_matrix*np.exp(-1j*phase)
363 
364  product_matrix = np.eye(16)*2 - product_matrix - product_matrix.conj().T
365  # the error of the decomposition
366  decomposition_error = (np.real(np.trace(product_matrix)))/2
367 
368  print('The error of the decomposition is ' + str(decomposition_error))
369 
370  assert( decomposition_error < 1e-3 )
371 
372 
373 
374 
A base class to determine the decomposition of an N-qubit unitary into a sequence of CNOT and U3 gate...