Sequential Quantum Gate Decomposer  v1.9.6
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  # set initial parameters
76  rng = np.random.default_rng( 42 )
77 
78  parameters = np.zeros(num_of_parameters)
79 
80  # the number of adaptive layers in one level
81  num_of_adaptive_layers = int(qbit_num*(qbit_num-1)/2 * levels)
82 
83  if (real):
84 
85  for idx in range(qbit_num):
86  parameters[idx*3] = rng.random(1)*2*np.pi
87 
88  else:
89  parameters[0:3*qbit_num] = rng.random(3*qbit_num)*np.pi
90  pass
91 
92 
93  nontrivial_adaptive_layers = np.zeros( (num_of_adaptive_layers ))
94 
95  for layer_idx in range(num_of_adaptive_layers) :
96 
97  nontrivial_adaptive_layer = rng.integers(0,1)
98  nontrivial_adaptive_layers[layer_idx] = nontrivial_adaptive_layer
99 
100  if (nontrivial_adaptive_layer) :
101 
102  # set the radom parameters of the chosen adaptive layer
103  start_idx = qbit_num*3 + layer_idx*7
104 
105  if (real):
106  parameters[start_idx] = rng.random(1)*2*np.pi
107  parameters[start_idx+1] = rng.random(1)*2*np.pi
108  parameters[start_idx+4] = rng.random(1)*2*np.pi
109  else:
110  end_idx = start_idx + 7
111  parameters[start_idx:end_idx] = rng.random(7)*2*np.pi
112 
113 
114 
115  #print( parameters )
116  return parameters, nontrivial_adaptive_layers
117 
118 
119 
121  """This is a test class of the python iterface to test the trace offset, and the optimized problem"""
122 
124 
125 
126 
128 
129 
130 
131 
132  # creating a class to decompose the unitary
133  cDecompose_createUmtx = N_Qubit_Decomposition_adaptive( np.eye(matrix_size, dtype=np.complex128), level_limit_max=5, level_limit_min=0, accelerator_num=0 )
134 
135 
136  # adding decomposing layers to the gat structure
137  for idx in range(levels):
138  cDecompose_createUmtx.add_Adaptive_Layers()
139 
140  cDecompose_createUmtx.add_Finalyzing_Layer_To_Gate_Structure()
141 
142 
143  # get the number of free parameters
144  num_of_parameters = cDecompose_createUmtx.get_Parameter_Num()
145 
146 
147  # create randomized parameters
148  parameters, nontrivial_adaptive_layers = create_randomized_parameters( num_of_parameters, real=real )
149 
150 
151 
152  Umtx = cDecompose_createUmtx.get_Matrix( parameters )
153 
154 
155  # cut the matrixt by trace offset
156  trace_offset = 80
157  Umtx = Umtx[trace_offset:240, :]
158 
159 
160 
161 
162  # test cost function with trace offset
163 
164 
165 
166  # creating a class to decompose the unitary
167  cDecompose_CPU = N_Qubit_Decomposition_adaptive( Umtx.conj().T, level_limit_max=5, level_limit_min=0, accelerator_num=0 )
168 
169  # set the trace offset
170  cDecompose_CPU.set_Trace_Offset( trace_offset )
171 
172  # adding decomposing layers to the gat structure
173  for idx in range(levels):
174  cDecompose_CPU.add_Adaptive_Layers()
175 
176  cDecompose_CPU.add_Finalyzing_Layer_To_Gate_Structure()
177 
178  # setting the cost function variant
179  cDecompose_CPU.set_Cost_Function_Variant(cost_function_variant)
180 
181  t0 = time.time()
182  f0_CPU, grad_CPU = cDecompose_CPU.Optimization_Problem_Combined( parameters )
183 
184  assert( np.abs( f0_CPU ) < 1e-8 )
185 
186 
187 
188 
190  # creating a class to decompose the unitary
191  cDecompose = N_Qubit_Decomposition_adaptive( np.eye(matrix_size, dtype=np.complex128), level_limit_max=5, level_limit_min=0, accelerator_num=0 )
192 
193 
194  # adding decomposing layers to the gat structure
195  for idx in range(levels):
196  cDecompose.add_Adaptive_Layers()
197 
198  cDecompose.add_Finalyzing_Layer_To_Gate_Structure()
199 
200 
201  # get the number of free parameters
202  num_of_parameters = cDecompose.get_Parameter_Num()
203 
204 
205  # create randomized parameters
206  parameters, nontrivial_adaptive_layers = create_randomized_parameters( num_of_parameters, real=real )
207 
208 
209 
210  Umtx = cDecompose.get_Matrix( parameters )
211  mat, mat_deriv = cDecompose.Optimization_Problem_Combined_Unitary(parameters)
212  assert np.allclose(Umtx, mat)
213 
214  cost = cDecompose.Optimization_Problem(parameters)
215  assert np.allclose(np.array([cost, cost, cost]), cDecompose.Optimization_Problem_Batch(np.vstack([parameters, parameters, parameters])))
216  grad = cDecompose.Optimization_Problem_Grad(parameters)
217  f0_CPU, grad_CPU = cDecompose.Optimization_Problem_Combined( parameters )
218  assert np.allclose(grad, grad_CPU)
219  assert np.isclose(f0_CPU, cost)
220 
221 
222 
223 
224 
225 
def create_randomized_parameters(num_of_parameters, real=False)
Call to construct random parameter, with limited number of non-trivial adaptive layers.