51 if (
gates.size() == 0 ) {
56 if (solution_guess.
size() == 0 ) {
67 int iteration_loops_max;
72 iteration_loops_max = 1;
82 tbb::tick_count bfgs_start = tbb::tick_count::now();
87 std::uniform_real_distribution<> distrib_real(0.0, 1.0);
90 long long max_inner_iterations_loc;
91 if (
config.count(
"max_inner_iterations_bfgs2") > 0 ) {
92 config[
"max_inner_iterations_bfgs2"].get_property( max_inner_iterations_loc );
94 else if (
config.count(
"max_inner_iterations") > 0 ) {
95 config[
"max_inner_iterations"].get_property( max_inner_iterations_loc );
102 long long export_circuit_2_binary_loc;
103 if (
config.count(
"export_circuit_2_binary_bfgs2") > 0 ) {
104 config[
"export_circuit_2_binary_bfgs2"].get_property( export_circuit_2_binary_loc );
106 else if (
config.count(
"export_circuit_2_binary") > 0 ) {
107 config[
"export_circuit_2_binary"].get_property( export_circuit_2_binary_loc );
110 export_circuit_2_binary_loc = 0;
115 double optimization_tolerance_loc;
116 if (
config.count(
"optimization_tolerance_adam") > 0 ) {
117 config[
"optimization_tolerance_adam"].get_property( optimization_tolerance_loc );
119 else if (
config.count(
"optimization_tolerance") > 0 ) {
120 config[
"optimization_tolerance"].get_property( optimization_tolerance_loc );
128 int output_periodicity;
129 if (
config.count(
"output_periodicity_cosine") > 0 ) {
131 config[
"output_periodicity_cosine"].get_property( value );
132 output_periodicity = (
int) value;
134 if (
config.count(
"output_periodicity") > 0 ) {
136 config[
"output_periodicity"].get_property( value );
137 output_periodicity = (
int) value;
140 output_periodicity = 0;
145 std::stringstream sstream;
146 sstream <<
"max_inner_iterations: " << max_inner_iterations_loc << std::endl;
149 long long use_basin_hopping = 0;
150 long long use_de = 0;
151 long long use_dual_annealing = 0;
152 if (
config.count(
"use_basin_hopping") > 0 ) {
153 config[
"use_basin_hopping"].get_property( use_basin_hopping );
154 }
else if (
config.count(
"use_differential_evolution") > 0 ) {
155 config[
"use_differential_evolution"].get_property( use_de );
156 }
else if (
config.count(
"use_dual_annealing") > 0 ) {
157 config[
"use_dual_annealing"].get_property( use_dual_annealing );
159 if (!use_basin_hopping && !use_de && !use_dual_annealing) {
160 use_dual_annealing = 1;
163 if (use_basin_hopping) {
166 double bh_stepsize = 0.5;
167 long long bh_interval = 50;
168 double bh_target_accept = 0.5;
169 double bh_stepwise_factor = 0.9;
171 if (
config.count(
"bh_T") > 0)
config[
"bh_T"].get_property(bh_T);
172 if (
config.count(
"bh_stepsize") > 0)
config[
"bh_stepsize"].get_property(bh_stepsize);
173 if (
config.count(
"bh_interval") > 0) {
long long v;
config[
"bh_interval"].get_property(v); bh_interval = std::max<long long>(1, v); }
174 if (
config.count(
"bh_target_accept_rate") > 0)
config[
"bh_target_accept_rate"].get_property(bh_target_accept);
175 if (
config.count(
"bh_stepwise_factor") > 0)
config[
"bh_stepwise_factor"].get_property(bh_stepwise_factor);
178 bh_target_accept = std::min(0.999, std::max(0.001, bh_target_accept));
179 if (!(bh_stepwise_factor > 0.0 && bh_stepwise_factor < 1.0)) bh_stepwise_factor = 0.9;
182 long long accept_count_window = 0;
183 long long window_len = 0;
184 long long no_improve_count = 0;
185 double stepsize_now = bh_stepsize;
196 for (
long long iter_idx=0; iter_idx<iteration_loops_max; iter_idx++) {
199 double delta = (distrib_real(
gen) * 2.0 - 1.0) * stepsize_now *
M_PI;
200 solution_guess[j] = fmod(solution_guess[j] + delta, 2.0 * M_PI);
207 if (f_trial <= current_minimum_hold) {
210 double dE = f_trial - current_minimum_hold;
211 double prob = std::exp(-dE / std::max(1e-300, bh_T));
212 accept = (distrib_real(
gen) < prob);
217 memcpy(x_current.
get_data(), solution_guess.
get_data(), num_of_parameters*
sizeof(double));
218 current_minimum_hold = f_trial;
219 ++accept_count_window;
221 memcpy(solution_guess.
get_data(), x_current.
get_data(), num_of_parameters*
sizeof(double));
230 no_improve_count = 0;
235 if ( iter_idx % 5000 == 0 ) {
236 std::stringstream sstream;
237 sstream <<
"BFGS2: processed iterations " << (double)iter_idx/max_inner_iterations_loc*100 <<
"%, current minimum:" <<
current_minimum << std::endl;
240 if ( export_circuit_2_binary_loc>0) {
241 std::string
filename(
"initial_circuit_iteration.binary");
249 if ( output_periodicity>0 && iter_idx % output_periodicity == 0 ) {
267 if (bh_interval > 0 && (window_len % bh_interval) == 0) {
268 double accept_rate = (double)accept_count_window / (
double)bh_interval;
270 if (accept_rate > bh_target_accept) {
271 stepsize_now /= bh_stepwise_factor;
273 stepsize_now *= bh_stepwise_factor;
276 accept_count_window = 0;
283 enum strategy_enum { STRAT_BEST1BIN, STRAT_RAND1BIN };
284 enum init_enum { INIT_RANDOM, INIT_LHS };
287 long long de_strategy = STRAT_BEST1BIN;
288 long long de_popsize = 15;
289 double de_mutation = 0.8;
290 double de_recombination = 0.7;
291 double de_tol = 1e-6;
292 long long de_init = INIT_RANDOM;
293 long long de_polish = 1;
296 if (
config.count(
"de_strategy") > 0)
config[
"de_strategy"].get_property(de_strategy);
297 if (
config.count(
"de_popsize") > 0)
config[
"de_popsize"].get_property(de_popsize);
298 if (
config.count(
"de_mutation") > 0)
config[
"de_mutation"].get_property(de_mutation);
299 if (
config.count(
"de_recombination") > 0)
config[
"de_recombination"].get_property(de_recombination);
300 if (
config.count(
"de_tol") > 0)
config[
"de_tol"].get_property(de_tol);
301 if (
config.count(
"de_init") > 0)
config[
"de_init"].get_property(de_init);
302 if (
config.count(
"de_polish") > 0) {
long long v;
config[
"de_polish"].get_property(v); de_polish = v ? 1 : 0; }
305 if (de_mutation <= 0.0) de_mutation = 0.8;
306 if (de_recombination < 0.0) de_recombination = 0.7;
else if (de_recombination > 1.0) de_recombination = 1.0;
307 if (de_popsize <= 0) de_popsize = 15;
310 int NP =
static_cast<int>(de_popsize * D);
311 NP = std::max(5, NP);
314 std::vector<Matrix_real> pop(NP,
Matrix_real(D, 1));
315 std::vector<double> fit(NP, DBL_MAX);
318 auto init_random = [&]() {
319 for (
int i = 0; i < NP; ++i) {
320 for (
int j = 0; j < D; ++j) {
321 pop[i][j] = distrib_real(
gen) * 2.0 *
M_PI;
326 auto init_lhs = [&]() {
328 std::vector<int> idx(NP);
329 for (
int i = 0; i < NP; ++i) idx[i] = i;
331 for (
int j = 0; j < D; ++j) {
332 std::shuffle(idx.begin(), idx.end(),
gen);
333 for (
int i = 0; i < NP; ++i) {
334 double a = (double)idx[i] / (
double)NP;
335 double b = (double)(idx[i] + 1) / (double)NP;
336 double r = a + (b - a) * distrib_real(
gen);
337 pop[i][j] = fmod(r * (2.0 *
M_PI), 2.0 *
M_PI);
342 if (de_init == INIT_LHS) init_lhs();
else init_random();
348 double best_f = DBL_MAX;
350 for (
int i = 0; i < NP; ++i) {
352 if (fit[i] < best_f) { best_f = fit[i]; best_i = i; }
360 std::vector<int> idx_all(NP);
361 for (
int i = 0; i < NP; ++i) idx_all[i] = i;
363 auto pick_3_distinct = [&](
int exclude) {
366 do { r1 = idx_all[std::uniform_int_distribution<int>(0, NP-1)(
gen)]; }
while (r1 == exclude);
367 do { r2 = idx_all[std::uniform_int_distribution<int>(0, NP-1)(
gen)]; }
while (r2 == exclude || r2 == r1);
368 do { r3 = idx_all[std::uniform_int_distribution<int>(0, NP-1)(
gen)]; }
while (r3 == exclude || r3 == r1 || r3 == r2);
369 return std::tuple<int,int,int>(r1, r2, r3);
373 long long gen_no_improve = 0;
374 double last_best = best_f;
376 for (
long long generation = 0; generation < iteration_loops_max; ++generation) {
378 for (
int i = 0; i < NP; ++i) {
380 if (de_strategy == STRAT_BEST1BIN) {
383 do { r1 = idx_all[std::uniform_int_distribution<int>(0, NP-1)(
gen)]; }
while (r1 == i || r1 == best_i);
384 do { r2 = idx_all[std::uniform_int_distribution<int>(0, NP-1)(
gen)]; }
while (r2 == i || r2 == r1 || r2 == best_i);
385 for (
int j = 0; j < D; ++j) {
386 mutant[j] = fmod(pop[best_i][j] + de_mutation * (pop[r1][j] - pop[r2][j]), 2.0 *
M_PI);
391 std::tie(r1, r2, r3) = pick_3_distinct(i);
392 for (
int j = 0; j < D; ++j) {
393 mutant[j] = fmod(pop[r1][j] + de_mutation * (pop[r2][j] - pop[r3][j]), 2.0 *
M_PI);
398 int jrand = std::uniform_int_distribution<int>(0, D - 1)(
gen);
399 for (
int j = 0; j < D; ++j) {
400 if (j == jrand || distrib_real(
gen) < de_recombination) {
401 trial[j] = mutant[j];
403 trial[j] = pop[i][j];
409 if (f_trial <= fit[i]) {
410 memcpy(pop[i].get_data(), trial.get_data(), D *
sizeof(double));
413 if (f_trial < best_f) {
427 if (generation % 50 == 0) {
428 std::stringstream sstream;
429 sstream <<
"DE: generation " << generation <<
"/" << iteration_loops_max
433 if (export_circuit_2_binary_loc > 0) {
434 std::string
filename(
"initial_circuit_iteration.binary");
440 if (output_periodicity > 0 && generation % output_periodicity == 0) {
453 if (std::abs(last_best - best_f) <= de_tol) {
460 if (gen_no_improve >= 1) {
470 double f_pol = cBFGS_Powell.
Start_Optimization(params, static_cast<long>(std::max<long long>(200, static_cast<long long>(D)*50)));
476 }
else if (use_dual_annealing) {
478 double da_initial_temp = 5230.0;
479 double da_restart_temp_ratio = 2e-5;
480 double da_visit = 2.62;
481 double da_accept = -5.0;
482 long long da_maxiter = iteration_loops_max;
483 long long da_maxfun = 10000000;
484 double da_tol = 1e-6;
485 long long da_no_local_search = 0;
486 if (
config.count(
"da_initial_temp") > 0)
config[
"da_initial_temp"].get_property(da_initial_temp);
487 if (
config.count(
"da_restart_temp_ratio") > 0)
config[
"da_restart_temp_ratio"].get_property(da_restart_temp_ratio);
488 if (
config.count(
"da_visit") > 0)
config[
"da_visit"].get_property(da_visit);
489 if (
config.count(
"da_accept") > 0)
config[
"da_accept"].get_property(da_accept);
490 if (
config.count(
"da_maxiter") > 0) {
491 long long v;
config[
"da_maxiter"].get_property(v);
492 da_maxiter = std::max<long long>(1, v);
494 if (
config.count(
"da_maxfun") > 0) {
495 long long v;
config[
"da_maxfun"].get_property(v);
496 da_maxfun = std::max<long long>(1, v);
498 if (
config.count(
"da_tol") > 0)
config[
"da_tol"].get_property(da_tol);
499 if (
config.count(
"da_no_local_search") > 0) {
500 long long v;
config[
"da_no_local_search"].get_property(v);
501 da_no_local_search = v ? 1 : 0;
505 if (da_initial_temp <= 0.0) da_initial_temp = 5230.0;
506 if (da_restart_temp_ratio <= 0.0 || da_restart_temp_ratio >= 1.0) da_restart_temp_ratio = 2e-5;
507 if (da_visit <= 1.0) da_visit = 2.62;
512 for (
int j = 0; j < D; ++j) {
513 solution_guess[j] = std::fmod(solution_guess[j], 2.0 *
M_PI);
521 double f_best = f_current;
526 double last_best = f_best;
527 int restart_count = 0;
530 for (
long long k = 0;
k < da_maxiter && nfev < da_maxfun; ++
k) {
533 double Tk = da_initial_temp / (1.0 + (double)
k + (
double)restart_count);
536 if (Tk < da_initial_temp * da_restart_temp_ratio) {
541 Tk = da_initial_temp / (1.0 + (double)restart_count);
548 for (
int j = 0; j < D; ++j) {
549 double u = distrib_real(
gen);
550 double sign = (u < 0.5) ? -1.0 : 1.0;
551 double v = distrib_real(
gen);
553 double step_mag = std::pow(1.0 / std::max(1e-12, v), 1.0 / (da_visit - 1.0)) - 1.0;
555 double step = sign * step_mag * Tk / da_initial_temp * (2.0 *
M_PI);
556 x_trial[j] = std::fmod(solution_guess[j] + step, 2.0 *
M_PI);
564 if (f_trial <= f_current) {
567 double dE = f_trial - f_current;
569 double scale = std::pow(std::max(1e-12, Tk / da_initial_temp), -da_accept);
570 scale = std::max(scale, 1e-12);
571 double prob = std::exp(-dE / scale);
572 if (distrib_real(
gen) < prob) {
583 if (f_trial < f_best) {
592 std::stringstream sstream;
593 sstream <<
"Dual annealing: iter " <<
k <<
"/" << da_maxiter
595 <<
", T=" << Tk << std::endl;
598 if (export_circuit_2_binary_loc > 0) {
599 std::string
filename(
"initial_circuit_iteration.binary");
605 if (output_periodicity > 0 &&
k % output_periodicity == 0) {
620 if (std::abs(last_best - f_best) <= da_tol) {
629 if (!da_no_local_search) {
643 tbb::tick_count bfgs_end = tbb::tick_count::now();
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.
Matrix_real copy() const
Call to create a copy of the matrix.
int get_accelerator_num()
Get the number of accelerators to be reserved on DFEs on users demand.
double optimization_problem(double *parameters)
Evaluate the optimization problem of the optimization.
scalar * get_data() const
Call to get the pointer to the stored data.
std::vector< Gate * > gates
The list of stored gates.
A class implementing the BFGS optimizer based on conjugate gradient direction method of M...
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.
double CPU_time
time spent on optimization
int verbose
Set the verbosity level of the output messages.
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...
volatile double current_minimum
The current minimum of the optimization problem.
void export_gate_list_to_binary(Matrix_real ¶meters, Gates_block *gates_block, const std::string &filename, int verbosity)
Use to export a quantum circuit into binary format.
int qbit_num
number of qubits spanning the matrix of the operation
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.
std::mt19937 gen
Standard mersenne_twister_engine seeded with rd()