3
3
4
4
#include < algorithm>
5
5
#include < cmath>
6
+ #include < limits>
6
7
7
8
#include " globals.h"
8
9
#include " place_macro.h"
10
+ #include " vpr_context.h"
11
+ #include " vpr_error.h"
9
12
#include " vpr_types.h"
10
13
#include " place_util.h"
11
14
#include " placer_state.h"
@@ -291,11 +294,145 @@ PlacementAnnealer::PlacementAnnealer(const t_placer_opts& placer_opts,
291
294
}
292
295
293
296
float PlacementAnnealer::estimate_starting_temperature_ () {
297
+
294
298
if (placer_opts_.anneal_sched .type == e_sched_type::USER_SCHED) {
295
299
return placer_opts_.anneal_sched .init_t ;
296
300
}
297
301
298
- const auto & cluster_ctx = g_vpr_ctx.clustering ();
302
+ switch (placer_opts_.anneal_init_t_estimator ) {
303
+ case e_anneal_init_t_estimator::COST_VARIANCE:
304
+ return estimate_starting_temp_using_cost_variance_ ();
305
+ case e_anneal_init_t_estimator::EQUILIBRIUM_EST:
306
+ return estimate_equilibrium_temp_ ();
307
+ default :
308
+ VPR_FATAL_ERROR (VPR_ERROR_PLACE,
309
+ " Unrecognized initial temperature estimator type" );
310
+ };
311
+ }
312
+
313
+ float PlacementAnnealer::estimate_equilibrium_temp_ () {
314
+ const ClusteringContext& cluster_ctx = g_vpr_ctx.clustering ();
315
+
316
+ // Determines the block swap loop count.
317
+ // TODO: Revisit this. We may be able to get away with doing fewer trial
318
+ // swaps. That or we may be able to get a more accurate initial
319
+ // temperature by doing more moves.
320
+ int move_lim = std::min (annealing_state_.move_lim_max , (int )cluster_ctx.clb_nlist .blocks ().size ());
321
+
322
+ // Perform N trial swaps and collect the change in cost for each of these
323
+ // swaps. Accepted swaps are swaps which resulted in a negative change in
324
+ // cost, rejected swaps are swaps which resulted in a positive change in
325
+ // cost.
326
+ std::vector<double > accepted_swaps;
327
+ std::vector<double > rejected_swaps;
328
+ accepted_swaps.reserve (move_lim);
329
+ rejected_swaps.reserve (move_lim);
330
+ for (int i = 0 ; i < move_lim; i++) {
331
+ bool manual_move_enabled = false ;
332
+ #ifndef NO_GRAPHICS
333
+ // Checks manual move flag for manual move feature
334
+ t_draw_state* draw_state = get_draw_state_vars ();
335
+ if (draw_state->show_graphics ) {
336
+ manual_move_enabled = manual_move_is_selected ();
337
+ }
338
+ #endif /* NO_GRAPHICS*/
339
+
340
+ t_swap_result swap_result = try_swap_ (*move_generator_1_,
341
+ placer_opts_.place_algorithm ,
342
+ manual_move_enabled);
343
+
344
+ if (swap_result.move_result == e_move_result::ACCEPTED) {
345
+ accepted_swaps.push_back (swap_result.delta_c );
346
+ // TODO: Look into not actually accepting these.
347
+ swap_stats_.num_swap_accepted ++;
348
+ } else if (swap_result.move_result == e_move_result::ABORTED) {
349
+ // Note: We do not keep track of the change in cost due to aborted
350
+ // swaps. These are not interesting for this approach.
351
+ swap_stats_.num_swap_aborted ++;
352
+ } else {
353
+ rejected_swaps.push_back (swap_result.delta_c );
354
+ swap_stats_.num_swap_rejected ++;
355
+ }
356
+ }
357
+
358
+ // Computed the total change in cost due to accepted swaps.
359
+ double total_accepted_cost = 0.0 ;
360
+ for (double accepted_cost : accepted_swaps) {
361
+ total_accepted_cost += accepted_cost;
362
+ }
363
+
364
+ // Perform a binary search to try and find the equilibrium temperature for
365
+ // this placement. This is the temperature that we expect would lead to no
366
+ // overall change in temperature. We do this by computing the expected
367
+ // change in cost given a trial temperature and try larger / smaller
368
+ // temperatures until one is found that causes the change cost is close to
369
+ // 0. Since the expected change in cost is monotonically increasing for
370
+ // all positive temperatures, this method will return a unique result if it
371
+ // exists within this range.
372
+ // Initialize the lower bound temperature to 0. The temperature cannot
373
+ // be less than 0.
374
+ double lower_bound_temp = 0.0 ;
375
+ // Initialize the upper bound temperature to 1e10. It is possible for
376
+ // the equilibrium temperature to be infinite if the initial placement
377
+ // is so bad that no swaps are accepted. In that case this value will
378
+ // be returned instead of infinity.
379
+ // TODO: Find what a reasonable value for this should be.
380
+ double upper_bound_temp = 1e10 ;
381
+ // The max search iterations should never be hit, but it is here as an
382
+ // exit condition to prevent infinite loops.
383
+ constexpr unsigned max_search_iters = 100 ;
384
+ for (unsigned binary_search_iter = 0 ; binary_search_iter < max_search_iters; binary_search_iter++) {
385
+ // Exit condition for binary search. Could be hit if the lower and upper
386
+ // bounds are arbitrarily close.
387
+ if (lower_bound_temp > upper_bound_temp)
388
+ break ;
389
+
390
+ // Try the temperature in the middle of the lower and upper bounds.
391
+ double trial_temp = (lower_bound_temp + upper_bound_temp) / 2.0 ;
392
+
393
+ // Calculate the expected change in cost at this temperature (which we
394
+ // call the residual here).
395
+ double expected_total_post_rejected_cost = 0.0 ;
396
+ for (double rejected_cost : rejected_swaps) {
397
+ // Expected change in cost after a rejected swap is the change in
398
+ // cost multiplied by the probability that this swap is accepted at
399
+ // this temperature.
400
+ double accpetance_prob = std::exp ((-1.0 * rejected_cost) / trial_temp);
401
+ expected_total_post_rejected_cost += rejected_cost * accpetance_prob;
402
+ }
403
+ double residual = expected_total_post_rejected_cost + total_accepted_cost;
404
+
405
+ // Return the trial temperature if it is within 6 decimal-points of precision.
406
+ // NOTE: This is arbitrary.
407
+ // TODO: We could stop this early and then use Newton's Method to quickly
408
+ // touch it up to a more accurate value.
409
+ if (std::abs (upper_bound_temp - lower_bound_temp) / trial_temp < 1e-6 )
410
+ return trial_temp;
411
+
412
+ if (residual < 0 ) {
413
+ // Since the function is monotonically increasing, if the residual
414
+ // is negative, then the lower bound should be raised to the trial
415
+ // temperature.
416
+ lower_bound_temp = trial_temp;
417
+ } else if (residual > 0 ) {
418
+ // Similarly, if the residual is positive, then the upper bound should
419
+ // be lowered to the trial temperature.
420
+ upper_bound_temp = trial_temp;
421
+ } else {
422
+ // If we happened to exactly hit the risidual, then this is the
423
+ // exact temperature we should use.
424
+ return trial_temp;
425
+ }
426
+ }
427
+
428
+ // If we get down here, it means that the upper loop did not reach a solution;
429
+ // however, we know that the answer should be somewhere between lower and upper
430
+ // bound. Therefore, return the average of the two.
431
+ return (lower_bound_temp + upper_bound_temp) / 2.0 ;
432
+ }
433
+
434
+ float PlacementAnnealer::estimate_starting_temp_using_cost_variance_ () {
435
+ const ClusteringContext& cluster_ctx = g_vpr_ctx.clustering ();
299
436
300
437
// Use to calculate the average of cost when swap is accepted.
301
438
int num_accepted = 0 ;
@@ -318,14 +455,14 @@ float PlacementAnnealer::estimate_starting_temperature_() {
318
455
#endif /* NO_GRAPHICS*/
319
456
320
457
// Will not deploy setup slack analysis, so omit crit_exponenet and setup_slack
321
- e_move_result swap_result = try_swap_ (*move_generator_1_, placer_opts_.place_algorithm , manual_move_enabled);
458
+ t_swap_result swap_result = try_swap_ (*move_generator_1_, placer_opts_.place_algorithm , manual_move_enabled);
322
459
323
- if (swap_result == e_move_result::ACCEPTED) {
460
+ if (swap_result. move_result == e_move_result::ACCEPTED) {
324
461
num_accepted++;
325
462
av += costs_.cost ;
326
463
sum_of_squares += costs_.cost * costs_.cost ;
327
464
swap_stats_.num_swap_accepted ++;
328
- } else if (swap_result == e_move_result::ABORTED) {
465
+ } else if (swap_result. move_result == e_move_result::ABORTED) {
329
466
swap_stats_.num_swap_aborted ++;
330
467
} else {
331
468
swap_stats_.num_swap_rejected ++;
@@ -345,7 +482,7 @@ float PlacementAnnealer::estimate_starting_temperature_() {
345
482
return init_temp;
346
483
}
347
484
348
- e_move_result PlacementAnnealer::try_swap_ (MoveGenerator& move_generator,
485
+ t_swap_result PlacementAnnealer::try_swap_ (MoveGenerator& move_generator,
349
486
const t_place_algorithm& place_algorithm,
350
487
bool manual_move_enabled) {
351
488
/* Picks some block and moves it to another spot. If this spot is
@@ -646,7 +783,11 @@ e_move_result PlacementAnnealer::try_swap_(MoveGenerator& move_generator,
646
783
VTR_LOGV_DEBUG (g_vpr_ctx.placement ().f_placer_debug ,
647
784
" \t\t After move Place cost %e, bb_cost %e, timing cost %e\n " ,
648
785
costs_.cost , costs_.bb_cost , costs_.timing_cost );
649
- return move_outcome;
786
+
787
+ t_swap_result swap_result;
788
+ swap_result.move_result = move_outcome;
789
+ swap_result.delta_c = delta_c;
790
+ return swap_result;
650
791
}
651
792
652
793
void PlacementAnnealer::outer_loop_update_timing_info () {
@@ -687,13 +828,13 @@ void PlacementAnnealer::placement_inner_loop() {
687
828
688
829
// Inner loop begins
689
830
for (int inner_iter = 0 , inner_crit_iter_count = 1 ; inner_iter < annealing_state_.move_lim ; inner_iter++) {
690
- e_move_result swap_result = try_swap_ (move_generator, placer_opts_.place_algorithm , manual_move_enabled);
831
+ t_swap_result swap_result = try_swap_ (move_generator, placer_opts_.place_algorithm , manual_move_enabled);
691
832
692
- if (swap_result == e_move_result::ACCEPTED) {
833
+ if (swap_result. move_result == e_move_result::ACCEPTED) {
693
834
// Move was accepted. Update statistics that are useful for the annealing schedule.
694
835
placer_stats_.single_swap_update (costs_);
695
836
swap_stats_.num_swap_accepted ++;
696
- } else if (swap_result == e_move_result::ABORTED) {
837
+ } else if (swap_result. move_result == e_move_result::ABORTED) {
697
838
swap_stats_.num_swap_aborted ++;
698
839
} else { // swap_result == REJECTED
699
840
swap_stats_.num_swap_rejected ++;
0 commit comments