Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
BFGS2.cpp
Go to the documentation of this file.
1 /*
2 Created on Fri Jun 26 14:13:26 2020
3 Copyright 2020 Peter Rakyta, Ph.D.
4 
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8 
9  http://www.apache.org/licenses/LICENSE-2.0
10 
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 
17 @author: Peter Rakyta, Ph.D.
18 */
24 #include "Optimization_Interface.h"
26 #include "BFGS_Powell.h"
27 
28 #include <fstream>
29 
30 
31 #ifdef __DFE__
32 #include "common_DFE.h"
33 #endif
34 
35 
36 
43 
44 
45 #ifdef __DFE__
46  if ( qbit_num >= 2 && get_accelerator_num() > 0 ) {
47  upload_Umtx_to_DFE();
48  }
49 #endif
50 
51 
52  if (gates.size() == 0 ) {
53  return;
54  }
55 
56 
57  if (solution_guess.size() == 0 ) {
58  solution_guess = Matrix_real(num_of_parameters,1);
59  }
60 
61 
62  if (optimized_parameters_mtx.size() == 0) {
63  optimized_parameters_mtx = Matrix_real(1, num_of_parameters);
64  memcpy(optimized_parameters_mtx.get_data(), solution_guess.get_data(), num_of_parameters*sizeof(double) );
65  }
66 
67  // maximal number of iteration loops
68  int iteration_loops_max;
69  try {
70  iteration_loops_max = std::max(iteration_loops[qbit_num], 1);
71  }
72  catch (...) {
73  iteration_loops_max = 1;
74  }
75 
76 
77  int random_shift_count = 0;
78  long long sub_iter_idx = 0;
79  double current_minimum_hold = current_minimum;
80 
81 
82 
83 
84 
85 tbb::tick_count bfgs_start = tbb::tick_count::now();
86 CPU_time = 0.0;
87 
88 
89  // random generator of real numbers
90  std::uniform_real_distribution<> distrib_real(0.0, 2*M_PI);
91 
92  // random generator of integers
93  std::uniform_int_distribution<> distrib_int(0, 5000);
94 
95 
96  long long max_inner_iterations_loc;
97  if ( config.count("max_inner_iterations_bfgs2") > 0 ) {
98  config["max_inner_iterations_bfgs2"].get_property( max_inner_iterations_loc );
99  }
100  else if ( config.count("max_inner_iterations") > 0 ) {
101  config["max_inner_iterations"].get_property( max_inner_iterations_loc );
102  }
103  else {
104  max_inner_iterations_loc =max_inner_iterations;
105  }
106 
107 
108  long long export_circuit_2_binary_loc;
109  if ( config.count("export_circuit_2_binary_bfgs2") > 0 ) {
110  config["export_circuit_2_binary_bfgs2"].get_property( export_circuit_2_binary_loc );
111  }
112  else if ( config.count("export_circuit_2_binary") > 0 ) {
113  config["export_circuit_2_binary"].get_property( export_circuit_2_binary_loc );
114  }
115  else {
116  export_circuit_2_binary_loc = 0;
117  }
118 
119 
120 
121  double optimization_tolerance_loc;
122  if ( config.count("optimization_tolerance_adam") > 0 ) {
123  config["optimization_tolerance_adam"].get_property( optimization_tolerance_loc );
124  }
125  else if ( config.count("optimization_tolerance") > 0 ) {
126  config["optimization_tolerance"].get_property( optimization_tolerance_loc );
127  }
128  else {
129  optimization_tolerance_loc = optimization_tolerance;
130  }
131 
132 
133  // The number if iterations after which the current results are displed/exported
134  int output_periodicity;
135  if ( config.count("output_periodicity_cosine") > 0 ) {
136  long long value = 1;
137  config["output_periodicity_cosine"].get_property( value );
138  output_periodicity = (int) value;
139  }
140  if ( config.count("output_periodicity") > 0 ) {
141  long long value = 1;
142  config["output_periodicity"].get_property( value );
143  output_periodicity = (int) value;
144  }
145  else {
146  output_periodicity = 0;
147  }
148 
149 
150 
151  std::stringstream sstream;
152  sstream << "max_inner_iterations: " << max_inner_iterations_loc << std::endl;
153  print(sstream, 2);
154 
155  // do the optimization loops
156  double f = DBL_MAX;
157  for (long long iter_idx=0; iter_idx<iteration_loops_max; iter_idx++) {
158 
159 
160  BFGS_Powell cBFGS_Powell(optimization_problem_combined, this);
161  double f = cBFGS_Powell.Start_Optimization(solution_guess, max_inner_iterations);
162 
163  if (sub_iter_idx == 1 ) {
164  current_minimum_hold = f;
165  }
166 
167 
168  if (current_minimum_hold*0.95 > f || (current_minimum_hold*0.97 > f && f < 1e-3) || (current_minimum_hold*0.99 > f && f < 1e-4) ) {
169  sub_iter_idx = 0;
170  current_minimum_hold = f;
171  }
172 
173 
174  if (current_minimum > f ) {
175  current_minimum = f;
176  memcpy( optimized_parameters_mtx.get_data(), solution_guess.get_data(), num_of_parameters*sizeof(double) );
177  }
178 
179 
180  if ( iter_idx % 5000 == 0 ) {
181  std::stringstream sstream;
182  sstream << "BFGS2: processed iterations " << (double)iter_idx/max_inner_iterations_loc*100 << "\%, current minimum:" << current_minimum << std::endl;
183  print(sstream, 2);
184 
185  if ( export_circuit_2_binary_loc>0) {
186  std::string filename("initial_circuit_iteration.binary");
187  if (project_name != "") {
188  filename=project_name+ "_" +filename;
189  }
191  }
192  }
193 
194 
195  if (f < optimization_tolerance_loc || random_shift_count > random_shift_count_max ) {
196  break;
197  }
198 
199 
200  sub_iter_idx++;
201  iter_idx++;
202 
203 
204 
205 
206  if (current_minimum > f) {
207  current_minimum = f;
208  memcpy( optimized_parameters_mtx.get_data(), solution_guess.get_data(), num_of_parameters*sizeof(double) );
209 
210  for ( int jdx=0; jdx<num_of_parameters; jdx++) {
211  solution_guess[jdx] = optimized_parameters_mtx[jdx] + distrib_real(gen)*2*M_PI/100;
212  }
213  }
214  else {
215  for ( int jdx=0; jdx<num_of_parameters; jdx++) {
216  solution_guess[jdx] = optimized_parameters_mtx[jdx] + distrib_real(gen)*2*M_PI;
217  }
218  }
219 
220  if ( output_periodicity>0 && iter_idx % output_periodicity == 0 ) {
222  }
223 
224 #ifdef __MPI__
225  MPI_Bcast( (void*)solution_guess.get_data(), num_of_parameters, MPI_DOUBLE, 0, MPI_COMM_WORLD);
226 #endif
227 
228 
229  if (current_minimum < optimization_tolerance_loc ) {
230  break;
231  }
232 
233 
234 
235  }
236 
237  tbb::tick_count bfgs_end = tbb::tick_count::now();
238  CPU_time = CPU_time + (bfgs_end-bfgs_start).seconds();
239  std::cout << "bfgs2 time: " << CPU_time << " " << current_minimum << std::endl;
240 
241 }
242 
243 
void export_current_cost_fnc(double current_minimum)
Call to print out into a file the current cost function and the second Rényi entropy on the subsyste...
void print(const std::stringstream &sstream, int verbose_level=1) const
Call to print output messages in the function of the verbosity level.
Definition: logging.cpp:55
double current_minimum
The current minimum of the optimization problem.
int get_accelerator_num()
Get the number of accelerators to be reserved on DFEs on users demand.
scalar * get_data() const
Call to get the pointer to the stored data.
std::vector< Gate * > gates
The list of stored gates.
Definition: Gates_block.h:46
A class implementing the BFGS optimizer based on conjugate gradient direction method of M...
Definition: BFGS_Powell.h:26
std::string project_name
the name of the project
double optimization_tolerance
The maximal allowed error of the optimization problem (The error of the decomposition would scale wit...
double Start_Optimization(Matrix_real &x, long maximal_iterations_in=5001)
Call this method to start the optimization.
std::map< int, int > iteration_loops
A map of <int n: int num> indicating the number of iteration in each step of the decomposition.
void solve_layer_optimization_problem_BFGS2(int num_of_parameters, Matrix_real solution_guess)
Call to solve layer by layer the optimization problem via BBFG algorithm.
Definition: BFGS2.cpp:42
double CPU_time
time spent on optimization
int verbose
Set the verbosity level of the output messages.
Definition: logging.h:50
int size() const
Call to get the number of the allocated elements.
static void optimization_problem_combined(Matrix_real parameters, void *void_instance, double *f0, Matrix_real &grad)
Call to calculate both the cost function and the its gradient components.
std::map< std::string, Config_Element > config
config metadata utilized during the optimization
Header file for the paralleized calculation of the cost function of the final optimization problem (s...
void export_gate_list_to_binary(Matrix_real &parameters, Gates_block *gates_block, const std::string &filename, int verbosity)
?????????
int qbit_num
number of qubits spanning the matrix of the operation
Definition: Gate.h:81
Header file for DFE support in unitary simulation.
int max_inner_iterations
the maximal number of iterations for which an optimization engine tries to solve the optimization pro...
int random_shift_count_max
the maximal number of parameter randomization tries to escape a local minimum.
Matrix_real optimized_parameters_mtx
The optimized parameters for the gates.
Class to store data of complex arrays and its properties.
Definition: matrix_real.h:39
std::mt19937 gen
Standard mersenne_twister_engine seeded with rd()