Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
test_optmization_problem_combined.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 from squander import N_Qubit_Decomposition_adaptive
27 
28 
29 #from squander import nn
30 
31 import numpy as np
32 import random
33 import scipy.linalg
34 import time
35 from scipy.fft import fft
36 
37 import time
38 
39 try:
40  from mpi4py import MPI
41  MPI_imported = True
42 except ModuleNotFoundError:
43  MPI_imported = False
44 
45 
46 np.set_printoptions(linewidth=200)
47 
48 
49 # number of qubits
50 qbit_num = 8
51 
52 # cost function variant
53 cost_function_variant = 0
54 
55 
56 # matrix size of the unitary
57 matrix_size = 1 << qbit_num #pow(2, qbit_num )
58 dim_over_2 = 1 << (qbit_num-1) #pow(2, qbit_num-1)
59 
60 # the number of basis in the space of 2^n x 2^n Hermitian matrices
61 num_of_basis = 1 << 2*qbit_num
62 
63 # number of adaptive levels
64 levels = 4
65 
66 # set true to limit calcualtions to real numbers
67 real=False
68 
69 
70 
73 def create_randomized_parameters( num_of_parameters, real=False ):
74 
75 
76  parameters = np.zeros(num_of_parameters)
77 
78  # the number of adaptive layers in one level
79  num_of_adaptive_layers = int(qbit_num*(qbit_num-1)/2 * levels)
80 
81  if (real):
82 
83  for idx in range(qbit_num):
84  parameters[idx*3] = np.random.rand(1)*2*np.pi
85 
86  else:
87  parameters[0:3*qbit_num] = np.random.rand(3*qbit_num)*np.pi
88  pass
89 
90 
91  nontrivial_adaptive_layers = np.zeros( (num_of_adaptive_layers ))
92 
93  for layer_idx in range(num_of_adaptive_layers) :
94 
95  nontrivial_adaptive_layer = random.randint(0,1)
96  nontrivial_adaptive_layers[layer_idx] = nontrivial_adaptive_layer
97 
98  if (nontrivial_adaptive_layer) :
99 
100  # set the radom parameters of the chosen adaptive layer
101  start_idx = qbit_num*3 + layer_idx*7
102 
103  if (real):
104  parameters[start_idx] = np.random.rand(1)*2*np.pi
105  parameters[start_idx+1] = np.random.rand(1)*2*np.pi
106  parameters[start_idx+4] = np.random.rand(1)*2*np.pi
107  else:
108  end_idx = start_idx + 7
109  parameters[start_idx:end_idx] = np.random.rand(7)*2*np.pi
110 
111 
112 
113  #print( parameters )
114  return parameters, nontrivial_adaptive_layers
115 
116 
117 
119  """This is a test class of the python iterface to test the trace offset, and the optimized problem"""
120 
122 
123 
124 
126 
127 
128 
129 
130  # creating a class to decompose the unitary
131  cDecompose_createUmtx = N_Qubit_Decomposition_adaptive( np.eye(matrix_size, dtype=np.complex128), level_limit_max=5, level_limit_min=0, accelerator_num=0 )
132 
133 
134  # adding decomposing layers to the gat structure
135  for idx in range(levels):
136  cDecompose_createUmtx.add_Adaptive_Layers()
137 
138  cDecompose_createUmtx.add_Finalyzing_Layer_To_Gate_Structure()
139 
140 
141  # get the number of free parameters
142  num_of_parameters = cDecompose_createUmtx.get_Parameter_Num()
143 
144 
145  # create randomized parameters
146  parameters, nontrivial_adaptive_layers = create_randomized_parameters( num_of_parameters, real=real )
147 
148 
149 
150  Umtx = cDecompose_createUmtx.get_Matrix( parameters )
151 
152 
153  # cut the matrixt by trace offset
154  trace_offset = 80
155  Umtx = Umtx[trace_offset:240, :]
156 
157 
158 
159 
160  # test cost function with trace offset
161 
162 
163 
164  # creating a class to decompose the unitary
165  cDecompose_CPU = N_Qubit_Decomposition_adaptive( Umtx.conj().T, level_limit_max=5, level_limit_min=0, accelerator_num=0 )
166 
167  # set the trace offset
168  cDecompose_CPU.set_Trace_Offset( trace_offset )
169 
170  # adding decomposing layers to the gat structure
171  for idx in range(levels):
172  cDecompose_CPU.add_Adaptive_Layers()
173 
174  cDecompose_CPU.add_Finalyzing_Layer_To_Gate_Structure()
175 
176  # setting the cost function variant
177  cDecompose_CPU.set_Cost_Function_Variant(cost_function_variant)
178 
179  t0 = time.time()
180  f0_CPU, grad_CPU = cDecompose_CPU.Optimization_Problem_Combined( parameters )
181 
182  assert( np.abs( f0_CPU ) < 1e-8 )
183 
184 
185 
186 
188  # creating a class to decompose the unitary
189  cDecompose = N_Qubit_Decomposition_adaptive( np.eye(matrix_size, dtype=np.complex128), level_limit_max=5, level_limit_min=0, accelerator_num=0 )
190 
191 
192  # adding decomposing layers to the gat structure
193  for idx in range(levels):
194  cDecompose.add_Adaptive_Layers()
195 
196  cDecompose.add_Finalyzing_Layer_To_Gate_Structure()
197 
198 
199  # get the number of free parameters
200  num_of_parameters = cDecompose.get_Parameter_Num()
201 
202 
203  # create randomized parameters
204  parameters, nontrivial_adaptive_layers = create_randomized_parameters( num_of_parameters, real=real )
205 
206 
207 
208  Umtx = cDecompose.get_Matrix( parameters )
209  mat, mat_deriv = cDecompose.Optimization_Problem_Combined_Unitary(parameters)
210  assert np.allclose(Umtx, mat)
211 
212  cost = cDecompose.Optimization_Problem(parameters)
213  assert np.allclose(np.array([cost, cost, cost]), cDecompose.Optimization_Problem_Batch(np.vstack([parameters, parameters, parameters])))
214  grad = cDecompose.Optimization_Problem_Grad(parameters)
215  f0_CPU, grad_CPU = cDecompose.Optimization_Problem_Combined( parameters )
216  assert np.allclose(grad, grad_CPU)
217  assert np.isclose(f0_CPU, cost)
218 
219 
220 
221 
222 
223 
def create_randomized_parameters(num_of_parameters, real=False)
Call to construct random parameter, with limited number of non-trivial adaptive layers.