33
44#include < algorithm>
55#include < cmath>
6+ #include < limits>
67
78#include " globals.h"
89#include " place_macro.h"
10+ #include " vpr_context.h"
11+ #include " vpr_error.h"
912#include " vpr_types.h"
1013#include " place_util.h"
1114#include " placer_state.h"
@@ -291,11 +294,147 @@ PlacementAnnealer::PlacementAnnealer(const t_placer_opts& placer_opts,
291294}
292295
293296float PlacementAnnealer::estimate_starting_temperature_ () {
297+
294298 if (placer_opts_.anneal_sched .type == e_sched_type::USER_SCHED) {
295299 return placer_opts_.anneal_sched .init_t ;
296300 }
297301
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 ();
299438
300439 // Use to calculate the average of cost when swap is accepted.
301440 int num_accepted = 0 ;
@@ -318,14 +457,14 @@ float PlacementAnnealer::estimate_starting_temperature_() {
318457#endif /* NO_GRAPHICS*/
319458
320459 // 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);
322461
323- if (swap_result == e_move_result::ACCEPTED) {
462+ if (swap_result. move_result == e_move_result::ACCEPTED) {
324463 num_accepted++;
325464 av += costs_.cost ;
326465 sum_of_squares += costs_.cost * costs_.cost ;
327466 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) {
329468 swap_stats_.num_swap_aborted ++;
330469 } else {
331470 swap_stats_.num_swap_rejected ++;
@@ -345,7 +484,7 @@ float PlacementAnnealer::estimate_starting_temperature_() {
345484 return init_temp;
346485}
347486
348- e_move_result PlacementAnnealer::try_swap_ (MoveGenerator& move_generator,
487+ t_swap_result PlacementAnnealer::try_swap_ (MoveGenerator& move_generator,
349488 const t_place_algorithm& place_algorithm,
350489 bool manual_move_enabled) {
351490 /* 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,
646785 VTR_LOGV_DEBUG (g_vpr_ctx.placement ().f_placer_debug ,
647786 " \t\t After move Place cost %e, bb_cost %e, timing cost %e\n " ,
648787 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;
650793}
651794
652795void PlacementAnnealer::outer_loop_update_timing_info () {
@@ -687,13 +830,13 @@ void PlacementAnnealer::placement_inner_loop() {
687830
688831 // Inner loop begins
689832 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);
691834
692- if (swap_result == e_move_result::ACCEPTED) {
835+ if (swap_result. move_result == e_move_result::ACCEPTED) {
693836 // Move was accepted. Update statistics that are useful for the annealing schedule.
694837 placer_stats_.single_swap_update (costs_);
695838 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) {
697840 swap_stats_.num_swap_aborted ++;
698841 } else { // swap_result == REJECTED
699842 swap_stats_.num_swap_rejected ++;
0 commit comments