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,147 @@ 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:
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
+ t_swap_result swap_result = try_swap_ (*move_generator_1_,
332
+ placer_opts_.place_algorithm ,
333
+ false /* manual_move_enabled*/ );
334
+
335
+ if (swap_result.move_result == e_move_result::ACCEPTED) {
336
+ accepted_swaps.push_back (swap_result.delta_c );
337
+ // TODO: Look into not actually accepting these.
338
+ swap_stats_.num_swap_accepted ++;
339
+ } else if (swap_result.move_result == e_move_result::ABORTED) {
340
+ // Note: We do not keep track of the change in cost due to aborted
341
+ // swaps. These are not interesting for this approach.
342
+ swap_stats_.num_swap_aborted ++;
343
+ } else {
344
+ rejected_swaps.push_back (swap_result.delta_c );
345
+ swap_stats_.num_swap_rejected ++;
346
+ }
347
+ }
348
+
349
+ // Computed the total change in cost due to accepted swaps.
350
+ double total_accepted_cost = 0.0 ;
351
+ for (double accepted_cost : accepted_swaps) {
352
+ total_accepted_cost += accepted_cost;
353
+ }
354
+
355
+ // Find the magnitude of the largest reject swap cost. This is useful for
356
+ // picking a worst-case initial temperature.
357
+ double max_rejected_swap_cost = 0.0 ;
358
+ for (double rejected_cost : rejected_swaps) {
359
+ max_rejected_swap_cost = std::max (max_rejected_swap_cost,
360
+ std::abs (rejected_cost));
361
+ }
362
+
363
+ // Perform a binary search to try and find the equilibrium temperature for
364
+ // this placement. This is the temperature that we expect would lead to no
365
+ // overall change in temperature. We do this by computing the expected
366
+ // change in cost given a trial temperature and try larger / smaller
367
+ // temperatures until one is found that causes the change cost is close to
368
+ // 0. Since the expected change in cost is monotonically increasing for
369
+ // all positive temperatures, this method will return a unique result if it
370
+ // exists within this range.
371
+ // Initialize the lower bound temperature to 0. The temperature cannot
372
+ // be less than 0.
373
+ double lower_bound_temp = 0.0 ;
374
+ // Initialize the upper bound temperature. It is possible for
375
+ // the equilibrium temperature to be infinite if the initial placement
376
+ // is so bad that no swaps are accepted. In that case this value will
377
+ // be returned instead of infinity.
378
+ // At this temperature, the probability of accepting this worst rejected
379
+ // swap would be 71.655% (e^(-1/3)).
380
+ // TODO: Investigate if this is a good initial temperature for these
381
+ // cases.
382
+ double upper_bound_temp = 3.0 * max_rejected_swap_cost;
383
+ // The max search iterations should never be hit, but it is here as an
384
+ // exit condition to prevent infinite loops.
385
+ constexpr unsigned max_search_iters = 100 ;
386
+ for (unsigned binary_search_iter = 0 ; binary_search_iter < max_search_iters; binary_search_iter++) {
387
+ // Exit condition for binary search. Could be hit if the lower and upper
388
+ // bounds are arbitrarily close.
389
+ if (lower_bound_temp >= upper_bound_temp)
390
+ break ;
391
+
392
+ // Try the temperature in the middle of the lower and upper bounds.
393
+ double trial_temp = (lower_bound_temp + upper_bound_temp) / 2.0 ;
394
+
395
+ // Return the trial temperature if it is within 6 decimal-points of precision.
396
+ // NOTE: This is arbitrary.
397
+ // TODO: We could stop this early and then use Newton's Method to quickly
398
+ // touch it up to a more accurate value.
399
+ if (std::abs (upper_bound_temp - lower_bound_temp) / trial_temp < 1e-6 )
400
+ return trial_temp;
401
+
402
+ // Calculate the expected change in cost at this temperature (which we
403
+ // call the residual here).
404
+ double expected_total_post_rejected_cost = 0.0 ;
405
+ for (double rejected_cost : rejected_swaps) {
406
+ // Expected change in cost after a rejected swap is the change in
407
+ // cost multiplied by the probability that this swap is accepted at
408
+ // this temperature.
409
+ double acceptance_prob = std::exp ((-1.0 * rejected_cost) / trial_temp);
410
+ expected_total_post_rejected_cost += rejected_cost * acceptance_prob;
411
+ }
412
+ double residual = expected_total_post_rejected_cost + total_accepted_cost;
413
+
414
+ if (residual < 0 ) {
415
+ // Since the function is monotonically increasing, if the residual
416
+ // is negative, then the lower bound should be raised to the trial
417
+ // temperature.
418
+ lower_bound_temp = trial_temp;
419
+ } else if (residual > 0 ) {
420
+ // Similarly, if the residual is positive, then the upper bound should
421
+ // be lowered to the trial temperature.
422
+ upper_bound_temp = trial_temp;
423
+ } else {
424
+ // If we happened to exactly hit the risidual, then this is the
425
+ // exact temperature we should use.
426
+ return trial_temp;
427
+ }
428
+ }
429
+
430
+ // If we get down here, it means that the upper loop did not reach a solution;
431
+ // however, we know that the answer should be somewhere between lower and upper
432
+ // bound. Therefore, return the average of the two.
433
+ return (lower_bound_temp + upper_bound_temp) / 2.0 ;
434
+ }
435
+
436
+ float PlacementAnnealer::estimate_starting_temp_using_cost_variance_ () {
437
+ const ClusteringContext& cluster_ctx = g_vpr_ctx.clustering ();
299
438
300
439
// Use to calculate the average of cost when swap is accepted.
301
440
int num_accepted = 0 ;
@@ -318,14 +457,14 @@ float PlacementAnnealer::estimate_starting_temperature_() {
318
457
#endif /* NO_GRAPHICS*/
319
458
320
459
// 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);
460
+ t_swap_result swap_result = try_swap_ (*move_generator_1_, placer_opts_.place_algorithm , manual_move_enabled);
322
461
323
- if (swap_result == e_move_result::ACCEPTED) {
462
+ if (swap_result. move_result == e_move_result::ACCEPTED) {
324
463
num_accepted++;
325
464
av += costs_.cost ;
326
465
sum_of_squares += costs_.cost * costs_.cost ;
327
466
swap_stats_.num_swap_accepted ++;
328
- } else if (swap_result == e_move_result::ABORTED) {
467
+ } else if (swap_result. move_result == e_move_result::ABORTED) {
329
468
swap_stats_.num_swap_aborted ++;
330
469
} else {
331
470
swap_stats_.num_swap_rejected ++;
@@ -345,7 +484,7 @@ float PlacementAnnealer::estimate_starting_temperature_() {
345
484
return init_temp;
346
485
}
347
486
348
- e_move_result PlacementAnnealer::try_swap_ (MoveGenerator& move_generator,
487
+ t_swap_result PlacementAnnealer::try_swap_ (MoveGenerator& move_generator,
349
488
const t_place_algorithm& place_algorithm,
350
489
bool manual_move_enabled) {
351
490
/* Picks some block and moves it to another spot. If this spot is
@@ -646,7 +785,11 @@ e_move_result PlacementAnnealer::try_swap_(MoveGenerator& move_generator,
646
785
VTR_LOGV_DEBUG (g_vpr_ctx.placement ().f_placer_debug ,
647
786
" \t\t After move Place cost %e, bb_cost %e, timing cost %e\n " ,
648
787
costs_.cost , costs_.bb_cost , costs_.timing_cost );
649
- return move_outcome;
788
+
789
+ t_swap_result swap_result;
790
+ swap_result.move_result = move_outcome;
791
+ swap_result.delta_c = delta_c;
792
+ return swap_result;
650
793
}
651
794
652
795
void PlacementAnnealer::outer_loop_update_timing_info () {
@@ -687,13 +830,13 @@ void PlacementAnnealer::placement_inner_loop() {
687
830
688
831
// Inner loop begins
689
832
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);
833
+ t_swap_result swap_result = try_swap_ (move_generator, placer_opts_.place_algorithm , manual_move_enabled);
691
834
692
- if (swap_result == e_move_result::ACCEPTED) {
835
+ if (swap_result. move_result == e_move_result::ACCEPTED) {
693
836
// Move was accepted. Update statistics that are useful for the annealing schedule.
694
837
placer_stats_.single_swap_update (costs_);
695
838
swap_stats_.num_swap_accepted ++;
696
- } else if (swap_result == e_move_result::ABORTED) {
839
+ } else if (swap_result. move_result == e_move_result::ABORTED) {
697
840
swap_stats_.num_swap_aborted ++;
698
841
} else { // swap_result == REJECTED
699
842
swap_stats_.num_swap_rejected ++;
0 commit comments