Sequential Quantum Gate Decomposer  v1.9.6
Powerful decomposition of general unitarias into one- and two-qubit gates gates
common/Bayes_Opt.cpp
Go to the documentation of this file.
1 /*
2 Copyright 2020 Peter Rakyta, Ph.D.
3 
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #define _USE_MATH_DEFINES
20 #include <math.h>
21 #include <cfloat>
22 #include <Bayes_Opt.h>
23 #include <Powells_method.h>
24 #include <common.h>
25 #include "tbb/tbb.h"
26 
27 extern "C" int LAPACKE_dposv(int matrix_layout, char uplo, int n, int nrhs, double* A, int LDA, double* B, int LDB);
28 
29 
35 
36  double* params = (double*)void_params;
37 
38  return params[0]*sin(2*parameters[0] + params[1]) + params[2]*sin(parameters[0] + params[3] ) + params[4];
39 }
40 
41 
47 
48  double* params = (double*)void_params;
49 
50  return params[0]*cos(4*parameters[0] + params[1]) + params[2]*cos(2*parameters[0] + params[3] ) + params[4];
51 }
52 
53 
59 
60 
61  double* params = (double*)void_params;
62  grad[0] = 2*params[0]*cos(2*parameters[0] + params[1]) + params[2]*cos(parameters[0] + params[3] );
63 
64 }
65 
66 
72 
73 
74  double* params = (double*)void_params;
75  grad[0] = -4*params[0]*sin(4*parameters[0] + params[1]) - 2*params[2]*sin(2*parameters[0] + params[3] );
76 
77 }
78 
83 void HS_partial_optimization_problem_combined( Matrix_real parameters, void* void_params, double* f0, Matrix_real& grad) {
84 
85  *f0 = HS_partial_optimization_problem( parameters, void_params );
86  HS_partial_optimization_problem_grad( parameters, void_params, grad);
87 
88 
89 }
90 
96 
97  *f0 = HS_partial_optimization_problem_cos( parameters, void_params );
98  HS_partial_optimization_problem_cos_grad( parameters, void_params, grad);
99 
100 
101 }
102 
103 
104 
111 Bayes_Opt::Bayes_Opt(double (* f_pointer) (Matrix_real, void *), void* meta_data_in) {
112 
113  maximal_iterations = 101;
114 
115  // numerical precision used in the calculations
116  num_precision = 1.42e-14;
117 
118  alpha0 = 1;
119 
120  costfnc = f_pointer;
121 
122  meta_data = meta_data_in;
123 
124 
125  initial_samples = 12;
126 
127  mu_0 = M_PI;
128 
129  current_maximum = -10000.;
130 
131  // Will be used to obtain a seed for the random number engine
132  std::random_device rd;
133 
134  // seedign the random generator
135  gen = std::mt19937(rd());
136 
137 }
138 
139 double Bayes_Opt::Start_Optimization(Matrix_real& x, int max_iterations_in){
140 
141  variable_num = x.size();
142 
143 
144  maximal_iterations = max_iterations_in;
145 
146  //get samples of f0 at n0 points
147  for (int sample_idx=0; sample_idx<initial_samples; sample_idx++){
148  Matrix_real covariance_new(sample_idx,sample_idx);
149  Matrix_real parameters_new(1,variable_num);
150  std::normal_distribution<> distrib_real(0, M_PI/4);
151  double f_random;
152  for(int idx = 0; idx < variable_num; idx++) {
153  double random = distrib_real(gen);
154  parameters_new[idx] = x[idx] + random;
155  }
156  f_random = -1.*costfnc(parameters_new,meta_data);
157 
158  x_prev.push_back(parameters_new);
159  f_prev.push_back(f_random);
160  if (f_random>current_maximum) {
161  current_maximum = f_random;
162  memcpy(x.get_data(),parameters_new.get_data(),sizeof(double)*variable_num);
163  }
164  }
165  //construct covariance matrix
166  covariance = Matrix_real(initial_samples,initial_samples);
167  for (int idx=0; idx<initial_samples; idx++){
168  for (int jdx=0; jdx<initial_samples; jdx++){
169  covariance[idx*initial_samples + jdx] = kernel(x_prev[idx],x_prev[jdx]);
170  if (idx==jdx){
171  covariance[idx*initial_samples + jdx] = covariance[idx*initial_samples + jdx] +1e-4;
172  }
173  }
174  }
175 
176  //Start optimization
177  int iterations = initial_samples;
178  for (int iter = iterations; iter<maximal_iterations;iter++){
179 
180 
181  Matrix_real solution_guess = x_prev[iterations-1];
182 
183  Powells_method cPowells_method(optimization_problem,this);
184  cPowells_method.Start_Optimization(solution_guess, 100);
185  double f = -1.*costfnc(solution_guess,meta_data);
186 
187  Matrix_real cov_x(1,(int)x_prev.size());
188 
189  for (int idx=0; idx<(int)x_prev.size();idx++){
190  cov_x[idx] = kernel(x_prev[idx],solution_guess);
191  }
192 
193  update_covariance(cov_x);
194  x_prev.push_back(solution_guess);
195  f_prev.push_back(f);
196  if (f>current_maximum){
197  current_maximum = f;
198  memcpy(x.get_data(),solution_guess.get_data(),sizeof(double)*variable_num);
199  }
200  /*Grad_Descend cBFGS_Powell(optimization_problem_combined, this);
201 
202  double f_bfgs = cBFGS_Powell.Start_Optimization(solution_guess, 100);
203  //solution_guess.print_matrix();
204  double f = -1.*costfnc(solution_guess,meta_data);
205 
206 
207  Matrix_real cov_x(1,(int)x_prev.size());
208  double self_cov = 1e-4;
209 
210  for (int idx=0; idx<(int)x_prev.size();idx++){
211  cov_x[idx] = kernel(x_prev[idx],solution_guess);
212  }
213 
214  update_covariance(cov_x);
215 
216  x_prev.push_back(solution_guess);
217  f_prev.push_back(f);
218  if (f>current_maximum){
219  current_maximum = f;
220  memcpy(solution_guess.get_data(),x.get_data(),sizeof(double)*variable_num);
221  }
222 
223  //std::cout<<iter<<std::endl;*/
224 
225  }
226  return -1.*current_maximum;
227 
228 }
229 
230 double Bayes_Opt::optimization_problem(Matrix_real x_Powell, void* void_instance){
231  Bayes_Opt* instance = reinterpret_cast<Bayes_Opt*>(void_instance);
232  int samples_n = (int)instance->x_prev.size();
233  Matrix_real cov_x(1,samples_n);
234  for (int idx=0; idx<samples_n; idx++){
235  cov_x[idx] = instance->kernel(x_Powell,(Matrix_real)instance->x_prev[idx]);
236  }
237  double mu_n = 0.0;
238  double sigma2_n = 0.0;
239  instance->calculate_conditional_distribution(x_Powell, cov_x, mu_n, sigma2_n);
240  double sigma_n = std::sqrt(std::fabs(sigma2_n));
241  double EI = -1.0*instance->expected_improvement(mu_n, sigma_n);
242  return EI;
243 }
244 
245 double Bayes_Opt::expected_improvement(double mu_n, double sigma_n){
246  double deltax = mu_n - current_maximum;
247  double deltax_max = (deltax>0.) ? deltax:0.0;
248 
249  double EI = deltax_max + sigma_n*pdf(deltax,sigma_n) - fabs(deltax)*cdf(deltax,sigma_n);
250  return EI;
251 }
252 
253 
254 void Bayes_Opt::calculate_conditional_distribution(Matrix_real x, Matrix_real cov_x, double& mu_n, double& sigma2_n){
255  double tol = 1e-6;
256  int samples = (int)f_prev.size();
257  Matrix_real mu_rhs(1,samples);
258  Matrix_real x0(1,samples);
259  for (int idx=0;idx<samples;idx++){
260  mu_rhs[idx] = f_prev[idx] - mu_0;
261  x0[idx] = M_PI;
262  }
263 
264  conjugate_gradient(covariance,mu_rhs,x0,tol);
265 
266  for (int idx=0;idx<samples;idx++){
267  mu_n = mu_n + x0[idx]*cov_x[idx];
268  }
269 
270  Matrix_real sigma2_rhs = cov_x.copy();
271  memset(x0.get_data(), 0, samples*sizeof(double) );
272  for (int i = 0; i < samples; i++) {
273  x0[i] = M_PI;
274  }
275  conjugate_gradient(covariance,mu_rhs,x0,tol);
276 
277  for (int idx=0;idx<mu_rhs.cols;idx++){
278  sigma2_n = sigma2_n + x0[idx] * cov_x[idx];
279  }
280 
281  sigma2_n = -1.0*(sigma2_n - kernel(x,x));
282 
283 
284  return;
285 
286 }
287 
288 
289 
291 
292  double dist=0.;
293  double sigma01 = 0.;
294  for (int idx=0; idx<variable_num; idx++){
295  dist = dist + (x0[idx]-x1[idx])*(x0[idx]-x1[idx]);
296  }
297  dist = std::sqrt(dist)/variable_num/variable_num;
298  sigma01 = alpha0*std::exp(-1.*std::sin(2*dist)*std::sin(2*dist)) + 1e-6;
299 
300  return sigma01;
301 
302 }
303 
304 double Bayes_Opt::pdf(double mu, double sigma){
305  return 1/sigma/std::sqrt(2*M_PI)*std::exp(0.5*(mu/sigma)*(mu/sigma));
306 }
307 
308 double Bayes_Opt::cdf(double mu, double sigma){
309  return 0.5+0.5*std::erf(mu/sigma/std::sqrt(2));
310 }
311 
312 double Bayes_Opt::grad_pdf(double mu, double sigma, double grad_mu, double grad_sigma){
313  return -1.0/sigma*grad_sigma*pdf(mu,sigma) - pdf(mu,sigma)*(grad_mu*sigma - mu*grad_sigma)/sigma/sigma;
314 }
315 
317 
318  int samples = covariance.cols+1;
319 
320  Matrix_real covariance_new(samples,samples);
321  double* data_new = covariance_new.get_data();
322  double* data_old = covariance.get_data();
324 
325  //copy old covariance matrix
326 
327  for (int idx=0;idx<covariance.cols; idx++){
328  memcpy(data_new + samples*idx,data_old + idx*covariance.cols,sizeof(double)*covariance.cols);
329  covariance_new[samples-1+idx*samples] = cov_new[idx];
330  }
331 
332  memcpy(data_new + (samples-1)*samples,cov_new.get_data(),sizeof(double)*covariance.cols);
333  covariance_new[samples*samples-1] = alpha0;
334 
335  covariance = covariance_new;
336  return;
337 }
338 
339 void Bayes_Opt::kernel_combined(Matrix_real x0, Matrix_real x, double& f, Matrix_real& grad, int grad_var, bool self){
340 
341  double dist=0.;
342  for (int idx=0; idx<variable_num; idx++){
343  dist = dist + (x0[idx]-x[idx])*(x0[idx]-x[idx]);
344  }
345  dist = std::sqrt(dist);
346  double cost_func_base = alpha0*std::exp(-1.*dist) + 1e-6;
347  f = cost_func_base;
348  for (int grad_idx=0; grad_idx<variable_num; grad_idx++){
349  double x1 = x[grad_idx];
350  grad[grad_var*variable_num + grad_idx] = 0.;
351  for (int idx=0; idx<variable_num; idx++){
352  if (grad_idx == idx && self == true){
353  grad[grad_var*variable_num + grad_idx] = 0.;
354  continue;
355  }
356  grad[grad_var*variable_num + grad_idx] = grad[grad_var*variable_num + grad_idx] - cost_func_base*(2.*x1-2.*x0[idx]);
357  }
358  }
359  return;
360 
361 }
362 
363 void Bayes_Opt::calculate_conditional_distribution_combined(Matrix_real x, Matrix_real cov_x, Matrix_real cov_x_grad, Matrix_real cov_self_grad, double& mu_n, double& sigma2_n, Matrix_real& grad_mu, Matrix_real& grad_sigma){
364 
365  int samples = (int)f_prev.size();
366  double tol = 1e-4;
367  Matrix_real b(1,samples);
368  Matrix_real mu_rhs(1,samples);
369  Matrix_real sigma2_rhs(1,samples);
370 
371 
372  Matrix_real sigma2_grad_rhs (samples,variable_num);
373  for (int idx=0;idx<samples;idx++){
374  b[idx] = f_prev[idx] - mu_0;
375  mu_rhs[idx] = 1.0;
376  sigma2_rhs[idx] = M_PI;
377  }
378  conjugate_gradient(covariance,b,mu_rhs,tol);
379  mu_n = 0.;
380  for (int idx=0; idx<samples; idx++){
381  mu_n = mu_n + mu_rhs[idx]*cov_x[idx];
382  }
383  mu_n = std::fabs(mu_n);
384  for (int grad_idx=0; grad_idx<variable_num; grad_idx++){
385  for (int idx=0;idx<samples;idx++){
386  grad_mu[grad_idx] = grad_mu[grad_idx] + cov_x_grad[idx*variable_num + grad_idx]*mu_rhs[idx];
387  //sigma2_grad_rhs[idx*variable_num + grad_idx] = M_PI;
388  }
389  }
390 
391  b = cov_x.copy();
392 
393  conjugate_gradient(covariance,b,sigma2_rhs,tol);
394  sigma2_n = 0.;
395  for (int idx=0;idx<samples;idx++){
396  sigma2_n = sigma2_n + sigma2_rhs[idx] * cov_x[idx];
397  }
398  sigma2_n = kernel(x,x)-sigma2_n;
399  //std::cout<<mu_n<<" "<<sigma2_n<<std::endl;
400  //b = cov_x_grad.copy();
401  // conjugate_gradient_parallel(covariance,b,sigma2_grad_rhs,tol);
402  for (int grad_idx=0; grad_idx<variable_num; grad_idx++){
403  b = Matrix_real(1,samples);
404  for (int idx=0;idx<samples;idx++){
405  b[idx] = cov_x_grad[idx*variable_num+grad_idx];
406  }
407  conjugate_gradient(covariance,b,sigma2_rhs,tol);
408  grad_sigma[grad_idx] = cov_self_grad[grad_idx];
409  for (int idx=0;idx<samples;idx++){
410  grad_sigma[grad_idx] = grad_sigma[grad_idx] - 2.*cov_x_grad[idx*variable_num + grad_idx];
411  }
412  grad_sigma[grad_idx] = grad_sigma[grad_idx]/std::sqrt(sigma2_n)/2;
413  }
414  //grad_sigma.print_matrix();
415  return;
416 
417 }
418 
419 void Bayes_Opt::expected_improvement_combined(double mu_n, double sigma_n, Matrix_real& grad_mu, Matrix_real& grad_sigma, double* f, Matrix_real& grad){
420  double deltax = mu_n - current_maximum;
421  double deltax_max = (deltax>0.) ? deltax:0.0;
422 
423  double pdf_mu = pdf(mu_n,sigma_n);
424  double cdf_mu = cdf(mu_n,sigma_n);
425  *f = -1.*(deltax_max + sigma_n*pdf_mu - fabs(deltax)*cdf_mu);
426 
427  for (int idx=0; idx<variable_num; idx++){
428  /*
429  double deltax_grad = grad_mu[idx];
430  double deltax_max_grad = (deltax_grad>0.) ? grad_mu[idx] : 0.0;
431  double grad_rhs = -1.*std::fabs(deltax_grad)*cdf_mu - std::fabs(deltax)*pdf_mu*(grad_mu[idx]*sigma_n-mu_n*grad_sigma[idx])/sigma_n/sigma_n;
432  double grad_lhs = grad_sigma[idx]*pdf_mu + sigma_n*grad_pdf(mu_n,sigma_n,grad_mu[idx],grad_sigma[idx]);
433  */
434  grad[idx] = -1.;//*(deltax_max_grad + grad_lhs + grad_rhs);
435  }
436  return;
437 }
438 void Bayes_Opt::optimization_problem_combined(Matrix_real x_bfgs, void* void_instance, double* f0, Matrix_real& grad ){
439 
440  Bayes_Opt* instance = reinterpret_cast<Bayes_Opt*>(void_instance);
441  int samples_n = (int)instance->x_prev.size();
442  int parameter_num = instance->variable_num;
443  Matrix_real cov_x(1,samples_n);
444  Matrix_real cov_x_grad(samples_n,parameter_num);
445  //x_bfgs.print_matrix();
446  for (int grad_idx=0; grad_idx<samples_n; grad_idx++){
447  double cov_new;
448  instance->kernel_combined(x_bfgs, (Matrix_real)instance->x_prev[grad_idx], cov_new, cov_x_grad, grad_idx, false);
449  cov_x[grad_idx] = cov_new;
450  }
451  //cov_x_grad.print_matrix();
452  double placeholder;
453  Matrix_real cov_self_grad(1,parameter_num);
454 
455  instance->kernel_combined(x_bfgs, x_bfgs, placeholder,cov_self_grad,0,true);
456 
457  double mu_n = M_PI;
458  double sigma2_n;
459  Matrix_real grad_mu(1,parameter_num);
460  Matrix_real grad_sigma(1,parameter_num);
461 
462  instance -> calculate_conditional_distribution_combined(x_bfgs, cov_x, cov_x_grad, cov_self_grad, mu_n, sigma2_n, grad_mu, grad_sigma);
463 
464  double sigma_n = std::sqrt(sigma2_n);
465  instance -> expected_improvement_combined(mu_n,sigma_n,grad_mu,grad_sigma,f0,grad);
466  //grad.print_matrix();
467  return;
468 }
473 
474 }
475 
476 
477 
478 Bayes_Opt_Beam::Bayes_Opt_Beam(double (* f_pointer) (Matrix_real, void *), void* meta_data_in, int start_in, Matrix_real parameters_original_in) {
479 
480  maximal_iterations = 101;
481 
482  costfnc = f_pointer;
483 
484  meta_data = meta_data_in;
485 
486  current_maximum = -10000.;
487 
488  // Will be used to obtain a seed for the random number engine
489  std::random_device rd;
490 
491  // seedign the random generator
492  gen = std::mt19937(rd());
493 
494  parameters = parameters_original_in;
495 
496  start = start_in;
497 
498 
499 }
500 
501 
502 
503 double Bayes_Opt_Beam::optimization_problem(Matrix_real x_Beam, void* void_instance){
504  Bayes_Opt_Beam* instance = reinterpret_cast<Bayes_Opt_Beam*>(void_instance);
505  Matrix_real x = instance->parameters.copy();
506  memcpy(x.get_data() + instance->start,x_Beam.get_data(),sizeof(double)*x_Beam.size());
507  return instance->costfnc(x,instance->meta_data);
508 }
509 
510 
511 
512 double Bayes_Opt_Beam::Start_Optimization(Matrix_real& x, int max_iterations_in){
513 
514  variable_num = x.size();
515 
516  maximal_iterations = max_iterations_in;
517  Bayes_Opt cBayes_opt(optimization_problem,this);
518  double f = cBayes_opt.Start_Optimization(x,maximal_iterations);
519 
520  return f;
521 }
523 
524 }
parameter_num
[set adaptive gate structure]
void conjugate_gradient(Matrix_real A, Matrix_real b, Matrix_real &x0, double tol)
Definition: common.cpp:485
std::vector< double > f_prev
Definition: Bayes_Opt.h:110
Matrix_real copy() const
Call to create a copy of the matrix.
Matrix_real covariance
covariance matrix
Definition: Bayes_Opt.h:85
void HS_partial_optimization_problem_cos_combined(Matrix_real parameters, void *void_params, double *f0, Matrix_real &grad)
???????????????
A class implementing the BayesOpt algorithm as seen in: https://browse.arxiv.org/pdf/1807.02811.pdf.
Definition: Bayes_Opt.h:79
double HS_partial_optimization_problem(Matrix_real parameters, void *void_params)
???????????????
double current_maximum
Definition: Bayes_Opt.h:114
std::mt19937 gen
Definition: Bayes_Opt.h:119
double Start_Optimization(Matrix_real &x, int max_iterations_in)
double expected_improvement(double mu_n, double sigma_n)
double grad_pdf(double mu, double sigma, double grad_mu, double grad_sigma)
scalar * get_data() const
Call to get the pointer to the stored data.
double Start_Optimization(Matrix_real &x, int max_iterations_in)
Matrix_real parameters
Definition: Bayes_Opt.h:176
int initial_samples
Definition: Bayes_Opt.h:117
double alpha0
amplitude of the kernel
Definition: Bayes_Opt.h:97
int cols
The number of columns.
Definition: matrix_base.hpp:44
long maximal_iterations
maximal count of iterations during the optimization
Definition: Bayes_Opt.h:91
void * meta_data
additional data needed to evaluate the cost function
Definition: Bayes_Opt.h:171
double mu_0
constant for the mean function
Definition: Bayes_Opt.h:82
#define M_PI
Definition: qgd_math.h:42
double Start_Optimization(Matrix_real &x, long max_iter)
Bayes_Opt(double(*f_pointer)(Matrix_real, void *), void *meta_data_in)
Constructor of the class.
Bayes_Opt_Beam(double(*f_pointer)(Matrix_real, void *), void *meta_data_in, int start_in, Matrix_real parameters_original_in)
double kernel(Matrix_real x0, Matrix_real x1)
double num_precision
numerical precision used in the calculations
Definition: Bayes_Opt.h:94
int size() const
Call to get the number of the allocated elements.
A class implementing the Powells-algorithm as seen in: https://academic.oup.com/comjnl/article-abstra...
void update_covariance(Matrix_real cov_new)
list sigma
Definition: GQML_test.py:51
double(* costfnc)(Matrix_real x, void *params)
function pointer to evaluate the cost function and its gradient vector
Definition: Bayes_Opt.h:100
void HS_partial_optimization_problem_grad(Matrix_real parameters, void *void_params, Matrix_real &grad)
???????????????
std::vector< Matrix_real > x_prev
previous parameters
Definition: Bayes_Opt.h:106
double cdf(double mu, double sigma)
static double optimization_problem(Matrix_real x_Beam, void *void_instance)
double pdf(double mu, double sigma)
Header file for commonly used functions and wrappers to CBLAS functions.
~Bayes_Opt()
Destructor of the class.
double HS_partial_optimization_problem_cos(Matrix_real parameters, void *void_params)
???????????????
int LAPACKE_dposv(int matrix_layout, char uplo, int n, int nrhs, double *A, int LDA, double *B, int LDB)
void calculate_conditional_distribution(Matrix_real x, Matrix_real cov_x, double &mu_n, double &sigma2_n)
static void optimization_problem_combined(Matrix_real x, void *void_instance, double *f0, Matrix_real &grad)
void HS_partial_optimization_problem_combined(Matrix_real parameters, void *void_params, double *f0, Matrix_real &grad)
???????????????
void expected_improvement_combined(double mu_n, double sigma_n, Matrix_real &grad_mu, Matrix_real &grad_sigma, double *f, Matrix_real &grad)
void kernel_combined(Matrix_real x0, Matrix_real x, double &f, Matrix_real &grad, int grad_var, bool self)
int variable_num
number of independent variables in the problem
Definition: Bayes_Opt.h:88
void * meta_data
additional data needed to evaluate the cost function
Definition: Bayes_Opt.h:103
void calculate_conditional_distribution_combined(Matrix_real x, Matrix_real cov_x, Matrix_real cov_x_grad, Matrix_real cov_self_grad, double &mu_n, double &sigma2_n, Matrix_real &grad_mu, Matrix_real &grad_sigma)
Class to store data of complex arrays and its properties.
Definition: matrix_real.h:41
static double optimization_problem(Matrix_real x_Powell, void *void_instance)
void HS_partial_optimization_problem_cos_grad(Matrix_real parameters, void *void_params, Matrix_real &grad)
???????????????
double(* costfnc)(Matrix_real x, void *params)
function pointer to evaluate the cost function and its gradient vector
Definition: Bayes_Opt.h:168